ruby_rnv 0.2.1 → 0.3.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a8fd8bf859c9269e4001838b7399bb2824ab6af9dad1ee25468c7534e3618fcc
4
- data.tar.gz: b5a09f8fb49485d338039d91b2f4c4f3f4f6815c68b976f1db716cdda5a4300e
3
+ metadata.gz: d336dc0c4dae28d9aa530925a9d322cc2a46598d77dc179da6785e47250fe552
4
+ data.tar.gz: 4e04b15b29ba46fad249f180b923def4cb69e04a041788022769a80ae4a0fb64
5
5
  SHA512:
6
- metadata.gz: c50fb3f7d4d5b38853169e4043c333b05ad2320c434f10a5474acca146b58769e17e75336cc77c1c7ebd7c3de81925871d3d6dd5f9188b8d126bdfbd5f39093a
7
- data.tar.gz: 9314404ae4355a652ec4e0191b68ce908a0a50b87def123b2c2b3b46415c6742477bc6078f49179b009f33925d41fb9736e053e8031f1ae6621b8816e1315125
6
+ metadata.gz: 8578ad4848314ed6f152bdd39e8824ad95b705ff6c6d32c150b8491564a0a78997455627903f1c8d00f43f581178c0c1dbb75c2e1ca4358f47ad1e962e98eac9
7
+ data.tar.gz: 6b3a9ad08b327a3931a3c944a43ecbb48dbcdf6f1a99dceb0c1e5935916254a2e88d45f7d7e26f6b9a374e39355c7e2f69d39777b4b7e5bf3fa0f6b44cbf877c
data/ext/rnv/ruby_rnv.c CHANGED
@@ -56,7 +56,7 @@ typedef struct document
56
56
 
57
57
  } document_t;
58
58
 
59
- VALUE RNV;
59
+ VALUE RNV, SchemaNotLoaded, Error, Document;
60
60
 
61
61
  // convert error code to symbol
62
62
  ID errno_to_id(int erno)
@@ -275,7 +275,7 @@ int ruby_verror_handler(rnv_t *rnv, int erno, char *format, va_list ap)
275
275
  // lazyly strip with ruby
276
276
  rb_funcall(error_str, rb_intern("strip!"), 0);
277
277
 
278
- VALUE err_class = rb_const_get(RNV, rb_intern("Error"));
278
+ VALUE err_class = Error;
279
279
  VALUE err_obj = rb_class_new_instance(0, NULL, err_class);
280
280
  rb_iv_set(err_obj, "@document", self);
281
281
  rb_iv_set(err_obj, "@code", error_erno);
@@ -317,61 +317,6 @@ int ruby_verror_handler(rnv_t *rnv, int erno, char *format, va_list ap)
317
317
  rb_ary_push(errors, err_obj);
318
318
  }
319
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
320
  void document_free(document_t *document)
376
321
  {
377
322
  // FIXME : introduce *_delete functions
@@ -417,7 +362,8 @@ void document_free(document_t *document)
417
362
 
418
363
  free(document->rnv);
419
364
 
420
- free(document->text);
365
+ if (document->text)
366
+ free(document->text);
421
367
 
422
368
  ruby_xfree(document);
423
369
  }
@@ -450,9 +396,12 @@ VALUE rb_document_init(VALUE self)
450
396
  document->rnv->user_data = (void *)self;
451
397
  document->rnv->verror_handler = &ruby_verror_handler;
452
398
  document->nexp = 16; /* maximum number of candidates to display */
399
+ document->text = NULL;
453
400
 
454
401
  rb_iv_set(self, "@errors", rb_ary_new2(0));
455
402
 
403
+ rb_iv_set(self, "@libraries", rb_hash_new());
404
+
456
405
  return self;
457
406
  }
458
407
 
@@ -470,7 +419,7 @@ static void document_load(document_t *document)
470
419
  /*
471
420
  * load schema from a buffer
472
421
  * @param [String] r_str buffer
473
- * @return [String]
422
+ * @return [Boolean]
474
423
  */
475
424
  VALUE rb_document_load_string(VALUE self, VALUE r_str)
