ox 2.0.0 → 2.0.1

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.

data/ext/ox/err.h ADDED
@@ -0,0 +1,61 @@
1
+ /* err.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_ERR_H__
32
+ #define __OX_ERR_H__
33
+
34
+ #include "ruby.h"
35
+
36
+ #define set_error(err, msg, xml, current) _ox_err_set_with_location(err, msg, xml, current, __FILE__, __LINE__)
37
+
38
+ typedef struct _Err {
39
+ VALUE clas;
40
+ char msg[128];
41
+ } *Err;
42
+
43
+ extern VALUE ox_arg_error_class;
44
+ extern VALUE ox_parse_error_class;
45
+
46
+ extern void ox_err_set(Err e, VALUE clas, const char *format, ...);
47
+ extern void _ox_err_set_with_location(Err err, const char *msg, const char *xml, const char *current, const char* file, int line);
48
+ extern void ox_err_raise(Err e);
49
+
50
+ inline static void
51
+ err_init(Err e) {
52
+ e->clas = Qnil;
53
+ *e->msg = '\0';
54
+ }
55
+
56
+ inline static int
57
+ err_has(Err e) {
58
+ return (Qnil != e->clas);
59
+ }
60
+
61
+ #endif /* __OX_ERR_H__ */
data/ext/ox/gen_load.c CHANGED
@@ -92,12 +92,12 @@ create_doc(PInfo pi) {
92
92
  VALUE doc;
93
93
  VALUE nodes;
94
94
 
95
- pi->h = pi->helpers;
95
+ helper_stack_init(&pi->helpers);
96
96
  doc = rb_obj_alloc(ox_document_clas);
97
97
  nodes = rb_ary_new();
98
98
  rb_ivar_set(doc, ox_attributes_id, rb_hash_new());
99
99
  rb_ivar_set(doc, ox_nodes_id, nodes);
100
- pi->h->obj = nodes;
100
+ helper_stack_push(&pi->helpers, 0, nodes, NoCode);
101
101
  pi->obj = doc;
102
102
  }
103
103
 
