/* ARGSUSED */ int blk_imp(MACRO_PROT_ARGS) { int la; char *p; struct man_node *n; /* Close out prior scopes. */ if ( ! rew_scope(MAN_BODY, man, tok)) return(0); if ( ! rew_scope(MAN_BLOCK, man, tok)) return(0); /* Allocate new block & head scope. */ if ( ! man_block_alloc(man, line, ppos, tok)) return(0); if ( ! man_head_alloc(man, line, ppos, tok)) return(0); n = man->last; /* Add line arguments. */ for (;;) { la = *pos; if ( ! man_args(man, line, pos, buf, &p)) break; if ( ! man_word_alloc(man, line, la, p)) return(0); } /* Close out head and open body (unless MAN_SCOPE). */ if (MAN_SCOPED & man_macros[tok].flags) { /* If we're forcing scope (`TP'), keep it open. */ if (MAN_FSCOPED & man_macros[tok].flags) { man->flags |= MAN_BLINE; return(1); } else if (n == man->last) { man->flags |= MAN_BLINE; return(1); } } if ( ! rew_scope(MAN_HEAD, man, tok)) return(0); return(man_body_alloc(man, line, ppos, tok)); }
/* ARGSUSED */ int blk_exp(MACRO_PROT_ARGS) { struct man_node *n; int la; char *p; /* Close out prior implicit scopes. */ if ( ! rew_scope(MAN_BLOCK, man, tok)) return(0); if ( ! man_block_alloc(man, line, ppos, tok)) return(0); if ( ! man_head_alloc(man, line, ppos, tok)) return(0); for (;;) { la = *pos; if ( ! man_args(man, line, pos, buf, &p)) break; if ( ! man_word_alloc(man, line, la, p)) return(0); } assert(man); assert(tok != MAN_MAX); for (n = man->last; n; n = n->parent) { if (n->tok != tok) continue; assert(MAN_HEAD == n->type); man_unscope(man, n, MANDOCERR_MAX); break; } return(man_body_alloc(man, line, ppos, tok)); }
static int man_descope(struct man *man, int line, int offs) { /* * Co-ordinate what happens with having a next-line scope open: * first close out the element scope (if applicable), then close * out the block scope (also if applicable). */ if (MAN_ELINE & man->flags) { man->flags &= ~MAN_ELINE; if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX)) return(0); } if ( ! (MAN_BLINE & man->flags)) return(1); man->flags &= ~MAN_BLINE; if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX)) return(0); return(man_body_alloc(man, line, offs, man->last->tok)); }
/* ARGSUSED */ int blk_exp(MACRO_PROT_ARGS) { int la; char *p; /* * Close out prior scopes. "Regular" explicit macros cannot be * nested, but we allow roff macros to be placed just about * anywhere. */ if ( ! rew_scope(MAN_BODY, m, tok)) return(0); if ( ! rew_scope(MAN_BLOCK, m, tok)) return(0); if ( ! man_block_alloc(m, line, ppos, tok)) return(0); if ( ! man_head_alloc(m, line, ppos, tok)) return(0); for (;;) { la = *pos; if ( ! man_args(m, line, pos, buf, &p)) break; if ( ! man_word_alloc(m, line, la, p)) return(0); } assert(m); assert(tok != MAN_MAX); if ( ! rew_scope(MAN_HEAD, m, tok)) return(0); return(man_body_alloc(m, line, ppos, tok)); }
static int man_pmacro(struct man *man, int ln, char *buf, int offs) { int i, ppos; enum mant tok; char mac[5]; struct man_node *n; if ('"' == buf[offs]) { man_pmsg(man, ln, offs, MANDOCERR_BADCOMMENT); return(1); } else if ('\0' == buf[offs]) return(1); ppos = offs; /* * Copy the first word into a nil-terminated buffer. * Stop copying when a tab, space, or eoln is encountered. */ i = 0; while (i < 4 && '\0' != buf[offs] && ' ' != buf[offs] && '\t' != buf[offs]) mac[i++] = buf[offs++]; mac[i] = '\0'; tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX; if (MAN_MAX == tok) { mandoc_vmsg(MANDOCERR_MACRO, man->parse, ln, ppos, "%s", buf + ppos - 1); return(1); } /* The macro is sane. Jump to the next word. */ while (buf[offs] && ' ' == buf[offs]) offs++; /* * Trailing whitespace. Note that tabs are allowed to be passed * into the parser as "text", so we only warn about spaces here. */ if ('\0' == buf[offs] && ' ' == buf[offs - 1]) man_pmsg(man, ln, offs - 1, MANDOCERR_EOLNSPACE); /* * Remove prior ELINE macro, as it's being clobbered by a new * macro. Note that NSCOPED macros do not close out ELINE * macros---they don't print text---so we let those slip by. */ if ( ! (MAN_NSCOPED & man_macros[tok].flags) && man->flags & MAN_ELINE) { n = man->last; assert(MAN_TEXT != n->type); /* Remove repeated NSCOPED macros causing ELINE. */ if (MAN_NSCOPED & man_macros[n->tok].flags) n = n->parent; mandoc_vmsg(MANDOCERR_LINESCOPE, man->parse, n->line, n->pos, "%s breaks %s", man_macronames[tok], man_macronames[n->tok]); man_node_delete(man, n); man->flags &= ~MAN_ELINE; } /* * Remove prior BLINE macro that is being clobbered. */ if ((man->flags & MAN_BLINE) && (MAN_BSCOPE & man_macros[tok].flags)) { n = man->last; /* Might be a text node like 8 in * .TP 8 * .SH foo */ if (MAN_TEXT == n->type) n = n->parent; /* Remove element that didn't end BLINE, if any. */ if ( ! (MAN_BSCOPE & man_macros[n->tok].flags)) n = n->parent; assert(MAN_HEAD == n->type); n = n->parent; assert(MAN_BLOCK == n->type); assert(MAN_SCOPED & man_macros[n->tok].flags); mandoc_vmsg(MANDOCERR_LINESCOPE, man->parse, n->line, n->pos, "%s breaks %s", man_macronames[tok], man_macronames[n->tok]); man_node_delete(man, n); man->flags &= ~MAN_BLINE; } /* * Save the fact that we're in the next-line for a block. In * this way, embedded roff instructions can "remember" state * when they exit. */ if (MAN_BLINE & man->flags) man->flags |= MAN_BPLINE; /* Call to handler... */ assert(man_macros[tok].fp); if ( ! (*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf)) goto err; /* * We weren't in a block-line scope when entering the * above-parsed macro, so return. */ if ( ! (MAN_BPLINE & man->flags)) { man->flags &= ~MAN_ILINE; return(1); } man->flags &= ~MAN_BPLINE; /* * If we're in a block scope, then allow this macro to slip by * without closing scope around it. */ if (MAN_ILINE & man->flags) { man->flags &= ~MAN_ILINE; return(1); } /* * If we've opened a new next-line element scope, then return * now, as the next line will close out the block scope. */ if (MAN_ELINE & man->flags) return(1); /* Close out the block scope opened in the prior line. */ assert(MAN_BLINE & man->flags); man->flags &= ~MAN_BLINE; if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX)) return(0); return(man_body_alloc(man, ln, ppos, man->last->tok)); err: /* Error out. */ man->flags |= MAN_HALT; return(0); }
static int man_pmacro(struct man *man, int ln, char *buf, int offs) { char mac[5]; struct man_node *n; enum mant tok; int i, ppos; int bline; if ('"' == buf[offs]) { mandoc_msg(MANDOCERR_COMMENT_BAD, man->parse, ln, offs, NULL); return(1); } else if ('\0' == buf[offs]) return(1); ppos = offs; /* * Copy the first word into a nil-terminated buffer. * Stop copying when a tab, space, or eoln is encountered. */ i = 0; while (i < 4 && '\0' != buf[offs] && ' ' != buf[offs] && '\t' != buf[offs]) mac[i++] = buf[offs++]; mac[i] = '\0'; tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX; if (MAN_MAX == tok) { mandoc_msg(MANDOCERR_MACRO, man->parse, ln, ppos, buf + ppos - 1); return(1); } /* The macro is sane. Jump to the next word. */ while (buf[offs] && ' ' == buf[offs]) offs++; /* * Trailing whitespace. Note that tabs are allowed to be passed * into the parser as "text", so we only warn about spaces here. */ if ('\0' == buf[offs] && ' ' == buf[offs - 1]) mandoc_msg(MANDOCERR_SPACE_EOL, man->parse, ln, offs - 1, NULL); /* * Remove prior ELINE macro, as it's being clobbered by a new * macro. Note that NSCOPED macros do not close out ELINE * macros---they don't print text---so we let those slip by. */ if ( ! (MAN_NSCOPED & man_macros[tok].flags) && man->flags & MAN_ELINE) { n = man->last; assert(MAN_TEXT != n->type); /* Remove repeated NSCOPED macros causing ELINE. */ if (MAN_NSCOPED & man_macros[n->tok].flags) n = n->parent; mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse, n->line, n->pos, "%s breaks %s", man_macronames[tok], man_macronames[n->tok]); man_node_delete(man, n); man->flags &= ~MAN_ELINE; } /* * Remove prior BLINE macro that is being clobbered. */ if ((man->flags & MAN_BLINE) && (MAN_BSCOPE & man_macros[tok].flags)) { n = man->last; /* Might be a text node like 8 in * .TP 8 * .SH foo */ if (MAN_TEXT == n->type) n = n->parent; /* Remove element that didn't end BLINE, if any. */ if ( ! (MAN_BSCOPE & man_macros[n->tok].flags)) n = n->parent; assert(MAN_HEAD == n->type); n = n->parent; assert(MAN_BLOCK == n->type); assert(MAN_SCOPED & man_macros[n->tok].flags); mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse, n->line, n->pos, "%s breaks %s", man_macronames[tok], man_macronames[n->tok]); man_node_delete(man, n); man->flags &= ~MAN_BLINE; } /* Remember whether we are in next-line scope for a block head. */ bline = man->flags & MAN_BLINE; /* Call to handler... */ assert(man_macros[tok].fp); if ( ! (*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf)) return(0); /* In quick mode (for mandocdb), abort after the NAME section. */ if (man->quick && MAN_SH == tok) { n = man->last; if (MAN_BODY == n->type && strcmp(n->prev->child->string, "NAME")) return(2); } /* * If we are in a next-line scope for a block head, * close it out now and switch to the body, * unless the next-line scope is allowed to continue. */ if ( ! bline || man->flags & MAN_ELINE || man_macros[tok].flags & MAN_NSCOPED) return(1); assert(MAN_BLINE & man->flags); man->flags &= ~MAN_BLINE; if ( ! man_unscope(man, man->last->parent)) return(0); return(man_body_alloc(man, ln, ppos, man->last->tok)); }