476
425
  {
@@ -489,40 +438,42 @@ VALUE rb_document_load_string(VALUE self, VALUE r_str)
489
438
  document->fn,
490
439
  RSTRING_PTR(r_str), RSTRING_LEN(r_str));
491
440
 
492
- document_load(document);
493
- return INT2NUM(document->ok);
441
+ if (document->opened)
442
+ {
443
+ document_load(document);
444
+ return Qtrue;
445
+ }
446
+ else
447
+ return Qfalse;
494
448
  }
495
449
 
496
450
  /*
497
451
  * load schema from a file
498
452
  * @param [String] r_fn filename
499
- * @return [String]
453
+ * @return [Boolean]
500
454
  */
501
455
  VALUE rb_document_load_file(VALUE self, VALUE r_fn)
502
456
  {
503
457
  document_t *document;
504
458
  Data_Get_Struct(self, document_t, document);
505
459
 
506
- switch (TYPE(r_fn))
507
- {
508
- case T_STRING:
509
- document->fn = RSTRING_PTR(r_fn);
460
+ Check_Type(r_fn, T_STRING);
510
461
 
511
- document->opened = rnl_fn(document->rnv,
512
- document->rnc_st,
513
- document->rn_st,
514
- document->rnd_st,
515
- document->fn);
462
+ document->fn = RSTRING_PTR(r_fn);
516
463
 
517
- break;
518
- case T_FILE: // TODO
519
- default:
520
- rb_raise(rb_eTypeError, "invalid argument");
521
- break;
522
- }
464
+ document->opened = rnl_fn(document->rnv,
465
+ document->rnc_st,
466
+ document->rn_st,
467
+ document->rnd_st,
468
+ document->fn);
523
469
 
524
- document_load(document);
525
- return INT2NUM(document->ok);
470
+ if (document->opened)
471
+ {
472
+ document_load(document);
473
+ return Qtrue;
474
+ }
475
+ else
476
+ return Qfalse;
526
477
  }
527
478
 
528
479
  /*
@@ -548,8 +499,61 @@ static void flush_text(document_t *document)
548
499
  document->text[document->n_txt = 0] = '\0';
549
500
  }
550
501
 
502
+ static int rb_dtl_equal(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ, char *val, char *s, int n)
503
+ {
504
+ VALUE self = (VALUE)rnv->user_data;
505
+ VALUE libraries = rb_iv_get(self, "@libraries");
506
+ VALUE lib = rb_hash_aref(libraries, INT2FIX(uri));
507
+
508
+ VALUE ret = rb_funcall(lib, rb_intern("equal"), 4,
509
+ rb_str_new2(typ), rb_str_new2(val), rb_str_new2(s), INT2FIX(n));
510
+
511
+ return RTEST(ret);
512
+ }
513
+
514
+ static int rb_dtl_allows(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ, char *ps, char *s, int n)
515
+ {
516
+ VALUE self = (VALUE)rnv->user_data;
517
+ VALUE libraries = rb_iv_get(self, "@libraries");
518
+ VALUE lib = rb_hash_aref(libraries, INT2FIX(uri));
519
+
520
+ VALUE ret = rb_funcall(lib, rb_intern("allows"), 4,
521
+ rb_str_new2(typ), rb_str_new2(ps), rb_str_new2(s), INT2FIX(n));
522
+
523
+ return RTEST(ret);
524
+ }
525
+
551
526
  /*
552
- * begin a new document
527
+ * add a new datatype library
528
+ * @see https://www.oasis-open.org/committees/relax-ng/spec-20010811.html#IDA1I1R
529
+ * @param [String] r_ns unique ns URL for this datatype
530
+ * @param [RNV::DataTypeLibrary] r_cb_obj
531
+ * @return [nil]
532
+ */
533
+ VALUE rb_document_add_dtl(VALUE self, VALUE r_ns, VALUE r_cb_obj)
534
+ {
535
+ document_t *document;
536
+ Data_Get_Struct(self, document_t, document);
537
+
538
+ if (document->opened)
539
+ {
540
+ Check_Type(r_ns, T_STRING);
541
+
542
+ char *suri = RSTRING_PTR(r_ns);
543
+
544
+ drv_add_dtl(document->rnv, document->drv_st, document->rn_st, suri, &rb_dtl_equal, &rb_dtl_allows);
545
+
546
+ int uri = document->drv_st->dtl[document->drv_st->n_dtl - 1].uri;
547
+
548
+ VALUE libraries = rb_iv_get(self, "@libraries");
549
+
550
+ rb_hash_aset(libraries, INT2FIX(uri), r_cb_obj);
551
+ }
552
+ return Qnil;
553
+ }
554
+
555
+ /*
556
+ * begin parsing a new document
553
557
  * @return [nil]
554
558
  */
