ruby_rnv 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +3 -0
  3. data/ext/rnv/extconf.rb +15 -0
  4. data/ext/rnv/ruby_rnv.c +742 -0
  5. data/ext/rnv/src/ary.c +78 -0
  6. data/ext/rnv/src/ary.h +10 -0
  7. data/ext/rnv/src/drv.c +472 -0
  8. data/ext/rnv/src/drv.h +35 -0
  9. data/ext/rnv/src/er.c +15 -0
  10. data/ext/rnv/src/er.h +16 -0
  11. data/ext/rnv/src/erbit.h +14 -0
  12. data/ext/rnv/src/ht.c +90 -0
  13. data/ext/rnv/src/ht.h +22 -0
  14. data/ext/rnv/src/ll.h +43 -0
  15. data/ext/rnv/src/m.c +60 -0
  16. data/ext/rnv/src/m.h +10 -0
  17. data/ext/rnv/src/rn.c +569 -0
  18. data/ext/rnv/src/rn.h +150 -0
  19. data/ext/rnv/src/rnc.c +1191 -0
  20. data/ext/rnv/src/rnc.h +68 -0
  21. data/ext/rnv/src/rnd.c +436 -0
  22. data/ext/rnv/src/rnd.h +25 -0
  23. data/ext/rnv/src/rnl.c +62 -0
  24. data/ext/rnv/src/rnl.h +18 -0
  25. data/ext/rnv/src/rnv.c +158 -0
  26. data/ext/rnv/src/rnv.h +30 -0
  27. data/ext/rnv/src/rnx.c +153 -0
  28. data/ext/rnv/src/rnx.h +16 -0
  29. data/ext/rnv/src/rx.c +749 -0
  30. data/ext/rnv/src/rx.h +43 -0
  31. data/ext/rnv/src/rx_cls_ranges.c +126 -0
  32. data/ext/rnv/src/rx_cls_u.c +262 -0
  33. data/ext/rnv/src/s.c +103 -0
  34. data/ext/rnv/src/s.h +32 -0
  35. data/ext/rnv/src/sc.c +62 -0
  36. data/ext/rnv/src/sc.h +26 -0
  37. data/ext/rnv/src/type.h +121 -0
  38. data/ext/rnv/src/u.c +88 -0
  39. data/ext/rnv/src/u.h +26 -0
  40. data/ext/rnv/src/xcl.c +472 -0
  41. data/ext/rnv/src/xmlc.c +20 -0
  42. data/ext/rnv/src/xmlc.h +16 -0
  43. data/ext/rnv/src/xsd.c +789 -0
  44. data/ext/rnv/src/xsd.h +27 -0
  45. data/ext/rnv/src/xsd_tm.c +100 -0
  46. data/ext/rnv/src/xsd_tm.h +15 -0
  47. data/lib/rnv.rb +2 -0
  48. data/lib/rnv/ox_sax_document.rb +84 -0
  49. data/lib/rnv/validator.rb +104 -0
  50. metadata +175 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1ce0f617fe47044b9ccbf17170bef6c3e4eff2e058391c807f893ecc6927444b
