/* ARGSUSED */ int blk_close(MACRO_PROT_ARGS) { enum mant ntok; const struct man_node *nn; switch (tok) { case (MAN_RE): ntok = MAN_RS; break; case (MAN_UE): ntok = MAN_UR; break; default: abort(); /* NOTREACHED */ } for (nn = man->last->parent; nn; nn = nn->parent) if (ntok == nn->tok && MAN_BLOCK == nn->type) break; if (NULL == nn) { man_pmsg(man, line, ppos, MANDOCERR_NOSCOPE); if ( ! rew_scope(MAN_BLOCK, man, MAN_PP)) return(0); } else man_unscope(man, nn, MANDOCERR_MAX); return(1); }
/* ARGSUSED */ int blk_close(MACRO_PROT_ARGS) { enum mant ntok; const struct man_node *nn; switch (tok) { case (MAN_RE): ntok = MAN_RS; break; default: abort(); /* NOTREACHED */ } for (nn = m->last->parent; nn; nn = nn->parent) if (ntok == nn->tok) break; if (NULL == nn) man_pmsg(m, line, ppos, MANDOCERR_NOSCOPE); if ( ! rew_scope(MAN_BODY, m, ntok)) return(0); if ( ! rew_scope(MAN_BLOCK, m, ntok)) return(0); return(1); }
static void check_text(CHKARGS) { char *cp, *p; if (MAN_LITERAL & man->flags) return; cp = n->string; for (p = cp; NULL != (p = strchr(p, '\t')); p++) man_pmsg(man, n->line, (int)(p - cp), MANDOCERR_BADTAB); }
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_ptext(struct man *man, int line, char *buf, int offs) { int i; /* Literal free-form text whitespace is preserved. */ if (MAN_LITERAL & man->flags) { if ( ! man_word_alloc(man, line, offs, buf + offs)) return(0); return(man_descope(man, line, offs)); } for (i = offs; ' ' == buf[i]; i++) /* Skip leading whitespace. */ ; /* * Blank lines are ignored right after headings * but add a single vertical space elsewhere. */ if ('\0' == buf[i]) { /* Allocate a blank entry. */ if (MAN_SH != man->last->tok && MAN_SS != man->last->tok) { if ( ! man_elem_alloc(man, line, offs, MAN_sp)) return(0); man->next = MAN_NEXT_SIBLING; } return(1); } /* * Warn if the last un-escaped character is whitespace. Then * strip away the remaining spaces (tabs stay!). */ i = (int)strlen(buf); assert(i); if (' ' == buf[i - 1] || '\t' == buf[i - 1]) { if (i > 1 && '\\' != buf[i - 2]) man_pmsg(man, line, i - 1, MANDOCERR_EOLNSPACE); for (--i; i && ' ' == buf[i]; i--) /* Spin back to non-space. */ ; /* Jump ahead of escaped whitespace. */ i += '\\' == buf[i] ? 2 : 1; buf[i] = '\0'; } if ( ! man_word_alloc(man, line, offs, buf + offs)) return(0); /* * 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(i); if (mandoc_eos(buf, (size_t)i, 0)) man->last->flags |= MAN_EOS; return(man_descope(man, line, offs)); }
static int man_ptext(struct man *m, int line, char *buf, int offs) { int i; /* Literal free-form text whitespace is preserved. */ if (MAN_LITERAL & m->flags) { if ( ! man_word_alloc(m, line, offs, buf + offs)) return(0); return(man_descope(m, line, offs)); } /* Pump blank lines directly into the backend. */ for (i = offs; ' ' == buf[i]; i++) /* Skip leading whitespace. */ ; if ('\0' == buf[i]) { /* Allocate a blank entry. */ if ( ! man_word_alloc(m, line, offs, "")) return(0); return(man_descope(m, line, offs)); } /* * Warn if the last un-escaped character is whitespace. Then * strip away the remaining spaces (tabs stay!). */ i = (int)strlen(buf); assert(i); if (' ' == buf[i - 1] || '\t' == buf[i - 1]) { if (i > 1 && '\\' != buf[i - 2]) man_pmsg(m, line, i - 1, MANDOCERR_EOLNSPACE); for (--i; i && ' ' == buf[i]; i--) /* Spin back to non-space. */ ; /* Jump ahead of escaped whitespace. */ i += '\\' == buf[i] ? 2 : 1; buf[i] = '\0'; } if ( ! man_word_alloc(m, line, offs, buf + offs)) return(0); /* * 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(i); if (mandoc_eos(buf, (size_t)i, 0)) m->last->flags |= MAN_EOS; return(man_descope(m, line, offs)); }