555
559
  VALUE rb_document_begin(VALUE self)
@@ -557,6 +561,12 @@ VALUE rb_document_begin(VALUE self)
557
561
  document_t *document;
558
562
  Data_Get_Struct(self, document_t, document);
559
563
 
564
+ if (!document->opened)
565
+ rb_raise(SchemaNotLoaded, "schema was not loaded correctly");
566
+
567
+ // reset errors
568
+ rb_iv_set(self, "@errors", rb_ary_new2(0));
569
+
560
570
  m_free(document->text);
561
571
  document->text = (char *)m_alloc(document->len_txt = LEN_T, sizeof(char));
562
572
 
@@ -572,14 +582,17 @@ VALUE rb_document_begin(VALUE self)
572
582
  /*
573
583
  * to be called by SAX characters handler
574
584
  * @param [String] r_str characters
575
- * @return [Integer]
585
+ * @return [Boolean]
576
586
  */
577
587
  VALUE rb_document_characters(VALUE self, VALUE r_str)
578
588
  {
579
589
  document_t *document;
580
590
  Data_Get_Struct(self, document_t, document);
581
591
 
582
- if (document->opened && document->current != document->rnv->rn_notAllowed)
592
+ if (!document->opened)
593
+ rb_raise(SchemaNotLoaded, "schema was not loaded correctly");
594
+
595
+ if (document->current != document->rnv->rn_notAllowed)
583
596
  {
584
597
  Check_Type(r_str, T_STRING);
585
598
  char *s = RSTRING_PTR(r_str);
@@ -600,22 +613,26 @@ VALUE rb_document_characters(VALUE self, VALUE r_str)
600
613
  document->text[document->n_txt] = '\0'; /* '\0' guarantees that the text is bounded, and strto[ld] work for data */
601
614
  }
602
615
 
603
- return INT2NUM(document->ok);
616
+ return RTEST(document->ok);
604
617
  }
605
618
 
606
619
  /*
607
620
  * to be called by SAX start tag handler
608
621
  * @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]
622
+ * @param [Array<Array<String>>] r_attrs flattened array of tag attributes in the form [['NS_URI:ATTR_NAME','ATTR_VALUE']]
623
+ * @return [Boolean]
611
624
  */
612
625
  VALUE rb_document_start_tag(VALUE self, VALUE r_name, VALUE r_attrs)
