ruby_rnv 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }