version 1.17, 2019/04/07 14:49:26 |
version 1.23, 2019/04/08 14:37:31 |
|
|
struct parse { |
struct parse { |
const char *fname; /* Name of the input file. */ |
const char *fname; /* Name of the input file. */ |
struct ptree *tree; /* Complete parse result. */ |
struct ptree *tree; /* Complete parse result. */ |
|
struct pnode *doctype; |
struct pnode *cur; /* Current node in the tree. */ |
struct pnode *cur; /* Current node in the tree. */ |
enum nodeid ncur; /* Type of the current node. */ |
enum nodeid ncur; /* Type of the current node. */ |
int line; /* Line number in the input file. */ |
int line; /* Line number in the input file. */ |
|
|
int nline; /* Line number of next token. */ |
int nline; /* Line number of next token. */ |
int ncol; /* Column number of next token. */ |
int ncol; /* Column number of next token. */ |
int del; /* Levels of nested nodes being deleted. */ |
int del; /* Levels of nested nodes being deleted. */ |
int spc; /* Whitespace before the next element. */ |
int flags; |
int attr; /* The most recent attribute is valid. */ |
#define PFLAG_WARN (1 << 0) /* Print warning messages. */ |
int warn; |
#define PFLAG_SPC (1 << 1) /* Whitespace before the next element. */ |
|
#define PFLAG_ATTR (1 << 2) /* The most recent attribute is valid. */ |
|
#define PFLAG_EEND (1 << 3) /* This element is self-closing. */ |
}; |
}; |
|
|
struct element { |
struct element { |
Line 66 static const struct element elements[] = { |
|
Line 69 static const struct element elements[] = { |
|
{ "acronym", NODE_IGNORE }, |
{ "acronym", NODE_IGNORE }, |
{ "affiliation", NODE_AFFILIATION }, |
{ "affiliation", NODE_AFFILIATION }, |
{ "anchor", NODE_DELETE }, |
{ "anchor", NODE_DELETE }, |
|
{ "appendix", NODE_APPENDIX }, |
{ "application", NODE_APPLICATION }, |
{ "application", NODE_APPLICATION }, |
{ "arg", NODE_ARG }, |
{ "arg", NODE_ARG }, |
|
{ "article", NODE_SECTION }, |
{ "author", NODE_AUTHOR }, |
{ "author", NODE_AUTHOR }, |
{ "authorgroup", NODE_AUTHORGROUP }, |
{ "authorgroup", NODE_AUTHORGROUP }, |
{ "blockquote", NODE_BLOCKQUOTE }, |
{ "blockquote", NODE_BLOCKQUOTE }, |
{ "book", NODE_BOOK }, |
{ "book", NODE_SECTION }, |
{ "bookinfo", NODE_BOOKINFO }, |
{ "bookinfo", NODE_BOOKINFO }, |
{ "caution", NODE_CAUTION }, |
{ "caution", NODE_CAUTION }, |
{ "chapter", NODE_SECTION }, |
{ "chapter", NODE_SECTION }, |
Line 85 static const struct element elements[] = { |
|
Line 90 static const struct element elements[] = { |
|
{ "contrib", NODE_CONTRIB }, |
{ "contrib", NODE_CONTRIB }, |
{ "copyright", NODE_COPYRIGHT }, |
{ "copyright", NODE_COPYRIGHT }, |
{ "date", NODE_DATE }, |
{ "date", NODE_DATE }, |
|
{ "!doctype", NODE_DOCTYPE }, |
|
{ "!DOCTYPE", NODE_DOCTYPE }, |
{ "editor", NODE_EDITOR }, |
{ "editor", NODE_EDITOR }, |
{ "email", NODE_EMAIL }, |
{ "email", NODE_EMAIL }, |
{ "emphasis", NODE_EMPHASIS }, |
{ "emphasis", NODE_EMPHASIS }, |
|
{ "!ENTITY", NODE_ENTITY }, |
{ "entry", NODE_ENTRY }, |
{ "entry", NODE_ENTRY }, |
{ "envar", NODE_ENVAR }, |
{ "envar", NODE_ENVAR }, |
{ "errorname", NODE_ERRORNAME }, |
{ "errorname", NODE_ERRORNAME }, |
Line 101 static const struct element elements[] = { |
|
Line 109 static const struct element elements[] = { |
|
{ "funcsynopsis", NODE_FUNCSYNOPSIS }, |
{ "funcsynopsis", NODE_FUNCSYNOPSIS }, |
{ "funcsynopsisinfo", NODE_FUNCSYNOPSISINFO }, |
{ "funcsynopsisinfo", NODE_FUNCSYNOPSISINFO }, |
{ "function", NODE_FUNCTION }, |
{ "function", NODE_FUNCTION }, |
|
{ "glossary", NODE_VARIABLELIST }, |
|
{ "glossdef", NODE_IGNORE }, |
|
{ "glossdiv", NODE_IGNORE }, |
|
{ "glossentry", NODE_VARLISTENTRY }, |
|
{ "glosslist", NODE_VARIABLELIST }, |
{ "glossterm", NODE_GLOSSTERM }, |
{ "glossterm", NODE_GLOSSTERM }, |
{ "group", NODE_GROUP }, |
{ "group", NODE_GROUP }, |
{ "holder", NODE_HOLDER }, |
{ "holder", NODE_HOLDER }, |
Line 190 static const struct element elements[] = { |
|
Line 203 static const struct element elements[] = { |
|
{ "title", NODE_TITLE }, |
{ "title", NODE_TITLE }, |
{ "trademark", NODE_IGNORE }, |
{ "trademark", NODE_IGNORE }, |
{ "type", NODE_TYPE }, |
{ "type", NODE_TYPE }, |
{ "ulink", NODE_ULINK }, |
{ "ulink", NODE_LINK }, |
{ "userinput", NODE_LITERAL }, |
{ "userinput", NODE_LITERAL }, |
{ "variablelist", NODE_VARIABLELIST }, |
{ "variablelist", NODE_VARIABLELIST }, |
{ "varlistentry", NODE_VARLISTENTRY }, |
{ "varlistentry", NODE_VARLISTENTRY }, |
Line 258 static const struct entity entities[] = { |
|
Line 271 static const struct entity entities[] = { |
|
{ NULL, NULL } |
{ NULL, NULL } |
}; |
}; |
|
|
|
static size_t parse_string(struct parse *, char *, size_t, |
|
enum pstate *, int); |
|
|
|
|
static void |
static void |
error_msg(struct parse *p, const char *fmt, ...) |
error_msg(struct parse *p, const char *fmt, ...) |
{ |
{ |
Line 276 warn_msg(struct parse *p, const char *fmt, ...) |
|
Line 293 warn_msg(struct parse *p, const char *fmt, ...) |
|
{ |
{ |
va_list ap; |
va_list ap; |
|
|
if (p->warn == 0) |
if ((p->flags & PFLAG_WARN) == 0) |
return; |
return; |
|
|
fprintf(stderr, "%s:%d:%d: warning: ", p->fname, p->line, p->col); |
fprintf(stderr, "%s:%d:%d: warning: ", p->fname, p->line, p->col); |
Line 311 xml_char(struct parse *ps, const char *p, int sz) |
|
Line 328 xml_char(struct parse *ps, const char *p, int sz) |
|
exit(1); |
exit(1); |
} |
} |
dat->node = NODE_TEXT; |
dat->node = NODE_TEXT; |
dat->spc = ps->spc; |
dat->spc = (ps->flags & PFLAG_SPC) != 0; |
dat->parent = ps->cur; |
dat->parent = ps->cur; |
TAILQ_INIT(&dat->childq); |
TAILQ_INIT(&dat->childq); |
TAILQ_INIT(&dat->attrq); |
TAILQ_INIT(&dat->attrq); |
Line 326 xml_char(struct parse *ps, const char *p, int sz) |
|
Line 343 xml_char(struct parse *ps, const char *p, int sz) |
|
/* 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->spc) + sz; |
newsz = ps->cur->bsz + (ps->cur->bsz && (ps->flags & PFLAG_SPC)) + sz; |
ps->cur->b = realloc(ps->cur->b, newsz + 1); |
ps->cur->b = realloc(ps->cur->b, newsz + 1); |
if (ps->cur->b == NULL) { |
if (ps->cur->b == NULL) { |
perror(NULL); |
perror(NULL); |
exit(1); |
exit(1); |
} |
} |
if (ps->cur->bsz && ps->spc) |
if (ps->cur->bsz && (ps->flags & PFLAG_SPC)) |
ps->cur->b[ps->cur->bsz++] = ' '; |
ps->cur->b[ps->cur->bsz++] = ' '; |
memcpy(ps->cur->b + ps->cur->bsz, p, sz); |
memcpy(ps->cur->b + ps->cur->bsz, p, sz); |
ps->cur->b[ps->cur->bsz = newsz] = '\0'; |
ps->cur->b[ps->cur->bsz = newsz] = '\0'; |
ps->cur->real = ps->cur->b; |
ps->cur->real = ps->cur->b; |
ps->spc = 0; |
ps->flags &= ~PFLAG_SPC; |
} |
} |
|
|
/* |
/* |
Line 353 pnode_closetext(struct parse *p) |
|
Line 370 pnode_closetext(struct parse *p) |
|
p->cur = n->parent; |
p->cur = n->parent; |
while (n->bsz > 0 && isspace((unsigned char)n->b[n->bsz - 1])) { |
while (n->bsz > 0 && isspace((unsigned char)n->b[n->bsz - 1])) { |
n->b[--n->bsz] = '\0'; |
n->b[--n->bsz] = '\0'; |
p->spc = 1; |
p->flags |= PFLAG_SPC; |
} |
} |
} |
} |
|
|
Line 362 xml_entity(struct parse *p, const char *name) |
|
Line 379 xml_entity(struct parse *p, const char *name) |
|
{ |
{ |
const struct entity *entity; |
const struct entity *entity; |
struct pnode *dat; |
struct pnode *dat; |
|
const char *ccp; |
|
char *cp; |
|
enum pstate pstate; |
|
|
if (p->del > 0) |
if (p->del > 0) |
return; |
return; |
Line 381 xml_entity(struct parse *p, const char *name) |
|
Line 401 xml_entity(struct parse *p, const char *name) |
|
break; |
break; |
|
|
if (entity->roff == NULL) { |
if (entity->roff == NULL) { |
|
if (p->doctype != NULL) { |
|
TAILQ_FOREACH(dat, &p->doctype->childq, child) { |
|
if ((ccp = pnode_getattr_raw(dat, |
|
ATTRKEY_NAME, NULL)) == NULL || |
|
strcmp(ccp, name) != 0 || |
|
(ccp = pnode_getattr_raw(dat, |
|
ATTRKEY_DEFINITION, NULL)) == NULL) |
|
continue; |
|
if ((cp = strdup(ccp)) == NULL) { |
|
perror(NULL); |
|
exit(1); |
|
} |
|
pstate = PARSE_ELEM; |
|
parse_string(p, cp, strlen(cp), &pstate, 0); |
|
p->flags &= ~PFLAG_SPC; |
|
free(cp); |
|
return; |
|
} |
|
} |
error_msg(p, "unknown entity &%s;", name); |
error_msg(p, "unknown entity &%s;", name); |
return; |
return; |
} |
} |
Line 393 xml_entity(struct parse *p, const char *name) |
|
Line 432 xml_entity(struct parse *p, const char *name) |
|
} |
} |
dat->node = NODE_ESCAPE; |
dat->node = NODE_ESCAPE; |
dat->bsz = strlen(dat->b); |
dat->bsz = strlen(dat->b); |
dat->spc = p->spc; |
dat->spc = (p->flags & PFLAG_SPC) != 0; |
dat->parent = p->cur; |
dat->parent = p->cur; |
TAILQ_INIT(&dat->childq); |
TAILQ_INIT(&dat->childq); |
TAILQ_INIT(&dat->attrq); |
TAILQ_INIT(&dat->attrq); |
TAILQ_INSERT_TAIL(&p->cur->childq, dat, child); |
TAILQ_INSERT_TAIL(&p->cur->childq, dat, child); |
p->spc = 0; |
p->flags &= ~PFLAG_SPC; |
} |
} |
|
|
/* |
/* |
Line 410 xml_elem_start(struct parse *ps, const char *name) |
|
Line 449 xml_elem_start(struct parse *ps, const char *name) |
|
const struct element *elem; |
const struct element *elem; |
struct pnode *dat; |
struct pnode *dat; |
|
|
if (*name == '!' || *name == '?') |
|
return; |
|
|
|
/* |
/* |
* 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 (ps->del > 0) { |
ps->del++; |
if (*name != '!' && *name != '?') |
|
ps->del++; |
return; |
return; |
} |
} |
|
|
Line 428 xml_elem_start(struct parse *ps, const char *name) |
|
Line 465 xml_elem_start(struct parse *ps, const char *name) |
|
if (strcmp(elem->name, name) == 0) |
if (strcmp(elem->name, name) == 0) |
break; |
break; |
|
|
if (elem->name == NULL) |
if (elem->name == NULL) { |
|
if (*name == '!' || *name == '?') |
|
return; |
error_msg(ps, "unknown element <%s>", name); |
error_msg(ps, "unknown element <%s>", name); |
|
} |
|
|
ps->ncur = elem->node; |
ps->ncur = elem->node; |
|
|
Line 463 xml_elem_start(struct parse *ps, const char *name) |
|
Line 503 xml_elem_start(struct parse *ps, const char *name) |
|
*/ |
*/ |
|
|
switch (dat->node = elem->node) { |
switch (dat->node = elem->node) { |
|
case NODE_DOCTYPE: |
|
case NODE_ENTITY: |
|
case NODE_SBR: |
|
ps->flags |= PFLAG_EEND; |
|
/* FALLTHROUGH */ |
|
case NODE_APPENDIX: |
case NODE_AUTHORGROUP: |
case NODE_AUTHORGROUP: |
|
case NODE_BLOCKQUOTE: |
case NODE_BOOKINFO: |
case NODE_BOOKINFO: |
case NODE_CAUTION: |
case NODE_CAUTION: |
case NODE_EDITOR: |
case NODE_EDITOR: |
Line 484 xml_elem_start(struct parse *ps, const char *name) |
|
Line 531 xml_elem_start(struct parse *ps, const char *name) |
|
case NODE_REFNAMEDIV: |
case NODE_REFNAMEDIV: |
case NODE_REFSYNOPSISDIV: |
case NODE_REFSYNOPSISDIV: |
case NODE_ROW: |
case NODE_ROW: |
case NODE_SBR: |
|
case NODE_SCREEN: |
case NODE_SCREEN: |
case NODE_SECTION: |
case NODE_SECTION: |
case NODE_SYNOPSIS: |
case NODE_SYNOPSIS: |
Line 497 xml_elem_start(struct parse *ps, const char *name) |
|
Line 543 xml_elem_start(struct parse *ps, const char *name) |
|
dat->spc = 1; |
dat->spc = 1; |
break; |
break; |
default: |
default: |
dat->spc = ps->spc; |
dat->spc = (ps->flags & PFLAG_SPC) != 0; |
break; |
break; |
} |
} |
dat->parent = ps->cur; |
dat->parent = ps->cur; |
Line 508 xml_elem_start(struct parse *ps, const char *name) |
|
Line 554 xml_elem_start(struct parse *ps, const char *name) |
|
TAILQ_INSERT_TAIL(&ps->cur->childq, dat, child); |
TAILQ_INSERT_TAIL(&ps->cur->childq, dat, child); |
|
|
ps->cur = dat; |
ps->cur = dat; |
if (ps->tree->root == NULL) |
if (dat->node == NODE_DOCTYPE) { |
|
if (ps->doctype == NULL) |
|
ps->doctype = dat; |
|
else |
|
error_msg(ps, "duplicate doctype"); |
|
} else if (dat->parent == NULL && ps->tree->root == NULL) |
ps->tree->root = dat; |
ps->tree->root = dat; |
} |
} |
|
|
|
|
xml_attrkey(struct parse *ps, const char *name) |
xml_attrkey(struct parse *ps, const char *name) |
{ |
{ |
struct pattr *attr; |
struct pattr *attr; |
|
const char *value; |
enum attrkey key; |
enum attrkey key; |
|
|
if (ps->del > 0 || *name == '\0') |
if (ps->del > 0 || ps->ncur == NODE_IGNORE || *name == '\0') |
return; |
return; |
|
|
|
if ((ps->ncur == NODE_DOCTYPE || ps->ncur == NODE_ENTITY) && |
|
TAILQ_FIRST(&ps->cur->attrq) == NULL) { |
|
value = name; |
|
name = "NAME"; |
|
} else |
|
value = NULL; |
|
|
if ((key = attrkey_parse(name)) == ATTRKEY__MAX) { |
if ((key = attrkey_parse(name)) == ATTRKEY__MAX) { |
ps->attr = 0; |
ps->flags &= ~PFLAG_ATTR; |
return; |
return; |
} |
} |
if ((attr = calloc(1, sizeof(*attr))) == NULL) { |
if ((attr = calloc(1, sizeof(*attr))) == NULL) { |
Line 530 xml_attrkey(struct parse *ps, const char *name) |
|
Line 590 xml_attrkey(struct parse *ps, const char *name) |
|
} |
} |
attr->key = key; |
attr->key = key; |
attr->val = ATTRVAL__MAX; |
attr->val = ATTRVAL__MAX; |
attr->rawval = NULL; |
if (value == NULL) { |
|
attr->rawval = NULL; |
|
ps->flags |= PFLAG_ATTR; |
|
} else { |
|
if ((attr->rawval = strdup(value)) == NULL) { |
|
perror(NULL); |
|
exit(1); |
|
} |
|
ps->flags &= ~PFLAG_ATTR; |
|
} |
TAILQ_INSERT_TAIL(&ps->cur->attrq, attr, child); |
TAILQ_INSERT_TAIL(&ps->cur->attrq, attr, child); |
ps->attr = 1; |
if (ps->ncur == NODE_ENTITY && key == ATTRKEY_NAME) |
|
xml_attrkey(ps, "DEFINITION"); |
} |
} |
|
|
static void |
static void |
Line 540 xml_attrval(struct parse *ps, const char *name) |
|
Line 610 xml_attrval(struct parse *ps, const char *name) |
|
{ |
{ |
struct pattr *attr; |
struct pattr *attr; |
|
|
if (ps->del > 0 || ps->attr == 0) |
if (ps->del > 0 || ps->ncur == NODE_IGNORE || |
|
(ps->flags & PFLAG_ATTR) == 0) |
return; |
return; |
if ((attr = TAILQ_LAST(&ps->cur->attrq, pattrq)) == NULL) |
if ((attr = TAILQ_LAST(&ps->cur->attrq, pattrq)) == NULL) |
return; |
return; |
Line 589 xml_elem_end(struct parse *ps, const char *name) |
|
Line 660 xml_elem_end(struct parse *ps, const char *name) |
|
break; |
break; |
case NODE_IGNORE: |
case NODE_IGNORE: |
break; |
break; |
|
case NODE_DOCTYPE: |
|
ps->flags &= ~PFLAG_EEND; |
|
/* FALLTHROUGH */ |
default: |
default: |
if (ps->cur == NULL || node != ps->cur->node) { |
if (ps->cur == NULL || node != ps->cur->node) { |
warn_msg(ps, "element not open: </%s>", name); |
warn_msg(ps, "element not open: </%s>", name); |
Line 602 xml_elem_end(struct parse *ps, const char *name) |
|
Line 676 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) |
if (ps->cur->parent != NULL || node == NODE_DOCTYPE) { |
ps->tree->flags |= TREE_CLOSED; |
|
else |
|
ps->cur = ps->cur->parent; |
ps->cur = ps->cur->parent; |
ps->spc = 0; |
if (ps->cur != NULL) |
|
ps->ncur = ps->cur->node; |
|
} else |
|
ps->tree->flags |= TREE_CLOSED; |
|
ps->flags &= ~PFLAG_SPC; |
break; |
break; |
} |
} |
assert(ps->del == 0); |
assert(ps->del == 0); |
Line 624 parse_alloc(int warn) |
|
Line 700 parse_alloc(int warn) |
|
free(p); |
free(p); |
return NULL; |
return NULL; |
} |
} |
p->warn = warn; |
if (warn) |
|
p->flags |= PFLAG_WARN; |
|
else |
|
p->flags &= ~PFLAG_WARN; |
return p; |
return p; |
} |
} |
|
|
Line 700 parse_string(struct parse *p, char *b, size_t rlen, |
|
Line 779 parse_string(struct parse *p, char *b, size_t rlen, |
|
size_t pend; /* Offset of the end of the current word. */ |
size_t pend; /* Offset of the end of the current word. */ |
int elem_end; |
int elem_end; |
|
|
p->spc = 0; |
|
pend = 0; |
pend = 0; |
for (;;) { |
for (;;) { |
|
|
Line 713 parse_string(struct parse *p, char *b, size_t rlen, |
|
Line 791 parse_string(struct parse *p, char *b, size_t rlen, |
|
if ((poff = pend) == rlen) |
if ((poff = pend) == rlen) |
break; |
break; |
if (isspace((unsigned char)b[pend])) { |
if (isspace((unsigned char)b[pend])) { |
p->spc = 1; |
p->flags |= PFLAG_SPC; |
increment(p, b, &pend, refill); |
increment(p, b, &pend, refill); |
continue; |
continue; |
} |
} |
Line 754 parse_string(struct parse *p, char *b, size_t rlen, |
|
Line 832 parse_string(struct parse *p, char *b, size_t rlen, |
|
b[pend - 1] = '\0'; |
b[pend - 1] = '\0'; |
elem_end = 1; |
elem_end = 1; |
} |
} |
|
if (p->flags & PFLAG_EEND) |
|
elem_end = 1; |
} |
} |
b[pend] = '\0'; |
b[pend] = '\0'; |
if (pend < rlen) |
if (pend < rlen) |
Line 765 parse_string(struct parse *p, char *b, size_t rlen, |
|
Line 845 parse_string(struct parse *p, char *b, size_t rlen, |
|
/* Look for an attribute name. */ |
/* Look for an attribute name. */ |
|
|
} else if (*pstate == PARSE_TAG) { |
} else if (*pstate == PARSE_TAG) { |
|
switch (p->ncur) { |
|
case NODE_DOCTYPE: |
|
if (b[pend] == '[') { |
|
*pstate = PARSE_ELEM; |
|
increment(p, b, &pend, refill); |
|
continue; |
|
} |
|
/* FALLTHROUGH */ |
|
case NODE_ENTITY: |
|
if (b[pend] == '"' || b[pend] == '\'') { |
|
*pstate = PARSE_ARG; |
|
continue; |
|
} |
|
break; |
|
default: |
|
break; |
|
} |
if (advance(p, b, rlen, &pend, " =>", refill)) |
if (advance(p, b, rlen, &pend, " =>", refill)) |
break; |
break; |
elem_end = 0; |
elem_end = 0; |
Line 775 parse_string(struct parse *p, char *b, size_t rlen, |
|
Line 872 parse_string(struct parse *p, char *b, size_t rlen, |
|
b[pend - 1] = '\0'; |
b[pend - 1] = '\0'; |
elem_end = 1; |
elem_end = 1; |
} |
} |
|
if (p->flags & PFLAG_EEND) |
|
elem_end = 1; |
break; |
break; |
case '=': |
case '=': |
*pstate = PARSE_ARG; |
*pstate = PARSE_ARG; |
Line 823 parse_string(struct parse *p, char *b, size_t rlen, |
|
Line 922 parse_string(struct parse *p, char *b, size_t rlen, |
|
if (b[++poff] == '/') { |
if (b[++poff] == '/') { |
elem_end = 1; |
elem_end = 1; |
poff++; |
poff++; |
} else |
} else { |
xml_elem_start(p, b + poff); |
xml_elem_start(p, b + poff); |
|
if (*pstate == PARSE_ELEM && |
|
p->flags & PFLAG_EEND) |
|
elem_end = 1; |
|
} |
if (elem_end) |
if (elem_end) |
xml_elem_end(p, b + poff); |
xml_elem_end(p, b + poff); |
|
|
|
/* Close a doctype. */ |
|
|
|
} else if (p->ncur == NODE_DOCTYPE && b[poff] == ']') { |
|
*pstate = PARSE_TAG; |
|
increment(p, b, &pend, refill); |
|
|
/* Process an entity. */ |
/* Process an entity. */ |
|
|
} else if (b[poff] == '&') { |
} else if (b[poff] == '&') { |
Line 890 parse_file(struct parse *p, int fd, const char *fname) |
|
Line 999 parse_file(struct parse *p, int fd, const char *fname) |
|
pnode_closetext(p); |
pnode_closetext(p); |
if ((p->tree->flags & TREE_CLOSED) == 0) |
if ((p->tree->flags & TREE_CLOSED) == 0) |
warn_msg(p, "document not closed"); |
warn_msg(p, "document not closed"); |
|
pnode_unlink(p->doctype); |
return p->tree; |
return p->tree; |
} |
} |