static int rew_last(struct mdoc *mdoc, const struct mdoc_node *to) { struct mdoc_node *n, *np; assert(to); mdoc->next = MDOC_NEXT_SIBLING; /* LINTED */ while (mdoc->last != to) { /* * Save the parent here, because we may delete the * m->last node in the post-validation phase and reset * it to m->last->parent, causing a step in the closing * out to be lost. */ np = mdoc->last->parent; if ( ! mdoc_valid_post(mdoc)) return(0); n = mdoc->last; mdoc->last = np; assert(mdoc->last); mdoc->last->last = n; } return(mdoc_valid_post(mdoc)); }
static int rew_last(struct mdoc *mdoc, const struct mdoc_node *to) { assert(to); mdoc->next = MDOC_NEXT_SIBLING; /* LINTED */ while (mdoc->last != to) { if ( ! mdoc_valid_post(mdoc)) return(0); if ( ! mdoc_action_post(mdoc)) return(0); mdoc->last = mdoc->last->parent; assert(mdoc->last); } if ( ! mdoc_valid_post(mdoc)) return(0); return(mdoc_action_post(mdoc)); }
static int node_append(struct mdoc *mdoc, struct mdoc_node *p) { assert(mdoc->last); assert(mdoc->first); assert(MDOC_ROOT != p->type); switch (mdoc->next) { case (MDOC_NEXT_SIBLING): mdoc->last->next = p; p->prev = mdoc->last; p->parent = mdoc->last->parent; break; case (MDOC_NEXT_CHILD): mdoc->last->child = p; p->parent = mdoc->last; break; default: abort(); /* NOTREACHED */ } p->parent->nchild++; /* * Copy over the normalised-data pointer of our parent. Not * everybody has one, but copying a null pointer is fine. */ switch (p->type) { case (MDOC_BODY): /* FALLTHROUGH */ case (MDOC_TAIL): /* FALLTHROUGH */ case (MDOC_HEAD): p->norm = p->parent->norm; break; default: break; } if ( ! mdoc_valid_pre(mdoc, p)) return(0); switch (p->type) { case (MDOC_HEAD): assert(MDOC_BLOCK == p->parent->type); p->parent->head = p; break; case (MDOC_TAIL): assert(MDOC_BLOCK == p->parent->type); p->parent->tail = p; break; case (MDOC_BODY): if (p->end) break; assert(MDOC_BLOCK == p->parent->type); p->parent->body = p; break; default: break; } mdoc->last = p; switch (p->type) { case (MDOC_TBL): /* FALLTHROUGH */ case (MDOC_TEXT): if ( ! mdoc_valid_post(mdoc)) return(0); break; default: break; } return(1); }
/* * Parse free-form text, that is, a line that does not begin with the * control character. */ static int mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs) { char *c, *ws, *end; struct mdoc_node *n; assert(mdoc->last); n = mdoc->last; /* * Divert directly to list processing if we're encountering a * columnar MDOC_BLOCK with or without a prior MDOC_BLOCK entry * (a MDOC_BODY means it's already open, in which case we should * process within its context in the normal way). */ if (MDOC_Bl == n->tok && MDOC_BODY == n->type && LIST_column == n->norm->Bl.type) { /* `Bl' is open without any children. */ mdoc->flags |= MDOC_FREECOL; mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf); return(1); } if (MDOC_It == n->tok && MDOC_BLOCK == n->type && NULL != n->parent && MDOC_Bl == n->parent->tok && LIST_column == n->parent->norm->Bl.type) { /* `Bl' has block-level `It' children. */ mdoc->flags |= MDOC_FREECOL; mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf); return(1); } /* * Search for the beginning of unescaped trailing whitespace (ws) * and for the first character not to be output (end). */ /* FIXME: replace with strcspn(). */ ws = NULL; for (c = end = buf + offs; *c; c++) { switch (*c) { case ' ': if (NULL == ws) ws = c; continue; case '\t': /* * Always warn about trailing tabs, * even outside literal context, * where they should be put on the next line. */ if (NULL == ws) ws = c; /* * Strip trailing tabs in literal context only; * outside, they affect the next line. */ if (MDOC_LITERAL & mdoc->flags) continue; break; case '\\': /* Skip the escaped character, too, if any. */ if (c[1]) c++; /* FALLTHROUGH */ default: ws = NULL; break; } end = c + 1; } *end = '\0'; if (ws) mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse, line, (int)(ws-buf), NULL); if (buf[offs] == '\0' && ! (mdoc->flags & MDOC_LITERAL)) { mandoc_msg(MANDOCERR_FI_BLANK, mdoc->parse, line, (int)(c - buf), NULL); /* * Insert a `sp' in the case of a blank line. Technically, * blank lines aren't allowed, but enough manuals assume this * behaviour that we want to work around it. */ mdoc_elem_alloc(mdoc, line, offs, MDOC_sp, NULL); mdoc->next = MDOC_NEXT_SIBLING; mdoc_valid_post(mdoc); return(1); } mdoc_word_alloc(mdoc, line, offs, buf+offs); if (mdoc->flags & MDOC_LITERAL) return(1); /* * End-of-sentence check. If the last character is an unescaped * EOS character, then flag the node as being the end of a * sentence. The front-end will know how to interpret this. */ assert(buf < end); if (mandoc_eos(buf+offs, (size_t)(end-buf-offs))) mdoc->last->flags |= MDOC_EOS; return(1); }