version 1.56, 2008/12/09 19:57:26 |
version 1.61, 2008/12/10 13:15:55 |
|
|
ERR_PR_OOO, /* Prelude macro bad order. */ |
ERR_PR_OOO, /* Prelude macro bad order. */ |
ERR_PR_REP, /* Prelude macro repeated. */ |
ERR_PR_REP, /* Prelude macro repeated. */ |
ERR_NOT_PR, /* Not allowed in prelude. */ |
ERR_NOT_PR, /* Not allowed in prelude. */ |
WRN_SECORD, /* Sections out-of-order. */ |
WRN_SECORD /* Sections out-of-order. */ |
}; |
}; |
|
|
struct rofftree { |
struct rofftree { |
Line 70 struct rofftree { |
|
Line 70 struct rofftree { |
|
char os[64]; /* `Os' results. */ |
char os[64]; /* `Os' results. */ |
char title[64]; /* `Dt' results. */ |
char title[64]; /* `Dt' results. */ |
enum roffmsec section; |
enum roffmsec section; |
char volume[64]; /* `Dt' results. */ |
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. */ |
struct roffcb cb; /* Callbacks. */ |
void *arg; /* Callbacks' arg. */ |
void *arg; /* Callbacks' arg. */ |
int csec; /* Current section. */ |
int csec; /* Current section. */ |
Line 100 static int rofffindarg(const char *); |
|
Line 94 static int rofffindarg(const char *); |
|
static int rofffindcallable(const char *); |
static int rofffindcallable(const char *); |
static int roffispunct(const char *); |
static int roffispunct(const char *); |
static int roffchecksec(struct rofftree *, |
static int roffchecksec(struct rofftree *, |
const char *, int); |
const char *, int, int); |
static int roffargs(const struct rofftree *, |
static int roffargs(const struct rofftree *, |
int, char *, char **); |
int, char *, char **); |
static int roffargok(int, int); |
static int roffargok(int, int); |
Line 140 roff_free(struct rofftree *tree, int flush) |
|
Line 134 roff_free(struct rofftree *tree, int flush) |
|
|
|
error = 1; |
error = 1; |
|
|
if (ROFF_PRELUDE & tree->state) { |
if ( ! (ROFFSec_NAME & tree->asec)) { |
(void)roff_err(tree, NULL, "prelude never finished"); |
|
goto end; |
|
} else if ( ! (ROFFSec_NAME & tree->asec)) { |
|
(void)roff_err(tree, NULL, "missing `NAME' section"); |
(void)roff_err(tree, NULL, "missing `NAME' section"); |
goto end; |
goto end; |
} else if ( ! (ROFFSec_NMASK & tree->asec)) |
} else if ( ! (ROFFSec_NMASK & tree->asec)) |
Line 164 roff_free(struct rofftree *tree, int flush) |
|
Line 155 roff_free(struct rofftree *tree, int flush) |
|
goto end; |
goto end; |
} |
} |
|
|
if ( ! (*tree->cb.rofftail)(tree->arg)) |
if ( ! (*tree->cb.rofftail)(tree->arg, &tree->tm, |
|
tree->os, tree->title, |
|
tree->section, tree->volume)) |
goto end; |
goto end; |
|
|
error = 0; |
error = 0; |
Line 191 roff_alloc(const struct roffcb *cb, void *args) |
|
Line 184 roff_alloc(const struct roffcb *cb, void *args) |
|
if (NULL == (tree = calloc(1, sizeof(struct rofftree)))) |
if (NULL == (tree = calloc(1, sizeof(struct rofftree)))) |
err(1, "calloc"); |
err(1, "calloc"); |
|
|
tree->state = ROFF_PRELUDE; |
|
tree->arg = args; |
tree->arg = args; |
tree->section = ROFF_MSEC_MAX; |
tree->section = ROFF_MSEC_MAX; |
|
|
Line 224 textparse(struct rofftree *tree, char *buf) |
|
Line 216 textparse(struct rofftree *tree, char *buf) |
|
|
|
/* TODO: literal parsing. */ |
/* TODO: literal parsing. */ |
|
|
if ( ! (ROFF_BODY & tree->state)) |
if ( ! (ROFFSec_NAME & tree->asec)) |
return(roff_err(tree, buf, "data not in body")); |
return(roff_err(tree, buf, "data before `NAME' section")); |
|
|
/* LINTED */ |
/* LINTED */ |
while (*buf) { |
while (*buf) { |
Line 352 roffparse(struct rofftree *tree, char *buf) |
|
Line 344 roffparse(struct rofftree *tree, char *buf) |
|
* Prelude macros break some assumptions, so branch now. |
* Prelude macros break some assumptions, so branch now. |
*/ |
*/ |
|
|
if (ROFF_PRELUDE & tree->state) { |
if ( ! (ROFFSec_PR_Dd & tree->asec)) { |
assert(NULL == tree->last); |
assert(NULL == tree->last); |
return(roffcall(tree, tok, argvp)); |
return(roffcall(tree, tok, argvp)); |
} |
} |
|
|
assert(ROFF_BODY & tree->state); |
|
|
|
/* |
/* |
* First check that our possible parents and parent's possible |
* First check that our possible parents and parent's possible |
* children are satisfied. |
* children are satisfied. |
Line 525 rofffindtok(const char *buf) |
|
Line 515 rofffindtok(const char *buf) |
|
|
|
|
|
static int |
static int |
roffchecksec(struct rofftree *tree, const char *start, int sec) |
roffchecksec(struct rofftree *tree, |
|
const char *start, int sec, int fail) |
{ |
{ |
int prior; |
|
|
|
switch (sec) { |
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): |
case(ROFFSec_SYNOP): |
if ((prior = ROFFSec_NAME) & tree->asec) |
if (ROFFSec_NAME & tree->asec) |
return(1); |
return(1); |
break; |
break; |
case(ROFFSec_DESC): |
case(ROFFSec_DESC): |
if ((prior = ROFFSec_SYNOP) & tree->asec) |
if (ROFFSec_SYNOP & tree->asec) |
return(1); |
return(1); |
break; |
break; |
case(ROFFSec_RETVAL): |
case(ROFFSec_RETVAL): |
if ((prior = ROFFSec_DESC) & tree->asec) |
if (ROFFSec_DESC & tree->asec) |
return(1); |
return(1); |
break; |
break; |
case(ROFFSec_ENV): |
case(ROFFSec_ENV): |
if ((prior = ROFFSec_RETVAL) & tree->asec) |
if (ROFFSec_RETVAL & tree->asec) |
return(1); |
return(1); |
break; |
break; |
case(ROFFSec_FILES): |
case(ROFFSec_FILES): |
if ((prior = ROFFSec_ENV) & tree->asec) |
if (ROFFSec_ENV & tree->asec) |
return(1); |
return(1); |
break; |
break; |
case(ROFFSec_EX): |
case(ROFFSec_EX): |
if ((prior = ROFFSec_FILES) & tree->asec) |
if (ROFFSec_FILES & tree->asec) |
return(1); |
return(1); |
break; |
break; |
case(ROFFSec_DIAG): |
case(ROFFSec_DIAG): |
if ((prior = ROFFSec_EX) & tree->asec) |
if (ROFFSec_EX & tree->asec) |
return(1); |
return(1); |
break; |
break; |
case(ROFFSec_ERRS): |
case(ROFFSec_ERRS): |
if ((prior = ROFFSec_DIAG) & tree->asec) |
if (ROFFSec_DIAG & tree->asec) |
return(1); |
return(1); |
break; |
break; |
case(ROFFSec_SEEALSO): |
case(ROFFSec_SEEALSO): |
if ((prior = ROFFSec_ERRS) & tree->asec) |
if (ROFFSec_ERRS & tree->asec) |
return(1); |
return(1); |
break; |
break; |
case(ROFFSec_STAND): |
case(ROFFSec_STAND): |
if ((prior = ROFFSec_SEEALSO) & tree->asec) |
if (ROFFSec_SEEALSO & tree->asec) |
return(1); |
return(1); |
break; |
break; |
case(ROFFSec_HIST): |
case(ROFFSec_HIST): |
if ((prior = ROFFSec_STAND) & tree->asec) |
if (ROFFSec_STAND & tree->asec) |
return(1); |
return(1); |
break; |
break; |
case(ROFFSec_AUTH): |
case(ROFFSec_AUTH): |
if ((prior = ROFFSec_HIST) & tree->asec) |
if (ROFFSec_HIST & tree->asec) |
return(1); |
return(1); |
break; |
break; |
case(ROFFSec_CAVEATS): |
case(ROFFSec_CAVEATS): |
if ((prior = ROFFSec_AUTH) & tree->asec) |
if (ROFFSec_AUTH & tree->asec) |
return(1); |
return(1); |
break; |
break; |
case(ROFFSec_BUGS): |
case(ROFFSec_BUGS): |
if ((prior = ROFFSec_CAVEATS) & tree->asec) |
if (ROFFSec_CAVEATS & tree->asec) |
return(1); |
return(1); |
break; |
break; |
default: |
default: |
return(1); |
return(1); |
} |
} |
|
|
|
if (fail) |
|
return(0); |
return(roff_warnp(tree, start, ROFF_Sh, WRN_SECORD)); |
return(roff_warnp(tree, start, ROFF_Sh, WRN_SECORD)); |
} |
} |
|
|
|
|
/* FIXME: move this into literals.c (or similar). */ |
|
static int |
static int |
roffispunct(const char *p) |
roffispunct(const char *p) |
{ |
{ |
Line 918 roff_Dd(ROFFCALL_ARGS) |
|
Line 923 roff_Dd(ROFFCALL_ARGS) |
|
char *p, buf[32]; |
char *p, buf[32]; |
size_t sz; |
size_t sz; |
|
|
if (ROFF_BODY & tree->state) { |
if (ROFFSec_PR_Os & tree->asec) |
assert( ! (ROFF_PRELUDE & tree->state)); |
|
assert(ROFF_PRELUDE_Dd & tree->state); |
|
return(roff_text(tok, tree, argv, type)); |
return(roff_text(tok, tree, argv, type)); |
} |
if (ROFFSec_PR_Dd & tree->asec) |
|
|
assert(ROFF_PRELUDE & tree->state); |
|
assert( ! (ROFF_BODY & tree->state)); |
|
|
|
if (ROFF_PRELUDE_Dd & tree->state) |
|
return(roff_errp(tree, *argv, tok, ERR_PR_REP)); |
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)); |
return(roff_errp(tree, *argv, tok, ERR_PR_OOO)); |
|
|
assert(NULL == tree->last); |
assert(NULL == tree->last); |
|
|
argv++; |
argv++; |
|
tree->asec |= (tree->csec = ROFFSec_PR_Dd); |
|
|
/* |
/* |
* This is a bit complex because there are many forms the date |
* This is a bit complex because there are many forms the date |
Line 946 roff_Dd(ROFFCALL_ARGS) |
|
Line 944 roff_Dd(ROFFCALL_ARGS) |
|
t = time(NULL); |
t = time(NULL); |
if (NULL == localtime_r(&t, &tree->tm)) |
if (NULL == localtime_r(&t, &tree->tm)) |
err(1, "localtime_r"); |
err(1, "localtime_r"); |
tree->state |= ROFF_PRELUDE_Dd; |
|
return(1); |
return(1); |
} |
} |
|
|
Line 960 roff_Dd(ROFFCALL_ARGS) |
|
Line 957 roff_Dd(ROFFCALL_ARGS) |
|
continue; |
continue; |
return(roff_errp(tree, p, tok, ERR_BADARG)); |
return(roff_errp(tree, p, tok, ERR_BADARG)); |
} |
} |
if (strptime(buf, "%b%d,%Y", &tree->tm)) { |
if (strptime(buf, "%b%d,%Y", &tree->tm)) |
tree->state |= ROFF_PRELUDE_Dd; |
|
return(1); |
return(1); |
} |
|
return(roff_errp(tree, p, tok, ERR_BADARG)); |
return(roff_errp(tree, p, tok, ERR_BADARG)); |
} |
} |
|
|
Line 981 roff_Dd(ROFFCALL_ARGS) |
|
Line 976 roff_Dd(ROFFCALL_ARGS) |
|
if (NULL == strptime(buf, "%b %d %Y", &tree->tm)) |
if (NULL == strptime(buf, "%b %d %Y", &tree->tm)) |
return(roff_errp(tree, p, tok, ERR_BADARG)); |
return(roff_errp(tree, p, tok, ERR_BADARG)); |
|
|
tree->state |= ROFF_PRELUDE_Dd; |
|
return(1); |
return(1); |
} |
} |
|
|
Line 992 roff_Dt(ROFFCALL_ARGS) |
|
Line 986 roff_Dt(ROFFCALL_ARGS) |
|
{ |
{ |
size_t sz; |
size_t sz; |
|
|
if (ROFF_BODY & tree->state) { |
if (ROFFSec_PR_Os & tree->asec) |
assert( ! (ROFF_PRELUDE & tree->state)); |
|
assert(ROFF_PRELUDE_Dt & tree->state); |
|
return(roff_text(tok, tree, argv, type)); |
return(roff_text(tok, tree, argv, type)); |
} |
if (ROFFSec_PR_Dt & tree->asec) |
|
|
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) |
|
return(roff_errp(tree, *argv, tok, ERR_PR_REP)); |
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++; |
argv++; |
|
tree->asec |= (tree->csec = ROFFSec_PR_Dt); |
sz = sizeof(tree->title); |
sz = sizeof(tree->title); |
|
|
if (NULL == *argv) |
if (NULL == *argv) |
Line 1022 roff_Dt(ROFFCALL_ARGS) |
|
Line 1010 roff_Dt(ROFFCALL_ARGS) |
|
return(roff_errp(tree, *argv, tok, ERR_BADARG)); |
return(roff_errp(tree, *argv, tok, ERR_BADARG)); |
|
|
argv++; |
argv++; |
sz = sizeof(tree->volume); |
|
|
|
if (NULL == *argv) { |
if (NULL == *argv) { |
tree->volume[0] = 0; |
switch (tree->section) { |
} else if (strlcpy(tree->volume, *argv, sz) >= sz) |
case(ROFF_MSEC_1): |
return(roff_errp(tree, *argv, tok, ERR_ARGLEN)); |
/* FALLTHROUGH */ |
|
case(ROFF_MSEC_6): |
|
/* FALLTHROUGH */ |
|
case(ROFF_MSEC_7): |
|
tree->volume = ROFF_VOL_URM; |
|
break; |
|
case(ROFF_MSEC_2): |
|
/* FALLTHROUGH */ |
|
case(ROFF_MSEC_3): |
|
/* FALLTHROUGH */ |
|
case(ROFF_MSEC_3p): |
|
/* FALLTHROUGH */ |
|
case(ROFF_MSEC_4): |
|
/* FALLTHROUGH */ |
|
case(ROFF_MSEC_5): |
|
tree->volume = ROFF_VOL_PRM; |
|
break; |
|
case(ROFF_MSEC_8): |
|
tree->volume = ROFF_VOL_PRM; |
|
break; |
|
case(ROFF_MSEC_9): |
|
tree->volume = ROFF_VOL_KM; |
|
break; |
|
case(ROFF_MSEC_UNASS): |
|
/* FALLTHROUGH */ |
|
case(ROFF_MSEC_DRAFT): |
|
/* FALLTHROUGH */ |
|
case(ROFF_MSEC_PAPER): |
|
tree->volume = ROFF_VOL_NONE; |
|
break; |
|
default: |
|
abort(); |
|
/* NOTREACHED */ |
|
} |
|
} else if (ROFF_VOL_MAX == (tree->volume = roff_vol(*argv))) |
|
return(roff_errp(tree, *argv, tok, ERR_BADARG)); |
|
|
assert(NULL == tree->last); |
assert(NULL == tree->last); |
tree->state |= ROFF_PRELUDE_Dt; |
|
|
|
return(1); |
return(1); |
} |
} |
Line 1109 roff_Os(ROFFCALL_ARGS) |
|
Line 1130 roff_Os(ROFFCALL_ARGS) |
|
char *p; |
char *p; |
size_t sz; |
size_t sz; |
|
|
if (ROFF_BODY & tree->state) { |
if (ROFFSec_PR_Os & tree->asec) |
assert( ! (ROFF_PRELUDE & tree->state)); |
|
assert(ROFF_PRELUDE_Os & tree->state); |
|
return(roff_text(tok, tree, argv, type)); |
return(roff_text(tok, tree, argv, type)); |
} |
if ( ! roffchecksec(tree, *argv, ROFFSec_PR_Os, 1)) |
|
|
assert(ROFF_PRELUDE & tree->state); |
|
if ( ! (ROFF_PRELUDE_Dt & tree->state) || |
|
! (ROFF_PRELUDE_Dd & tree->state)) |
|
return(roff_errp(tree, *argv, tok, ERR_PR_OOO)); |
return(roff_errp(tree, *argv, tok, ERR_PR_OOO)); |
|
|
tree->os[0] = 0; |
|
|
|
p = *++argv; |
p = *++argv; |
sz = sizeof(tree->os); |
sz = sizeof(tree->os); |
|
tree->asec |= (tree->csec = ROFFSec_PR_Os); |
|
|
|
tree->os[0] = 0; |
|
|
while (*argv) |
while (*argv) |
if (strlcat(tree->os, *argv++, sz) >= sz) |
if (strlcat(tree->os, *argv++, sz) >= sz) |
return(roff_errp(tree, p, tok, ERR_ARGLEN)); |
return(roff_errp(tree, p, tok, ERR_ARGLEN)); |
Line 1133 roff_Os(ROFFCALL_ARGS) |
|
Line 1149 roff_Os(ROFFCALL_ARGS) |
|
if (strlcpy(tree->os, "LOCAL", sz) >= sz) |
if (strlcpy(tree->os, "LOCAL", sz) >= sz) |
return(roff_errp(tree, p, tok, ERR_ARGLEN)); |
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(ROFF_MSEC_MAX != tree->section); |
assert(0 != tree->title[0]); |
assert(0 != tree->title[0]); |
assert(0 != tree->os[0]); |
assert(0 != tree->os[0]); |
|
|
roff_layout(ROFFCALL_ARGS) |
roff_layout(ROFFCALL_ARGS) |
{ |
{ |
int i, c, argcp[ROFF_MAXLINEARG]; |
int i, c, argcp[ROFF_MAXLINEARG]; |
char *argvp[ROFF_MAXLINEARG], *p; |
char *argvp[ROFF_MAXLINEARG]; |
|
|
/* |
/* |
* The roff_layout function is for multi-line macros. A layout |
* The roff_layout function is for multi-line macros. A layout |
Line 1170 roff_layout(ROFFCALL_ARGS) |
|
Line 1182 roff_layout(ROFFCALL_ARGS) |
|
|
|
assert( ! (ROFF_CALLABLE & tokens[tok].flags)); |
assert( ! (ROFF_CALLABLE & tokens[tok].flags)); |
|
|
if (ROFF_PRELUDE & tree->state) |
if ( ! ROFFSec_NAME & tree->asec) |
return(roff_errp(tree, *argv, tok, ERR_NOT_PR)); |
return(roff_errp(tree, *argv, tok, ERR_NOT_PR)); |
|
|
if (ROFF_EXIT == type) { |
if (ROFF_EXIT == type) { |
Line 1180 roff_layout(ROFFCALL_ARGS) |
|
Line 1192 roff_layout(ROFFCALL_ARGS) |
|
return((*tree->cb.roffblkout)(tree->arg, tok)); |
return((*tree->cb.roffblkout)(tree->arg, tok)); |
} |
} |
|
|
|
argv++; |
assert( ! (ROFF_CALLABLE & tokens[tok].flags)); |
assert( ! (ROFF_CALLABLE & tokens[tok].flags)); |
|
|
p = *argv++; |
|
|
|
if ( ! roffparseopts(tree, tok, &argv, argcp, argvp)) |
if ( ! roffparseopts(tree, tok, &argv, argcp, argvp)) |
return(0); |
return(0); |
if (NULL == roffnode_new(tok, tree)) |
if (NULL == roffnode_new(tok, tree)) |
Line 1234 roff_layout(ROFFCALL_ARGS) |
|
Line 1245 roff_layout(ROFFCALL_ARGS) |
|
if (0 == tree->asec && ! (ROFFSec_NAME & tree->csec)) |
if (0 == tree->asec && ! (ROFFSec_NAME & tree->csec)) |
return(roff_err(tree, *argv, "`NAME' section " |
return(roff_err(tree, *argv, "`NAME' section " |
"must be first")); |
"must be first")); |
if ( ! roffchecksec(tree, *argv, tree->csec)) |
if ( ! roffchecksec(tree, *argv, tree->csec, 0)) |
return(0); |
return(0); |
|
|
tree->asec |= tree->csec; |
tree->asec |= tree->csec; |
Line 1335 roff_ordered(ROFFCALL_ARGS) |
|
Line 1346 roff_ordered(ROFFCALL_ARGS) |
|
* .Xr arg1 arg2 punctuation |
* .Xr arg1 arg2 punctuation |
*/ |
*/ |
|
|
if (ROFF_PRELUDE & tree->state) |
if ( ! ROFFSec_NAME & tree->asec) |
return(roff_errp(tree, *argv, tok, ERR_NOT_PR)); |
return(roff_errp(tree, *argv, tok, ERR_NOT_PR)); |
|
|
first = (*argv == tree->cur); |
first = (*argv == tree->cur); |
Line 1407 roff_text(ROFFCALL_ARGS) |
|
Line 1418 roff_text(ROFFCALL_ARGS) |
|
* <fl> v W f </fl> ; |
* <fl> v W f </fl> ; |
*/ |
*/ |
|
|
if (ROFF_PRELUDE & tree->state) |
if ( ! ROFFSec_NAME & tree->asec) |
return(roff_errp(tree, *argv, tok, ERR_NOT_PR)); |
return(roff_errp(tree, *argv, tok, ERR_NOT_PR)); |
|
|
first = (*argv == tree->cur); |
first = (*argv == tree->cur); |