4
+ data.tar.gz: 1f1cd9b725b0ac0bb1c911a46b61cd972e530eb32a52b83436a4ef98d3eeacb2
5
+ SHA512:
6
+ metadata.gz: 39f3d4546aeaa960ae63fc05125cc66187821b28c2863d575f2d4a9073eeb09d7b7881a4f10d678092e3f4d7c11f02320af6ff176b5a25d8b62f57e3bec111f7
7
+ data.tar.gz: f463ff1d5afcc72d8872475a26b397d24b7b25716fee83f025cc7ab3ddd038f4f591e810a350463eda65b1dc6b87ce8ea518a4470abc931d56e1322d8e100206
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,15 @@
1
+ require 'mkmf'
2
+
3
+ CONFIG['warnflags'].gsub!(/-W.* /, '')
4
+
5
+ $srcs = %w{src/rn.c src/rnc.c src/rnd.c src/rnl.c src/rnv.c src/rnx.c src/drv.c src/ary.c src/xsd.c src/xsd_tm.c
6
+ src/sc.c src/u.c src/ht.c src/er.c src/xmlc.c src/s.c src/m.c src/rx.c ruby_rnv.c}
7
+
8
+ $INCFLAGS << " -I$(srcdir)/src"
9
+
10
+ # add folder, where compiler can search source files
11
+ $VPATH << "$(srcdir)/src"
12
+
13
+ extension_name = 'rnv'
14
+ dir_config(extension_name)
15
+ create_makefile("#{extension_name}/#{extension_name}")
@@ -0,0 +1,742 @@
1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+ #include <stdarg.h>
4
+ #include <fcntl.h> /*open,close*/
5
+ #include <sys/types.h>
6
+ #include <unistd.h> /*open,read,close*/
7
+ #include <string.h> /*strerror*/
8
+ #include <errno.h>
9
+ #include <assert.h>
10
+
11
+ #include "src/m.h"
12
+ #include "src/s.h"
13
+ #include "src/erbit.h"
14
+ #include "src/drv.h"
15
+ #include "src/rnl.h"
16
+ #include "src/rnv.h"
17
+ #include "src/rnx.h"
18
+ #include "src/ll.h"
19
+ #include "src/er.h"
20
+ #include "src/erbit.h"
21
+ #include "src/rnc.h"
22
+ #include "src/rnd.h"
23
+ #include "src/rx.h"
24
+ #include "src/xsd.h"
25
+
26
+ #include <ruby.h>
27
+ #include <ruby/io.h>
28
+
29
+ #define LEN_T XCL_LEN_T
30
+ #define LIM_T XCL_LIM_T
31
+
32
+ typedef struct document
33
+ {
34
+ char *fn;
35
+ int start;
36
+ int current;
37
+ int previous;
38
+ int lastline;
39
+ int lastcol;
40
+ int level;
41
+ int opened;
42
+ int ok;
43
+ char *text;
44
+ int len_txt;
45
+ int n_txt;
46
+ int mixed;
47
+ int nexp;
48
+
49
+ rnv_t *rnv;
50
+ rn_st_t *rn_st;
51
+ rnc_st_t *rnc_st;
52
+ rnx_st_t *rnx_st;
53
+ drv_st_t *drv_st;
54
+ rx_st_t *rx_st;
55
+ rnd_st_t *rnd_st;
56
+
57
+ } document_t;
58
+
59
+ VALUE RNV;
60
+
61
+ // convert error code to symbol
62
+ ID errno_to_id(int erno)
63
+ {
64
+ ID id;
65
+ switch (erno)
66
+ {
67
+ case (ERBIT_RNC | RNC_ER_IO):
68
+ id = rb_intern("rnc_er_io");
69
+ break;
70
+ case (ERBIT_RNC | RNC_ER_UTF):
71
+ id = rb_intern("rnc_er_urf");
72
+ break;
73
+ case (ERBIT_RNC | RNC_ER_XESC):
74
+ id = rb_intern("rnc_er_xesc");
75
+ break;
76
+ case (ERBIT_RNC | RNC_ER_LEXP):
77
+ id = rb_intern("rnc_er_lexp");
78
+ break;
79
+ case (ERBIT_RNC | RNC_ER_LLIT):
80
+ id = rb_intern("rnc_er_llit");
81
+ break;
82
+ case (ERBIT_RNC | RNC_ER_LILL):
83
+ id = rb_intern("rnc_er_lill");
84
+ break;
85
+ case (ERBIT_RNC | RNC_ER_SEXP):
86
+ id = rb_intern("rnc_er_sexp");
87
+ break;
88
+ case (ERBIT_RNC | RNC_ER_SILL):
89
+ id = rb_intern("rnc_er_still");
90
+ break;
91
+ case (ERBIT_RNC | RNC_ER_NOTGR):
92
+ id = rb_intern("rnc_er_notgr");
93
+ break;
94
+ case (ERBIT_RNC | RNC_ER_EXT):
95
+ id = rb_intern("rnc_er_ext");
96
+ break;
97
+ case (ERBIT_RNC | RNC_ER_DUPNS):
98
+ id = rb_intern("rnc_er_dupns");
99
+ break;
100
+ case (ERBIT_RNC | RNC_ER_DUPDT):
101
+ id = rb_intern("rnc_er_dupdt");
102
+ break;
103
+ case (ERBIT_RNC | RNC_ER_DFLTNS):
104
+ id = rb_intern("rnc_er_dfltns");
105
+ break;
106
+ case (ERBIT_RNC | RNC_ER_DFLTDT):
107
+ id = rb_intern("rnc_er_dfltdt");
108
+ break;
109
+ case (ERBIT_RNC | RNC_ER_NONS):
110
+ id = rb_intern("rnc_er_nons");
111
+ break;
112
+ case (ERBIT_RNC | RNC_ER_NODT):
113
+ id = rb_intern("rnc_er_nodt");
114
+ break;
115
+ case (ERBIT_RNC | RNC_ER_NCEX):
116
+ id = rb_intern("rnc_er_ncex");
117
+ break;
118
+ case (ERBIT_RNC | RNC_ER_2HEADS):
119
+ id = rb_intern("rnc_er_2heads");
120
+ break;
121
+ case (ERBIT_RNC | RNC_ER_COMBINE):
122
+ id = rb_intern("rnc_er_combine");
123
+ break;
124
+ case (ERBIT_RNC | RNC_ER_OVRIDE):
125
+ id = rb_intern("rnc_er_ovride");
126
+ break;
127
+ case (ERBIT_RNC | RNC_ER_EXPT):
128
+ id = rb_intern("rnc_er_excpt");
129
+ break;
130
+ case (ERBIT_RNC | RNC_ER_INCONT):
131
+ id = rb_intern("rnc_er_incont");
132
+ break;
133
+ case (ERBIT_RNC | RNC_ER_NOSTART):
134
+ id = rb_intern("rnc_er_nostart");
135
+ break;
136
+ case (ERBIT_RNC | RNC_ER_UNDEF):
137
+ id = rb_intern("rnc_er_undef");
138
+ break;
139
+
140
+ case (ERBIT_RND | RND_ER_LOOPST):
141
+ id = rb_intern("rnd_er_loopst");
142
+ break;
143
+ case (ERBIT_RND | RND_ER_LOOPEL):
144
+ id = rb_intern("rnd_er_loopel");
145
+ break;
146
+ case (ERBIT_RND | RND_ER_CTYPE):
147
+ id = rb_intern("rnd_er_ctype");
148
+ break;
149
+ case (ERBIT_RND | RND_ER_BADSTART):
150
+ id = rb_intern("rnd_er_badstart");
151
+ break;
152
+ case (ERBIT_RND | RND_ER_BADMORE):
153
+ id = rb_intern("rnd_er_badmore");
154
+ break;
155
+ case (ERBIT_RND | RND_ER_BADEXPT):
156
+ id = rb_intern("rnd_er_badexpt");
157
+ break;
158
+ case (ERBIT_RND | RND_ER_BADLIST):
159
+ id = rb_intern("rnd_er_badlist");
160
+ break;
161
+ case (ERBIT_RND | RND_ER_BADATTR):
162
+ id = rb_intern("rnd_er_badattr");
163
+ break;
164
+
165
+ case (ERBIT_RX | RX_ER_BADCH):
166
+ id = rb_intern("rx_er_badch");
167
+ break;
168
+ case (ERBIT_RX | RX_ER_UNFIN):
169
+ id = rb_intern("rx_er_unfin");
170
+ break;
171
+ case (ERBIT_RX | RX_ER_NOLSQ):
172
+ id = rb_intern("rx_er_nolsq");
173
+ break;
174
+ case (ERBIT_RX | RX_ER_NORSQ):
175
+ id = rb_intern("rx_er_norsq");
176
+ break;
177
+ case (ERBIT_RX | RX_ER_NOLCU):
178
+ id = rb_intern("rx_er_nolcu");
179
+ break;
180
+ case (ERBIT_RX | RX_ER_NORCU):
181
+ id = rb_intern("rx_er_norcu");
182
+ break;
183
+ case (ERBIT_RX | RX_ER_NOLPA):
184
+ id = rb_intern("rx_er_nolpa");
185
+ break;
186
+ case (ERBIT_RX | RX_ER_NORPA):
187
+ id = rb_intern("rx_er_norpa");
188
+ break;
189
+ case (ERBIT_RX | RX_ER_BADCL):
190
+ id = rb_intern("rx_er_badcl");
191
+ break;
192
+ case (ERBIT_RX | RX_ER_NODGT):
193
+ id = rb_intern("rx_er_nodgt");
194
+ break;
195
+ case (ERBIT_RX | RX_ER_DNUOB):
196
+ id = rb_intern("rx_er_dnuob");
197
+ break;
198
+ case (ERBIT_RX | RX_ER_NOTRC):
199
+ id = rb_intern("rx_er_notrc");
200
+ break;
201
+
202
+ case (ERBIT_XSD | XSD_ER_TYP):
203
+ id = rb_intern("xsd_er_typ");
204
+ break;
205
+ case (ERBIT_XSD | XSD_ER_PAR):
206
+ id = rb_intern("xsd_er_par");
207
+ break;
208
+ case (ERBIT_XSD | XSD_ER_PARVAL):
209
+ id = rb_intern("xsd_er_parval");
210
+ break;
211
+ case (ERBIT_XSD | XSD_ER_VAL):
212
+ id = rb_intern("xsd_er_val");
213
+ break;
214
+ case (ERBIT_XSD | XSD_ER_NPAT):
215
+ id = rb_intern("xsd_er_npat");
216
+ break;
217
+ case (ERBIT_XSD | XSD_ER_WS):
218
+ id = rb_intern("xsd_er_ws");
219
+ break;
220
+ case (ERBIT_XSD | XSD_ER_ENUM):
221
+ id = rb_intern("xsd_er_enum");
222
+ break;
223
+
224
+ case (ERBIT_DRV | DRV_ER_NODTL):
225
+ id = rb_intern("drv_er_nodtl");
226
+ break;
227
+
228
+ case (ERBIT_RNV | RNV_ER_ELEM):
229
+ id = rb_intern("rnv_er_elem");
230
+ break;
231
+ case (ERBIT_RNV | RNV_ER_AKEY):
232
+ id = rb_intern("rnv_er_akey");
233
+ break;
234
+ case (ERBIT_RNV | RNV_ER_AVAL):
235
+ id = rb_intern("rnv_er_aval");
236
+ break;
237
+ case (ERBIT_RNV | RNV_ER_EMIS):
238
+ id = rb_intern("rnv_er_emis");
239
+ break;
240
+ case (ERBIT_RNV | RNV_ER_AMIS):
241
+ id = rb_intern("rnv_er_amis");
242
+ break;
243
+ case (ERBIT_RNV | RNV_ER_UFIN):
244
+ id = rb_intern("rnv_er_ufin");
245
+ break;
246
+ case (ERBIT_RNV | RNV_ER_TEXT):
247
+ id = rb_intern("rnv_er_text");
248
+ break;
249
+ case (ERBIT_RNV | RNV_ER_NOTX):
250
+ id = rb_intern("rnv_er_notx");
251
+ break;
252
+
253
+ default:
254
+ id = rb_intern("unknown");
255
+ break;
256
+ }
257
+ return id;
258
+ }
259
+
260
+ int ruby_verror_handler(rnv_t *rnv, int erno, char *format, va_list ap)
261
+ {
262
+ VALUE self = (VALUE)rnv->user_data;
263
+ document_t *document;
264
+
265
+ Data_Get_Struct(self, document_t, document);
266
+
267
+ rnx_st_t *rnx_st = document->rnx_st;
268
+
269
+ VALUE errors = rb_iv_get(self, "@errors");
270
+
271
+ VALUE error_array = rb_ary_new2(2);
272
+ VALUE error_str = rb_vsprintf(format, ap);
273
+ VALUE error_erno = ID2SYM(errno_to_id(erno));
274
+
275
+ // lazyly strip with ruby
276
+ rb_funcall(error_str, rb_intern("strip!"), 0);
277
+
278
+ VALUE err_class = rb_const_get(RNV, rb_intern("Error"));
279
+ VALUE err_obj = rb_class_new_instance(0, NULL, err_class);
280
+ rb_iv_set(err_obj, "@document", self);
281
+ rb_iv_set(err_obj, "@code", error_erno);
282
+ rb_iv_set(err_obj, "@message", error_str);
283
+ rb_iv_set(err_obj, "@line", rb_iv_get(self, "@last_line"));
284
+ rb_iv_set(err_obj, "@col", rb_iv_get(self, "@last_col"));
285
+
286
+ VALUE expected = rb_str_new2("");
287
+ if (erno & ERBIT_RNV)
288
+ {
289
+ if (document->nexp)
290
+ {
291
+ int req = 2, i = 0;
292
+ char *s;
293
+ while (req--)
294
+ {
295
+ rnx_expected(rnv, rnx_st, document->previous, req);
296
+ if (i == rnv->rnx_n_exp)
297
+ continue;
298
+ if (rnv->rnx_n_exp > document->nexp)
299
+ break;
300
+
301
+ expected = rb_str_cat2(expected, (char *)(req ? "required:\n" : "allowed:\n"));
302
+
303
+ for (; i != rnv->rnx_n_exp; ++i)
304
+ {
305
+ s = rnx_p2str(rnv, rnv->rnx_exp[i]);
306
+ expected = rb_str_cat2(expected, "\t");
307
+ expected = rb_str_cat2(expected, s);
308
+ expected = rb_str_cat2(expected, "\n");
309
+ m_free(s);
310
+ }
311
+ }
312
+ }
313
+ }
314
+
315
+ rb_iv_set(err_obj, "@expected", expected);
316
+
317
+ rb_ary_push(errors, err_obj);
318
+ }
319
+
320
+ /*
321
+ * @return [String]
322
+ */
323
+ VALUE rb_error_inspect(VALUE self)
324
+ {
325
+ VALUE code = rb_iv_get(self, "@code");
326
+ VALUE message = rb_iv_get(self, "@message");
327
+ VALUE expected = rb_iv_get(self, "@expected");
328
+ VALUE line = rb_iv_get(self, "@line");
329
+ VALUE col = rb_iv_get(self, "@col");
330
+
331
+ VALUE ret = rb_str_new2("#<RNV::Error ");
332
+ ret = rb_str_cat2(ret, "code: :");
333
+ ret = rb_str_append(ret, rb_obj_as_string(code));
334
+ ret = rb_str_cat2(ret, ", ");
335
+ ret = rb_str_cat2(ret, "message: '");
336
+ ret = rb_str_append(ret, message);
337
+ ret = rb_str_cat2(ret, "', ");
338
+ ret = rb_str_cat2(ret, "expected: '");
339
+ ret = rb_str_append(ret, expected);
340
+ ret = rb_str_cat2(ret, "', ");
341
+ ret = rb_str_cat2(ret, "line: ");
342
+ ret = rb_str_append(ret, rb_obj_as_string(line));
343
+ ret = rb_str_cat2(ret, ", ");
344
+ ret = rb_str_cat2(ret, "col: ");
345
+ ret = rb_str_append(ret, rb_obj_as_string(col));
346
+ ret = rb_str_cat2(ret, ">");
347
+ return ret;
348
+ }
349
+
350
+ /*
351
+ * @return [String]
352
+ */
353
+ VALUE rb_error_to_s(VALUE self)
354
+ {
355
+ VALUE message = rb_iv_get(self, "@message");
356
+ VALUE expected = rb_iv_get(self, "@expected");
357
+ VALUE line = rb_iv_get(self, "@line");
358
+ VALUE col = rb_iv_get(self, "@col");
359
+
360
+ VALUE ret = rb_str_new2("");
361
+
362
+ ret = rb_str_append(ret, rb_obj_as_string(line));
363
+ ret = rb_str_cat2(ret, ":");
364
+ ret = rb_str_append(ret, rb_obj_as_string(col));
365
+
366
+ ret = rb_str_cat2(ret, ": error: ");
367
+
368
+ ret = rb_str_append(ret, message);
369
+ ret = rb_str_cat2(ret, "\n");
370
+ ret = rb_str_append(ret, expected);
371
+
372
+ return ret;
373
+ }
374
+
375
+ void document_free(document_t *document)
376
+ {
377
+ // FIXME : introduce *_delete functions
378
+ if (document->rnd_st->flat)
379
+ free(document->rnd_st->flat);
380
+ free(document->rnd_st);
381
+
382
+ ht_dispose(&document->rx_st->ht_r);
383
+ ht_dispose(&document->rx_st->ht_p);
384
+ ht_dispose(&document->rx_st->ht_2);
385
+ ht_dispose(&document->rx_st->ht_m);
386
+ if (document->rx_st->regex)
387
+ free(document->rx_st->regex);
388
+ if (document->rx_st->pattern)
389
+ free(document->rx_st->pattern);
390
+ free(document->rx_st);
391
+
392
+ if (document->drv_st->dtl)
393
+ free(document->drv_st->dtl);
394
+ ht_dispose(&document->drv_st->ht_m);
395
+ free(document->drv_st);
396
+
397
+ free(document->rnx_st);
398
+
399
+ if (document->rnc_st->path)
400
+ free(document->rnc_st->path);
401
+ free(document->rnc_st);
402
+
403
+ ht_dispose(&document->rn_st->ht_p);
404
+ ht_dispose(&document->rn_st->ht_nc);
405
+ ht_dispose(&document->rn_st->ht_s);
406
+
407
+ free(document->rn_st);
408
+
409
+ if (document->rnv->rn_pattern)
410
+ free(document->rnv->rn_pattern);
411
+ if (document->rnv->rn_nameclass)
412
+ free(document->rnv->rn_nameclass);
413
+ if (document->rnv->rn_string)
414
+ free(document->rnv->rn_string);
415
+ if (document->rnv->rnx_exp)
416
+ free(document->rnv->rnx_exp);
417
+
418
+ free(document->rnv);
419
+
420
+ free(document->text);
421
+
422
+ ruby_xfree(document);
423
+ }
424
+
425
+ VALUE rb_document_alloc(VALUE klass)
426
+ {
427
+ document_t *document = ruby_xmalloc(sizeof(document_t));
428
+
429
+ document->rnv = malloc(sizeof(rnv_t));
430
+ document->rn_st = malloc(sizeof(rn_st_t));
431
+ document->rnc_st = malloc(sizeof(rnc_st_t));
432
+ document->rnx_st = malloc(sizeof(rnx_st_t));
433
+ document->drv_st = malloc(sizeof(drv_st_t));
434
+ document->rx_st = malloc(sizeof(rx_st_t));
435
+ document->rnd_st = malloc(sizeof(rnd_st_t));
436
+
437
+ return Data_Wrap_Struct(klass, NULL, document_free, document);
438
+ }
439
+
440
+ VALUE rb_document_init(VALUE self)
441
+ {
442
+ document_t *document;
443
+ Data_Get_Struct(self, document_t, document);
444
+
445
+ rnl_init(document->rnv, document->rn_st, document->rnc_st, document->rnd_st);
446
+ rnv_init(document->rnv, document->drv_st, document->rn_st, document->rx_st);
447
+ rnx_init(document->rnv, document->rnx_st);
448
+
449
+ document->opened = document->ok = 0;
450
+ document->rnv->user_data = (void *)self;
451
+ document->rnv->verror_handler = &ruby_verror_handler;
452
+ document->nexp = 16; /* maximum number of candidates to display */
453
+
454
+ rb_iv_set(self, "@errors", rb_ary_new2(0));
455
+
456
+ return self;
457
+ }
458
+
459
+ static void document_load(document_t *document)
460
+ {
461
+ document->ok = document->current = document->previous = document->start = document->opened;
462
+ document->len_txt = LEN_T;
463
+ document->text = (char *)m_alloc(document->len_txt, sizeof(char));
464
+
465
+ document->text[0] = '\0';
466
+ document->n_txt = 0;
467
+ document->mixed = 0;
468
+ }
469
+
470
+ /*
471
+ * load schema from a buffer
472
+ * @param [String] r_str buffer
473
+ * @return [String]
474
+ */
475
+ VALUE rb_document_load_string(VALUE self, VALUE r_str)
476
+ {
477
+ document_t *document;
478
+ Data_Get_Struct(self, document_t, document);
479
+
480
+ Check_Type(r_str, T_STRING);
481
+
482
+ VALUE r_fn = rb_str_new2("");
483
+ document->fn = RSTRING_PTR(r_fn);
484
+
485
+ document->opened = rnl_s(document->rnv,
486
+ document->rnc_st,
487
+ document->rn_st,
488
+ document->rnd_st,
489
+ document->fn,
490
+ RSTRING_PTR(r_str), RSTRING_LEN(r_str));
491
+
492
+ document_load(document);
493
+ return INT2NUM(document->ok);
494
+ }
495
+
496
+ /*
497
+ * load schema from a file
498
+ * @param [String] r_fn filename
499
+ * @return [String]
500
+ */
501
+ VALUE rb_document_load_file(VALUE self, VALUE r_fn)
502
+ {
503
+ document_t *document;
504
+ Data_Get_Struct(self, document_t, document);
505
+
506
+ switch (TYPE(r_fn))
507
+ {
508
+ case T_STRING:
509
+ document->fn = RSTRING_PTR(r_fn);
510
+
511
+ document->opened = rnl_fn(document->rnv,
512
+ document->rnc_st,
513
+ document->rn_st,
514
+ document->rnd_st,
515
+ document->fn);
516
+
517
+ break;
518
+ case T_FILE: // TODO
519
+ default:
520
+ rb_raise(rb_eTypeError, "invalid argument");
521
+ break;
522
+ }
523
+
524
+ document_load(document);
525
+ return INT2NUM(document->ok);
526
+ }
527
+
528
+ /*
529
+ * is current document valid ?
530
+ * @return [Array<RNV::Error>]
531
+ */
532
+ VALUE rb_document_valid(VALUE self)
533
+ {
534
+ document_t *document;
535
+ Data_Get_Struct(self, document_t, document);
536
+
537
+ if (document->ok)
538
+ return Qtrue;
539
+ else
540
+ return Qfalse;
541
+ }
542
+
543
+ static void flush_text(document_t *document)
544
+ {
545
+ document->ok = rnv_text(document->rnv, document->drv_st, document->rn_st, document->rx_st,
546
+ &document->current, &document->previous, document->text, document->n_txt, document->mixed) &&
547
+ document->ok;
548
+ document->text[document->n_txt = 0] = '\0';
549
+ }
550
+
551
+ /*
552
+ * begin a new document
553
+ * @return [nil]
554
+ */
555
+ VALUE rb_document_begin(VALUE self)
556
+ {
557
+ document_t *document;
558
+ Data_Get_Struct(self, document_t, document);
559
+
560
+ m_free(document->text);
561
+ document->text = (char *)m_alloc(document->len_txt = LEN_T, sizeof(char));
562
+
563
+ document->ok = document->current = document->previous = document->start;
564
+
565
+ document->text[0] = '\0';
566
+ document->n_txt = 0;
567
+ document->mixed = 0;
568
+
569
+ return Qnil;
570
+ }
571
+
572
+ /*
573
+ * to be called by SAX characters handler
574
+ * @param [String] r_str characters
575
+ * @return [Integer]
576
+ */
577
+ VALUE rb_document_characters(VALUE self, VALUE r_str)
578
+ {
579
+ document_t *document;
580
+ Data_Get_Struct(self, document_t, document);
581
+
582
+ if (document->opened && document->current != document->rnv->rn_notAllowed)
583
+ {
584
+ Check_Type(r_str, T_STRING);
585
+ char *s = RSTRING_PTR(r_str);
586
+ int len = RSTRING_LEN(r_str);
587
+
588
+ int newlen_txt = document->n_txt + len + 1;
589
+ if (newlen_txt <= LIM_T && LIM_T < document->len_txt)
590
+ newlen_txt = LIM_T;
591
+ else if (newlen_txt < document->len_txt)
592
+ newlen_txt = document->len_txt;
593
+ if (document->len_txt != newlen_txt)
594
+ {
595
+ document->text = (char *)m_stretch(document->text, document->len_txt = newlen_txt, document->n_txt, sizeof(char));
596
+ }
597
+
598
+ memcpy(document->text + document->n_txt, s, len);
599
+ document->n_txt += len;
600
+ document->text[document->n_txt] = '\0'; /* '\0' guarantees that the text is bounded, and strto[ld] work for data */
601
+ }
602
+
603
+ return INT2NUM(document->ok);
604
+ }
605
+
606
+ /*
607
+ * to be called by SAX start tag handler
608
+ * @param [String] r_name tag name, must be in the form 'NS_URI:TAG_NAME'
609
+ * @param [Array<String>] r_attrs flattened array of tag attributes in the form ['NS_URI:ATTR_NAME','ATTR_VALUE']
610
+ * @return [Integer]
611
+ */
612
+ VALUE rb_document_start_tag(VALUE self, VALUE r_name, VALUE r_attrs)
613
+ {
614
+ document_t *document;
615
+ Data_Get_Struct(self, document_t, document);
616
+
617
+ if (document->opened && document->current != document->rnv->rn_notAllowed)
618
+ {
619
+ char *name;
620
+ char **attrs;
621
+
622
+ Check_Type(r_name, T_STRING);
623
+ name = RSTRING_PTR(r_name);
624
+
625
+ Check_Type(r_attrs, T_ARRAY);
626
+ unsigned int attrs_len = RARRAY_LEN(r_attrs);
627
+
628
+ attrs = malloc(sizeof(char *) * (attrs_len + 1));
629
+
630
+ for (int i = 0; i < attrs_len; i++)
631
+ {
632
+ attrs[i] = RSTRING_PTR(rb_ary_entry(r_attrs, i));
633
+ }
634
+ attrs[attrs_len] = 0; // zero terminated
635
+
636
+ document->mixed = 1;
637
+
638
+ flush_text(document);
639
+ //printf("RNV START %d/%d %s %d\n", current, previous, name, attrs_len);
640
+ document->ok = rnv_start_tag(document->rnv, document->drv_st, document->rn_st, document->rx_st,
641
+ &document->current, &document->previous, (char *)name, (char **)attrs) &&
642
+ document->ok;
643
+
644
+ document->mixed = 0;
645
+ free(attrs);
646
+ }
647
+
648
+ return INT2NUM(document->ok);
649
+ }
650
+
651
+ /*
652
+ * to be called by SAX end tag handler
653
+ * @param [String] r_name tag name, must be in the form 'NS_URI:TAG_NAME'
654
+ * @return [Integer]
655
+ */
656
+ VALUE rb_document_end_tag(VALUE self, VALUE r_name)
657
+ {
658
+ document_t *document;
659
+ Data_Get_Struct(self, document_t, document);
660
+
661
+ if (document->opened && document->current != document->rnv->rn_notAllowed)
662
+ {
663
+ char *name;
664
+
665
+ Check_Type(r_name, T_STRING);
666
+ name = RSTRING_PTR(r_name);
667
+
668
+ flush_text(document);
669
+
670
+ //printf("RNV END %d/%d %s\n", current, previous, name);
671
+ document->ok = rnv_end_tag(document->rnv, document->drv_st, document->rn_st,
672
+ &document->current, &document->previous, (char *)name) &&
673
+ document->ok;
674
+
675
+ document->mixed = 1;
676
+ }
677
+
678
+ return INT2NUM(document->ok);
679
+ }
680
+
681
+ // The initialization method for this module
682
+ void Init_rnv()
683
+ {
684
+ RNV = rb_define_module("RNV");
685
+
686
+ VALUE Error = rb_define_class_under(RNV, "Error", rb_cObject);
687
+
688
+ rb_define_method(Error, "inspect", rb_error_inspect, 0);
689
+ rb_define_method(Error, "to_s", rb_error_to_s, 0);
690
+
691
+ /*
692
+ * error symbol code
693
+ * @return [Symbol]
694
+ */
695
+ rb_define_attr(Error, "code", 1, 0);
696
+ /*
697
+ * error message
698
+ * @return [String]
699
+ */
700
+ rb_define_attr(Error, "message", 1, 0);
701
+ /*
702
+ * error line
703
+ * @return [Integer]
704
+ */
705
+ rb_define_attr(Error, "line", 1, 0);
706
+ /*
707
+ * error column
708
+ * @return [Integer]
709
+ */
710
+ rb_define_attr(Error, "col", 1, 0);
711
+
712
+ VALUE Document = rb_define_class_under(RNV, "Document", rb_cObject);
713
+
714
+ rb_define_alloc_func(Document, rb_document_alloc);
715
+ rb_define_method(Document, "initialize", rb_document_init, 0);
716
+
717
+ rb_define_method(Document, "load_file", rb_document_load_file, 1);
718
+ rb_define_method(Document, "load_string", rb_document_load_string, 1);
719
+ rb_define_method(Document, "valid?", rb_document_valid, 0);
720
+
721
+ rb_define_method(Document, "start_document", rb_document_begin, 0);
722
+ rb_define_method(Document, "start_tag", rb_document_start_tag, 2);
723
+ rb_define_method(Document, "characters", rb_document_characters, 1);
724
+ rb_define_method(Document, "end_tag", rb_document_end_tag, 1);
725
+
726
+ /*
727
+ * last line processed, set by SAX handler
728
+ * @return [Integer]
729
+ */
730
+ rb_define_attr(Document, "last_line", 1, 1);
731
+ /*
732
+ * last column processed, set by SAX handler
733
+ * @return [Integer]
734
+ */
735
+ rb_define_attr(Document, "last_col", 1, 1);
736
+
737
+ /*
738
+ * errors from current document
739
+ * @return [Array<RNV::Error>]
740
+ */
741
+ rb_define_attr(Document, "errors", 1, 1);
742
+ }