blob: 7731d4dd8e79e74bcd2437c63a08b34db1c31fcc [file] [log] [blame]
/**
* 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;
/*
* dictionary 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"