/* ARGSUSED */ static enum rofferr roff_block_sub(ROFF_ARGS) { enum rofft t; int i, j; /* * First check whether a custom macro exists at this level. If * it does, then check against it. This is some of groff's * stranger behaviours. If we encountered a custom end-scope * tag and that tag also happens to be a "real" macro, then we * need to try interpreting it again as a real macro. If it's * not, then return ignore. Else continue. */ if (r->last->end) { for (i = pos, j = 0; r->last->end[j]; j++, i++) if ((*bufp)[i] != r->last->end[j]) break; if ('\0' == r->last->end[j] && ('\0' == (*bufp)[i] || ' ' == (*bufp)[i] || '\t' == (*bufp)[i])) { roffnode_pop(r); roffnode_cleanscope(r); while (' ' == (*bufp)[i] || '\t' == (*bufp)[i]) i++; pos = i; if (ROFF_MAX != roff_parse(r, *bufp, &pos)) return(ROFF_RERUN); return(ROFF_IGN); } } /* * If we have no custom end-query or lookup failed, then try * pulling it out of the hashtable. */ t = roff_parse(r, *bufp, &pos); /* * Macros other than block-end are only significant * in `de' blocks; elsewhere, simply throw them away. */ if (ROFF_cblock != t) { if (ROFF_de == tok) roff_setstr(r, r->last->name, *bufp + ppos, 1); return(ROFF_IGN); } assert(roffs[t].proc); return((*roffs[t].proc)(r, t, bufp, szp, ln, ppos, pos, offs)); }
/* ARGSUSED */ static enum rofferr roff_block_sub(ROFF_ARGS) { enum rofft t; int i, j; /* * First check whether a custom macro exists at this level. If * it does, then check against it. This is some of groff's * stranger behaviours. If we encountered a custom end-scope * tag and that tag also happens to be a "real" macro, then we * need to try interpreting it again as a real macro. If it's * not, then return ignore. Else continue. */ if (r->last->end) { i = pos + 1; while (' ' == (*bufp)[i] || '\t' == (*bufp)[i]) i++; for (j = 0; r->last->end[j]; j++, i++) if ((*bufp)[i] != r->last->end[j]) break; if ('\0' == r->last->end[j] && ('\0' == (*bufp)[i] || ' ' == (*bufp)[i] || '\t' == (*bufp)[i])) { roffnode_pop(r); roffnode_cleanscope(r); if (ROFF_MAX != roff_parse(*bufp, &pos)) return(ROFF_RERUN); return(ROFF_IGN); } } /* * If we have no custom end-query or lookup failed, then try * pulling it out of the hashtable. */ ppos = pos; t = roff_parse(*bufp, &pos); /* If we're not a comment-end, then throw it away. */ if (ROFF_cblock != t) return(ROFF_IGN); assert(roffs[t].proc); return((*roffs[t].proc)(r, t, bufp, szp, ln, ppos, pos, offs)); }
enum rofferr roff_parseln(struct roff *r, int ln, char **bufp, size_t *szp, int pos, int *offs) { enum rofft t; int ppos; /* * First, if a scope is open and we're not a macro, pass the * text through the macro's filter. If a scope isn't open and * we're not a macro, just let it through. */ if (r->last && ! ROFF_CTL((*bufp)[pos])) { t = r->last->tok; assert(roffs[t].text); ROFF_DEBUG("roff: intercept scoped text: %s, [%s]\n", roffs[t].name, &(*bufp)[pos]); return((*roffs[t].text) (r, t, bufp, szp, ln, pos, pos, offs)); } else if ( ! ROFF_CTL((*bufp)[pos])) { ROFF_DEBUG("roff: pass non-scoped text: [%s]\n", &(*bufp)[pos]); return(ROFF_CONT); } /* * If a scope is open, go to the child handler for that macro, * as it may want to preprocess before doing anything with it. */ if (r->last) { t = r->last->tok; assert(roffs[t].sub); ROFF_DEBUG("roff: intercept scoped context: %s\n", roffs[t].name); return((*roffs[t].sub) (r, t, bufp, szp, ln, pos, pos, offs)); } /* * Lastly, as we've no scope open, try to look up and execute * the new macro. If no macro is found, simply return and let * the compilers handle it. */ ppos = pos; if (ROFF_MAX == (t = roff_parse(*bufp, &pos))) { ROFF_DEBUG("roff: pass non-scoped non-macro: [%s]\n", &(*bufp)[pos]); return(ROFF_CONT); } ROFF_DEBUG("roff: intercept new-scope: %s, [%s]\n", roffs[t].name, &(*bufp)[pos]); assert(roffs[t].proc); return((*roffs[t].proc) (r, t, bufp, szp, ln, ppos, pos, offs)); }
/* ARGSUSED */ static enum rofferr roff_cond_sub(ROFF_ARGS) { enum rofft t; enum roffrule rr; char *ep; rr = r->last->rule; roffnode_cleanscope(r); t = roff_parse(r, *bufp, &pos); /* * Fully handle known macros when they are structurally * required or when the conditional evaluated to true. */ if ((ROFF_MAX != t) && (ROFF_ccond == t || ROFFRULE_ALLOW == rr || ROFFMAC_STRUCT & roffs[t].flags)) { assert(roffs[t].proc); return((*roffs[t].proc)(r, t, bufp, szp, ln, ppos, pos, offs)); } /* Always check for the closing delimiter `\}'. */ ep = &(*bufp)[pos]; while (NULL != (ep = strchr(ep, '\\'))) { if ('}' != *(++ep)) continue; /* * If we're at the end of line, then just chop * off the \} and resize the buffer. * If we aren't, then convert it to spaces. */ if ('\0' == *(ep + 1)) { *--ep = '\0'; *szp -= 2; } else *(ep - 1) = *ep = ' '; roff_ccond(r, ROFF_ccond, bufp, szp, ln, pos, pos + 2, offs); break; } return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); }
/* ARGSUSED */ static enum rofferr roff_cond_sub(ROFF_ARGS) { enum rofft t; enum roffrule rr; struct roffnode *l; ppos = pos; rr = r->last->rule; /* * Clean out scope. If we've closed ourselves, then don't * continue. */ l = r->last; roffnode_cleanscope(r); if (l != r->last) return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); if (ROFF_MAX == (t = roff_parse(*bufp, &pos))) return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); /* * A denied conditional must evaluate its children if and only * if they're either structurally required (such as loops and * conditionals) or a closing macro. */ if (ROFFRULE_DENY == rr) if ( ! (ROFFMAC_STRUCT & roffs[t].flags)) if (ROFF_ccond != t) return(ROFF_IGN); assert(roffs[t].proc); return((*roffs[t].proc) (r, t, bufp, szp, ln, ppos, pos, offs)); }
enum rofferr roff_parseln(struct roff *r, int ln, char **bufp, size_t *szp, int pos, int *offs) { enum rofft t; enum rofferr e; int ppos, ctl; /* * Run the reserved-word filter only if we have some reserved * words to fill in. */ e = roff_res(r, bufp, szp, ln, pos); if (ROFF_IGN == e) return(e); assert(ROFF_CONT == e); ppos = pos; ctl = roff_getcontrol(r, *bufp, &pos); /* * First, if a scope is open and we're not a macro, pass the * text through the macro's filter. If a scope isn't open and * we're not a macro, just let it through. * Finally, if there's an equation scope open, divert it into it * no matter our state. */ if (r->last && ! ctl) { t = r->last->tok; assert(roffs[t].text); e = (*roffs[t].text) (r, t, bufp, szp, ln, pos, pos, offs); assert(ROFF_IGN == e || ROFF_CONT == e); if (ROFF_CONT != e) return(e); if (r->eqn) return(eqn_read(&r->eqn, ln, *bufp, pos, offs)); if (r->tbl) return(tbl_read(r->tbl, ln, *bufp, pos)); return(roff_parsetext(*bufp + pos)); } else if ( ! ctl) { if (r->eqn) return(eqn_read(&r->eqn, ln, *bufp, pos, offs)); if (r->tbl) return(tbl_read(r->tbl, ln, *bufp, pos)); return(roff_parsetext(*bufp + pos)); } else if (r->eqn) return(eqn_read(&r->eqn, ln, *bufp, ppos, offs)); /* * If a scope is open, go to the child handler for that macro, * as it may want to preprocess before doing anything with it. * Don't do so if an equation is open. */ if (r->last) { t = r->last->tok; assert(roffs[t].sub); return((*roffs[t].sub) (r, t, bufp, szp, ln, ppos, pos, offs)); } /* * Lastly, as we've no scope open, try to look up and execute * the new macro. If no macro is found, simply return and let * the compilers handle it. */ if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos))) return(ROFF_CONT); assert(roffs[t].proc); return((*roffs[t].proc) (r, t, bufp, szp, ln, ppos, pos, offs)); }
/* ARGSUSED */ static enum rofferr roff_cond_sub(ROFF_ARGS) { enum rofft t; enum roffrule rr; char *ep; rr = r->last->rule; roffnode_cleanscope(r); /* * If the macro is unknown, first check if it contains a closing * delimiter `\}'. If it does, close out our scope and return * the currently-scoped rule (ignore or continue). Else, drop * into the currently-scoped rule. */ if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos))) { ep = &(*bufp)[pos]; for ( ; NULL != (ep = strchr(ep, '\\')); ep++) { ep++; if ('}' != *ep) continue; /* * Make the \} go away. * This is a little haphazard, as it's not quite * clear how nroff does this. * If we're at the end of line, then just chop * off the \} and resize the buffer. * If we aren't, then conver it to spaces. */ if ('\0' == *(ep + 1)) { *--ep = '\0'; *szp -= 2; } else *(ep - 1) = *ep = ' '; roff_ccond(r, ROFF_ccond, bufp, szp, ln, pos, pos + 2, offs); break; } return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); } /* * A denied conditional must evaluate its children if and only * if they're either structurally required (such as loops and * conditionals) or a closing macro. */ if (ROFFRULE_DENY == rr) if ( ! (ROFFMAC_STRUCT & roffs[t].flags)) if (ROFF_ccond != t) return(ROFF_IGN); assert(roffs[t].proc); return((*roffs[t].proc)(r, t, bufp, szp, ln, ppos, pos, offs)); }