613
626
  {
614
627
  document_t *document;
615
628
  Data_Get_Struct(self, document_t, document);
616
629
 
617
- if (document->opened && document->current != document->rnv->rn_notAllowed)
630
+ if (!document->opened)
631
+ rb_raise(SchemaNotLoaded, "schema was not loaded correctly");
632
+
633
+ if (document->current != document->rnv->rn_notAllowed)
618
634
  {
635
+ int i;
619
636
  char *name;
620
637
  char **attrs;
621
638
 
@@ -623,20 +640,22 @@ VALUE rb_document_start_tag(VALUE self, VALUE r_name, VALUE r_attrs)
623
640
  name = RSTRING_PTR(r_name);
624
641
 
625
642
  Check_Type(r_attrs, T_ARRAY);
626
- unsigned int attrs_len = RARRAY_LEN(r_attrs);
643
+
644
+ // lazyly flatten with ruby
645
+ VALUE r_flat_attrs = rb_funcall(r_attrs, rb_intern("flatten"), 0);
646
+ unsigned int attrs_len = RARRAY_LEN(r_flat_attrs);
627
647
 
628
648
  attrs = malloc(sizeof(char *) * (attrs_len + 1));
629
649
 
630
- for (int i = 0; i < attrs_len; i++)
650
+ for (i = 0; i < attrs_len; i++)
631
651
  {
632
- attrs[i] = RSTRING_PTR(rb_ary_entry(r_attrs, i));
652
+ attrs[i] = RSTRING_PTR(rb_ary_entry(r_flat_attrs, i));
633
653
  }
634
654
  attrs[attrs_len] = 0; // zero terminated
635
655
 
636
656
  document->mixed = 1;
637
657
 
638
658
  flush_text(document);
639
- //printf("RNV START %d/%d %s %d\n", current, previous, name, attrs_len);
640
659
  document->ok = rnv_start_tag(document->rnv, document->drv_st, document->rn_st, document->rx_st,
641
660
  &document->current, &document->previous, (char *)name, (char **)attrs) &&
642
661
  document->ok;
@@ -645,20 +664,23 @@ VALUE rb_document_start_tag(VALUE self, VALUE r_name, VALUE r_attrs)
645
664
  free(attrs);
646
665
  }
647
666
 
648
- return INT2NUM(document->ok);
667
+ return RTEST(document->ok);
649
668
  }
650
669
 
651
670
  /*
652
671
  * to be called by SAX end tag handler
653
672
  * @param [String] r_name tag name, must be in the form 'NS_URI:TAG_NAME'
654
- * @return [Integer]
673
+ * @return [Boolean]
655
674
  */
656
675
  VALUE rb_document_end_tag(VALUE self, VALUE r_name)
657
676
  {
658
677
  document_t *document;
659
678
  Data_Get_Struct(self, document_t, document);
660
679
 
661
- if (document->opened && document->current != document->rnv->rn_notAllowed)
680
+ if (!document->opened)
681
+ rb_raise(SchemaNotLoaded, "schema was not loaded correctly");
682
+
683
+ if (document->current != document->rnv->rn_notAllowed)
662
684
  {
663
685
  char *name;
664
686
 
@@ -667,7 +689,6 @@ VALUE rb_document_end_tag(VALUE self, VALUE r_name)
667
689
 
668
690
  flush_text(document);
669
691
 
670
- //printf("RNV END %d/%d %s\n", current, previous, name);
671
692
  document->ok = rnv_end_tag(document->rnv, document->drv_st, document->rn_st,
672
693
  &document->current, &document->previous, (char *)name) &&
673
694
  document->ok;
@@ -675,7 +696,7 @@ VALUE rb_document_end_tag(VALUE self, VALUE r_name)
675
696
  document->mixed = 1;
676
697
  }
677
698
 
678
- return INT2NUM(document->ok);
699
+ return RTEST(document->ok);
679
700
  }
680
701
 
681
702
  // The initialization method for this module
