/* ARGSUSED */ static enum rofferr roff_block(ROFF_ARGS) { int sv; size_t sz; if (ROFF_ig != tok && '\0' == (*bufp)[pos]) { if ( ! (*r->msg)(MANDOCERR_NOARGS, r->data, ln, ppos, NULL)) return(ROFF_ERR); return(ROFF_IGN); } else if (ROFF_ig != tok) { while ((*bufp)[pos] && ' ' != (*bufp)[pos]) pos++; while (' ' == (*bufp)[pos]) pos++; } if ( ! roffnode_push(r, tok, ln, ppos)) return(ROFF_ERR); if ('\0' == (*bufp)[pos]) return(ROFF_IGN); sv = pos; while ((*bufp)[pos] && ' ' != (*bufp)[pos] && '\t' != (*bufp)[pos]) pos++; /* * Note: groff does NOT like escape characters in the input. * Instead of detecting this, we're just going to let it fly and * to hell with it. */ assert(pos > sv); sz = (size_t)(pos - sv); if (1 == sz && '.' == (*bufp)[sv]) return(ROFF_IGN); r->last->end = malloc(sz + 1); if (NULL == r->last->end) { (*r->msg)(MANDOCERR_MEM, r->data, ln, pos, NULL); return(ROFF_ERR); } memcpy(r->last->end, *bufp + sv, sz); r->last->end[(int)sz] = '\0'; if ((*bufp)[pos]) if ( ! (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL)) return(ROFF_ERR); return(ROFF_IGN); }
/* ARGSUSED */ static enum rofferr roff_cond(ROFF_ARGS) { int sv; enum roffrule rule; /* Stack overflow! */ if (ROFF_ie == tok && r->rstackpos == RSTACK_MAX - 1) { (*r->msg)(MANDOCERR_MEM, r->data, ln, ppos, NULL); return(ROFF_ERR); } /* First, evaluate the conditional. */ if (ROFF_el == tok) { /* * An `.el' will get the value of the current rstack * entry set in prior `ie' calls or defaults to DENY. */ if (r->rstackpos < 0) rule = ROFFRULE_DENY; else rule = r->rstack[r->rstackpos]; } else rule = roff_evalcond(*bufp, &pos); sv = pos; while (' ' == (*bufp)[pos]) pos++; /* * Roff is weird. If we have just white-space after the * conditional, it's considered the BODY and we exit without * really doing anything. Warn about this. It's probably * wrong. */ if ('\0' == (*bufp)[pos] && sv != pos) { if ((*r->msg)(MANDOCERR_NOARGS, r->data, ln, ppos, NULL)) return(ROFF_IGN); return(ROFF_ERR); } if ( ! roffnode_push(r, tok, ln, ppos)) return(ROFF_ERR); r->last->rule = rule; ROFF_DEBUG("roff: cond: %s -> %s\n", roffs[tok].name, ROFFRULE_ALLOW == rule ? "allow" : "deny"); if (ROFF_ie == tok) { /* * An if-else will put the NEGATION of the current * evaluated conditional into the stack. */ r->rstackpos++; if (ROFFRULE_DENY == r->last->rule) r->rstack[r->rstackpos] = ROFFRULE_ALLOW; else r->rstack[r->rstackpos] = ROFFRULE_DENY; } /* If the parent has false as its rule, then so do we. */ if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule) { r->last->rule = ROFFRULE_DENY; ROFF_DEBUG("roff: cond override: %s -> deny\n", roffs[tok].name); } /* * Determine scope. If we're invoked with "\{" trailing the * conditional, then we're in a multiline scope. Else our scope * expires on the next line. */ r->last->endspan = 1; if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) { r->last->endspan = -1; pos += 2; ROFF_DEBUG("roff: cond-scope: %s, multi-line\n", roffs[tok].name); } else ROFF_DEBUG("roff: cond-scope: %s, one-line\n", roffs[tok].name); /* * If there are no arguments on the line, the next-line scope is * assumed. */ if ('\0' == (*bufp)[pos]) return(ROFF_IGN); /* Otherwise re-run the roff parser after recalculating. */ *offs = pos; return(ROFF_RERUN); }
/* ARGSUSED */ static enum rofferr roff_cond(ROFF_ARGS) { roffnode_push(r, tok, NULL, ln, ppos); /* * An `.el' has no conditional body: it will consume the value * of the current rstack entry set in prior `ie' calls or * defaults to DENY. * * If we're not an `el', however, then evaluate the conditional. */ r->last->rule = ROFF_el == tok ? (r->rstackpos < 0 ? ROFFRULE_DENY : r->rstack[r->rstackpos--]) : roff_evalcond(*bufp, &pos); /* * An if-else will put the NEGATION of the current evaluated * conditional into the stack of rules. */ if (ROFF_ie == tok) { if (r->rstackpos == RSTACK_MAX - 1) { mandoc_msg(MANDOCERR_MEM, r->parse, ln, ppos, NULL); return(ROFF_ERR); } r->rstack[++r->rstackpos] = ROFFRULE_DENY == r->last->rule ? ROFFRULE_ALLOW : ROFFRULE_DENY; } /* If the parent has false as its rule, then so do we. */ if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule) r->last->rule = ROFFRULE_DENY; /* * Determine scope. * If there is nothing on the line after the conditional, * not even whitespace, use next-line scope. */ if ('\0' == (*bufp)[pos]) { r->last->endspan = 2; goto out; } while (' ' == (*bufp)[pos]) pos++; /* An opening brace requests multiline scope. */ if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) { r->last->endspan = -1; pos += 2; goto out; } /* * Anything else following the conditional causes * single-line scope. Warn if the scope contains * nothing but trailing whitespace. */ if ('\0' == (*bufp)[pos]) mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL); r->last->endspan = 1; out: *offs = pos; return(ROFF_RERUN); }
/* ARGSUSED */ static enum rofferr roff_block(ROFF_ARGS) { int sv; size_t sz; char *name; name = NULL; if (ROFF_ig != tok) { if ('\0' == (*bufp)[pos]) { mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL); return(ROFF_IGN); } /* * Re-write `de1', since we don't really care about * groff's strange compatibility mode, into `de'. */ if (ROFF_de1 == tok) tok = ROFF_de; if (ROFF_de == tok) name = *bufp + pos; else mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos, roffs[tok].name); while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos])) pos++; while (isspace((unsigned char)(*bufp)[pos])) (*bufp)[pos++] = '\0'; } roffnode_push(r, tok, name, ln, ppos); /* * At the beginning of a `de' macro, clear the existing string * with the same name, if there is one. New content will be * added from roff_block_text() in multiline mode. */ if (ROFF_de == tok) roff_setstr(r, name, "", 0); if ('\0' == (*bufp)[pos]) return(ROFF_IGN); /* If present, process the custom end-of-line marker. */ sv = pos; while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos])) pos++; /* * Note: groff does NOT like escape characters in the input. * Instead of detecting this, we're just going to let it fly and * to hell with it. */ assert(pos > sv); sz = (size_t)(pos - sv); if (1 == sz && '.' == (*bufp)[sv]) return(ROFF_IGN); r->last->end = mandoc_malloc(sz + 1); memcpy(r->last->end, *bufp + sv, sz); r->last->end[(int)sz] = '\0'; if ((*bufp)[pos]) mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL); return(ROFF_IGN); }
/* ARGSUSED */ static enum rofferr roff_cond(ROFF_ARGS) { int sv; enum roffrule rule; /* * An `.el' has no conditional body: it will consume the value * of the current rstack entry set in prior `ie' calls or * defaults to DENY. * * If we're not an `el', however, then evaluate the conditional. */ rule = ROFF_el == tok ? (r->rstackpos < 0 ? ROFFRULE_DENY : r->rstack[r->rstackpos--]) : roff_evalcond(*bufp, &pos); sv = pos; while (' ' == (*bufp)[pos]) pos++; /* * Roff is weird. If we have just white-space after the * conditional, it's considered the BODY and we exit without * really doing anything. Warn about this. It's probably * wrong. */ if ('\0' == (*bufp)[pos] && sv != pos) { mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL); return(ROFF_IGN); } roffnode_push(r, tok, NULL, ln, ppos); r->last->rule = rule; /* * An if-else will put the NEGATION of the current evaluated * conditional into the stack of rules. */ if (ROFF_ie == tok) { if (r->rstackpos == RSTACK_MAX - 1) { mandoc_msg(MANDOCERR_MEM, r->parse, ln, ppos, NULL); return(ROFF_ERR); } r->rstack[++r->rstackpos] = ROFFRULE_DENY == r->last->rule ? ROFFRULE_ALLOW : ROFFRULE_DENY; } /* If the parent has false as its rule, then so do we. */ if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule) r->last->rule = ROFFRULE_DENY; /* * Determine scope. If we're invoked with "\{" trailing the * conditional, then we're in a multiline scope. Else our scope * expires on the next line. */ r->last->endspan = 1; if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) { r->last->endspan = -1; pos += 2; } /* * If there are no arguments on the line, the next-line scope is * assumed. */ if ('\0' == (*bufp)[pos]) return(ROFF_IGN); /* Otherwise re-run the roff parser after recalculating. */ *offs = pos; return(ROFF_RERUN); }