diff options
Diffstat (limited to 'usr.bin/mandoc')
-rw-r--r-- | usr.bin/mandoc/Makefile | 4 | ||||
-rw-r--r-- | usr.bin/mandoc/libmdoc.h | 5 | ||||
-rw-r--r-- | usr.bin/mandoc/main.c | 3 | ||||
-rw-r--r-- | usr.bin/mandoc/mandoc.h | 3 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc.c | 6 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc_action.c | 1063 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc_html.c | 4 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc_macro.c | 16 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc_term.c | 4 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc_validate.c | 1290 |
10 files changed, 1009 insertions, 1389 deletions
diff --git a/usr.bin/mandoc/Makefile b/usr.bin/mandoc/Makefile index 17c175ee2d5..3833770beb0 100644 --- a/usr.bin/mandoc/Makefile +++ b/usr.bin/mandoc/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.46 2010/10/15 20:45:03 schwarze Exp $ +# $OpenBSD: Makefile,v 1.47 2010/12/01 22:02:29 schwarze Exp $ .include <bsd.own.mk> @@ -12,7 +12,7 @@ CFLAGS+=-Wno-unused-parameter SRCS= roff.c mandoc.c SRCS+= mdoc_macro.c mdoc.c mdoc_hash.c mdoc_strings.c \ - mdoc_argv.c mdoc_validate.c mdoc_action.c lib.c att.c \ + mdoc_argv.c mdoc_validate.c lib.c att.c \ arch.c vol.c msec.c st.c SRCS+= man_macro.c man.c man_hash.c man_validate.c \ man_action.c man_argv.c diff --git a/usr.bin/mandoc/libmdoc.h b/usr.bin/mandoc/libmdoc.h index 2b643bdcf59..6ff3759cbe4 100644 --- a/usr.bin/mandoc/libmdoc.h +++ b/usr.bin/mandoc/libmdoc.h @@ -1,4 +1,4 @@ -/* $Id: libmdoc.h,v 1.42 2010/08/20 00:53:35 schwarze Exp $ */ +/* $Id: libmdoc.h,v 1.43 2010/12/01 22:02:29 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -128,9 +128,6 @@ const char *mdoc_a2vol(const char *); const char *mdoc_a2msec(const char *); int mdoc_valid_pre(struct mdoc *, struct mdoc_node *); int mdoc_valid_post(struct mdoc *); -int mdoc_action_pre(struct mdoc *, - struct mdoc_node *); -int mdoc_action_post(struct mdoc *); enum margverr mdoc_argv(struct mdoc *, int, enum mdoct, struct mdoc_arg **, int *, char *); void mdoc_argv_free(struct mdoc_arg *); diff --git a/usr.bin/mandoc/main.c b/usr.bin/mandoc/main.c index f30f9f7dfc7..7e9f56cd616 100644 --- a/usr.bin/mandoc/main.c +++ b/usr.bin/mandoc/main.c @@ -1,4 +1,4 @@ -/* $Id: main.c,v 1.57 2010/11/29 00:12:02 schwarze Exp $ */ +/* $Id: main.c,v 1.58 2010/12/01 22:02:29 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> @@ -147,7 +147,6 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { "unknown AT&T UNIX version", "bad Boolean value", "unknown font", - "unknown library specifier", "unknown standard specifier", "bad width argument", diff --git a/usr.bin/mandoc/mandoc.h b/usr.bin/mandoc/mandoc.h index 446341aebf0..aa7a04de05e 100644 --- a/usr.bin/mandoc/mandoc.h +++ b/usr.bin/mandoc/mandoc.h @@ -1,4 +1,4 @@ -/* $Id: mandoc.h,v 1.22 2010/11/29 00:12:02 schwarze Exp $ */ +/* $Id: mandoc.h,v 1.23 2010/12/01 22:02:29 schwarze Exp $ */ /* * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -88,7 +88,6 @@ enum mandocerr { MANDOCERR_BADATT, /* unknown AT&T UNIX version */ MANDOCERR_BADBOOL, /* bad Boolean value */ MANDOCERR_BADFONT, /* unknown font */ - MANDOCERR_BADLIB, /* unknown library specifier */ MANDOCERR_BADSTANDARD, /* unknown standard specifier */ MANDOCERR_BADWIDTH, /* bad width argument */ diff --git a/usr.bin/mandoc/mdoc.c b/usr.bin/mandoc/mdoc.c index 67976bfbf5d..f7b7b826ddd 100644 --- a/usr.bin/mandoc/mdoc.c +++ b/usr.bin/mandoc/mdoc.c @@ -1,4 +1,4 @@ -/* $Id: mdoc.c,v 1.69 2010/11/28 19:35:33 schwarze Exp $ */ +/* $Id: mdoc.c,v 1.70 2010/12/01 22:02:29 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> @@ -340,8 +340,6 @@ node_append(struct mdoc *mdoc, struct mdoc_node *p) if ( ! mdoc_valid_pre(mdoc, p)) return(0); - if ( ! mdoc_action_pre(mdoc, p)) - return(0); switch (p->type) { case (MDOC_HEAD): @@ -368,8 +366,6 @@ node_append(struct mdoc *mdoc, struct mdoc_node *p) case (MDOC_TEXT): if ( ! mdoc_valid_post(mdoc)) return(0); - if ( ! mdoc_action_post(mdoc)) - return(0); break; default: break; diff --git a/usr.bin/mandoc/mdoc_action.c b/usr.bin/mandoc/mdoc_action.c deleted file mode 100644 index 884900ab008..00000000000 --- a/usr.bin/mandoc/mdoc_action.c +++ /dev/null @@ -1,1063 +0,0 @@ -/* $Id: mdoc_action.c,v 1.47 2010/10/26 22:48:07 schwarze Exp $ */ -/* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#ifndef OSNAME -#include <sys/utsname.h> -#endif - -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> - -#include "mandoc.h" -#include "libmdoc.h" -#include "libmandoc.h" - -#include "out.h" -#include "term.h" -#include "tbl.h" - -/* - * FIXME: this file is deprecated. All future "actions" should be - * pushed into mdoc_validate.c. - */ - -#define POST_ARGS struct mdoc *m, struct mdoc_node *n -#define PRE_ARGS struct mdoc *m, struct mdoc_node *n - -#define NUMSIZ 32 -#define DATESIZE 32 - -struct actions { - int (*pre)(PRE_ARGS); - int (*post)(POST_ARGS); -}; - -static int concat(struct mdoc *, char *, - const struct mdoc_node *, size_t); -static inline int order_rs(enum mdoct); - -static int post_ar(POST_ARGS); -static int post_at(POST_ARGS); -static int post_bl(POST_ARGS); -static int post_bl_head(POST_ARGS); -static int post_bl_tagwidth(POST_ARGS); -static int post_bl_width(POST_ARGS); -static int post_dd(POST_ARGS); -static int post_display(POST_ARGS); -static int post_dt(POST_ARGS); -static int post_lb(POST_ARGS); -static int post_li(POST_ARGS); -static int post_nm(POST_ARGS); -static int post_os(POST_ARGS); -static int post_pa(POST_ARGS); -static int post_prol(POST_ARGS); -static int post_rs(POST_ARGS); -static int post_sh(POST_ARGS); -static int post_st(POST_ARGS); -static int post_std(POST_ARGS); - -static int pre_bd(PRE_ARGS); -static int pre_dl(PRE_ARGS); -static int pre_ts(PRE_ARGS); - -static const struct actions mdoc_actions[MDOC_MAX] = { - { NULL, NULL }, /* Ap */ - { NULL, post_dd }, /* Dd */ - { NULL, post_dt }, /* Dt */ - { NULL, post_os }, /* Os */ - { NULL, post_sh }, /* Sh */ - { NULL, NULL }, /* Ss */ - { NULL, NULL }, /* Pp */ - { NULL, NULL }, /* D1 */ - { pre_dl, post_display }, /* Dl */ - { pre_bd, post_display }, /* Bd */ - { NULL, NULL }, /* Ed */ - { NULL, post_bl }, /* Bl */ - { NULL, NULL }, /* El */ - { NULL, NULL }, /* It */ - { NULL, NULL }, /* Ad */ - { NULL, NULL }, /* An */ - { NULL, post_ar }, /* Ar */ - { NULL, NULL }, /* Cd */ - { NULL, NULL }, /* Cm */ - { NULL, NULL }, /* Dv */ - { NULL, NULL }, /* Er */ - { NULL, NULL }, /* Ev */ - { NULL, post_std }, /* Ex */ - { NULL, NULL }, /* Fa */ - { NULL, NULL }, /* Fd */ - { NULL, NULL }, /* Fl */ - { NULL, NULL }, /* Fn */ - { NULL, NULL }, /* Ft */ - { NULL, NULL }, /* Ic */ - { NULL, NULL }, /* In */ - { NULL, post_li }, /* Li */ - { NULL, NULL }, /* Nd */ - { NULL, post_nm }, /* Nm */ - { NULL, NULL }, /* Op */ - { NULL, NULL }, /* Ot */ - { NULL, post_pa }, /* Pa */ - { NULL, post_std }, /* Rv */ - { NULL, post_st }, /* St */ - { NULL, NULL }, /* Va */ - { NULL, NULL }, /* Vt */ - { NULL, NULL }, /* Xr */ - { NULL, NULL }, /* %A */ - { NULL, NULL }, /* %B */ - { NULL, NULL }, /* %D */ - { NULL, NULL }, /* %I */ - { NULL, NULL }, /* %J */ - { NULL, NULL }, /* %N */ - { NULL, NULL }, /* %O */ - { NULL, NULL }, /* %P */ - { NULL, NULL }, /* %R */ - { NULL, NULL }, /* %T */ - { NULL, NULL }, /* %V */ - { NULL, NULL }, /* Ac */ - { NULL, NULL }, /* Ao */ - { NULL, NULL }, /* Aq */ - { NULL, post_at }, /* At */ - { NULL, NULL }, /* Bc */ - { NULL, NULL }, /* Bf */ - { NULL, NULL }, /* Bo */ - { NULL, NULL }, /* Bq */ - { NULL, NULL }, /* Bsx */ - { NULL, NULL }, /* Bx */ - { NULL, NULL }, /* Db */ - { NULL, NULL }, /* Dc */ - { NULL, NULL }, /* Do */ - { NULL, NULL }, /* Dq */ - { NULL, NULL }, /* Ec */ - { NULL, NULL }, /* Ef */ - { NULL, NULL }, /* Em */ - { NULL, NULL }, /* Eo */ - { NULL, NULL }, /* Fx */ - { NULL, NULL }, /* Ms */ - { NULL, NULL }, /* No */ - { NULL, NULL }, /* Ns */ - { NULL, NULL }, /* Nx */ - { NULL, NULL }, /* Ox */ - { NULL, NULL }, /* Pc */ - { NULL, NULL }, /* Pf */ - { NULL, NULL }, /* Po */ - { NULL, NULL }, /* Pq */ - { NULL, NULL }, /* Qc */ - { NULL, NULL }, /* Ql */ - { NULL, NULL }, /* Qo */ - { NULL, NULL }, /* Qq */ - { NULL, NULL }, /* Re */ - { NULL, post_rs }, /* Rs */ - { NULL, NULL }, /* Sc */ - { NULL, NULL }, /* So */ - { NULL, NULL }, /* Sq */ - { NULL, NULL }, /* Sm */ - { NULL, NULL }, /* Sx */ - { NULL, NULL }, /* Sy */ - { NULL, NULL }, /* Tn */ - { NULL, NULL }, /* Ux */ - { NULL, NULL }, /* Xc */ - { NULL, NULL }, /* Xo */ - { NULL, NULL }, /* Fo */ - { NULL, NULL }, /* Fc */ - { NULL, NULL }, /* Oo */ - { NULL, NULL }, /* Oc */ - { NULL, NULL }, /* Bk */ - { NULL, NULL }, /* Ek */ - { NULL, NULL }, /* Bt */ - { NULL, NULL }, /* Hf */ - { NULL, NULL }, /* Fr */ - { NULL, NULL }, /* Ud */ - { NULL, post_lb }, /* Lb */ - { NULL, NULL }, /* Lp */ - { NULL, NULL }, /* Lk */ - { NULL, NULL }, /* Mt */ - { NULL, NULL }, /* Brq */ - { NULL, NULL }, /* Bro */ - { NULL, NULL }, /* Brc */ - { NULL, NULL }, /* %C */ - { NULL, NULL }, /* Es */ - { NULL, NULL }, /* En */ - { NULL, NULL }, /* Dx */ - { NULL, NULL }, /* %Q */ - { NULL, NULL }, /* br */ - { NULL, NULL }, /* sp */ - { NULL, NULL }, /* %U */ - { NULL, NULL }, /* Ta */ - { pre_ts, NULL }, /* TS */ - { NULL, NULL }, /* TE */ -}; - -#define RSORD_MAX 14 - -static const enum mdoct rsord[RSORD_MAX] = { - MDOC__A, - MDOC__T, - MDOC__B, - MDOC__I, - MDOC__J, - MDOC__R, - MDOC__N, - MDOC__V, - MDOC__P, - MDOC__Q, - MDOC__D, - MDOC__O, - MDOC__C, - MDOC__U -}; - - -int -mdoc_action_pre(struct mdoc *m, struct mdoc_node *n) -{ - - switch (n->type) { - case (MDOC_ROOT): - /* FALLTHROUGH */ - case (MDOC_TEXT): - return(1); - default: - break; - } - - if (NULL == mdoc_actions[n->tok].pre) - return(1); - return((*mdoc_actions[n->tok].pre)(m, n)); -} - - -int -mdoc_action_post(struct mdoc *m) -{ - - if (MDOC_ACTED & m->last->flags) - return(1); - m->last->flags |= MDOC_ACTED; - - switch (m->last->type) { - case (MDOC_TEXT): - /* FALLTHROUGH */ - case (MDOC_ROOT): - return(1); - default: - break; - } - - if (NULL == mdoc_actions[m->last->tok].post) - return(1); - return((*mdoc_actions[m->last->tok].post)(m, m->last)); -} - - -/* - * Concatenate sibling nodes together. All siblings must be of type - * MDOC_TEXT or an assertion is raised. Concatenation is separated by a - * single whitespace. - */ -static int -concat(struct mdoc *m, char *p, const struct mdoc_node *n, size_t sz) -{ - - assert(sz); - p[0] = '\0'; - for ( ; n; n = n->next) { - assert(MDOC_TEXT == n->type); - /* - * XXX: yes, these can technically be resized, but it's - * highly unlikely that we're going to get here, so let - * it slip for now. - */ - if (strlcat(p, n->string, sz) >= sz) { - mdoc_nmsg(m, n, MANDOCERR_MEM); - return(0); - } - if (NULL == n->next) - continue; - if (strlcat(p, " ", sz) >= sz) { - mdoc_nmsg(m, n, MANDOCERR_MEM); - return(0); - } - } - - return(1); -} - - -/* - * Macros accepting `-std' as an argument have the name of the current - * document (`Nm') filled in as the argument if it's not provided. - */ -static int -post_std(POST_ARGS) -{ - struct mdoc_node *nn; - - if (n->child) - return(1); - if (NULL == m->meta.name) - return(1); - - nn = n; - m->next = MDOC_NEXT_CHILD; - - if ( ! mdoc_word_alloc(m, n->line, n->pos, m->meta.name)) - return(0); - m->last = nn; - return(1); -} - - -/* - * The `Nm' macro's first use sets the name of the document. See also - * post_std(), etc. - */ -static int -post_nm(POST_ARGS) -{ - char buf[BUFSIZ]; - - if (m->meta.name) - return(1); - if ( ! concat(m, buf, n->child, BUFSIZ)) - return(0); - m->meta.name = mandoc_strdup(buf); - return(1); -} - - -/* - * Look up the value of `Lb' for matching predefined strings. If it has - * one, then substitute the current value for the formatted value. Note - * that the lookup may fail (we can provide arbitrary strings). - */ -/* ARGSUSED */ -static int -post_lb(POST_ARGS) -{ - const char *p; - char *buf; - size_t sz; - - assert(MDOC_TEXT == n->child->type); - p = mdoc_a2lib(n->child->string); - - if (p) { - free(n->child->string); - n->child->string = mandoc_strdup(p); - return(1); - } - - sz = strlen(n->child->string) + - 2 + strlen("\\(lqlibrary\\(rq"); - buf = mandoc_malloc(sz); - snprintf(buf, sz, "library \\(lq%s\\(rq", n->child->string); - free(n->child->string); - n->child->string = buf; - return(1); -} - - -/* - * Substitute the value of `St' for the corresponding formatted string. - * We're guaranteed that this exists (it's been verified during the - * validation phase). - */ -/* ARGSUSED */ -static int -post_st(POST_ARGS) -{ - const char *p; - - assert(MDOC_TEXT == n->child->type); - p = mdoc_a2st(n->child->string); - if (p != NULL) { - free(n->child->string); - n->child->string = mandoc_strdup(p); - } - return(1); -} - - -/* - * Look up the standard string in a table. We know that it exists from - * the validation phase, so assert on failure. If a standard key wasn't - * supplied, supply the default ``AT&T UNIX''. - */ -static int -post_at(POST_ARGS) -{ - struct mdoc_node *nn; - const char *p, *q; - char *buf; - size_t sz; - - if (n->child) { - assert(MDOC_TEXT == n->child->type); - p = mdoc_a2att(n->child->string); - if (p) { - free(n->child->string); - n->child->string = mandoc_strdup(p); - } else { - p = "AT&T UNIX "; - q = n->child->string; - sz = strlen(p) + strlen(q) + 1; - buf = mandoc_malloc(sz); - strlcpy(buf, p, sz); - strlcat(buf, q, sz); - free(n->child->string); - n->child->string = buf; - } - return(1); - } - - nn = n; - m->next = MDOC_NEXT_CHILD; - if ( ! mdoc_word_alloc(m, nn->line, nn->pos, "AT&T UNIX")) - return(0); - m->last = nn; - return(1); -} - - -/* - * Mark the current section. The ``named'' section (lastnamed) is set - * whenever the current section isn't a custom section--we use this to - * keep track of section ordering. Also check that the section is - * allowed within the document's manual section. - */ -static int -post_sh(POST_ARGS) -{ - enum mdoc_sec sec; - char buf[BUFSIZ]; - - if (MDOC_HEAD != n->type) - return(1); - - if ( ! concat(m, buf, n->child, BUFSIZ)) - return(0); - sec = mdoc_str2sec(buf); - /* - * The first section should always make us move into a non-new - * state. - */ - if (SEC_NONE == m->lastnamed || SEC_CUSTOM != sec) - m->lastnamed = sec; - - /* - * Switch the parser's SYNOPSIS mode, to be copied - * into individual nodes when creating them. - * Note that this mode can also be set and unset - * using the roff nS register. - */ - if (SEC_SYNOPSIS == sec) - m->flags |= MDOC_SYNOPSIS; - else - m->flags &= ~MDOC_SYNOPSIS; - - /* Some sections only live in certain manual sections. */ - - switch ((m->lastsec = sec)) { - case (SEC_RETURN_VALUES): - /* FALLTHROUGH */ - case (SEC_ERRORS): - assert(m->meta.msec); - if (*m->meta.msec == '2') - break; - if (*m->meta.msec == '3') - break; - if (*m->meta.msec == '9') - break; - return(mdoc_nmsg(m, n, MANDOCERR_SECMSEC)); - default: - break; - } - return(1); -} - - -/* - * Parse out the contents of `Dt'. See in-line documentation for how we - * handle the various fields of this macro. - */ -static int -post_dt(POST_ARGS) -{ - struct mdoc_node *nn; - const char *cp; - - if (m->meta.title) - free(m->meta.title); - if (m->meta.vol) - free(m->meta.vol); - if (m->meta.arch) - free(m->meta.arch); - - m->meta.title = m->meta.vol = m->meta.arch = NULL; - /* Handles: `.Dt' - * --> title = unknown, volume = local, msec = 0, arch = NULL - */ - - if (NULL == (nn = n->child)) { - /* XXX: make these macro values. */ - /* FIXME: warn about missing values. */ - m->meta.title = mandoc_strdup("UNKNOWN"); - m->meta.vol = mandoc_strdup("LOCAL"); - m->meta.msec = mandoc_strdup("1"); - return(post_prol(m, n)); - } - - /* Handles: `.Dt TITLE' - * --> title = TITLE, volume = local, msec = 0, arch = NULL - */ - - m->meta.title = mandoc_strdup - ('\0' == nn->string[0] ? "UNKNOWN" : nn->string); - - if (NULL == (nn = nn->next)) { - /* FIXME: warn about missing msec. */ - /* XXX: make this a macro value. */ - m->meta.vol = mandoc_strdup("LOCAL"); - m->meta.msec = mandoc_strdup("1"); - return(post_prol(m, n)); - } - - /* Handles: `.Dt TITLE SEC' - * --> title = TITLE, volume = SEC is msec ? - * format(msec) : SEC, - * msec = SEC is msec ? atoi(msec) : 0, - * arch = NULL - */ - - cp = mdoc_a2msec(nn->string); - if (cp) { - m->meta.vol = mandoc_strdup(cp); - m->meta.msec = mandoc_strdup(nn->string); - } else if (mdoc_nmsg(m, n, MANDOCERR_BADMSEC)) { - m->meta.vol = mandoc_strdup(nn->string); - m->meta.msec = mandoc_strdup(nn->string); - } else - return(0); - - if (NULL == (nn = nn->next)) - return(post_prol(m, n)); - - /* Handles: `.Dt TITLE SEC VOL' - * --> title = TITLE, volume = VOL is vol ? - * format(VOL) : - * VOL is arch ? format(arch) : - * VOL - */ - - cp = mdoc_a2vol(nn->string); - if (cp) { - free(m->meta.vol); - m->meta.vol = mandoc_strdup(cp); - } else { - /* FIXME: warn about bad arch. */ - cp = mdoc_a2arch(nn->string); - if (NULL == cp) { - free(m->meta.vol); - m->meta.vol = mandoc_strdup(nn->string); - } else - m->meta.arch = mandoc_strdup(cp); - } - - /* Ignore any subsequent parameters... */ - /* FIXME: warn about subsequent parameters. */ - - return(post_prol(m, n)); -} - - -/* - * Set the operating system by way of the `Os' macro. Note that if an - * argument isn't provided and -DOSNAME="\"foo\"" is provided during - * compilation, this value will be used instead of filling in "sysname - * release" from uname(). - */ -static int -post_os(POST_ARGS) -{ - char buf[BUFSIZ]; -#ifndef OSNAME - struct utsname utsname; -#endif - - free(m->meta.os); - - if ( ! concat(m, buf, n->child, BUFSIZ)) - return(0); - - /* XXX: yes, these can all be dynamically-adjusted buffers, but - * it's really not worth the extra hackery. - */ - - if ('\0' == buf[0]) { -#ifdef OSNAME - if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) { - mdoc_nmsg(m, n, MANDOCERR_MEM); - return(0); - } -#else /*!OSNAME */ - if (uname(&utsname)) { - mdoc_nmsg(m, n, MANDOCERR_UNAME); - m->meta.os = mandoc_strdup("UNKNOWN"); - return(post_prol(m, n)); - } - - if (strlcat(buf, utsname.sysname, BUFSIZ) >= BUFSIZ) { - mdoc_nmsg(m, n, MANDOCERR_MEM); - return(0); - } - if (strlcat(buf, " ", BUFSIZ) >= BUFSIZ) { - mdoc_nmsg(m, n, MANDOCERR_MEM); - return(0); - } - if (strlcat(buf, utsname.release, BUFSIZ) >= BUFSIZ) { - mdoc_nmsg(m, n, MANDOCERR_MEM); - return(0); - } -#endif /*!OSNAME*/ - } - - m->meta.os = mandoc_strdup(buf); - return(post_prol(m, n)); -} - - -/* - * Calculate the -width for a `Bl -tag' list if it hasn't been provided. - * Uses the first head macro. NOTE AGAIN: this is ONLY if the -width - * argument has NOT been provided. See post_bl_width() for converting - * the -width string. - */ -static int -post_bl_tagwidth(POST_ARGS) -{ - struct mdoc_node *nn; - size_t sz, ssz; - int i; - char buf[NUMSIZ]; - - sz = 10; - - for (nn = n->body->child; nn; nn = nn->next) { - if (MDOC_It != nn->tok) - continue; - - assert(MDOC_BLOCK == nn->type); - nn = nn->head->child; - - if (nn == NULL) - break; - - if (MDOC_TEXT == nn->type) { - sz = strlen(nn->string) + 1; - break; - } - - if (0 != (ssz = mdoc_macro2len(nn->tok))) - sz = ssz; - - break; - } - - /* Defaults to ten ens. */ - - snprintf(buf, NUMSIZ, "%zun", sz); - - /* - * We have to dynamically add this to the macro's argument list. - * We're guaranteed that a MDOC_Width doesn't already exist. - */ - - assert(n->args); - i = (int)(n->args->argc)++; - - n->args->argv = mandoc_realloc(n->args->argv, - n->args->argc * sizeof(struct mdoc_argv)); - - n->args->argv[i].arg = MDOC_Width; - n->args->argv[i].line = n->line; - n->args->argv[i].pos = n->pos; - n->args->argv[i].sz = 1; - n->args->argv[i].value = mandoc_malloc(sizeof(char *)); - n->args->argv[i].value[0] = mandoc_strdup(buf); - - /* Set our width! */ - n->data.Bl->width = n->args->argv[i].value[0]; - return(1); -} - - -/* - * Calculate the real width of a list from the -width string, which may - * contain a macro (with a known default width), a literal string, or a - * scaling width. - */ -static int -post_bl_width(POST_ARGS) -{ - size_t width; - int i; - enum mdoct tok; - char buf[NUMSIZ]; - - /* - * If the value to -width is a macro, then we re-write it to be - * the macro's width as set in share/tmac/mdoc/doc-common. - */ - - if (0 == strcmp(n->data.Bl->width, "Ds")) - width = 6; - else if (MDOC_MAX == (tok = mdoc_hash_find(n->data.Bl->width))) - return(1); - else if (0 == (width = mdoc_macro2len(tok))) - return(mdoc_nmsg(m, n, MANDOCERR_BADWIDTH)); - - /* The value already exists: free and reallocate it. */ - - assert(n->args); - - for (i = 0; i < (int)n->args->argc; i++) - if (MDOC_Width == n->args->argv[i].arg) - break; - - assert(i < (int)n->args->argc); - - snprintf(buf, NUMSIZ, "%zun", width); - free(n->args->argv[i].value[0]); - n->args->argv[i].value[0] = mandoc_strdup(buf); - - /* Set our width! */ - n->data.Bl->width = n->args->argv[i].value[0]; - return(1); -} - - -/* - * Do processing for -column lists, which can have two distinct styles - * of invocation. Merge this two styles into a consistent form. - */ -/* ARGSUSED */ -static int -post_bl_head(POST_ARGS) -{ - int i, c; - struct mdoc_node *np, *nn, *nnp; - - if (LIST_column != n->data.Bl->type) - return(1); - else if (NULL == n->child) - return(1); - - np = n->parent; - assert(np->args); - - for (c = 0; c < (int)np->args->argc; c++) - if (MDOC_Column == np->args->argv[c].arg) - break; - - assert(c < (int)np->args->argc); - assert(0 == np->args->argv[c].sz); - - /* - * Accomodate for new-style groff column syntax. Shuffle the - * child nodes, all of which must be TEXT, as arguments for the - * column field. Then, delete the head children. - */ - - np->args->argv[c].sz = (size_t)n->nchild; - np->args->argv[c].value = mandoc_malloc - ((size_t)n->nchild * sizeof(char *)); - - n->data.Bl->ncols = np->args->argv[c].sz; - n->data.Bl->cols = (const char **)np->args->argv[c].value; - - for (i = 0, nn = n->child; nn; i++) { - np->args->argv[c].value[i] = nn->string; - nn->string = NULL; - nnp = nn; - nn = nn->next; - mdoc_node_delete(NULL, nnp); - } - - n->nchild = 0; - n->child = NULL; - return(1); -} - - -static int -post_bl(POST_ARGS) -{ - - if (MDOC_HEAD == n->type) - return(post_bl_head(m, n)); - if (MDOC_BLOCK != n->type) - return(1); - - /* - * These are fairly complicated, so we've broken them into two - * functions. post_bl_tagwidth() is called when a -tag is - * specified, but no -width (it must be guessed). The second - * when a -width is specified (macro indicators must be - * rewritten into real lengths). - */ - - if (LIST_tag == n->data.Bl->type && NULL == n->data.Bl->width) { - if ( ! post_bl_tagwidth(m, n)) - return(0); - } else if (NULL != n->data.Bl->width) { - if ( ! post_bl_width(m, n)) - return(0); - } else - return(1); - - assert(n->data.Bl->width); - return(1); -} - - -/* - * The `Pa' macro defaults to a tilde if no value is provided as an - * argument. - */ -static int -post_pa(POST_ARGS) -{ - struct mdoc_node *np; - - if (n->child) - return(1); - - np = n; - m->next = MDOC_NEXT_CHILD; - if ( ! mdoc_word_alloc(m, n->line, n->pos, "~")) - return(0); - m->last = np; - return(1); -} - - -/* - * Empty `Li' macros get an empty string to make front-ends add an extra - * space. - */ -static int -post_li(POST_ARGS) -{ - struct mdoc_node *np; - - if (n->child) - return(1); - - np = n; - m->next = MDOC_NEXT_CHILD; - if ( ! mdoc_word_alloc(m, n->line, n->pos, "")) - return(0); - m->last = np; - return(1); -} - - -/* - * The `Ar' macro defaults to two strings "file ..." if no value is - * provided as an argument. - */ -static int -post_ar(POST_ARGS) -{ - struct mdoc_node *np; - - if (n->child) - return(1); - - np = n; - m->next = MDOC_NEXT_CHILD; - /* XXX: make into macro values. */ - if ( ! mdoc_word_alloc(m, n->line, n->pos, "file")) - return(0); - if ( ! mdoc_word_alloc(m, n->line, n->pos, "...")) - return(0); - m->last = np; - return(1); -} - - -/* - * Parse the date field in `Dd'. - */ -static int -post_dd(POST_ARGS) -{ - char buf[DATESIZE]; - - if (NULL == n->child) { - m->meta.date = time(NULL); - return(post_prol(m, n)); - } - - if ( ! concat(m, buf, n->child, DATESIZE)) - return(0); - - m->meta.date = mandoc_a2time - (MTIME_MDOCDATE | MTIME_CANONICAL, buf); - - if (0 == m->meta.date) { - if ( ! mdoc_nmsg(m, n, MANDOCERR_BADDATE)) - return(0); - m->meta.date = time(NULL); - } - - return(post_prol(m, n)); -} - - -/* - * Remove prologue macros from the document after they're processed. - * The final document uses mdoc_meta for these values and discards the - * originals. - */ -static int -post_prol(POST_ARGS) -{ - - mdoc_node_delete(m, n); - if (m->meta.title && m->meta.date && m->meta.os) - m->flags |= MDOC_PBODY; - return(1); -} - - -/* - * Trigger a literal context. - */ -static int -pre_dl(PRE_ARGS) -{ - - if (MDOC_BODY == n->type) - m->flags |= MDOC_LITERAL; - return(1); -} - - -static int -pre_bd(PRE_ARGS) -{ - - if (MDOC_BODY != n->type) - return(1); - - assert(n->data.Bd); - if (DISP_literal == n->data.Bd->type) - m->flags |= MDOC_LITERAL; - if (DISP_unfilled == n->data.Bd->type) - m->flags |= MDOC_LITERAL; - - return(1); -} - - -/* ARGSUSED */ -static int -pre_ts(PRE_ARGS) -{ - - if (MDOC_BLOCK == n->type) - n->data.TS = tbl_alloc(); - - return(1); -} - - -static int -post_display(POST_ARGS) -{ - - if (MDOC_BODY == n->type) - m->flags &= ~MDOC_LITERAL; - return(1); -} - - -static inline int -order_rs(enum mdoct t) -{ - int i; - - for (i = 0; i < (int)RSORD_MAX; i++) - if (rsord[i] == t) - return(i); - - abort(); - /* NOTREACHED */ -} - - -/* ARGSUSED */ -static int -post_rs(POST_ARGS) -{ - struct mdoc_node *nn, *next, *prev; - int o; - - if (MDOC_BLOCK != n->type) - return(1); - - assert(n->body->child); - for (next = NULL, nn = n->body->child->next; nn; nn = next) { - o = order_rs(nn->tok); - - /* Remove `nn' from the chain. */ - next = nn->next; - if (next) - next->prev = nn->prev; - - prev = nn->prev; - if (prev) - prev->next = nn->next; - - nn->prev = nn->next = NULL; - - /* - * Scan back until we reach a node that's ordered before - * us, then set ourselves as being the next. - */ - for ( ; prev; prev = prev->prev) - if (order_rs(prev->tok) <= o) - break; - - nn->prev = prev; - if (prev) { - if (prev->next) - prev->next->prev = nn; - nn->next = prev->next; - prev->next = nn; - continue; - } - - n->body->child->prev = nn; - nn->next = n->body->child; - n->body->child = nn; - } - return(1); -} diff --git a/usr.bin/mandoc/mdoc_html.c b/usr.bin/mandoc/mdoc_html.c index 5676c815749..a83235cd6da 100644 --- a/usr.bin/mandoc/mdoc_html.c +++ b/usr.bin/mandoc/mdoc_html.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_html.c,v 1.37 2010/10/23 23:30:41 schwarze Exp $ */ +/* $Id: mdoc_html.c,v 1.38 2010/12/01 22:02:29 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -1673,7 +1673,7 @@ mdoc_lk_pre(MDOC_ARGS) PAIR_HREF_INIT(&tag[1], nn->string); print_otag(h, TAG_A, 2, tag); - if (NULL == nn->next) + if (NULL == nn || NULL == nn->next) return(1); for (nn = nn->next; nn; nn = nn->next) diff --git a/usr.bin/mandoc/mdoc_macro.c b/usr.bin/mandoc/mdoc_macro.c index 22af70bdab6..de16673d093 100644 --- a/usr.bin/mandoc/mdoc_macro.c +++ b/usr.bin/mandoc/mdoc_macro.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_macro.c,v 1.59 2010/10/24 18:15:43 schwarze Exp $ */ +/* $Id: mdoc_macro.c,v 1.60 2010/12/01 22:02:29 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> @@ -258,15 +258,11 @@ rew_last(struct mdoc *mdoc, const struct mdoc_node *to) while (mdoc->last != to) { if ( ! mdoc_valid_post(mdoc)) return(0); - if ( ! mdoc_action_post(mdoc)) - return(0); mdoc->last = mdoc->last->parent; assert(mdoc->last); } - if ( ! mdoc_valid_post(mdoc)) - return(0); - return(mdoc_action_post(mdoc)); + return(mdoc_valid_post(mdoc)); } @@ -697,10 +693,8 @@ blk_exp_close(MACRO_PROT_ARGS) if (later && MDOC_EXPLICIT & mdoc_macros[later->tok].flags) continue; - if (MDOC_CALLABLE & mdoc_macros[n->tok].flags) { - assert( ! (MDOC_ACTED & n->flags)); + if (MDOC_CALLABLE & mdoc_macros[n->tok].flags) later = n; - } } if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) { @@ -791,7 +785,7 @@ in_line(MACRO_PROT_ARGS) /* FALLTHROUGH */ case (MDOC_Fl): /* FALLTHROUGH */ - case (MDOC_Lk): + case (MDOC_Mt): /* FALLTHROUGH */ case (MDOC_Nm): /* FALLTHROUGH */ @@ -1144,7 +1138,6 @@ blk_full(MACRO_PROT_ARGS) if (MDOC_BLOCK == n->type && MDOC_EXPLICIT & mdoc_macros[n->tok].flags && ! (MDOC_VALID & n->flags)) { - assert( ! (MDOC_ACTED & n->flags)); n->pending = head; return(1); } @@ -1282,7 +1275,6 @@ blk_part_imp(MACRO_PROT_ARGS) if (MDOC_BLOCK == n->type && MDOC_EXPLICIT & mdoc_macros[n->tok].flags && ! (MDOC_VALID & n->flags)) { - assert( ! (MDOC_ACTED & n->flags)); make_pending(n, tok, m, line, ppos); if ( ! mdoc_endbody_alloc(m, line, ppos, tok, body, ENDBODY_NOSPACE)) diff --git a/usr.bin/mandoc/mdoc_term.c b/usr.bin/mandoc/mdoc_term.c index 99c696edcf9..1b519bd6a16 100644 --- a/usr.bin/mandoc/mdoc_term.c +++ b/usr.bin/mandoc/mdoc_term.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_term.c,v 1.113 2010/10/23 23:30:41 schwarze Exp $ */ +/* $Id: mdoc_term.c,v 1.114 2010/12/01 22:02:29 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> @@ -2076,7 +2076,7 @@ termp_lk_pre(DECL_ARGS) nn = sv = n->child; - if (NULL == nn->next) + if (NULL == nn || NULL == nn->next) return(1); for (nn = nn->next; nn; nn = nn->next) diff --git a/usr.bin/mandoc/mdoc_validate.c b/usr.bin/mandoc/mdoc_validate.c index 985d853fafa..6c412b47793 100644 --- a/usr.bin/mandoc/mdoc_validate.c +++ b/usr.bin/mandoc/mdoc_validate.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_validate.c,v 1.75 2010/10/26 22:48:07 schwarze Exp $ */ +/* $Id: mdoc_validate.c,v 1.76 2010/12/01 22:02:29 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -14,6 +14,10 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#ifndef OSNAME +#include <sys/utsname.h> +#endif + #include <sys/types.h> #include <assert.h> @@ -22,16 +26,24 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include "mandoc.h" #include "libmdoc.h" #include "libmandoc.h" +#include "out.h" +#include "term.h" +#include "tbl.h" + /* FIXME: .Bl -diag can't have non-text children in HEAD. */ #define PRE_ARGS struct mdoc *mdoc, struct mdoc_node *n #define POST_ARGS struct mdoc *mdoc +#define NUMSIZ 32 +#define DATESIZE 32 + enum check_ineq { CHECK_LT, CHECK_GT, @@ -55,11 +67,13 @@ struct valids { static int check_count(struct mdoc *, enum mdoc_type, enum check_lvl, enum check_ineq, int); static int check_parent(PRE_ARGS, enum mdoct, enum mdoc_type); -static int check_stdarg(PRE_ARGS); -static int check_text(struct mdoc *, int, int, char *); -static int check_argv(struct mdoc *, +static void check_text(struct mdoc *, int, int, char *); +static void check_argv(struct mdoc *, struct mdoc_node *, struct mdoc_argv *); -static int check_args(struct mdoc *, struct mdoc_node *); +static void check_args(struct mdoc *, struct mdoc_node *); + +static int concat(struct mdoc *, char *, + const struct mdoc_node *, size_t); static int ebool(POST_ARGS); static int berr_ge1(POST_ARGS); @@ -80,18 +94,27 @@ static int post_an(POST_ARGS); static int post_at(POST_ARGS); static int post_bf(POST_ARGS); static int post_bl(POST_ARGS); +static int post_bl_block(POST_ARGS); +static int post_bl_block_width(POST_ARGS); +static int post_bl_block_tag(POST_ARGS); static int post_bl_head(POST_ARGS); +static int post_dd(POST_ARGS); static int post_dt(POST_ARGS); +static int post_defaults(POST_ARGS); +static int post_literal(POST_ARGS); +static int post_eoln(POST_ARGS); static int post_it(POST_ARGS); static int post_lb(POST_ARGS); static int post_nm(POST_ARGS); +static int post_os(POST_ARGS); +static int post_prol(POST_ARGS); static int post_root(POST_ARGS); static int post_rs(POST_ARGS); static int post_sh(POST_ARGS); static int post_sh_body(POST_ARGS); static int post_sh_head(POST_ARGS); static int post_st(POST_ARGS); -static int post_eoln(POST_ARGS); +static int post_std(POST_ARGS); static int post_vt(POST_ARGS); static int pre_an(PRE_ARGS); static int pre_bd(PRE_ARGS); @@ -100,76 +123,85 @@ static int pre_dd(PRE_ARGS); static int pre_display(PRE_ARGS); static int pre_dt(PRE_ARGS); static int pre_it(PRE_ARGS); +static int pre_literal(PRE_ARGS); static int pre_os(PRE_ARGS); -static int pre_pp(PRE_ARGS); -static int pre_rv(PRE_ARGS); +static int pre_par(PRE_ARGS); static int pre_sh(PRE_ARGS); static int pre_ss(PRE_ARGS); +static int pre_std(PRE_ARGS); +static int pre_ts(PRE_ARGS); static v_post posts_an[] = { post_an, NULL }; -static v_post posts_at[] = { post_at, NULL }; -static v_post posts_bd_bk[] = { hwarn_eq0, bwarn_ge1, NULL }; +static v_post posts_at[] = { post_at, post_defaults, NULL }; +static v_post posts_bd[] = { post_literal, hwarn_eq0, bwarn_ge1, NULL }; static v_post posts_bf[] = { hwarn_le1, post_bf, NULL }; +static v_post posts_bk[] = { hwarn_eq0, bwarn_ge1, NULL }; static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL }; static v_post posts_bool[] = { eerr_eq1, ebool, NULL }; static v_post posts_eoln[] = { post_eoln, NULL }; -static v_post posts_dt[] = { post_dt, NULL }; +static v_post posts_defaults[] = { post_defaults, NULL }; +static v_post posts_dd[] = { ewarn_ge1, post_dd, post_prol, NULL }; +static v_post posts_dl[] = { post_literal, bwarn_ge1, herr_eq0, NULL }; +static v_post posts_dt[] = { post_dt, post_prol, NULL }; static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL }; static v_post posts_it[] = { post_it, NULL }; static v_post posts_lb[] = { eerr_eq1, post_lb, NULL }; static v_post posts_nd[] = { berr_ge1, NULL }; static v_post posts_nm[] = { post_nm, NULL }; static v_post posts_notext[] = { ewarn_eq0, NULL }; +static v_post posts_os[] = { post_os, post_prol, NULL }; static v_post posts_rs[] = { berr_ge1, herr_eq0, post_rs, NULL }; static v_post posts_sh[] = { herr_ge1, bwarn_ge1, post_sh, NULL }; static v_post posts_sp[] = { eerr_le1, NULL }; static v_post posts_ss[] = { herr_ge1, NULL }; static v_post posts_st[] = { eerr_eq1, post_st, NULL }; +static v_post posts_std[] = { post_std, NULL }; static v_post posts_text[] = { eerr_ge1, NULL }; static v_post posts_text1[] = { eerr_eq1, NULL }; static v_post posts_vt[] = { post_vt, NULL }; static v_post posts_wline[] = { bwarn_ge1, herr_eq0, NULL }; static v_post posts_wtext[] = { ewarn_ge1, NULL }; static v_pre pres_an[] = { pre_an, NULL }; -static v_pre pres_bd[] = { pre_display, pre_bd, pre_pp, NULL }; -static v_pre pres_bl[] = { pre_bl, pre_pp, NULL }; +static v_pre pres_bd[] = { pre_display, pre_bd, pre_literal, pre_par, NULL }; +static v_pre pres_bl[] = { pre_bl, pre_par, NULL }; static v_pre pres_d1[] = { pre_display, NULL }; +static v_pre pres_dl[] = { pre_literal, pre_display, NULL }; static v_pre pres_dd[] = { pre_dd, NULL }; static v_pre pres_dt[] = { pre_dt, NULL }; static v_pre pres_er[] = { NULL, NULL }; -static v_pre pres_ex[] = { NULL, NULL }; static v_pre pres_fd[] = { NULL, NULL }; static v_pre pres_it[] = { pre_it, NULL }; static v_pre pres_os[] = { pre_os, NULL }; -static v_pre pres_pp[] = { pre_pp, NULL }; -static v_pre pres_rv[] = { pre_rv, NULL }; +static v_pre pres_pp[] = { pre_par, NULL }; static v_pre pres_sh[] = { pre_sh, NULL }; static v_pre pres_ss[] = { pre_ss, NULL }; +static v_pre pres_std[] = { pre_std, NULL }; +static v_pre pres_ts[] = { pre_ts, NULL }; const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* Ap */ - { pres_dd, posts_wtext }, /* Dd */ + { pres_dd, posts_dd }, /* Dd */ { pres_dt, posts_dt }, /* Dt */ - { pres_os, NULL }, /* Os */ + { pres_os, posts_os }, /* Os */ { pres_sh, posts_sh }, /* Sh */ { pres_ss, posts_ss }, /* Ss */ { pres_pp, posts_notext }, /* Pp */ { pres_d1, posts_wline }, /* D1 */ - { pres_d1, posts_wline }, /* Dl */ - { pres_bd, posts_bd_bk }, /* Bd */ + { pres_dl, posts_dl }, /* Dl */ + { pres_bd, posts_bd }, /* Bd */ { NULL, NULL }, /* Ed */ { pres_bl, posts_bl }, /* Bl */ { NULL, NULL }, /* El */ { pres_it, posts_it }, /* It */ { NULL, posts_text }, /* Ad */ { pres_an, posts_an }, /* An */ - { NULL, NULL }, /* Ar */ + { NULL, posts_defaults }, /* Ar */ { NULL, posts_text }, /* Cd */ { NULL, NULL }, /* Cm */ { NULL, NULL }, /* Dv */ { pres_er, posts_text }, /* Er */ { NULL, NULL }, /* Ev */ - { pres_ex, NULL }, /* Ex */ + { pres_std, posts_std }, /* Ex */ { NULL, NULL }, /* Fa */ { pres_fd, posts_wtext }, /* Fd */ { NULL, NULL }, /* Fl */ @@ -177,13 +209,13 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, posts_wtext }, /* Ft */ { NULL, posts_text }, /* Ic */ { NULL, posts_text1 }, /* In */ - { NULL, NULL }, /* Li */ + { NULL, posts_defaults }, /* Li */ { NULL, posts_nd }, /* Nd */ { NULL, posts_nm }, /* Nm */ { NULL, posts_wline }, /* Op */ { NULL, NULL }, /* Ot */ - { NULL, NULL }, /* Pa */ - { pres_rv, NULL }, /* Rv */ + { NULL, posts_defaults }, /* Pa */ + { pres_std, posts_std }, /* Rv */ { NULL, posts_st }, /* St */ { NULL, NULL }, /* Va */ { NULL, posts_vt }, /* Vt */ @@ -247,7 +279,7 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* Fc */ { NULL, NULL }, /* Oo */ { NULL, NULL }, /* Oc */ - { NULL, posts_bd_bk }, /* Bk */ + { NULL, posts_bk }, /* Bk */ { NULL, NULL }, /* Ek */ { NULL, posts_eoln }, /* Bt */ { NULL, NULL }, /* Hf */ @@ -256,7 +288,7 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, posts_lb }, /* Lb */ { NULL, posts_notext }, /* Lp */ { NULL, posts_text }, /* Lk */ - { NULL, posts_text }, /* Mt */ + { NULL, posts_defaults }, /* Mt */ { NULL, posts_wline }, /* Brq */ { NULL, NULL }, /* Bro */ { NULL, NULL }, /* Brc */ @@ -269,10 +301,29 @@ const struct valids mdoc_valids[MDOC_MAX] = { { pres_pp, posts_sp }, /* sp */ { NULL, posts_text1 }, /* %U */ { NULL, NULL }, /* Ta */ - { NULL, NULL }, /* TS */ + { pres_ts, NULL }, /* TS */ { NULL, NULL }, /* TE */ }; +#define RSORD_MAX 14 /* Number of `Rs' blocks. */ + +static const enum mdoct rsord[RSORD_MAX] = { + MDOC__A, + MDOC__T, + MDOC__B, + MDOC__I, + MDOC__J, + MDOC__R, + MDOC__N, + MDOC__V, + MDOC__P, + MDOC__Q, + MDOC__D, + MDOC__O, + MDOC__C, + MDOC__U +}; + int mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n) @@ -285,11 +336,12 @@ mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n) tp = n->string; line = n->line; pos = n->pos; - return(check_text(mdoc, line, pos, tp)); + check_text(mdoc, line, pos, tp); + return(1); } - if ( ! check_args(mdoc, n)) - return(0); + check_args(mdoc, n); + if (NULL == mdoc_valids[n->tok].pre) return(1); for (p = mdoc_valids[n->tok].pre; *p; p++) @@ -347,6 +399,9 @@ check_count(struct mdoc *m, enum mdoc_type type, if (val == m->last->nchild) return(1); break; + default: + abort(); + /* NOTREACHED */ } if (CHECK_WARN == lvl) { @@ -356,6 +411,8 @@ check_count(struct mdoc *m, enum mdoc_type type, p, val, m->last->nchild)); } + /* FIXME: THIS IS THE SAME AS THE ABOVE. */ + return(mdoc_vmsg(m, MANDOCERR_ARGCOUNT, m->last->line, m->last->pos, "require %s%d children (have %d)", @@ -441,56 +498,35 @@ hwarn_le1(POST_ARGS) return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_LT, 2)); } - -static int -check_stdarg(PRE_ARGS) -{ - - if (n->args && 1 == n->args->argc) - if (MDOC_Std == n->args->argv[0].arg) - return(1); - return(mdoc_nmsg(mdoc, n, MANDOCERR_NOARGV)); -} - - -static int +static void check_args(struct mdoc *m, struct mdoc_node *n) { int i; if (NULL == n->args) - return(1); + return; assert(n->args->argc); for (i = 0; i < (int)n->args->argc; i++) - if ( ! check_argv(m, n, &n->args->argv[i])) - return(0); - - return(1); + check_argv(m, n, &n->args->argv[i]); } - -static int +static void check_argv(struct mdoc *m, struct mdoc_node *n, struct mdoc_argv *v) { int i; for (i = 0; i < (int)v->sz; i++) - if ( ! check_text(m, v->line, v->pos, v->value[i])) - return(0); + check_text(m, v->line, v->pos, v->value[i]); - if (MDOC_Std == v->arg) { - if (v->sz || m->meta.name) - return(1); - if ( ! mdoc_nmsg(m, n, MANDOCERR_NONAME)) - return(0); - } + /* FIXME: move to post_std(). */ - return(1); + if (MDOC_Std == v->arg) + if ( ! (v->sz || m->meta.name)) + mdoc_nmsg(m, n, MANDOCERR_NONAME); } - -static int +static void check_text(struct mdoc *m, int ln, int pos, char *p) { int c; @@ -506,27 +542,21 @@ check_text(struct mdoc *m, int ln, int pos, char *p) pos += (int)sz; if ('\t' == *p) { - if (MDOC_LITERAL & m->flags) - continue; - if (mdoc_pmsg(m, ln, pos, MANDOCERR_BADTAB)) - continue; - return(0); + if ( ! (MDOC_LITERAL & m->flags)) + mdoc_pmsg(m, ln, pos, MANDOCERR_BADTAB); + continue; } - /* Check the special character. */ - - c = mandoc_special(p); - if (c) { - p += c - 1; - pos += c - 1; - } else + if (0 == (c = mandoc_special(p))) { mdoc_pmsg(m, ln, pos, MANDOCERR_BADESCAPE); - } + continue; + } - return(1); + p += c - 1; + pos += c - 1; + } } - static int check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t) { @@ -556,6 +586,7 @@ pre_display(PRE_ARGS) if (MDOC_BLOCK == node->type) if (MDOC_Bd == node->tok) break; + if (node) mdoc_nmsg(mdoc, n, MANDOCERR_NESTEDDISP); @@ -651,8 +682,7 @@ pre_bl(PRE_ARGS) dup = (NULL != n->data.Bl->offs); break; } - if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV)) - return(0); + mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV); break; default: continue; @@ -660,8 +690,8 @@ pre_bl(PRE_ARGS) /* Check: duplicate auxiliary arguments. */ - if (dup && ! mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP)) - return(0); + if (dup) + mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP); if (comp && ! dup) n->data.Bl->comp = comp; @@ -673,8 +703,7 @@ pre_bl(PRE_ARGS) /* Check: multiple list types. */ if (LIST__NONE != lt && n->data.Bl->type != LIST__NONE) - if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_LISTREP)) - return(0); + mdoc_nmsg(mdoc, n, MANDOCERR_LISTREP); /* Assign list type. */ @@ -695,8 +724,7 @@ pre_bl(PRE_ARGS) if (n->data.Bl->width || n->data.Bl->offs || n->data.Bl->comp) - if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST)) - return(0); + mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST); continue; } @@ -704,8 +732,7 @@ pre_bl(PRE_ARGS) /* Allow lists to default to LIST_item. */ if (LIST__NONE == n->data.Bl->type) { - if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE)) - return(0); + mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE); n->data.Bl->type = LIST_item; } @@ -719,9 +746,8 @@ pre_bl(PRE_ARGS) case (LIST_tag): if (n->data.Bl->width) break; - if (mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG)) - break; - return(0); + mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG); + break; case (LIST_column): /* FALLTHROUGH */ case (LIST_diag): @@ -800,8 +826,7 @@ pre_bd(PRE_ARGS) dup = (NULL != n->data.Bd->offs); break; } - if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV)) - return(0); + mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV); break; case (MDOC_Compact): comp = 1; @@ -814,8 +839,8 @@ pre_bd(PRE_ARGS) /* Check whether we have duplicates. */ - if (dup && ! mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP)) - return(0); + if (dup) + mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP); /* Make our auxiliary assignments. */ @@ -827,8 +852,7 @@ pre_bd(PRE_ARGS) /* Check whether a type has already been assigned. */ if (DISP__NONE != dt && n->data.Bd->type != DISP__NONE) - if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_DISPREP)) - return(0); + mdoc_nmsg(mdoc, n, MANDOCERR_DISPREP); /* Make our type assignment. */ @@ -837,8 +861,7 @@ pre_bd(PRE_ARGS) } if (DISP__NONE == n->data.Bd->type) { - if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_DISPTYPE)) - return(0); + mdoc_nmsg(mdoc, n, MANDOCERR_DISPTYPE); n->data.Bd->type = DISP_ragged; } @@ -874,6 +897,7 @@ pre_it(PRE_ARGS) if (MDOC_BLOCK != n->type) return(1); + /* * FIXME: this can probably be lifted if we make the It into * something else on-the-fly? @@ -891,9 +915,8 @@ pre_an(PRE_ARGS) return(1); for (i = 1; i < (int)n->args->argc; i++) - if ( ! mdoc_pmsg(mdoc, n->args->argv[i].line, - n->args->argv[i].pos, MANDOCERR_IGNARGV)) - return(0); + mdoc_pmsg(mdoc, n->args->argv[i].line, + n->args->argv[i].pos, MANDOCERR_IGNARGV); if (MDOC_Split == n->args->argv[0].arg) n->data.An.auth = AUTH_split; @@ -905,72 +928,54 @@ pre_an(PRE_ARGS) return(1); } - -static int -pre_rv(PRE_ARGS) -{ - - return(check_stdarg(mdoc, n)); -} - - static int -post_dt(POST_ARGS) +pre_std(PRE_ARGS) { - const struct mdoc_node *nn; - const char *p; - if (NULL != (nn = mdoc->last->child)) - for (p = nn->string; *p; p++) { - if (toupper((u_char)*p) == *p) - continue; - if ( ! mdoc_nmsg(mdoc, nn, MANDOCERR_UPPERCASE)) - return(0); - break; - } + if (n->args && 1 == n->args->argc) + if (MDOC_Std == n->args->argv[0].arg) + return(1); + mdoc_nmsg(mdoc, n, MANDOCERR_NOARGV); return(1); } - static int pre_dt(PRE_ARGS) { if (0 == mdoc->meta.date || mdoc->meta.os) - if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO)) - return(0); + mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO); + if (mdoc->meta.title) - if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP)) - return(0); + mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP); + return(1); } - static int pre_os(PRE_ARGS) { if (NULL == mdoc->meta.title || 0 == mdoc->meta.date) - if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO)) - return(0); + mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO); + if (mdoc->meta.os) - if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP)) - return(0); + mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP); + return(1); } - static int pre_dd(PRE_ARGS) { if (mdoc->meta.title || mdoc->meta.os) - if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO)) - return(0); + mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO); + if (mdoc->meta.date) - if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP)) - return(0); + mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP); + return(1); } @@ -1016,8 +1021,10 @@ post_bf(POST_ARGS) if (np->parent->args && np->child) { mdoc_nmsg(mdoc, np, MANDOCERR_SYNTARGVCOUNT); return(0); - } else if (NULL == np->parent->args && NULL == np->child) - return(mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE)); + } else if (NULL == np->parent->args && NULL == np->child) { + mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE); + return(1); + } /* Extract argument into data. */ @@ -1042,30 +1049,51 @@ post_bf(POST_ARGS) np->data.Bf->font = FONT_Li; else if (0 == strcmp(np->child->string, "Sy")) np->data.Bf->font = FONT_Sy; - else if ( ! mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE)) - return(0); + else + mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE); return(1); } - static int post_lb(POST_ARGS) { + const char *p; + char *buf; + size_t sz; + + assert(mdoc->last->child); + assert(MDOC_TEXT == mdoc->last->child->type); + + p = mdoc_a2lib(mdoc->last->child->string); + + /* If lookup ok, replace with table value. */ - if (mdoc_a2lib(mdoc->last->child->string)) + if (p) { + free(mdoc->last->child->string); + mdoc->last->child->string = mandoc_strdup(p); return(1); - return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADLIB)); -} + } + /* If not, use "library ``xxxx''. */ + + sz = strlen(mdoc->last->child->string) + + 2 + strlen("\\(lqlibrary\\(rq"); + buf = mandoc_malloc(sz); + snprintf(buf, sz, "library \\(lq%s\\(rq", + mdoc->last->child->string); + free(mdoc->last->child->string); + mdoc->last->child->string = buf; + return(1); +} static int post_eoln(POST_ARGS) { - if (NULL == mdoc->last->child) - return(1); - return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST)); + if (mdoc->last->child) + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST); + return(1); } @@ -1088,8 +1116,7 @@ post_vt(POST_ARGS) for (n = mdoc->last->child; n; n = n->next) if (MDOC_TEXT != n->type) - if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_CHILD)) - return(0); + mdoc_nmsg(mdoc, n, MANDOCERR_CHILD); return(1); } @@ -1098,27 +1125,128 @@ post_vt(POST_ARGS) static int post_nm(POST_ARGS) { + char buf[BUFSIZ]; - if (mdoc->last->child) + /* If no child specified, make sure we have the meta name. */ + + if (NULL == mdoc->last->child && NULL == mdoc->meta.name) { + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME); return(1); - if (mdoc->meta.name) + } else if (mdoc->meta.name) return(1); - return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME)); + + /* If no meta name, set it from the child. */ + + if ( ! concat(mdoc, buf, mdoc->last->child, BUFSIZ)) + return(0); + + mdoc->meta.name = mandoc_strdup(buf); + + return(1); +} + +static int +post_literal(POST_ARGS) +{ + + /* + * The `Dl' (note "el" not "one") and `Bd' macros unset the + * MDOC_LITERAL flag as they leave. Note that `Bd' only sets + * this in literal mode, but it doesn't hurt to just switch it + * off in general since displays can't be nested. + */ + + if (MDOC_BODY == mdoc->last->type) + mdoc->flags &= ~MDOC_LITERAL; + + return(1); } +static int +post_defaults(POST_ARGS) +{ + struct mdoc_node *nn; + + /* + * The `Ar' defaults to "file ..." if no value is provided as an + * argument; the `Mt' and `Pa' macros use "~"; the `Li' just + * gets an empty string. + */ + + if (mdoc->last->child) + return(1); + + nn = mdoc->last; + mdoc->next = MDOC_NEXT_CHILD; + + switch (nn->tok) { + case (MDOC_Ar): + if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "file")) + return(0); + if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "...")) + return(0); + break; + case (MDOC_At): + if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "AT&T")) + return(0); + if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "UNIX")) + return(0); + break; + case (MDOC_Li): + if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "")) + return(0); + break; + case (MDOC_Pa): + /* FALLTHROUGH */ + case (MDOC_Mt): + if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "~")) + return(0); + break; + default: + abort(); + /* NOTREACHED */ + } + + mdoc->last = nn; + return(1); +} static int post_at(POST_ARGS) { + const char *p, *q; + char *buf; + size_t sz; + /* + * If we have a child, look it up in the standard keys. If a + * key exist, use that instead of the child; if it doesn't, + * prefix "AT&T UNIX " to the existing data. + */ + if (NULL == mdoc->last->child) return(1); + assert(MDOC_TEXT == mdoc->last->child->type); - if (mdoc_a2att(mdoc->last->child->string)) - return(1); - return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADATT)); -} + p = mdoc_a2att(mdoc->last->child->string); + + if (p) { + free(mdoc->last->child->string); + mdoc->last->child->string = mandoc_strdup(p); + } else { + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADATT); + p = "AT&T UNIX "; + q = mdoc->last->child->string; + sz = strlen(p) + strlen(q) + 1; + buf = mandoc_malloc(sz); + strlcpy(buf, p, sz); + strlcat(buf, q, sz); + free(mdoc->last->child->string); + mdoc->last->child->string = buf; + } + return(1); +} static int post_an(POST_ARGS) @@ -1128,13 +1256,16 @@ post_an(POST_ARGS) np = mdoc->last; if (AUTH__NONE != np->data.An.auth && np->child) return(eerr_eq0(mdoc)); + /* * FIXME: make this ewarn and make sure that the front-ends * don't print the arguments. */ if (AUTH__NONE != np->data.An.auth || np->child) return(1); - return(mdoc_nmsg(mdoc, np, MANDOCERR_NOARGS)); + + mdoc_nmsg(mdoc, np, MANDOCERR_NOARGS); + return(1); } @@ -1155,7 +1286,7 @@ post_it(POST_ARGS) if (LIST__NONE == lt) { mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_LISTTYPE); - return(0); + return(1); } switch (lt) { @@ -1163,8 +1294,7 @@ post_it(POST_ARGS) if (mdoc->last->head->child) break; /* FIXME: give this a dummy value. */ - if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS)) - return(0); + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS); break; case (LIST_hang): /* FALLTHROUGH */ @@ -1174,8 +1304,7 @@ post_it(POST_ARGS) /* FALLTHROUGH */ case (LIST_diag): if (NULL == mdoc->last->head->child) - if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS)) - return(0); + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS); break; case (LIST_bullet): /* FALLTHROUGH */ @@ -1185,13 +1314,11 @@ post_it(POST_ARGS) /* FALLTHROUGH */ case (LIST_hyphen): if (NULL == mdoc->last->body->child) - if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY)) - return(0); + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY); /* FALLTHROUGH */ case (LIST_item): if (mdoc->last->head->child) - if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST)) - return(0); + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST); break; case (LIST_column): cols = (int)n->data.Bl->ncols; @@ -1199,8 +1326,7 @@ post_it(POST_ARGS) assert(NULL == mdoc->last->head->child); if (NULL == mdoc->last->body->child) - if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY)) - return(0); + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY); for (i = 0, c = mdoc->last->child; c; c = c->next) if (MDOC_BODY == c->type) @@ -1224,27 +1350,215 @@ post_it(POST_ARGS) return(1); } - static int -post_bl_head(POST_ARGS) +post_bl_block(POST_ARGS) { struct mdoc_node *n; - assert(mdoc->last->parent); - n = mdoc->last->parent; + /* + * These are fairly complicated, so we've broken them into two + * functions. post_bl_block_tag() is called when a -tag is + * specified, but no -width (it must be guessed). The second + * when a -width is specified (macro indicators must be + * rewritten into real lengths). + */ + + n = mdoc->last; - if (LIST_column == n->data.Bl->type) { - if (n->data.Bl->ncols && mdoc->last->nchild) { - mdoc_nmsg(mdoc, n, MANDOCERR_COLUMNS); + if (LIST_tag == n->data.Bl->type && + NULL == n->data.Bl->width) { + if ( ! post_bl_block_tag(mdoc)) return(0); - } + } else if (NULL != n->data.Bl->width) { + if ( ! post_bl_block_width(mdoc)) + return(0); + } else + return(1); + + assert(n->data.Bl->width); + return(1); +} + +static int +post_bl_block_width(POST_ARGS) +{ + size_t width; + int i; + enum mdoct tok; + struct mdoc_node *n; + char buf[NUMSIZ]; + + n = mdoc->last; + + /* + * Calculate the real width of a list from the -width string, + * which may contain a macro (with a known default width), a + * literal string, or a scaling width. + * + * If the value to -width is a macro, then we re-write it to be + * the macro's width as set in share/tmac/mdoc/doc-common. + */ + + if (0 == strcmp(n->data.Bl->width, "Ds")) + width = 6; + else if (MDOC_MAX == (tok = mdoc_hash_find(n->data.Bl->width))) + return(1); + else if (0 == (width = mdoc_macro2len(tok))) { + mdoc_nmsg(mdoc, n, MANDOCERR_BADWIDTH); return(1); } - /* FIXME: should be ERROR class. */ - return(hwarn_eq0(mdoc)); + /* The value already exists: free and reallocate it. */ + + assert(n->args); + + for (i = 0; i < (int)n->args->argc; i++) + if (MDOC_Width == n->args->argv[i].arg) + break; + + assert(i < (int)n->args->argc); + + snprintf(buf, NUMSIZ, "%zun", width); + free(n->args->argv[i].value[0]); + n->args->argv[i].value[0] = mandoc_strdup(buf); + + /* Set our width! */ + n->data.Bl->width = n->args->argv[i].value[0]; + return(1); } +static int +post_bl_block_tag(POST_ARGS) +{ + struct mdoc_node *n, *nn; + size_t sz, ssz; + int i; + char buf[NUMSIZ]; + + /* + * Calculate the -width for a `Bl -tag' list if it hasn't been + * provided. Uses the first head macro. NOTE AGAIN: this is + * ONLY if the -width argument has NOT been provided. See + * post_bl_block_width() for converting the -width string. + */ + + sz = 10; + n = mdoc->last; + + for (nn = n->body->child; nn; nn = nn->next) { + if (MDOC_It != nn->tok) + continue; + + assert(MDOC_BLOCK == nn->type); + nn = nn->head->child; + + if (nn == NULL) + break; + + if (MDOC_TEXT == nn->type) { + sz = strlen(nn->string) + 1; + break; + } + + if (0 != (ssz = mdoc_macro2len(nn->tok))) + sz = ssz; + + break; + } + + /* Defaults to ten ens. */ + + snprintf(buf, NUMSIZ, "%zun", sz); + + /* + * We have to dynamically add this to the macro's argument list. + * We're guaranteed that a MDOC_Width doesn't already exist. + */ + + assert(n->args); + i = (int)(n->args->argc)++; + + n->args->argv = mandoc_realloc(n->args->argv, + n->args->argc * sizeof(struct mdoc_argv)); + + n->args->argv[i].arg = MDOC_Width; + n->args->argv[i].line = n->line; + n->args->argv[i].pos = n->pos; + n->args->argv[i].sz = 1; + n->args->argv[i].value = mandoc_malloc(sizeof(char *)); + n->args->argv[i].value[0] = mandoc_strdup(buf); + + /* Set our width! */ + n->data.Bl->width = n->args->argv[i].value[0]; + return(1); +} + + +static int +post_bl_head(POST_ARGS) +{ + struct mdoc_node *np, *nn, *nnp; + int i, j; + + if (LIST_column != mdoc->last->data.Bl->type) + /* FIXME: this should be ERROR class... */ + return(hwarn_eq0(mdoc)); + + /* + * Convert old-style lists, where the column width specifiers + * trail as macro parameters, to the new-style ("normal-form") + * lists where they're argument values following -column. + */ + + /* First, disallow both types and allow normal-form. */ + + /* + * TODO: technically, we can accept both and just merge the two + * lists, but I'll leave that for another day. + */ + + if (mdoc->last->data.Bl->ncols && mdoc->last->nchild) { + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_COLUMNS); + return(0); + } else if (NULL == mdoc->last->child) + return(1); + + np = mdoc->last->parent; + assert(np->args); + + for (j = 0; j < (int)np->args->argc; j++) + if (MDOC_Column == np->args->argv[j].arg) + break; + + assert(j < (int)np->args->argc); + assert(0 == np->args->argv[j].sz); + + /* + * Accomodate for new-style groff column syntax. Shuffle the + * child nodes, all of which must be TEXT, as arguments for the + * column field. Then, delete the head children. + */ + + np->args->argv[j].sz = (size_t)mdoc->last->nchild; + np->args->argv[j].value = mandoc_malloc + ((size_t)mdoc->last->nchild * sizeof(char *)); + + mdoc->last->data.Bl->ncols = np->args->argv[j].sz; + mdoc->last->data.Bl->cols = (const char **)np->args->argv[j].value; + + for (i = 0, nn = mdoc->last->child; nn; i++) { + np->args->argv[j].value[i] = nn->string; + nn->string = NULL; + nnp = nn; + nn = nn->next; + mdoc_node_delete(NULL, nnp); + } + + mdoc->last->nchild = 0; + mdoc->last->child = NULL; + + return(1); +} static int post_bl(POST_ARGS) @@ -1253,6 +1567,8 @@ post_bl(POST_ARGS) if (MDOC_HEAD == mdoc->last->type) return(post_bl_head(mdoc)); + if (MDOC_BLOCK == mdoc->last->type) + return(post_bl_block(mdoc)); if (MDOC_BODY != mdoc->last->type) return(1); if (NULL == mdoc->last->child) @@ -1277,105 +1593,173 @@ post_bl(POST_ARGS) return(1); } - static int ebool(struct mdoc *mdoc) { - struct mdoc_node *n; - /* LINTED */ - for (n = mdoc->last->child; n; n = n->next) { - if (MDOC_TEXT != n->type) - break; - if (0 == strcmp(n->string, "on")) - continue; - if (0 == strcmp(n->string, "off")) - continue; - break; - } + if (NULL == mdoc->last->child) + return(1); + + assert(MDOC_TEXT == mdoc->last->child->type); - if (NULL == n) + if (0 == strcmp(mdoc->last->child->string, "on")) + return(1); + if (0 == strcmp(mdoc->last->child->string, "off")) return(1); - return(mdoc_nmsg(mdoc, n, MANDOCERR_BADBOOL)); -} + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL); + return(1); +} static int post_root(POST_ARGS) { + int erc; + struct mdoc_node *n; + + erc = 0; - if (NULL == mdoc->first->child) - mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCBODY); - else if ( ! (MDOC_PBODY & mdoc->flags)) + /* Check that we have a finished prologue. */ + + if ( ! (MDOC_PBODY & mdoc->flags)) { + erc++; mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCPROLOG); - else if (MDOC_BLOCK != mdoc->first->child->type) - mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCBODY); - else if (MDOC_Sh != mdoc->first->child->tok) - mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCBODY); - else - return(1); + } - return(0); -} + n = mdoc->first; + assert(n); + + /* Check that we begin with a proper `Sh'. */ + + if (NULL == n->child) { + erc++; + mdoc_nmsg(mdoc, n, MANDOCERR_NODOCBODY); + } else if (MDOC_BLOCK != n->child->type || + MDOC_Sh != n->child->tok) { + erc++; + /* Can this be lifted? See rxdebug.1 for example. */ + mdoc_nmsg(mdoc, n, MANDOCERR_NODOCBODY); + } + return(erc ? 0 : 1); +} static int post_st(POST_ARGS) { + const char *p; - if (mdoc_a2st(mdoc->last->child->string)) - return(1); - return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADSTANDARD)); -} + assert(MDOC_TEXT == mdoc->last->child->type); + p = mdoc_a2st(mdoc->last->child->string); + + if (p == NULL) { + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADSTANDARD); + mdoc_node_delete(mdoc, mdoc->last); + } else { + free(mdoc->last->child->string); + mdoc->last->child->string = mandoc_strdup(p); + } + + return(1); +} static int post_rs(POST_ARGS) { - struct mdoc_node *nn; + struct mdoc_node *nn, *next, *prev; + int i, j; if (MDOC_BODY != mdoc->last->type) return(1); - for (nn = mdoc->last->child; nn; nn = nn->next) - switch (nn->tok) { - case(MDOC__U): - /* FALLTHROUGH */ - case(MDOC__Q): - /* FALLTHROUGH */ - case(MDOC__C): - /* FALLTHROUGH */ - case(MDOC__A): - /* FALLTHROUGH */ - case(MDOC__B): - /* FALLTHROUGH */ - case(MDOC__D): - /* FALLTHROUGH */ - case(MDOC__I): - /* FALLTHROUGH */ - case(MDOC__J): - /* FALLTHROUGH */ - case(MDOC__N): - /* FALLTHROUGH */ - case(MDOC__O): - /* FALLTHROUGH */ - case(MDOC__P): - /* FALLTHROUGH */ - case(MDOC__R): - /* FALLTHROUGH */ - case(MDOC__T): - /* FALLTHROUGH */ - case(MDOC__V): - break; - default: - mdoc_nmsg(mdoc, nn, MANDOCERR_SYNTCHILD); - return(0); + /* + * Make sure only certain types of nodes are allowed within the + * the `Rs' body. Delete offending nodes and raise a warning. + * Do this before re-ordering for the sake of clarity. + */ + + next = NULL; + for (nn = mdoc->last->child; nn; nn = next) { + for (i = 0; i < RSORD_MAX; i++) + if (nn->tok == rsord[i]) + break; + + if (i < RSORD_MAX) { + next = nn->next; + continue; } + next = nn->next; + mdoc_nmsg(mdoc, nn, MANDOCERR_CHILD); + mdoc_node_delete(mdoc, nn); + } + + /* + * The full `Rs' block needs special handling to order the + * sub-elements according to `rsord'. Pick through each element + * and correctly order it. This is a insertion sort. + */ + + next = NULL; + for (nn = mdoc->last->child->next; nn; nn = next) { + /* Determine order of `nn'. */ + for (i = 0; i < RSORD_MAX; i++) + if (rsord[i] == nn->tok) + break; + + /* + * Remove `nn' from the chain. This somewhat + * repeats mdoc_node_unlink(), but since we're + * just re-ordering, there's no need for the + * full unlink process. + */ + + if (NULL != (next = nn->next)) + next->prev = nn->prev; + + if (NULL != (prev = nn->prev)) + prev->next = nn->next; + + nn->prev = nn->next = NULL; + + /* + * Scan back until we reach a node that's + * ordered before `nn'. + */ + + for ( ; prev ; prev = prev->prev) { + /* Determine order of `prev'. */ + for (j = 0; j < RSORD_MAX; j++) + if (rsord[j] == prev->tok) + break; + + if (j <= i) + break; + } + + /* + * Set `nn' back into its correct place in front + * of the `prev' node. + */ + + nn->prev = prev; + + if (prev) { + if (prev->next) + prev->next->prev = nn; + nn->next = prev->next; + prev->next = nn; + } else { + mdoc->last->child->prev = nn; + nn->next = mdoc->last->child; + mdoc->last->child = nn; + } + } + return(1); } - static int post_sh(POST_ARGS) { @@ -1388,7 +1772,6 @@ post_sh(POST_ARGS) return(1); } - static int post_sh_body(POST_ARGS) { @@ -1403,99 +1786,99 @@ post_sh_body(POST_ARGS) * children of the BODY declaration can also be "text". */ - if (NULL == (n = mdoc->last->child)) - return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC)); + if (NULL == (n = mdoc->last->child)) { + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC); + return(1); + } for ( ; n && n->next; n = n->next) { if (MDOC_ELEM == n->type && MDOC_Nm == n->tok) continue; if (MDOC_TEXT == n->type) continue; - if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC)) - return(0); + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC); } assert(n); if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok) return(1); - return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC)); -} + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC); + return(1); +} static int post_sh_head(POST_ARGS) { - char buf[BUFSIZ]; - enum mdoc_sec sec; - const struct mdoc_node *n; + char buf[BUFSIZ]; + enum mdoc_sec sec; /* * Process a new section. Sections are either "named" or - * "custom"; custom sections are user-defined, while named ones - * usually follow a conventional order and may only appear in - * certain manual sections. + * "custom". Custom sections are user-defined, while named ones + * follow a conventional order and may only appear in certain + * manual sections. */ - buf[0] = '\0'; + if ( ! concat(mdoc, buf, mdoc->last->child, BUFSIZ)) + return(0); + + sec = mdoc_str2sec(buf); - /* - * FIXME: yes, these can use a dynamic buffer, but I don't do so - * in the interests of simplicity. - */ + /* The NAME should be first. */ - for (n = mdoc->last->child; n; n = n->next) { - /* XXX - copied from compact(). */ - assert(MDOC_TEXT == n->type); + if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed) + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NAMESECFIRST); - if (strlcat(buf, n->string, BUFSIZ) >= BUFSIZ) { - mdoc_nmsg(mdoc, n, MANDOCERR_MEM); - return(0); - } - if (NULL == n->next) - continue; - if (strlcat(buf, " ", BUFSIZ) >= BUFSIZ) { - mdoc_nmsg(mdoc, n, MANDOCERR_MEM); - return(0); - } - } + /* The SYNOPSIS gets special attention in other areas. */ - sec = mdoc_str2sec(buf); + if (SEC_SYNOPSIS == sec) + mdoc->flags |= MDOC_SYNOPSIS; + else + mdoc->flags &= ~MDOC_SYNOPSIS; - /* - * Check: NAME should always be first, CUSTOM has no roles, - * non-CUSTOM has a conventional order to be followed. - */ + /* Mark our last section. */ - if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed) - if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NAMESECFIRST)) - return(0); + mdoc->lastsec = sec; + + /* We don't care about custom sections after this. */ if (SEC_CUSTOM == sec) return(1); + /* + * Check whether our non-custom section is being repeated or is + * out of order. + */ + if (sec == mdoc->lastnamed) - if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECREP)) - return(0); + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECREP); if (sec < mdoc->lastnamed) - if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECOOO)) - return(0); + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECOOO); - /* - * Check particular section/manual conventions. LIBRARY can - * only occur in manual section 2, 3, and 9. - */ + /* Mark the last named section. */ + + mdoc->lastnamed = sec; + + /* Check particular section/manual conventions. */ + + assert(mdoc->meta.msec); switch (sec) { + case (SEC_RETURN_VALUES): + /* FALLTHROUGH */ + case (SEC_ERRORS): + /* FALLTHROUGH */ case (SEC_LIBRARY): - assert(mdoc->meta.msec); if (*mdoc->meta.msec == '2') break; if (*mdoc->meta.msec == '3') break; if (*mdoc->meta.msec == '9') break; - return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECMSEC)); + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECMSEC); + break; default: break; } @@ -1503,15 +1886,27 @@ post_sh_head(POST_ARGS) return(1); } +static int +pre_ts(PRE_ARGS) +{ + + if (MDOC_BLOCK == mdoc->last->type) + mdoc->last->data.TS = tbl_alloc(); + + return(1); +} static int -pre_pp(PRE_ARGS) +pre_par(PRE_ARGS) { if (NULL == mdoc->last) return(1); - /* Don't allow prior `Lp' or `Pp'. */ + /* + * Don't allow prior `Lp' or `Pp' prior to a paragraph-type + * block: `Lp', `Pp', or non-compact `Bd' or `Bl'. + */ if (MDOC_Pp != mdoc->last->tok && MDOC_Lp != mdoc->last->tok) return(1); @@ -1525,3 +1920,308 @@ pre_pp(PRE_ARGS) mdoc_node_delete(mdoc, mdoc->last); return(1); } + +static int +pre_literal(PRE_ARGS) +{ + + if (MDOC_BODY != n->type) + return(1); + + /* + * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd + * -unfilled' macros set MDOC_LITERAL on entrance to the body. + */ + + switch (n->tok) { + case (MDOC_Dl): + mdoc->flags |= MDOC_LITERAL; + break; + case (MDOC_Bd): + assert(n->data.Bd); + if (DISP_literal == n->data.Bd->type) + mdoc->flags |= MDOC_LITERAL; + if (DISP_unfilled == n->data.Bd->type) + mdoc->flags |= MDOC_LITERAL; + break; + default: + abort(); + /* NOTREACHED */ + } + + return(1); +} + +static int +post_dd(POST_ARGS) +{ + char buf[DATESIZE]; + struct mdoc_node *n; + + n = mdoc->last; + + if (NULL == n->child) { + mdoc->meta.date = time(NULL); + return(1); + } + + if ( ! concat(mdoc, buf, n->child, DATESIZE)) + return(0); + + mdoc->meta.date = mandoc_a2time + (MTIME_MDOCDATE | MTIME_CANONICAL, buf); + + if (0 == mdoc->meta.date) { + mdoc_nmsg(mdoc, n, MANDOCERR_BADDATE); + mdoc->meta.date = time(NULL); + } + + return(1); +} + +static int +post_dt(POST_ARGS) +{ + struct mdoc_node *nn, *n; + const char *cp; + char *p; + + n = mdoc->last; + + if (mdoc->meta.title) + free(mdoc->meta.title); + if (mdoc->meta.vol) + free(mdoc->meta.vol); + if (mdoc->meta.arch) + free(mdoc->meta.arch); + + mdoc->meta.title = mdoc->meta.vol = mdoc->meta.arch = NULL; + + /* First make all characters uppercase. */ + + if (NULL != (nn = n->child)) + for (p = nn->string; *p; p++) { + if (toupper((u_char)*p) == *p) + continue; + + /* + * FIXME: don't be lazy: have this make all + * characters be uppercase and just warn once. + */ + mdoc_nmsg(mdoc, nn, MANDOCERR_UPPERCASE); + break; + } + + /* Handles: `.Dt' + * --> title = unknown, volume = local, msec = 0, arch = NULL + */ + + if (NULL == (nn = n->child)) { + /* XXX: make these macro values. */ + /* FIXME: warn about missing values. */ + mdoc->meta.title = mandoc_strdup("UNKNOWN"); + mdoc->meta.vol = mandoc_strdup("LOCAL"); + mdoc->meta.msec = mandoc_strdup("1"); + return(1); + } + + /* Handles: `.Dt TITLE' + * --> title = TITLE, volume = local, msec = 0, arch = NULL + */ + + mdoc->meta.title = mandoc_strdup + ('\0' == nn->string[0] ? "UNKNOWN" : nn->string); + + if (NULL == (nn = nn->next)) { + /* FIXME: warn about missing msec. */ + /* XXX: make this a macro value. */ + mdoc->meta.vol = mandoc_strdup("LOCAL"); + mdoc->meta.msec = mandoc_strdup("1"); + return(1); + } + + /* Handles: `.Dt TITLE SEC' + * --> title = TITLE, volume = SEC is msec ? + * format(msec) : SEC, + * msec = SEC is msec ? atoi(msec) : 0, + * arch = NULL + */ + + cp = mdoc_a2msec(nn->string); + if (cp) { + mdoc->meta.vol = mandoc_strdup(cp); + mdoc->meta.msec = mandoc_strdup(nn->string); + } else { + mdoc_nmsg(mdoc, n, MANDOCERR_BADMSEC); + mdoc->meta.vol = mandoc_strdup(nn->string); + mdoc->meta.msec = mandoc_strdup(nn->string); + } + + if (NULL == (nn = nn->next)) + return(1); + + /* Handles: `.Dt TITLE SEC VOL' + * --> title = TITLE, volume = VOL is vol ? + * format(VOL) : + * VOL is arch ? format(arch) : + * VOL + */ + + cp = mdoc_a2vol(nn->string); + if (cp) { + free(mdoc->meta.vol); + mdoc->meta.vol = mandoc_strdup(cp); + } else { + /* FIXME: warn about bad arch. */ + cp = mdoc_a2arch(nn->string); + if (NULL == cp) { + free(mdoc->meta.vol); + mdoc->meta.vol = mandoc_strdup(nn->string); + } else + mdoc->meta.arch = mandoc_strdup(cp); + } + + /* Ignore any subsequent parameters... */ + /* FIXME: warn about subsequent parameters. */ + + return(1); +} + +static int +post_prol(POST_ARGS) +{ + /* + * Remove prologue macros from the document after they're + * processed. The final document uses mdoc_meta for these + * values and discards the originals. + */ + + mdoc_node_delete(mdoc, mdoc->last); + if (mdoc->meta.title && mdoc->meta.date && mdoc->meta.os) + mdoc->flags |= MDOC_PBODY; + + return(1); +} + +static int +post_os(POST_ARGS) +{ + struct mdoc_node *n; + char buf[BUFSIZ]; +#ifndef OSNAME + struct utsname utsname; +#endif + + n = mdoc->last; + + /* + * Set the operating system by way of the `Os' macro. Note that + * if an argument isn't provided and -DOSNAME="\"foo\"" is + * provided during compilation, this value will be used instead + * of filling in "sysname release" from uname(). + */ + + free(mdoc->meta.os); + + if ( ! concat(mdoc, buf, n->child, BUFSIZ)) + return(0); + + /* XXX: yes, these can all be dynamically-adjusted buffers, but + * it's really not worth the extra hackery. + */ + + if ('\0' == buf[0]) { +#ifdef OSNAME + if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) { + mdoc_nmsg(mdoc, n, MANDOCERR_MEM); + return(0); + } +#else /*!OSNAME */ + if (uname(&utsname)) { + mdoc_nmsg(mdoc, n, MANDOCERR_UNAME); + mdoc->meta.os = mandoc_strdup("UNKNOWN"); + return(post_prol(mdoc)); + } + + if (strlcat(buf, utsname.sysname, BUFSIZ) >= BUFSIZ) { + mdoc_nmsg(mdoc, n, MANDOCERR_MEM); + return(0); + } + if (strlcat(buf, " ", BUFSIZ) >= BUFSIZ) { + mdoc_nmsg(mdoc, n, MANDOCERR_MEM); + return(0); + } + if (strlcat(buf, utsname.release, BUFSIZ) >= BUFSIZ) { + mdoc_nmsg(mdoc, n, MANDOCERR_MEM); + return(0); + } +#endif /*!OSNAME*/ + } + + mdoc->meta.os = mandoc_strdup(buf); + return(1); +} + +static int +post_std(POST_ARGS) +{ + struct mdoc_node *nn, *n; + + n = mdoc->last; + + /* + * Macros accepting `-std' as an argument have the name of the + * current document (`Nm') filled in as the argument if it's not + * provided. + */ + + if (n->child) + return(1); + + if (NULL == mdoc->meta.name) + return(1); + + nn = n; + mdoc->next = MDOC_NEXT_CHILD; + + if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name)) + return(0); + + mdoc->last = nn; + return(1); +} + + +static int +concat(struct mdoc *m, char *p, const struct mdoc_node *n, size_t sz) +{ + + p[0] = '\0'; + + /* + * Concatenate sibling nodes together. All siblings must be of + * type MDOC_TEXT or an assertion is raised. Concatenation is + * separated by a single whitespace. Returns 0 on fatal (string + * overrun) error. + */ + + for ( ; n; n = n->next) { + assert(MDOC_TEXT == n->type); + + if (strlcat(p, n->string, sz) >= sz) { + mdoc_nmsg(m, n, MANDOCERR_MEM); + return(0); + } + + if (NULL == n->next) + continue; + + if (strlcat(p, " ", sz) >= sz) { + mdoc_nmsg(m, n, MANDOCERR_MEM); + return(0); + } + } + + return(1); +} + |