@@ -683,21 +704,15 @@ void Init_rnv()
683
704
  {
684
705
  RNV = rb_define_module("RNV");
685
706
 
686
- VALUE Error = rb_define_class_under(RNV, "Error", rb_cObject);
707
+ SchemaNotLoaded = rb_define_class_under(RNV, "SchemaNotLoaded", rb_eStandardError);
687
708
 
688
- rb_define_method(Error, "inspect", rb_error_inspect, 0);
689
- rb_define_method(Error, "to_s", rb_error_to_s, 0);
709
+ Error = rb_define_class_under(RNV, "Error", rb_cObject);
690
710
 
691
711
  /*
692
712
  * error symbol code
693
713
  * @return [Symbol]
694
714
  */
695
715
  rb_define_attr(Error, "code", 1, 0);
696
- /*
697
- * error message
698
- * @return [String]
699
- */
700
- rb_define_attr(Error, "message", 1, 0);
701
716
  /*
702
717
  * error line
703
718
  * @return [Integer]
@@ -708,8 +723,18 @@ void Init_rnv()
708
723
  * @return [Integer]
709
724
  */
710
725
  rb_define_attr(Error, "col", 1, 0);
726
+ /*
727
+ * error message
728
+ * @return [String]
729
+ */
730
+ rb_define_attr(Error, "message", 1, 0);
731
+ /*
732
+ * what was expected
733
+ * @return [String]
734
+ */
735
+ rb_define_attr(Error, "expected", 1, 0);
711
736
 
712
- VALUE Document = rb_define_class_under(RNV, "Document", rb_cObject);
737
+ Document = rb_define_class_under(RNV, "Document", rb_cObject);
713
738
 
714
739
  rb_define_alloc_func(Document, rb_document_alloc);
715
740
  rb_define_method(Document, "initialize", rb_document_init, 0);
@@ -718,6 +743,8 @@ void Init_rnv()
718
743
  rb_define_method(Document, "load_string", rb_document_load_string, 1);
719
744
  rb_define_method(Document, "valid?", rb_document_valid, 0);
720
745
 
746
+ rb_define_method(Document, "add_datatype_library", rb_document_add_dtl, 2);
747
+
721
748
  rb_define_method(Document, "start_document", rb_document_begin, 0);
722
749
  rb_define_method(Document, "start_tag", rb_document_start_tag, 2);
723
750
  rb_define_method(Document, "characters", rb_document_characters, 1);
data/ext/rnv/src/drv.c CHANGED
@@ -13,12 +13,6 @@
13
13
  #include "er.h"
14
14
  #include "drv.h"
15
15
 
16
- struct dtl {
17
- int uri;
18
- int (*equal)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *val,char *s,int n);
19
- int (*allows)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *ps,char *s,int n);
20
- };
21
-
22
16
  #define LEN_DTL DRV_LEN_DTL
23
17
  #define LEN_M DRV_LEN_M
24
18
  #define PRIME_M DRV_PRIME_M
@@ -112,10 +106,10 @@ static void accept_m(rnv_t *rnv, drv_st_t *drv_st) {
112
106
  if(drv_st->i_m==drv_st->len_m) drv_st->memo=(int(*)[M_SIZE])m_stretch(drv_st->memo,drv_st->len_m=2*drv_st->i_m,drv_st->i_m,sizeof(int[M_SIZE]));
113
107
  }
114
108
 
115
- static int fallback_equal(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *val,char *s,int n) {return 1;}
116
- static int fallback_allows(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *ps,char *s,int n) {return 1;}
109
+ static int fallback_equal(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *val,char *s,int n) {return 1;}
110
+ static int fallback_allows(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *ps,char *s,int n) {return 1;}
117
111
 
