-static int
-roffargs(const struct rofftree *tree,
- int tok, char *buf, char **argv)
-{
- int i;
- char *p;
-
- assert(tok >= 0 && tok < ROFF_MAX);
- assert('.' == *buf);
-
- p = buf;
-
- /*
- * This is an ugly little loop. It parses a line into
- * space-delimited tokens. If a quote mark is encountered, a
- * token is alloted the entire quoted text. If whitespace is
- * escaped, it's included in the prior alloted token.
- */
-
- /* LINTED */
- for (i = 0; *buf && i < ROFF_MAXLINEARG; i++) {
- if ('\"' == *buf) {
- argv[i] = ++buf;
- while (*buf && '\"' != *buf)
- buf++;
- if (0 == *buf)
- return(roff_err(tree, argv[i],
- "unclosed quote in arg list"));
- } else {
- argv[i] = buf++;
- while (*buf) {
- if ( ! isspace(*buf)) {
- buf++;
- continue;
- }
- if (*(buf - 1) == '\\') {
- buf++;
- continue;
- }
- break;
- }
- if (0 == *buf)
- continue;
- }
- *buf++ = 0;
- while (*buf && isspace(*buf))
- buf++;
- }
-
- assert(i > 0);
- if (ROFF_MAXLINEARG == i && *buf)
- return(roff_err(tree, p, "too many args"));
-
- argv[i] = NULL;
- return(1);
-}
-
-
-static int
-roffscan(int tok, const int *tokv)
-{
-
- if (NULL == tokv)
- return(1);
-
- for ( ; ROFF_MAX != *tokv; tokv++)
- if (tok == *tokv)
- return(1);
-
- return(0);
-}
-
-
-static int
-roffparse(struct rofftree *tree, char *buf)
-{
- int tok, t;
- struct roffnode *n;
- char *argv[ROFF_MAXLINEARG];
- char **argvp;
-
- if (0 != *buf && 0 != *(buf + 1) && 0 != *(buf + 2))
- if (0 == strncmp(buf, ".\\\"", 3))
- return(1);
-
- if (ROFF_MAX == (tok = rofffindtok(buf + 1)))
- return(roff_err(tree, buf, "bogus line macro"));
- else if ( ! roffargs(tree, tok, buf, argv))
- return(0);
-
- argvp = (char **)argv;
-
- /*
- * Prelude macros break some assumptions, so branch now.
- */
-
- if (ROFF_PRELUDE & tree->state) {
- assert(NULL == tree->last);
- return(roffcall(tree, tok, argvp));
- }
-
- assert(ROFF_BODY & tree->state);
-
- /*
- * First check that our possible parents and parent's possible
- * children are satisfied.
- */
-
- if (tree->last && ! roffscan
- (tree->last->tok, tokens[tok].parents))
- return(roff_err(tree, *argvp, "`%s' has invalid "
- "parent `%s'", toknames[tok],
- toknames[tree->last->tok]));
-
- if (tree->last && ! roffscan
- (tok, tokens[tree->last->tok].children))
- return(roff_err(tree, *argvp, "`%s' has invalid "
- "child `%s'", toknames[tok],
- toknames[tree->last->tok]));
-
- /*
- * Branch if we're not a layout token.
- */
-
- if (ROFF_LAYOUT != tokens[tok].type)
- return(roffcall(tree, tok, argvp));
- if (0 == tokens[tok].ctx)
- return(roffcall(tree, tok, argvp));
-
- /*
- * First consider implicit-end tags, like as follows:
- * .Sh SECTION 1
- * .Sh SECTION 2
- * In this, we want to close the scope of the NAME section. If
- * there's an intermediary implicit-end tag, such as
- * .Sh SECTION 1
- * .Ss Subsection 1
- * .Sh SECTION 2
- * then it must be closed as well.
- */
-
- if (tok == tokens[tok].ctx) {
- /*
- * First search up to the point where we must close.
- * If one doesn't exist, then we can open a new scope.
- */
-
- for (n = tree->last; n; n = n->parent) {
- assert(0 == tokens[n->tok].ctx ||
- n->tok == tokens[n->tok].ctx);
- if (n->tok == tok)
- break;
- if (ROFF_SHALLOW & tokens[tok].flags) {
- n = NULL;
- break;
- }
- if (tokens[n->tok].ctx == n->tok)
- continue;
- return(roff_err(tree, *argv, "`%s' breaks "
- "scope of prior`%s'",
- toknames[tok],
- toknames[n->tok]));
- }
-
- /*
- * Create a new scope, as no previous one exists to
- * close out.
- */
-
- if (NULL == n)
- return(roffcall(tree, tok, argvp));
-
- /*
- * Close out all intermediary scoped blocks, then hang
- * the current scope from our predecessor's parent.
- */
-
- do {
- t = tree->last->tok;
- if ( ! roffexit(tree, t))
- return(0);
- } while (t != tok);
-
- return(roffcall(tree, tok, argvp));
- }
-
- /*
- * Now consider explicit-end tags, where we want to close back
- * to a specific tag. Example:
- * .Bl
- * .It Item.
- * .El
- * In this, the `El' tag closes out the scope of `Bl'.
- */
-
- assert(tok != tokens[tok].ctx && 0 != tokens[tok].ctx);
-
- /* LINTED */
- for (n = tree->last; n; n = n->parent)
- if (n->tok != tokens[tok].ctx) {
- if (n->tok == tokens[n->tok].ctx)
- continue;
- return(roff_err(tree, *argv, "`%s' breaks "
- "scope of prior `%s'",
- toknames[tok],
- toknames[n->tok]));
- } else
- break;
-
- if (NULL == n)
- return(roff_err(tree, *argv, "`%s' has no starting "
- "tag `%s'", toknames[tok],
- toknames[tokens[tok].ctx]));
-
- /* LINTED */
- do {
- t = tree->last->tok;
- if ( ! roffexit(tree, t))
- return(0);
- } while (t != tokens[tok].ctx);
-
- return(1);
-}
-
-
-static int
-rofffindarg(const char *name)
-{
- size_t i;
-
- /* FIXME: use a table, this is slow but ok for now. */