version 1.29, 2019/04/09 15:23:51 |
version 1.31, 2019/04/10 14:34:08 |
Line 322 warn_msg(struct parse *p, const char *fmt, ...) |
|
Line 322 warn_msg(struct parse *p, const char *fmt, ...) |
|
* Otherwise, create a new one as a child of the current node. |
* Otherwise, create a new one as a child of the current node. |
*/ |
*/ |
static void |
static void |
xml_char(struct parse *ps, const char *p, int sz) |
xml_char(struct parse *p, const char *word, int sz) |
{ |
{ |
struct pnode *dat; |
struct pnode *n; |
size_t newsz; |
size_t newsz; |
|
|
if (ps->del > 0) |
if (p->del > 0) |
return; |
return; |
|
|
if (ps->cur == NULL) { |
if (p->cur == NULL) { |
error_msg(ps, "discarding text before document: %.*s", sz, p); |
error_msg(p, "discarding text before document: %.*s", sz, word); |
return; |
return; |
} |
} |
|
|
if (ps->cur->node != NODE_TEXT) { |
if (p->cur->node != NODE_TEXT) { |
if ((dat = calloc(1, sizeof(*dat))) == NULL) |
if ((n = calloc(1, sizeof(*n))) == NULL) |
fatal(ps); |
fatal(p); |
dat->node = NODE_TEXT; |
n->node = NODE_TEXT; |
dat->spc = (ps->flags & PFLAG_SPC) != 0; |
n->spc = (p->flags & PFLAG_SPC) != 0; |
dat->parent = ps->cur; |
n->parent = p->cur; |
TAILQ_INIT(&dat->childq); |
TAILQ_INIT(&n->childq); |
TAILQ_INIT(&dat->attrq); |
TAILQ_INIT(&n->attrq); |
TAILQ_INSERT_TAIL(&ps->cur->childq, dat, child); |
TAILQ_INSERT_TAIL(&p->cur->childq, n, child); |
ps->cur = dat; |
p->cur = n; |
} |
} |
|
|
if (ps->tree->flags & TREE_CLOSED && |
if (p->tree->flags & TREE_CLOSED && |
ps->cur->parent == ps->tree->root) |
p->cur->parent == p->tree->root) |
warn_msg(ps, "text after end of document: %.*s", sz, p); |
warn_msg(p, "text after end of document: %.*s", sz, word); |
|
|
/* Append to the current text node. */ |
/* Append to the current text node. */ |
|
|
assert(sz >= 0); |
assert(sz >= 0); |
newsz = ps->cur->bsz + (ps->cur->bsz && (ps->flags & PFLAG_SPC)) + sz; |
newsz = p->cur->bsz + (p->cur->bsz && (p->flags & PFLAG_SPC)) + sz; |
if ((ps->cur->b = realloc(ps->cur->b, newsz + 1)) == NULL) |
if ((p->cur->b = realloc(p->cur->b, newsz + 1)) == NULL) |
fatal(ps); |
fatal(p); |
if (ps->cur->bsz && (ps->flags & PFLAG_SPC)) |
if (p->cur->bsz && (p->flags & PFLAG_SPC)) |
ps->cur->b[ps->cur->bsz++] = ' '; |
p->cur->b[p->cur->bsz++] = ' '; |
memcpy(ps->cur->b + ps->cur->bsz, p, sz); |
memcpy(p->cur->b + p->cur->bsz, word, sz); |
ps->cur->b[ps->cur->bsz = newsz] = '\0'; |
p->cur->b[p->cur->bsz = newsz] = '\0'; |
ps->cur->real = ps->cur->b; |
p->cur->real = p->cur->b; |
ps->flags &= ~PFLAG_SPC; |
p->flags &= ~PFLAG_SPC; |
} |
} |
|
|
/* |
/* |
|
|
xml_entity(struct parse *p, const char *name) |
xml_entity(struct parse *p, const char *name) |
{ |
{ |
const struct entity *entity; |
const struct entity *entity; |
struct pnode *dat; |
struct pnode *n; |
const char *ccp; |
const char *ccp; |
char *cp; |
char *cp; |
enum pstate pstate; |
enum pstate pstate; |
Line 410 xml_entity(struct parse *p, const char *name) |
|
Line 410 xml_entity(struct parse *p, const char *name) |
|
|
|
if (entity->roff == NULL) { |
if (entity->roff == NULL) { |
if (p->doctype != NULL) { |
if (p->doctype != NULL) { |
TAILQ_FOREACH(dat, &p->doctype->childq, child) { |
TAILQ_FOREACH(n, &p->doctype->childq, child) { |
if ((ccp = pnode_getattr_raw(dat, |
if ((ccp = pnode_getattr_raw(n, |
ATTRKEY_NAME, NULL)) == NULL || |
ATTRKEY_NAME, NULL)) == NULL || |
strcmp(ccp, name) != 0) |
strcmp(ccp, name) != 0) |
continue; |
continue; |
if ((ccp = pnode_getattr_raw(dat, |
if ((ccp = pnode_getattr_raw(n, |
ATTRKEY_SYSTEM, NULL)) != NULL) { |
ATTRKEY_SYSTEM, NULL)) != NULL) { |
parse_file(p, -1, ccp); |
parse_file(p, -1, ccp); |
p->flags &= ~PFLAG_SPC; |
p->flags &= ~PFLAG_SPC; |
return; |
return; |
} |
} |
if ((ccp = pnode_getattr_raw(dat, |
if ((ccp = pnode_getattr_raw(n, |
ATTRKEY_DEFINITION, NULL)) == NULL) |
ATTRKEY_DEFINITION, NULL)) == NULL) |
continue; |
continue; |
if ((cp = strdup(ccp)) == NULL) |
if ((cp = strdup(ccp)) == NULL) |
Line 438 xml_entity(struct parse *p, const char *name) |
|
Line 438 xml_entity(struct parse *p, const char *name) |
|
} |
} |
|
|
/* Create, append, and close out an entity node. */ |
/* Create, append, and close out an entity node. */ |
if ((dat = calloc(1, sizeof(*dat))) == NULL || |
if ((n = calloc(1, sizeof(*n))) == NULL || |
(dat->b = dat->real = strdup(entity->roff)) == NULL) |
(n->b = n->real = strdup(entity->roff)) == NULL) |
fatal(p); |
fatal(p); |
dat->node = NODE_ESCAPE; |
n->node = NODE_ESCAPE; |
dat->bsz = strlen(dat->b); |
n->bsz = strlen(n->b); |
dat->spc = (p->flags & PFLAG_SPC) != 0; |
n->spc = (p->flags & PFLAG_SPC) != 0; |
dat->parent = p->cur; |
n->parent = p->cur; |
TAILQ_INIT(&dat->childq); |
TAILQ_INIT(&n->childq); |
TAILQ_INIT(&dat->attrq); |
TAILQ_INIT(&n->attrq); |
TAILQ_INSERT_TAIL(&p->cur->childq, dat, child); |
TAILQ_INSERT_TAIL(&p->cur->childq, n, child); |
p->flags &= ~PFLAG_SPC; |
p->flags &= ~PFLAG_SPC; |
} |
} |
|
|
Line 455 xml_entity(struct parse *p, const char *name) |
|
Line 455 xml_entity(struct parse *p, const char *name) |
|
* Begin an element. |
* Begin an element. |
*/ |
*/ |
static void |
static void |
xml_elem_start(struct parse *ps, const char *name) |
xml_elem_start(struct parse *p, const char *name) |
{ |
{ |
const struct element *elem; |
const struct element *elem; |
struct pnode *dat; |
struct pnode *n; |
|
|
/* |
/* |
* An ancestor is excluded from the tree; |
* An ancestor is excluded from the tree; |
* keep track of the number of levels excluded. |
* keep track of the number of levels excluded. |
*/ |
*/ |
if (ps->del > 0) { |
if (p->del > 0) { |
if (*name != '!' && *name != '?') |
if (*name != '!' && *name != '?') |
ps->del++; |
p->del++; |
return; |
return; |
} |
} |
|
|
pnode_closetext(ps); |
pnode_closetext(p); |
|
|
for (elem = elements; elem->name != NULL; elem++) |
for (elem = elements; elem->name != NULL; elem++) |
if (strcmp(elem->name, name) == 0) |
if (strcmp(elem->name, name) == 0) |
Line 479 xml_elem_start(struct parse *ps, const char *name) |
|
Line 479 xml_elem_start(struct parse *ps, const char *name) |
|
if (elem->name == NULL) { |
if (elem->name == NULL) { |
if (*name == '!' || *name == '?') |
if (*name == '!' || *name == '?') |
return; |
return; |
error_msg(ps, "unknown element <%s>", name); |
error_msg(p, "unknown element <%s>", name); |
} |
} |
|
|
ps->ncur = elem->node; |
p->ncur = elem->node; |
|
|
switch (ps->ncur) { |
switch (p->ncur) { |
case NODE_DELETE_WARN: |
case NODE_DELETE_WARN: |
warn_msg(ps, "skipping element <%s>", name); |
warn_msg(p, "skipping element <%s>", name); |
/* FALLTHROUGH */ |
/* FALLTHROUGH */ |
case NODE_DELETE: |
case NODE_DELETE: |
ps->del = 1; |
p->del = 1; |
/* FALLTHROUGH */ |
/* FALLTHROUGH */ |
case NODE_IGNORE: |
case NODE_IGNORE: |
return; |
return; |
case NODE_INLINEEQUATION: |
case NODE_INLINEEQUATION: |
ps->tree->flags |= TREE_EQN; |
p->tree->flags |= TREE_EQN; |
break; |
break; |
default: |
default: |
break; |
break; |
} |
} |
|
|
if (ps->tree->flags & TREE_CLOSED && ps->cur->parent == NULL) |
if (p->tree->flags & TREE_CLOSED && p->cur->parent == NULL) |
warn_msg(ps, "element after end of document: <%s>", name); |
warn_msg(p, "element after end of document: <%s>", name); |
|
|
if ((dat = calloc(1, sizeof(*dat))) == NULL) |
if ((n = calloc(1, sizeof(*n))) == NULL) |
fatal(ps); |
fatal(p); |
|
|
/* |
/* |
* Nodes that begin a new macro or request line or start by |
* Nodes that begin a new macro or request line or start by |
* printing text always want whitespace before themselves. |
* printing text always want whitespace before themselves. |
*/ |
*/ |
|
|
switch (dat->node = elem->node) { |
switch (n->node = elem->node) { |
case NODE_DOCTYPE: |
case NODE_DOCTYPE: |
case NODE_ENTITY: |
case NODE_ENTITY: |
case NODE_SBR: |
case NODE_SBR: |
ps->flags |= PFLAG_EEND; |
p->flags |= PFLAG_EEND; |
/* FALLTHROUGH */ |
/* FALLTHROUGH */ |
case NODE_APPENDIX: |
case NODE_APPENDIX: |
case NODE_AUTHORGROUP: |
case NODE_AUTHORGROUP: |
Line 549 xml_elem_start(struct parse *ps, const char *name) |
|
Line 549 xml_elem_start(struct parse *ps, const char *name) |
|
case NODE_VARIABLELIST: |
case NODE_VARIABLELIST: |
case NODE_VARLISTENTRY: |
case NODE_VARLISTENTRY: |
case NODE_WARNING: |
case NODE_WARNING: |
dat->spc = 1; |
n->spc = 1; |
break; |
break; |
default: |
default: |
dat->spc = (ps->flags & PFLAG_SPC) != 0; |
n->spc = (p->flags & PFLAG_SPC) != 0; |
break; |
break; |
} |
} |
dat->parent = ps->cur; |
n->parent = p->cur; |
TAILQ_INIT(&dat->childq); |
TAILQ_INIT(&n->childq); |
TAILQ_INIT(&dat->attrq); |
TAILQ_INIT(&n->attrq); |
|
|
if (ps->cur != NULL) |
if (p->cur != NULL) |
TAILQ_INSERT_TAIL(&ps->cur->childq, dat, child); |
TAILQ_INSERT_TAIL(&p->cur->childq, n, child); |
|
|
ps->cur = dat; |
p->cur = n; |
if (dat->node == NODE_DOCTYPE) { |
if (n->node == NODE_DOCTYPE) { |
if (ps->doctype == NULL) |
if (p->doctype == NULL) |
ps->doctype = dat; |
p->doctype = n; |
else |
else |
error_msg(ps, "duplicate doctype"); |
error_msg(p, "duplicate doctype"); |
} else if (dat->parent == NULL && ps->tree->root == NULL) |
} else if (n->parent == NULL && p->tree->root == NULL) |
ps->tree->root = dat; |
p->tree->root = n; |
} |
} |
|
|
static void |
static void |
xml_attrkey(struct parse *ps, const char *name) |
xml_attrkey(struct parse *p, const char *name) |
{ |
{ |
struct pattr *attr; |
struct pattr *a; |
const char *value; |
const char *value; |
enum attrkey key; |
enum attrkey key; |
|
|
if (ps->del > 0 || ps->ncur == NODE_IGNORE || *name == '\0') |
if (p->del > 0 || p->ncur == NODE_IGNORE || *name == '\0') |
return; |
return; |
|
|
if ((ps->ncur == NODE_DOCTYPE || ps->ncur == NODE_ENTITY) && |
if ((p->ncur == NODE_DOCTYPE || p->ncur == NODE_ENTITY) && |
TAILQ_FIRST(&ps->cur->attrq) == NULL) { |
TAILQ_FIRST(&p->cur->attrq) == NULL) { |
value = name; |
value = name; |
name = "NAME"; |
name = "NAME"; |
} else |
} else |
value = NULL; |
value = NULL; |
|
|
if ((key = attrkey_parse(name)) == ATTRKEY__MAX) { |
if ((key = attrkey_parse(name)) == ATTRKEY__MAX) { |
ps->flags &= ~PFLAG_ATTR; |
p->flags &= ~PFLAG_ATTR; |
return; |
return; |
} |
} |
if ((attr = calloc(1, sizeof(*attr))) == NULL) |
if ((a = calloc(1, sizeof(*a))) == NULL) |
fatal(ps); |
fatal(p); |
|
|
attr->key = key; |
a->key = key; |
attr->val = ATTRVAL__MAX; |
a->val = ATTRVAL__MAX; |
if (value == NULL) { |
if (value == NULL) { |
attr->rawval = NULL; |
a->rawval = NULL; |
ps->flags |= PFLAG_ATTR; |
p->flags |= PFLAG_ATTR; |
} else { |
} else { |
if ((attr->rawval = strdup(value)) == NULL) |
if ((a->rawval = strdup(value)) == NULL) |
fatal(ps); |
fatal(p); |
ps->flags &= ~PFLAG_ATTR; |
p->flags &= ~PFLAG_ATTR; |
} |
} |
TAILQ_INSERT_TAIL(&ps->cur->attrq, attr, child); |
TAILQ_INSERT_TAIL(&p->cur->attrq, a, child); |
if (ps->ncur == NODE_ENTITY && key == ATTRKEY_NAME) |
if (p->ncur == NODE_ENTITY && key == ATTRKEY_NAME) |
xml_attrkey(ps, "DEFINITION"); |
xml_attrkey(p, "DEFINITION"); |
} |
} |
|
|
static void |
static void |
xml_attrval(struct parse *ps, const char *name) |
xml_attrval(struct parse *p, const char *name) |
{ |
{ |
struct pattr *attr; |
struct pattr *a; |
|
|
if (ps->del > 0 || ps->ncur == NODE_IGNORE || |
if (p->del > 0 || p->ncur == NODE_IGNORE || |
(ps->flags & PFLAG_ATTR) == 0) |
(p->flags & PFLAG_ATTR) == 0) |
return; |
return; |
if ((attr = TAILQ_LAST(&ps->cur->attrq, pattrq)) == NULL) |
if ((a = TAILQ_LAST(&p->cur->attrq, pattrq)) == NULL) |
return; |
return; |
if ((attr->val = attrval_parse(name)) == ATTRVAL__MAX && |
if ((a->val = attrval_parse(name)) == ATTRVAL__MAX && |
(attr->rawval = strdup(name)) == NULL) |
(a->rawval = strdup(name)) == NULL) |
fatal(ps); |
fatal(p); |
ps->flags &= ~PFLAG_ATTR; |
p->flags &= ~PFLAG_ATTR; |
} |
} |
|
|
/* |
/* |
Line 632 xml_attrval(struct parse *ps, const char *name) |
|
Line 632 xml_attrval(struct parse *ps, const char *name) |
|
* If we're at a text node, roll that one up first. |
* If we're at a text node, roll that one up first. |
*/ |
*/ |
static void |
static void |
xml_elem_end(struct parse *ps, const char *name) |
xml_elem_end(struct parse *p, const char *name) |
{ |
{ |
const struct element *elem; |
const struct element *elem; |
struct pnode *n; |
struct pnode *n; |
Line 643 xml_elem_end(struct parse *ps, const char *name) |
|
Line 643 xml_elem_end(struct parse *ps, const char *name) |
|
* An ancestor is excluded from the tree; |
* An ancestor is excluded from the tree; |
* keep track of the number of levels excluded. |
* keep track of the number of levels excluded. |
*/ |
*/ |
if (ps->del > 1) { |
if (p->del > 1) { |
ps->del--; |
p->del--; |
return; |
return; |
} |
} |
|
|
if (ps->del == 0) |
if (p->del == 0) |
pnode_closetext(ps); |
pnode_closetext(p); |
|
|
if (name != NULL) { |
if (name != NULL) { |
for (elem = elements; elem->name != NULL; elem++) |
for (elem = elements; elem->name != NULL; elem++) |
Line 657 xml_elem_end(struct parse *ps, const char *name) |
|
Line 657 xml_elem_end(struct parse *ps, const char *name) |
|
break; |
break; |
node = elem->node; |
node = elem->node; |
} else |
} else |
node = ps->ncur; |
node = p->ncur; |
|
|
switch (node) { |
switch (node) { |
case NODE_DELETE_WARN: |
case NODE_DELETE_WARN: |
case NODE_DELETE: |
case NODE_DELETE: |
if (ps->del > 0) |
if (p->del > 0) |
ps->del--; |
p->del--; |
break; |
break; |
case NODE_IGNORE: |
case NODE_IGNORE: |
break; |
break; |
case NODE_INCLUDE: |
case NODE_INCLUDE: |
n = ps->cur; |
n = p->cur; |
ps->cur = ps->cur->parent; |
p->cur = p->cur->parent; |
cp = pnode_getattr_raw(n, ATTRKEY_HREF, NULL); |
cp = pnode_getattr_raw(n, ATTRKEY_HREF, NULL); |
if (cp == NULL) |
if (cp == NULL) |
error_msg(ps, "<xi:include> element " |
error_msg(p, "<xi:include> element " |
"without href attribute"); |
"without href attribute"); |
else |
else |
parse_file(ps, -1, cp); |
parse_file(p, -1, cp); |
pnode_unlink(n); |
pnode_unlink(n); |
ps->flags &= ~PFLAG_SPC; |
p->flags &= ~PFLAG_SPC; |
break; |
break; |
case NODE_DOCTYPE: |
case NODE_DOCTYPE: |
ps->flags &= ~PFLAG_EEND; |
p->flags &= ~PFLAG_EEND; |
/* FALLTHROUGH */ |
/* FALLTHROUGH */ |
default: |
default: |
if (ps->cur == NULL || node != ps->cur->node) { |
if (p->cur == NULL || node != p->cur->node) { |
warn_msg(ps, "element not open: </%s>", name); |
warn_msg(p, "element not open: </%s>", name); |
break; |
break; |
} |
} |
|
|
Line 695 xml_elem_end(struct parse *ps, const char *name) |
|
Line 695 xml_elem_end(struct parse *ps, const char *name) |
|
* obviously better than discarding it or crashing. |
* obviously better than discarding it or crashing. |
*/ |
*/ |
|
|
if (ps->cur->parent != NULL || node == NODE_DOCTYPE) { |
if (p->cur->parent != NULL || node == NODE_DOCTYPE) { |
ps->cur = ps->cur->parent; |
p->cur = p->cur->parent; |
if (ps->cur != NULL) |
if (p->cur != NULL) |
ps->ncur = ps->cur->node; |
p->ncur = p->cur->node; |
} else |
} else |
ps->tree->flags |= TREE_CLOSED; |
p->tree->flags |= TREE_CLOSED; |
ps->flags &= ~PFLAG_SPC; |
p->flags &= ~PFLAG_SPC; |
break; |
break; |
} |
} |
assert(ps->del == 0); |
assert(p->del == 0); |
} |
} |
|
|
struct parse * |
struct parse * |