118
- static int builtin_equal(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *val,char *s,int n) {
112
+ static int builtin_equal(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *val,char *s,int n) {
119
113
  int dt=rn_newDatatype(rnv, rn_st, 0,typ-rnv->rn_string);
120
114
  if(dt==rnv->rn_dt_string) return s_cmpn(val,s,n)==0;
121
115
  else if(dt==rnv->rn_dt_token) return s_tokcmpn(val,s,n)==0;
@@ -123,7 +117,7 @@ static int builtin_equal(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,c
123
117
  return 0;
124
118
  }
125
119
 
126
- static int builtin_allows(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *ps,char *s,int n) {return 1;}
120
+ static int builtin_allows(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *ps,char *s,int n) {return 1;}
127
121
 
128
122
  static void windup(rnv_t *rnv, drv_st_t *drv_st, rn_st_t *rn_st);
129
123
 
@@ -140,11 +134,11 @@ void drv_init(rnv_t *rnv, drv_st_t *drv_st, rn_st_t *rn_st, rx_st_t *rx_st) {
140
134
  windup(rnv, drv_st, rn_st);
141
135
  }
142
136
 
143
- static int emb_xsd_allows(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *ps,char *s,int n) {
137
+ static int emb_xsd_allows(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *ps,char *s,int n) {
144
138
  return xsd_allows(rx_st, typ,ps,s,n);
145
139
  }
146
140
 
147
- static int emb_xsd_equal(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *val,char *s,int n) {
141
+ static int emb_xsd_equal(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *val,char *s,int n) {
148
142
  return xsd_equal(rx_st, typ,val,s,n);
149
143
  }
150
144
 
@@ -160,7 +154,9 @@ void drv_clear(rnv_t *rnv, drv_st_t *drv_st, rn_st_t *rn_st) {
160
154
  windup(rnv, drv_st, rn_st);
161
155
  }
162
156
 
163
- void drv_add_dtl(rnv_t *rnv, drv_st_t *drv_st, rn_st_t *rn_st, char *suri,int (*equal)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *val,char *s,int n),int (*allows)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *ps,char *s,int n)) {
157
+ void drv_add_dtl(rnv_t *rnv, drv_st_t *drv_st, rn_st_t *rn_st, char *suri,
158
+ int (*equal)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *val,char *s,int n),
159
+ int (*allows)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *ps,char *s,int n)) {
164
160
  if(drv_st->n_dtl==drv_st->len_dtl) drv_st->dtl=(struct dtl *)m_stretch(drv_st->dtl,drv_st->len_dtl=drv_st->n_dtl*2,drv_st->n_dtl,sizeof(struct dtl));
165
161
  drv_st->dtl[drv_st->n_dtl].uri=rn_newString(rnv, rn_st, suri);
166
162
  drv_st->dtl[drv_st->n_dtl].equal=equal;
@@ -381,13 +377,13 @@ static int text(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, drv_st_t *drv_st, in
381
377
  ret=rn_nullable(list(rnv, rn_st, rx_st, drv_st, p1,s,n))?rnv->rn_empty:rnv->rn_notAllowed;
382
378
  break;
383
379
  case RN_P_DATA: rn_Data(p,dt,ps); rn_Datatype(dt,lib,typ);
384
- ret=getdtl(rnv, drv_st, lib)->allows(rnv,rn_st,rx_st,rnv->rn_string+typ,rnv->rn_string+ps,s,n)?rnv->rn_empty:rnv->rn_notAllowed;
380
+ ret=getdtl(rnv, drv_st, lib)->allows(rnv,rn_st,rx_st, lib, rnv->rn_string+typ,rnv->rn_string+ps,s,n)?rnv->rn_empty:rnv->rn_notAllowed;
385
381
  break;
386
382
  case RN_P_DATA_EXCEPT: rn_DataExcept(p,p1,p2);
387
383
  ret=text(rnv, rn_st, rx_st, drv_st, p1,s,n)==rnv->rn_empty&&!rn_nullable(text(rnv, rn_st, rx_st, drv_st, p2,s,n))?rnv->rn_empty:rnv->rn_notAllowed;
388
384
  break;
389
385
  case RN_P_VALUE: rn_Value(p,dt,val); rn_Datatype(dt,lib,typ);
390
- ret=getdtl(rnv, drv_st, lib)->equal(rnv,rn_st,rx_st, rnv->rn_string+typ,rnv->rn_string+val,s,n)?rnv->rn_empty:rnv->rn_notAllowed;
386
+ ret=getdtl(rnv, drv_st, lib)->equal(rnv,rn_st,rx_st, lib, rnv->rn_string+typ,rnv->rn_string+val,s,n)?rnv->rn_empty:rnv->rn_notAllowed;
391
387
  break;
392
388
  default: assert(0);
393
389
  }
data/ext/rnv/src/drv.h CHANGED
@@ -9,13 +9,21 @@
9
9
 
10
10
  #define DRV_ER_NODTL 0
11
11
 
12
+ struct dtl {
13
+ int uri;
14
+ int (*equal)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *val,char *s,int n);
15
+ int (*allows)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *ps,char *s,int n);
16
+ };
17
+
12
18
  extern void drv_default_verror_handler(rnv_t *rnv, int erno,va_list ap);
13
19
 
14
20
  extern void drv_init(rnv_t *rnv, drv_st_t *drv_st, rn_st_t *rn_st, rx_st_t *rx_st);
15
21
  extern void drv_clear(rnv_t *rnv, drv_st_t *drv_st, rn_st_t *rn_st);
16
22
 
17
23
  /* Expat passes character data unterminated. Hence functions that can deal with cdata expect the length of the data */
