diff options
-rw-r--r-- | macro.c | 172 | ||||
-rw-r--r-- | mdoc.c | 19 | ||||
-rw-r--r-- | mdoc.h | 29 | ||||
-rw-r--r-- | mdocml.c | 42 | ||||
-rw-r--r-- | private.h | 15 | ||||
-rw-r--r-- | strings.c | 193 |
6 files changed, 435 insertions, 35 deletions
@@ -20,11 +20,15 @@ #include <ctype.h> #include <stdlib.h> #include <stdio.h> +#include <string.h> #include "private.h" #define _CC(p) ((const char **)p) +static int xstrlcat(char *, const char *, size_t); +static int xstrlcpy(char *, const char *, size_t); +static int xstrcmp(const char *, const char *); static int append_text(struct mdoc *, int, int, int, char *[]); static int append_scoped(struct mdoc *, int, @@ -81,10 +85,25 @@ static int append_scoped(struct mdoc *mdoc, int tok, int pos, int sz, char *args[]) { + enum mdoc_sec sec; + + if (0 == sz) + return(mdoc_err(mdoc, tok, pos, ERR_ARGS_GE1)); switch (tok) { /* ======= ADD MORE MACRO CHECKS BELOW. ======= */ case (MDOC_Sh): + sec = mdoc_atosec((size_t)sz, _CC(args)); + if (SEC_CUSTOM != sec && sec < mdoc->sec_lastn) + if ( ! mdoc_warn(mdoc, tok, pos, WARN_SEC_OO)) + return(0); + + if (SEC_BODY == mdoc->sec_last && SEC_NAME != sec) + return(mdoc_err(mdoc, tok, pos, ERR_SEC_NAME)); + + if (SEC_CUSTOM != sec) + mdoc->sec_lastn = sec; + mdoc->sec_last = sec; break; case (MDOC_Ss): break; @@ -166,7 +185,7 @@ append_text(struct mdoc *mdoc, int tok, int -macro_text(struct mdoc *mdoc, int tok, int ppos, int *pos, char *buf) +macro_text(MACRO_PROT_ARGS) { int lastarg, c, lasttok, lastpunct, j; char *args[MDOC_LINEARG_MAX], *p; @@ -175,6 +194,9 @@ macro_text(struct mdoc *mdoc, int tok, int ppos, int *pos, char *buf) lastpunct = 0; j = 0; + if (SEC_PROLOGUE == mdoc->sec_lastn) + return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE)); + again: lastarg = *pos; @@ -224,19 +246,131 @@ again: int -macro_scoped_implicit(struct mdoc *mdoc, - int tok, int ppos, int *pos, char *buf) +macro_prologue_dtitle(MACRO_PROT_ARGS) +{ + int c, lastarg, j; + char *args[MDOC_LINEARG_MAX]; + + if (SEC_PROLOGUE != mdoc->sec_lastn) + return(mdoc_err(mdoc, tok, ppos, ERR_SEC_NPROLOGUE)); + if (0 == mdoc->meta.date) + return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_OO)); + if (mdoc->meta.title[0]) + return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_REP)); + + j = -1; + +again: + lastarg = *pos; + c = args_next(mdoc, tok, pos, buf, &args[++j]); + + if (0 == c) { + mdoc->sec_lastn = mdoc->sec_last = SEC_BODY; /* FIXME */ + if (mdoc->meta.title) + return(1); + if ( ! mdoc_warn(mdoc, tok, ppos, WARN_ARGS_GE1)) + return(0); + (void)xstrlcpy(mdoc->meta.title, + "UNTITLED", META_TITLE_SZ); + return(1); + } else if (-1 == c) + return(0); + + if (MDOC_MAX != mdoc_find(mdoc, args[j]) && ! mdoc_warn + (mdoc, tok, lastarg, WARN_SYNTAX_MACLIKE)) + return(0); + + if (0 == j) { + if (xstrlcpy(mdoc->meta.title, args[0], META_TITLE_SZ)) + goto again; + return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGS)); + + } else if (1 == j) { + mdoc->meta.msec = mdoc_atomsec(args[1]); + if (MSEC_DEFAULT != mdoc->meta.msec) + goto again; + return(mdoc_err(mdoc, tok, -1, ERR_SYNTAX_ARGS)); + + } else if (2 == j) { + mdoc->meta.vol = mdoc_atovol(args[2]); + if (VOL_DEFAULT != mdoc->meta.vol) + goto again; + mdoc->meta.arch = mdoc_atoarch(args[2]); + if (ARCH_DEFAULT != mdoc->meta.arch) + goto again; + return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGS)); + } + + return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY)); +} + + +int +macro_prologue_ddate(MACRO_PROT_ARGS) +{ + int c, lastarg, j; + char *args[MDOC_LINEARG_MAX], date[64]; + + if (SEC_PROLOGUE != mdoc->sec_lastn) + return(mdoc_err(mdoc, tok, ppos, ERR_SEC_NPROLOGUE)); + if (mdoc->meta.title[0]) + return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_OO)); + if (mdoc->meta.date) + return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_REP)); + + j = -1; + date[0] = 0; + +again: + + lastarg = *pos; + c = args_next(mdoc, tok, pos, buf, &args[++j]); + if (0 == c) { + if (mdoc->meta.date) + return(1); + mdoc->meta.date = mdoc_atotime(date); + if (mdoc->meta.date) + return(1); + return(mdoc_err(mdoc, tok, ppos, ERR_SYNTAX_ARGS)); + } else if (-1 == c) + return(0); + + if (MDOC_MAX != mdoc_find(mdoc, args[j]) && ! mdoc_warn + (mdoc, tok, lastarg, WARN_SYNTAX_MACLIKE)) + return(0); + + if (0 == j) { + if (xstrcmp("$Mdocdate$", args[j])) { + mdoc->meta.date = time(NULL); + goto again; + } else if (xstrcmp("$Mdocdate:", args[j])) + goto again; + } else if (4 == j) + if ( ! xstrcmp("$", args[j])) + goto again; + + if ( ! xstrlcat(date, args[j], sizeof(date))) + return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGS)); + if ( ! xstrlcat(date, " ", sizeof(date))) + return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGS)); + + goto again; + /* NOTREACHED */ +} + + +int +macro_scoped_implicit(MACRO_PROT_ARGS) { int t, c, lastarg, j; char *args[MDOC_LINEARG_MAX]; struct mdoc_node *n; - /* - * Look for an implicit parent. - */ - assert( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)); + if (SEC_PROLOGUE == mdoc->sec_lastn) + return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE)); + /* LINTED */ for (n = mdoc->last; n; n = n->parent) { if (MDOC_BLOCK != n->type) @@ -281,3 +415,27 @@ again: /* NOTREACHED */ } + + +static int +xstrcmp(const char *p1, const char *p2) +{ + + return(0 == strcmp(p1, p2)); +} + + +static int +xstrlcat(char *dst, const char *src, size_t sz) +{ + + return(strlcat(dst, src, sz) < sz); +} + + +static int +xstrlcpy(char *dst, const char *src, size_t sz) +{ + + return(strlcpy(dst, src, sz) < sz); +} @@ -26,10 +26,6 @@ #include "private.h" -extern int macro_text(struct mdoc *, int, int, int *, char *); -extern int macro_scoped_implicit(struct mdoc *, - int, int, int *, char *); - const char *const __mdoc_macronames[MDOC_MAX] = { "\\\"", "Dd", "Dt", "Os", "Sh", "Ss", "Pp", "D1", @@ -88,8 +84,8 @@ const char *const __mdoc_argnames[MDOC_ARG_MAX] = { const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { { NULL, 0 }, /* \" */ - { NULL, 0 }, /* Dd */ - { NULL, 0 }, /* Dt */ + { macro_prologue_ddate, 0 }, /* Dd */ + { macro_prologue_dtitle, 0 }, /* Dt */ { NULL, 0 }, /* Os */ { macro_scoped_implicit, 0 }, /* Sh */ { macro_scoped_implicit, 0 }, /* Ss */ @@ -310,12 +306,7 @@ mdoc_parseln(struct mdoc *mdoc, char *buf) while (buf[i] && isspace(buf[i])) i++; - if (NULL == (mdoc_macros[c].fp)) { - (void)mdoc_err(mdoc, c, 1, ERR_MACRO_NOTSUP); - return(0); - } - - return((*mdoc_macros[c].fp)(mdoc, c, 1, &i, buf)); + return(mdoc_macro(mdoc, c, 1, &i, buf)); } @@ -363,7 +354,9 @@ mdoc_macro(struct mdoc *mdoc, int tok, int ppos, int *pos, char *buf) if (NULL == (mdoc_macros[tok].fp)) { (void)mdoc_err(mdoc, tok, ppos, ERR_MACRO_NOTSUP); return(0); - } else if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) { + } + + if (1 != ppos && ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) { (void)mdoc_err(mdoc, tok, ppos, ERR_MACRO_NOTCALL); return(0); } @@ -194,15 +194,23 @@ enum mdoc_err { ERR_SYNTAX_QUOTE, ERR_SYNTAX_WS, + ERR_SYNTAX_ARGS, ERR_MACRO_NOTSUP, ERR_MACRO_NOTCALL, ERR_SCOPE_BREAK, - ERR_ARGS_GE1 + ERR_SEC_PROLOGUE, + ERR_SEC_NPROLOGUE, + ERR_SEC_PROLOGUE_OO, + ERR_SEC_PROLOGUE_REP, + ERR_SEC_NAME, + ERR_ARGS_GE1, + ERR_ARGS_MANY }; enum mdoc_warn { WARN_SYNTAX_WS_EOLN, WARN_SYNTAX_MACLIKE, + WARN_SEC_OO, WARN_ARGS_GE1 }; @@ -221,6 +229,7 @@ enum mdoc_type { }; enum mdoc_msec { + MSEC_DEFAULT = 0, MSEC_1, MSEC_2, MSEC_3, @@ -238,12 +247,12 @@ enum mdoc_msec { MSEC_n, MSEC_unass, MSEC_draft, - MSEC_paper, - MSEC_NONE + MSEC_paper }; enum mdoc_sec { - SEC_PROLOGUE, + SEC_PROLOGUE = 0, + SEC_BODY, SEC_NAME, SEC_SYNOPSIS, SEC_DESCRIPTION, @@ -263,6 +272,7 @@ enum mdoc_sec { }; enum mdoc_vol { + VOL_DEFAULT = 0, VOL_AMD, VOL_IND, VOL_KM, @@ -271,11 +281,11 @@ enum mdoc_vol { VOL_PS1, VOL_SMM, VOL_URM, - VOL_USD, - VOL_DEFAULT + VOL_USD }; enum mdoc_arch { + ARCH_DEFAULT = 0, ARCH_alpha, ARCH_amd64, ARCH_amiga, @@ -300,15 +310,16 @@ enum mdoc_arch { ARCH_sparc64, ARCH_sun3, ARCH_vax, - ARCH_zaurus, - ARCH_DEFAULT + ARCH_zaurus }; struct mdoc_meta { enum mdoc_msec msec; enum mdoc_vol vol; enum mdoc_arch arch; - struct tm tm; + time_t date; +#define META_TITLE_SZ (64) + char title[META_TITLE_SZ]; }; struct mdoc_text { @@ -265,9 +265,9 @@ parse_begin(struct md_parse *p) for (i = 0; i < sz; i++) { if ('\n' != p->buf[i]) { if (pos < sizeof(line)) { - /* LINTED */ - sv[pos] = p->buf[i]; - line[pos++] = p->buf[i]; + sv[(int)pos] = p->buf[(int)i]; + line[(int)pos++] = + p->buf[(int)i]; continue; } warnx("%s: line %d too long", @@ -306,6 +306,9 @@ msg_err(void *arg, int tok, int col, enum mdoc_err type) case (ERR_SYNTAX_WS): lit = "syntax: whitespace in argument"; break; + case (ERR_SYNTAX_ARGS): + fmt = "syntax: macro `%s' arguments malformed"; + break; case (ERR_SCOPE_BREAK): /* Which scope is broken? */ fmt = "macro `%s' breaks prior explicit scope"; @@ -316,9 +319,27 @@ msg_err(void *arg, int tok, int col, enum mdoc_err type) case (ERR_MACRO_NOTCALL): fmt = "macro `%s' not callable"; break; + case (ERR_SEC_PROLOGUE): + fmt = "macro `%s' cannot be called in the prologue"; + break; + case (ERR_SEC_NPROLOGUE): + fmt = "macro `%s' called outside of prologue"; + break; case (ERR_ARGS_GE1): fmt = "macro `%s' expects one or more arguments"; break; + case (ERR_ARGS_MANY): + fmt = "macro `%s' has too many arguments"; + break; + case (ERR_SEC_PROLOGUE_OO): + fmt = "prologue macro `%s' is out-of-order"; + break; + case (ERR_SEC_PROLOGUE_REP): + fmt = "prologue macro `%s' repeated"; + break; + case (ERR_SEC_NAME): + lit = "`NAME' section must be first"; + break; default: abort(); /* NOTREACHED */ @@ -333,7 +354,11 @@ msg_err(void *arg, int tok, int col, enum mdoc_err type) p->name, p->lnn, lit); if (p->dbg < 1) { - (void)fprintf(stderr, " (column %d)\n", col); + if (-1 != col) + (void)fprintf(stderr, " (column %d)\n", col); + return(0); + } else if (-1 == col) { + (void)fprintf(stderr, "\nFrom: %s", p->line); return(0); } @@ -360,7 +385,11 @@ msg_msg(void *arg, int col, const char *msg) (void)printf("%s:%d: %s", p->name, p->lnn, msg); if (p->dbg < 3) { - (void)printf(" (column %d)\n", col); + if (-1 != col) + (void)printf(" (column %d)\n", col); + return; + } else if (-1 == col) { + (void)printf("\nFrom %s\n", p->line); return; } @@ -393,6 +422,9 @@ msg_warn(void *arg, int tok, int col, enum mdoc_warn type) case (WARN_SYNTAX_MACLIKE): lit = "syntax: macro-like argument"; break; + case (WARN_SEC_OO): + lit = "section is out of conventional order"; + break; case (WARN_ARGS_GE1): fmt = "macro `%s' suggests one or more arguments"; break; @@ -27,7 +27,7 @@ struct mdoc { void *htab; struct mdoc_node *last; struct mdoc_node *first; - + struct mdoc_meta meta; enum mdoc_sec sec_lastn; enum mdoc_sec sec_last; }; @@ -41,6 +41,9 @@ struct mdoc_macro { extern const struct mdoc_macro *const mdoc_macros; +#define MACRO_PROT_ARGS struct mdoc *mdoc, int tok, \ + int ppos, int *pos, char *buf + __BEGIN_DECLS int mdoc_err(struct mdoc *, int, int, enum mdoc_err); @@ -64,6 +67,16 @@ void *mdoc_hash_alloc(void); int mdoc_hash_find(const void *, const char *); void mdoc_hash_free(void *); int mdoc_isdelim(const char *); +enum mdoc_sec mdoc_atosec(size_t, const char **); +enum mdoc_msec mdoc_atomsec(const char *); +enum mdoc_vol mdoc_atovol(const char *); +enum mdoc_arch mdoc_atoarch(const char *); +time_t mdoc_atotime(const char *); + +int macro_text(MACRO_PROT_ARGS); +int macro_scoped_implicit(MACRO_PROT_ARGS); +int macro_prologue_ddate(MACRO_PROT_ARGS); +int macro_prologue_dtitle(MACRO_PROT_ARGS); __END_DECLS @@ -20,6 +20,7 @@ #include <ctype.h> #include <stdlib.h> #include <stdio.h> +#include <string.h> #include "private.h" @@ -64,3 +65,195 @@ mdoc_isdelim(const char *p) return(0); } + +enum mdoc_sec +mdoc_atosec(size_t sz, const char **p) +{ + + assert(sz > 0); + if (sz > 2) + return(SEC_CUSTOM); + if (sz == 2) { + if (0 == strcmp(*p, "RETURN") && + 0 == strcmp(*(p + 1), "VALUES")) + return(SEC_RETURN_VALUES); + if (0 == strcmp(*p, "SEE") && + 0 == strcmp(*(p + 1), "ALSO")) + return(SEC_SEE_ALSO); + return(SEC_CUSTOM); + } + + if (0 == strcmp(*p, "NAME")) + return(SEC_NAME); + else if (0 == strcmp(*p, "SYNOPSIS")) + return(SEC_SYNOPSIS); + else if (0 == strcmp(*p, "DESCRIPTION")) + return(SEC_DESCRIPTION); + else if (0 == strcmp(*p, "ENVIRONMENT")) + return(SEC_ENVIRONMENT); + else if (0 == strcmp(*p, "FILES")) + return(SEC_FILES); + else if (0 == strcmp(*p, "EXAMPLES")) + return(SEC_EXAMPLES); + else if (0 == strcmp(*p, "DIAGNOSTICS")) + return(SEC_DIAGNOSTICS); + else if (0 == strcmp(*p, "ERRORS")) + return(SEC_ERRORS); + else if (0 == strcmp(*p, "STANDARDS")) + return(SEC_STANDARDS); + else if (0 == strcmp(*p, "HISTORY")) + return(SEC_HISTORY); + else if (0 == strcmp(*p, "AUTHORS")) + return(SEC_AUTHORS); + else if (0 == strcmp(*p, "CAVEATS")) + return(SEC_CAVEATS); + else if (0 == strcmp(*p, "BUGS")) + return(SEC_BUGS); + + return(SEC_CUSTOM); +} + + +time_t +mdoc_atotime(const char *p) +{ + struct tm tm; + + if (strptime(p, "%b %d %Y", &tm)) + return(mktime(&tm)); + if (strptime(p, "%b %d, %Y", &tm)) + return(mktime(&tm)); + + return(0); +} + + +enum mdoc_msec +mdoc_atomsec(const char *p) +{ + + if (0 == strcmp(p, "1")) + return(MSEC_1); + else if (0 == strcmp(p, "2")) + return(MSEC_2); + else if (0 == strcmp(p, "3")) + return(MSEC_3); + else if (0 == strcmp(p, "3f")) + return(MSEC_3f); + else if (0 == strcmp(p, "3p")) + return(MSEC_3p); + else if (0 == strcmp(p, "4")) + return(MSEC_4); + else if (0 == strcmp(p, "5")) + return(MSEC_5); + else if (0 == strcmp(p, "6")) + return(MSEC_6); + else if (0 == strcmp(p, "7")) + return(MSEC_7); + else if (0 == strcmp(p, "8")) + return(MSEC_8); + else if (0 == strcmp(p, "9")) + return(MSEC_9); + else if (0 == strcmp(p, "X11")) + return(MSEC_X11); + else if (0 == strcmp(p, "X11R6")) + return(MSEC_X11R6); + else if (0 == strcmp(p, "local")) + return(MSEC_local); + else if (0 == strcmp(p, "n")) + return(MSEC_n); + else if (0 == strcmp(p, "unass")) + return(MSEC_unass); + else if (0 == strcmp(p, "draft")) + return(MSEC_draft); + else if (0 == strcmp(p, "paper")) + return(MSEC_paper); + + return(MSEC_DEFAULT); +} + + +enum mdoc_vol +mdoc_atovol(const char *p) +{ + + if (0 == strcmp(p, "AMD")) + return(VOL_AMD); + else if (0 == strcmp(p, "IND")) + return(VOL_IND); + else if (0 == strcmp(p, "KM")) + return(VOL_KM); + else if (0 == strcmp(p, "LOCAL")) + return(VOL_LOCAL); + else if (0 == strcmp(p, "PRM")) + return(VOL_PRM); + else if (0 == strcmp(p, "PS1")) + return(VOL_PS1); + else if (0 == strcmp(p, "SMM")) + return(VOL_SMM); + else if (0 == strcmp(p, "URM")) + return(VOL_URM); + else if (0 == strcmp(p, "USD")) + return(VOL_USD); + + return(VOL_DEFAULT); +} + + +enum mdoc_arch +mdoc_atoarch(const char *p) +{ + + if (0 == strcmp(p, "alpha")) + return(ARCH_alpha); + else if (0 == strcmp(p, "amd64")) + return(ARCH_amd64); + else if (0 == strcmp(p, "amiga")) + return(ARCH_amiga); + else if (0 == strcmp(p, "arc")) + return(ARCH_arc); + else if (0 == strcmp(p, "armish")) + return(ARCH_armish); + else if (0 == strcmp(p, "aviion")) + return(ARCH_aviion); + else if (0 == strcmp(p, "hp300")) + return(ARCH_hp300); + else if (0 == strcmp(p, "hppa")) + return(ARCH_hppa); + else if (0 == strcmp(p, "hppa64")) + return(ARCH_hppa64); + else if (0 == strcmp(p, "i386")) + return(ARCH_i386); + else if (0 == strcmp(p, "landisk")) + return(ARCH_landisk); + else if (0 == strcmp(p, "luna88k")) + return(ARCH_luna88k); + else if (0 == strcmp(p, "mac68k")) + return(ARCH_mac68k); + else if (0 == strcmp(p, "macppc")) + return(ARCH_macppc); + else if (0 == strcmp(p, "mvme68k")) + return(ARCH_mvme68k); + else if (0 == strcmp(p, "mvme88k")) + return(ARCH_mvme88k); + else if (0 == strcmp(p, "mvmeppc")) + return(ARCH_mvmeppc); + else if (0 == strcmp(p, "pmax")) + return(ARCH_pmax); + else if (0 == strcmp(p, "sgi")) + return(ARCH_sgi); + else if (0 == strcmp(p, "socppc")) + return(ARCH_socppc); + else if (0 == strcmp(p, "sparc")) + return(ARCH_sparc); + else if (0 == strcmp(p, "sparc64")) + return(ARCH_sparc64); + else if (0 == strcmp(p, "sun3")) + return(ARCH_sun3); + else if (0 == strcmp(p, "vax")) + return(ARCH_vax); + else if (0 == strcmp(p, "zaurus")) + return(ARCH_zaurus); + + return(ARCH_DEFAULT); +} |