=================================================================== RCS file: /cvs/mandoc/roff.c,v retrieving revision 1.60 retrieving revision 1.64 diff -u -p -r1.60 -r1.64 --- mandoc/roff.c 2008/12/10 12:09:47 1.60 +++ mandoc/roff.c 2008/12/12 10:11:10 1.64 @@ -1,4 +1,4 @@ -/* $Id: roff.c,v 1.60 2008/12/10 12:09:47 kristaps Exp $ */ +/* $Id: roff.c,v 1.64 2008/12/12 10:11:10 kristaps Exp $ */ /* * Copyright (c) 2008 Kristaps Dzonsons * @@ -38,7 +38,6 @@ /* TODO: (warn) some sections need specific elements. */ /* TODO: (warn) NAME section has particular order. */ /* TODO: macros with a set number of arguments? */ -/* TODO: validate Dt macro arguments. */ /* FIXME: Bl -diag supposed to ignore callable children. */ struct roffnode { @@ -71,16 +70,11 @@ struct rofftree { char title[64]; /* `Dt' results. */ enum roffmsec section; enum roffvol volume; - int state; -#define ROFF_PRELUDE (1 << 1) /* In roff prelude. */ /* FIXME: put into asec. */ -#define ROFF_PRELUDE_Os (1 << 2) /* `Os' is parsed. */ -#define ROFF_PRELUDE_Dt (1 << 3) /* `Dt' is parsed. */ -#define ROFF_PRELUDE_Dd (1 << 4) /* `Dd' is parsed. */ -#define ROFF_BODY (1 << 5) /* In roff body. */ struct roffcb cb; /* Callbacks. */ void *arg; /* Callbacks' arg. */ int csec; /* Current section. */ int asec; /* Thus-far sections. */ + int literal; /* Literal mode. */ }; static struct roffnode *roffnode_new(int, struct rofftree *); @@ -100,7 +94,7 @@ static int rofffindarg(const char *); static int rofffindcallable(const char *); static int roffispunct(const char *); static int roffchecksec(struct rofftree *, - const char *, int); + const char *, int, int); static int roffargs(const struct rofftree *, int, char *, char **); static int roffargok(int, int); @@ -140,10 +134,7 @@ roff_free(struct rofftree *tree, int flush) error = 1; - if (ROFF_PRELUDE & tree->state) { - (void)roff_err(tree, NULL, "prelude never finished"); - goto end; - } else if ( ! (ROFFSec_NAME & tree->asec)) { + if ( ! (ROFFSec_NAME & tree->asec)) { (void)roff_err(tree, NULL, "missing `NAME' section"); goto end; } else if ( ! (ROFFSec_NMASK & tree->asec)) @@ -193,7 +184,6 @@ roff_alloc(const struct roffcb *cb, void *args) if (NULL == (tree = calloc(1, sizeof(struct rofftree)))) err(1, "calloc"); - tree->state = ROFF_PRELUDE; tree->arg = args; tree->section = ROFF_MSEC_MAX; @@ -226,9 +216,12 @@ textparse(struct rofftree *tree, char *buf) /* TODO: literal parsing. */ - if ( ! (ROFF_BODY & tree->state)) - return(roff_err(tree, buf, "data not in body")); + if ( ! (ROFFSec_NAME & tree->asec)) + return(roff_err(tree, buf, "data before `NAME' section")); + if (tree->literal) + return(roffdata(tree, 0, buf)); + /* LINTED */ while (*buf) { while (*buf && isspace(*buf)) @@ -354,13 +347,11 @@ roffparse(struct rofftree *tree, char *buf) * Prelude macros break some assumptions, so branch now. */ - if (ROFF_PRELUDE & tree->state) { + if ( ! (ROFFSec_PR_Dd & tree->asec)) { 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. @@ -527,10 +518,25 @@ rofffindtok(const char *buf) static int -roffchecksec(struct rofftree *tree, const char *start, int sec) +roffchecksec(struct rofftree *tree, + const char *start, int sec, int fail) { switch (sec) { + case(ROFFSec_PR_Dd): + return(1); + case(ROFFSec_PR_Dt): + if (ROFFSec_PR_Dd & tree->asec) + return(1); + break; + case(ROFFSec_PR_Os): + if (ROFFSec_PR_Dt & tree->asec) + return(1); + break; + case(ROFFSec_NAME): + if (ROFFSec_PR_Os & tree->asec) + return(1); + break; case(ROFFSec_SYNOP): if (ROFFSec_NAME & tree->asec) return(1); @@ -591,11 +597,12 @@ roffchecksec(struct rofftree *tree, const char *start, return(1); } + if (fail) + return(0); return(roff_warnp(tree, start, ROFF_Sh, WRN_SECORD)); } -/* FIXME: move this into literals.c (or similar). */ static int roffispunct(const char *p) { @@ -919,35 +926,27 @@ roff_Dd(ROFFCALL_ARGS) char *p, buf[32]; size_t sz; - if (ROFF_BODY & tree->state) { - assert( ! (ROFF_PRELUDE & tree->state)); - assert(ROFF_PRELUDE_Dd & tree->state); + if (ROFFSec_PR_Os & tree->asec) return(roff_text(tok, tree, argv, type)); - } - - assert(ROFF_PRELUDE & tree->state); - assert( ! (ROFF_BODY & tree->state)); - - if (ROFF_PRELUDE_Dd & tree->state) + if (ROFFSec_PR_Dd & tree->asec) return(roff_errp(tree, *argv, tok, ERR_PR_REP)); - if (ROFF_PRELUDE_Dt & tree->state) + if ( ! roffchecksec(tree, *argv, ROFFSec_PR_Dd, 1)) return(roff_errp(tree, *argv, tok, ERR_PR_OOO)); assert(NULL == tree->last); - argv++; + tree->asec |= (tree->csec = ROFFSec_PR_Dd); /* * This is a bit complex because there are many forms the date - * can be in: it can be simply $Mdocdate: December 10 2008 $, $Mdocdate $, + * can be in: it can be simply $Mdocdate: December 12 2008 $, $Mdocdate $, * or a raw date. Process accordingly. */ - if (0 == strcmp(*argv, "$Mdocdate: December 10 2008 $")) { + if (0 == strcmp(*argv, "$Mdocdate: December 12 2008 $")) { t = time(NULL); if (NULL == localtime_r(&t, &tree->tm)) err(1, "localtime_r"); - tree->state |= ROFF_PRELUDE_Dd; return(1); } @@ -961,10 +960,8 @@ roff_Dd(ROFFCALL_ARGS) continue; return(roff_errp(tree, p, tok, ERR_BADARG)); } - if (strptime(buf, "%b%d,%Y", &tree->tm)) { - tree->state |= ROFF_PRELUDE_Dd; + if (strptime(buf, "%b%d,%Y", &tree->tm)) return(1); - } return(roff_errp(tree, p, tok, ERR_BADARG)); } @@ -982,7 +979,6 @@ roff_Dd(ROFFCALL_ARGS) if (NULL == strptime(buf, "%b %d %Y", &tree->tm)) return(roff_errp(tree, p, tok, ERR_BADARG)); - tree->state |= ROFF_PRELUDE_Dd; return(1); } @@ -993,21 +989,15 @@ roff_Dt(ROFFCALL_ARGS) { size_t sz; - if (ROFF_BODY & tree->state) { - assert( ! (ROFF_PRELUDE & tree->state)); - assert(ROFF_PRELUDE_Dt & tree->state); + if (ROFFSec_PR_Os & tree->asec) return(roff_text(tok, tree, argv, type)); - } - - assert(ROFF_PRELUDE & tree->state); - assert( ! (ROFF_BODY & tree->state)); - - if ( ! (ROFF_PRELUDE_Dd & tree->state)) - return(roff_errp(tree, *argv, tok, ERR_PR_OOO)); - if (ROFF_PRELUDE_Dt & tree->state) + if (ROFFSec_PR_Dt & tree->asec) return(roff_errp(tree, *argv, tok, ERR_PR_REP)); + if ( ! roffchecksec(tree, *argv, ROFFSec_PR_Dt, 1)) + return(roff_errp(tree, *argv, tok, ERR_PR_OOO)); argv++; + tree->asec |= (tree->csec = ROFFSec_PR_Dt); sz = sizeof(tree->title); if (NULL == *argv) @@ -1065,7 +1055,6 @@ roff_Dt(ROFFCALL_ARGS) return(roff_errp(tree, *argv, tok, ERR_BADARG)); assert(NULL == tree->last); - tree->state |= ROFF_PRELUDE_Dt; return(1); } @@ -1144,22 +1133,17 @@ roff_Os(ROFFCALL_ARGS) char *p; size_t sz; - if (ROFF_BODY & tree->state) { - assert( ! (ROFF_PRELUDE & tree->state)); - assert(ROFF_PRELUDE_Os & tree->state); + if (ROFFSec_PR_Os & tree->asec) return(roff_text(tok, tree, argv, type)); - } - - assert(ROFF_PRELUDE & tree->state); - if ( ! (ROFF_PRELUDE_Dt & tree->state) || - ! (ROFF_PRELUDE_Dd & tree->state)) + if ( ! roffchecksec(tree, *argv, ROFFSec_PR_Os, 1)) return(roff_errp(tree, *argv, tok, ERR_PR_OOO)); - tree->os[0] = 0; - p = *++argv; sz = sizeof(tree->os); + tree->asec |= (tree->csec = ROFFSec_PR_Os); + tree->os[0] = 0; + while (*argv) if (strlcat(tree->os, *argv++, sz) >= sz) return(roff_errp(tree, p, tok, ERR_ARGLEN)); @@ -1168,10 +1152,6 @@ roff_Os(ROFFCALL_ARGS) if (strlcpy(tree->os, "LOCAL", sz) >= sz) return(roff_errp(tree, p, tok, ERR_ARGLEN)); - tree->state |= ROFF_PRELUDE_Os; - tree->state &= ~ROFF_PRELUDE; - tree->state |= ROFF_BODY; - assert(ROFF_MSEC_MAX != tree->section); assert(0 != tree->title[0]); assert(0 != tree->os[0]); @@ -1189,7 +1169,7 @@ static int roff_layout(ROFFCALL_ARGS) { int i, c, argcp[ROFF_MAXLINEARG]; - char *argvp[ROFF_MAXLINEARG]; + char *argvp[ROFF_MAXLINEARG], *p; /* * The roff_layout function is for multi-line macros. A layout @@ -1205,7 +1185,7 @@ roff_layout(ROFFCALL_ARGS) assert( ! (ROFF_CALLABLE & tokens[tok].flags)); - if (ROFF_PRELUDE & tree->state) + if ( ! (ROFFSec_PR_Os & tree->asec)) return(roff_errp(tree, *argv, tok, ERR_NOT_PR)); if (ROFF_EXIT == type) { @@ -1215,7 +1195,7 @@ roff_layout(ROFFCALL_ARGS) return((*tree->cb.roffblkout)(tree->arg, tok)); } - argv++; + p = *argv++; assert( ! (ROFF_CALLABLE & tokens[tok].flags)); if ( ! roffparseopts(tree, tok, &argv, argcp, argvp)) @@ -1252,6 +1232,10 @@ roff_layout(ROFFCALL_ARGS) /* +++ Begin run macro-specific hooks over argv. */ switch (tok) { + case (ROFF_Bd): + tree->literal++; + break; + case (ROFF_Sh): if (NULL == *argv) { argv--; @@ -1268,10 +1252,14 @@ roff_layout(ROFFCALL_ARGS) if (0 == tree->asec && ! (ROFFSec_NAME & tree->csec)) return(roff_err(tree, *argv, "`NAME' section " "must be first")); - if ( ! roffchecksec(tree, *argv, tree->csec)) + if ( ! roffchecksec(tree, *argv, tree->csec, 0)) return(0); tree->asec |= tree->csec; + + if ( ! roffspecial(tree, tok, p, argcp, + (const char **)argvp, 0, argv)) + return(0); break; default: break; @@ -1369,7 +1357,7 @@ roff_ordered(ROFFCALL_ARGS) * .Xr arg1 arg2 punctuation */ - if (ROFF_PRELUDE & tree->state) + if ( ! (ROFFSec_PR_Os & tree->asec)) return(roff_errp(tree, *argv, tok, ERR_NOT_PR)); first = (*argv == tree->cur); @@ -1422,6 +1410,80 @@ roff_ordered(ROFFCALL_ARGS) } +static int +macro_default(struct rofftree *tree, int tok, char *args[]) +{ + char **p; + char *argv[ROFF_MAXLINEARG]; + int i, argc[ROFF_MAXLINEARG]; + + if ( ! roffparseopts(tree, tok, &args, argc, argv)) + return(0); + + if ( ! (ROFF_PARSED & tokens[tok].flags)) + return((*tree->cb.macro)(tree->arg, tok, argc, argv, 0, args)); + + p = args; + + while (*args) { + c = rofffindcallable(*args); + if (ROFF_MAX == c) { + if (roffispunct(*args)) { + + + } + } + + if (ROFF_MAX != (c = rofffindcallable(*argv))) { + if ( ! (ROFF_LSCOPE & tokens[tok].flags)) + if ( ! (*tree->cb.roffout)(tree->arg, tok)) + return(0); + + if ( ! roffcall(tree, c, argv)) + return(0); + if (ROFF_LSCOPE & tokens[tok].flags) + if ( ! (*tree->cb.roffout)(tree->arg, tok)) + return(0); + break; + } + + if ( ! roffispunct(*argv)) { + if ( ! roffdata(tree, i++, *argv++)) + return(0); + continue; + } + + i = 1; + for (j = 0; argv[j]; j++) + if ( ! roffispunct(argv[j])) + break; + + if (argv[j]) { + if (ROFF_LSCOPE & tokens[tok].flags) { + if ( ! roffdata(tree, 0, *argv++)) + return(0); + continue; + } + if ( ! (*tree->cb.roffout)(tree->arg, tok)) + return(0); + if ( ! roffdata(tree, 0, *argv++)) + return(0); + if ( ! (*tree->cb.roffin)(tree->arg, tok, + argcp, + (const char **)argvp)) + return(0); + + i = 0; + continue; + } + + if ( ! (*tree->cb.roffout)(tree->arg, tok)) + return(0); + break; + } +} + + /* ARGSUSED */ static int roff_text(ROFFCALL_ARGS) @@ -1441,7 +1503,7 @@ roff_text(ROFFCALL_ARGS) * v W f ; */ - if (ROFF_PRELUDE & tree->state) + if ( ! (ROFFSec_PR_Os & tree->asec)) return(roff_errp(tree, *argv, tok, ERR_NOT_PR)); first = (*argv == tree->cur); @@ -1536,6 +1598,14 @@ static int roff_noop(ROFFCALL_ARGS) { + switch (tok) { + case (ROFF_Ed): + tree->literal--; + break; + default: + break; + } + return(1); } @@ -1549,6 +1619,7 @@ roff_depr(ROFFCALL_ARGS) } +/* FIXME: push this into the filter. */ static int roff_warnp(const struct rofftree *tree, const char *pos, int tok, enum rofferr type) @@ -1583,6 +1654,7 @@ roff_warn(const struct rofftree *tree, const char *pos } +/* FIXME: push this into the filter. */ static int roff_errp(const struct rofftree *tree, const char *pos, int tok, enum rofferr type)