| Index: third_party/libxml/src/rngparser.c
|
| diff --git a/third_party/libxml/src/rngparser.c b/third_party/libxml/src/rngparser.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e681e0c22cd1dbbf9a5dc2a2576fb26a70036227
|
| --- /dev/null
|
| +++ b/third_party/libxml/src/rngparser.c
|
| @@ -0,0 +1,1595 @@
|
| +/**
|
| + * rngparser.c: parser for the Relax-NG compact syntax.
|
| + *
|
| + * Based on:
|
| + * RELAX NG Compact Syntax
|
| + * Committee Specification 21 November 2002
|
| + * http://www.oasis-open.org/committees/relax-ng/compact-20021121.html
|
| + *
|
| + * See Copyright for the status of this software.
|
| + *
|
| + * Daniel Veillard <veillard@redhat.com>
|
| + */
|
| +
|
| +#include <string.h>
|
| +
|
| +#include <libxml/parser.h>
|
| +#include <libxml/parserInternals.h>
|
| +#include <libxml/relaxng.h>
|
| +#include <libxml/dict.h>
|
| +
|
| +#define TODO \
|
| + xmlGenericError(xmlGenericErrorContext, \
|
| + "Unimplemented block at %s:%d\n", \
|
| + __FILE__, __LINE__);
|
| +
|
| +#define MAX_TOKEN 10
|
| +
|
| +typedef enum {
|
| + CRNG_NONE = 0,
|
| + CRNG_OP = 1,
|
| + CRNG_KEYWORD,
|
| + CRNG_IDENTIFIER,
|
| + CRNG_LITERAL_SEGMENT,
|
| + CRNG_CNAME,
|
| + CRNG_QNAME,
|
| + CRNG_NSNAME,
|
| + CRNG_DOCUMENTATION
|
| +} xmlCRNGTokType;
|
| +
|
| +typedef enum {
|
| + CRNG_OKAY = 0,
|
| + CRNG_MEMORY_ERROR,
|
| + CRNG_INVALID_CHAR_ERROR,
|
| + CRNG_END_ERROR,
|
| + CRNG_ENCODING_ERROR
|
| +} xmlCRNGError;
|
| +
|
| +typedef enum {
|
| + XML_CRNG_ERROR = -1,
|
| + XML_CRNG_OK = 0,
|
| + XML_CRNG_EOF = 1
|
| +} xmlCRelaxNGParserState;
|
| +
|
| +typedef struct _token _token;
|
| +typedef _token *tokenPtr;
|
| +struct _token {
|
| + xmlCRNGTokType toktype;
|
| + int toklen;
|
| + const xmlChar *token;
|
| + const xmlChar *prefix;
|
| +};
|
| +
|
| +typedef struct _xmlCRelaxNGParserCtxt xmlCRelaxNGParserCtxt;
|
| +typedef xmlCRelaxNGParserCtxt *xmlCRelaxNGParserCtxtPtr;
|
| +struct _xmlCRelaxNGParserCtxt {
|
| + void *userData; /* user specific data block */
|
| + xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
|
| + xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
|
| + xmlRelaxNGValidErr err;
|
| +
|
| + const xmlChar *compact;
|
| + const xmlChar *end;
|
| + const xmlChar *cur;
|
| + int isElem;
|
| + int lineno;
|
| + const xmlChar *linestart;
|
| + const char *filename;
|
| +
|
| + int nbTokens;
|
| + int firstToken;
|
| + _token tokens[MAX_TOKEN];
|
| + int totalToken;
|
| +
|
| + xmlCRelaxNGParserState state;
|
| +
|
| + int nbErrors;
|
| +
|
| + xmlDocPtr res; /* the result */
|
| + xmlNodePtr ins; /* the current insertion node */
|
| +
|
| + xmlNsPtr nsDef;
|
| + tokenPtr token;
|
| +
|
| + xmlHashTablePtr namespaces;
|
| + xmlHashTablePtr datatypes;
|
| +
|
| + /*
|
| + * dictionnary and keywords
|
| + */
|
| + xmlDictPtr dict;
|
| + const xmlChar *key_attribute;
|
| + const xmlChar *key_default;
|
| + const xmlChar *key_datatypes;
|
| + const xmlChar *key_div;
|
| + const xmlChar *key_element;
|
| + const xmlChar *key_empty;
|
| + const xmlChar *key_external;
|
| + const xmlChar *key_grammar;
|
| + const xmlChar *key_include;
|
| + const xmlChar *key_inherit;
|
| + const xmlChar *key_list;
|
| + const xmlChar *key_mixed;
|
| + const xmlChar *key_namespace;
|
| + const xmlChar *key_notAllowed;
|
| + const xmlChar *key_parent;
|
| + const xmlChar *key_start;
|
| + const xmlChar *key_string;
|
| + const xmlChar *key_text;
|
| + const xmlChar *key_token;
|
| + const xmlChar *key_equal;
|
| + const xmlChar *key_orequal;
|
| + const xmlChar *key_andequal;
|
| + const xmlChar *key_combine;
|
| + const xmlChar *key_or;
|
| + const xmlChar *key_comma;
|
| + const xmlChar *key_and;
|
| + const xmlChar *key_choice;
|
| + const xmlChar *key_group;
|
| + const xmlChar *key_interleave;
|
| + const xmlChar *key_ref;
|
| + const xmlChar *key_define;
|
| +
|
| + /* results */
|
| + xmlDocPtr doc; /* the resulting doc */
|
| + xmlNodePtr insert; /* the insertion point */
|
| + xmlAttrPtr attrs; /* pending attributes */
|
| +};
|
| +
|
| +static const xmlChar *xmlCRelaxNGInherit = BAD_CAST "Inherit string";
|
| +static const xmlChar *xmlCRelaxNGDefault = BAD_CAST "Default string";
|
| +
|
| +#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
|
| +/**
|
| + * IS_BLANK:
|
| + * @c: an UNICODE value (int)
|
| + *
|
| + * Macro to check the following production in the XML spec:
|
| + *
|
| + * [3] S ::= (#x20 | #x9 | #xD | #xA)+
|
| + */
|
| +#ifndef IS_BLANK
|
| +#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
|
| + ((c) == 0x0D))
|
| +#endif
|
| +#define IS_SEPARATOR(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
|
| + ((c) == 0x0D) || (c == '#'))
|
| +
|
| +#define CRNG_ERROR0(X) \
|
| + { xmlCRNGErr(ctxt, X, NULL); return(0); }
|
| +#define CRNG_ERROR(X) \
|
| + { xmlCRNGErr(ctxt, X, NULL); }
|
| +
|
| +#define CRNG_MEM_ERROR0() \
|
| + { xmlCRNGErr(ctxt, CRNG_MEMORY_ERROR, NULL); return(0); }
|
| +#define CRNG_MEM_ERROR() \
|
| + { xmlCRNGErr(ctxt, CRNG_MEMORY_ERROR, NULL); }
|
| +
|
| +#define ERROR(str) xmlCRNGErr(ctxt, 0, str);
|
| +
|
| +static void
|
| +xmlCRNGErr(xmlCRelaxNGParserCtxtPtr ctxt, int err_no, const char *err_msg) {
|
| + const xmlChar *cur;
|
| + xmlChar buffer[150];
|
| + int i, l;
|
| +
|
| + if (ctxt != NULL) {
|
| + if (ctxt->filename != NULL)
|
| + fprintf(stderr, "%s:%d ", ctxt->filename, ctxt->lineno);
|
| + }
|
| + if (err_msg != NULL) {
|
| + fprintf(stderr, "error: %s\n", err_msg);
|
| + } else if (err_no != 0)
|
| + fprintf(stderr, "error %d\n", err_no);
|
| + cur = ctxt->cur;
|
| + while ((*cur != '\n') && (*cur != '\r') && (ctxt->cur - cur < 80)) cur--;
|
| + l = ctxt->cur - cur;
|
| + cur++;
|
| + for (i = 0; i < 100;i++) {
|
| + if ((*cur == '\n') || (*cur == '\r')) break;
|
| + buffer[i] = *cur++;
|
| + }
|
| + buffer[i] = 0;
|
| + fprintf(stderr, "%s\n", buffer);
|
| + for (i = 0; i < l;i++) buffer[i] = ' ';
|
| + buffer[i++] = '^';
|
| + buffer[i++] = 0;
|
| + fprintf(stderr, "%s\n", buffer);
|
| +}
|
| +
|
| +/**
|
| + * IS_OP
|
| + * @c: an UNICODE value (int)
|
| + *
|
| + * Macro to check for operator value
|
| + */
|
| +#ifndef IS_OP
|
| +#define IS_OP(c) (((c) == ',') || ((c) == '&') || ((c) == '|') || \
|
| + ((c) == '?') || ((c) == '-') || ((c) == '*') || \
|
| + ((c) == '{') || ((c) == '}') || ((c) == '(') || \
|
| + ((c) == ')') || ((c) == '+') || ((c) == '=') || \
|
| + ((c) == ':'))
|
| +#endif
|
| +
|
| +static int
|
| +xmlCRNGIsKeyword(xmlCRelaxNGParserCtxtPtr ctxt, const xmlChar *str) {
|
| + if ((str == ctxt->key_attribute) ||
|
| + (str == ctxt->key_default) ||
|
| + (str == ctxt->key_datatypes) ||
|
| + (str == ctxt->key_div) ||
|
| + (str == ctxt->key_element) ||
|
| + (str == ctxt->key_empty) ||
|
| + (str == ctxt->key_external) ||
|
| + (str == ctxt->key_grammar) ||
|
| + (str == ctxt->key_include) ||
|
| + (str == ctxt->key_inherit) ||
|
| + (str == ctxt->key_list) ||
|
| + (str == ctxt->key_mixed) ||
|
| + (str == ctxt->key_namespace) ||
|
| + (str == ctxt->key_notAllowed) ||
|
| + (str == ctxt->key_parent) ||
|
| + (str == ctxt->key_start) ||
|
| + (str == ctxt->key_string) ||
|
| + (str == ctxt->key_text) ||
|
| + (str == ctxt->key_token))
|
| + return(1);
|
| + return(0);
|
| +
|
| +}
|
| +
|
| +/*
|
| + * xmlCRNGNextToken:
|
| + * ctxt: a compact RNG parser context
|
| + *
|
| + * Scan the schema to get the next token
|
| + *
|
| + * Return 0 if success and -1 in case of error
|
| + */
|
| +
|
| +static int
|
| +xmlCRNGNextToken(xmlCRelaxNGParserCtxtPtr ctxt) {
|
| + const xmlChar *cur;
|
| + tokenPtr token;
|
| +
|
| + if (ctxt == NULL) return(-1);
|
| + if (ctxt->nbTokens >= MAX_TOKEN) return(-1);
|
| + token = &(ctxt->tokens[(ctxt->firstToken + ctxt->nbTokens) % MAX_TOKEN]);
|
| + token->toktype = CRNG_NONE;
|
| +
|
| + if (ctxt->cur == NULL) {
|
| + ctxt->cur = ctxt->compact;
|
| + }
|
| +retry:
|
| + if (ctxt->cur >= ctxt->end) {
|
| + ctxt->state = XML_CRNG_EOF;
|
| + return(-1);
|
| + }
|
| + while ((ctxt->cur < ctxt->end) &&
|
| + (IS_BLANK(*ctxt->cur))) ctxt->cur++;
|
| + if (ctxt->cur >= ctxt->end) {
|
| + ctxt->state = XML_CRNG_EOF;
|
| + return(-1);
|
| + }
|
| + if (*ctxt->cur == '#') {
|
| + cur = ctxt->cur;
|
| + cur++;
|
| + while ((cur < ctxt->end) && (*cur != '\n') && (*cur != '\r'))
|
| + cur++;
|
| + ctxt->cur = cur;
|
| + goto retry;
|
| + } else if (*ctxt->cur == '"') {
|
| + /* string, check for '"""' */
|
| + ctxt->cur++;
|
| + if (ctxt->cur >= ctxt->end) goto eof;
|
| + cur = ctxt->cur;
|
| + if ((ctxt->end - ctxt->end > 2) &&
|
| + (*cur == '"') && (cur[1] == '"')) {
|
| + TODO
|
| + } else {
|
| + while ((cur < ctxt->end) && (*cur != '"')) cur++;
|
| + if (cur >= ctxt->end) goto eof;
|
| + token->toklen = cur - ctxt->cur;
|
| + token->token = xmlDictLookup(ctxt->dict, ctxt->cur, token->toklen);
|
| + token->toktype = CRNG_LITERAL_SEGMENT;
|
| + token->prefix = NULL;
|
| + cur++;
|
| + ctxt->cur = cur;
|
| + }
|
| + } else if (*ctxt->cur == '\'') {
|
| + /* string, check for "'''" */
|
| + TODO
|
| + } else if ((IS_OP(*ctxt->cur)) || (*ctxt->cur == ':')) {
|
| + cur = ctxt->cur;
|
| + cur++;
|
| + if ((cur < ctxt->end) &&
|
| + (((*cur == '=') &&
|
| + ((*ctxt->cur == '|') || (*ctxt->cur == '&'))) ||
|
| + ((*cur == '*') && (*ctxt->cur == ':')))) {
|
| + token->toklen = 2;
|
| + } else {
|
| + token->toklen = 1;
|
| + }
|
| + token->token = xmlDictLookup(ctxt->dict, ctxt->cur, token->toklen);
|
| + token->toktype = CRNG_OP;
|
| + token->prefix = NULL;
|
| + ctxt->cur += token->toklen;
|
| + } else {
|
| + int escape = 0;
|
| +
|
| + cur = ctxt->cur;
|
| + if (*cur == '\\') {
|
| + escape = 1;
|
| + cur++;
|
| + ctxt->cur++;
|
| + }
|
| + while ((cur < ctxt->end) &&
|
| + (!(IS_SEPARATOR(*cur))) && (!(IS_OP(*cur)))) cur++;
|
| +
|
| + token->toklen = cur - ctxt->cur;
|
| + token->token = xmlDictLookup(ctxt->dict, ctxt->cur, token->toklen);
|
| + token->prefix = NULL;
|
| + ctxt->cur = cur;
|
| + if ((escape == 0) && (xmlCRNGIsKeyword(ctxt, token->token)))
|
| + token->toktype = CRNG_KEYWORD;
|
| + else {
|
| + token->toktype = CRNG_IDENTIFIER;
|
| + }
|
| + if (*ctxt->cur == ':') {
|
| + ctxt->cur++;
|
| + if (*ctxt->cur == '*') {
|
| + ctxt->cur++;
|
| + token->toktype = CRNG_NSNAME;
|
| + } else {
|
| + cur = ctxt->cur;
|
| + while ((cur < ctxt->end) &&
|
| + (!(IS_SEPARATOR(*cur))) && (!(IS_OP(*cur)))) cur++;
|
| + token->prefix = token->token;
|
| + token->toklen = cur - ctxt->cur;
|
| + token->token = xmlDictLookup(ctxt->dict, ctxt->cur,
|
| + token->toklen);
|
| + ctxt->cur = cur;
|
| + if (xmlValidateNCName(token->token, 0) == 0)
|
| + token->toktype = CRNG_QNAME;
|
| + else {
|
| + TODO /* sounds like an error ! */
|
| + token->toktype = CRNG_IDENTIFIER;
|
| + }
|
| + }
|
| + }
|
| + }
|
| + ctxt->nbTokens++;
|
| + return(0);
|
| +eof:
|
| + ctxt->state = XML_CRNG_EOF;
|
| + CRNG_ERROR(CRNG_END_ERROR);
|
| + return(-1);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNGGetToken:
|
| + * @ctxt: a compact RNG parser context
|
| + * @no: the number of the token from 1 for the first one
|
| + * and 2, 3 ... for read-ahead
|
| + *
|
| + * Token reading interface
|
| + *
|
| + * returns a pointer to the new token, or NULL in case of error or EOF
|
| + */
|
| +static tokenPtr
|
| +xmlParseCRNGGetToken(xmlCRelaxNGParserCtxtPtr ctxt, int no) {
|
| + tokenPtr ret;
|
| + int res;
|
| +
|
| + if ((no <= 0) || (no >= MAX_TOKEN)) return(NULL);
|
| + no--;
|
| + while (ctxt->nbTokens <= no) {
|
| + res = xmlCRNGNextToken(ctxt);
|
| + if (res < 0)
|
| + return(NULL);
|
| + }
|
| + ret = &(ctxt->tokens[(ctxt->firstToken + no) % MAX_TOKEN]);
|
| + return(ret);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNGDropTokens:
|
| + * @ctxt: a compact RNG parser context
|
| + * @nr: the number of token marked as read
|
| + *
|
| + * mark a number of token as read and consumed.
|
| + *
|
| + * Returns -1 in case of error and 0 otherwise
|
| + */
|
| +static int
|
| +xmlParseCRNGDropTokens(xmlCRelaxNGParserCtxtPtr ctxt, int nr) {
|
| + if ((nr <= 0) || (nr >= MAX_TOKEN)) return(-1);
|
| + while ((ctxt->nbTokens >0) && (nr > 0)) {
|
| + ctxt->firstToken++;
|
| + nr--;
|
| + ctxt->nbTokens--;
|
| + ctxt->totalToken++;
|
| + if (ctxt->totalToken == 384)
|
| + fprintf(stderr, "found\n");
|
| + }
|
| + ctxt->firstToken = ctxt->firstToken % MAX_TOKEN;
|
| + return(0);
|
| +}
|
| +
|
| +static void
|
| +xmlParseCRNGTokenize(xmlCRelaxNGParserCtxtPtr ctxt) {
|
| + tokenPtr token;
|
| +
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + while (token != NULL) {
|
| + switch (token->toktype) {
|
| + case CRNG_NONE: printf("none"); break;
|
| + case CRNG_OP: printf("op"); break;
|
| + case CRNG_KEYWORD: printf("keyword"); break;
|
| + case CRNG_IDENTIFIER: printf("identifier"); break;
|
| + case CRNG_LITERAL_SEGMENT: printf("literal"); break;
|
| + case CRNG_CNAME: printf("cname"); break;
|
| + case CRNG_QNAME: printf("qname"); break;
|
| + case CRNG_NSNAME: printf("nsname"); break;
|
| + case CRNG_DOCUMENTATION: printf("doc"); break;
|
| + }
|
| + printf(":%s\n", token->token);
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNG_attribute:
|
| + * @ctxt: a compact RNG parser context
|
| + * @name: the attribute name
|
| + * @ns: the attribute namespace
|
| + * @value: the attribute value
|
| + *
|
| + * implements attribute of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns 0 in case of success and -1 in case of error
|
| + */
|
| +static int
|
| +xmlParseCRNG_attribute(xmlCRelaxNGParserCtxtPtr ctxt,
|
| + const xmlChar *name,
|
| + xmlNsPtr ns,
|
| + const xmlChar *value)
|
| +{
|
| + xmlAttrPtr attr;
|
| +
|
| + attr = xmlNewNsPropEatName(NULL, ns, (xmlChar *) name, value);
|
| + if (attr == NULL) CRNG_MEM_ERROR0();
|
| + attr->next = ctxt->attrs;
|
| + if (ctxt->attrs != NULL)
|
| + ctxt->attrs->prev = attr;
|
| + ctxt->attrs = attr;
|
| + return(0);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNG_bindPrefix:
|
| + * @ctxt: a compact RNG parser context
|
| + * @prefix: the namespace prefix or NULL
|
| + * @namespace: the namespace name
|
| + *
|
| + * implements bindPrefix of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns 0 in case of success and -1 in case of error
|
| + */
|
| +static int
|
| +xmlParseCRNG_bindPrefix(xmlCRelaxNGParserCtxtPtr ctxt,
|
| + const xmlChar *prefix,
|
| + const xmlChar *namespace)
|
| +{
|
| + int ret;
|
| +
|
| + if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml")) &&
|
| + (!xmlStrEqual(namespace, XML_XML_NAMESPACE))) {
|
| + ERROR("The \"xml\" prefix must be bound to \"http://www.w3.org/XML/1998/namespace\"");
|
| + return(-1);
|
| + } else if ((xmlStrEqual(namespace, XML_XML_NAMESPACE)) &&
|
| + (!xmlStrEqual(prefix, BAD_CAST "xml"))) {
|
| + ERROR("The \"http://www.w3.org/XML/1998/namespace\" name must be bound to \"xml\" prefix");
|
| + return(-1);
|
| + }
|
| + if (ctxt->namespaces == NULL)
|
| + ctxt->namespaces = xmlHashCreate(10);
|
| + if (ctxt->namespaces == NULL) {
|
| + ERROR("Failed to create namespace hash table");
|
| + return(-1);
|
| + }
|
| + if (prefix == NULL)
|
| + ret = xmlHashAddEntry(ctxt->namespaces, xmlCRelaxNGDefault,
|
| + (void *) namespace);
|
| + else
|
| + ret = xmlHashAddEntry(ctxt->namespaces, prefix,
|
| + (void *) namespace);
|
| + if (ret < 0) {
|
| + if (prefix == NULL) {
|
| + ERROR("Redefinition of default namespace");
|
| + } else {
|
| + ERROR("Redefinition of namespace");
|
| + }
|
| + return(-1);
|
| + }
|
| +
|
| + return(0);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNG_bindDatatypePrefix:
|
| + * @ctxt: a compact RNG parser context
|
| + * @prefix: the datatype prefix
|
| + * @namespace: the datatype identifier
|
| + *
|
| + * implements bindDatatypePrefix of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns 0 in case of success and -1 in case of error
|
| + */
|
| +static int
|
| +xmlParseCRNG_bindDatatypePrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
|
| + const xmlChar *prefix,
|
| + const xmlChar *namespace)
|
| +{
|
| + int ret;
|
| +
|
| + if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xsd")) &&
|
| + (!xmlStrEqual(namespace,
|
| + BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes"))) {
|
| + ERROR("The \"xsd\" prefix must be bound to \"http://www.w3.org/2001/XMLSchema-datatypes\"");
|
| + return(-1);
|
| + }
|
| + if (ctxt->datatypes == NULL)
|
| + ctxt->datatypes = xmlHashCreate(10);
|
| + if (ctxt->datatypes == NULL) {
|
| + ERROR("Failed to create namespace hash table");
|
| + return(-1);
|
| + }
|
| + ret = xmlHashAddEntry(ctxt->datatypes, prefix,
|
| + (void *) namespace);
|
| + if (ret < 0) {
|
| + ERROR("Redefinition of datatype");
|
| + return(-1);
|
| + }
|
| + return(0);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNG_lookupPrefix:
|
| + * @ctxt: a compact RNG parser context
|
| + * @prefix: the namespace prefix or NULL
|
| + *
|
| + * implements lookupPrefix of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns the prefix in case of success or NULL in case of error
|
| + */
|
| +static const xmlChar *
|
| +xmlParseCRNG_lookupPrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
|
| + const xmlChar *prefix)
|
| +{
|
| + const xmlChar *ret;
|
| +
|
| + if (prefix == NULL)
|
| + ret = xmlHashLookup(ctxt->namespaces, xmlCRelaxNGDefault);
|
| + else
|
| + ret = xmlHashLookup(ctxt->namespaces, prefix);
|
| + return(ret);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNG_lookupDatatypePrefix:
|
| + * @ctxt: a compact RNG parser context
|
| + * @prefix: the namespace prefix or NULL
|
| + *
|
| + * implements lookupDatatypePrefix of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns the prefix in case of success or NULL in case of error
|
| + */
|
| +static const xmlChar *
|
| +xmlParseCRNG_lookupDatatypePrefix(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
|
| + const xmlChar *prefix)
|
| +{
|
| + const xmlChar *ret;
|
| + ret = xmlHashLookup(ctxt->datatypes, prefix);
|
| + return(ret);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNG_datatypeAttributes:
|
| + * @ctxt: a compact RNG parser context
|
| + * @prefix: the namespace prefix or NULL
|
| + *
|
| + * implements lookupPrefix of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns the prefix in case of success or NULL in case of error
|
| + */
|
| +static xmlAttrPtr
|
| +xmlParseCRNG_datatypeAttributes(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
|
| + const xmlChar *library, const xmlChar *type)
|
| +{
|
| + xmlAttrPtr lib, typ;
|
| +
|
| + lib = xmlNewNsProp(NULL, NULL, BAD_CAST "datatypeLibrary", library);
|
| + if (lib == NULL) {
|
| + CRNG_MEM_ERROR();
|
| + return(NULL);
|
| + }
|
| + typ = xmlNewNsProp(NULL, NULL, BAD_CAST "type", type);
|
| + if (typ == NULL) {
|
| + CRNG_MEM_ERROR();
|
| + return(lib);
|
| + }
|
| + lib->next = typ;
|
| +
|
| + return(lib);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNG_XXX:
|
| + * @ctxt: a compact RNG parser context
|
| + *
|
| + * Parse XXX of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns 0 in case of success and -1 in case of error
|
| + */
|
| +static int
|
| +xmlParseCRNG_XXX(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
|
| +{
|
| + return(0);
|
| +}
|
| +
|
| +static int xmlParseCRNG_pattern(xmlCRelaxNGParserCtxtPtr ctxt);
|
| +static int xmlParseCRNG_nameClass(xmlCRelaxNGParserCtxtPtr ctxt);
|
| +
|
| +/**
|
| + * xmlParseCRNG_params:
|
| + * @ctxt: a compact RNG parser context
|
| + *
|
| + * Parse params of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns 0 in case of success and -1 in case of error
|
| + */
|
| +static int
|
| +xmlParseCRNG_params(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
|
| +{
|
| + TODO
|
| + return(0);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNG_exceptNameClass:
|
| + * @ctxt: a compact RNG parser context
|
| + *
|
| + * Parse exceptNameClass of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns 0 in case of success and -1 in case of error
|
| + */
|
| +static int
|
| +xmlParseCRNG_exceptNameClass(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
|
| +{
|
| + tokenPtr token;
|
| + xmlNodePtr insert = ctxt->insert, cur;
|
| +
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + if ((token->toktype == CRNG_OP) &&
|
| + (token->token[0] == '-') && (token->token[1] == 0)) {
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + cur = xmlNewNode(NULL, BAD_CAST "except");
|
| + if (cur == NULL) CRNG_MEM_ERROR0();
|
| + if (ctxt->insert != NULL)
|
| + xmlAddChild(ctxt->insert, cur);
|
| + ctxt->insert = cur;
|
| + xmlParseCRNG_nameClass(ctxt);
|
| + }
|
| + ctxt->insert = insert;
|
| + return(0);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNG_innerNameClass:
|
| + * @ctxt: a compact RNG parser context
|
| + *
|
| + * Parse innerNameClass of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns 0 in case of success and -1 in case of error
|
| + */
|
| +static int
|
| +xmlParseCRNG_innerNameClass(xmlCRelaxNGParserCtxtPtr ctxt)
|
| +{
|
| + tokenPtr token;
|
| + xmlNodePtr cur;
|
| +
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + if (token->toktype == CRNG_OP) {
|
| + if ((token->token[0] == '(') && (token->token[1] == 0)) {
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + xmlParseCRNG_nameClass(ctxt);
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + if ((token->toktype != CRNG_OP) ||
|
| + (token->token[0] != ')') || (token->token[1] != 0)) {
|
| + ERROR("Expecting \")\" here");
|
| + }
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + } else if ((token->token[0] == '*') && (token->token[1] == 0)) {
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + cur = xmlNewNode(NULL, BAD_CAST "anyName");
|
| + if (cur == NULL) CRNG_MEM_ERROR0();
|
| + if (ctxt->insert != NULL)
|
| + xmlAddChild(ctxt->insert, cur);
|
| + ctxt->insert = cur;
|
| + xmlParseCRNG_exceptNameClass(ctxt);
|
| + } else {
|
| + TODO
|
| + }
|
| + } else if ((token->toktype == CRNG_IDENTIFIER) ||
|
| + (token->toktype == CRNG_KEYWORD)) {
|
| + cur = xmlNewNode(NULL, BAD_CAST "name");
|
| + if (cur == NULL) CRNG_MEM_ERROR0();
|
| + if (ctxt->isElem) {
|
| + xmlSetProp(cur, BAD_CAST "ns",
|
| + xmlParseCRNG_lookupPrefix(ctxt, NULL));
|
| + } else {
|
| + xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
|
| + }
|
| + xmlNodeAddContent(cur, token->token);
|
| + if (ctxt->insert != NULL)
|
| + xmlAddChild(ctxt->insert, cur);
|
| + ctxt->insert = cur;
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + } else if (token->toktype == CRNG_CNAME) {
|
| + TODO
|
| + } else if (token->toktype == CRNG_NSNAME) {
|
| + cur = xmlNewNode(NULL, BAD_CAST "nsName");
|
| + if (cur == NULL) CRNG_MEM_ERROR0();
|
| + xmlSetProp(cur, BAD_CAST "ns",
|
| + xmlParseCRNG_lookupPrefix(ctxt, token->token));
|
| + if (ctxt->insert != NULL)
|
| + xmlAddChild(ctxt->insert, cur);
|
| + ctxt->insert = cur;
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + xmlParseCRNG_exceptNameClass(ctxt);
|
| + } else {
|
| + TODO /* probably an error */
|
| + }
|
| +
|
| + return(0);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNG_nameClass:
|
| + * @ctxt: a compact RNG parser context
|
| + *
|
| + * Parse nameClass of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns 0 in case of success and -1 in case of error
|
| + */
|
| +static int
|
| +xmlParseCRNG_nameClass(xmlCRelaxNGParserCtxtPtr ctxt)
|
| +{
|
| + tokenPtr token;
|
| + xmlNodePtr insert = ctxt->insert, last, choice;
|
| +
|
| + ctxt->insert = NULL;
|
| + xmlParseCRNG_innerNameClass(ctxt);
|
| + last = ctxt->insert;
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + while ((token->toktype == CRNG_OP) &&
|
| + (token->token[0] == '|') && (token->token[1] == 0)) {
|
| + choice = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_choice);
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + if (choice == NULL) CRNG_MEM_ERROR0();
|
| + ctxt->insert = NULL;
|
| + xmlParseCRNG_innerNameClass(ctxt);
|
| + xmlAddChild(choice, last);
|
| + xmlAddChild(choice, ctxt->insert);
|
| + last = choice;
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + }
|
| + xmlAddChild(insert, last);
|
| +
|
| + ctxt->insert = insert;
|
| + return(0);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNG_patternBlock:
|
| + * @ctxt: a compact RNG parser context
|
| + *
|
| + * Parse a pattern block of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns 0 in case of success and -1 in case of error
|
| + */
|
| +static int
|
| +xmlParseCRNG_patternBlock(xmlCRelaxNGParserCtxtPtr ctxt)
|
| +{
|
| + tokenPtr token;
|
| +
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + if ((token->toktype != CRNG_OP) ||
|
| + (token->token[0] != '{') || (token->token[1] != 0)) {
|
| + ERROR("Expecting \"{\" here");
|
| + }
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + xmlParseCRNG_pattern(ctxt);
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + if ((token->toktype != CRNG_OP) ||
|
| + (token->token[0] != '}') || (token->token[1] != 0)) {
|
| + ERROR("Expecting \"}\" here");
|
| + }
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + return(0);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNG_datatype:
|
| + * @ctxt: a compact RNG parser context
|
| + *
|
| + * Parse datatype of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns 0 in case of success and -1 in case of error
|
| + */
|
| +static int
|
| +xmlParseCRNG_datatype(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
|
| +{
|
| + tokenPtr token;
|
| + xmlAttrPtr attrs = NULL;
|
| +
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + if (token->toktype == CRNG_KEYWORD) {
|
| + if (token->token == ctxt->key_string) {
|
| + attrs = xmlParseCRNG_datatypeAttributes(ctxt, BAD_CAST "",
|
| + token->token);
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + } else if (token->token == ctxt->key_token) {
|
| + attrs = xmlParseCRNG_datatypeAttributes(ctxt, BAD_CAST "",
|
| + token->token);
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + } else {
|
| + TODO /* probably an error */
|
| + }
|
| + } else if (token->toktype == CRNG_LITERAL_SEGMENT) {
|
| + ctxt->insert = xmlNewNode(NULL, BAD_CAST "value");
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
|
| + xmlNodeAddContent(ctxt->insert, token->token);
|
| + } else if (token->toktype == CRNG_QNAME) {
|
| + attrs = xmlParseCRNG_datatypeAttributes(ctxt,
|
| + xmlParseCRNG_lookupDatatypePrefix(ctxt, token->prefix),
|
| + token->token);
|
| + } else {
|
| + TODO
|
| + }
|
| + if (attrs != NULL) {
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + if (token->toktype == CRNG_LITERAL_SEGMENT) {
|
| + ctxt->insert = xmlNewNode(NULL, BAD_CAST "value");
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + if (ctxt->insert == NULL) {
|
| + xmlFreePropList(attrs);
|
| + CRNG_MEM_ERROR0();
|
| + }
|
| + ctxt->insert->properties = attrs;
|
| + xmlNodeAddContent(ctxt->insert, token->token);
|
| + } else if ((token->toktype == CRNG_OP) &&
|
| + (token->token[0] == '{') && (token->token[0] == 0)) {
|
| + ctxt->insert = xmlNewNode(NULL, BAD_CAST "data");
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + if (ctxt->insert == NULL) {
|
| + xmlFreePropList(attrs);
|
| + CRNG_MEM_ERROR0();
|
| + }
|
| + ctxt->insert->properties = attrs;
|
| + xmlParseCRNG_params(ctxt);
|
| + } else {
|
| + ctxt->insert = xmlNewNode(NULL, BAD_CAST "data");
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + if (ctxt->insert == NULL) {
|
| + xmlFreePropList(attrs);
|
| + CRNG_MEM_ERROR0();
|
| + }
|
| + ctxt->insert->properties = attrs;
|
| + xmlNodeAddContent(ctxt->insert, token->token);
|
| + }
|
| + }
|
| + return(0);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNG_primary:
|
| + * @ctxt: a compact RNG parser context
|
| + *
|
| + * Parse primary of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns 0 in case of success and -1 in case of error
|
| + */
|
| +static int
|
| +xmlParseCRNG_primary(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
|
| +{
|
| + tokenPtr token;
|
| +
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + if (token == NULL)
|
| + return(0);
|
| + if (token->toktype == CRNG_KEYWORD) {
|
| + if (token->token == ctxt->key_element) {
|
| + ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
|
| + ctxt->isElem = 1;
|
| + xmlParseCRNG_nameClass(ctxt);
|
| + xmlParseCRNG_patternBlock(ctxt);
|
| + } else if (token->token == ctxt->key_attribute) {
|
| + ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
|
| + ctxt->isElem = 0;
|
| + xmlParseCRNG_nameClass(ctxt);
|
| + xmlParseCRNG_patternBlock(ctxt);
|
| + } else if (token->token == ctxt->key_mixed) {
|
| + ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
|
| + xmlParseCRNG_patternBlock(ctxt);
|
| + } else if (token->token == ctxt->key_list) {
|
| + ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
|
| + xmlParseCRNG_patternBlock(ctxt);
|
| + } else if (token->token == ctxt->key_empty) {
|
| + ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
|
| + } else if (token->token == ctxt->key_notAllowed) {
|
| + ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
|
| + } else if (token->token == ctxt->key_text) {
|
| + ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
|
| + } else if (token->token == ctxt->key_parent) {
|
| + ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
|
| + TODO
|
| + } else if (token->token == ctxt->key_grammar) {
|
| + ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) token->token);
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
|
| + TODO
|
| + } else if (token->token == ctxt->key_external) {
|
| + ctxt->insert = xmlNewNode(NULL, BAD_CAST "externalRef");
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
|
| + TODO
|
| + } else {
|
| + TODO
|
| + }
|
| + } else if (token->toktype == CRNG_IDENTIFIER) {
|
| + ctxt->insert = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_ref);
|
| + if (ctxt->insert == NULL) CRNG_MEM_ERROR0();
|
| + xmlSetProp(ctxt->insert, BAD_CAST "name", token->token);
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + } else if (token->toktype == CRNG_QNAME) {
|
| + xmlParseCRNG_datatype(ctxt);
|
| + } else if (token->toktype == CRNG_LITERAL_SEGMENT) {
|
| + xmlParseCRNG_datatype(ctxt);
|
| + } else if ((token->toktype == CRNG_OP) &&
|
| + (token->token[0] == '(') && (token->token[1] == 0)) {
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + xmlParseCRNG_pattern(ctxt);
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + if ((token->toktype != CRNG_OP) ||
|
| + (token->token[0] != ')') || (token->token[1] != 0)) {
|
| + ERROR("Expecting \")\" here");
|
| + }
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + }
|
| + return(0);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNG_particle:
|
| + * @ctxt: a compact RNG parser context
|
| + *
|
| + * Parse particle of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns 0 in case of success and -1 in case of error
|
| + */
|
| +static int
|
| +xmlParseCRNG_particle(xmlCRelaxNGParserCtxtPtr ctxt)
|
| +{
|
| + tokenPtr token;
|
| + xmlNodePtr insert = ctxt->insert, res, tmp = NULL;
|
| +
|
| + ctxt->insert = NULL;
|
| + xmlParseCRNG_primary(ctxt);
|
| + res = ctxt->insert;
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + if ((token != NULL) && (token->toktype == CRNG_OP)) {
|
| + if ((token->token[0] == '*') && (token->token[1] == 0)) {
|
| + tmp = xmlNewNode(NULL, BAD_CAST "zeroOrMore");
|
| + if (tmp == NULL) CRNG_MEM_ERROR0();
|
| + } else if ((token->token[0] == '+') && (token->token[1] == 0)) {
|
| + tmp = xmlNewNode(NULL, BAD_CAST "oneOrMore");
|
| + if (tmp == NULL) CRNG_MEM_ERROR0();
|
| + } else if ((token->token[0] == '?') && (token->token[1] == 0)) {
|
| + tmp = xmlNewNode(NULL, BAD_CAST "optional");
|
| + if (tmp == NULL) CRNG_MEM_ERROR0();
|
| + }
|
| + if (tmp != NULL) {
|
| + xmlAddChild(tmp, res);
|
| + res = tmp;
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + }
|
| + }
|
| + if (insert != NULL) {
|
| + xmlAddChild(insert, res);
|
| + ctxt->insert = insert;
|
| + } else
|
| + ctxt->insert = res;
|
| + return(0);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNG_pattern:
|
| + * @ctxt: a compact RNG parser context
|
| + *
|
| + * Parse pattern of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns 0 in case of success and -1 in case of error
|
| + */
|
| +static int
|
| +xmlParseCRNG_pattern(xmlCRelaxNGParserCtxtPtr ctxt)
|
| +{
|
| + tokenPtr token;
|
| + xmlNodePtr insert = ctxt->insert, prev, grp;
|
| +
|
| + ctxt->insert = NULL;
|
| + xmlParseCRNG_particle(ctxt);
|
| + prev = ctxt->insert;
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + while ((prev != NULL) && (token != NULL) && (token->toktype == CRNG_OP)) {
|
| + if (token->token == ctxt->key_or) {
|
| + grp = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_choice);
|
| + if (grp == NULL) CRNG_MEM_ERROR0();
|
| + } else if (token->token == ctxt->key_and) {
|
| + grp = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_interleave);
|
| + if (grp == NULL) CRNG_MEM_ERROR0();
|
| + } else if (token->token == ctxt->key_comma) {
|
| + grp = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_group);
|
| + if (grp == NULL) CRNG_MEM_ERROR0();
|
| + } else
|
| + break;
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + ctxt->insert = NULL;
|
| + xmlParseCRNG_particle(ctxt);
|
| + xmlAddChild(grp, prev);
|
| + xmlAddChild(grp, ctxt->insert);
|
| + prev = grp;
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + }
|
| + if (insert != NULL) {
|
| + xmlAddChild(insert, prev);
|
| + ctxt->insert = insert;
|
| + } else {
|
| + ctxt->insert = prev;
|
| + }
|
| +
|
| + return(0);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNG_component:
|
| + * @ctxt: a compact RNG parser context
|
| + *
|
| + * Parse component of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns 0 in case of success and -1 in case of error
|
| + */
|
| +static int
|
| +xmlParseCRNG_component(xmlCRelaxNGParserCtxtPtr ctxt)
|
| +{
|
| + tokenPtr token, tok2;
|
| + xmlNodePtr insert = ctxt->insert;
|
| +
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + if (token == NULL)
|
| + return(0);
|
| + if (token->toktype == CRNG_KEYWORD) {
|
| + if (token->token == ctxt->key_start) {
|
| + xmlNodePtr start;
|
| +
|
| + start = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_start);
|
| + if (start == NULL) CRNG_MEM_ERROR0();
|
| + if (ctxt->insert != NULL)
|
| + xmlAddChild(ctxt->insert, start);
|
| + ctxt->insert = start;
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| +
|
| + if ((token->toktype == CRNG_OP) &&
|
| + (token->token == ctxt->key_equal)) {
|
| + } else if ((token->toktype == CRNG_OP) &&
|
| + (token->token == ctxt->key_orequal)) {
|
| + xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL,
|
| + BAD_CAST "choice");
|
| + } else if ((token->toktype == CRNG_OP) &&
|
| + (token->token == ctxt->key_andequal)) {
|
| + xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL,
|
| + BAD_CAST "interleave");
|
| + } else {
|
| + ERROR("expecting \"=\" or \"&=\" or \"|=\" here")
|
| + return(-1);
|
| + }
|
| + start->properties = ctxt->attrs;
|
| + ctxt->attrs = NULL;
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + xmlParseCRNG_pattern(ctxt);
|
| +
|
| + } else if (token->token == ctxt->key_include) {
|
| + TODO
|
| + } else if (token->token == ctxt->key_div) {
|
| + TODO
|
| + } else {
|
| + return(-1);
|
| + }
|
| + } else if (token->toktype == CRNG_IDENTIFIER) {
|
| + xmlNodePtr define;
|
| + const xmlChar *identifier;
|
| +
|
| + identifier = token->token;
|
| + tok2 = xmlParseCRNGGetToken(ctxt, 2);
|
| + if ((tok2->toktype == CRNG_OP) &&
|
| + (tok2->token == ctxt->key_equal)) {
|
| + } else if ((tok2->toktype == CRNG_OP) &&
|
| + (tok2->token == ctxt->key_orequal)) {
|
| + xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL,
|
| + BAD_CAST "choice");
|
| + } else if ((tok2->toktype == CRNG_OP) &&
|
| + (tok2->token == ctxt->key_andequal)) {
|
| + xmlParseCRNG_attribute(ctxt, ctxt->key_combine, NULL,
|
| + BAD_CAST "interleave");
|
| + } else {
|
| + ERROR("expecting \"=\" or \"&=\" or \"|=\" here")
|
| + return(-1);
|
| + }
|
| + xmlParseCRNGDropTokens(ctxt, 2);
|
| +
|
| + define = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_define);
|
| + if (define == NULL) CRNG_MEM_ERROR0();
|
| + define->properties = ctxt->attrs;
|
| + ctxt->attrs = NULL;
|
| + xmlSetProp(define, BAD_CAST "name", identifier);
|
| + if (ctxt->insert != NULL)
|
| + xmlAddChild(ctxt->insert, define);
|
| + ctxt->insert = define;
|
| + xmlParseCRNG_pattern(ctxt);
|
| + } else {
|
| + return(-1);
|
| + }
|
| + ctxt->insert = insert;
|
| + return(0);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNG_grammar:
|
| + * @ctxt: a compact RNG parser context
|
| + *
|
| + * Parse grammar of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns 0 in case of success and -1 in case of error
|
| + */
|
| +static int
|
| +xmlParseCRNG_grammar(xmlCRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED)
|
| +{
|
| + tokenPtr token;
|
| + int ret;
|
| +
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + while (token != NULL) {
|
| + ret = xmlParseCRNG_component(ctxt);
|
| + if (ret != 0)
|
| + break;
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + }
|
| + return(0);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNG_topLevelBody:
|
| + * @ctxt: a compact RNG parser context
|
| + *
|
| + * Parse topLevelBody of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns 0 in case of success and -1 in case of error
|
| + */
|
| +static int
|
| +xmlParseCRNG_topLevelBody(xmlCRelaxNGParserCtxtPtr ctxt)
|
| +{
|
| + tokenPtr token, tok2;
|
| +
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + if (token->toktype == CRNG_KEYWORD) {
|
| + if ((token->token == ctxt->key_start) ||
|
| + (token->token == ctxt->key_include) ||
|
| + (token->token == ctxt->key_div)) {
|
| + xmlNodePtr grammar;
|
| +
|
| + grammar = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_grammar);
|
| + if (grammar == NULL) CRNG_MEM_ERROR0();
|
| + xmlDocSetRootElement(ctxt->doc, grammar);
|
| + ctxt->insert = grammar;
|
| +
|
| + xmlParseCRNG_grammar(ctxt);
|
| + } else {
|
| + xmlParseCRNG_pattern(ctxt);
|
| + }
|
| + } else {
|
| + tok2 = xmlParseCRNGGetToken(ctxt, 2);
|
| + if ((tok2->toktype == CRNG_OP) &&
|
| + ((tok2->token == ctxt->key_equal) ||
|
| + (tok2->token == ctxt->key_orequal) ||
|
| + (tok2->token == ctxt->key_andequal))) {
|
| + xmlNodePtr grammar;
|
| +
|
| + grammar = xmlNewNodeEatName(NULL, (xmlChar *) ctxt->key_grammar);
|
| + if (grammar == NULL) CRNG_MEM_ERROR0();
|
| + xmlDocSetRootElement(ctxt->doc, grammar);
|
| + ctxt->insert = grammar;
|
| +
|
| + xmlParseCRNG_grammar(ctxt);
|
| + } else {
|
| + xmlParseCRNG_pattern(ctxt);
|
| + }
|
| + }
|
| + return(0);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNG_namespacePrefix:
|
| + * @ctxt: a compact RNG parser context
|
| + *
|
| + * Parse namespacePrefix of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns the prefix or NULL in case of error
|
| + */
|
| +static const xmlChar *
|
| +xmlParseCRNG_namespacePrefix(xmlCRelaxNGParserCtxtPtr ctxt)
|
| +{
|
| + tokenPtr token;
|
| + const xmlChar *prefix = NULL;
|
| +
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + if (token->toktype == CRNG_IDENTIFIER) {
|
| + prefix = token->token;
|
| + } else if (token->toktype == CRNG_OP) {
|
| + if ((token->token[0] == '=') && (token->token[1] == 0))
|
| + return(NULL);
|
| + prefix = token->token;
|
| + } else {
|
| + ERROR("Expecting a namespace prefix");
|
| + return(NULL);
|
| + }
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| +
|
| + if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
|
| + ERROR("Namespace prefix \"xmlns\" is forbidden");
|
| + }
|
| + return(prefix);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNG_decl:
|
| + * @ctxt: a compact RNG parser context
|
| + *
|
| + * Parse decl of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns 0 in case of success and -1 in case of error
|
| + */
|
| +static int
|
| +xmlParseCRNG_decl(xmlCRelaxNGParserCtxtPtr ctxt)
|
| +{
|
| + const xmlChar *prefix = NULL;
|
| + const xmlChar *namespace = NULL;
|
| + tokenPtr token;
|
| +
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + if (token->toktype != CRNG_KEYWORD) return(-1);
|
| + if (token->token == ctxt->key_default) {
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + if ((token->toktype != CRNG_KEYWORD) ||
|
| + (token->token != ctxt->key_namespace)) {
|
| + ERROR("Expecting keyword \"namespace\" after \"default\"");
|
| + }
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + prefix = xmlParseCRNG_namespacePrefix(ctxt);
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + if ((token->toktype != CRNG_OP) ||
|
| + (token->token[0] != '=') || (token->token[1] != 0)) {
|
| + ERROR("Expecting keyword \"=\" here");
|
| + }
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + if ((token->toktype == CRNG_KEYWORD) &&
|
| + (token->token == ctxt->key_inherit)) {
|
| + namespace = xmlCRelaxNGInherit;
|
| + } else if (token->toktype == CRNG_LITERAL_SEGMENT) {
|
| + namespace = token->token;
|
| + } else {
|
| + ERROR("Expecting an URI or \"inherit\" value");
|
| + }
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + if (namespace != NULL) {
|
| + if (prefix != NULL)
|
| + xmlParseCRNG_bindPrefix(ctxt, prefix, namespace);
|
| + xmlParseCRNG_bindPrefix(ctxt, NULL, namespace);
|
| + }
|
| + } else if (token->token == ctxt->key_namespace) {
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + prefix = xmlParseCRNG_namespacePrefix(ctxt);
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + if ((token->toktype != CRNG_OP) ||
|
| + (token->token[0] != '=') || (token->token[1] != 0)) {
|
| + ERROR("Expecting keyword \"=\" here");
|
| + }
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + if ((token->toktype == CRNG_KEYWORD) &&
|
| + (token->token == ctxt->key_inherit)) {
|
| + namespace = xmlCRelaxNGInherit;
|
| + } else if (token->toktype == CRNG_LITERAL_SEGMENT) {
|
| + namespace = token->token;
|
| + } else {
|
| + ERROR("Expecting an URI or \"inherit\" value");
|
| + }
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + if (namespace != NULL)
|
| + xmlParseCRNG_bindPrefix(ctxt, prefix, namespace);
|
| + } else if (token->token == ctxt->key_datatypes) {
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| +
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + if ((token->toktype != CRNG_KEYWORD) &&
|
| + (token->toktype != CRNG_IDENTIFIER)) {
|
| + ERROR("Expecting a datatype prefix identifier here");
|
| + } else
|
| + prefix = token->token;
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + if ((token->toktype != CRNG_OP) ||
|
| + (token->token[0] != '=') || (token->token[1] != 0)) {
|
| + ERROR("Expecting keyword \"=\" here");
|
| + }
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + if (token->toktype == CRNG_LITERAL_SEGMENT) {
|
| + namespace = token->token;
|
| + } else {
|
| + ERROR("Expecting a literal value for the datatype identifier");
|
| + }
|
| + xmlParseCRNGDropTokens(ctxt, 1);
|
| + if ((namespace != NULL) && (prefix != NULL))
|
| + xmlParseCRNG_bindDatatypePrefix(ctxt, prefix, namespace);
|
| + }
|
| +
|
| + return(0);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNG_preamble:
|
| + * @ctxt: a compact RNG parser context
|
| + *
|
| + * Parse preamble of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns 0 in case of success and -1 in case of error
|
| + */
|
| +static int
|
| +xmlParseCRNG_preamble(xmlCRelaxNGParserCtxtPtr ctxt)
|
| +{
|
| + tokenPtr token;
|
| +
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + while (token != NULL) {
|
| + if (token == NULL) return(-1);
|
| + if ((token->toktype == CRNG_KEYWORD) &&
|
| + ((token->token == ctxt->key_default) ||
|
| + (token->token == ctxt->key_namespace) ||
|
| + (token->token == ctxt->key_datatypes))) {
|
| + xmlParseCRNG_decl(ctxt);
|
| + } else
|
| + break;
|
| + token = xmlParseCRNGGetToken(ctxt, 1);
|
| + }
|
| + return(0);
|
| +}
|
| +
|
| +/**
|
| + * xmlParseCRNG_topLevel:
|
| + * @ctxt: a compact RNG parser context
|
| + *
|
| + * Parse topLevel of the RELAX NG Compact Syntax Appendix A
|
| + *
|
| + * Returns 0 in case of success and -1 in case of error
|
| + */
|
| +static int
|
| +xmlParseCRNG_topLevel(xmlCRelaxNGParserCtxtPtr ctxt)
|
| +{
|
| + xmlParseCRNG_preamble(ctxt);
|
| + xmlParseCRNG_topLevelBody(ctxt);
|
| + return(0);
|
| +}
|
| +
|
| +/**
|
| + * xmlConvertCRNG:
|
| + * @schemas: pointer to the text of the compact schemas
|
| + * @len: length of the schemas in bytes (or 0)
|
| + * @encoding: encoding indicated by the context or NULL
|
| + *
|
| + * Compiles the schemas into the equivalent Relax-NG XML structure
|
| + *
|
| + * Returns the xmlDocPtr resulting from the compilation or
|
| + * NULL in case of error
|
| + */
|
| +xmlDocPtr
|
| +xmlConvertCRNG(const char *schemas, int len, const char *encoding) {
|
| + struct _xmlCRelaxNGParserCtxt ctxt;
|
| + xmlDocPtr ret = NULL;
|
| +
|
| + if (schemas == NULL) return(NULL);
|
| + if (len <= 5) len = xmlStrlen((const unsigned char *) schemas);
|
| + if (len <= 0) return(NULL);
|
| +
|
| + memset(&ctxt, 0, sizeof(ctxt));
|
| + ctxt.compact = (const unsigned char *) schemas;
|
| + ctxt.cur = (const unsigned char *) schemas;
|
| + ctxt.end = (const unsigned char *) &schemas[len];
|
| + ctxt.dict = xmlDictCreate();
|
| + if (ctxt.dict == NULL)
|
| + return(NULL);
|
| + ctxt.doc = xmlNewDoc(NULL);
|
| + if (ctxt.doc == NULL) {
|
| + xmlDictFree(ctxt.dict);
|
| + return(NULL);
|
| + }
|
| + ctxt.doc->dict = ctxt.dict;
|
| + xmlDictReference(ctxt.dict);
|
| +
|
| + ctxt.nbTokens = 0;
|
| + ctxt.firstToken = 0;
|
| + ctxt.key_attribute = xmlDictLookup(ctxt.dict, BAD_CAST "attribute", -1);
|
| + ctxt.key_default = xmlDictLookup(ctxt.dict, BAD_CAST "default", -1);
|
| + ctxt.key_datatypes = xmlDictLookup(ctxt.dict, BAD_CAST "datatypes", -1);
|
| + ctxt.key_div = xmlDictLookup(ctxt.dict, BAD_CAST "div", -1);
|
| + ctxt.key_element = xmlDictLookup(ctxt.dict, BAD_CAST "element", -1);
|
| + ctxt.key_empty = xmlDictLookup(ctxt.dict, BAD_CAST "empty", -1);
|
| + ctxt.key_external = xmlDictLookup(ctxt.dict, BAD_CAST "external", -1);
|
| + ctxt.key_grammar = xmlDictLookup(ctxt.dict, BAD_CAST "grammar", -1);
|
| + ctxt.key_include = xmlDictLookup(ctxt.dict, BAD_CAST "include", -1);
|
| + ctxt.key_inherit = xmlDictLookup(ctxt.dict, BAD_CAST "inherit", -1);
|
| + ctxt.key_list = xmlDictLookup(ctxt.dict, BAD_CAST "list", -1);
|
| + ctxt.key_mixed = xmlDictLookup(ctxt.dict, BAD_CAST "mixed", -1);
|
| + ctxt.key_namespace = xmlDictLookup(ctxt.dict, BAD_CAST "namespace", -1);
|
| + ctxt.key_notAllowed = xmlDictLookup(ctxt.dict, BAD_CAST "notAllowed", -1);
|
| + ctxt.key_parent = xmlDictLookup(ctxt.dict, BAD_CAST "parent", -1);
|
| + ctxt.key_start = xmlDictLookup(ctxt.dict, BAD_CAST "start", -1);
|
| + ctxt.key_string = xmlDictLookup(ctxt.dict, BAD_CAST "string", -1);
|
| + ctxt.key_text = xmlDictLookup(ctxt.dict, BAD_CAST "text", -1);
|
| + ctxt.key_token = xmlDictLookup(ctxt.dict, BAD_CAST "token", -1);
|
| + ctxt.key_equal = xmlDictLookup(ctxt.dict, BAD_CAST "=", 1);
|
| + ctxt.key_orequal = xmlDictLookup(ctxt.dict, BAD_CAST "|=", 2);
|
| + ctxt.key_andequal = xmlDictLookup(ctxt.dict, BAD_CAST "&=", 2);
|
| + ctxt.key_combine = xmlDictLookup(ctxt.dict, BAD_CAST "&=", 2);
|
| + ctxt.key_or = xmlDictLookup(ctxt.dict, BAD_CAST "|", 1);
|
| + ctxt.key_comma = xmlDictLookup(ctxt.dict, BAD_CAST ",", 1);
|
| + ctxt.key_and = xmlDictLookup(ctxt.dict, BAD_CAST "&", 1);
|
| + ctxt.key_choice = xmlDictLookup(ctxt.dict, BAD_CAST "choice", -1);
|
| + ctxt.key_group = xmlDictLookup(ctxt.dict, BAD_CAST "group", -1);
|
| + ctxt.key_interleave = xmlDictLookup(ctxt.dict, BAD_CAST "interleave", -1);
|
| + ctxt.key_ref = xmlDictLookup(ctxt.dict, BAD_CAST "ref", 3);
|
| + ctxt.key_define = xmlDictLookup(ctxt.dict, BAD_CAST "define", 6);
|
| +
|
| + /* xmlConvertCRNGTokenize(&ctxt); */
|
| + xmlConvertCRNG_topLevel(&ctxt);
|
| +
|
| + xmlDictFree(ctxt.dict);
|
| +
|
| + ret = ctxt.doc;
|
| + return(ret);
|
| +}
|
| +
|
| +/**
|
| + * xmlConvertCRNGFile:
|
| + * @URL: URL or filename for the resource
|
| + * @encoding: encoding indicated by the context or NULL
|
| + *
|
| + * Compiles the schemas into the equivalent Relax-NG XML structure
|
| + *
|
| + * Returns the xmlDocPtr resulting from the compilation or
|
| + * NULL in case of error
|
| + */
|
| +xmlDocPtr
|
| +xmlConvertCRNGFile(const char *URL, const char *encoding) {
|
| +}
|
| +
|
| +#ifdef STANDALONE
|
| +const xmlChar *schemas =
|
| +"# RELAX NG XML syntax specified in compact syntax.\n\
|
| +\n\
|
| +default namespace rng = \"http://relaxng.org/ns/structure/1.0\"\n\
|
| +namespace local = \"\"\n\
|
| +datatypes xsd = \"http://www.w3.org/2001/XMLSchema-datatypes\"\n\
|
| +\n\
|
| +start = pattern\n\
|
| +\n\
|
| +pattern =\n\
|
| + element element { (nameQName | nameClass), (common & pattern+) }\n\
|
| + | element attribute { (nameQName | nameClass), (common & pattern?) }\n\
|
| + | element group|interleave|choice|optional\n\
|
| + |zeroOrMore|oneOrMore|list|mixed { common & pattern+ }\n\
|
| + | element ref|parentRef { nameNCName, common }\n\
|
| + | element empty|notAllowed|text { common }\n\
|
| + | element data { type, param*, (common & exceptPattern?) }\n\
|
| + | element value { commonAttributes, type?, xsd:string }\n\
|
| + | element externalRef { href, common }\n\
|
| + | element grammar { common & grammarContent* }\n\
|
| +\n\
|
| +param = element param { commonAttributes, nameNCName, xsd:string }\n\
|
| +\n\
|
| +exceptPattern = element except { common & pattern+ }\n\
|
| +\n\
|
| +grammarContent =\n\
|
| + definition\n\
|
| + | element div { common & grammarContent* }\n\
|
| + | element include { href, (common & includeContent*) }\n\
|
| +\n\
|
| +includeContent =\n\
|
| + definition\n\
|
| + | element div { common & includeContent* }\n\
|
| +\n\
|
| +definition =\n\
|
| + element start { combine?, (common & pattern+) }\n\
|
| + | element define { nameNCName, combine?, (common & pattern+) }\n\
|
| +\n\
|
| +combine = attribute combine { \"choice\" | \"interleave\" }\n\
|
| +\n\
|
| +nameClass =\n\
|
| + element name { commonAttributes, xsd:QName }\n\
|
| + | element anyName { common & exceptNameClass? }\n\
|
| + | element nsName { common & exceptNameClass? }\n\
|
| + | element choice { common & nameClass+ }\n\
|
| +\n\
|
| +exceptNameClass = element except { common & nameClass+ }\n\
|
| +\n\
|
| +nameQName = attribute name { xsd:QName }\n\
|
| +nameNCName = attribute name { xsd:NCName }\n\
|
| +href = attribute href { xsd:anyURI }\n\
|
| +type = attribute type { xsd:NCName }\n\
|
| +\n\
|
| +common = commonAttributes, foreignElement*\n\
|
| +\n\
|
| +commonAttributes =\n\
|
| + attribute ns { xsd:string }?,\n\
|
| + attribute datatypeLibrary { xsd:anyURI }?,\n\
|
| + foreignAttribute*\n\
|
| +\n\
|
| +foreignElement = element * - rng:* { (anyAttribute | text | anyElement)* }\n\
|
| +foreignAttribute = attribute * - (rng:*|local:*) { text }\n\
|
| +anyElement = element * { (anyAttribute | text | anyElement)* }\n\
|
| +anyAttribute = attribute * { text }\n\
|
| +";
|
| +
|
| +int main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
|
| + xmlDocPtr res;
|
| +
|
| + res = xmlConvertCRNG(schemas, -1);
|
| + if (res != NULL) {
|
| + xmlDocFormatDump(stdout, res, 1);
|
| + xmlFreeDoc(res);
|
| + }
|
| + return(0);
|
| +}
|
| +#endif
|
| +#define bottom_rngparser
|
| +#include "elfgcchack.h"
|
|
|