18
- extern void drv_add_dtl(rnv_t *rnv, drv_st_t *drv_st, rn_st_t *rn_st, char *suri,int (*equal)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *val,char *s,int n),int (*allows)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, char *typ,char *ps,char *s,int n));
24
+ extern void drv_add_dtl(rnv_t *rnv, drv_st_t *drv_st, rn_st_t *rn_st, char *suri,
25
+ int (*equal)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *val,char *s,int n),
26
+ int (*allows)(rnv_t *rnv, rn_st_t *rn_st, rx_st_t *rx_st, int uri, char *typ,char *ps,char *s,int n));
19
27
 
20
28
  extern int drv_start_tag_open(rnv_t *rnv, drv_st_t *drv_st, rn_st_t *rn_st, int p,char *suri,char *sname);
21
29
  extern int drv_start_tag_open_recover(rnv_t *rnv, drv_st_t *drv_st, rn_st_t *rn_st, int p,char *suri,char *sname);
data/lib/rnv.rb CHANGED
@@ -1,2 +1,5 @@
1
1
  require 'rnv/rnv'
2
+ require 'rnv/error'
2
3
  require 'rnv/validator'
4
+ require 'rnv/data_type_library'
5
+ require 'rnv/pre_processor'
@@ -0,0 +1,23 @@
1
+ module RNV
2
+ # Datatype library callback object
3
+ # @see https://www.oasis-open.org/committees/relax-ng/spec-20010811.html#IDA1I1R
4
+ class DataTypeLibrary
5
+ # @param [String] typ
6
+ # @param [String] val
7
+ # @param [String] s
8
+ # @param [Integer] n
9
+ # @return [Boolean]
10
+ def equal(typ, val, s, n)
11
+ true
12
+ end
13
+
14
+ # @param [String] typ
15
+ # @param [String] ps
16
+ # @param [String] s
17
+ # @param [Integer] n
18
+ # @return [Boolean]
19
+ def allows(typ, ps, s, n)
20
+ true
21
+ end
22
+ end
23
+ end
data/lib/rnv/error.rb ADDED
@@ -0,0 +1,13 @@
1
+ module RNV
2
+ class Error
3
+ # @return [String]
4
+ def to_s
5
+ "#{@line}:#{@col}:error: #{@message}\n#{@expected}"
6
+ end
7
+
8
+ # @return [String]
9
+ def inspect
10
+ "#<RNV::Error code: :#{@code}, message: '#{@message}', expected: '#{@expected} line: #{@line}, column: #{@col}>"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,25 @@
1
+ module RNV
2
+ # Object to modify data before validation (eg: HTML5 data-* attributes)
3
+ class PreProcessor
4
+ # replace attributes before validate
5
+ # @param [Array<Array<String>>] attrs
6
+ # @return [Array<Array<String>>]
7
+ def attributes(attrs)
8
+ attrs
9
+ end
10
+
11
+ # replace tag name before validate
12
+ # @param [String] tag
13
+ # @return [String]
14
+ def tag(tag)
15
+ tag
16
+ end
17
+
18
+ # replace content text before validate
19
+ # @param [String] txt
20
+ # @return [String]
21
+ def text(txt)
22
+ txt
23
+ end
24
+ end
25
+ end
data/lib/rnv/validator.rb CHANGED
@@ -1,11 +1,12 @@
1
1
  require 'nokogiri'
2
2
  require 'rnv/rnv'
3
+ require 'rnv/pre_processor'
3
4
 
4
5
  module RNV
5
6
  # @!visibility private
6
7
  class NokogiriSaxDocument < Nokogiri::XML::SAX::Document
7
8
  # @return [Nokogiri::XML::SAX::ParserContext]
8
- attr_accessor :ctx
9
+ attr_accessor :ctx, :pre_processor
9
10
  # @param [RNV::Document] document
10
11
  def initialize(document)
11
12
  @document = document
@@ -15,23 +16,23 @@ module RNV
15
16
  update_line_col
16
17
  tag_attrs = attrs.map { |attr| [attr.uri ? "#{attr.uri}:#{attr.localname}" : attr.localname, attr.value] }
17
18
  tag_name = uri ? "#{uri}:#{name}" : name
18
- @document.start_tag(tag_name, tag_attrs.flatten)
19
+ @document.start_tag(@pre_processor.tag(tag_name), @pre_processor.attributes(tag_attrs))
19
20
  end