@@ -108,10 +108,10 @@ create_prolog_doc(PInfo pi, const char *target, Attr attrs) {
108
108
  VALUE nodes;
109
109
  VALUE sym;
110
110
 
111
- if (0 != pi->h) { /* top level object */
112
- rb_raise(rb_eSyntaxError, "Prolog must be the first element in an XML document.\n");
111
+ if (!helper_stack_empty(&pi->helpers)) { /* top level object */
112
+ ox_err_set(&pi->err, rb_eSyntaxError, "Prolog must be the first element in an XML document.\n");
113
+ return;
113
114
  }
114
- pi->h = pi->helpers;
115
115
  doc = rb_obj_alloc(ox_document_clas);
116
116
  ah = rb_hash_new();
117
117
  for (; 0 != attrs->name; attrs++) {
@@ -165,7 +165,7 @@ create_prolog_doc(PInfo pi, const char *target, Attr attrs) {
165
165
  nodes = rb_ary_new();
166
166
  rb_ivar_set(doc, ox_attributes_id, ah);
167
167
  rb_ivar_set(doc, ox_nodes_id, nodes);
168
- pi->h->obj = nodes;
168
+ helper_stack_push(&pi->helpers, 0, nodes, ArrayCode);
169
169
  pi->obj = doc;
170
170
  }
171
171
 
@@ -177,7 +177,8 @@ instruct(PInfo pi, const char *target, Attr attrs, const char *content) {
177
177
  for (; 0 != attrs->name; attrs++) {
178
178
  if (0 == strcmp("version", attrs->name)) {
179
179
  if (0 != strcmp("1.0", attrs->value)) {
180
- rb_raise(rb_eSyntaxError, "Only Ox XML Object version 1.0 supported, not %s.\n", attrs->value);
180
+ ox_err_set(&pi->err, rb_eSyntaxError, "Only Ox XML Object version 1.0 supported, not %s.\n", attrs->value);
181
+ return;
181
182
  }
182
183
  }
183
184
  /* ignore other instructions */
@@ -195,21 +196,23 @@ nomode_instruct(PInfo pi, const char *target, Attr attrs, const char *content) {
195
196
  for (; 0 != attrs->name; attrs++) {
196
197
  if (0 == strcmp("version", attrs->name)) {
197
198
  if (0 != strcmp("1.0", attrs->value)) {
198
- rb_raise(rb_eSyntaxError, "Only Ox XML Object version 1.0 supported, not %s.\n", attrs->value);
199
+ ox_err_set(&pi->err, rb_eSyntaxError, "Only Ox XML Object version 1.0 supported, not %s.\n", attrs->value);
200
+ return;
199
201
  }
200
202
  } else if (0 == strcmp("mode", attrs->name)) {
201
203
  if (0 == strcmp("object", attrs->value)) {
202
204
  pi->pcb = ox_obj_callbacks;
203
205
  pi->obj = Qnil;
204
- pi->h = 0;
206
+ helper_stack_init(&pi->helpers);
205
207
  } else if (0 == strcmp("generic", attrs->value)) {
206
208
  pi->pcb = ox_gen_callbacks;
207
209
  } else if (0 == strcmp("limited", attrs->value)) {
208
210
  pi->pcb = ox_limited_callbacks;
209
211
  pi->obj = Qnil;
210
- pi->h = 0;
212
+ helper_stack_init(&pi->helpers);
211
213
  } else {
212
- rb_raise(rb_eSyntaxError, "%s is not a valid processing instruction mode.\n", attrs->value);
214
+ ox_err_set(&pi->err, rb_eSyntaxError, "%s is not a valid processing instruction mode.\n", attrs->value);
215
+ return;
213
216
  }
214
217
  }
215
218
  }
@@ -235,10 +238,10 @@ add_doctype(PInfo pi, const char *docType) {
235
238
  }
236
239
  #endif
237
240
  rb_ivar_set(n, ox_at_value_id, s);
238
- if (0 == pi->h) { /* top level object */
241
+ if (helper_stack_empty(&pi->helpers)) { /* top level object */
239
242
  create_doc(pi);
240
243
  }
241
- rb_ary_push(pi->h->obj, n);
244
+ rb_ary_push(helper_stack_peek(&pi->helpers)->obj, n);
242
245
  }
243
246
 
244
247
  static void
@@ -256,10 +259,10 @@ add_comment(PInfo pi, const char *comment) {
256
259
  }
257
260
  #endif
258
261
  rb_ivar_set(n, ox_at_value_id, s);
259
- if (0 == pi->h) { /* top level object */
262
+ if (helper_stack_empty(&pi->helpers)) { /* top level object */
260
263
  create_doc(pi);
261
264
  }
262
- rb_ary_push(pi->h->obj, n);
265
+ rb_ary_push(helper_stack_peek(&pi->helpers)->obj, n);
263
266
  }
264
267
 
265
268
  static void
@@ -277,10 +280,10 @@ add_cdata(PInfo pi, const char *cdata, size_t len) {
277
280
  }
278
281
  #endif
279
282
  rb_ivar_set(n, ox_at_value_id, s);
280
- if (0 == pi->h) { /* top level object */
283
+ if (helper_stack_empty(&pi->helpers)) { /* top level object */
281
284
  create_doc(pi);
282
285
  }
283
- rb_ary_push(pi->h->obj, n);
286
+ rb_ary_push(helper_stack_peek(&pi->helpers)->obj, n);
284
287
  }
285
288
 
286
289
  static void
@@ -296,10 +299,10 @@ add_text(PInfo pi, char *text, int closed) {
296
299
  rb_funcall(s, ox_force_encoding_id, 1, pi->options->rb_enc);
297
300
  }
298
301
  #endif
299
- if (0 == pi->h) { /* top level object */
302
+ if (helper_stack_empty(&pi->helpers)) { /* top level object */
300
303
  create_doc(pi);
301
304
  }
302
- rb_ary_push(pi->h->obj, s);
305
+ rb_ary_push(helper_stack_peek(&pi->helpers)->obj, s);
303
306
  }
304
307
 
305
308
  static void
@@ -376,29 +379,25 @@ add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren) {
376
379
  }
377
380
  rb_ivar_set(e, ox_attributes_id, ah);
378
381
  }
379
- if (0 == pi->h) { /* top level object */
380
- pi->h = pi->helpers;
381
- pi->obj = e;
382
+ if (helper_stack_empty(&pi->helpers)) { /* top level object */
383
+ pi->obj = e;
382
384
  } else {
383
- rb_ary_push(pi->h->obj, e);
384
- pi->h++;
385
+ rb_ary_push(helper_stack_peek(&pi->helpers)->obj, e);
385
386
  }
386
387
  if (hasChildren) {
387
388
  VALUE nodes = rb_ary_new();
388
389
 
389
390
  rb_ivar_set(e, ox_nodes_id, nodes);
390
- pi->h->obj = nodes;
391
+ helper_stack_push(&pi->helpers, 0, nodes, NoCode);
392
+ } else {
393
+ helper_stack_push(&pi->helpers, 0, Qnil, NoCode); // will be popped in end_element
391
394
  }
392
395
  }
393
396
 
394
397
  static void
395
398
  end_element(PInfo pi, const char *ename) {
396
- if (0 != pi->h) {
397
- if (pi->helpers < pi->h) {
398
- pi->h--;
399
- } else {
400
- pi->h = 0;
401
- }
399
+ if (!helper_stack_empty(&pi->helpers)) {
400
+ helper_stack_pop(&pi->helpers);
402
401
  }
403
402
  }
404
403
 
@@ -488,8 +487,8 @@ add_instruct(PInfo pi, const char *name, Attr attrs, const char *content) {
488
487
  }
489
488
  rb_ivar_set(inst, ox_attributes_id, ah);
490
489
  }
491
- if (0 == pi->h) { /* top level object */
490
+ if (helper_stack_empty(&pi->helpers)) { /* top level object */
492
491
  create_doc(pi);
493
492
  }
494
- rb_ary_push(pi->h->obj, inst);
493
+ rb_ary_push(helper_stack_peek(&pi->helpers)->obj, inst);
495
494
  }
data/ext/ox/helper.h ADDED
@@ -0,0 +1,116 @@
1
+ /* helper.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_HELPER_H__
32
+ #define __OX_HELPER_H__
33
+
34
+ #include "type.h"
35
+
36
+ #define HELPER_STACK_INC 16
37
+
38
+ typedef struct _Helper {
39
+ ID var; /* Object var ID */
40
+ VALUE obj; /* object created or Qundef if not appropriate */
41
+ Type type; /* type of object in obj */
42
+ } *Helper;
43
+
44
+ typedef struct _HelperStack {
45
+ struct _Helper base[HELPER_STACK_INC];
46
+ Helper head; /* current stack */
47
+ Helper end; /* stack end */
48
+ Helper tail; /* pointer to one past last element name on stack */
49
+ } *HelperStack;
50
+
51
+ inline static void
52
+ helper_stack_init(HelperStack stack) {
53
+ stack->head = stack->base;
54
+ stack->end = stack->base + sizeof(stack->base) / sizeof(struct _Helper);
55
+ stack->tail = stack->head;
56
+ }
57
+
58
+ inline static int
59
+ helper_stack_empty(HelperStack stack) {
60
+ return (stack->head == stack->tail);
61
+ }
62
+
63
+ inline static int
64
+ helper_stack_depth(HelperStack stack) {
65
+ return (int)(stack->tail - stack->head);
66
+ }
67
+
68
+ inline static void
69
+ helper_stack_cleanup(HelperStack stack) {
70
+ if (stack->base != stack->head) {
71
+ xfree(stack->head);
72
+ stack->head = stack->base;
73
+ }
74
+ }
75
+
76
+ inline static Helper
77
+ helper_stack_push(HelperStack stack, ID var, VALUE obj, Type type) {
78
+ if (stack->end <= stack->tail) {
79
+ size_t len = stack->end - stack->head;
80
+ size_t toff = stack->tail - stack->head;
81
+
82
+ if (stack->base == stack->head) {
83
+ stack->head = ALLOC_N(struct _Helper, len + HELPER_STACK_INC);
84
+ memcpy(stack->head, stack->base, sizeof(struct _Helper) * len);
85
+ } else {
86
+ REALLOC_N(stack->head, struct _Helper, len + HELPER_STACK_INC);
87
+ }
88
+ stack->tail = stack->head + toff;
89
+ stack->end = stack->head + len + HELPER_STACK_INC;
90
+ }
91
+ stack->tail->var = var;
92
+ stack->tail->obj = obj;
93
+ stack->tail->type = type;
94
+ stack->tail++;
95
+
96
+ return stack->tail - 1;
97
+ }
98
+
99
+ inline static Helper
100
+ helper_stack_peek(HelperStack stack) {
101
+ if (stack->head < stack->tail) {
102
+ return stack->tail - 1;
103
+ }
104
+ return 0;
105
+ }
106
+
107
+ inline static Helper
108
+ helper_stack_pop(HelperStack stack) {
109
+ if (stack->head < stack->tail) {
110
+ stack->tail--;
111
+ return stack->tail;
112
+ }
113
+ return 0;
114
+ }
115
+
116
+ #endif /* __OX_HELPER_H__ */
data/ext/ox/obj_load.c CHANGED
@@ -39,31 +39,31 @@
39
39
  #include "base64.h"
40
40
  #include "ox.h"
41
41
 
42
- static void instruct(PInfo pi, const char *target, Attr attrs, const char *content);
43
- static void add_text(PInfo pi, char *text, int closed);
44
- static void add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren);
45
- static void end_element(PInfo pi, const char *ename);
46
-
47
- static VALUE parse_time(const char *text, VALUE clas);
48
- static VALUE parse_xsd_time(const char *text, VALUE clas);
49
- static VALUE parse_double_time(const char *text, VALUE clas);
50
- static VALUE parse_regexp(const char *text);
51
-
52
- static VALUE get_var_sym_from_attrs(Attr a, void *encoding);
53
- static VALUE get_obj_from_attrs(Attr a, PInfo pi, VALUE base_class);
54
- static VALUE get_class_from_attrs(Attr a, PInfo pi, VALUE base_class);
55
- static VALUE classname2class(const char *name, PInfo pi, VALUE base_class);
56
- static unsigned long get_id_from_attrs(PInfo pi, Attr a);
57
- static CircArray circ_array_new(void);
58
- static void circ_array_free(CircArray ca);
59
- static void circ_array_set(CircArray ca, VALUE obj, unsigned long id);
60
- static VALUE circ_array_get(CircArray ca, unsigned long id);
61
-
62
- static void debug_stack(PInfo pi, const char *comment);
63
- static void fill_indent(PInfo pi, char *buf, size_t size);
64
-
65
-
66
- struct _ParseCallbacks _ox_obj_callbacks = {
42
+ static void instruct(PInfo pi, const char *target, Attr attrs, const char *content);
43
+ static void add_text(PInfo pi, char *text, int closed);
44
+ static void add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren);
45
+ static void end_element(PInfo pi, const char *ename);
46
+
47
+ static VALUE parse_time(const char *text, VALUE clas);
48
+ static VALUE parse_xsd_time(const char *text, VALUE clas);
49
+ static VALUE parse_double_time(const char *text, VALUE clas);
50
+ static VALUE parse_regexp(const char *text);
51
+
52
+ static VALUE get_var_sym_from_attrs(Attr a, void *encoding);
53
+ static VALUE get_obj_from_attrs(Attr a, PInfo pi, VALUE base_class);
54
+ static VALUE get_class_from_attrs(Attr a, PInfo pi, VALUE base_class);
55
+ static VALUE classname2class(const char *name, PInfo pi, VALUE base_class);
56
+ static unsigned long get_id_from_attrs(PInfo pi, Attr a);
57
+ static CircArray circ_array_new(void);
58
+ static void circ_array_free(CircArray ca);
59
+ static void circ_array_set(CircArray ca, VALUE obj, unsigned long id);
60
+ static VALUE circ_array_get(CircArray ca, unsigned long id);
61
+
62
+ static void debug_stack(PInfo pi, const char *comment);
63
+ static void fill_indent(PInfo pi, char *buf, size_t size);
64
+
65
+
66
+ struct _ParseCallbacks _ox_obj_callbacks = {
67
67
  instruct, /* instruct, */
68
68
  0, /* add_doctype, */
69
69
  0, /* add_comment, */
@@ -73,9 +73,9 @@ struct _ParseCallbacks _ox_obj_callbacks = {
73
73
  end_element,
74
74
  };
75
75
 
76
- ParseCallbacks ox_obj_callbacks = &_ox_obj_callbacks;
76
+ ParseCallbacks ox_obj_callbacks = &_ox_obj_callbacks;
77
77
 
78
- extern ParseCallbacks ox_gen_callbacks;
78
+ extern ParseCallbacks ox_gen_callbacks;
79
79
 
80
80
 
81
81
  inline static VALUE
@@ -99,11 +99,11 @@ str2sym(const char *str, void *encoding) {
99
99
 
100
100
  inline static ID
101
101
  name2var(const char *name, void *encoding) {
102
- VALUE *slot;
103
- ID var_id;
102
+ VALUE *slot;
103
+ ID var_id;
104
104
 
105
105
  if ('0' <= *name && *name <= '9') {
106
- var_id = INT2NUM(atoi(name));
106
+ var_id = INT2NUM(atoi(name));
107
107
  } else if (Qundef == (var_id = ox_cache_get(ox_attr_cache, name, &slot, 0))) {
108
108
  #ifdef HAVE_RUBY_ENCODING_H
109
109
  if (0 != encoding) {
@@ -119,36 +119,36 @@ name2var(const char *name, void *encoding) {
119
119
  #else
120
120
  var_id = rb_intern(name);
121
121
  #endif
122
- *slot = var_id;
122
+ *slot = var_id;
123
123
  }
124
124
  return var_id;
125
125
  }
126
126
 
127
127
  inline static VALUE
128
128
  resolve_classname(VALUE mod, const char *class_name, Effort effort, VALUE base_class) {
129
- VALUE clas;
130
- ID ci = rb_intern(class_name);
129
+ VALUE clas;
130
+ ID ci = rb_intern(class_name);
131
131
 
132
132
  switch (effort) {
133
133
  case TolerantEffort:
134
- if (rb_const_defined_at(mod, ci)) {
135
- clas = rb_const_get_at(mod, ci);
136
- } else {
137
- clas = Qundef;
138
- }
139
- break;
134
+ if (rb_const_defined_at(mod, ci)) {
135
+ clas = rb_const_get_at(mod, ci);
136
+ } else {
137
+ clas = Qundef;
138
+ }
139
+ break;
140
140
  case AutoEffort:
141
- if (rb_const_defined_at(mod, ci)) {
142
- clas = rb_const_get_at(mod, ci);
143
- } else {
144
- clas = rb_define_class_under(mod, class_name, base_class);
145
- }
146
- break;
141
+ if (rb_const_defined_at(mod, ci)) {
142
+ clas = rb_const_get_at(mod, ci);
143
+ } else {
144
+ clas = rb_define_class_under(mod, class_name, base_class);
145
+ }
146
+ break;
147
147
  case StrictEffort:
148
148
  default:
149
- /* raise an error if name is not defined */
150
- clas = rb_const_get_at(mod, ci);
151
- break;
149
+ /* raise an error if name is not defined */
150
+ clas = rb_const_get_at(mod, ci);
151
+ break;
152
152
  }
153
153
  return clas;
154
154
  }
@@ -158,26 +158,26 @@ classname2obj(const char *name, PInfo pi, VALUE base_class) {
158
158
  VALUE clas = classname2class(name, pi, base_class);
159
159
 
160
160
  if (Qundef == clas) {
161
- return Qnil;
161
+ return Qnil;
162
162
  } else {
163
- return rb_obj_alloc(clas);
163
+ return rb_obj_alloc(clas);
164
164
  }
165
165
  }
166
166
 
167
167
  #if HAS_RSTRUCT
168
168
  inline static VALUE
169
169
  structname2obj(const char *name) {
170
- VALUE ost;
171
- const char *s = name;
170
+ VALUE ost;
171
+ const char *s = name;
172
172
 
173
173
  for (; 1; s++) {
174
- if ('\0' == *s) {
175
- s = name;
176
- break;
177
- } else if (':' == *s) {
178
- s += 2;
179
- break;
180
- }
174
+ if ('\0' == *s) {
175
+ s = name;
176
+ break;
177
+ } else if (':' == *s) {
178
+ s += 2;
179
+ break;
180
+ }
181
181
  }
182
182
  ost = rb_const_get(ox_struct_class, rb_intern(s));
183
183
  /* use encoding as the indicator for Ruby 1.8.7 or 1.9.x */
@@ -199,7 +199,8 @@ parse_ulong(const char *s, PInfo pi) {
199
199
  if ('0' <= *s && *s <= '9') {
200
200
  n = n * 10 + (*s - '0');
201
201
  } else {
202
- raise_error("Invalid number for a julian day", pi->str, pi->s);
202
+ set_error(&pi->err, "Invalid number for a julian day", pi->str, pi->s);
203
+ return Qundef;
203
204
  }
204
205
  }
205
206
  return ULONG2NUM(n);
@@ -208,49 +209,50 @@ parse_ulong(const char *s, PInfo pi) {
208
209
  /* 2010-07-09T10:47:45.895826162+09:00 */
209
210
  inline static VALUE
210
211
  parse_time(const char *text, VALUE clas) {
211
- VALUE t;
212
+ VALUE t;
212
213
 
213
214
  if (Qnil == (t = parse_double_time(text, clas)) &&
214
- Qnil == (t = parse_xsd_time(text, clas))) {
215
- VALUE args[1];
215
+ Qnil == (t = parse_xsd_time(text, clas))) {
216
+ VALUE args[1];
216
217
 
217
- /*printf("**** time parse\n"); */
218
- *args = rb_str_new2(text);
219
- t = rb_funcall2(ox_time_class, ox_parse_id, 1, args);
218
+ /*printf("**** time parse\n"); */
219
+ *args = rb_str_new2(text);
220
+ t = rb_funcall2(ox_time_class, ox_parse_id, 1, args);
220
221
  }
221
222
  return t;
222
223
  }
223
224
 
224
225
  static VALUE
225
226
  classname2class(const char *name, PInfo pi, VALUE base_class) {
226
- VALUE *slot;
227
- VALUE clas;
228
-
227
+ VALUE *slot;
228
+ VALUE clas;
229
+
229
230
  if (Qundef == (clas = ox_cache_get(ox_class_cache, name, &slot, 0))) {
230
- char class_name[1024];
231
- char *s;
232
- const char *n = name;
233
-
234
- clas = rb_cObject;
235
- for (s = class_name; '\0' != *n; n++) {
236
- if (':' == *n) {
237
- *s = '\0';
238
- n++;
231
+ char class_name[1024];
232
+ char *s;
233
+ const char *n = name;
234
+
235
+ clas = rb_cObject;
236
+ for (s = class_name; '\0' != *n; n++) {
237
+ if (':' == *n) {
238
+ *s = '\0';
239
+ n++;
239
240
  if (':' != *n) {
240
- raise_error("Invalid classname, expected another ':'", pi->str, pi->s);
241
+ set_error(&pi->err, "Invalid classname, expected another ':'", pi->str, pi->s);
242
+ return Qundef;
241
243
  }
242
- if (Qundef == (clas = resolve_classname(clas, class_name, pi->options->effort, base_class))) {
243
- return Qundef;
244
- }
245
- s = class_name;
246
- } else {
247
- *s++ = *n;
248
- }
249
- }
250
- *s = '\0';
251
- if (Qundef != (clas = resolve_classname(clas, class_name, pi->options->effort, base_class))) {
252
- *slot = clas;
253
- }
244
+ if (Qundef == (clas = resolve_classname(clas, class_name, pi->options->effort, base_class))) {
245
+ return Qundef;
246
+ }
247
+ s = class_name;
248
+ } else {
249
+ *s++ = *n;
250
+ }
251
+ }
252
+ *s = '\0';
253
+ if (Qundef != (clas = resolve_classname(clas, class_name, pi->options->effort, base_class))) {
254
+ *slot = clas;
255
+ }
254
256
  }
255
257
  return clas;
256
258
  }
@@ -258,9 +260,9 @@ classname2class(const char *name, PInfo pi, VALUE base_class) {
258
260
  static VALUE
259
261
  get_var_sym_from_attrs(Attr a, void *encoding) {
260
262
  for (; 0 != a->name; a++) {
261
- if ('a' == *a->name && '\0' == *(a->name + 1)) {
262
- return name2var(a->value, encoding);
263
- }
263
+ if ('a' == *a->name && '\0' == *(a->name + 1)) {
264
+ return name2var(a->value, encoding);
265
+ }
264
266
  }
265
267
  return Qundef;
266
268
  }
@@ -268,9 +270,9 @@ get_var_sym_from_attrs(Attr a, void *encoding) {
268
270
  static VALUE
269
271
  get_obj_from_attrs(Attr a, PInfo pi, VALUE base_class) {
270
272
  for (; 0 != a->name; a++) {
271
- if ('c' == *a->name && '\0' == *(a->name + 1)) {
272
- return classname2obj(a->value, pi, base_class);
273
- }
273
+ if ('c' == *a->name && '\0' == *(a->name + 1)) {
274
+ return classname2obj(a->value, pi, base_class);
275
+ }
274
276
  }
275
277
  return Qundef;
276
278
  }
@@ -279,9 +281,9 @@ get_obj_from_attrs(Attr a, PInfo pi, VALUE base_class) {
279
281
  static VALUE
280
282
  get_struct_from_attrs(Attr a) {
281
283
  for (; 0 != a->name; a++) {
282
- if ('c' == *a->name && '\0' == *(a->name + 1)) {
283
- return structname2obj(a->value);
284
- }
284
+ if ('c' == *a->name && '\0' == *(a->name + 1)) {
285
+ return structname2obj(a->value);
286
+ }
285
287
  }
286
288
  return Qundef;
287
289
  }
@@ -290,9 +292,9 @@ get_struct_from_attrs(Attr a) {
290
292
  static VALUE
291
293
  get_class_from_attrs(Attr a, PInfo pi, VALUE base_class) {
292
294
  for (; 0 != a->name; a++) {
293
- if ('c' == *a->name && '\0' == *(a->name + 1)) {
294
- return classname2class(a->value, pi, base_class);
295
- }
295
+ if ('c' == *a->name && '\0' == *(a->name + 1)) {
296
+ return classname2class(a->value, pi, base_class);
297
+ }
296
298
  }
297
299
  return Qundef;
298
300
  }
@@ -300,28 +302,29 @@ get_class_from_attrs(Attr a, PInfo pi, VALUE base_class) {
300
302
  static unsigned long
301
303
  get_id_from_attrs(PInfo pi, Attr a) {
302
304
  for (; 0 != a->name; a++) {
303
- if ('i' == *a->name && '\0' == *(a->name + 1)) {
304
- unsigned long id = 0;
305
- const char *text = a->value;
306
- char c;
307
-
308
- for (; '\0' != *text; text++) {
309
- c = *text;
310
- if ('0' <= c && c <= '9') {
311
- id = id * 10 + (c - '0');
312
- } else {
313
- raise_error("bad number format", pi->str, pi->s);
314
- }
315
- }
316
- return id;
317
- }
305
+ if ('i' == *a->name && '\0' == *(a->name + 1)) {
306
+ unsigned long id = 0;
307
+ const char *text = a->value;
308
+ char c;
309
+
310
+ for (; '\0' != *text; text++) {
311
+ c = *text;
312
+ if ('0' <= c && c <= '9') {
313
+ id = id * 10 + (c - '0');
314
+ } else {
315
+ set_error(&pi->err, "bad number format", pi->str, pi->s);
316
+ return 0;
317
+ }
318
+ }
319
+ return id;
320
+ }
318
321
  }
319
322
  return 0;
320
323
  }
321
324
 
322
325
  static CircArray
323
326
  circ_array_new() {
324
- CircArray ca;
327
+ CircArray ca;
325
328
 
326
329
  ca = ALLOC(struct _CircArray);
327
330
  ca->objs = ca->obj_array;
@@ -334,7 +337,7 @@ circ_array_new() {
334
337
  static void
335
338
  circ_array_free(CircArray ca) {
336
339
  if (ca->objs != ca->obj_array) {
337
- xfree(ca->objs);
340
+ xfree(ca->objs);
338
341
  }
339
342
  xfree(ca);
340
343
  }
@@ -342,54 +345,54 @@ circ_array_free(CircArray ca) {
342
345
  static void
343
346
  circ_array_set(CircArray ca, VALUE obj, unsigned long id) {
344
347
  if (0 < id) {
345
- unsigned long i;
348
+ unsigned long i;
346
349
 
347
- if (ca->size < id) {
348
- unsigned long cnt = id + 512;
350
+ if (ca->size < id) {
351
+ unsigned long cnt = id + 512;
349
352
 
350
- if (ca->objs == ca->obj_array) {
351
- ca->objs = ALLOC_N(VALUE, cnt);
352
- memcpy(ca->objs, ca->obj_array, sizeof(VALUE) * ca->cnt);
353
- } else {
353
+ if (ca->objs == ca->obj_array) {
354
+ ca->objs = ALLOC_N(VALUE, cnt);
355
+ memcpy(ca->objs, ca->obj_array, sizeof(VALUE) * ca->cnt);
356
+ } else {
354
357
  REALLOC_N(ca->objs, VALUE, cnt);
355
- }
356
- ca->size = cnt;
357
- }
358
- id--;
359
- for (i = ca->cnt; i < id; i++) {
360
- ca->objs[i] = Qundef;
361
- }
362
- ca->objs[id] = obj;
363
- if (ca->cnt <= id) {
364
- ca->cnt = id + 1;
365
- }
358
+ }
359
+ ca->size = cnt;
360
+ }
361
+ id--;
362
+ for (i = ca->cnt; i < id; i++) {
363
+ ca->objs[i] = Qundef;
364
+ }
365
+ ca->objs[id] = obj;
366
+ if (ca->cnt <= id) {
367
+ ca->cnt = id + 1;
368
+ }
366
369
  }
367
370
  }
368
371
 
369
372
  static VALUE
370
373
  circ_array_get(CircArray ca, unsigned long id) {
371
- VALUE obj = Qundef;
374
+ VALUE obj = Qundef;
372
375
 
373
376
  if (id <= ca->cnt) {
374
- obj = ca->objs[id - 1];
377
+ obj = ca->objs[id - 1];
375
378
  }
376
379
  return obj;
377
380
  }
378
381
 
379
382
  static VALUE
380
383
  parse_regexp(const char *text) {
381
- const char *te;
382
- int options = 0;
383
-
384
+ const char *te;
385
+ int options = 0;
386
+
384
387
  te = text + strlen(text) - 1;
385
388
  #if HAS_ONIG
386
389
  for (; text < te && '/' != *te; te--) {
387
- switch (*te) {
388
- case 'i': options |= ONIG_OPTION_IGNORECASE; break;
389
- case 'm': options |= ONIG_OPTION_MULTILINE; break;
390
- case 'x': options |= ONIG_OPTION_EXTEND; break;
391
- default: break;
392
- }
390
+ switch (*te) {
391
+ case 'i': options |= ONIG_OPTION_IGNORECASE; break;
392
+ case 'm': options |= ONIG_OPTION_MULTILINE; break;
393
+ case 'x': options |= ONIG_OPTION_EXTEND; break;
394
+ default: break;
395
+ }
393
396
  }
394
397
  #endif
395
398
  return rb_reg_new(text + 1, te - text - 1, options);
@@ -399,214 +402,221 @@ static void
399
402
  instruct(PInfo pi, const char *target, Attr attrs, const char *content) {
400
403
  if (0 == strcmp("xml", target)) {
401
404
  #if HAS_ENCODING_SUPPORT
402
- for (; 0 != attrs->name; attrs++) {
403
- if (0 == strcmp("encoding", attrs->name)) {
404
- pi->options->rb_enc = rb_enc_find(attrs->value);
405
- }
406
- }
405
+ for (; 0 != attrs->name; attrs++) {
406
+ if (0 == strcmp("encoding", attrs->name)) {
407
+ pi->options->rb_enc = rb_enc_find(attrs->value);
408
+ }
409
+ }
407
410
  #elif HAS_PRIVATE_ENCODING
408
- for (; 0 != attrs->name; attrs++) {
409
- if (0 == strcmp("encoding", attrs->name)) {
410
- pi->options->rb_enc = rb_str_new2(attrs->value);
411
- }
412
- }
411
+ for (; 0 != attrs->name; attrs++) {
412
+ if (0 == strcmp("encoding", attrs->name)) {
413
+ pi->options->rb_enc = rb_str_new2(attrs->value);
414
+ }
415
+ }
413
416
  #endif
414
417
  }
415
418
  }
416
419
 
417
420
  static void
418
421
  add_text(PInfo pi, char *text, int closed) {
422
+ Helper h = helper_stack_peek(&pi->helpers);
423
+
419
424
  if (!closed) {
420
- raise_error("Text not closed", pi->str, pi->s);
425
+ set_error(&pi->err, "Text not closed", pi->str, pi->s);
426
+ return;
427
+ }
428
+ if (0 == h) {
429
+ set_error(&pi->err, "Unexpected text", pi->str, pi->s);
430
+ return;
421
431
  }
422
432
  if (DEBUG <= pi->options->trace) {
423
- char indent[128];
433
+ char indent[128];
424
434
 
425
- fill_indent(pi, indent, sizeof(indent));
426
- printf("%s '%s' to type %c\n", indent, text, pi->h->type);
435
+ fill_indent(pi, indent, sizeof(indent));
436
+ printf("%s '%s' to type %c\n", indent, text, h->type);
427
437
  }
428
- switch (pi->h->type) {
438
+ switch (h->type) {
429
439
  case NoCode:
430
440
  case StringCode:
431
- pi->h->obj = rb_str_new2(text);
441
+ h->obj = rb_str_new2(text);
432
442
  #if HAS_ENCODING_SUPPORT
433
- if (0 != pi->options->rb_enc) {
434
- rb_enc_associate(pi->h->obj, pi->options->rb_enc);
435
- }
443
+ if (0 != pi->options->rb_enc) {
444
+ rb_enc_associate(h->obj, pi->options->rb_enc);
445
+ }
436
446
  #elif HAS_PRIVATE_ENCODING
437
- if (Qnil != pi->options->rb_enc) {
438
- rb_funcall(pi->h->obj, ox_force_encoding_id, 1, pi->options->rb_enc);
439
- }
447
+ if (Qnil != pi->options->rb_enc) {
448
+ rb_funcall(h->obj, ox_force_encoding_id, 1, pi->options->rb_enc);
449
+ }
440
450
  #endif
441
- if (0 != pi->circ_array) {
442
- circ_array_set(pi->circ_array, pi->h->obj, (unsigned long)pi->id);
443
- }
444
- break;
451
+ if (0 != pi->circ_array) {
452
+ circ_array_set(pi->circ_array, h->obj, (unsigned long)pi->id);
453
+ }
454
+ break;
445
455
  case FixnumCode:
446
456
  {
447
- long n = 0;
448
- char c;
449
- int neg = 0;
450
-
451
- if ('-' == *text) {
452
- neg = 1;
453
- text++;
454
- }
455
- for (; '\0' != *text; text++) {
456
- c = *text;
457
- if ('0' <= c && c <= '9') {
458
- n = n * 10 + (c - '0');
459
- } else {
460
- raise_error("bad number format", pi->str, pi->s);
461
- }
462
- }
463
- if (neg) {
464
- n = -n;
465
- }
466
- pi->h->obj = LONG2NUM(n);
467
- break;
457
+ long n = 0;
458
+ char c;
459
+ int neg = 0;
460
+
461
+ if ('-' == *text) {
462
+ neg = 1;
463
+ text++;
464
+ }
465
+ for (; '\0' != *text; text++) {
466
+ c = *text;
467
+ if ('0' <= c && c <= '9') {
468
+ n = n * 10 + (c - '0');
469
+ } else {
470
+ set_error(&pi->err, "bad number format", pi->str, pi->s);
471
+ return;
472
+ }
473
+ }
474
+ if (neg) {
475
+ n = -n;
476
+ }
477
+ h->obj = LONG2NUM(n);
478
+ break;
468
479
  }
469
480
  case FloatCode:
470
- pi->h->obj = rb_float_new(strtod(text, 0));
471
- break;
481
+ h->obj = rb_float_new(strtod(text, 0));
482
+ break;
472
483
  case SymbolCode:
473
484
  {
474
- VALUE sym;
475
- VALUE *slot;
485
+ VALUE sym;
486
+ VALUE *slot;
476
487
 
477
- if (Qundef == (sym = ox_cache_get(ox_symbol_cache, text, &slot, 0))) {
488
+ if (Qundef == (sym = ox_cache_get(ox_symbol_cache, text, &slot, 0))) {
478
489
  sym = str2sym(text, (void*)pi->options->rb_enc);
479
- *slot = sym;
480
- }
481
- pi->h->obj = sym;
482
- break;
490
+ *slot = sym;
491
+ }
492
+ h->obj = sym;
493
+ break;
483
494
  }
484
495
  case DateCode:
485
496
  {
486
497
  VALUE args[1];
487
498
 
488
- *args = parse_ulong(text, pi);
489
- pi->h->obj = rb_funcall2(ox_date_class, ox_jd_id, 1, args);
490
- break;
499
+ if (Qundef == (*args = parse_ulong(text, pi))) {
500
+ return;
501
+ }
502
+ h->obj = rb_funcall2(ox_date_class, ox_jd_id, 1, args);
503
+ break;
491
504
  }
492
505
  case TimeCode:
493
- pi->h->obj = parse_time(text, ox_time_class);
494
- break;
506
+ h->obj = parse_time(text, ox_time_class);
507
+ break;
495
508
  case String64Code:
496
509
  {
497
- unsigned long str_size = b64_orig_size(text);
498
- VALUE v;
499
- char *str = ALLOCA_N(char, str_size + 1);
500
-
501
- from_base64(text, (uchar*)str);
502
- v = rb_str_new(str, str_size);
510
+ unsigned long str_size = b64_orig_size(text);
511
+ VALUE v;
512
+ char *str = ALLOCA_N(char, str_size + 1);
513
+
514
+ from_base64(text, (uchar*)str);
515
+ v = rb_str_new(str, str_size);
503
516
  #if HAS_ENCODING_SUPPORT
504
- if (0 != pi->options->rb_enc) {
505
- rb_enc_associate(v, pi->options->rb_enc);
506
- }
517
+ if (0 != pi->options->rb_enc) {
518
+ rb_enc_associate(v, pi->options->rb_enc);
519
+ }
507
520
  #elif HAS_PRIVATE_ENCODING
508
- if (0 != pi->options->rb_enc) {
521
+ if (0 != pi->options->rb_enc) {
509
522
  rb_funcall(v, ox_force_encoding_id, 1, pi->options->rb_enc);
510
- }
523
+ }
511
524
  #endif
512
- if (0 != pi->circ_array) {
513
- circ_array_set(pi->circ_array, v, (unsigned long)pi->h->obj);
514
- }
515
- pi->h->obj = v;
516
- break;
525
+ if (0 != pi->circ_array) {
526
+ circ_array_set(pi->circ_array, v, (unsigned long)h->obj);
527
+ }
528
+ h->obj = v;
529
+ break;
517
530
  }
518
531
  case Symbol64Code:
519
532
  {
520
- VALUE sym;
521
- VALUE *slot;
522
- unsigned long str_size = b64_orig_size(text);
523
- char *str = ALLOCA_N(char, str_size + 1);
524
-
525
- from_base64(text, (uchar*)str);
526
- if (Qundef == (sym = ox_cache_get(ox_symbol_cache, str, &slot, 0))) {
533
+ VALUE sym;
534
+ VALUE *slot;
535
+ unsigned long str_size = b64_orig_size(text);
536
+ char *str = ALLOCA_N(char, str_size + 1);
537
+
538
+ from_base64(text, (uchar*)str);
539
+ if (Qundef == (sym = ox_cache_get(ox_symbol_cache, str, &slot, 0))) {
527
540
  sym = str2sym(str, (void*)pi->options->rb_enc);
528
- *slot = sym;
529
- }
530
- pi->h->obj = sym;
531
- break;
541
+ *slot = sym;
542
+ }
543
+ h->obj = sym;
544
+ break;
532
545
  }
533
546
  case RegexpCode:
534
- if ('/' == *text) {
535
- pi->h->obj = parse_regexp(text);
536
- } else {
537
- unsigned long str_size = b64_orig_size(text);
547
+ if ('/' == *text) {
548
+ h->obj = parse_regexp(text);
549
+ } else {
550
+ unsigned long str_size = b64_orig_size(text);
538
551
  char *str = ALLOCA_N(char, str_size + 1);
539
-
540
- from_base64(text, (uchar*)str);
541
- pi->h->obj = parse_regexp(str);
542
- }
543
- break;
552
+
553
+ from_base64(text, (uchar*)str);
554
+ h->obj = parse_regexp(str);
555
+ }
556
+ break;
544
557
  case BignumCode:
545
- pi->h->obj = rb_cstr_to_inum(text, 10, 1);
546
- break;
558
+ h->obj = rb_cstr_to_inum(text, 10, 1);
559
+ break;
547
560
  default:
548
- pi->h->obj = Qnil;
549
- break;
561
+ h->obj = Qnil;
562
+ break;
550
563
  }
551
564
  }
552
565
 
553
566
  static void
554
567
  add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren) {
555
- Attr a;
556
- Helper h;
557
- unsigned long id;
568
+ Attr a;
569
+ Helper h;
570
+ unsigned long id;
558
571
 
559
572
  if (TRACE <= pi->options->trace) {
560
- char buf[1024];
561
- char indent[128];
562
- char *s = buf;
563
- char *end = buf + sizeof(buf) - 2;
564
-
565
- s += snprintf(s, end - s, " <%s%s", (hasChildren) ? "" : "/", ename);
566
- for (a = attrs; 0 != a->name; a++) {
567
- s += snprintf(s, end - s, " %s=%s", a->name, a->value);
568
- }
569
- *s++ = '>';
570
- *s++ = '\0';
571
- if (DEBUG <= pi->options->trace) {
572
- debug_stack(pi, buf);
573
- } else {
574
- fill_indent(pi, indent, sizeof(indent));
575
- printf("%s%s\n", indent, buf);
576
- }
577
- }
578
- if (0 == pi->h) { /* top level object */
579
- pi->h = pi->helpers;
580
- if (0 != (id = get_id_from_attrs(pi, attrs))) {
581
- pi->circ_array = circ_array_new();
582
- }
583
- } else {
584
- pi->h++;
573
+ char buf[1024];
574
+ char indent[128];
575
+ char *s = buf;
576
+ char *end = buf + sizeof(buf) - 2;
577
+
578
+ s += snprintf(s, end - s, " <%s%s", (hasChildren) ? "" : "/", ename);
579
+ for (a = attrs; 0 != a->name; a++) {
580
+ s += snprintf(s, end - s, " %s=%s", a->name, a->value);
581
+ }
582
+ *s++ = '>';
583
+ *s++ = '\0';
584
+ if (DEBUG <= pi->options->trace) {
585
+ printf("===== add element stack(%d) =====\n", helper_stack_depth(&pi->helpers));
586
+ debug_stack(pi, buf);
587
+ } else {
588
+ fill_indent(pi, indent, sizeof(indent));
589
+ printf("%s%s\n", indent, buf);
590
+ }
591
+ }
592
+ if (helper_stack_empty(&pi->helpers)) { /* top level object */
593
+ if (0 != (id = get_id_from_attrs(pi, attrs))) {
594
+ pi->circ_array = circ_array_new();
595
+ }
585
596
  }
586
597
  if ('\0' != ename[1]) {
587
- raise_error("Invalid element name", pi->str, pi->s);
598
+ set_error(&pi->err, "Invalid element name", pi->str, pi->s);
599
+ return;
588
600
  }
589
- h = pi->h;
590
- h->type = *ename;
591
- h->var = get_var_sym_from_attrs(attrs, (void*)pi->options->rb_enc);
601
+ h = helper_stack_push(&pi->helpers, get_var_sym_from_attrs(attrs, (void*)pi->options->rb_enc), Qundef, *ename);
592
602
  switch (h->type) {
593
603
  case NilClassCode:
594
- h->obj = Qnil;
595
- break;
604
+ h->obj = Qnil;
605
+ break;
596
606
  case TrueClassCode:
597
- h->obj = Qtrue;
598
- break;
607
+ h->obj = Qtrue;
608
+ break;
599
609
  case FalseClassCode:
600
- h->obj = Qfalse;
601
- break;
610
+ h->obj = Qfalse;
611
+ break;
602
612
  case StringCode:
603
- /* h->obj will be replaced by add_text if it is called */
604
- h->obj = ox_empty_string;
605
- if (0 != pi->circ_array) {
606
- pi->id = get_id_from_attrs(pi, attrs);
607
- circ_array_set(pi->circ_array, h->obj, pi->id);
608
- }
609
- break;
613
+ /* h->obj will be replaced by add_text if it is called */
614
+ h->obj = ox_empty_string;
615
+ if (0 != pi->circ_array) {
616
+ pi->id = get_id_from_attrs(pi, attrs);
617
+ circ_array_set(pi->circ_array, h->obj, pi->id);
618
+ }
619
+ break;
610
620
  case FixnumCode:
611
621
  case FloatCode:
612
622
  case SymbolCode:
@@ -617,213 +627,235 @@ add_element(PInfo pi, const char *ename, Attr attrs, int hasChildren) {
617
627
  case DateCode:
618
628
  case TimeCode:
619
629
  case RationalCode: /* sub elements read next */
620
- /* value will be read in the following add_text */
621
- h->obj = Qundef;
622
- break;
630
+ /* value will be read in the following add_text */
631
+ h->obj = Qundef;
632
+ break;
623
633
  case String64Code:
624
- h->obj = Qundef;
625
- if (0 != pi->circ_array) {
626
- pi->id = get_id_from_attrs(pi, attrs);
627
- }
628
- break;
634
+ h->obj = Qundef;
635
+ if (0 != pi->circ_array) {
636
+ pi->id = get_id_from_attrs(pi, attrs);
637
+ }
638
+ break;
629
639
  case ArrayCode:
630
- h->obj = rb_ary_new();
631
- if (0 != pi->circ_array) {
632
- circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
633
- }
634
- break;
640
+ h->obj = rb_ary_new();
641
+ if (0 != pi->circ_array) {
642
+ circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
643
+ }
644
+ break;
635
645
  case HashCode:
636
- h->obj = rb_hash_new();
637
- if (0 != pi->circ_array) {
638
- circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
639
- }
640
- break;
646
+ h->obj = rb_hash_new();
647
+ if (0 != pi->circ_array) {
648
+ circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
649
+ }
650
+ break;
641
651
  case RangeCode:
642
- h->obj = rb_range_new(ox_zero_fixnum, ox_zero_fixnum, Qfalse);
643
- break;
652
+ h->obj = rb_range_new(ox_zero_fixnum, ox_zero_fixnum, Qfalse);
653
+ break;
644
654
  case RawCode:
645
- if (hasChildren) {
646
- h->obj = ox_parse(pi->s, ox_gen_callbacks, &pi->s, pi->options);
647
- if (0 != pi->circ_array) {
648
- circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
649
- }
650
- } else {
651
- h->obj = Qnil;
652
- }
653
- break;
655
+ if (hasChildren) {
656
+ h->obj = ox_parse(pi->s, ox_gen_callbacks, &pi->s, pi->options, &pi->err);
657
+ if (0 != pi->circ_array) {
658
+ circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
659
+ }
660
+ } else {
661
+ h->obj = Qnil;
662
+ }
663
+ break;
654
664
  case ExceptionCode:
655
- h->obj = get_obj_from_attrs(attrs, pi, rb_eException);
656
- if (0 != pi->circ_array && Qnil != h->obj) {
657
- circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
658
- }
659
- break;
665
+ if (Qundef == (h->obj = get_obj_from_attrs(attrs, pi, rb_eException))) {
666
+ return;
667
+ }
668
+ if (0 != pi->circ_array && Qnil != h->obj) {
669
+ circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
670
+ }
671
+ break;
660
672
  case ObjectCode:
661
- h->obj = get_obj_from_attrs(attrs, pi, ox_bag_clas);
662
- if (0 != pi->circ_array && Qnil != h->obj) {
663
- circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
664
- }
665
- break;
673
+ if (Qundef == (h->obj = get_obj_from_attrs(attrs, pi, ox_bag_clas))) {
674
+ return;
675
+ }
676
+ if (0 != pi->circ_array && Qnil != h->obj) {
677
+ circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
678
+ }
679
+ break;
666
680
  case StructCode:
667
681
  #if HAS_RSTRUCT
668
- h->obj = get_struct_from_attrs(attrs);
669
- if (0 != pi->circ_array) {
670
- circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
671
- }
682
+ h->obj = get_struct_from_attrs(attrs);
683
+ if (0 != pi->circ_array) {
684
+ circ_array_set(pi->circ_array, h->obj, get_id_from_attrs(pi, attrs));
685
+ }
672
686
  #else
673
- raise_error("Ruby structs not supported with this verion of Ruby", pi->str, pi->s);
687
+ set_error(&pi->err, "Ruby structs not supported with this verion of Ruby", pi->str, pi->s);
688
+ return;
674
689
  #endif
675
- break;
690
+ break;
676
691
  case ClassCode:
677
- h->obj = get_class_from_attrs(attrs, pi, ox_bag_clas);
678
- break;
692
+ if (Qundef == (h->obj = get_class_from_attrs(attrs, pi, ox_bag_clas))) {
693
+ return;
694
+ }
695
+ break;
679
696
  case RefCode:
680
- h->obj = Qundef;
681
- if (0 != pi->circ_array) {
682
- h->obj = circ_array_get(pi->circ_array, get_id_from_attrs(pi, attrs));
683
- }
684
- if (Qundef == h->obj) {
685
- raise_error("Invalid circular reference", pi->str, pi->s);
686
- }
687
- break;
697
+ h->obj = Qundef;
698
+ if (0 != pi->circ_array) {
699
+ h->obj = circ_array_get(pi->circ_array, get_id_from_attrs(pi, attrs));
700
+ }
701
+ if (Qundef == h->obj) {
702
+ set_error(&pi->err, "Invalid circular reference", pi->str, pi->s);
703
+ return;
704
+ }
705
+ break;
688
706
  default:
689
- raise_error("Invalid element name", pi->str, pi->s);
690
- break;
707
+ set_error(&pi->err, "Invalid element name", pi->str, pi->s);
708
+ return;
709
+ break;
691
710
  }
692
711
  if (DEBUG <= pi->options->trace) {
693
- debug_stack(pi, " -----------");
712
+ debug_stack(pi, " -----------");
694
713
  }
695
714
  }
696
715
 
697
716
  static void
698
717
  end_element(PInfo pi, const char *ename) {
699
718
  if (TRACE <= pi->options->trace) {
700
- char indent[128];
701
-
702
- if (DEBUG <= pi->options->trace) {
703
- char buf[1024];
704
-
705
- snprintf(buf, sizeof(buf) - 1, "</%s>", ename);
706
- debug_stack(pi, buf);
707
- } else {
708
- fill_indent(pi, indent, sizeof(indent));
709
- printf("%s</%s>\n", indent, ename);
710
- }
711
- }
712
- if (0 != pi->h && pi->helpers <= pi->h) {
713
- Helper h = pi->h;
714
-
715
- if (ox_empty_string == h->obj) {
716
- /* special catch for empty strings */
717
- h->obj = rb_str_new2("");
718
- }
719
- pi->obj = h->obj;
720
- pi->h--;
721
- if (pi->helpers <= pi->h) {
722
- switch (pi->h->type) {
723
- case ArrayCode:
724
- rb_ary_push(pi->h->obj, h->obj);
725
- break;
726
- case ExceptionCode:
727
- case ObjectCode:
728
- if (Qnil != pi->h->obj) {
729
- rb_ivar_set(pi->h->obj, h->var, h->obj);
730
- }
731
- break;
732
- case StructCode:
719
+ char indent[128];
720
+
721
+ if (DEBUG <= pi->options->trace) {
722
+ char buf[1024];
723
+
724
+ printf("===== end element stack(%d) =====\n", helper_stack_depth(&pi->helpers));
725
+ snprintf(buf, sizeof(buf) - 1, "</%s>", ename);
726
+ debug_stack(pi, buf);
727
+ } else {
728
+ fill_indent(pi, indent, sizeof(indent));
729
+ printf("%s</%s>\n", indent, ename);
730
+ }
731
+ }
732
+ if (!helper_stack_empty(&pi->helpers)) {
733
+ Helper h = helper_stack_pop(&pi->helpers);
734
+ Helper ph = helper_stack_peek(&pi->helpers);
735
+
736
+ if (ox_empty_string == h->obj) {
737
+ /* special catch for empty strings */
738
+ h->obj = rb_str_new2("");
739
+ }
740
+ pi->obj = h->obj;
741
+ if (0 != ph) {
742
+ switch (ph->type) {
743
+ case ArrayCode:
744
+ rb_ary_push(ph->obj, h->obj);
745
+ break;
746
+ case ExceptionCode:
747
+ case ObjectCode:
748
+ if (Qnil != ph->obj) {
749
+ rb_ivar_set(ph->obj, h->var, h->obj);
750
+ }
751
+ break;
752
+ case StructCode:
733
753
  #if HAS_RSTRUCT
734
- rb_struct_aset(pi->h->obj, h->var, h->obj);
754
+ rb_struct_aset(ph->obj, h->var, h->obj);
735
755
  #else
736
- raise_error("Ruby structs not supported with this verion of Ruby", pi->str, pi->s);
756
+ set_error(&pi->err, "Ruby structs not supported with this verion of Ruby", pi->str, pi->s);
757
+ return;
737
758
  #endif
738
- break;
739
- case HashCode:
740
- h->type = KeyCode;
741
- pi->h++;
742
- break;
743
- case RangeCode:
759
+ break;
760
+ case HashCode:
761
+ // put back h
762
+ helper_stack_push(&pi->helpers, h->var, h->obj, KeyCode);
763
+ break;
764
+ case RangeCode:
744
765
  #if HAS_RSTRUCT
745
- if (ox_beg_id == h->var) {
746
- RSTRUCT_PTR(pi->h->obj)[0] = h->obj;
747
- } else if (ox_end_id == h->var) {
748
- RSTRUCT_PTR(pi->h->obj)[1] = h->obj;
749
- } else if (ox_excl_id == h->var) {
750
- RSTRUCT_PTR(pi->h->obj)[2] = h->obj;
751
- } else {
752
- raise_error("Invalid range attribute", pi->str, pi->s);
753
- }
766
+ if (ox_beg_id == h->var) {
767
+ RSTRUCT_PTR(ph->obj)[0] = h->obj;
768
+ } else if (ox_end_id == h->var) {
769
+ RSTRUCT_PTR(ph->obj)[1] = h->obj;
770
+ } else if (ox_excl_id == h->var) {
771
+ RSTRUCT_PTR(ph->obj)[2] = h->obj;
772
+ } else {
773
+ set_error(&pi->err, "Invalid range attribute", pi->str, pi->s);
774
+ return;
775
+ }
754
776
  #else
755
- raise_error("Ruby structs not supported with this verion of Ruby", pi->str, pi->s);
777
+ set_error(&pi->err, "Ruby structs not supported with this verion of Ruby", pi->str, pi->s);
778
+ return;
756
779
  #endif
757
- break;
758
- case KeyCode:
759
- rb_hash_aset((pi->h - 1)->obj, pi->h->obj, h->obj);
760
- pi->h--;
761
- break;
762
- case ComplexCode:
780
+ break;
781
+ case KeyCode:
782
+ {
783
+ Helper gh;
784
+
785
+ helper_stack_pop(&pi->helpers);
786
+ gh = helper_stack_peek(&pi->helpers);
787
+
788
+ rb_hash_aset(gh->obj, ph->obj, h->obj);
789
+ }
790
+ break;
791
+ case ComplexCode:
763
792
  #ifdef T_COMPLEX
764
- if (Qundef == pi->h->obj) {
765
- pi->h->obj = h->obj;
766
- } else {
767
- pi->h->obj = rb_complex_new(pi->h->obj, h->obj);
768
- }
793
+ if (Qundef == ph->obj) {
794
+ ph->obj = h->obj;
795
+ } else {
796
+ ph->obj = rb_complex_new(ph->obj, h->obj);
797
+ }
769
798
  #else
770
- raise_error("Complex Objects not implemented in Ruby 1.8.7", pi->str, pi->s);
799
+ set_error(&pi->err, "Complex Objects not implemented in Ruby 1.8.7", pi->str, pi->s);
800
+ return;
771
801
  #endif
772
- break;
773
- case RationalCode:
802
+ break;
803
+ case RationalCode:
774
804
  #ifdef T_RATIONAL
775
- if (Qundef == pi->h->obj) {
776
- pi->h->obj = h->obj;
777
- } else {
805
+ if (Qundef == ph->obj) {
806
+ ph->obj = h->obj;
807
+ } else {
778
808
  #ifdef RUBINIUS_RUBY
779
- pi->h->obj = rb_Rational(pi->h->obj, h->obj);
809
+ ph->obj = rb_Rational(ph->obj, h->obj);
780
810
  #else
781
- pi->h->obj = rb_rational_new(pi->h->obj, h->obj);
811
+ ph->obj = rb_rational_new(ph->obj, h->obj);
782
812
  #endif
783
- }
813
+ }
784
814
  #else
785
- raise_error("Rational Objects not implemented in Ruby 1.8.7", pi->str, pi->s);
815
+ set_error(&pi->err, "Rational Objects not implemented in Ruby 1.8.7", pi->str, pi->s);
816
+ return;
786
817
  #endif
787
- break;
788
- default:
789
- raise_error("Corrupt parse stack, container is wrong type", pi->str, pi->s);
790
- break;
791
- }
792
- }
818
+ break;
819
+ default:
820
+ set_error(&pi->err, "Corrupt parse stack, container is wrong type", pi->str, pi->s);
821
+ return;
822
+ break;
823
+ }
824
+ }
793
825
  }
794
- if (0 != pi->circ_array && pi->helpers > pi->h) {
795
- circ_array_free(pi->circ_array);
796
- pi->circ_array = 0;
826
+ if (0 != pi->circ_array && helper_stack_empty(&pi->helpers)) {
827
+ circ_array_free(pi->circ_array);
828
+ pi->circ_array = 0;
797
829
  }
798
830
  if (DEBUG <= pi->options->trace) {
799
- debug_stack(pi, " ----------");
831
+ debug_stack(pi, " ----------");
800
832
  }
801
833
  }
802
834
 
803
835
  static VALUE
804
836
  parse_double_time(const char *text, VALUE clas) {
805
- long v = 0;
806
- long v2 = 0;
807
- const char *dot = 0;
808
- char c;
837
+ long v = 0;
838
+ long v2 = 0;
839
+ const char *dot = 0;
840
+ char c;
809
841
 
810
842
  for (; '.' != *text; text++) {
811
- c = *text;
812
- if (c < '0' || '9' < c) {
813
- return Qnil;
814
- }
815
- v = 10 * v + (long)(c - '0');
843
+ c = *text;
844
+ if (c < '0' || '9' < c) {
845
+ return Qnil;
846
+ }
847
+ v = 10 * v + (long)(c - '0');
816
848
  }
817
849
  dot = text++;
818
850
  for (; '\0' != *text && text - dot <= 6; text++) {
819
- c = *text;
820
- if (c < '0' || '9' < c) {
821
- return Qnil;
822
- }
823
- v2 = 10 * v2 + (long)(c - '0');
851
+ c = *text;
852
+ if (c < '0' || '9' < c) {
853
+ return Qnil;
854
+ }
855
+ v2 = 10 * v2 + (long)(c - '0');
824
856
  }
825
857
  for (; text - dot <= 9; text++) {
826
- v2 *= 10;
858
+ v2 *= 10;
827
859
  }
828
860
  #if HAS_NANO_TIME
829
861
  return rb_time_nano_new(v, v2);
@@ -833,47 +865,47 @@ parse_double_time(const char *text, VALUE clas) {
833
865
  }
834
866
 
835
867
  typedef struct _Tp {
836
- int cnt;
837
- char end;
838
- char alt;
868
+ int cnt;
869
+ char end;
870
+ char alt;
839
871
  } *Tp;
840
872
 
841
873
  static VALUE
842
874
  parse_xsd_time(const char *text, VALUE clas) {
843
- long cargs[10];
844
- long *cp = cargs;
845
- long v;
846
- int i;
847
- char c;
848
- struct _Tp tpa[10] = { { 4, '-', '-' },
849
- { 2, '-', '-' },
850
- { 2, 'T', 'T' },
851
- { 2, ':', ':' },
852
- { 2, ':', ':' },
853
- { 2, '.', '.' },
854
- { 9, '+', '-' },
855
- { 2, ':', ':' },
856
- { 2, '\0', '\0' },
857
- { 0, '\0', '\0' } };
858
- Tp tp = tpa;
859
- struct tm tm;
875
+ long cargs[10];
876
+ long *cp = cargs;
877
+ long v;
878
+ int i;
879
+ char c;
880
+ struct _Tp tpa[10] = { { 4, '-', '-' },
881
+ { 2, '-', '-' },
882
+ { 2, 'T', 'T' },
883
+ { 2, ':', ':' },
884
+ { 2, ':', ':' },
885
+ { 2, '.', '.' },
886
+ { 9, '+', '-' },
887
+ { 2, ':', ':' },
888
+ { 2, '\0', '\0' },
889
+ { 0, '\0', '\0' } };
890
+ Tp tp = tpa;
891
+ struct tm tm;
860
892
 
861
893
  for (; 0 != tp->cnt; tp++) {
862
- for (i = tp->cnt, v = 0; 0 < i ; text++, i--) {
863
- c = *text;
864
- if (c < '0' || '9' < c) {
865
- if (tp->end == c || tp->alt == c) {
866
- break;
867
- }
868
- return Qnil;
869
- }
870
- v = 10 * v + (long)(c - '0');
871
- }
872
- c = *text++;
873
- if (tp->end != c && tp->alt != c) {
874
- return Qnil;
875
- }
876
- *cp++ = v;
894
+ for (i = tp->cnt, v = 0; 0 < i ; text++, i--) {
895
+ c = *text;
896
+ if (c < '0' || '9' < c) {
897
+ if (tp->end == c || tp->alt == c) {
898
+ break;
899
+ }
900
+ return Qnil;
901
+ }
902
+ v = 10 * v + (long)(c - '0');
903
+ }
904
+ c = *text++;
905
+ if (tp->end != c && tp->alt != c) {
906
+ return Qnil;
907
+ }
908
+ *cp++ = v;
877
909
  }
878
910
  tm.tm_year = (int)cargs[0] - 1900;
879
911
  tm.tm_mon = (int)cargs[1] - 1;
@@ -891,48 +923,49 @@ parse_xsd_time(const char *text, VALUE clas) {
891
923
  /* debug functions */
892
924
  static void
893
925
  fill_indent(PInfo pi, char *buf, size_t size) {
894
- if (0 != pi->h) {
895
- size_t cnt = pi->h - pi->helpers + 1;
926
+ size_t cnt;
896
927
 
897
- if (size < cnt + 1) {
898
- cnt = size - 1;
899
- }
900
- memset(buf, ' ', cnt);
901
- buf += cnt;
928
+ if (0 < (cnt = helper_stack_depth(&pi->helpers))) {
929
+ cnt *= 2;
930
+ if (size < cnt + 1) {
931
+ cnt = size - 1;
932
+ }
933
+ memset(buf, ' ', cnt);
934
+ buf += cnt;
902
935
  }
903
936
  *buf = '\0';
904
937
  }
905
938
 
906
939
  static void
907
940
  debug_stack(PInfo pi, const char *comment) {
908
- char indent[128];
909
- Helper h;
941
+ char indent[128];
942
+ Helper h;
910
943
 
911
944
  fill_indent(pi, indent, sizeof(indent));
912
945
  printf("%s%s\n", indent, comment);
913
- if (0 != pi->h) {
914
- for (h = pi->helpers; h <= pi->h; h++) {
915
- const char *clas = "---";
916
- const char *key = "---";
917
-
918
- if (Qundef != h->obj) {
919
- VALUE c = rb_obj_class(h->obj);
920
-
921
- clas = rb_class2name(c);
922
- }
923
- if (Qundef != h->var) {
924
- if (HashCode == h->type) {
925
- VALUE v;
926
-
927
- v = rb_funcall2(h->var, rb_intern("to_s"), 0, 0);
928
- key = StringValuePtr(v);
929
- } else if (ObjectCode == (h - 1)->type || ExceptionCode == (h - 1)->type || RangeCode == (h - 1)->type || StructCode == (h - 1)->type) {
930
- key = rb_id2name(h->var);
931
- } else {
932
- printf("%s*** corrupt stack ***\n", indent);
933
- }
934
- }
935
- printf("%s [%c] %s : %s\n", indent, h->type, clas, key);
936
- }
946
+ if (!helper_stack_empty(&pi->helpers)) {
947
+ for (h = pi->helpers.head; h < pi->helpers.tail; h++) {
948
+ const char *clas = "---";
949
+ const char *key = "---";
950
+
951
+ if (Qundef != h->obj) {
952
+ VALUE c = rb_obj_class(h->obj);
953
+
954
+ clas = rb_class2name(c);
955
+ }
956
+ if (Qundef != h->var) {
957
+ if (HashCode == h->type) {
958
+ VALUE v;
959
+
960
+ v = rb_funcall2(h->var, rb_intern("to_s"), 0, 0);
961
+ key = StringValuePtr(v);
962
+ } else if (ObjectCode == (h - 1)->type || ExceptionCode == (h - 1)->type || RangeCode == (h - 1)->type || StructCode == (h - 1)->type) {
963
+ key = rb_id2name(h->var);
964
+ } else {
965
+ printf("%s*** corrupt stack ***\n", indent);
966
+ }
967
+ }
968
+ printf("%s [%c] %s : %s\n", indent, h->type, clas, key);
969
+ }
937
970
  }
938
971
  }