1/** 2 * rngparser.c: parser for the Relax-NG compact syntax. 3 * 4 * Based on: 5 * RELAX NG Compact Syntax 6 * Committee Specification 21 November 2002 7 * http://www.oasis-open.org/committees/relax-ng/compact-20021121.html 8 * 9 * See Copyright for the status of this software. 10 * 11 * Daniel Veillard <veillard@redhat.com> 12 */ 13 14#include <string.h> 15 16#include <libxml/parser.h> 17#include <libxml/parserInternals.h> 18#include <libxml/relaxng.h> 19#include <libxml/dict.h> 20 21#define TODO \ 22 xmlGenericError(xmlGenericErrorContext, \ 23 "Unimplemented block at %s:%d\n", \ 24 __FILE__, __LINE__); 25 26#define MAX_TOKEN 10 27 28typedef enum { 29 CRNG_NONE = 0, 30 CRNG_OP = 1, 31 CRNG_KEYWORD, 32 CRNG_IDENTIFIER, 33 CRNG_LITERAL_SEGMENT, 34 CRNG_CNAME, 35 CRNG_QNAME, 36 CRNG_NSNAME, 37 CRNG_DOCUMENTATION 38} xmlCRNGTokType; 39 40typedef enum { 41 CRNG_OKAY = 0, 42 CRNG_MEMORY_ERROR, 43 CRNG_INVALID_CHAR_ERROR, 44 CRNG_END_ERROR, 45 CRNG_ENCODING_ERROR 46} xmlCRNGError; 47 48typedef enum { 49 XML_CRNG_ERROR = -1, 50 XML_CRNG_OK = 0, 51 XML_CRNG_EOF = 1 52} xmlCRelaxNGParserState; 53 54typedef struct _token _token; 55typedef _token *tokenPtr; 56struct _token { 57 xmlCRNGTokType toktype; 58 int toklen; 59 const xmlChar *token; 60 const xmlChar *prefix; 61}; 62 63typedef struct _xmlCRelaxNGParserCtxt xmlCRelaxNGParserCtxt; 64typedef xmlCRelaxNGParserCtxt *xmlCRelaxNGParserCtxtPtr; 65struct _xmlCRelaxNGParserCtxt { 66 void *userData; /* user specific data block */ 67 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */ 68 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */ 69 xmlRelaxNGValidErr err; 70 71 const xmlChar *compact; 72 const xmlChar *end; 73 const xmlChar *cur; 74 int isElem; 75 int lineno; 76 const xmlChar *linestart; 77 const char *filename; 78 79 int nbTokens; 80 int firstToken; 81 _token tokens[MAX_TOKEN]; 82 int totalToken; 83 84 xmlCRelaxNGParserState state; 85 86 int nbErrors; 87 88 xmlDocPtr res; /* the result */ 89 xmlNodePtr ins; /* the current insertion node */ 90 91 xmlNsPtr nsDef; 92 tokenPtr token; 93 94 xmlHashTablePtr namespaces; 95 xmlHashTablePtr datatypes; 96 97 /* 98 * dictionnary and keywords 99 */ 100 xmlDictPtr dict; 101 const xmlChar *key_attribute; 102 const xmlChar *key_default; 103 const xmlChar *key_datatypes; 104 const xmlChar *key_div; 105 const xmlChar *key_element; 106 const xmlChar *key_empty; 107 const xmlChar *key_external; 108 const xmlChar *key_grammar; 109 const xmlChar *key_include; 110 const xmlChar *key_inherit; 111 const xmlChar *key_list; 112 const xmlChar *key_mixed; 113 const xmlChar *key_namespace; 114 const xmlChar *key_notAllowed; 115 const xmlChar *key_parent; 116 const xmlChar *key_start; 117 const xmlChar *key_string; 118 const xmlChar *key_text; 119 const xmlChar *key_token; 120 const xmlChar *key_equal; 121 const xmlChar *key_orequal; 122 const xmlChar *key_andequal; 123 const xmlChar *key_combine; 124 const xmlChar *key_or; 125 const xmlChar *key_comma; 126 const xmlChar *key_and; 127 const xmlChar *key_choice; 128 const xmlChar *key_group; 129 const xmlChar *key_interleave; 130 const xmlChar *key_ref; 131 const xmlChar *key_define; 132 133 /* results */ 134 xmlDocPtr doc; /* the resulting doc */ 135 xmlNodePtr insert; /* the insertion point */ 136 xmlAttrPtr attrs; /* pending attributes */ 137}; 138 139static const xmlChar *xmlCRelaxNGInherit = BAD_CAST "Inherit string"; 140static const xmlChar *xmlCRelaxNGDefault = BAD_CAST "Default string"; 141 142#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) 143/** 144 * IS_BLANK: 145 * @c: an UNICODE value (int) 146 * 147 * Macro to check the following production in the XML spec: 148 * 149 * [3] S ::= (#x20 | #x9 | #xD | #xA)+ 150 */ 151#ifndef IS_BLANK 152#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \ 153 ((c) == 0x0D)) 154#endif 155#define IS_SEPARATOR(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \ 156 ((c) == 0x0D) || (c == '#')) 157 158#define CRNG_ERROR0(X) \ 159 { xmlCRNGErr(ctxt, X, NULL); return(0); } 160#define CRNG_ERROR(X) \ 161 { xmlCRNGErr(ctxt, X, NULL); } 162 163#define CRNG_MEM_ERROR0() \ 164 { xmlCRNGErr(ctxt, CRNG_MEMORY_ERROR, NULL); return(0); } 165#define CRNG_MEM_ERROR() \ 166 { xmlCRNGErr(ctxt, CRNG_MEMORY_ERROR, NULL); } 167 168#define ERROR(str) xmlCRNGErr(ctxt, 0, str); 169 170static void 171xmlCRNGErr(xmlCRelaxNGParserCtxtPtr ctxt, int err_no, const char *err_msg) { 172 const xmlChar *cur; 173 xmlChar buffer[150]; 174 int i, l; 175 176 if (ctxt != NULL) { 177 if (ctxt->filename != NULL) 178 fprintf(stderr, "%s:%d ", ctxt->filename, ctxt->lineno); 179 } 180 if (err_msg != NULL) { 181 fprintf(stderr, "error: %s\n", err_msg); 182 } else if (err_no != 0) 183 fprintf(stderr, "error %d\n", err_no); 184 cur = ctxt->cur; 185 while ((*cur != '\n') && (*cur != '\r') && (ctxt->cur - cur < 80)) cur--; 186 l = ctxt->cur - cur; 187 cur++; 188 for (i = 0; i < 100;i++) { 189 if ((*cur == '\n') || (*cur == '\r')) break; 190 buffer[i] = *cur++; 191 } 192 buffer[i] = 0; 193 fprintf(stderr, "%s\n", buffer); 194 for (i = 0; i < l;i++) buffer[i] = ' '; 195 buffer[i++] = '^'; 196 buffer[i++] = 0; 197 fprintf(stderr, "%s\n", buffer); 198} 199 200/** 201 * IS_OP 202 * @c: an UNICODE value (int) 203 * 204 * Macro to check for operator value 205 */ 206#ifndef IS_OP 207#define IS_OP(c) (((c) == ',') || ((c) == '&') || ((c) == '|') || \ 208 ((c) == '?') || ((c) == '-') || ((c) == '*') || \ 209 ((c) == '{') || ((c) == '}') || ((c) == '(') || \ 210 ((c) == ')') || ((c) == '+') || ((c) == '=') || \ 211 ((c) == ':')) 212#endif 213 214static int 215xmlCRNGIsKeyword(xmlCRelaxNGParserCtxtPtr ctxt, const xmlChar *str) { 216 if ((str == ctxt->key_attribute) || 217 (str == ctxt->key_default) || 218 (str == ctxt->key_datatypes) || 219 (str == ctxt->key_div) || 220 (str == ctxt->key_element) || 221 (str == ctxt->key_empty) || 222 (str == ctxt->key_external) || 223 (str == ctxt->key_grammar) || 224 (str == ctxt->key_include) || 225 (str == ctxt->key_inherit) || 226 (str == ctxt->key_list) || 227 (str == ctxt->key_mixed) || 228 (str == ctxt->key_namespace) || 229 (str == ctxt->key_notAllowed) || 230 (str == ctxt->key_parent) || 231 (str == ctxt->key_start) || 232 (str == ctxt->key_string) || 233 (str == ctxt->key_text) || 234 (str == ctxt->key_token)) 235 return(1); 236 return(0); 237 238} 239 240/* 241 * xmlCRNGNextToken: 242 * ctxt: a compact RNG parser context 243 * 244 * Scan the schema to get the next token 245 * 246 * Return 0 if success and -1 in case of error 247 */ 248 249static int 250xmlCRNGNextToken(xmlCRelaxNGParserCtxtPtr ctxt) { 251 const xmlChar *cur; 252 tokenPtr token; 253 254 if (ctxt == NULL) return(-1); 255 if (ctxt->nbTokens >= MAX_TOKEN) return(-1); 256 token = &(ctxt->tokens[(ctxt->firstToken + ctxt->nbTokens) % MAX_TOKEN]); 257 token->toktype = CRNG_NONE; 258 259 if (ctxt->cur == NULL) { 260 ctxt->cur = ctxt->compact; 261 } 262retry: 263 if (ctxt->cur >= ctxt->end) { 264 ctxt->state = XML_CRNG_EOF; 265 return(-1); 266 } 267 while ((ctxt->cur < ctxt->end) && 268 (IS_BLANK(*ctxt->cur))) ctxt->cur++; 269 if (ctxt->cur >= ctxt->end) { 270 ctxt->state = XML_CRNG_EOF; 271 return(-1); 272 } 273 if (*ctxt->cur == '#') { 274 cur = ctxt->cur; 275 cur++; 276 while ((cur < ctxt->end) && (*cur != '\n') && (*cur != '\r')) 277 cur++; 278 ctxt->cur = cur; 279 goto retry; 280 } else if (*ctxt->cur == '"') { 281 /* string, check for '"""' */ 282 ctxt->cur++; 283 if (ctxt->cur >= ctxt->end) goto eof; 284 cur = ctxt->cur; 285 if ((ctxt->end - ctxt->end > 2) && 286 (*cur == '"') && (cur[1] == '"')) { 287 TODO 288 } else { 289 while ((cur < ctxt->end) && (*cur != '"')) cur++; 290 if (cur >= ctxt->end) goto eof; 291 token->toklen = cur - ctxt->cur; 292 token->token = xmlDictLookup(ctxt->dict, ctxt->cur, token->toklen); 293 token->toktype = CRNG_LITERAL_SEGMENT; 294 token->prefix = NULL; 295 cur++; 296 ctxt->cur = cur; 297 } 298 } else if (*ctxt->cur == '\'') { 299 /* string, check for "'''" */ 300 TODO 301 } else if ((IS_OP(*ctxt->cur)) || (*ctxt->cur == ':')) { 302 cur = ctxt->cur; 303 cur++; 304 if ((cur < ctxt->end) && 305 (((*cur == '=') && 306 ((*ctxt->cur == '|') || (*ctxt->cur == '&'))) || 307 ((*cur == '*') && (*ctxt->cur == ':')))) { 308 token->toklen = 2; 309 } else { 310 token->toklen = 1; 311 } 312 token->token = xmlDictLookup(ctxt->dict, ctxt->cur, token->toklen); 313 token->toktype = CRNG_OP; 314 token->prefix = NULL; 315 ctxt->cur += token->toklen; 316 } else { 317 int escape = 0; 318 319 cur = ctxt->cur; 320 if (*cur == '\\') { 321 escape = 1; 322 cur++; 323 ctxt->cur++; 324 } 325 while ((cur < ctxt->end) && 326 (!(IS_SEPARATOR(*cur))) && (!(IS_OP(*cur)))) cur++; 327 328 token->toklen = cur - ctxt->cur; 329 token->token = xmlDictLookup(ctxt->dict, ctxt->cur, token->toklen); 330 token->prefix = NULL; 331 ctxt->cur = cur; 332 if ((escape == 0) && (xmlCRNGIsKeyword(ctxt, token->token))) 333 token->toktype = CRNG_KEYWORD; 334 else { 335 token->toktype = CRNG_IDENTIFIER; 336 } 337 if (*ctxt->cur == ':') { 338 ctxt->cur++; 339 if (*ctxt->cur == '*') { 340 ctxt->cur++; 341 token->toktype = CRNG_NSNAME; 342 } else { 343 cur = ctxt->cur; 344 while ((cur < ctxt->end) && 345 (!(IS_SEPARATOR(*cur))) && (!(IS_OP(*cur)))) cur++; 346 token->prefix = token->token; 347 token->toklen = cur - ctxt->cur; 348 token->token = xmlDictLookup(ctxt->dict, ctxt->cur, 349 token->toklen); 350 ctxt->cur = cur; 351 if (xmlValidateNCName(token->token, 0) == 0) 352 token->toktype = CRNG_QNAME; 353 else { 354 TODO /* sounds like an error ! */ 355 token->toktype = CRNG_IDENTIFIER; 356 } 357 } 358 } 359 } 360 ctxt->nbTokens++; 361 return(0); 362eof: 363 ctxt->state = XML_CRNG_EOF; 364 CRNG_ERROR(CRNG_END_ERROR); 365 return(-1); 366} 367 368/** 369 * xmlParseCRNGGetToken: 370 * @ctxt: a compact RNG parser context 371 * @no: the number of the token from 1 for the first one 372 * and 2, 3 ... for read-ahead 373 * 374 * Token reading interface 375 * 376 * returns a pointer to the new token, or NULL in case of error or EOF 377 */ 378static tokenPtr 379xmlParseCRNGGetToken(xmlCRelaxNGParserCtxtPtr ctxt, int no) { 380 tokenPtr ret; 381 int res; 382 383 if ((no <= 0) || (no >= MAX_TOKEN)) return(NULL); 384 no--; 385 while (ctxt->nbTokens <= no) { 386 res = xmlCRNGNextToken(ctxt); 387 if (res < 0) 388 return(NULL); 389 } 390 ret = &(ctxt->tokens[(ctxt->firstToken + no) % MAX_TOKEN]); 391 return(ret); 392} 393 394/** 395 * xmlParseCRNGDropTokens: 396 * @ctxt: a compact RNG parser context 397 * @nr: the number of token marked as read 398 * 399 * mark a number of token as read and consumed. 400 * 401 * Returns -1 in case of error and 0 otherwise 402 */ 403static int 404xmlParseCRNGDropTokens(xmlCRelaxNGParserCtxtPtr ctxt, int nr) { 405 if ((nr <= 0) || (nr >= MAX_TOKEN)) return(-1); 406 while ((ctxt->nbTokens >0) && (nr > 0)) { 407 ctxt->firstToken++; 408 nr--; 409 ctxt->nbTokens--; 410 ctxt->totalToken++; 411 if (ctxt->totalToken == 384) 412 fprintf(stderr, "found\n"); 413 } 414 ctxt->firstToken = ctxt->firstToken % MAX_TOKEN; 415 return(0); 416} 417 418static void 419xmlParseCRNGTokenize(xmlCRelaxNGParserCtxtPtr ctxt) { 420 tokenPtr token; 421 422 token = xmlParseCRNGGetToken(ctxt, 1); 423 while (token != NULL) { 424 switch (token->toktype) { 425 case CRNG_NONE: printf("none"); break; 426 case CRNG_OP: printf("op"); break; 427 case CRNG_KEYWORD: printf("keyword"); break; 428 case CRNG_IDENTIFIER: printf("identifier"); break; 429 case CRNG_LITERAL_SEGMENT: printf("literal"); break; 430 case CRNG_CNAME: printf("cname"); break; 431 case CRNG_QNAME: printf("qname"); break; 432 case CRNG_NSNAME: printf("nsname"); break; 433 case CRNG_DOCUMENTATION: printf("doc"); break; 434 } 435 printf(":%s\n", token->token); 436 xmlParseCRNGDropTokens(ctxt, 1); 437 token = xmlParseCRNGGetToken(ctxt, 1); 438 } 439} 440 441/** 442 * xmlParseCRNG_attribute: 443 * @ctxt: a compact RNG parser context 444 * @name: the attribute name 445 * @ns: the attribute namespace 446 * @value: the attribute value 447 * 448 * implements attribute of the RELAX NG Compact Syntax Appendix A 449 * 450 * Returns 0 in case of success and -1 in case of error 451 */ 452static int 453xmlParseCRNG_attribute(xmlCRelaxNGParserCtxtPtr ctxt, 454 const xmlChar *name, 455 xmlNsPtr ns, 456 const xmlChar *value) 457{ 458 xmlAttrPtr attr; 459 460 attr = xmlNewNsPropEatName(NULL, ns, (xmlChar *) name, value); 461 if (attr == NULL) CRNG_MEM_ERROR0(); 462 attr->next = ctxt->attrs; 463 if (ctxt->attrs != NULL) 464 ctxt->attrs->prev = attr; 465 ctxt->attrs = attr; 466 return(0); 467} 468 469/** 470 * xmlParseCRNG_bindPrefix: 471 * @ctxt: a compact RNG parser context 472 * @prefix: the namespace prefix or NULL 473 * @namespace: the namespace name 474 * 475 * implements bindPrefix of the RELAX NG Compact Syntax Appendix A 476 * 477 * Returns 0 in case of success and -1 in case of error 478 */ 479static int 480xmlParseCRNG_bindPrefix(xmlCRelaxNGParserCtxtPtr ctxt, 481 const xmlChar *prefix, 482 const xmlChar *namespace) 483{ 484 int ret; 485 486 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")) && 487 (!xmlStrEqual(namespace, XML_XML_NAMESPACE))) { 488 ERROR("The \"xml\" prefix must be bound to \"http://www.w3.org/XML/1998/namespace\""); 489 return(-1); 490 } else if ((xmlStrEqual(namespace, XML_XML_NAMESPACE)) && 491 (!xmlStrEqual(prefix, BAD_CAST "xml"))) { 492 ERROR("The \"http://www.w3.org/XML/1998/namespace\" name must be bound to \"xml\" prefix"); 493 return(-1); 494 } 495 if (ctxt->namespaces == NULL) 496 ctxt->namespaces = xmlHashCreate(10); 497 if (ctxt->namespaces == NULL) { 498 ERROR("Failed to create namespace hash table"); 499 return(-1); 500 } 501 if (prefix == NULL) 502 ret = xmlHashAddEntry(ctxt->namespaces, xmlCRelaxNGDefault, 503 (void *) namespace); 504 else 505 ret = xmlHashAddEntry(ctxt->namespaces, prefix, 506 (void *) namespace); 507 if (ret < 0) { 508 if (prefix == NULL) { 509 ERROR("Redefinition of default namespace"); 510 } else { 511 ERROR("Redefinition of namespace"); 512 } 513 return(-1); 514 } 515 516 return(0); 517} 518 519/** 520 * xmlParseCRNG_bindDatatypePrefix: 521 * @ctxt: a compact RNG parser context 522 * @prefix: the datatype prefix 523 * @namespace: the datatype identifier 524 * 525 * implements bindDatatypePrefix of the RELAX NG Compact Syntax Appendix A 526 * 527 * Returns 0 in case of success and -1 in case of error 528 */ 529static int 530xmlParseCRNG_bindDatatypePrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, 531 const xmlChar *prefix, 532 const xmlChar *namespace) 533{ 534 int ret; 535 536 if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xsd")) && 537 (!xmlStrEqual(namespace, 538 BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes"))) { 539 ERROR("The \"xsd\" prefix must be bound to \"http://www.w3.org/2001/XMLSchema-datatypes\""); 540 return(-1); 541 } 542 if (ctxt->datatypes == NULL) 543 ctxt->datatypes = xmlHashCreate(10); 544 if (ctxt->datatypes == NULL) { 545 ERROR("Failed to create namespace hash table"); 546 return(-1); 547 } 548 ret = xmlHashAddEntry(ctxt->datatypes, prefix, 549 (void *) namespace); 550 if (ret < 0) { 551 ERROR("Redefinition of datatype"); 552 return(-1); 553 } 554 return(0); 555} 556 557/** 558 * xmlParseCRNG_lookupPrefix: 559 * @ctxt: a compact RNG parser context 560 * @prefix: the namespace prefix or NULL 561 * 562 * implements lookupPrefix of the RELAX NG Compact Syntax Appendix A 563 * 564 * Returns the prefix in case of success or NULL in case of error 565 */ 566static const xmlChar * 567xmlParseCRNG_lookupPrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, 568 const xmlChar *prefix) 569{ 570 const xmlChar *ret; 571 572 if (prefix == NULL) 573 ret = xmlHashLookup(ctxt->namespaces, xmlCRelaxNGDefault); 574 else 575 ret = xmlHashLookup(ctxt->namespaces, prefix); 576 return(ret); 577} 578 579/** 580 * xmlParseCRNG_lookupDatatypePrefix: 581 * @ctxt: a compact RNG parser context 582 * @prefix: the namespace prefix or NULL 583 * 584 * implements lookupDatatypePrefix of the RELAX NG Compact Syntax Appendix A 585 * 586 * Returns the prefix in case of success or NULL in case of error 587 */ 588static const xmlChar * 589xmlParseCRNG_lookupDatatypePrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, 590 const xmlChar *prefix) 591{ 592 const xmlChar *ret; 593 ret = xmlHashLookup(ctxt->datatypes, prefix); 594 return(ret); 595} 596 597/** 598 * xmlParseCRNG_datatypeAttributes: 599 * @ctxt: a compact RNG parser context 600 * @prefix: the namespace prefix or NULL 601 * 602 * implements lookupPrefix of the RELAX NG Compact Syntax Appendix A 603 * 604 * Returns the prefix in case of success or NULL in case of error 605 */ 606static xmlAttrPtr 607xmlParseCRNG_datatypeAttributes(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, 608 const xmlChar *library, const xmlChar *type) 609{ 610 xmlAttrPtr lib, typ; 611 612 lib = xmlNewNsProp(NULL, NULL, BAD_CAST "datatypeLibrary", library); 613 if (lib == NULL) { 614 CRNG_MEM_ERROR(); 615 return(NULL); 616 } 617 typ = xmlNewNsProp(NULL, NULL, BAD_CAST "type", type); 618 if (typ == NULL) { 619 CRNG_MEM_ERROR(); 620 return(lib); 621 } 622 lib->next = typ; 623 624 return(lib); 625} 626 627/** 628 * xmlParseCRNG_XXX: 629 * @ctxt: a compact RNG parser context 630 * 631 * Parse XXX of the RELAX NG Compact Syntax Appendix A 632 * 633 * Returns 0 in case of success and -1 in case of error 634 */ 635static int 636xmlParseCRNG_XXX(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED) 637{ 638 return(0); 639} 640 641static int xmlParseCRNG_pattern(xmlCRelaxNGParserCtxtPtr ctxt); 642static int xmlParseCRNG_nameClass(xmlCRelaxNGParserCtxtPtr ctxt); 643 644/** 645 * xmlParseCRNG_params: 646 * @ctxt: a compact RNG parser context 647 * 648 * Parse params of the RELAX NG Compact Syntax Appendix A 649 * 650 * Returns 0 in case of success and -1 in case of error 651 */ 652static int 653xmlParseCRNG_params(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED) 654{ 655 TODO 656 return(0); 657} 658 659/** 660 * xmlParseCRNG_exceptNameClass: 661 * @ctxt: a compact RNG parser context 662 * 663 * Parse exceptNameClass of the RELAX NG Compact Syntax Appendix A 664 * 665 * Returns 0 in case of success and -1 in case of error 666 */ 667static int 668xmlParseCRNG_exceptNameClass(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED) 669{ 670 tokenPtr token; 671 xmlNodePtr insert = ctxt->insert, cur; 672 673 token = xmlParseCRNGGetToken(ctxt, 1); 674 if ((token->toktype == CRNG_OP) && 675 (token->token[0] == '-') && (token->token[1] == 0)) { 676 xmlParseCRNGDropTokens(ctxt, 1); 677 cur = xmlNewNode(NULL, BAD_CAST "except"); 678 if (cur == NULL) CRNG_MEM_ERROR0(); 679 if (ctxt->insert != NULL) 680 xmlAddChild(ctxt->insert, cur); 681 ctxt->insert = cur; 682 xmlParseCRNG_nameClass(ctxt); 683 } 684 ctxt->insert = insert; 685 return(0); 686} 687 688/** 689 * xmlParseCRNG_innerNameClass: 690 * @ctxt: a compact RNG parser context 691 * 692 * Parse innerNameClass of the RELAX NG Compact Syntax Appendix A 693 * 694 * Returns 0 in case of success and -1 in case of error 695 */ 696static int 697xmlParseCRNG_innerNameClass(xmlCRelaxNGParserCtxtPtr ctxt) 698{ 699 tokenPtr token; 700 xmlNodePtr cur; 701 702 token = xmlParseCRNGGetToken(ctxt, 1); 703 if (token->toktype == CRNG_OP) { 704 if ((token->token[0] == '(') && (token->token[1] == 0)) { 705 xmlParseCRNGDropTokens(ctxt, 1); 706 xmlParseCRNG_nameClass(ctxt); 707 token = xmlParseCRNGGetToken(ctxt, 1); 708 if ((token->toktype != CRNG_OP) || 709 (token->token[0] != ')') || (token->token[1] != 0)) { 710 ERROR("Expecting \")\" here"); 711 } 712 xmlParseCRNGDropTokens(ctxt, 1); 713 } else if ((token->token[0] == '*') && (token->token[1] == 0)) { 714 xmlParseCRNGDropTokens(ctxt, 1); 715 cur = xmlNewNode(NULL, BAD_CAST "anyName"); 716 if (cur == NULL) CRNG_MEM_ERROR0(); 717 if (ctxt->insert != NULL) 718 xmlAddChild(ctxt->insert, cur); 719 ctxt->insert = cur; 720 xmlParseCRNG_exceptNameClass(ctxt); 721 } else { 722 TODO 723 } 724 } else if ((token->toktype == CRNG_IDENTIFIER) || 725 (token->toktype == CRNG_KEYWORD)) { 726 cur = xmlNewNode(NULL, BAD_CAST "name"); 727 if (cur == NULL) CRNG_MEM_ERROR0(); 728 if (ctxt->isElem) { 729 xmlSetProp(cur, BAD_CAST "ns", 730 xmlParseCRNG_lookupPrefix(ctxt, NULL)); 731 } else { 732 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST ""); 733 } 734 xmlNodeAddContent(cur, token->token); 735 if (ctxt->insert != NULL) 736 xmlAddChild(ctxt->insert, cur); 737 ctxt->insert = cur; 738 xmlParseCRNGDropTokens(ctxt, 1); 739 } else if (token->toktype == CRNG_CNAME) { 740 TODO 741 } else if (token->toktype == CRNG_NSNAME) { 742 cur = xmlNewNode(NULL, BAD_CAST "nsName"); 743 if (cur == NULL) CRNG_MEM_ERROR0(); 744 xmlSetProp(cur, BAD_CAST "ns", 745 xmlParseCRNG_lookupPrefix(ctxt, token->token)); 746 if (ctxt->insert != NULL) 747 xmlAddChild(ctxt->insert, cur); 748 ctxt->insert = cur; 749 xmlParseCRNGDropTokens(ctxt, 1); 750 xmlParseCRNG_exceptNameClass(ctxt); 751 } else { 752 TODO /* probably an error */ 753 } 754 755 return(0); 756} 757 758/** 759 * xmlParseCRNG_nameClass: 760 * @ctxt: a compact RNG parser context 761 * 762 * Parse nameClass of the RELAX NG Compact Syntax Appendix A 763 * 764 * Returns 0 in case of success and -1 in case of error 765 */ 766static int 767xmlParseCRNG_nameClass(xmlCRelaxNGParserCtxtPtr ctxt) 768{ 769 tokenPtr token; 770 xmlNodePtr insert = ctxt->insert, last, choice; 771 772 ctxt->insert = NULL; 773 xmlParseCRNG_innerNameClass(ctxt); 774 last = ctxt->insert; 775 token = xmlParseCRNGGetToken(ctxt, 1); 776 while ((token->toktype == CRNG_OP) && 777 (token->token[0] == '|') && (token->token[1] == 0)) { 778 choice = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_choice); 779 xmlParseCRNGDropTokens(ctxt, 1); 780 if (choice == NULL) CRNG_MEM_ERROR0(); 781 ctxt->insert = NULL; 782 xmlParseCRNG_innerNameClass(ctxt); 783 xmlAddChild(choice, last); 784 xmlAddChild(choice, ctxt->insert); 785 last = choice; 786 token = xmlParseCRNGGetToken(ctxt, 1); 787 } 788 xmlAddChild(insert, last); 789 790 ctxt->insert = insert; 791 return(0); 792} 793 794/** 795 * xmlParseCRNG_patternBlock: 796 * @ctxt: a compact RNG parser context 797 * 798 * Parse a pattern block of the RELAX NG Compact Syntax Appendix A 799 * 800 * Returns 0 in case of success and -1 in case of error 801 */ 802static int 803xmlParseCRNG_patternBlock(xmlCRelaxNGParserCtxtPtr ctxt) 804{ 805 tokenPtr token; 806 807 token = xmlParseCRNGGetToken(ctxt, 1); 808 if ((token->toktype != CRNG_OP) || 809 (token->token[0] != '{') || (token->token[1] != 0)) { 810 ERROR("Expecting \"{\" here"); 811 } 812 xmlParseCRNGDropTokens(ctxt, 1); 813 xmlParseCRNG_pattern(ctxt); 814 token = xmlParseCRNGGetToken(ctxt, 1); 815 if ((token->toktype != CRNG_OP) || 816 (token->token[0] != '}') || (token->token[1] != 0)) { 817 ERROR("Expecting \"}\" here"); 818 } 819 xmlParseCRNGDropTokens(ctxt, 1); 820 return(0); 821} 822 823/** 824 * xmlParseCRNG_datatype: 825 * @ctxt: a compact RNG parser context 826 * 827 * Parse datatype of the RELAX NG Compact Syntax Appendix A 828 * 829 * Returns 0 in case of success and -1 in case of error 830 */ 831static int 832xmlParseCRNG_datatype(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED) 833{ 834 tokenPtr token; 835 xmlAttrPtr attrs = NULL; 836 837 token = xmlParseCRNGGetToken(ctxt, 1); 838 if (token->toktype == CRNG_KEYWORD) { 839 if (token->token == ctxt->key_string) { 840 attrs = xmlParseCRNG_datatypeAttributes(ctxt, BAD_CAST "", 841 token->token); 842 xmlParseCRNGDropTokens(ctxt, 1); 843 } else if (token->token == ctxt->key_token) { 844 attrs = xmlParseCRNG_datatypeAttributes(ctxt, BAD_CAST "", 845 token->token); 846 xmlParseCRNGDropTokens(ctxt, 1); 847 } else { 848 TODO /* probably an error */ 849 } 850 } else if (token->toktype == CRNG_LITERAL_SEGMENT) { 851 ctxt->insert = xmlNewNode(NULL, BAD_CAST "value"); 852 xmlParseCRNGDropTokens(ctxt, 1); 853 if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); 854 xmlNodeAddContent(ctxt->insert, token->token); 855 } else if (token->toktype == CRNG_QNAME) { 856 attrs = xmlParseCRNG_datatypeAttributes(ctxt, 857 xmlParseCRNG_lookupDatatypePrefix(ctxt, token->prefix), 858 token->token); 859 } else { 860 TODO 861 } 862 if (attrs != NULL) { 863 token = xmlParseCRNGGetToken(ctxt, 1); 864 if (token->toktype == CRNG_LITERAL_SEGMENT) { 865 ctxt->insert = xmlNewNode(NULL, BAD_CAST "value"); 866 xmlParseCRNGDropTokens(ctxt, 1); 867 if (ctxt->insert == NULL) { 868 xmlFreePropList(attrs); 869 CRNG_MEM_ERROR0(); 870 } 871 ctxt->insert->properties = attrs; 872 xmlNodeAddContent(ctxt->insert, token->token); 873 } else if ((token->toktype == CRNG_OP) && 874 (token->token[0] == '{') && (token->token[0] == 0)) { 875 ctxt->insert = xmlNewNode(NULL, BAD_CAST "data"); 876 xmlParseCRNGDropTokens(ctxt, 1); 877 if (ctxt->insert == NULL) { 878 xmlFreePropList(attrs); 879 CRNG_MEM_ERROR0(); 880 } 881 ctxt->insert->properties = attrs; 882 xmlParseCRNG_params(ctxt); 883 } else { 884 ctxt->insert = xmlNewNode(NULL, BAD_CAST "data"); 885 xmlParseCRNGDropTokens(ctxt, 1); 886 if (ctxt->insert == NULL) { 887 xmlFreePropList(attrs); 888 CRNG_MEM_ERROR0(); 889 } 890 ctxt->insert->properties = attrs; 891 xmlNodeAddContent(ctxt->insert, token->token); 892 } 893 } 894 return(0); 895} 896 897/** 898 * xmlParseCRNG_primary: 899 * @ctxt: a compact RNG parser context 900 * 901 * Parse primary of the RELAX NG Compact Syntax Appendix A 902 * 903 * Returns 0 in case of success and -1 in case of error 904 */ 905static int 906xmlParseCRNG_primary(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED) 907{ 908 tokenPtr token; 909 910 token = xmlParseCRNGGetToken(ctxt, 1); 911 if (token == NULL) 912 return(0); 913 if (token->toktype == CRNG_KEYWORD) { 914 if (token->token == ctxt->key_element) { 915 ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); 916 xmlParseCRNGDropTokens(ctxt, 1); 917 if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); 918 ctxt->isElem = 1; 919 xmlParseCRNG_nameClass(ctxt); 920 xmlParseCRNG_patternBlock(ctxt); 921 } else if (token->token == ctxt->key_attribute) { 922 ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); 923 xmlParseCRNGDropTokens(ctxt, 1); 924 if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); 925 ctxt->isElem = 0; 926 xmlParseCRNG_nameClass(ctxt); 927 xmlParseCRNG_patternBlock(ctxt); 928 } else if (token->token == ctxt->key_mixed) { 929 ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); 930 xmlParseCRNGDropTokens(ctxt, 1); 931 if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); 932 xmlParseCRNG_patternBlock(ctxt); 933 } else if (token->token == ctxt->key_list) { 934 ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); 935 xmlParseCRNGDropTokens(ctxt, 1); 936 if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); 937 xmlParseCRNG_patternBlock(ctxt); 938 } else if (token->token == ctxt->key_empty) { 939 ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); 940 xmlParseCRNGDropTokens(ctxt, 1); 941 if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); 942 } else if (token->token == ctxt->key_notAllowed) { 943 ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); 944 xmlParseCRNGDropTokens(ctxt, 1); 945 if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); 946 } else if (token->token == ctxt->key_text) { 947 ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); 948 xmlParseCRNGDropTokens(ctxt, 1); 949 if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); 950 } else if (token->token == ctxt->key_parent) { 951 ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); 952 xmlParseCRNGDropTokens(ctxt, 1); 953 if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); 954 TODO 955 } else if (token->token == ctxt->key_grammar) { 956 ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token); 957 xmlParseCRNGDropTokens(ctxt, 1); 958 if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); 959 TODO 960 } else if (token->token == ctxt->key_external) { 961 ctxt->insert = xmlNewNode(NULL, BAD_CAST "externalRef"); 962 xmlParseCRNGDropTokens(ctxt, 1); 963 if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); 964 TODO 965 } else { 966 TODO 967 } 968 } else if (token->toktype == CRNG_IDENTIFIER) { 969 ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_ref); 970 if (ctxt->insert == NULL) CRNG_MEM_ERROR0(); 971 xmlSetProp(ctxt->insert, BAD_CAST "name", token->token); 972 xmlParseCRNGDropTokens(ctxt, 1); 973 } else if (token->toktype == CRNG_QNAME) { 974 xmlParseCRNG_datatype(ctxt); 975 } else if (token->toktype == CRNG_LITERAL_SEGMENT) { 976 xmlParseCRNG_datatype(ctxt); 977 } else if ((token->toktype == CRNG_OP) && 978 (token->token[0] == '(') && (token->token[1] == 0)) { 979 xmlParseCRNGDropTokens(ctxt, 1); 980 xmlParseCRNG_pattern(ctxt); 981 token = xmlParseCRNGGetToken(ctxt, 1); 982 if ((token->toktype != CRNG_OP) || 983 (token->token[0] != ')') || (token->token[1] != 0)) { 984 ERROR("Expecting \")\" here"); 985 } 986 xmlParseCRNGDropTokens(ctxt, 1); 987 } 988 return(0); 989} 990 991/** 992 * xmlParseCRNG_particle: 993 * @ctxt: a compact RNG parser context 994 * 995 * Parse particle of the RELAX NG Compact Syntax Appendix A 996 * 997 * Returns 0 in case of success and -1 in case of error 998 */ 999static int 1000xmlParseCRNG_particle(xmlCRelaxNGParserCtxtPtr ctxt) 1001{ 1002 tokenPtr token; 1003 xmlNodePtr insert = ctxt->insert, res, tmp = NULL; 1004 1005 ctxt->insert = NULL; 1006 xmlParseCRNG_primary(ctxt); 1007 res = ctxt->insert; 1008 token = xmlParseCRNGGetToken(ctxt, 1); 1009 if ((token != NULL) && (token->toktype == CRNG_OP)) { 1010 if ((token->token[0] == '*') && (token->token[1] == 0)) { 1011 tmp = xmlNewNode(NULL, BAD_CAST "zeroOrMore"); 1012 if (tmp == NULL) CRNG_MEM_ERROR0(); 1013 } else if ((token->token[0] == '+') && (token->token[1] == 0)) { 1014 tmp = xmlNewNode(NULL, BAD_CAST "oneOrMore"); 1015 if (tmp == NULL) CRNG_MEM_ERROR0(); 1016 } else if ((token->token[0] == '?') && (token->token[1] == 0)) { 1017 tmp = xmlNewNode(NULL, BAD_CAST "optional"); 1018 if (tmp == NULL) CRNG_MEM_ERROR0(); 1019 } 1020 if (tmp != NULL) { 1021 xmlAddChild(tmp, res); 1022 res = tmp; 1023 xmlParseCRNGDropTokens(ctxt, 1); 1024 } 1025 } 1026 if (insert != NULL) { 1027 xmlAddChild(insert, res); 1028 ctxt->insert = insert; 1029 } else 1030 ctxt->insert = res; 1031 return(0); 1032} 1033 1034/** 1035 * xmlParseCRNG_pattern: 1036 * @ctxt: a compact RNG parser context 1037 * 1038 * Parse pattern of the RELAX NG Compact Syntax Appendix A 1039 * 1040 * Returns 0 in case of success and -1 in case of error 1041 */ 1042static int 1043xmlParseCRNG_pattern(xmlCRelaxNGParserCtxtPtr ctxt) 1044{ 1045 tokenPtr token; 1046 xmlNodePtr insert = ctxt->insert, prev, grp; 1047 1048 ctxt->insert = NULL; 1049 xmlParseCRNG_particle(ctxt); 1050 prev = ctxt->insert; 1051 token = xmlParseCRNGGetToken(ctxt, 1); 1052 while ((prev != NULL) && (token != NULL) && (token->toktype == CRNG_OP)) { 1053 if (token->token == ctxt->key_or) { 1054 grp = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_choice); 1055 if (grp == NULL) CRNG_MEM_ERROR0(); 1056 } else if (token->token == ctxt->key_and) { 1057 grp = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_interleave); 1058 if (grp == NULL) CRNG_MEM_ERROR0(); 1059 } else if (token->token == ctxt->key_comma) { 1060 grp = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_group); 1061 if (grp == NULL) CRNG_MEM_ERROR0(); 1062 } else 1063 break; 1064 xmlParseCRNGDropTokens(ctxt, 1); 1065 ctxt->insert = NULL; 1066 xmlParseCRNG_particle(ctxt); 1067 xmlAddChild(grp, prev); 1068 xmlAddChild(grp, ctxt->insert); 1069 prev = grp; 1070 token = xmlParseCRNGGetToken(ctxt, 1); 1071 } 1072 if (insert != NULL) { 1073 xmlAddChild(insert, prev); 1074 ctxt->insert = insert; 1075 } else { 1076 ctxt->insert = prev; 1077 } 1078 1079 return(0); 1080} 1081 1082/** 1083 * xmlParseCRNG_component: 1084 * @ctxt: a compact RNG parser context 1085 * 1086 * Parse component of the RELAX NG Compact Syntax Appendix A 1087 * 1088 * Returns 0 in case of success and -1 in case of error 1089 */ 1090static int 1091xmlParseCRNG_component(xmlCRelaxNGParserCtxtPtr ctxt) 1092{ 1093 tokenPtr token, tok2; 1094 xmlNodePtr insert = ctxt->insert; 1095 1096 token = xmlParseCRNGGetToken(ctxt, 1); 1097 if (token == NULL) 1098 return(0); 1099 if (token->toktype == CRNG_KEYWORD) { 1100 if (token->token == ctxt->key_start) { 1101 xmlNodePtr start; 1102 1103 start = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_start); 1104 if (start == NULL) CRNG_MEM_ERROR0(); 1105 if (ctxt->insert != NULL) 1106 xmlAddChild(ctxt->insert, start); 1107 ctxt->insert = start; 1108 xmlParseCRNGDropTokens(ctxt, 1); 1109 token = xmlParseCRNGGetToken(ctxt, 1); 1110 1111 if ((token->toktype == CRNG_OP) && 1112 (token->token == ctxt->key_equal)) { 1113 } else if ((token->toktype == CRNG_OP) && 1114 (token->token == ctxt->key_orequal)) { 1115 xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL, 1116 BAD_CAST "choice"); 1117 } else if ((token->toktype == CRNG_OP) && 1118 (token->token == ctxt->key_andequal)) { 1119 xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL, 1120 BAD_CAST "interleave"); 1121 } else { 1122 ERROR("expecting \"=\" or \"&=\" or \"|=\" here") 1123 return(-1); 1124 } 1125 start->properties = ctxt->attrs; 1126 ctxt->attrs = NULL; 1127 xmlParseCRNGDropTokens(ctxt, 1); 1128 xmlParseCRNG_pattern(ctxt); 1129 1130 } else if (token->token == ctxt->key_include) { 1131 TODO 1132 } else if (token->token == ctxt->key_div) { 1133 TODO 1134 } else { 1135 return(-1); 1136 } 1137 } else if (token->toktype == CRNG_IDENTIFIER) { 1138 xmlNodePtr define; 1139 const xmlChar *identifier; 1140 1141 identifier = token->token; 1142 tok2 = xmlParseCRNGGetToken(ctxt, 2); 1143 if ((tok2->toktype == CRNG_OP) && 1144 (tok2->token == ctxt->key_equal)) { 1145 } else if ((tok2->toktype == CRNG_OP) && 1146 (tok2->token == ctxt->key_orequal)) { 1147 xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL, 1148 BAD_CAST "choice"); 1149 } else if ((tok2->toktype == CRNG_OP) && 1150 (tok2->token == ctxt->key_andequal)) { 1151 xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL, 1152 BAD_CAST "interleave"); 1153 } else { 1154 ERROR("expecting \"=\" or \"&=\" or \"|=\" here") 1155 return(-1); 1156 } 1157 xmlParseCRNGDropTokens(ctxt, 2); 1158 1159 define = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_define); 1160 if (define == NULL) CRNG_MEM_ERROR0(); 1161 define->properties = ctxt->attrs; 1162 ctxt->attrs = NULL; 1163 xmlSetProp(define, BAD_CAST "name", identifier); 1164 if (ctxt->insert != NULL) 1165 xmlAddChild(ctxt->insert, define); 1166 ctxt->insert = define; 1167 xmlParseCRNG_pattern(ctxt); 1168 } else { 1169 return(-1); 1170 } 1171 ctxt->insert = insert; 1172 return(0); 1173} 1174 1175/** 1176 * xmlParseCRNG_grammar: 1177 * @ctxt: a compact RNG parser context 1178 * 1179 * Parse grammar of the RELAX NG Compact Syntax Appendix A 1180 * 1181 * Returns 0 in case of success and -1 in case of error 1182 */ 1183static int 1184xmlParseCRNG_grammar(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED) 1185{ 1186 tokenPtr token; 1187 int ret; 1188 1189 token = xmlParseCRNGGetToken(ctxt, 1); 1190 while (token != NULL) { 1191 ret = xmlParseCRNG_component(ctxt); 1192 if (ret != 0) 1193 break; 1194 token = xmlParseCRNGGetToken(ctxt, 1); 1195 } 1196 return(0); 1197} 1198 1199/** 1200 * xmlParseCRNG_topLevelBody: 1201 * @ctxt: a compact RNG parser context 1202 * 1203 * Parse topLevelBody of the RELAX NG Compact Syntax Appendix A 1204 * 1205 * Returns 0 in case of success and -1 in case of error 1206 */ 1207static int 1208xmlParseCRNG_topLevelBody(xmlCRelaxNGParserCtxtPtr ctxt) 1209{ 1210 tokenPtr token, tok2; 1211 1212 token = xmlParseCRNGGetToken(ctxt, 1); 1213 if (token->toktype == CRNG_KEYWORD) { 1214 if ((token->token == ctxt->key_start) || 1215 (token->token == ctxt->key_include) || 1216 (token->token == ctxt->key_div)) { 1217 xmlNodePtr grammar; 1218 1219 grammar = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_grammar); 1220 if (grammar == NULL) CRNG_MEM_ERROR0(); 1221 xmlDocSetRootElement(ctxt->doc, grammar); 1222 ctxt->insert = grammar; 1223 1224 xmlParseCRNG_grammar(ctxt); 1225 } else { 1226 xmlParseCRNG_pattern(ctxt); 1227 } 1228 } else { 1229 tok2 = xmlParseCRNGGetToken(ctxt, 2); 1230 if ((tok2->toktype == CRNG_OP) && 1231 ((tok2->token == ctxt->key_equal) || 1232 (tok2->token == ctxt->key_orequal) || 1233 (tok2->token == ctxt->key_andequal))) { 1234 xmlNodePtr grammar; 1235 1236 grammar = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_grammar); 1237 if (grammar == NULL) CRNG_MEM_ERROR0(); 1238 xmlDocSetRootElement(ctxt->doc, grammar); 1239 ctxt->insert = grammar; 1240 1241 xmlParseCRNG_grammar(ctxt); 1242 } else { 1243 xmlParseCRNG_pattern(ctxt); 1244 } 1245 } 1246 return(0); 1247} 1248 1249/** 1250 * xmlParseCRNG_namespacePrefix: 1251 * @ctxt: a compact RNG parser context 1252 * 1253 * Parse namespacePrefix of the RELAX NG Compact Syntax Appendix A 1254 * 1255 * Returns the prefix or NULL in case of error 1256 */ 1257static const xmlChar * 1258xmlParseCRNG_namespacePrefix(xmlCRelaxNGParserCtxtPtr ctxt) 1259{ 1260 tokenPtr token; 1261 const xmlChar *prefix = NULL; 1262 1263 token = xmlParseCRNGGetToken(ctxt, 1); 1264 if (token->toktype == CRNG_IDENTIFIER) { 1265 prefix = token->token; 1266 } else if (token->toktype == CRNG_OP) { 1267 if ((token->token[0] == '=') && (token->token[1] == 0)) 1268 return(NULL); 1269 prefix = token->token; 1270 } else { 1271 ERROR("Expecting a namespace prefix"); 1272 return(NULL); 1273 } 1274 xmlParseCRNGDropTokens(ctxt, 1); 1275 1276 if (xmlStrEqual(prefix, BAD_CAST "xmlns")) { 1277 ERROR("Namespace prefix \"xmlns\" is forbidden"); 1278 } 1279 return(prefix); 1280} 1281 1282/** 1283 * xmlParseCRNG_decl: 1284 * @ctxt: a compact RNG parser context 1285 * 1286 * Parse decl of the RELAX NG Compact Syntax Appendix A 1287 * 1288 * Returns 0 in case of success and -1 in case of error 1289 */ 1290static int 1291xmlParseCRNG_decl(xmlCRelaxNGParserCtxtPtr ctxt) 1292{ 1293 const xmlChar *prefix = NULL; 1294 const xmlChar *namespace = NULL; 1295 tokenPtr token; 1296 1297 token = xmlParseCRNGGetToken(ctxt, 1); 1298 if (token->toktype != CRNG_KEYWORD) return(-1); 1299 if (token->token == ctxt->key_default) { 1300 xmlParseCRNGDropTokens(ctxt, 1); 1301 token = xmlParseCRNGGetToken(ctxt, 1); 1302 if ((token->toktype != CRNG_KEYWORD) || 1303 (token->token != ctxt->key_namespace)) { 1304 ERROR("Expecting keyword \"namespace\" after \"default\""); 1305 } 1306 xmlParseCRNGDropTokens(ctxt, 1); 1307 prefix = xmlParseCRNG_namespacePrefix(ctxt); 1308 token = xmlParseCRNGGetToken(ctxt, 1); 1309 if ((token->toktype != CRNG_OP) || 1310 (token->token[0] != '=') || (token->token[1] != 0)) { 1311 ERROR("Expecting keyword \"=\" here"); 1312 } 1313 xmlParseCRNGDropTokens(ctxt, 1); 1314 token = xmlParseCRNGGetToken(ctxt, 1); 1315 if ((token->toktype == CRNG_KEYWORD) && 1316 (token->token == ctxt->key_inherit)) { 1317 namespace = xmlCRelaxNGInherit; 1318 } else if (token->toktype == CRNG_LITERAL_SEGMENT) { 1319 namespace = token->token; 1320 } else { 1321 ERROR("Expecting an URI or \"inherit\" value"); 1322 } 1323 xmlParseCRNGDropTokens(ctxt, 1); 1324 if (namespace != NULL) { 1325 if (prefix != NULL) 1326 xmlParseCRNG_bindPrefix(ctxt, prefix, namespace); 1327 xmlParseCRNG_bindPrefix(ctxt, NULL, namespace); 1328 } 1329 } else if (token->token == ctxt->key_namespace) { 1330 xmlParseCRNGDropTokens(ctxt, 1); 1331 prefix = xmlParseCRNG_namespacePrefix(ctxt); 1332 token = xmlParseCRNGGetToken(ctxt, 1); 1333 if ((token->toktype != CRNG_OP) || 1334 (token->token[0] != '=') || (token->token[1] != 0)) { 1335 ERROR("Expecting keyword \"=\" here"); 1336 } 1337 xmlParseCRNGDropTokens(ctxt, 1); 1338 token = xmlParseCRNGGetToken(ctxt, 1); 1339 if ((token->toktype == CRNG_KEYWORD) && 1340 (token->token == ctxt->key_inherit)) { 1341 namespace = xmlCRelaxNGInherit; 1342 } else if (token->toktype == CRNG_LITERAL_SEGMENT) { 1343 namespace = token->token; 1344 } else { 1345 ERROR("Expecting an URI or \"inherit\" value"); 1346 } 1347 xmlParseCRNGDropTokens(ctxt, 1); 1348 if (namespace != NULL) 1349 xmlParseCRNG_bindPrefix(ctxt, prefix, namespace); 1350 } else if (token->token == ctxt->key_datatypes) { 1351 xmlParseCRNGDropTokens(ctxt, 1); 1352 1353 token = xmlParseCRNGGetToken(ctxt, 1); 1354 if ((token->toktype != CRNG_KEYWORD) && 1355 (token->toktype != CRNG_IDENTIFIER)) { 1356 ERROR("Expecting a datatype prefix identifier here"); 1357 } else 1358 prefix = token->token; 1359 xmlParseCRNGDropTokens(ctxt, 1); 1360 token = xmlParseCRNGGetToken(ctxt, 1); 1361 if ((token->toktype != CRNG_OP) || 1362 (token->token[0] != '=') || (token->token[1] != 0)) { 1363 ERROR("Expecting keyword \"=\" here"); 1364 } 1365 xmlParseCRNGDropTokens(ctxt, 1); 1366 token = xmlParseCRNGGetToken(ctxt, 1); 1367 if (token->toktype == CRNG_LITERAL_SEGMENT) { 1368 namespace = token->token; 1369 } else { 1370 ERROR("Expecting a literal value for the datatype identifier"); 1371 } 1372 xmlParseCRNGDropTokens(ctxt, 1); 1373 if ((namespace != NULL) && (prefix != NULL)) 1374 xmlParseCRNG_bindDatatypePrefix(ctxt, prefix, namespace); 1375 } 1376 1377 return(0); 1378} 1379 1380/** 1381 * xmlParseCRNG_preamble: 1382 * @ctxt: a compact RNG parser context 1383 * 1384 * Parse preamble of the RELAX NG Compact Syntax Appendix A 1385 * 1386 * Returns 0 in case of success and -1 in case of error 1387 */ 1388static int 1389xmlParseCRNG_preamble(xmlCRelaxNGParserCtxtPtr ctxt) 1390{ 1391 tokenPtr token; 1392 1393 token = xmlParseCRNGGetToken(ctxt, 1); 1394 while (token != NULL) { 1395 if (token == NULL) return(-1); 1396 if ((token->toktype == CRNG_KEYWORD) && 1397 ((token->token == ctxt->key_default) || 1398 (token->token == ctxt->key_namespace) || 1399 (token->token == ctxt->key_datatypes))) { 1400 xmlParseCRNG_decl(ctxt); 1401 } else 1402 break; 1403 token = xmlParseCRNGGetToken(ctxt, 1); 1404 } 1405 return(0); 1406} 1407 1408/** 1409 * xmlParseCRNG_topLevel: 1410 * @ctxt: a compact RNG parser context 1411 * 1412 * Parse topLevel of the RELAX NG Compact Syntax Appendix A 1413 * 1414 * Returns 0 in case of success and -1 in case of error 1415 */ 1416static int 1417xmlParseCRNG_topLevel(xmlCRelaxNGParserCtxtPtr ctxt) 1418{ 1419 xmlParseCRNG_preamble(ctxt); 1420 xmlParseCRNG_topLevelBody(ctxt); 1421 return(0); 1422} 1423 1424/** 1425 * xmlConvertCRNG: 1426 * @schemas: pointer to the text of the compact schemas 1427 * @len: length of the schemas in bytes (or 0) 1428 * @encoding: encoding indicated by the context or NULL 1429 * 1430 * Compiles the schemas into the equivalent Relax-NG XML structure 1431 * 1432 * Returns the xmlDocPtr resulting from the compilation or 1433 * NULL in case of error 1434 */ 1435xmlDocPtr 1436xmlConvertCRNG(const char *schemas, int len, const char *encoding) { 1437 struct _xmlCRelaxNGParserCtxt ctxt; 1438 xmlDocPtr ret = NULL; 1439 1440 if (schemas == NULL) return(NULL); 1441 if (len <= 5) len = xmlStrlen((const unsigned char *) schemas); 1442 if (len <= 0) return(NULL); 1443 1444 memset(&ctxt, 0, sizeof(ctxt)); 1445 ctxt.compact = (const unsigned char *) schemas; 1446 ctxt.cur = (const unsigned char *) schemas; 1447 ctxt.end = (const unsigned char *) &schemas[len]; 1448 ctxt.dict = xmlDictCreate(); 1449 if (ctxt.dict == NULL) 1450 return(NULL); 1451 ctxt.doc = xmlNewDoc(NULL); 1452 if (ctxt.doc == NULL) { 1453 xmlDictFree(ctxt.dict); 1454 return(NULL); 1455 } 1456 ctxt.doc->dict = ctxt.dict; 1457 xmlDictReference(ctxt.dict); 1458 1459 ctxt.nbTokens = 0; 1460 ctxt.firstToken = 0; 1461 ctxt.key_attribute = xmlDictLookup(ctxt.dict, BAD_CAST "attribute", -1); 1462 ctxt.key_default = xmlDictLookup(ctxt.dict, BAD_CAST "default", -1); 1463 ctxt.key_datatypes = xmlDictLookup(ctxt.dict, BAD_CAST "datatypes", -1); 1464 ctxt.key_div = xmlDictLookup(ctxt.dict, BAD_CAST "div", -1); 1465 ctxt.key_element = xmlDictLookup(ctxt.dict, BAD_CAST "element", -1); 1466 ctxt.key_empty = xmlDictLookup(ctxt.dict, BAD_CAST "empty", -1); 1467 ctxt.key_external = xmlDictLookup(ctxt.dict, BAD_CAST "external", -1); 1468 ctxt.key_grammar = xmlDictLookup(ctxt.dict, BAD_CAST "grammar", -1); 1469 ctxt.key_include = xmlDictLookup(ctxt.dict, BAD_CAST "include", -1); 1470 ctxt.key_inherit = xmlDictLookup(ctxt.dict, BAD_CAST "inherit", -1); 1471 ctxt.key_list = xmlDictLookup(ctxt.dict, BAD_CAST "list", -1); 1472 ctxt.key_mixed = xmlDictLookup(ctxt.dict, BAD_CAST "mixed", -1); 1473 ctxt.key_namespace = xmlDictLookup(ctxt.dict, BAD_CAST "namespace", -1); 1474 ctxt.key_notAllowed = xmlDictLookup(ctxt.dict, BAD_CAST "notAllowed", -1); 1475 ctxt.key_parent = xmlDictLookup(ctxt.dict, BAD_CAST "parent", -1); 1476 ctxt.key_start = xmlDictLookup(ctxt.dict, BAD_CAST "start", -1); 1477 ctxt.key_string = xmlDictLookup(ctxt.dict, BAD_CAST "string", -1); 1478 ctxt.key_text = xmlDictLookup(ctxt.dict, BAD_CAST "text", -1); 1479 ctxt.key_token = xmlDictLookup(ctxt.dict, BAD_CAST "token", -1); 1480 ctxt.key_equal = xmlDictLookup(ctxt.dict, BAD_CAST "=", 1); 1481 ctxt.key_orequal = xmlDictLookup(ctxt.dict, BAD_CAST "|=", 2); 1482 ctxt.key_andequal = xmlDictLookup(ctxt.dict, BAD_CAST "&=", 2); 1483 ctxt.key_combine = xmlDictLookup(ctxt.dict, BAD_CAST "&=", 2); 1484 ctxt.key_or = xmlDictLookup(ctxt.dict, BAD_CAST "|", 1); 1485 ctxt.key_comma = xmlDictLookup(ctxt.dict, BAD_CAST ",", 1); 1486 ctxt.key_and = xmlDictLookup(ctxt.dict, BAD_CAST "&", 1); 1487 ctxt.key_choice = xmlDictLookup(ctxt.dict, BAD_CAST "choice", -1); 1488 ctxt.key_group = xmlDictLookup(ctxt.dict, BAD_CAST "group", -1); 1489 ctxt.key_interleave = xmlDictLookup(ctxt.dict, BAD_CAST "interleave", -1); 1490 ctxt.key_ref = xmlDictLookup(ctxt.dict, BAD_CAST "ref", 3); 1491 ctxt.key_define = xmlDictLookup(ctxt.dict, BAD_CAST "define", 6); 1492 1493 /* xmlConvertCRNGTokenize(&ctxt); */ 1494 xmlConvertCRNG_topLevel(&ctxt); 1495 1496 xmlDictFree(ctxt.dict); 1497 1498 ret = ctxt.doc; 1499 return(ret); 1500} 1501 1502/** 1503 * xmlConvertCRNGFile: 1504 * @URL: URL or filename for the resource 1505 * @encoding: encoding indicated by the context or NULL 1506 * 1507 * Compiles the schemas into the equivalent Relax-NG XML structure 1508 * 1509 * Returns the xmlDocPtr resulting from the compilation or 1510 * NULL in case of error 1511 */ 1512xmlDocPtr 1513xmlConvertCRNGFile(const char *URL, const char *encoding) { 1514} 1515 1516#ifdef STANDALONE 1517const xmlChar *schemas = 1518"# RELAX NG XML syntax specified in compact syntax.\n\ 1519\n\ 1520default namespace rng = \"http://relaxng.org/ns/structure/1.0\"\n\ 1521namespace local = \"\"\n\ 1522datatypes xsd = \"http://www.w3.org/2001/XMLSchema-datatypes\"\n\ 1523\n\ 1524start = pattern\n\ 1525\n\ 1526pattern =\n\ 1527 element element { (nameQName | nameClass), (common & pattern+) }\n\ 1528 | element attribute { (nameQName | nameClass), (common & pattern?) }\n\ 1529 | element group|interleave|choice|optional\n\ 1530 |zeroOrMore|oneOrMore|list|mixed { common & pattern+ }\n\ 1531 | element ref|parentRef { nameNCName, common }\n\ 1532 | element empty|notAllowed|text { common }\n\ 1533 | element data { type, param*, (common & exceptPattern?) }\n\ 1534 | element value { commonAttributes, type?, xsd:string }\n\ 1535 | element externalRef { href, common }\n\ 1536 | element grammar { common & grammarContent* }\n\ 1537\n\ 1538param = element param { commonAttributes, nameNCName, xsd:string }\n\ 1539\n\ 1540exceptPattern = element except { common & pattern+ }\n\ 1541\n\ 1542grammarContent =\n\ 1543 definition\n\ 1544 | element div { common & grammarContent* }\n\ 1545 | element include { href, (common & includeContent*) }\n\ 1546\n\ 1547includeContent =\n\ 1548 definition\n\ 1549 | element div { common & includeContent* }\n\ 1550\n\ 1551definition =\n\ 1552 element start { combine?, (common & pattern+) }\n\ 1553 | element define { nameNCName, combine?, (common & pattern+) }\n\ 1554\n\ 1555combine = attribute combine { \"choice\" | \"interleave\" }\n\ 1556\n\ 1557nameClass =\n\ 1558 element name { commonAttributes, xsd:QName }\n\ 1559 | element anyName { common & exceptNameClass? }\n\ 1560 | element nsName { common & exceptNameClass? }\n\ 1561 | element choice { common & nameClass+ }\n\ 1562\n\ 1563exceptNameClass = element except { common & nameClass+ }\n\ 1564\n\ 1565nameQName = attribute name { xsd:QName }\n\ 1566nameNCName = attribute name { xsd:NCName }\n\ 1567href = attribute href { xsd:anyURI }\n\ 1568type = attribute type { xsd:NCName }\n\ 1569\n\ 1570common = commonAttributes, foreignElement*\n\ 1571\n\ 1572commonAttributes =\n\ 1573 attribute ns { xsd:string }?,\n\ 1574 attribute datatypeLibrary { xsd:anyURI }?,\n\ 1575 foreignAttribute*\n\ 1576\n\ 1577foreignElement = element * - rng:* { (anyAttribute | text | anyElement)* }\n\ 1578foreignAttribute = attribute * - (rng:*|local:*) { text }\n\ 1579anyElement = element * { (anyAttribute | text | anyElement)* }\n\ 1580anyAttribute = attribute * { text }\n\ 1581"; 1582 1583int main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) { 1584 xmlDocPtr res; 1585 1586 res = xmlConvertCRNG(schemas, -1); 1587 if (res != NULL) { 1588 xmlDocFormatDump(stdout, res, 1); 1589 xmlFreeDoc(res); 1590 } 1591 return(0); 1592} 1593#endif 1594#define bottom_rngparser 1595#include "elfgcchack.h" 1596