20
21
 
21
22
  def end_element_namespace(name, prefix = nil, uri = nil)
22
23
  update_line_col
23
24
  tag_name = uri ? "#{uri}:#{name}" : name
24
- @document.end_tag(tag_name)
25
+ @document.end_tag(@pre_processor.tag(tag_name))
25
26
  end
26
27
 
27
28
  def characters str
28
29
  update_line_col
29
- @document.characters(str)
30
+ @document.characters(@pre_processor.text(str))
30
31
  end
31
32
 
32
33
  def cdata_block str
33
34
  update_line_col
34
- @document.characters(str)
35
+ @document.characters(@pre_processor.text(str))
35
36
  end
36
37
 
37
38
  private
@@ -57,25 +58,29 @@ module RNV
57
58
  end
58
59
 
59
60
  # @param [String] str RNC schema buffer
61
+ # @return [Boolean] true if schema loaded successfuly
60
62
  def load_schema_from_string(str)
61
63
  @document.load_string(str)
62
64
  end
63
65
 
64
66
  # @param [String] file RNC schema filename
67
+ # @return [Boolean] true if schema loaded successfuly
65
68
  def load_schema_from_file(file)
66
69
  @document.load_file(file)
67
70
  end
68
71
 
69
72
  # parse and validate buffer
70
73
  # @param [String] str XML buffer to parse
74
+ # @param [RNV::PreProcessor] pre_processor an optional pre-processor for tag and attributes data
71
75
  # @return [Boolean] true if valid
72
- def parse_string(str)
73
- @document.errors = [] # reset errors
76
+ def parse_string(str, pre_processor = PreProcessor.new)
74
77
  @document.start_document
75
78
  rnv_doc = NokogiriSaxDocument.new(@document)
79
+ rnv_doc.pre_processor = pre_processor
76
80
 
77
81
  parser = Nokogiri::XML::SAX::Parser.new(rnv_doc)
78
82
  parser.parse_memory(str) do |ctx|
83
+ ctx.replace_entities = true
79
84
  rnv_doc.ctx = ctx
80
85
  end
81
86
 
@@ -84,16 +89,18 @@ module RNV
84
89
 
85
90
  # parse and validate file
86
91
  # @param [String, File] xml XML file to parse
92
+ # @param [RNV::PreProcessor] pre_processor an optional pre-processor for tag and attributes data
87
93
  # @return [Boolean] true if valid
88
- def parse_file(xml)
89
- @document.errors = [] # reset errors
94
+ def parse_file(xml, pre_processor = PreProcessor.new)
90
95
  @document.start_document
91
96
  rnv_doc = NokogiriSaxDocument.new(@document)
97
+ rnv_doc.pre_processor = pre_processor
92
98
 
93
99
  file = xml.is_a?(File) ? xml : File.open(xml)
94
100
 
95
101
  parser = Nokogiri::XML::SAX::Parser.new(rnv_doc)
96
102
  parser.parse(file) do |ctx|
103
+ ctx.replace_entities = true
97
104
  rnv_doc.ctx = ctx
98
105
  end
99
106
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_rnv
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julien Boulnois
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-07 00:00:00.000000000 Z
11
+ date: 2021-04-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -147,8 +147,11 @@ files:
147
147
  - ext/rnv/src/xsd_tm.c
148
148
  - ext/rnv/src/xsd_tm.h
149
149
  - lib/rnv.rb
150
+ - lib/rnv/data_type_library.rb
151
+ - lib/rnv/error.rb
152
+ - lib/rnv/pre_processor.rb
150
153
  - lib/rnv/validator.rb
151
- homepage:
154
+ homepage: https://github.com/immateriel/ruby_rnv
152
155
  licenses:
153
156
  - MIT
154
157
  metadata: {}
@@ -170,5 +173,5 @@ requirements: []
170
173
  rubygems_version: 3.0.8
171
174
  signing_key:
172
175
  specification_version: 4
173
- summary: RelaxNG compact syntax validator
176
+ summary: RelaxNG compact syntax validator for Ruby
174
177
  test_files: []