/ libxml2 / rngparser.c
rngparser.c
   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  
  28  typedef 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  
  40  typedef 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  
  48  typedef enum {
  49      XML_CRNG_ERROR = -1,
  50      XML_CRNG_OK = 0,
  51      XML_CRNG_EOF = 1
  52  } xmlCRelaxNGParserState;
  53  
  54  typedef struct _token _token;
  55  typedef _token *tokenPtr;
  56  struct _token {
  57      xmlCRNGTokType toktype;
  58      int toklen;
  59      const xmlChar *token;
  60      const xmlChar *prefix;
  61  };
  62  
  63  typedef struct _xmlCRelaxNGParserCtxt xmlCRelaxNGParserCtxt;
  64  typedef xmlCRelaxNGParserCtxt *xmlCRelaxNGParserCtxtPtr;
  65  struct _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       * dictionary 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  
 139  static const xmlChar *xmlCRelaxNGInherit = BAD_CAST "Inherit string";
 140  static 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  
 170  static void
 171  xmlCRNGErr(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  
 214  static int
 215  xmlCRNGIsKeyword(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  
 249  static int
 250  xmlCRNGNextToken(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      }
 262  retry:
 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);
 362  eof:
 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   */
 378  static tokenPtr
 379  xmlParseCRNGGetToken(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   */
 403  static int
 404  xmlParseCRNGDropTokens(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  
 418  static void
 419  xmlParseCRNGTokenize(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   */
 452  static int
 453  xmlParseCRNG_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   */
 479  static int
 480  xmlParseCRNG_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   */
 529  static int
 530  xmlParseCRNG_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   */
 566  static const xmlChar *
 567  xmlParseCRNG_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   */
 588  static const xmlChar *
 589  xmlParseCRNG_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   */
 606  static xmlAttrPtr
 607  xmlParseCRNG_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   */
 635  static int
 636  xmlParseCRNG_XXX(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
 637  {
 638      return(0);
 639  }
 640  
 641  static int xmlParseCRNG_pattern(xmlCRelaxNGParserCtxtPtr ctxt);
 642  static 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   */
 652  static int
 653  xmlParseCRNG_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   */
 667  static int
 668  xmlParseCRNG_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   */
 696  static int
 697  xmlParseCRNG_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   */
 766  static int
 767  xmlParseCRNG_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   */
 802  static int
 803  xmlParseCRNG_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   */
 831  static int
 832  xmlParseCRNG_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   */
 905  static int
 906  xmlParseCRNG_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   */
 999  static int
1000  xmlParseCRNG_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   */
1042  static int
1043  xmlParseCRNG_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   */
1090  static int
1091  xmlParseCRNG_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   */
1183  static int
1184  xmlParseCRNG_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   */
1207  static int
1208  xmlParseCRNG_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   */
1257  static const xmlChar *
1258  xmlParseCRNG_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   */
1290  static int
1291  xmlParseCRNG_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   */
1388  static int
1389  xmlParseCRNG_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   */
1416  static int
1417  xmlParseCRNG_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   */
1435  xmlDocPtr
1436  xmlConvertCRNG(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   */
1512  xmlDocPtr
1513  xmlConvertCRNGFile(const char *URL, const char *encoding) {
1514  }
1515  
1516  #ifdef STANDALONE
1517  const xmlChar *schemas =
1518  "# RELAX NG XML syntax specified in compact syntax.\n\
1519  \n\
1520  default namespace rng = \"http://relaxng.org/ns/structure/1.0\"\n\
1521  namespace local = \"\"\n\
1522  datatypes xsd = \"http://www.w3.org/2001/XMLSchema-datatypes\"\n\
1523  \n\
1524  start = pattern\n\
1525  \n\
1526  pattern =\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\
1538  param = element param { commonAttributes, nameNCName, xsd:string }\n\
1539  \n\
1540  exceptPattern = element except { common & pattern+ }\n\
1541  \n\
1542  grammarContent =\n\
1543    definition\n\
1544    | element div { common & grammarContent* }\n\
1545    | element include { href, (common & includeContent*) }\n\
1546  \n\
1547  includeContent =\n\
1548    definition\n\
1549    | element div { common & includeContent* }\n\
1550  \n\
1551  definition =\n\
1552    element start { combine?, (common & pattern+) }\n\
1553    | element define { nameNCName, combine?, (common & pattern+) }\n\
1554  \n\
1555  combine = attribute combine { \"choice\" | \"interleave\" }\n\
1556  \n\
1557  nameClass =\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\
1563  exceptNameClass = element except { common & nameClass+ }\n\
1564  \n\
1565  nameQName = attribute name { xsd:QName }\n\
1566  nameNCName = attribute name { xsd:NCName }\n\
1567  href = attribute href { xsd:anyURI }\n\
1568  type = attribute type { xsd:NCName }\n\
1569  \n\
1570  common = commonAttributes, foreignElement*\n\
1571  \n\
1572  commonAttributes =\n\
1573    attribute ns { xsd:string }?,\n\
1574    attribute datatypeLibrary { xsd:anyURI }?,\n\
1575    foreignAttribute*\n\
1576  \n\
1577  foreignElement = element * - rng:* { (anyAttribute | text | anyElement)* }\n\
1578  foreignAttribute = attribute * - (rng:*|local:*) { text }\n\
1579  anyElement = element * { (anyAttribute | text | anyElement)* }\n\
1580  anyAttribute = attribute * { text }\n\
1581  ";
1582  
1583  int 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"