ox 1.9.4 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of ox might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/README.md +21 -17
- data/ext/ox/cache.c +1 -2
- data/ext/ox/dump.c +11 -11
- data/ext/ox/extconf.rb +4 -2
- data/ext/ox/obj_load.c +1 -10
- data/ext/ox/ox.c +26 -11
- data/ext/ox/ox.h +1 -2
- data/ext/ox/sax.c +713 -1087
- data/ext/ox/sax.h +116 -0
- data/ext/ox/sax_as.c +254 -0
- data/ext/ox/sax_buf.c +262 -0
- data/ext/ox/sax_buf.h +198 -0
- data/ext/ox/sax_has.h +85 -0
- data/ext/ox/sax_hint.c +217 -0
- data/ext/ox/sax_hint.h +50 -0
- data/ext/ox/sax_stack.h +108 -0
- data/lib/ox/version.rb +1 -1
- metadata +19 -14
data/ext/ox/sax.h
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
/* sax.h
|
2
|
+
* Copyright (c) 2011, Peter Ohler
|
3
|
+
* All rights reserved.
|
4
|
+
*
|
5
|
+
* Redistribution and use in source and binary forms, with or without
|
6
|
+
* modification, are permitted provided that the following conditions are met:
|
7
|
+
*
|
8
|
+
* - Redistributions of source code must retain the above copyright notice, this
|
9
|
+
* list of conditions and the following disclaimer.
|
10
|
+
*
|
11
|
+
* - Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
* this list of conditions and the following disclaimer in the documentation
|
13
|
+
* and/or other materials provided with the distribution.
|
14
|
+
*
|
15
|
+
* - Neither the name of Peter Ohler nor the names of its contributors may be
|
16
|
+
* used to endorse or promote products derived from this software without
|
17
|
+
* specific prior written permission.
|
18
|
+
*
|
19
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
22
|
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
23
|
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
24
|
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
25
|
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
26
|
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
27
|
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
*/
|
30
|
+
|
31
|
+
#ifndef __OX_SAX_H__
|
32
|
+
#define __OX_SAX_H__
|
33
|
+
|
34
|
+
#include "sax_buf.h"
|
35
|
+
#include "sax_has.h"
|
36
|
+
#include "sax_stack.h"
|
37
|
+
#include "sax_hint.h"
|
38
|
+
|
39
|
+
typedef struct _SaxOptions {
|
40
|
+
int symbolize;
|
41
|
+
int convert_special;
|
42
|
+
int smart;
|
43
|
+
} *SaxOptions;
|
44
|
+
|
45
|
+
typedef struct _SaxDrive {
|
46
|
+
struct _Buf buf;
|
47
|
+
struct _NStack stack; /* element name stack */
|
48
|
+
VALUE handler;
|
49
|
+
VALUE value_obj;
|
50
|
+
struct _SaxOptions options;
|
51
|
+
int err;
|
52
|
+
struct _Has has;
|
53
|
+
Hints hints;
|
54
|
+
#if HAS_ENCODING_SUPPORT
|
55
|
+
rb_encoding *encoding;
|
56
|
+
#elif HAS_PRIVATE_ENCODING
|
57
|
+
VALUE encoding;
|
58
|
+
#endif
|
59
|
+
} *SaxDrive;
|
60
|
+
|
61
|
+
extern void ox_sax_parse(VALUE handler, VALUE io, SaxOptions options);
|
62
|
+
extern void ox_sax_drive_cleanup(SaxDrive dr);
|
63
|
+
extern void ox_sax_drive_error(SaxDrive dr, const char *msg);
|
64
|
+
extern int ox_sax_collapse_special(SaxDrive dr, char *str, int line, int col);
|
65
|
+
|
66
|
+
extern VALUE ox_sax_value_class;
|
67
|
+
|
68
|
+
inline static VALUE
|
69
|
+
str2sym(SaxDrive dr, const char *str, char **strp) {
|
70
|
+
VALUE *slot;
|
71
|
+
VALUE sym;
|
72
|
+
|
73
|
+
if (dr->options.symbolize) {
|
74
|
+
if (Qundef == (sym = ox_cache_get(ox_symbol_cache, str, &slot, strp))) {
|
75
|
+
#if HAS_ENCODING_SUPPORT
|
76
|
+
if (0 != dr->encoding) {
|
77
|
+
VALUE rstr = rb_str_new2(str);
|
78
|
+
|
79
|
+
rb_enc_associate(rstr, dr->encoding);
|
80
|
+
sym = rb_funcall(rstr, ox_to_sym_id, 0);
|
81
|
+
} else {
|
82
|
+
sym = ID2SYM(rb_intern(str));
|
83
|
+
}
|
84
|
+
#elif HAS_PRIVATE_ENCODING
|
85
|
+
if (Qnil != dr->encoding) {
|
86
|
+
VALUE rstr = rb_str_new2(str);
|
87
|
+
|
88
|
+
rb_funcall(rstr, ox_force_encoding_id, 1, dr->encoding);
|
89
|
+
sym = rb_funcall(rstr, ox_to_sym_id, 0);
|
90
|
+
} else {
|
91
|
+
sym = ID2SYM(rb_intern(str));
|
92
|
+
}
|
93
|
+
#else
|
94
|
+
sym = ID2SYM(rb_intern(str));
|
95
|
+
#endif
|
96
|
+
*slot = sym;
|
97
|
+
}
|
98
|
+
} else {
|
99
|
+
sym = rb_str_new2(str);
|
100
|
+
#if HAS_ENCODING_SUPPORT
|
101
|
+
if (0 != dr->encoding) {
|
102
|
+
rb_enc_associate(sym, dr->encoding);
|
103
|
+
}
|
104
|
+
#elif HAS_PRIVATE_ENCODING
|
105
|
+
if (Qnil != dr->encoding) {
|
106
|
+
rb_funcall(sym, ox_force_encoding_id, 1, dr->encoding);
|
107
|
+
}
|
108
|
+
#endif
|
109
|
+
if (0 != strp) {
|
110
|
+
*strp = StringValuePtr(sym);
|
111
|
+
}
|
112
|
+
}
|
113
|
+
return sym;
|
114
|
+
}
|
115
|
+
|
116
|
+
#endif /* __OX_SAX_H__ */
|
data/ext/ox/sax_as.c
ADDED
@@ -0,0 +1,254 @@
|
|
1
|
+
/* sax_as.c
|
2
|
+
* Copyright (c) 2011, Peter Ohler
|
3
|
+
* All rights reserved.
|
4
|
+
*
|
5
|
+
* Redistribution and use in source and binary forms, with or without
|
6
|
+
* modification, are permitted provided that the following conditions are met:
|
7
|
+
*
|
8
|
+
* - Redistributions of source code must retain the above copyright notice, this
|
9
|
+
* list of conditions and the following disclaimer.
|
10
|
+
*
|
11
|
+
* - Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
* this list of conditions and the following disclaimer in the documentation
|
13
|
+
* and/or other materials provided with the distribution.
|
14
|
+
*
|
15
|
+
* - Neither the name of Peter Ohler nor the names of its contributors may be
|
16
|
+
* used to endorse or promote products derived from this software without
|
17
|
+
* specific prior written permission.
|
18
|
+
*
|
19
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
22
|
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
23
|
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
24
|
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
25
|
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
26
|
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
27
|
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
*/
|
30
|
+
|
31
|
+
#include <stdlib.h>
|
32
|
+
#include <errno.h>
|
33
|
+
#include <stdio.h>
|
34
|
+
#include <strings.h>
|
35
|
+
#include <sys/types.h>
|
36
|
+
#if NEEDS_UIO
|
37
|
+
#include <sys/uio.h>
|
38
|
+
#endif
|
39
|
+
#include <unistd.h>
|
40
|
+
#include <time.h>
|
41
|
+
|
42
|
+
#include "ruby.h"
|
43
|
+
#include "ox.h"
|
44
|
+
#include "sax.h"
|
45
|
+
|
46
|
+
static VALUE
|
47
|
+
parse_double_time(const char *text) {
|
48
|
+
long v = 0;
|
49
|
+
long v2 = 0;
|
50
|
+
const char *dot = 0;
|
51
|
+
char c;
|
52
|
+
|
53
|
+
for (; '.' != *text; text++) {
|
54
|
+
c = *text;
|
55
|
+
if (c < '0' || '9' < c) {
|
56
|
+
return Qnil;
|
57
|
+
}
|
58
|
+
v = 10 * v + (long)(c - '0');
|
59
|
+
}
|
60
|
+
dot = text++;
|
61
|
+
for (; '\0' != *text && text - dot <= 6; text++) {
|
62
|
+
c = *text;
|
63
|
+
if (c < '0' || '9' < c) {
|
64
|
+
return Qnil;
|
65
|
+
}
|
66
|
+
v2 = 10 * v2 + (long)(c - '0');
|
67
|
+
}
|
68
|
+
for (; text - dot <= 9; text++) {
|
69
|
+
v2 *= 10;
|
70
|
+
}
|
71
|
+
#if HAS_NANO_TIME
|
72
|
+
return rb_time_nano_new(v, v2);
|
73
|
+
#else
|
74
|
+
return rb_time_new(v, v2 / 1000);
|
75
|
+
#endif
|
76
|
+
}
|
77
|
+
|
78
|
+
typedef struct _Tp {
|
79
|
+
int cnt;
|
80
|
+
char end;
|
81
|
+
char alt;
|
82
|
+
} *Tp;
|
83
|
+
|
84
|
+
static VALUE
|
85
|
+
parse_xsd_time(const char *text) {
|
86
|
+
long cargs[10];
|
87
|
+
long *cp = cargs;
|
88
|
+
long v;
|
89
|
+
int i;
|
90
|
+
char c = '\0';
|
91
|
+
struct _Tp tpa[10] = { { 4, '-', '-' },
|
92
|
+
{ 2, '-', '-' },
|
93
|
+
{ 2, 'T', ' ' },
|
94
|
+
{ 2, ':', ':' },
|
95
|
+
{ 2, ':', ':' },
|
96
|
+
{ 2, '.', '.' },
|
97
|
+
{ 9, '+', '-' },
|
98
|
+
{ 2, ':', ':' },
|
99
|
+
{ 2, '\0', '\0' },
|
100
|
+
{ 0, '\0', '\0' } };
|
101
|
+
Tp tp = tpa;
|
102
|
+
struct tm tm;
|
103
|
+
|
104
|
+
memset(cargs, 0, sizeof(cargs));
|
105
|
+
for (; 0 != tp->cnt; tp++) {
|
106
|
+
for (i = tp->cnt, v = 0; 0 < i ; text++, i--) {
|
107
|
+
c = *text;
|
108
|
+
if (c < '0' || '9' < c) {
|
109
|
+
if ('\0' == c || tp->end == c || tp->alt == c) {
|
110
|
+
break;
|
111
|
+
}
|
112
|
+
return Qnil;
|
113
|
+
}
|
114
|
+
v = 10 * v + (long)(c - '0');
|
115
|
+
}
|
116
|
+
if ('\0' == c) {
|
117
|
+
break;
|
118
|
+
}
|
119
|
+
c = *text++;
|
120
|
+
if (tp->end != c && tp->alt != c) {
|
121
|
+
return Qnil;
|
122
|
+
}
|
123
|
+
*cp++ = v;
|
124
|
+
}
|
125
|
+
tm.tm_year = (int)cargs[0] - 1900;
|
126
|
+
tm.tm_mon = (int)cargs[1] - 1;
|
127
|
+
tm.tm_mday = (int)cargs[2];
|
128
|
+
tm.tm_hour = (int)cargs[3];
|
129
|
+
tm.tm_min = (int)cargs[4];
|
130
|
+
tm.tm_sec = (int)cargs[5];
|
131
|
+
#if HAS_NANO_TIME
|
132
|
+
return rb_time_nano_new(mktime(&tm), cargs[6]);
|
133
|
+
#else
|
134
|
+
return rb_time_new(mktime(&tm), cargs[6] / 1000);
|
135
|
+
#endif
|
136
|
+
}
|
137
|
+
|
138
|
+
static VALUE
|
139
|
+
sax_value_as_s(VALUE self) {
|
140
|
+
SaxDrive dr = DATA_PTR(self);
|
141
|
+
VALUE rs;
|
142
|
+
|
143
|
+
if ('\0' == *dr->buf.str) {
|
144
|
+
return Qnil;
|
145
|
+
}
|
146
|
+
if (dr->options.convert_special) {
|
147
|
+
ox_sax_collapse_special(dr, dr->buf.str, dr->buf.line, dr->buf.col);
|
148
|
+
}
|
149
|
+
rs = rb_str_new2(dr->buf.str);
|
150
|
+
#if HAS_ENCODING_SUPPORT
|
151
|
+
if (0 != dr->encoding) {
|
152
|
+
rb_enc_associate(rs, dr->encoding);
|
153
|
+
}
|
154
|
+
#elif HAS_PRIVATE_ENCODING
|
155
|
+
if (Qnil != dr->encoding) {
|
156
|
+
rb_funcall(rs, ox_force_encoding_id, 1, dr->encoding);
|
157
|
+
}
|
158
|
+
#endif
|
159
|
+
return rs;
|
160
|
+
}
|
161
|
+
|
162
|
+
static VALUE
|
163
|
+
sax_value_as_sym(VALUE self) {
|
164
|
+
SaxDrive dr = DATA_PTR(self);
|
165
|
+
|
166
|
+
if ('\0' == *dr->buf.str) {
|
167
|
+
return Qnil;
|
168
|
+
}
|
169
|
+
return str2sym(dr, dr->buf.str, 0);
|
170
|
+
}
|
171
|
+
|
172
|
+
static VALUE
|
173
|
+
sax_value_as_f(VALUE self) {
|
174
|
+
SaxDrive dr = DATA_PTR(self);
|
175
|
+
|
176
|
+
if ('\0' == *dr->buf.str) {
|
177
|
+
return Qnil;
|
178
|
+
}
|
179
|
+
return rb_float_new(strtod(dr->buf.str, 0));
|
180
|
+
}
|
181
|
+
|
182
|
+
static VALUE
|
183
|
+
sax_value_as_i(VALUE self) {
|
184
|
+
SaxDrive dr = DATA_PTR(self);
|
185
|
+
const char *s = dr->buf.str;
|
186
|
+
long n = 0;
|
187
|
+
int neg = 0;
|
188
|
+
|
189
|
+
if ('\0' == *s) {
|
190
|
+
return Qnil;
|
191
|
+
}
|
192
|
+
if ('-' == *s) {
|
193
|
+
neg = 1;
|
194
|
+
s++;
|
195
|
+
} else if ('+' == *s) {
|
196
|
+
s++;
|
197
|
+
}
|
198
|
+
for (; '\0' != *s; s++) {
|
199
|
+
if ('0' <= *s && *s <= '9') {
|
200
|
+
n = n * 10 + (*s - '0');
|
201
|
+
} else {
|
202
|
+
rb_raise(ox_arg_error_class, "Not a valid Fixnum.\n");
|
203
|
+
}
|
204
|
+
}
|
205
|
+
if (neg) {
|
206
|
+
n = -n;
|
207
|
+
}
|
208
|
+
return LONG2NUM(n);
|
209
|
+
}
|
210
|
+
|
211
|
+
static VALUE
|
212
|
+
sax_value_as_time(VALUE self) {
|
213
|
+
SaxDrive dr = DATA_PTR(self);
|
214
|
+
const char *str = dr->buf.str;
|
215
|
+
VALUE t;
|
216
|
+
|
217
|
+
if ('\0' == *str) {
|
218
|
+
return Qnil;
|
219
|
+
}
|
220
|
+
if (Qnil == (t = parse_double_time(str)) &&
|
221
|
+
Qnil == (t = parse_xsd_time(str))) {
|
222
|
+
VALUE args[1];
|
223
|
+
|
224
|
+
/*printf("**** time parse\n"); */
|
225
|
+
*args = rb_str_new2(str);
|
226
|
+
t = rb_funcall2(ox_time_class, ox_parse_id, 1, args);
|
227
|
+
}
|
228
|
+
return t;
|
229
|
+
}
|
230
|
+
|
231
|
+
static VALUE
|
232
|
+
sax_value_as_bool(VALUE self) {
|
233
|
+
return (0 == strcasecmp("true", ((SaxDrive)DATA_PTR(self))->buf.str)) ? Qtrue : Qfalse;
|
234
|
+
}
|
235
|
+
|
236
|
+
static VALUE
|
237
|
+
sax_value_empty(VALUE self) {
|
238
|
+
return ('\0' == *((SaxDrive)DATA_PTR(self))->buf.str) ? Qtrue : Qfalse;
|
239
|
+
}
|
240
|
+
|
241
|
+
void
|
242
|
+
ox_sax_define() {
|
243
|
+
VALUE sax_module = rb_const_get_at(Ox, rb_intern("Sax"));
|
244
|
+
|
245
|
+
ox_sax_value_class = rb_define_class_under(sax_module, "Value", rb_cObject);
|
246
|
+
|
247
|
+
rb_define_method(ox_sax_value_class, "as_s", sax_value_as_s, 0);
|
248
|
+
rb_define_method(ox_sax_value_class, "as_sym", sax_value_as_sym, 0);
|
249
|
+
rb_define_method(ox_sax_value_class, "as_i", sax_value_as_i, 0);
|
250
|
+
rb_define_method(ox_sax_value_class, "as_f", sax_value_as_f, 0);
|
251
|
+
rb_define_method(ox_sax_value_class, "as_time", sax_value_as_time, 0);
|
252
|
+
rb_define_method(ox_sax_value_class, "as_bool", sax_value_as_bool, 0);
|
253
|
+
rb_define_method(ox_sax_value_class, "empty?", sax_value_empty, 0);
|
254
|
+
}
|
data/ext/ox/sax_buf.c
ADDED
@@ -0,0 +1,262 @@
|
|
1
|
+
/* sax_buf.c
|
2
|
+
* Copyright (c) 2011, Peter Ohler
|
3
|
+
* All rights reserved.
|
4
|
+
*
|
5
|
+
* Redistribution and use in source and binary forms, with or without
|
6
|
+
* modification, are permitted provided that the following conditions are met:
|
7
|
+
*
|
8
|
+
* - Redistributions of source code must retain the above copyright notice, this
|
9
|
+
* list of conditions and the following disclaimer.
|
10
|
+
*
|
11
|
+
* - Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
* this list of conditions and the following disclaimer in the documentation
|
13
|
+
* and/or other materials provided with the distribution.
|
14
|
+
*
|
15
|
+
* - Neither the name of Peter Ohler nor the names of its contributors may be
|
16
|
+
* used to endorse or promote products derived from this software without
|
17
|
+
* specific prior written permission.
|
18
|
+
*
|
19
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
22
|
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
23
|
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
24
|
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
25
|
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
26
|
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
27
|
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
*/
|
30
|
+
|
31
|
+
#include <stdlib.h>
|
32
|
+
#include <errno.h>
|
33
|
+
#include <stdio.h>
|
34
|
+
#include <strings.h>
|
35
|
+
#include <sys/types.h>
|
36
|
+
#if NEEDS_UIO
|
37
|
+
#include <sys/uio.h>
|
38
|
+
#endif
|
39
|
+
#include <unistd.h>
|
40
|
+
#include <time.h>
|
41
|
+
|
42
|
+
#include "ruby.h"
|
43
|
+
#include "ox.h"
|
44
|
+
#include "sax.h"
|
45
|
+
|
46
|
+
static VALUE rescue_cb(VALUE rdr, VALUE err);
|
47
|
+
static VALUE io_cb(VALUE rdr);
|
48
|
+
static VALUE partial_io_cb(VALUE rdr);
|
49
|
+
static int read_from_io(Buf buf);
|
50
|
+
#ifndef JRUBY_RUBY
|
51
|
+
static int read_from_fd(Buf buf);
|
52
|
+
#endif
|
53
|
+
static int read_from_io_partial(Buf buf);
|
54
|
+
static int read_from_str(Buf buf);
|
55
|
+
|
56
|
+
void
|
57
|
+
ox_sax_buf_init(Buf buf, VALUE io) {
|
58
|
+
if (ox_stringio_class == rb_obj_class(io)) {
|
59
|
+
VALUE s = rb_funcall2(io, ox_string_id, 0, 0);
|
60
|
+
|
61
|
+
buf->read_func = read_from_str;
|
62
|
+
buf->in_str = StringValuePtr(s);
|
63
|
+
} else if (rb_respond_to(io, ox_readpartial_id)) {
|
64
|
+
#ifdef JRUBY_RUBY
|
65
|
+
buf->read_func = read_from_io_partial;
|
66
|
+
buf->io = io;
|
67
|
+
#else
|
68
|
+
VALUE rfd;
|
69
|
+
|
70
|
+
if (rb_respond_to(io, ox_fileno_id) && Qnil != (rfd = rb_funcall(io, ox_fileno_id, 0))) {
|
71
|
+
buf->read_func = read_from_fd;
|
72
|
+
buf->fd = FIX2INT(rfd);
|
73
|
+
} else {
|
74
|
+
buf->read_func = read_from_io_partial;
|
75
|
+
buf->io = io;
|
76
|
+
}
|
77
|
+
#endif
|
78
|
+
} else if (rb_respond_to(io, ox_read_id)) {
|
79
|
+
#ifdef JRUBY_RUBY
|
80
|
+
buf->read_func = read_from_io;
|
81
|
+
buf->io = io;
|
82
|
+
#else
|
83
|
+
VALUE rfd;
|
84
|
+
|
85
|
+
if (rb_respond_to(io, ox_fileno_id) && Qnil != (rfd = rb_funcall(io, ox_fileno_id, 0))) {
|
86
|
+
buf->read_func = read_from_fd;
|
87
|
+
buf->fd = FIX2INT(rfd);
|
88
|
+
} else {
|
89
|
+
buf->read_func = read_from_io;
|
90
|
+
buf->io = io;
|
91
|
+
}
|
92
|
+
#endif
|
93
|
+
} else {
|
94
|
+
rb_raise(ox_arg_error_class, "sax_parser io argument must respond to readpartial() or read().\n");
|
95
|
+
}
|
96
|
+
buf->head = buf->base;
|
97
|
+
*buf->head = '\0';
|
98
|
+
buf->end = buf->head + sizeof(buf->base) - 1; /* 1 less to make debugging easier */
|
99
|
+
buf->tail = buf->head;
|
100
|
+
buf->read_end = buf->head;
|
101
|
+
buf->pro = 0;
|
102
|
+
buf->str = 0;
|
103
|
+
buf->line = 1;
|
104
|
+
buf->col = 0;
|
105
|
+
buf->pro_line = 1;
|
106
|
+
buf->pro_col = 0;
|
107
|
+
buf->dr = 0;
|
108
|
+
}
|
109
|
+
|
110
|
+
int
|
111
|
+
ox_sax_buf_read(Buf buf) {
|
112
|
+
int err;
|
113
|
+
size_t shift = 0;
|
114
|
+
|
115
|
+
if (buf->head < buf->tail) {
|
116
|
+
if (0 == buf->pro) {
|
117
|
+
shift = buf->tail - buf->head;
|
118
|
+
} else {
|
119
|
+
shift = buf->pro - buf->head;
|
120
|
+
}
|
121
|
+
/*printf("\n*** shift: %lu\n", shift); */
|
122
|
+
if (0 == shift) { /* no space left so allocate more */
|
123
|
+
char *old = buf->head;
|
124
|
+
size_t size = buf->end - buf->head;
|
125
|
+
|
126
|
+
if (buf->head == buf->base) {
|
127
|
+
buf->head = ALLOC_N(char, size * 2);
|
128
|
+
memcpy(buf->head, old, size);
|
129
|
+
} else {
|
130
|
+
REALLOC_N(buf->head, char, size * 2);
|
131
|
+
}
|
132
|
+
buf->end = buf->head + size * 2;
|
133
|
+
buf->tail = buf->head + (buf->tail - old);
|
134
|
+
buf->read_end = buf->head + (buf->read_end - old);
|
135
|
+
if (0 != buf->pro) {
|
136
|
+
buf->pro = buf->head + (buf->pro - old);
|
137
|
+
}
|
138
|
+
if (0 != buf->str) {
|
139
|
+
buf->str = buf->head + (buf->str - old);
|
140
|
+
}
|
141
|
+
} else {
|
142
|
+
memmove(buf->head, buf->head + shift, buf->read_end - (buf->head + shift));
|
143
|
+
buf->tail -= shift;
|
144
|
+
buf->read_end -= shift;
|
145
|
+
if (0 != buf->pro) {
|
146
|
+
buf->pro -= shift;
|
147
|
+
}
|
148
|
+
if (0 != buf->str) {
|
149
|
+
buf->str -= shift;
|
150
|
+
}
|
151
|
+
}
|
152
|
+
}
|
153
|
+
err = buf->read_func(buf);
|
154
|
+
*buf->read_end = '\0';
|
155
|
+
|
156
|
+
return err;
|
157
|
+
}
|
158
|
+
|
159
|
+
static VALUE
|
160
|
+
rescue_cb(VALUE rbuf, VALUE err) {
|
161
|
+
#ifndef JRUBY_RUBY
|
162
|
+
/* JRuby seems to play by a different set if rules. It passes in an Fixnum
|
163
|
+
* instead of an error like other Rubies. For now assume all errors are
|
164
|
+
* EOF and deal with the results further down the line. */
|
165
|
+
#if (defined(RUBINIUS_RUBY) || (1 == RUBY_VERSION_MAJOR && 8 == RUBY_VERSION_MINOR))
|
166
|
+
if (rb_obj_class(err) != rb_eTypeError) {
|
167
|
+
#else
|
168
|
+
if (rb_obj_class(err) != rb_eEOFError) {
|
169
|
+
#endif
|
170
|
+
Buf buf = (Buf)rbuf;
|
171
|
+
|
172
|
+
ox_sax_drive_cleanup(buf->dr);
|
173
|
+
rb_raise(err, "at line %d, column %d\n", buf->line, buf->col);
|
174
|
+
}
|
175
|
+
#endif
|
176
|
+
return Qfalse;
|
177
|
+
}
|
178
|
+
|
179
|
+
static VALUE
|
180
|
+
partial_io_cb(VALUE rbuf) {
|
181
|
+
Buf buf = (Buf)rbuf;
|
182
|
+
VALUE args[1];
|
183
|
+
VALUE rstr;
|
184
|
+
char *str;
|
185
|
+
size_t cnt;
|
186
|
+
|
187
|
+
args[0] = ULONG2NUM(buf->end - buf->tail);
|
188
|
+
rstr = rb_funcall2(buf->io, ox_readpartial_id, 1, args);
|
189
|
+
str = StringValuePtr(rstr);
|
190
|
+
cnt = strlen(str);
|
191
|
+
/*printf("*** read %lu bytes, str: '%s'\n", cnt, str); */
|
192
|
+
strcpy(buf->tail, str);
|
193
|
+
buf->read_end = buf->tail + cnt;
|
194
|
+
|
195
|
+
return Qtrue;
|
196
|
+
}
|
197
|
+
|
198
|
+
static VALUE
|
199
|
+
io_cb(VALUE rbuf) {
|
200
|
+
Buf buf = (Buf)rbuf;
|
201
|
+
VALUE args[1];
|
202
|
+
VALUE rstr;
|
203
|
+
char *str;
|
204
|
+
size_t cnt;
|
205
|
+
|
206
|
+
args[0] = ULONG2NUM(buf->end - buf->tail);
|
207
|
+
rstr = rb_funcall2(buf->io, ox_read_id, 1, args);
|
208
|
+
str = StringValuePtr(rstr);
|
209
|
+
cnt = strlen(str);
|
210
|
+
/*printf("*** read %lu bytes, str: '%s'\n", cnt, str); */
|
211
|
+
strcpy(buf->tail, str);
|
212
|
+
buf->read_end = buf->tail + cnt;
|
213
|
+
|
214
|
+
return Qtrue;
|
215
|
+
}
|
216
|
+
|
217
|
+
static int
|
218
|
+
read_from_io_partial(Buf buf) {
|
219
|
+
return (Qfalse == rb_rescue(partial_io_cb, (VALUE)buf, rescue_cb, (VALUE)buf));
|
220
|
+
}
|
221
|
+
|
222
|
+
static int
|
223
|
+
read_from_io(Buf buf) {
|
224
|
+
return (Qfalse == rb_rescue(io_cb, (VALUE)buf, rescue_cb, (VALUE)buf));
|
225
|
+
}
|
226
|
+
|
227
|
+
#ifndef JRUBY_RUBY
|
228
|
+
static int
|
229
|
+
read_from_fd(Buf buf) {
|
230
|
+
ssize_t cnt;
|
231
|
+
size_t max = buf->end - buf->tail;
|
232
|
+
|
233
|
+
cnt = read(buf->fd, buf->tail, max);
|
234
|
+
if (cnt < 0) {
|
235
|
+
ox_sax_drive_error(buf->dr, "failed to read from file");
|
236
|
+
return -1;
|
237
|
+
} else if (0 != cnt) {
|
238
|
+
buf->read_end = buf->tail + cnt;
|
239
|
+
}
|
240
|
+
return 0;
|
241
|
+
}
|
242
|
+
#endif
|
243
|
+
|
244
|
+
static int
|
245
|
+
read_from_str(Buf buf) {
|
246
|
+
size_t max = buf->end - buf->tail - 1;
|
247
|
+
char *s;
|
248
|
+
long cnt;
|
249
|
+
|
250
|
+
if ('\0' == *buf->in_str) {
|
251
|
+
/* done */
|
252
|
+
return -1;
|
253
|
+
}
|
254
|
+
s = stpncpy(buf->tail, buf->in_str, max);
|
255
|
+
*s = '\0';
|
256
|
+
cnt = s - buf->tail;
|
257
|
+
buf->in_str += cnt;
|
258
|
+
buf->read_end = buf->tail + cnt;
|
259
|
+
|
260
|
+
return 0;
|
261
|
+
}
|
262
|
+
|