version 1.29, 2008/12/01 16:14:34 |
version 1.31, 2008/12/02 00:10:37 |
|
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
* PERFORMANCE OF THIS SOFTWARE. |
* PERFORMANCE OF THIS SOFTWARE. |
*/ |
*/ |
|
#include <sys/param.h> |
|
|
#include <assert.h> |
#include <assert.h> |
#include <ctype.h> |
#include <ctype.h> |
#include <err.h> |
#include <err.h> |
Line 90 struct rofftree { |
|
Line 92 struct rofftree { |
|
struct roffnode *last; /* Last parsed node. */ |
struct roffnode *last; /* Last parsed node. */ |
char *cur; |
char *cur; |
|
|
time_t date; /* `Dd' results. */ |
struct tm tm; /* `Dd' results. */ |
char os[64]; /* `Os' results. */ |
char os[64]; /* `Os' results. */ |
char title[64]; /* `Dt' results. */ |
char title[64]; /* `Dt' results. */ |
char section[64]; /* `Dt' results. */ |
char section[64]; /* `Dt' results. */ |
Line 110 struct rofftree { |
|
Line 112 struct rofftree { |
|
static int roff_Dd(ROFFCALL_ARGS); |
static int roff_Dd(ROFFCALL_ARGS); |
static int roff_Dt(ROFFCALL_ARGS); |
static int roff_Dt(ROFFCALL_ARGS); |
static int roff_Os(ROFFCALL_ARGS); |
static int roff_Os(ROFFCALL_ARGS); |
|
static int roff_Ns(ROFFCALL_ARGS); |
|
|
static int roff_layout(ROFFCALL_ARGS); |
static int roff_layout(ROFFCALL_ARGS); |
static int roff_text(ROFFCALL_ARGS); |
static int roff_text(ROFFCALL_ARGS); |
Line 124 static void roff_warn(const struct rofftree *, |
|
Line 127 static void roff_warn(const struct rofftree *, |
|
static void roff_err(const struct rofftree *, |
static void roff_err(const struct rofftree *, |
const char *, char *, ...); |
const char *, char *, ...); |
|
|
|
static int roffpurgepunct(struct rofftree *, char **); |
static int roffscan(int, const int *); |
static int roffscan(int, const int *); |
static int rofffindtok(const char *); |
static int rofffindtok(const char *); |
static int rofffindarg(const char *); |
static int rofffindarg(const char *); |
Line 251 static const struct rofftok tokens[ROFF_MAX] = { |
|
Line 255 static const struct rofftok tokens[ROFF_MAX] = { |
|
{ roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Fx */ |
{ roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Fx */ |
{ roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Ms */ |
{ roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Ms */ |
{ NULL, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* No */ |
{ NULL, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* No */ |
{ NULL, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Ns */ |
{ roff_Ns, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Ns */ |
{ roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Nx */ |
{ roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Nx */ |
{ roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Ox */ |
{ roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED }, /* Ox */ |
{ roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Pc */ |
{ roff_text, NULL, NULL, NULL, 0, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Pc */ |
Line 397 roff_free(struct rofftree *tree, int flush) |
|
Line 401 roff_free(struct rofftree *tree, int flush) |
|
goto end; |
goto end; |
} |
} |
|
|
|
if ( ! (*tree->cb.rofftail)(tree->arg)) |
|
goto end; |
|
|
error = 0; |
error = 0; |
|
|
end: |
end: |
|
|
textparse(const struct rofftree *tree, char *buf) |
textparse(const struct rofftree *tree, char *buf) |
{ |
{ |
|
|
|
if ( ! (ROFF_BODY & tree->state)) { |
|
roff_err(tree, buf, "data not in body"); |
|
return(0); |
|
} |
return((*tree->cb.roffdata)(tree->arg, 1, buf)); |
return((*tree->cb.roffdata)(tree->arg, 1, buf)); |
} |
} |
|
|
Line 869 roffnextopt(const struct rofftree *tree, int tok, |
|
Line 880 roffnextopt(const struct rofftree *tree, int tok, |
|
|
|
|
|
static int |
static int |
|
roffpurgepunct(struct rofftree *tree, char **argv) |
|
{ |
|
int i; |
|
|
|
i = 0; |
|
while (argv[i]) |
|
i++; |
|
assert(i > 0); |
|
if ( ! roffispunct(argv[--i])) |
|
return(1); |
|
while (i >= 0 && roffispunct(argv[i])) |
|
i--; |
|
i++; |
|
|
|
/* LINTED */ |
|
while (argv[i]) |
|
if ( ! (*tree->cb.roffdata)(tree->arg, 0, argv[i++])) |
|
return(0); |
|
return(1); |
|
} |
|
|
|
|
|
static int |
roffparseopts(struct rofftree *tree, int tok, |
roffparseopts(struct rofftree *tree, int tok, |
char ***args, int *argc, char **argv) |
char ***args, int *argc, char **argv) |
{ |
{ |
Line 897 roffparseopts(struct rofftree *tree, int tok, |
|
Line 931 roffparseopts(struct rofftree *tree, int tok, |
|
static int |
static int |
roff_Dd(ROFFCALL_ARGS) |
roff_Dd(ROFFCALL_ARGS) |
{ |
{ |
|
time_t t; |
|
char *p, buf[32]; |
|
|
if (ROFF_BODY & tree->state) { |
if (ROFF_BODY & tree->state) { |
assert( ! (ROFF_PRELUDE & tree->state)); |
assert( ! (ROFF_PRELUDE & tree->state)); |
Line 915 roff_Dd(ROFFCALL_ARGS) |
|
Line 951 roff_Dd(ROFFCALL_ARGS) |
|
return(0); |
return(0); |
} |
} |
|
|
/* TODO: parse date. */ |
|
|
|
assert(NULL == tree->last); |
assert(NULL == tree->last); |
tree->state |= ROFF_PRELUDE_Dd; |
|
|
|
|
argv++; |
|
|
|
if (0 == strcmp(*argv, "$Mdocdate$")) { |
|
t = time(NULL); |
|
if (NULL == localtime_r(&t, &tree->tm)) |
|
err(1, "localtime_r"); |
|
tree->state |= ROFF_PRELUDE_Dd; |
|
return(1); |
|
} |
|
|
|
/* Build this from Mdocdate or raw date. */ |
|
|
|
buf[0] = 0; |
|
p = *argv; |
|
|
|
if (0 != strcmp(*argv, "$Mdocdate:")) { |
|
while (*argv) { |
|
if (strlcat(buf, *argv++, sizeof(buf)) |
|
< sizeof(buf)) |
|
continue; |
|
roff_err(tree, p, "bad `Dd' date"); |
|
return(0); |
|
} |
|
if (strptime(buf, "%b%d,%Y", &tree->tm)) { |
|
tree->state |= ROFF_PRELUDE_Dd; |
|
return(1); |
|
} |
|
roff_err(tree, *argv, "bad `Dd' date"); |
|
return(0); |
|
} |
|
|
|
argv++; |
|
while (*argv && **argv != '$') { |
|
if (strlcat(buf, *argv++, sizeof(buf)) |
|
>= sizeof(buf)) { |
|
roff_err(tree, p, "bad `Dd' Mdocdate"); |
|
return(0); |
|
} |
|
if (strlcat(buf, " ", sizeof(buf)) |
|
>= sizeof(buf)) { |
|
roff_err(tree, p, "bad `Dd' Mdocdate"); |
|
return(0); |
|
} |
|
} |
|
if (NULL == *argv) { |
|
roff_err(tree, p, "bad `Dd' Mdocdate"); |
|
return(0); |
|
} |
|
|
|
if (NULL == strptime(buf, "%b %d %Y", &tree->tm)) { |
|
roff_err(tree, *argv, "bad `Dd' Mdocdate"); |
|
return(0); |
|
} |
|
|
|
tree->state |= ROFF_PRELUDE_Dd; |
return(1); |
return(1); |
} |
} |
|
|
Line 946 roff_Dt(ROFFCALL_ARGS) |
|
Line 1034 roff_Dt(ROFFCALL_ARGS) |
|
return(0); |
return(0); |
} |
} |
|
|
/* TODO: parse date. */ |
argv++; |
|
if (NULL == *argv) { |
|
roff_err(tree, *argv, "`Dt' needs document title"); |
|
return(0); |
|
} else if (strlcpy(tree->title, *argv, sizeof(tree->title)) |
|
>= sizeof(tree->title)) { |
|
roff_err(tree, *argv, "`Dt' document title too long"); |
|
return(0); |
|
} |
|
|
|
argv++; |
|
if (NULL == *argv) { |
|
roff_err(tree, *argv, "`Dt' needs section"); |
|
return(0); |
|
} else if (strlcpy(tree->section, *argv, sizeof(tree->section)) |
|
>= sizeof(tree->section)) { |
|
roff_err(tree, *argv, "`Dt' section too long"); |
|
return(0); |
|
} |
|
|
|
argv++; |
|
if (NULL == *argv) { |
|
tree->volume[0] = 0; |
|
} else if (strlcpy(tree->volume, *argv, sizeof(tree->volume)) |
|
>= sizeof(tree->volume)) { |
|
roff_err(tree, *argv, "`Dt' volume too long"); |
|
return(0); |
|
} |
|
|
assert(NULL == tree->last); |
assert(NULL == tree->last); |
tree->state |= ROFF_PRELUDE_Dt; |
tree->state |= ROFF_PRELUDE_Dt; |
|
|
Line 957 roff_Dt(ROFFCALL_ARGS) |
|
Line 1072 roff_Dt(ROFFCALL_ARGS) |
|
|
|
/* ARGSUSED */ |
/* ARGSUSED */ |
static int |
static int |
|
roff_Ns(ROFFCALL_ARGS) |
|
{ |
|
int j, c, first; |
|
|
|
first = (*argv == tree->cur); |
|
|
|
argv++; |
|
|
|
if (ROFF_MAX != (c = rofffindcallable(*argv))) { |
|
if (NULL == tokens[c].cb) { |
|
roff_err(tree, *argv, "unsupported macro `%s'", |
|
toknames[c]); |
|
return(0); |
|
} |
|
if ( ! (*tree->cb.roffspecial)(tree->arg, tok)) |
|
return(0); |
|
if ( ! (*tokens[c].cb)(c, tree, argv, ROFF_ENTER)) |
|
return(0); |
|
if ( ! first) |
|
return(1); |
|
return(roffpurgepunct(tree, argv)); |
|
} |
|
|
|
if ( ! (*tree->cb.roffdata)(tree->arg, 0, *argv++)) |
|
return(0); |
|
|
|
while (*argv) { |
|
if (ROFF_MAX == (c = rofffindcallable(*argv))) { |
|
if ( ! roffispunct(*argv)) { |
|
if ( ! (*tree->cb.roffdata) |
|
(tree->arg, 1, *argv++)) |
|
return(0); |
|
continue; |
|
} |
|
|
|
/* FIXME: this is identical to that of |
|
* roff_text. */ |
|
|
|
/* See if only punctuation remains. */ |
|
|
|
for (j = 0; argv[j]; j++) |
|
if ( ! roffispunct(argv[j])) |
|
break; |
|
|
|
if (argv[j]) { |
|
if ( ! (*tree->cb.roffdata) |
|
(tree->arg, 0, *argv++)) |
|
return(0); |
|
continue; |
|
} |
|
|
|
/* Only punctuation remains. */ |
|
|
|
break; |
|
} |
|
if (NULL == tokens[c].cb) { |
|
roff_err(tree, *argv, "unsupported macro `%s'", |
|
toknames[c]); |
|
return(0); |
|
} |
|
if ( ! (*tokens[c].cb)(c, tree, argv, ROFF_ENTER)) |
|
return(0); |
|
break; |
|
} |
|
|
|
if ( ! first) |
|
return(1); |
|
return(roffpurgepunct(tree, argv)); |
|
} |
|
|
|
|
|
/* ARGSUSED */ |
|
static int |
roff_Os(ROFFCALL_ARGS) |
roff_Os(ROFFCALL_ARGS) |
{ |
{ |
|
char *p; |
|
|
if (ROFF_EXIT == type) { |
if (ROFF_BODY & tree->state) { |
return((*tree->cb.rofftail)(tree->arg)); |
|
} else if (ROFF_BODY & tree->state) { |
|
assert( ! (ROFF_PRELUDE & tree->state)); |
assert( ! (ROFF_PRELUDE & tree->state)); |
assert(ROFF_PRELUDE_Os & tree->state); |
assert(ROFF_PRELUDE_Os & tree->state); |
return(roff_text(tok, tree, argv, type)); |
return(roff_text(tok, tree, argv, type)); |
Line 975 roff_Os(ROFFCALL_ARGS) |
|
Line 1162 roff_Os(ROFFCALL_ARGS) |
|
return(0); |
return(0); |
} |
} |
|
|
/* TODO: extract OS. */ |
tree->os[0] = 0; |
|
|
|
p = *++argv; |
|
|
|
while (*argv) { |
|
if (strlcat(tree->os, *argv++, sizeof(tree->os)) |
|
< sizeof(tree->os)) |
|
continue; |
|
roff_err(tree, p, "`Os' value too long"); |
|
return(0); |
|
} |
|
|
|
if (0 == tree->os[0]) |
|
if (strlcpy(tree->os, "LOCAL", sizeof(tree->os)) |
|
>= sizeof(tree->os)) { |
|
roff_err(tree, p, "`Os' value too long"); |
|
return(0); |
|
} |
|
|
tree->state |= ROFF_PRELUDE_Os; |
tree->state |= ROFF_PRELUDE_Os; |
tree->state &= ~ROFF_PRELUDE; |
tree->state &= ~ROFF_PRELUDE; |
tree->state |= ROFF_BODY; |
tree->state |= ROFF_BODY; |
Line 1082 roff_layout(ROFFCALL_ARGS) |
|
Line 1286 roff_layout(ROFFCALL_ARGS) |
|
* a token isn't punctuation. |
* a token isn't punctuation. |
*/ |
*/ |
|
|
i = 0; |
if ( ! roffpurgepunct(tree, argv)) |
while (argv[i]) |
return(0); |
i++; |
|
|
|
assert(i > 0); |
|
if ( ! roffispunct(argv[--i])) |
|
return((*tree->cb.roffout)(tree->arg, tok)); |
|
|
|
while (i >= 0 && roffispunct(argv[i])) |
|
i--; |
|
|
|
assert(0 != i); |
|
i++; |
|
|
|
/* LINTED */ |
|
while (argv[i]) |
|
if ( ! (*tree->cb.roffdata)(tree->arg, 0, argv[i++])) |
|
return(0); |
|
|
|
return((*tree->cb.roffout)(tree->arg, tok)); |
return((*tree->cb.roffout)(tree->arg, tok)); |
} |
} |
|
|
Line 1209 roff_text(ROFFCALL_ARGS) |
|
Line 1397 roff_text(ROFFCALL_ARGS) |
|
if ( ! first) |
if ( ! first) |
return(1); |
return(1); |
|
|
/* |
return(roffpurgepunct(tree, argv)); |
* We're the line-dominant macro. Check if there's remaining |
|
* punctuation. If there is, then flush it out before exiting. |
|
*/ |
|
|
|
i = 0; |
|
while (argv[i]) |
|
i++; |
|
|
|
assert(i > 0); |
|
if ( ! roffispunct(argv[--i])) |
|
return(1); |
|
|
|
while (i >= 0 && roffispunct(argv[i])) |
|
i--; |
|
|
|
assert(0 != i); |
|
i++; |
|
|
|
/* LINTED */ |
|
while (argv[i]) |
|
if ( ! (*tree->cb.roffdata)(tree->arg, 0, argv[i++])) |
|
return(0); |
|
|
|
return(1); |
|
} |
} |
|
|
|
|