diff options
-rw-r--r-- | usr.bin/mandoc/Makefile | 5 | ||||
-rw-r--r-- | usr.bin/mandoc/html.c | 649 | ||||
-rw-r--r-- | usr.bin/mandoc/html.h | 133 | ||||
-rw-r--r-- | usr.bin/mandoc/libmdoc.h | 3 | ||||
-rw-r--r-- | usr.bin/mandoc/main.c | 36 | ||||
-rw-r--r-- | usr.bin/mandoc/main.h | 47 | ||||
-rw-r--r-- | usr.bin/mandoc/man.7 | 312 | ||||
-rw-r--r-- | usr.bin/mandoc/man_html.c | 696 | ||||
-rw-r--r-- | usr.bin/mandoc/man_term.c | 132 | ||||
-rw-r--r-- | usr.bin/mandoc/man_validate.c | 39 | ||||
-rw-r--r-- | usr.bin/mandoc/mandoc.1 | 104 | ||||
-rw-r--r-- | usr.bin/mandoc/mandoc_char.7 | 76 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc.7 | 1568 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc.c | 5 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc.h | 5 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc_argv.c | 6 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc_html.c | 2217 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc_term.c | 154 | ||||
-rw-r--r-- | usr.bin/mandoc/mdoc_validate.c | 64 | ||||
-rw-r--r-- | usr.bin/mandoc/out.c | 119 | ||||
-rw-r--r-- | usr.bin/mandoc/out.h | 58 | ||||
-rw-r--r-- | usr.bin/mandoc/term.c | 121 | ||||
-rw-r--r-- | usr.bin/mandoc/term.h | 5 | ||||
-rw-r--r-- | usr.bin/mandoc/tree.c | 3 |
24 files changed, 5868 insertions, 689 deletions
diff --git a/usr.bin/mandoc/Makefile b/usr.bin/mandoc/Makefile index 711a40fd398..9c6f0c24dec 100644 --- a/usr.bin/mandoc/Makefile +++ b/usr.bin/mandoc/Makefile @@ -1,8 +1,8 @@ -# $OpenBSD: Makefile,v 1.19 2009/10/19 09:16:58 schwarze Exp $ +# $OpenBSD: Makefile,v 1.20 2009/10/21 19:13:50 schwarze Exp $ .include <bsd.own.mk> -VERSION=1.9.2 +VERSION=1.9.9 CFLAGS+=-DVERSION=\"${VERSION}\" CFLAGS+=-W -Wall -Wstrict-prototypes .if ${USE_GCC3:L} != "no" @@ -15,6 +15,7 @@ SRCS= mandoc.c mdoc_macro.c mdoc.c mdoc_hash.c mdoc_strings.c \ SRCS+= man_macro.c man.c man_hash.c man_validate.c \ man_action.c man_argv.c SRCS+= main.c mdoc_term.c chars.c term.c tree.c man_term.c +SRCS+= html.c mdoc_html.c man_html.c out.c PROG= mandoc diff --git a/usr.bin/mandoc/html.c b/usr.bin/mandoc/html.c new file mode 100644 index 00000000000..306547d23cc --- /dev/null +++ b/usr.bin/mandoc/html.c @@ -0,0 +1,649 @@ +/* $Id: html.c,v 1.1 2009/10/21 19:13:50 schwarze Exp $ */ +/* + * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> + * + * 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. + */ +#include <sys/types.h> +#include <sys/queue.h> + +#include <assert.h> +#include <err.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "out.h" +#include "chars.h" +#include "html.h" +#include "main.h" + +#define UNCONST(a) ((void *)(uintptr_t)(const void *)(a)) + +#define DOCTYPE "-//W3C//DTD HTML 4.01//EN" +#define DTD "http://www.w3.org/TR/html4/strict.dtd" + +struct htmldata { + const char *name; + int flags; +#define HTML_CLRLINE (1 << 0) +#define HTML_NOSTACK (1 << 1) +}; + +static const struct htmldata htmltags[TAG_MAX] = { + {"html", HTML_CLRLINE}, /* TAG_HTML */ + {"head", HTML_CLRLINE}, /* TAG_HEAD */ + {"body", HTML_CLRLINE}, /* TAG_BODY */ + {"meta", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_META */ + {"title", HTML_CLRLINE}, /* TAG_TITLE */ + {"div", HTML_CLRLINE}, /* TAG_DIV */ + {"h1", 0}, /* TAG_H1 */ + {"h2", 0}, /* TAG_H2 */ + {"p", HTML_CLRLINE}, /* TAG_P */ + {"span", 0}, /* TAG_SPAN */ + {"link", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */ + {"br", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */ + {"a", 0}, /* TAG_A */ + {"table", HTML_CLRLINE}, /* TAG_TABLE */ + {"col", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_COL */ + {"tr", HTML_CLRLINE}, /* TAG_TR */ + {"td", HTML_CLRLINE}, /* TAG_TD */ + {"li", HTML_CLRLINE}, /* TAG_LI */ + {"ul", HTML_CLRLINE}, /* TAG_UL */ + {"ol", HTML_CLRLINE}, /* TAG_OL */ + {"base", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_BASE */ +}; + +static const char *const htmlattrs[ATTR_MAX] = { + "http-equiv", + "content", + "name", + "rel", + "href", + "type", + "media", + "class", + "style", + "width", + "valign", + "target", + "id", +}; + +void * +html_alloc(char *outopts) +{ + struct html *h; + const char *toks[4]; + char *v; + + toks[0] = "style"; + toks[1] = "man"; + toks[2] = "includes"; + toks[3] = NULL; + + if (NULL == (h = calloc(1, sizeof(struct html)))) + return(NULL); + + SLIST_INIT(&h->tags); + SLIST_INIT(&h->ords); + + if (NULL == (h->symtab = chars_init(CHARS_HTML))) { + free(h); + return(NULL); + } + + while (outopts && *outopts) + switch (getsubopt(&outopts, UNCONST(toks), &v)) { + case (0): + h->style = v; + break; + case (1): + h->base_man = v; + break; + case (2): + h->base_includes = v; + break; + default: + break; + } + + return(h); +} + + +void +html_free(void *p) +{ + struct tag *tag; + struct ord *ord; + struct html *h; + + h = (struct html *)p; + + while ( ! SLIST_EMPTY(&h->ords)) { + ord = SLIST_FIRST(&h->ords); + SLIST_REMOVE_HEAD(&h->ords, entry); + free(ord); + } + + while ( ! SLIST_EMPTY(&h->tags)) { + tag = SLIST_FIRST(&h->tags); + SLIST_REMOVE_HEAD(&h->tags, entry); + free(tag); + } + + if (h->symtab) + chars_free(h->symtab); + + free(h); +} + + +void +print_gen_head(struct html *h) +{ + struct htmlpair tag[4]; + + tag[0].key = ATTR_HTTPEQUIV; + tag[0].val = "Content-Type"; + tag[1].key = ATTR_CONTENT; + tag[1].val = "text/html; charset=utf-8"; + print_otag(h, TAG_META, 2, tag); + + tag[0].key = ATTR_NAME; + tag[0].val = "resource-type"; + tag[1].key = ATTR_CONTENT; + tag[1].val = "document"; + print_otag(h, TAG_META, 2, tag); + + if (h->style) { + tag[0].key = ATTR_REL; + tag[0].val = "stylesheet"; + tag[1].key = ATTR_HREF; + tag[1].val = h->style; + tag[2].key = ATTR_TYPE; + tag[2].val = "text/css"; + tag[3].key = ATTR_MEDIA; + tag[3].val = "all"; + print_otag(h, TAG_LINK, 4, tag); + } +} + + +static void +print_spec(struct html *h, const char *p, int len) +{ + const char *rhs; + int i; + size_t sz; + + rhs = chars_a2ascii(h->symtab, p, (size_t)len, &sz); + + if (NULL == rhs) + return; + for (i = 0; i < (int)sz; i++) + putchar(rhs[i]); +} + + +static void +print_res(struct html *h, const char *p, int len) +{ + const char *rhs; + int i; + size_t sz; + + rhs = chars_a2res(h->symtab, p, (size_t)len, &sz); + + if (NULL == rhs) + return; + for (i = 0; i < (int)sz; i++) + putchar(rhs[i]); +} + + +static void +print_escape(struct html *h, const char **p) +{ + int j, type; + const char *wp; + + wp = *p; + type = 1; + + if (0 == *(++wp)) { + *p = wp; + return; + } + + if ('(' == *wp) { + wp++; + if (0 == *wp || 0 == *(wp + 1)) { + *p = 0 == *wp ? wp : wp + 1; + return; + } + + print_spec(h, wp, 2); + *p = ++wp; + return; + + } else if ('*' == *wp) { + if (0 == *(++wp)) { + *p = wp; + return; + } + + switch (*wp) { + case ('('): + wp++; + if (0 == *wp || 0 == *(wp + 1)) { + *p = 0 == *wp ? wp : wp + 1; + return; + } + + print_res(h, wp, 2); + *p = ++wp; + return; + case ('['): + type = 0; + break; + default: + print_res(h, wp, 1); + *p = wp; + return; + } + + } else if ('f' == *wp) { + if (0 == *(++wp)) { + *p = wp; + return; + } + + switch (*wp) { + case ('B'): + /* TODO */ + break; + case ('I'): + /* TODO */ + break; + case ('P'): + /* FALLTHROUGH */ + case ('R'): + /* TODO */ + break; + default: + break; + } + + *p = wp; + return; + + } else if ('[' != *wp) { + print_spec(h, wp, 1); + *p = wp; + return; + } + + wp++; + for (j = 0; *wp && ']' != *wp; wp++, j++) + /* Loop... */ ; + + if (0 == *wp) { + *p = wp; + return; + } + + if (type) + print_spec(h, wp - j, j); + else + print_res(h, wp - j, j); + + *p = wp; +} + + +static void +print_encode(struct html *h, const char *p) +{ + + for (; *p; p++) { + if ('\\' == *p) { + print_escape(h, &p); + continue; + } + switch (*p) { + case ('<'): + printf("<"); + break; + case ('>'): + printf(">"); + break; + case ('&'): + printf("&"); + break; + default: + putchar(*p); + break; + } + } +} + + +struct tag * +print_otag(struct html *h, enum htmltag tag, + int sz, const struct htmlpair *p) +{ + int i; + struct tag *t; + + if ( ! (HTML_NOSTACK & htmltags[tag].flags)) { + if (NULL == (t = malloc(sizeof(struct tag)))) + err(EXIT_FAILURE, "malloc"); + t->tag = tag; + SLIST_INSERT_HEAD(&h->tags, t, entry); + } else + t = NULL; + + if ( ! (HTML_NOSPACE & h->flags)) + if ( ! (HTML_CLRLINE & htmltags[tag].flags)) + printf(" "); + + printf("<%s", htmltags[tag].name); + for (i = 0; i < sz; i++) { + printf(" %s=\"", htmlattrs[p[i].key]); + assert(p->val); + print_encode(h, p[i].val); + printf("\""); + } + printf(">"); + + h->flags |= HTML_NOSPACE; + if (HTML_CLRLINE & htmltags[tag].flags) + h->flags |= HTML_NEWLINE; + else + h->flags &= ~HTML_NEWLINE; + + return(t); +} + + +/* ARGSUSED */ +static void +print_ctag(struct html *h, enum htmltag tag) +{ + + printf("</%s>", htmltags[tag].name); + if (HTML_CLRLINE & htmltags[tag].flags) + h->flags |= HTML_NOSPACE; + if (HTML_CLRLINE & htmltags[tag].flags) + h->flags |= HTML_NEWLINE; + else + h->flags &= ~HTML_NEWLINE; +} + + +/* ARGSUSED */ +void +print_gen_doctype(struct html *h) +{ + + printf("<!DOCTYPE HTML PUBLIC \"%s\" \"%s\">", DOCTYPE, DTD); +} + + +void +print_text(struct html *h, const char *p) +{ + + if (*p && 0 == *(p + 1)) + switch (*p) { + case('.'): + /* FALLTHROUGH */ + case(','): + /* FALLTHROUGH */ + case(';'): + /* FALLTHROUGH */ + case(':'): + /* FALLTHROUGH */ + case('?'): + /* FALLTHROUGH */ + case('!'): + /* FALLTHROUGH */ + case(')'): + /* FALLTHROUGH */ + case(']'): + /* FALLTHROUGH */ + case('}'): + if ( ! (HTML_IGNDELIM & h->flags)) + h->flags |= HTML_NOSPACE; + break; + default: + break; + } + + if ( ! (h->flags & HTML_NOSPACE)) + printf(" "); + + h->flags &= ~HTML_NOSPACE; + h->flags &= ~HTML_NEWLINE; + + if (p) + print_encode(h, p); + + if (*p && 0 == *(p + 1)) + switch (*p) { + case('('): + /* FALLTHROUGH */ + case('['): + /* FALLTHROUGH */ + case('{'): + h->flags |= HTML_NOSPACE; + break; + default: + break; + } +} + + +void +print_tagq(struct html *h, const struct tag *until) +{ + struct tag *tag; + + while ( ! SLIST_EMPTY(&h->tags)) { + tag = SLIST_FIRST(&h->tags); + print_ctag(h, tag->tag); + SLIST_REMOVE_HEAD(&h->tags, entry); + free(tag); + if (until && tag == until) + return; + } +} + + +void +print_stagq(struct html *h, const struct tag *suntil) +{ + struct tag *tag; + + while ( ! SLIST_EMPTY(&h->tags)) { + tag = SLIST_FIRST(&h->tags); + if (suntil && tag == suntil) + return; + print_ctag(h, tag->tag); + SLIST_REMOVE_HEAD(&h->tags, entry); + free(tag); + } +} + + +void +bufinit(struct html *h) +{ + + h->buf[0] = '\0'; + h->buflen = 0; +} + + +void +bufcat_style(struct html *h, const char *key, const char *val) +{ + + bufcat(h, key); + bufncat(h, ":", 1); + bufcat(h, val); + bufncat(h, ";", 1); +} + + +void +bufcat(struct html *h, const char *p) +{ + + bufncat(h, p, strlen(p)); +} + + +void +buffmt(struct html *h, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + (void)vsnprintf(h->buf + (int)h->buflen, + BUFSIZ - h->buflen - 1, fmt, ap); + va_end(ap); + h->buflen = strlen(h->buf); +} + + +void +bufncat(struct html *h, const char *p, size_t sz) +{ + + if (h->buflen + sz > BUFSIZ - 1) + sz = BUFSIZ - 1 - h->buflen; + + (void)strncat(h->buf, p, sz); + h->buflen += sz; +} + + +void +buffmt_includes(struct html *h, const char *name) +{ + const char *p, *pp; + + pp = h->base_includes; + + while (NULL != (p = strchr(pp, '%'))) { + bufncat(h, pp, (size_t)(p - pp)); + switch (*(p + 1)) { + case('I'): + bufcat(h, name); + break; + default: + bufncat(h, p, 2); + break; + } + pp = p + 2; + } + if (pp) + bufcat(h, pp); +} + + +void +buffmt_man(struct html *h, + const char *name, const char *sec) +{ + const char *p, *pp; + + pp = h->base_man; + + /* LINTED */ + while (NULL != (p = strchr(pp, '%'))) { + bufncat(h, pp, (size_t)(p - pp)); + switch (*(p + 1)) { + case('S'): + bufcat(h, sec ? sec : "1"); + break; + case('N'): + buffmt(h, name); + break; + default: + bufncat(h, p, 2); + break; + } + pp = p + 2; + } + if (pp) + bufcat(h, pp); +} + + +void +bufcat_su(struct html *h, const char *p, const struct roffsu *su) +{ + double v; + const char *u; + + v = su->scale; + + switch (su->unit) { + case (SCALE_CM): + u = "cm"; + break; + case (SCALE_IN): + u = "in"; + break; + case (SCALE_PC): + u = "pc"; + break; + case (SCALE_PT): + u = "pt"; + break; + case (SCALE_EM): + u = "em"; + break; + case (SCALE_MM): + if (0 == (v /= 100)) + v = 1; + u = "em"; + break; + case (SCALE_EN): + u = "ex"; + break; + case (SCALE_BU): + u = "ex"; + break; + case (SCALE_VS): + u = "em"; + break; + default: + u = "ex"; + break; + } + + if (su->pt) + buffmt(h, "%s: %f%s;", p, v, u); + else + /* LINTED */ + buffmt(h, "%s: %d%s;", p, (int)v, u); +} + diff --git a/usr.bin/mandoc/html.h b/usr.bin/mandoc/html.h new file mode 100644 index 00000000000..5f2362e1339 --- /dev/null +++ b/usr.bin/mandoc/html.h @@ -0,0 +1,133 @@ +/* $Id: html.h,v 1.1 2009/10/21 19:13:50 schwarze Exp $ */ +/* + * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> + * + * 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 HTML_H +#define HTML_H + +__BEGIN_DECLS + +enum htmltag { + TAG_HTML, + TAG_HEAD, + TAG_BODY, + TAG_META, + TAG_TITLE, + TAG_DIV, + TAG_H1, + TAG_H2, + TAG_P, + TAG_SPAN, + TAG_LINK, + TAG_BR, + TAG_A, + TAG_TABLE, + TAG_COL, + TAG_TR, + TAG_TD, + TAG_LI, + TAG_UL, + TAG_OL, + TAG_BASE, + TAG_MAX +}; + +enum htmlattr { + ATTR_HTTPEQUIV, + ATTR_CONTENT, + ATTR_NAME, + ATTR_REL, + ATTR_HREF, + ATTR_TYPE, + ATTR_MEDIA, + ATTR_CLASS, + ATTR_STYLE, + ATTR_WIDTH, + ATTR_VALIGN, + ATTR_TARGET, + ATTR_ID, + ATTR_MAX +}; + +struct tag { + enum htmltag tag; + SLIST_ENTRY(tag) entry; +}; + +struct ord { + int pos; + const void *cookie; + SLIST_ENTRY(ord) entry; +}; + +SLIST_HEAD(tagq, tag); +SLIST_HEAD(ordq, ord); + +struct htmlpair { + enum htmlattr key; + const char *val; +}; + +#define PAIR_CLASS_INIT(p, v) \ + do { (p)->key = ATTR_CLASS; \ + (p)->val = (v); } while (/* CONSTCOND */ 0) +#define PAIR_HREF_INIT(p, v) \ + do { (p)->key = ATTR_HREF; \ + (p)->val = (v); } while (/* CONSTCOND */ 0) +#define PAIR_STYLE_INIT(p, h) \ + do { (p)->key = ATTR_STYLE; \ + (p)->val = (h)->buf; } while (/* CONSTCOND */ 0) + +struct html { + int flags; +#define HTML_NOSPACE (1 << 0) +#define HTML_NEWLINE (1 << 1) +#define HTML_IGNDELIM (1 << 2) + struct tagq tags; + struct ordq ords; + void *symtab; + char *base; + char *base_man; + char *base_includes; + char *style; + char buf[BUFSIZ]; + size_t buflen; +}; + +struct roffsu; + +void print_gen_doctype(struct html *); +void print_gen_head(struct html *); +struct tag *print_otag(struct html *, enum htmltag, + int, const struct htmlpair *); +void print_tagq(struct html *, const struct tag *); +void print_stagq(struct html *, const struct tag *); +void print_text(struct html *, const char *); + +void bufcat_su(struct html *, const char *, + const struct roffsu *); +void buffmt_man(struct html *, + const char *, const char *); +void buffmt_includes(struct html *, const char *); +void buffmt(struct html *, const char *, ...); +void bufcat(struct html *, const char *); +void bufcat_style(struct html *, + const char *, const char *); +void bufncat(struct html *, const char *, size_t); +void bufinit(struct html *); + +__END_DECLS + +#endif /*!HTML_H*/ diff --git a/usr.bin/mandoc/libmdoc.h b/usr.bin/mandoc/libmdoc.h index 916064f5e11..86cdf99efc9 100644 --- a/usr.bin/mandoc/libmdoc.h +++ b/usr.bin/mandoc/libmdoc.h @@ -1,4 +1,4 @@ -/* $Id: libmdoc.h,v 1.22 2009/10/19 16:27:52 schwarze Exp $ */ +/* $Id: libmdoc.h,v 1.23 2009/10/21 19:13:50 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -93,6 +93,7 @@ enum merr { ENOCTX, ELIB, EBADCHILD, + ENOTYPE, MERRMAX }; diff --git a/usr.bin/mandoc/main.c b/usr.bin/mandoc/main.c index e8f76223343..2b2d9bd0b06 100644 --- a/usr.bin/mandoc/main.c +++ b/usr.bin/mandoc/main.c @@ -1,4 +1,4 @@ -/* $Id: main.c,v 1.16 2009/09/21 20:57:57 schwarze Exp $ */ +/* $Id: main.c,v 1.17 2009/10/21 19:13:50 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -20,12 +20,16 @@ #include <err.h> #include <fcntl.h> #include <stdio.h> +#include <stdint.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "mdoc.h" #include "man.h" +#include "main.h" + +#define UNCONST(a) ((void *)(uintptr_t)(const void *)(a)) typedef void (*out_mdoc)(void *, const struct mdoc *); typedef void (*out_man)(void *, const struct man *); @@ -45,6 +49,7 @@ enum intt { enum outt { OUTT_ASCII = 0, OUTT_TREE, + OUTT_HTML, OUTT_LINT }; @@ -70,15 +75,9 @@ struct curparse { out_man outman; out_free outfree; void *outdata; + char *outopts; }; -extern void *ascii_alloc(void); -extern void tree_mdoc(void *, const struct mdoc *); -extern void tree_man(void *, const struct man *); -extern void terminal_mdoc(void *, const struct mdoc *); -extern void terminal_man(void *, const struct man *); -extern void terminal_free(void *); - static int foptions(int *, char *); static int toptions(enum outt *, char *); static int moptions(enum intt *, char *); @@ -112,7 +111,7 @@ main(int argc, char *argv[]) curp.outtype = OUTT_ASCII; /* LINTED */ - while (-1 != (c = getopt(argc, argv, "f:m:VW:T:"))) + while (-1 != (c = getopt(argc, argv, "f:m:o:T:VW:"))) switch (c) { case ('f'): if ( ! foptions(&curp.fflags, optarg)) @@ -122,6 +121,9 @@ main(int argc, char *argv[]) if ( ! moptions(&curp.inttype, optarg)) return(EXIT_FAILURE); break; + case ('o'): + curp.outopts = optarg; + break; case ('T'): if ( ! toptions(&curp.outtype, optarg)) return(EXIT_FAILURE); @@ -419,6 +421,12 @@ fdesc(struct buf *blk, struct buf *ln, struct curparse *curp) if ( ! (curp->outman && curp->outmdoc)) { switch (curp->outtype) { + case (OUTT_HTML): + curp->outdata = html_alloc(curp->outopts); + curp->outman = html_man; + curp->outmdoc = html_mdoc; + curp->outfree = html_free; + break; case (OUTT_TREE): curp->outman = tree_man; curp->outmdoc = tree_mdoc; @@ -533,6 +541,8 @@ toptions(enum outt *tflags, char *arg) *tflags = OUTT_LINT; else if (0 == strcmp(arg, "tree")) *tflags = OUTT_TREE; + else if (0 == strcmp(arg, "html")) + *tflags = OUTT_HTML; else { warnx("bad argument: -T%s", arg); return(0); @@ -546,7 +556,7 @@ static int foptions(int *fflags, char *arg) { char *v, *o; - char *toks[7]; + const char *toks[7]; toks[0] = "ign-scope"; toks[1] = "no-ign-escape"; @@ -558,7 +568,7 @@ foptions(int *fflags, char *arg) while (*arg) { o = arg; - switch (getsubopt(&arg, toks, &v)) { + switch (getsubopt(&arg, UNCONST(toks), &v)) { case (0): *fflags |= IGN_SCOPE; break; @@ -592,7 +602,7 @@ static int woptions(int *wflags, char *arg) { char *v, *o; - char *toks[3]; + const char *toks[3]; toks[0] = "all"; toks[1] = "error"; @@ -600,7 +610,7 @@ woptions(int *wflags, char *arg) while (*arg) { o = arg; - switch (getsubopt(&arg, toks, &v)) { + switch (getsubopt(&arg, UNCONST(toks), &v)) { case (0): *wflags |= WARN_WALL; break; diff --git a/usr.bin/mandoc/main.h b/usr.bin/mandoc/main.h new file mode 100644 index 00000000000..667e4fa9a3f --- /dev/null +++ b/usr.bin/mandoc/main.h @@ -0,0 +1,47 @@ +/* $Id: main.h,v 1.1 2009/10/21 19:13:50 schwarze Exp $ */ +/* + * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> + * + * 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 MAIN_H +#define MAIN_H + +__BEGIN_DECLS + +struct mdoc; +struct man; + +/* + * Definitions for main.c-visible output device functions, e.g., -Thtml + * and -Tascii. Note that ascii_alloc() is named as such in + * anticipation of latin1_alloc() and so on, all of which map into the + * terminal output routines with different character settings. + */ + +void *html_alloc(char *); +void html_mdoc(void *, const struct mdoc *); +void html_man(void *, const struct man *); +void html_free(void *); + +void tree_mdoc(void *, const struct mdoc *); +void tree_man(void *, const struct man *); + +void *ascii_alloc(void); +void terminal_mdoc(void *, const struct mdoc *); +void terminal_man(void *, const struct man *); +void terminal_free(void *); + +__END_DECLS + +#endif /*!MAIN_H*/ diff --git a/usr.bin/mandoc/man.7 b/usr.bin/mandoc/man.7 index bccfc130c40..a251e1da61a 100644 --- a/usr.bin/mandoc/man.7 +++ b/usr.bin/mandoc/man.7 @@ -1,4 +1,4 @@ -.\" $Id: man.7,v 1.11 2009/09/18 22:46:14 schwarze Exp $ +.\" $Id: man.7,v 1.12 2009/10/21 19:13:50 schwarze Exp $ .\" .\" Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: September 18 2009 $ +.Dd $Mdocdate: October 21 2009 $ .Dt MAN 7 .Os . @@ -119,19 +119,86 @@ from input. These are later re-added, if applicable, by a front-end utility such as .Xr mandoc 1 . . +.Ss Scaling Widths +Many macros support scaled widths for their arguments, such as +stipulating a two-inch paragraph indentation with the following: +.Bd -literal -offset indent +\&.HP 2i +.Ed +. +.Pp +The syntax for scaled widths is +.Sq Li [+-]?[0-9]*.[0-9]*[:unit:]? , +where a decimal must be preceded or proceeded by at least one digit. +Negative numbers, while accepted, are truncated to zero. The following +scaling units are accepted: +. +.Pp +.Bl -tag -width Ds -offset indent -compact +.It c +centimetre +.It i +inch +.It P +pica (~1/6 inch) +.It p +point (~1/72 inch) +.It f +synonym for +.Sq u +.It v +default vertical span +.It m +width of rendered +.Sq m +.Pq em +character +.It n +width of rendered +.Sq n +.Pq en +character +.It u +default horizontal span +.It M +mini-em (~1/100 em) +.El +.Pp +Using anything other than +.Sq m , +.Sq n , +.Sq u , +or +.Sq v +is necessarily non-portable across output media. See +.Sx COMPATIBILITY . +. +.Pp +If a scaling unit is not provided, the numerical value is interpreted +under the default rules of +.Sq v +for vertical spaces and +.Sq u +for horizontal ones. +.Em Note : +this differs from +.Xr mdoc 7 , +which, if a unit is not provided, will instead interpret the string as +literal text. +. . .Sh MANUAL STRUCTURE Each .Nm document must contain contains at least the -.Sq TH +.Sx \&TH macro describing the document's section and title. It may occur anywhere in the document, although conventionally, it appears as the first macro. . .Pp Beyond -.Sq TH , +.Sx \&TH , at least one macro or text node must appear in the document. Documents are generally structured as follows: .Bd -literal -offset indent @@ -177,11 +244,12 @@ Macros are one to three three characters in length and begin with a control character , .Sq \&. , at the beginning of the line. An arbitrary amount of whitespace may -sit between the control character and the macro name. Thus, -.Sq .PP -and -.Sq \&.\ \ \ PP -are equivalent. +sit between the control character and the macro name. Thus, the +following are equivalent: +.Bd -literal -offset indent +\&.PP +\&.\ \ \ PP +.Ed . .Pp The @@ -215,42 +283,42 @@ If a next-line macro is proceded by a block macro, it is ignored. .Pp .Bl -column -compact -offset indent "MacroX" "ArgumentsX" "ScopeXXXXX" .It Em Macro Ta Em Arguments Ta Em Scope -.It B Ta n Ta next-line -.It BI Ta n Ta current -.It BR Ta n Ta current -.It DT Ta 0 Ta current -.It I Ta n Ta next-line -.It IB Ta n Ta current -.It IR Ta n Ta current -.It R Ta n Ta next-line -.It RB Ta n Ta current -.It RI Ta n Ta current -.It SB Ta n Ta next-line -.It SM Ta n Ta next-line -.It TH Ta >1, <6 Ta current -.It UC Ta n Ta current -.It br Ta 0 Ta current -.It fi Ta 0 Ta current -.It i Ta n Ta current -.It na Ta 0 Ta current -.It nf Ta 0 Ta current -.It r Ta 0 Ta current -.It sp Ta 1 Ta current +.It Sx \&B Ta n Ta next-line +.It Sx \&BI Ta n Ta current +.It Sx \&BR Ta n Ta current +.It Sx \&DT Ta 0 Ta current +.It Sx \&I Ta n Ta next-line +.It Sx \&IB Ta n Ta current +.It Sx \&IR Ta n Ta current +.It Sx \&R Ta n Ta next-line +.It Sx \&RB Ta n Ta current +.It Sx \&RI Ta n Ta current +.It Sx \&SB Ta n Ta next-line +.It Sx \&SM Ta n Ta next-line +.It Sx \&TH Ta >1, <6 Ta current +.It Sx \&UC Ta n Ta current +.It Sx \&br Ta 0 Ta current +.It Sx \&fi Ta 0 Ta current +.It Sx \&i Ta n Ta current +.It Sx \&na Ta 0 Ta current +.It Sx \&nf Ta 0 Ta current +.It Sx \&r Ta 0 Ta current +.It Sx \&sp Ta 1 Ta current .El . .Pp The -.Sq RS , -.Sq RE , -.Sq UC , -.Sq br , -.Sq fi , -.Sq i , -.Sq na , -.Sq nf , -.Sq r , +.Sx \&RS , +.Sx \&RE , +.Sx \&UC , +.Sx \&br , +.Sx \&fi , +.Sx \&i , +.Sx \&na , +.Sx \&nf , +.Sx \&r , and -.Sq sp +.Sx \&sp macros should not be used. They're included for compatibility. . . @@ -268,48 +336,48 @@ subsequent block macro invocation. .Pp The closure of body scope may be to the section, where a macro is closed by -.Sq SH ; +.Sx \&SH ; sub-section, closed by a section or -.Sq SS ; +.Sx \&SS ; part, closed by a section, sub-section, or -.Sq RE ; +.Sx \&RE ; or paragraph, closed by a section, sub-section, part, -.Sq HP , -.Sq IP , -.Sq LP , -.Sq P , -.Sq PP , +.Sx \&HP , +.Sx \&IP , +.Sx \&LP , +.Sx \&P , +.Sx \&PP , or -.Sq TP . +.Sx \&TP . No closure refers to an explicit block closing macro. . .Pp .Bl -column "MacroX" "ArgumentsX" "Head ScopeX" "sub-sectionX" -compact -offset indent .It Em Macro Ta Em Arguments Ta Em Head Scope Ta Em Body Scope -.It HP Ta <2 Ta current Ta paragraph -.It IP Ta <3 Ta current Ta paragraph -.It LP Ta 0 Ta current Ta paragraph -.It P Ta 0 Ta current Ta paragraph -.It PP Ta 0 Ta current Ta paragraph -.It RE Ta 0 Ta current Ta none -.It RS Ta 1 Ta current Ta part -.It SH Ta >0 Ta next-line Ta section -.It SS Ta >0 Ta next-line Ta sub-section -.It TP Ta n Ta next-line Ta paragraph +.It Sx \&HP Ta <2 Ta current Ta paragraph +.It Sx \&IP Ta <3 Ta current Ta paragraph +.It Sx \&LP Ta 0 Ta current Ta paragraph +.It Sx \&P Ta 0 Ta current Ta paragraph +.It Sx \&PP Ta 0 Ta current Ta paragraph +.It Sx \&RE Ta 0 Ta current Ta none +.It Sx \&RS Ta 1 Ta current Ta part +.It Sx \&SH Ta >0 Ta next-line Ta section +.It Sx \&SS Ta >0 Ta next-line Ta sub-section +.It Sx \&TP Ta n Ta next-line Ta paragraph .El . .Pp If a block macro is next-line scoped, it may only be followed by in-line macros (excluding -.Sq DT , -.Sq TH , -.Sq UC , -.Sq br , -.Sq na , -.Sq sp , -.Sq nf , +.Sx \&DT , +.Sx \&TH , +.Sx \&UC , +.Sx \&br , +.Sx \&na , +.Sx \&sp , +.Sx \&nf , and -.Sq fi ) . +.Sx \&fi ) . . . .Sh REFERENCE @@ -317,32 +385,9 @@ This section is a canonical reference to all macros, arranged alphabetically. For the scoping of individual macros, see .Sx MACRO SYNTAX . . -. -.Ss Definitions -In this reference, a numerical width may be either a standalone natural -number (such as 3, 4, 10, etc.) or a natural number followed by a width -multiplier -.Qq n , -corresponding to the width of the formatted letter n, or -.Qq m , -corresponding to the width of the formatted letter m. The latter is the -default, if unspecified. Thus, -.Bd -literal -offset indent -\&.HP 12n -.Ed -. -.Pp -indicates an offset of 12 -.Qq n -.Ns -sized -letters. -. -. -.Ss Macro Reference -.Bl -tag -width Ds -.It B +.Ss \&B Text is rendered in bold face. -.It BI +.Ss \&BI Text is rendered alternately in bold face and italic. Thus, .Sq .BI this word and that causes @@ -354,12 +399,12 @@ to render in bold face, while and .Sq that render in italics. Whitespace between arguments is omitted in output. -.It BR +.Ss \&BR Text is rendered alternately in bold face and roman (the default font). Whitespace between arguments is omitted in output. -.It DT +.Ss \&DT Has no effect. Included for compatibility. -.It HP +.Ss \&HP Begin a paragraph whose initial output line is left-justified, but subsequent output lines are indented, with the following syntax: .Bd -literal -offset indent @@ -367,16 +412,16 @@ subsequent output lines are indented, with the following syntax: .Ed . .Pp -If +If scaling width .Va width is specified, it's saved for later paragraph left-margins; if unspecified, the saved or default width is used. -.It I +.Ss \&I Text is rendered in italics. -.It IB +.Ss \&IB Text is rendered alternately in italics and bold face. Whitespace between arguments is omitted in output. -.It IP +.Ss \&IP Begin a paragraph with the following syntax: .Bd -literal -offset indent \&.IP [head [width]] @@ -384,36 +429,42 @@ Begin a paragraph with the following syntax: . .Pp This follows the behaviour of the -.Sq TP +.Sx \&TP except for the macro syntax (all arguments on the line, instead of having next-line scope). If .Va width is specified, it's saved for later paragraph left-margins; if unspecified, the saved or default width is used. -.It IR +.Ss \&IR Text is rendered alternately in italics and roman (the default font). Whitespace between arguments is omitted in output. -.It LP, P, PP +.Ss \&LP Begin an undecorated paragraph. The scope of a paragraph is closed by a subsequent paragraph, sub-section, section, or end of file. The saved paragraph left-margin width is re-set to the default. -.It R +.Ss \&P +Synonym for +.Sx \&LP . +.Ss \&PP +Synonym for +.Sx \&LP . +.Ss \&R Text is rendered in roman (the default font). -.It RB +.Ss \&RB Text is rendered alternately in roman (the default font) and bold face. Whitespace between arguments is omitted in output. -.It RE +.Ss \&RE Explicitly close out the scope of a prior -.Sq RS . -.It RI +.Sx \&RS . +.Ss \&RI Text is rendered alternately in roman (the default font) and italics. Whitespace between arguments is omitted in output. -.It RS +.Ss \&RS Begin a part setting the left margin. The left margin controls the offset, following an initial indentation, to un-indented text such as that of -.Sq PP . -The width may be specified as following: +.Sx \&PP . +A scaling width may be specified as following: .Bd -literal -offset indent \&.RS [width] .Ed @@ -422,21 +473,21 @@ The width may be specified as following: If .Va width is not specified, the saved or default width is used. -.It SB +.Ss \&SB Text is rendered in small size (one point smaller than the default font) bold face. -.It SH +.Ss \&SH Begin a section. The scope of a section is only closed by another section or the end of file. The paragraph left-margin width is re-set to the default. -.It SM +.Ss \&SM Text is rendered in small size (one point smaller than the default font). -.It SS +.Ss \&SS Begin a sub-section. The scope of a sub-section is closed by a subsequent sub-section, section, or end of file. The paragraph left-margin width is re-set to the default. -.It TH +.Ss \&TH Sets the title of the manual page with the following syntax: .Bd -literal -offset indent \&.TH title section [date [source [volume]]] @@ -458,48 +509,45 @@ The string specifies the organisation providing the utility. The .Va volume replaces the default rendered volume as dictated by the manual section. -.It TP +.Ss \&TP Begin a paragraph where the head, if exceeding the indentation width, is followed by a newline; if not, the body follows on the same line after a buffer to the indentation width. Subsequent output lines are indented. . .Pp -The indentation width may be set as follows: +The indentation scaling width may be set as follows: .Bd -literal -offset indent \&.TP [width] .Ed . .Pp -Where -.Va width -must be a properly-formed numeric width. If +If .Va width is specified, it's saved for later paragraph left-margins; if unspecified, the saved or default width is used. -.It UC +.Ss \&UC Has no effect. Included for compatibility. -.It br +.Ss \&br Breaks the current line. Consecutive invocations have no further effect. -.It fi +.Ss \&fi End literal mode begun by -.Sq nf . -.It i +.Sx \&nf . +.Ss \&i Italicise arguments. If no arguments are specified, all subsequent text is italicised. -.It na +.Ss \&na Don't align to the right margin. -.It nf +.Ss \&nf Begin literal mode: all subsequent free-form lines have their end of line boundaries preserved. May be ended by -.Sq fi . -.It r +.Sx \&fi . +.Ss \&r Fonts and styles (bold face, italics) reset to roman (default font). -.It sp +.Ss \&sp Insert n spaces, where n is the macro's positive numeric argument. If 0, this is equivalent to the -.Sq br +.Sx \&br macro. -.El . . .Sh COMPATIBILITY diff --git a/usr.bin/mandoc/man_html.c b/usr.bin/mandoc/man_html.c new file mode 100644 index 00000000000..15349ccb28c --- /dev/null +++ b/usr.bin/mandoc/man_html.c @@ -0,0 +1,696 @@ +/* $Id: man_html.c,v 1.1 2009/10/21 19:13:50 schwarze Exp $ */ +/* + * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> + * + * 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. + */ +#include <sys/types.h> +#include <sys/queue.h> + +#include <assert.h> +#include <ctype.h> +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "out.h" +#include "html.h" +#include "man.h" +#include "main.h" + +/* TODO: preserve ident widths. */ + +#define INDENT 5 +#define HALFINDENT 3 + +#define MAN_ARGS const struct man_meta *m, \ + const struct man_node *n, \ + struct html *h + +struct htmlman { + int (*pre)(MAN_ARGS); + int (*post)(MAN_ARGS); +}; + +static void print_man(MAN_ARGS); +static void print_man_head(MAN_ARGS); +static void print_man_nodelist(MAN_ARGS); +static void print_man_node(MAN_ARGS); + +static int a2width(const struct man_node *, + struct roffsu *); + +static int man_alt_pre(MAN_ARGS); +static int man_br_pre(MAN_ARGS); +static int man_ign_pre(MAN_ARGS); +static void man_root_post(MAN_ARGS); +static int man_root_pre(MAN_ARGS); +static int man_B_pre(MAN_ARGS); +static int man_HP_pre(MAN_ARGS); +static int man_I_pre(MAN_ARGS); +static int man_IP_pre(MAN_ARGS); +static int man_PP_pre(MAN_ARGS); +static int man_RS_pre(MAN_ARGS); +static int man_SB_pre(MAN_ARGS); +static int man_SH_pre(MAN_ARGS); +static int man_SM_pre(MAN_ARGS); +static int man_SS_pre(MAN_ARGS); + +static const struct htmlman mans[MAN_MAX] = { + { man_br_pre, NULL }, /* br */ + { NULL, NULL }, /* TH */ + { man_SH_pre, NULL }, /* SH */ + { man_SS_pre, NULL }, /* SS */ + { man_IP_pre, NULL }, /* TP */ + { man_PP_pre, NULL }, /* LP */ + { man_PP_pre, NULL }, /* PP */ + { man_PP_pre, NULL }, /* P */ + { man_IP_pre, NULL }, /* IP */ + { man_HP_pre, NULL }, /* HP */ + { man_SM_pre, NULL }, /* SM */ + { man_SB_pre, NULL }, /* SB */ + { man_alt_pre, NULL }, /* BI */ + { man_alt_pre, NULL }, /* IB */ + { man_alt_pre, NULL }, /* BR */ + { man_alt_pre, NULL }, /* RB */ + { NULL, NULL }, /* R */ + { man_B_pre, NULL }, /* B */ + { man_I_pre, NULL }, /* I */ + { man_alt_pre, NULL }, /* IR */ + { man_alt_pre, NULL }, /* RI */ + { NULL, NULL }, /* na */ + { NULL, NULL }, /* i */ + { man_br_pre, NULL }, /* sp */ + { NULL, NULL }, /* nf */ + { NULL, NULL }, /* fi */ + { NULL, NULL }, /* r */ + { NULL, NULL }, /* RE */ + { man_RS_pre, NULL }, /* RS */ + { man_ign_pre, NULL }, /* DT */ + { man_ign_pre, NULL }, /* UC */ +}; + + +void +html_man(void *arg, const struct man *m) +{ + struct html *h; + struct tag *t; + + h = (struct html *)arg; + + print_gen_doctype(h); + + t = print_otag(h, TAG_HTML, 0, NULL); + print_man(man_meta(m), man_node(m), h); + print_tagq(h, t); + + printf("\n"); +} + + +static void +print_man(MAN_ARGS) +{ + struct tag *t; + struct htmlpair tag; + + t = print_otag(h, TAG_HEAD, 0, NULL); + + print_man_head(m, n, h); + print_tagq(h, t); + t = print_otag(h, TAG_BODY, 0, NULL); + + tag.key = ATTR_CLASS; + tag.val = "body"; + print_otag(h, TAG_DIV, 1, &tag); + + print_man_nodelist(m, n, h); + + print_tagq(h, t); +} + + +/* ARGSUSED */ +static void +print_man_head(MAN_ARGS) +{ + + print_gen_head(h); + bufinit(h); + buffmt(h, "%s(%d)", m->title, m->msec); + + print_otag(h, TAG_TITLE, 0, NULL); + print_text(h, h->buf); +} + + +static void +print_man_nodelist(MAN_ARGS) +{ + + print_man_node(m, n, h); + if (n->next) + print_man_nodelist(m, n->next, h); +} + + +static void +print_man_node(MAN_ARGS) +{ + int child; + struct tag *t; + + child = 1; + t = SLIST_FIRST(&h->tags); + + bufinit(h); + + switch (n->type) { + case (MAN_ROOT): + child = man_root_pre(m, n, h); + break; + case (MAN_TEXT): + print_text(h, n->string); + break; + default: + if (mans[n->tok].pre) + child = (*mans[n->tok].pre)(m, n, h); + break; + } + + if (child && n->child) + print_man_nodelist(m, n->child, h); + + print_stagq(h, t); + + bufinit(h); + + switch (n->type) { + case (MAN_ROOT): + man_root_post(m, n, h); + break; + case (MAN_TEXT): + break; + default: + if (mans[n->tok].post) + (*mans[n->tok].post)(m, n, h); + break; + } +} + + +static int +a2width(const struct man_node *n, struct roffsu *su) +{ + + if (MAN_TEXT != n->type) + return(0); + if (a2roffsu(n->string, su, SCALE_BU)) + return(1); + + return(0); +} + + +/* ARGSUSED */ +static int +man_root_pre(MAN_ARGS) +{ + struct htmlpair tag[2]; + struct tag *t, *tt; + char b[BUFSIZ], title[BUFSIZ]; + + b[0] = 0; + if (m->vol) + (void)strlcat(b, m->vol, BUFSIZ); + + (void)snprintf(title, BUFSIZ - 1, + "%s(%d)", m->title, m->msec); + + PAIR_CLASS_INIT(&tag[0], "header"); + bufcat_style(h, "width", "100%"); + PAIR_STYLE_INIT(&tag[1], h); + t = print_otag(h, TAG_TABLE, 2, tag); + tt = print_otag(h, TAG_TR, 0, NULL); + + bufinit(h); + bufcat_style(h, "width", "10%"); + PAIR_STYLE_INIT(&tag[0], h); + print_otag(h, TAG_TD, 1, tag); + print_text(h, title); + print_stagq(h, tt); + + bufinit(h); + bufcat_style(h, "width", "80%"); + bufcat_style(h, "white-space", "nowrap"); + bufcat_style(h, "text-align", "center"); + PAIR_STYLE_INIT(&tag[0], h); + print_otag(h, TAG_TD, 1, tag); + print_text(h, b); + print_stagq(h, tt); + + bufinit(h); + bufcat_style(h, "width", "10%"); + bufcat_style(h, "text-align", "right"); + PAIR_STYLE_INIT(&tag[0], h); + print_otag(h, TAG_TD, 1, tag); + print_text(h, title); + print_tagq(h, t); + return(1); +} + + +/* ARGSUSED */ +static void +man_root_post(MAN_ARGS) +{ + struct tm tm; + struct htmlpair tag[2]; + struct tag *t, *tt; + char b[BUFSIZ]; + + (void)localtime_r(&m->date, &tm); + + if (0 == strftime(b, BUFSIZ - 1, "%B %e, %Y", &tm)) + err(EXIT_FAILURE, "strftime"); + + PAIR_CLASS_INIT(&tag[0], "footer"); + bufcat_style(h, "width", "100%"); + PAIR_STYLE_INIT(&tag[1], h); + t = print_otag(h, TAG_TABLE, 2, tag); + tt = print_otag(h, TAG_TR, 0, NULL); + + bufinit(h); + bufcat_style(h, "width", "50%"); + PAIR_STYLE_INIT(&tag[0], h); + print_otag(h, TAG_TD, 1, tag); + print_text(h, b); + print_stagq(h, tt); + + bufinit(h); + bufcat_style(h, "width", "50%"); + bufcat_style(h, "text-align", "right"); + PAIR_STYLE_INIT(&tag[0], h); + print_otag(h, TAG_TD, 1, tag); + if (m->source) + print_text(h, m->source); + print_tagq(h, t); +} + + + +/* ARGSUSED */ +static int +man_br_pre(MAN_ARGS) +{ + struct roffsu su; + struct htmlpair tag; + + SCALE_VS_INIT(&su, 1); + + if (MAN_sp == n->tok && n->child) + a2roffsu(n->child->string, &su, SCALE_VS); + else if (MAN_br == n->tok) + su.scale = 0; + + bufcat_su(h, "height", &su); + PAIR_STYLE_INIT(&tag, h); + print_otag(h, TAG_DIV, 1, &tag); + return(0); +} + + +/* ARGSUSED */ +static int +man_SH_pre(MAN_ARGS) +{ + struct htmlpair tag[2]; + struct roffsu su; + + if (MAN_BODY == n->type) { + SCALE_HS_INIT(&su, INDENT); + bufcat_su(h, "margin-left", &su); + PAIR_CLASS_INIT(&tag[0], "sec-body"); + PAIR_STYLE_INIT(&tag[1], h); + print_otag(h, TAG_DIV, 2, tag); + return(1); + } else if (MAN_BLOCK == n->type) { + PAIR_CLASS_INIT(&tag[0], "sec-block"); + if (n->prev && MAN_SH == n->prev->tok) + if (NULL == n->prev->body->child) { + print_otag(h, TAG_DIV, 1, tag); + return(1); + } + + SCALE_VS_INIT(&su, 1); + bufcat_su(h, "margin-top", &su); + if (NULL == n->next) + bufcat_su(h, "margin-bottom", &su); + PAIR_STYLE_INIT(&tag[1], h); + print_otag(h, TAG_DIV, 2, tag); + return(1); + } + + PAIR_CLASS_INIT(&tag[0], "sec-head"); + print_otag(h, TAG_DIV, 1, tag); + return(1); +} + + +/* ARGSUSED */ +static int +man_alt_pre(MAN_ARGS) +{ + const struct man_node *nn; + struct tag *t; + int i; + struct htmlpair tagi, tagb, *tagp; + + PAIR_CLASS_INIT(&tagi, "italic"); + PAIR_CLASS_INIT(&tagb, "bold"); + + for (i = 0, nn = n->child; nn; nn = nn->next, i++) { + switch (n->tok) { + case (MAN_BI): + tagp = i % 2 ? &tagi : &tagb; + break; + case (MAN_IB): + tagp = i % 2 ? &tagb : &tagi; + break; + case (MAN_RI): + tagp = i % 2 ? &tagi : NULL; + break; + case (MAN_IR): + tagp = i % 2 ? NULL : &tagi; + break; + case (MAN_BR): + tagp = i % 2 ? NULL : &tagb; + break; + case (MAN_RB): + tagp = i % 2 ? &tagb : NULL; + break; + default: + abort(); + /* NOTREACHED */ + } + + if (i) + h->flags |= HTML_NOSPACE; + + if (tagp) { + t = print_otag(h, TAG_SPAN, 1, tagp); + print_man_node(m, nn, h); + print_tagq(h, t); + } else + print_man_node(m, nn, h); + } + + return(0); +} + + +/* ARGSUSED */ +static int +man_SB_pre(MAN_ARGS) +{ + struct htmlpair tag; + + PAIR_CLASS_INIT(&tag, "small bold"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +man_SM_pre(MAN_ARGS) +{ + struct htmlpair tag; + + PAIR_CLASS_INIT(&tag, "small"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +man_SS_pre(MAN_ARGS) +{ + struct htmlpair tag[3]; + struct roffsu su; + + SCALE_VS_INIT(&su, 1); + + if (MAN_BODY == n->type) { + PAIR_CLASS_INIT(&tag[0], "ssec-body"); + if (n->parent->next && n->child) { + bufcat_su(h, "margin-bottom", &su); + PAIR_STYLE_INIT(&tag[1], h); + print_otag(h, TAG_DIV, 2, tag); + return(1); + } + + print_otag(h, TAG_DIV, 1, tag); + return(1); + } else if (MAN_BLOCK == n->type) { + PAIR_CLASS_INIT(&tag[0], "ssec-block"); + if (n->prev && MAN_SS == n->prev->tok) + if (n->prev->body->child) { + bufcat_su(h, "margin-top", &su); + PAIR_STYLE_INIT(&tag[1], h); + print_otag(h, TAG_DIV, 2, tag); + return(1); + } + + print_otag(h, TAG_DIV, 1, tag); + return(1); + } + + SCALE_HS_INIT(&su, INDENT - HALFINDENT); + bufcat_su(h, "margin-left", &su); + PAIR_CLASS_INIT(&tag[0], "ssec-head"); + PAIR_STYLE_INIT(&tag[1], h); + print_otag(h, TAG_DIV, 2, tag); + return(1); +} + + +/* ARGSUSED */ +static int +man_PP_pre(MAN_ARGS) +{ + struct htmlpair tag; + struct roffsu su; + int i; + + if (MAN_BLOCK != n->type) + return(1); + + i = 0; + + if (MAN_ROOT == n->parent->tok) { + SCALE_HS_INIT(&su, INDENT); + bufcat_su(h, "margin-left", &su); + i++; + } + if (n->next && n->next->child) { + SCALE_VS_INIT(&su, 1); + bufcat_su(h, "margin-bottom", &su); + i++; + } + + PAIR_STYLE_INIT(&tag, h); + print_otag(h, TAG_DIV, i ? 1 : 0, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +man_IP_pre(MAN_ARGS) +{ + struct roffsu su; + struct htmlpair tag; + const struct man_node *nn; + int width; + + /* + * This scattering of 1-BU margins and pads is to make sure that + * when text overruns its box, the subsequent text isn't flush + * up against it. However, the rest of the right-hand box must + * also be adjusted in consideration of this 1-BU space. + */ + + if (MAN_BODY == n->type) { + SCALE_HS_INIT(&su, INDENT); + bufcat_su(h, "margin-left", &su); + PAIR_STYLE_INIT(&tag, h); + print_otag(h, TAG_DIV, 1, &tag); + return(1); + } + + nn = MAN_BLOCK == n->type ? + n->head->child : n->parent->head->child; + + SCALE_HS_INIT(&su, INDENT); + width = 0; + + if (MAN_IP == n->tok && NULL != nn) + if (NULL != (nn = nn->next)) { + for ( ; nn->next; nn = nn->next) + /* Do nothing. */ ; + width = a2width(nn, &su); + } + + if (MAN_TP == n->tok && NULL != nn) + width = a2width(nn, &su); + + if (MAN_BLOCK == n->type) { + bufcat_su(h, "margin-left", &su); + SCALE_VS_INIT(&su, 1); + bufcat_su(h, "margin-top", &su); + bufcat_style(h, "clear", "both"); + PAIR_STYLE_INIT(&tag, h); + print_otag(h, TAG_DIV, 1, &tag); + return(1); + } + + bufcat_su(h, "min-width", &su); + SCALE_INVERT(&su); + bufcat_su(h, "margin-left", &su); + SCALE_HS_INIT(&su, 1); + bufcat_su(h, "margin-right", &su); + bufcat_style(h, "clear", "left"); + + if (n->next && n->next->child) + bufcat_style(h, "float", "left"); + + PAIR_STYLE_INIT(&tag, h); + print_otag(h, TAG_DIV, 1, &tag); + + /* With a length string, manually omit the last child. */ + + if ( ! width) + return(1); + + if (MAN_IP == n->tok) + for (nn = n->child; nn->next; nn = nn->next) + print_man_node(m, nn, h); + if (MAN_TP == n->tok) + for (nn = n->child->next; nn; nn = nn->next) + print_man_node(m, nn, h); + + return(0); +} + + +/* ARGSUSED */ +static int +man_HP_pre(MAN_ARGS) +{ + const struct man_node *nn; + struct htmlpair tag; + struct roffsu su; + + if (MAN_HEAD == n->type) + return(0); + + nn = MAN_BLOCK == n->type ? + n->head->child : n->parent->head->child; + + SCALE_HS_INIT(&su, INDENT); + + if (NULL != nn) + (void)a2width(nn, &su); + + if (MAN_BLOCK == n->type) { + bufcat_su(h, "margin-left", &su); + SCALE_VS_INIT(&su, 1); + bufcat_su(h, "margin-top", &su); + bufcat_style(h, "clear", "both"); + PAIR_STYLE_INIT(&tag, h); + print_otag(h, TAG_DIV, 1, &tag); + return(1); + } + + bufcat_su(h, "margin-left", &su); + SCALE_INVERT(&su); + bufcat_su(h, "text-indent", &su); + + PAIR_STYLE_INIT(&tag, h); + print_otag(h, TAG_DIV, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +man_B_pre(MAN_ARGS) +{ + struct htmlpair tag; + + PAIR_CLASS_INIT(&tag, "bold"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +man_I_pre(MAN_ARGS) +{ + struct htmlpair tag; + + PAIR_CLASS_INIT(&tag, "italic"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +man_ign_pre(MAN_ARGS) +{ + + return(0); +} + + +/* ARGSUSED */ +static int +man_RS_pre(MAN_ARGS) +{ + struct htmlpair tag; + struct roffsu su; + + if (MAN_HEAD == n->type) + return(0); + else if (MAN_BODY == n->type) + return(1); + + SCALE_HS_INIT(&su, INDENT); + bufcat_su(h, "margin-left", &su); + + if (n->head->child) { + SCALE_VS_INIT(&su, 1); + a2width(n->head->child, &su); + bufcat_su(h, "margin-top", &su); + } + + PAIR_STYLE_INIT(&tag, h); + print_otag(h, TAG_DIV, 1, &tag); + return(1); +} diff --git a/usr.bin/mandoc/man_term.c b/usr.bin/mandoc/man_term.c index 54dbe2651f6..68a8a45b113 100644 --- a/usr.bin/mandoc/man_term.c +++ b/usr.bin/mandoc/man_term.c @@ -1,4 +1,4 @@ -/* $Id: man_term.c,v 1.17 2009/10/19 21:43:16 schwarze Exp $ */ +/* $Id: man_term.c,v 1.18 2009/10/21 19:13:50 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -23,8 +23,11 @@ #include <stdlib.h> #include <string.h> -#include "term.h" +#include "out.h" #include "man.h" +#include "term.h" +#include "chars.h" +#include "main.h" #define INDENT 7 #define HALFINDENT 3 @@ -59,6 +62,18 @@ struct termact { void (*post)(DECL_ARGS); }; +static int arg2width(const struct man_node *); +static int arg2height(const struct man_node *); + +static void print_head(struct termp *, + const struct man_meta *); +static void print_body(DECL_ARGS); +static void print_node(DECL_ARGS); +static void print_foot(struct termp *, + const struct man_meta *); +static void print_bvspace(struct termp *, + const struct man_node *); + static int pre_B(DECL_ARGS); static int pre_BI(DECL_ARGS); static int pre_HP(DECL_ARGS); @@ -123,77 +138,86 @@ static const struct termact termacts[MAN_MAX] = { { pre_ign, NULL }, /* UC */ }; -static void print_head(struct termp *, - const struct man_meta *); -static void print_body(DECL_ARGS); -static void print_node(DECL_ARGS); -static void print_foot(struct termp *, - const struct man_meta *); -static void fmt_block_vspace(struct termp *, - const struct man_node *); -static int arg_width(const struct man_node *); void -man_run(struct termp *p, const struct man *m) +terminal_man(void *arg, const struct man *man) { - struct mtermp mt; + struct termp *p; + const struct man_node *n; + const struct man_meta *m; + struct mtermp mt; + + p = (struct termp *)arg; + + if (NULL == p->symtab) + switch (p->enc) { + case (TERMENC_ASCII): + p->symtab = chars_init(CHARS_ASCII); + break; + default: + abort(); + /* NOTREACHED */ + } + + n = man_node(man); + m = man_meta(man); - print_head(p, man_meta(m)); + print_head(p, m); p->flags |= TERMP_NOSPACE; mt.fl = 0; mt.lmargin = INDENT; mt.offset = INDENT; - if (man_node(m)->child) - print_body(p, &mt, man_node(m)->child, man_meta(m)); - print_foot(p, man_meta(m)); + if (n->child) + print_body(p, &mt, n->child, m); + print_foot(p, m); } -static void -fmt_block_vspace(struct termp *p, const struct man_node *n) +static int +arg2height(const struct man_node *n) { - term_newln(p); + struct roffsu su; - if (NULL == n->prev) - return; - - if (MAN_SS == n->prev->tok) - return; - if (MAN_SH == n->prev->tok) - return; + assert(MAN_TEXT == n->type); + assert(n->string); + if ( ! a2roffsu(n->string, &su, SCALE_VS)) + SCALE_VS_INIT(&su, strlen(n->string)); - term_vspace(p); + return((int)term_vspan(&su)); } static int -arg_width(const struct man_node *n) +arg2width(const struct man_node *n) { - int i, len; - const char *p; + struct roffsu su; assert(MAN_TEXT == n->type); assert(n->string); + if ( ! a2roffsu(n->string, &su, SCALE_BU)) + return(-1); - p = n->string; + return((int)term_hspan(&su)); +} - if (0 == (len = (int)strlen(p))) - return(-1); - for (i = 0; i < len; i++) - if ( ! isdigit((u_char)p[i])) - break; +static void +print_bvspace(struct termp *p, const struct man_node *n) +{ + term_newln(p); - if (i == len - 1) { - if ('n' == p[len - 1] || 'm' == p[len - 1]) - return(atoi(p)); - } else if (i == len) - return(atoi(p)); + if (NULL == n->prev) + return; - return(-1); + if (MAN_SS == n->prev->tok) + return; + if (MAN_SH == n->prev->tok) + return; + + term_vspace(p); } @@ -392,12 +416,8 @@ pre_sp(DECL_ARGS) { int i, len; - if (NULL == n->child) { - term_vspace(p); - return(0); - } + len = n->child ? arg2height(n->child) : 1; - len = atoi(n->child->string); if (0 == len) term_newln(p); for (i = 0; i < len; i++) @@ -427,7 +447,7 @@ pre_HP(DECL_ARGS) switch (n->type) { case (MAN_BLOCK): - fmt_block_vspace(p, n); + print_bvspace(p, n); return(1); case (MAN_BODY): p->flags |= TERMP_NOBREAK; @@ -443,7 +463,7 @@ pre_HP(DECL_ARGS) /* Calculate offset. */ if (NULL != (nn = n->parent->head->child)) - if ((ival = arg_width(nn)) >= 0) + if ((ival = arg2width(nn)) >= 0) len = (size_t)ival; if (0 == len) @@ -489,7 +509,7 @@ pre_PP(DECL_ARGS) switch (n->type) { case (MAN_BLOCK): mt->lmargin = INDENT; - fmt_block_vspace(p, n); + print_bvspace(p, n); break; default: p->offset = mt->offset; @@ -518,7 +538,7 @@ pre_IP(DECL_ARGS) p->flags |= TERMP_TWOSPACE; break; case (MAN_BLOCK): - fmt_block_vspace(p, n); + print_bvspace(p, n); /* FALLTHROUGH */ default: return(1); @@ -533,7 +553,7 @@ pre_IP(DECL_ARGS) if (NULL != (nn = nn->next)) { for ( ; nn->next; nn = nn->next) /* Do nothing. */ ; - if ((ival = arg_width(nn)) >= 0) + if ((ival = arg2width(nn)) >= 0) len = (size_t)ival; } @@ -607,7 +627,7 @@ pre_TP(DECL_ARGS) p->flags |= TERMP_NOSPACE; break; case (MAN_BLOCK): - fmt_block_vspace(p, n); + print_bvspace(p, n); /* FALLTHROUGH */ default: return(1); @@ -620,7 +640,7 @@ pre_TP(DECL_ARGS) if (NULL != (nn = n->parent->head->child)) if (NULL != nn->next) - if ((ival = arg_width(nn)) >= 0) + if ((ival = arg2width(nn)) >= 0) len = (size_t)ival; switch (n->type) { @@ -798,7 +818,7 @@ pre_RS(DECL_ARGS) return(1); } - if ((ival = arg_width(nn)) < 0) + if ((ival = arg2width(nn)) < 0) return(1); mt->offset = INDENT + (size_t)ival; diff --git a/usr.bin/mandoc/man_validate.c b/usr.bin/mandoc/man_validate.c index 358c23bdb91..50e28d0feda 100644 --- a/usr.bin/mandoc/man_validate.c +++ b/usr.bin/mandoc/man_validate.c @@ -1,4 +1,4 @@ -/* $Id: man_validate.c,v 1.9 2009/09/18 22:46:14 schwarze Exp $ */ +/* $Id: man_validate.c,v 1.10 2009/10/21 19:13:50 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -37,14 +37,13 @@ struct man_valid { static int check_bline(CHKARGS); static int check_eq0(CHKARGS); -static int check_eq1(CHKARGS); +static int check_le1(CHKARGS); static int check_ge2(CHKARGS); static int check_le5(CHKARGS); static int check_par(CHKARGS); static int check_part(CHKARGS); static int check_root(CHKARGS); static int check_sec(CHKARGS); -static int check_sp(CHKARGS); static int check_text(CHKARGS); static v_check posts_eq0[] = { check_eq0, NULL }; @@ -52,7 +51,7 @@ static v_check posts_ge2_le5[] = { check_ge2, check_le5, NULL }; static v_check posts_par[] = { check_par, NULL }; static v_check posts_part[] = { check_part, NULL }; static v_check posts_sec[] = { check_sec, NULL }; -static v_check posts_sp[] = { check_sp, NULL }; +static v_check posts_sp[] = { check_le1, NULL }; static v_check pres_bline[] = { check_bline, NULL }; static const struct man_valid man_valids[MAN_MAX] = { @@ -205,42 +204,12 @@ check_##name(CHKARGS) \ } INEQ_DEFINE(0, ==, eq0) -INEQ_DEFINE(1, ==, eq1) +INEQ_DEFINE(1, <=, le1) INEQ_DEFINE(2, >=, ge2) INEQ_DEFINE(5, <=, le5) static int -check_sp(CHKARGS) -{ - long lval; - char *ep, *buf; - - if (NULL == n->child) - return(1); - else if ( ! check_eq1(m, n)) - return(0); - - assert(MAN_TEXT == n->child->type); - buf = n->child->string; - assert(buf); - - /* From OpenBSD's strtol(3). */ - - errno = 0; - lval = strtol(buf, &ep, 10); - if (buf[0] == '\0' || *ep != '\0') - return(man_nerr(m, n->child, WNUMFMT)); - - if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) || - (lval > INT_MAX || lval < 0)) - return(man_nerr(m, n->child, WNUMFMT)); - - return(1); -} - - -static int check_sec(CHKARGS) { diff --git a/usr.bin/mandoc/mandoc.1 b/usr.bin/mandoc/mandoc.1 index d92aa0a4949..e3804058c28 100644 --- a/usr.bin/mandoc/mandoc.1 +++ b/usr.bin/mandoc/mandoc.1 @@ -1,4 +1,4 @@ -.\" $Id: mandoc.1,v 1.16 2009/09/18 22:46:14 schwarze Exp $ +.\" $Id: mandoc.1,v 1.17 2009/10/21 19:13:50 schwarze Exp $ .\" .\" Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: September 18 2009 $ +.Dd $Mdocdate: October 21 2009 $ .Dt MANDOC 1 .Os . @@ -26,11 +26,12 @@ . .Sh SYNOPSIS .Nm mandoc -.Op Fl V .Op Fl f Ns Ar option... .Op Fl m Ns Ar format -.Op Fl W Ns Ar err... +.Op Fl o Ns Ar option... .Op Fl T Ns Ar output +.Op Fl V +.Op Fl W Ns Ar err... .Op Ar infile... . . @@ -43,7 +44,7 @@ manual pages for display. The arguments are as follows: . .Bl -tag -width Ds .It Fl f Ns Ar option... -Override default compiler behaviour. See +Comma-separated compiler options. See .Sx Compiler Options for details. . @@ -53,6 +54,11 @@ Input format. See for available formats. Defaults to .Fl m Ns Ar andoc . . +.It Fl o Ns Ar option... +Comma-separated output options. See +.Sx Output Options +for details. +. .It Fl T Ns Ar output Output format. See .Sx Output Formats @@ -63,7 +69,7 @@ for available formats. Defaults to Print version and exit. . .It Fl W Ns Ar err... -Configure warning messages. Use +Comma-separated warning options. Use .Fl W Ns Ar all to print warnings, .Fl W Ns Ar error @@ -196,6 +202,9 @@ arguments: Produce 7-bit ASCII output, backspace-encoded for bold and underline styles. This is the default. . +.It Fl T Ns Ar html +Produce strict HTML-4.01 output, with a sane default style. +. .It Fl T Ns Ar tree Produce an indented parse tree. . @@ -241,16 +250,42 @@ Don't halt when encountering parse errors. Useful with over a large set of manuals passed on the command line. .El . -.Pp -As with the -.Fl W -flag, multiple -.Fl f -options may be grouped and delimited with a comma. Using -.Fl f Ns Ar ign-scope,no-ign-escape , -for example, will try to ignore scope and not ignore character-escape -errors. -. +.Ss Output Options +For the time being, only +.Fl T Ns Ar html +is the only mode with output options: +.Bl -tag -width Ds +.It Fl o Ns Ar style=style.css +The file +.Ar style.css +is used for an external style-sheet. This must be a valid absolute or +relative URI. +.It Fl o Ns Ar includes=fmt +The string +.Ar fmt , +for example, +.Ar ../src/%I.html , +is used as a template for linked header files (usually via the +.Sq \&In +macro). Instances of +.Sq \&%I +are replaced with the include filename. The default is not to present a +hyperlink. +.It Fl o Ns Ar man=fmt +The string +.Ar fmt , +for example, +.Ar ../html%S/%N.%S.html , +is used as a template for linked manuals (usually via the +.Sq \&Xr +macro). Instances of +.Sq \&%N +and +.Sq %S +are replaced with the linked manual's name and section, respectively. +If no section is included, section 1 is assumed. The default is not to +present a hyperlink. +.El . .Sh EXAMPLES To page manuals to the terminal: @@ -260,6 +295,12 @@ To page manuals to the terminal: .D1 % mandoc mandoc.1 mdoc.3 mdoc.7 | less . .Pp +To produce HTML manuals with +.Ar style.css +as the style-sheet: +.Pp +.D1 % mandoc \-Thtml -ostyle=style.css mdoc.7 > mdoc.7.html +.Pp To check over a large set of manuals: . .Pp @@ -333,14 +374,43 @@ retains spaces. .It Sentences are unilaterally monospaced. .El +. +.Ss HTML output +.Bl -bullet -compact +.It +The +.Xr mdoc 7 +.Sq \&Bl \-hang +and +.Sq \&Bl \-tag +list types render similarly (no break following overreached left-hand +side) due to the expressive constraints of HTML. +. +.It +The +.Xr man 7 +.Sq IP +and +.Sq TP +lists render similarly. +.El .\" SECTION .Sh SEE ALSO .Xr mandoc_char 7 , .Xr mdoc 7 , .Xr man 7 -.\" SECTION +. .Sh AUTHORS The .Nm utility was written by .An Kristaps Dzonsons Aq kristaps@kth.se . +. +.Sh CAVEATS +In +.Fl T Ns Ar html , +the maximum size of an element attribute is determined by +.Dv BUFSIZ , +which is usually 1024 bytes. Be aware of this when setting long link +formats with +.Fl o Ns Ar man=fmt . diff --git a/usr.bin/mandoc/mandoc_char.7 b/usr.bin/mandoc/mandoc_char.7 index 3c1bf120305..d2975be52a9 100644 --- a/usr.bin/mandoc/mandoc_char.7 +++ b/usr.bin/mandoc/mandoc_char.7 @@ -1,4 +1,4 @@ -.\" $Id: mandoc_char.7,v 1.6 2009/10/19 09:48:17 schwarze Exp $ +.\" $Id: mandoc_char.7,v 1.7 2009/10/21 19:13:50 schwarze Exp $ .\" .\" Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: October 19 2009 $ +.Dd $Mdocdate: October 21 2009 $ .Dt MANDOC_CHAR 7 .Os . @@ -76,13 +76,32 @@ Note that each output mode will have a different rendering of the characters. It's guaranteed that each input symbol will correspond to a (more or less) meaningful output rendering, regardless the mode. . -. -.Sh Special Characters +.Ss ASCII output +Formatting documents with ASCII output results in a 7-bit ASCII +approximation of zero or more characters, for example, the +.Dq aleph +character +.Sq \e(Ah +will render as +.Sq N . +Approximations are a best-effort, and naturally some clarity will be lost. +. +.Ss HTML output +The HTML output mode uses decimal-encoded UTF-8 for sequences, for +example, the +.Dq aleph +character +.Sq \e(Ah +will render as +.Sq ℵ . +. +. +.Sh SPECIAL CHARACTERS These are the preferred input symbols for producing special characters. . .Pp Spacing: -.Bl -compact -offset indent -column 10n 20n +.Bl -column -compact -offset indent 10m 20m .It Em Input Ta Em Description .It \e~ Ta non-breaking, non-collapsing space .It \e Ta breaking, non-collapsing n-width space @@ -95,7 +114,7 @@ Spacing: . .Pp Lines: -.Bl -compact -offset indent -column 10n 10n 10n +.Bl -column -compact -offset indent 10m 10m 10m .It Em Input Ta Em Rendered Ta Em Description .It \e(ba Ta \(ba Ta bar .It \e(br Ta \(br Ta box rule @@ -108,7 +127,7 @@ Lines: . .Pp Text markers: -.Bl -compact -offset indent -column 10n 10n 10n +.Bl -column -compact -offset indent 10m 10m 10m .It Em Input Ta Em Rendered Ta Em Description .It \e(ci Ta \(ci Ta circle .It \e(bu Ta \(bu Ta bullet @@ -128,7 +147,7 @@ Text markers: . .Pp Legal symbols: -.Bl -compact -offset indent -column 10n 10n 10n +.Bl -column -compact -offset indent 10m 10m 10m .It Em Input Ta Em Rendered Ta Em Description .It \e(co Ta \(co Ta copyright .It \e(rg Ta \(rg Ta registered @@ -137,7 +156,7 @@ Legal symbols: . .Pp Punctuation: -.Bl -compact -offset indent -column 10n 10n 10n +.Bl -column -compact -offset indent 10m 10m 10m .It Em Input Ta Em Rendered Ta Em Description .It \e(em Ta \(em Ta em-dash .It \e(en Ta \(en Ta en-dash @@ -151,7 +170,7 @@ Punctuation: . .Pp Quotes: -.Bl -compact -offset indent -column 10n 10n 10n +.Bl -column -compact -offset indent 10m 10m 10m .It Em Input Ta Em Rendered Ta Em Description .It \e(Bq Ta \(Bq Ta right low double-quote .It \e(bq Ta \(bq Ta right low single-quote @@ -169,7 +188,7 @@ Quotes: . .Pp Brackets: -.Bl -compact -offset indent -column 10n 10n 10n +.Bl -column -compact -offset indent 10m 10m 10m .It Em Input Ta Em Rendered Ta Em Description .It \e(lB Ta \(lB Ta left bracket .It \e(rB Ta \(rB Ta right bracket @@ -209,7 +228,7 @@ Brackets: . .Pp Arrows: -.Bl -compact -offset indent -column 10n 10n 10n +.Bl -column -compact -offset indent 10m 10m 10m .It Em Input Ta Em Rendered Ta Em Description .It \e(<- Ta \(<- Ta left arrow .It \e(-> Ta \(-> Ta right arrow @@ -227,7 +246,7 @@ Arrows: . .Pp Logical: -.Bl -compact -offset indent -column 10n 10n 10n +.Bl -column -compact -offset indent 10m 10m 10m .It Em Input Ta Em Rendered Ta Em Description .It \e(AN Ta \(AN Ta logical and .It \e(OR Ta \(OR Ta logical or @@ -243,7 +262,7 @@ Logical: . .Pp Mathematical: -.Bl -compact -offset indent -column 10n 10n 10n +.Bl -column -compact -offset indent 10m 10m 10m .It Em Input Ta Em Rendered Ta Em Description .It \e(pl Ta \(pl Ta plus .It \e(mi Ta \(mi Ta minus @@ -309,7 +328,7 @@ Mathematical: . .Pp Ligatures: -.Bl -compact -offset indent -column 10n 10n 10n +.Bl -column -compact -offset indent 10m 10m 10m .It Em Input Ta Em Rendered Ta Em Description .It \e(ff Ta \(ff Ta ff ligature .It \e(fi Ta \(fi Ta fi ligature @@ -327,7 +346,7 @@ Ligatures: . .Pp Accents: -.Bl -compact -offset indent -column 10n 10n 10n +.Bl -column -compact -offset indent 10m 10m 10m .It Em Input Ta Em Rendered Ta Em Description .It \e(a" Ta \(a" Ta Hungarian umlaut .It \e(a- Ta \(a- Ta macron @@ -350,7 +369,7 @@ Accents: . .Pp Accented letters: -.Bl -compact -offset indent -column 10n 10n 10n +.Bl -column -compact -offset indent 10m 10m 10m .It Em Input Ta Em Rendered Ta Em Description .It \e('A Ta \('A Ta acute A .It \e('E Ta \('E Ta acute E @@ -411,7 +430,7 @@ Accented letters: . .Pp Special letters: -.Bl -compact -offset indent -column 10n 10n 10n +.Bl -column -compact -offset indent 10m 10m 10m .It Em Input Ta Em Rendered Ta Em Description .It \e(-D Ta \(-D Ta Eth .It \e(Sd Ta \(Sd Ta eth @@ -423,7 +442,7 @@ Special letters: . .Pp Currency: -.Bl -compact -offset indent -column 10n 10n 10n +.Bl -column -compact -offset indent 10m 10m 10m .It Em Input Ta Em Rendered Ta Em Description .It \e(Do Ta \(Do Ta dollar .It \e(ct Ta \(ct Ta cent @@ -437,7 +456,7 @@ Currency: . .Pp Units: -.Bl -compact -offset indent -column 10n 10n 10n +.Bl -column -compact -offset indent 10m 10m 10m .It Em Input Ta Em Rendered Ta Em Description .It \e(de Ta \(de Ta degree .It \e(%0 Ta \(%0 Ta per-thousand @@ -448,7 +467,7 @@ Units: . .Pp Greek letters: -.Bl -compact -offset indent -column 10n 10n 10n +.Bl -column -compact -offset indent 10m 10m 10m .It Em Input Ta Em Rendered Ta Em Description .It \e(*A Ta \(*A Ta Alpha .It \e(*B Ta \(*B Ta Beta @@ -511,7 +530,7 @@ These are not recommended for use, as they differ across implementations: . .Pp -.Bl -compact -offset indent -column 10n 10n 10n +.Bl -column -compact -offset indent 10m 10m 10m .It Em Input Ta Em Rendered Ta Em Description .It \e*(Ba Ta \*(Ba Ta vertical bar .It \e*(Ne Ta \*(Ne Ta not equal @@ -577,6 +596,19 @@ having no known representation: .Xr mandoc 1 . . +.Sh STANDARDS +.Rs +.%A The Unicode Consortium +.%T The Unicode Standard: Worldwide Character Encoding, Version 5.2 +.%D 1991 +.Re +.Rs +.%A W3C +.%T HTML 4.01 Specification +.%D December, 1999 +.Re +. +. .Sh AUTHORS The .Nm diff --git a/usr.bin/mandoc/mdoc.7 b/usr.bin/mandoc/mdoc.7 index 120630b418a..6c3cec176e0 100644 --- a/usr.bin/mandoc/mdoc.7 +++ b/usr.bin/mandoc/mdoc.7 @@ -1,4 +1,4 @@ -.\" $Id: mdoc.7,v 1.16 2009/10/19 20:44:35 schwarze Exp $ +.\" $Id: mdoc.7,v 1.17 2009/10/21 19:13:50 schwarze Exp $ .\" .\" Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: October 19 2009 $ +.Dd $Mdocdate: October 21 2009 $ .Dt MDOC 7 .Os . @@ -73,6 +73,7 @@ whitespace are stripped from input. . .Ss Reserved Characters Within a macro line, the following characters are reserved: +.Pp .Bl -tag -width Ds -offset indent -compact .It \&. .Pq period @@ -208,19 +209,124 @@ considered literal text. Thus, the following produces .Pp In free-form mode, quotes are regarded as opaque text. . +.Ss Dates +There are several macros in +.Nm +that require a date argument. The +.Em canonical form +for dates is the American format: +.Pp +.D1 Cm Month Day , Year +.Pp +The +.Cm Day +value is an optionally zero-padded numeral. The +.Cm Month +value is the full month name. The +.Cm Year +value is the full four-digit year. +.Pp +The +.Em non-canonical form +is the same as the canonical form, but without the comma between the +.Cm Day +and +.Cm Year +field. +.Pp +Lastly, +.Em reduced form +dates range from only a +.Cm Year +to the full canonical or non-canonical form. +.Pp +Some examples of valid dates follow: +.Pp +.D1 "May, 2009" Pq reduced form +.D1 "2009" Pq reduced form +.D1 "May 20, 2009" Pq canonical form +.D1 "May 20 2009" Pq non-canonical form +. +.Ss Scaling Widths +Many macros support scaled widths for their arguments, such as +stipulating a two-inch list indentation with the following: +.Bd -literal -offset indent +\&.Bl -tag -width 2i +.Ed +. +.Pp +The syntax for scaled widths is +.Sq Li [+-]?[0-9]*.[0-9]*[:unit:] , +where a decimal must be preceded or proceeded by at least one digit. +Negative numbers, while accepted, are truncated to zero. The following +scaling units are accepted: +.Pp +.Bl -tag -width Ds -offset indent -compact +.It c +centimetre +.It i +inch +.It P +pica (~1/6 inch) +.It p +point (~1/72 inch) +.It f +synonym for +.Sq u +.It v +default vertical span +.It m +width of rendered +.Sq m +.Pq em +character +.It n +width of rendered +.Sq n +.Pq en +character +.It u +default horizontal span +.It M +mini-em (~1/100 em) +.El +.Pp +Using anything other than +.Sq m , +.Sq n , +.Sq u , +or +.Sq v +is necessarily non-portable across output media. See +.Sx COMPATIBILITY . +. . .Sh MANUAL STRUCTURE -Each +A well-formed .Nm -document must begin with a document prologue, containing, in order, -.Sq \&Dd , -.Sq \&Dt , +document consists of a document prologue followed by one or more +sections. +.Pp +The prologue, which consists of (in order) the +.Sx \&Dd , +.Sx \&Dt , and -.Sq \&Os , -then the NAME section containing at least one -.Sq \&Nm +.Sx \&Os +macros, is required for every document. +.Pp +The first section (sections are denoted by +.Sx \&Sh ) +must be the NAME section, consisting of at least one +.Sx \&Nm followed by -.Sq \&Nd : +.Sx \&Nd . +.Pp +Following that, convention dictates specifying at least the SYNOPSIS and +DESCRIPTION sections, although this varies between manual sections. +.Pp +The following is a well-formed skeleton +.Nm +file: .Bd -literal -offset indent \&.Dd $\&Mdocdate$ \&.Dt mdoc 7 @@ -263,10 +369,44 @@ utility processes files ... \&.\e\*q .Sh BUGS \&.\e\*q .Sh SECURITY CONSIDERATIONS .Ed -. .Pp -Subsequent SYNOPSIS and DESCRIPTION sections are strongly encouraged, -but non-compulsory. +The sections in a +.Nm +document are conventionally ordered as they appear above. Sections +should be composed as follows: +.Bl -tag -width Ds -offset Ds +.It NAME +Must contain at least one +.Sx \&Nm +followed by +.Sx \&Nd . +The name needs re-stating since one +.Nm +documents can be used for more than one utility or function, such as +.Xr grep 1 +also being referenced as +.Xr egrep 1 +and +.Xr fgrep 1 . +.It LIBRARY +.It SYNOPSIS +.It DESCRIPTION +.It IMPLEMENTATION NOTES +.It EXIT STATUS +.It RETURN VALUES +.It ENVIRONMENT +.It FILES +.It EXAMPLES +.It DIAGNOSTICS +.It ERRORS +.It SEE ALSO +.It STANDARDS +.It HISTORY +.It AUTHORS +.It CAVEATS +.It BUGS +.It SECURITY CONSIDERATIONS +.El . . .Sh MACRO SYNTAX @@ -274,11 +414,12 @@ Macros are one to three three characters in length and begin with a control character , .Sq \&. , at the beginning of the line. An arbitrary amount of whitespace may -sit between the control character and the macro name. Thus, -.Sq \&.Pp -and -.Sq \&.\ \ \ \&Pp -are equivalent. Macro names are two or three characters in length. +sit between the control character and the macro name. Thus, the +following are equivalent: +.Bd -literal -offset indent +\&.Pp +\&.\ \ \ \&Pp +.Ed . .Pp The syntax of a macro depends on its classification. In this section, @@ -317,7 +458,7 @@ column, if applicable, describes closure rules. .Ss Block full-explicit Multi-line scope closed by an explicit closing macro. All macros contains bodies; only -.Pq Sq \&Bf +.Sx \&Bf contains a head. .Bd -literal -offset indent \&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead...\(rB @@ -328,14 +469,14 @@ contains a head. .Pp .Bl -column -compact -offset indent "MacroX" "CallableX" "ParsableX" "closed by XXX" .It Em Macro Ta Em Callable Ta Em Parsable Ta Em Scope -.It \&Bd Ta \&No Ta \&No Ta closed by \&Ed -.It \&Bf Ta \&No Ta \&No Ta closed by \&Ef -.It \&Bk Ta \&No Ta \&No Ta closed by \&Ek -.It \&Bl Ta \&No Ta \&No Ta closed by \&El -.It \&Ed Ta \&No Ta \&No Ta opened by \&Bd -.It \&Ef Ta \&No Ta \&No Ta opened by \&Bf -.It \&Ek Ta \&No Ta \&No Ta opened by \&Bk -.It \&El Ta \&No Ta \&No Ta opened by \&Bl +.It Sx \&Bd Ta \&No Ta \&No Ta closed by Sx \&Ed +.It Sx \&Bf Ta \&No Ta \&No Ta closed by Sx \&Ef +.It Sx \&Bk Ta \&No Ta \&No Ta closed by Sx \&Ek +.It Sx \&Bl Ta \&No Ta \&No Ta closed by Sx \&El +.It Sx \&Ed Ta \&No Ta \&No Ta opened by Sx \&Bd +.It Sx \&Ef Ta \&No Ta \&No Ta opened by Sx \&Bf +.It Sx \&Ek Ta \&No Ta \&No Ta opened by Sx \&Bk +.It Sx \&El Ta \&No Ta \&No Ta opened by Sx \&Bl .El . . @@ -343,15 +484,17 @@ contains a head. Multi-line scope closed by end-of-file or implicitly by another macro. All macros have bodies; some .Po -.Sq \&It \-bullet , -.Sq \-hyphen , -.Sq \-dash , -.Sq \-enum , -.Sq \-item +.Sx \&It Fl bullet , +.Fl hyphen , +.Fl dash , +.Fl enum , +.Fl item .Pc -don't have heads, while -.Sq \&It \-column -may have multiple heads. +don't have heads; only one +.Po +.Sx \&It Fl column +.Pc +has multiple heads. .Bd -literal -offset indent \&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead... \(lBTa head...\(rB\(rB \(lBbody...\(rB @@ -360,19 +503,22 @@ may have multiple heads. .Pp .Bl -column -compact -offset indent "MacroX" "CallableX" "ParsableX" "closed by XXXXXXXXXXX" .It Em Macro Ta Em Callable Ta Em Parsable Ta Em Scope -.It \&It Ta \&No Ta Yes Ta closed by \&It, \&El -.It \&Nd Ta \&No Ta \&No Ta closed by \&Sh -.It \&Sh Ta \&No Ta \&No Ta closed by \&Sh -.It \&Ss Ta \&No Ta \&No Ta closed by \&Sh, \&Ss +.It Sx \&It Ta \&No Ta Yes Ta closed by Sx \&It , Sx \&El +.It Sx \&Nd Ta \&No Ta \&No Ta closed by Sx \&Sh +.It Sx \&Sh Ta \&No Ta \&No Ta closed by Sx \&Sh +.It Sx \&Ss Ta \&No Ta \&No Ta closed by Sx \&Sh , Sx \&Ss .El . . .Ss Block partial-explicit Like block full-explicit, but also with single-line scope. Each has at least a body and, in limited circumstances, a head -.Pq So \&Fo Sc , So \&Eo Sc +.Po +.Sx \&Fo , +.Sx \&Eo +.Pc and/or tail -.Pq So \&Ec Sc . +.Pq Sx \&Ec . .Bd -literal -offset indent \&.Yo \(lB\-arg \(lBparm...\(rB\(rB \(lBhead...\(rB \(lBbody...\(rB @@ -385,30 +531,30 @@ and/or tail .Pp .Bl -column "MacroX" "CallableX" "ParsableX" "closed by XXXX" -compact -offset indent .It Em Macro Ta Em Callable Ta Em Parsable Ta Em Scope -.It \&Ac Ta Yes Ta Yes Ta opened by \&Ao -.It \&Ao Ta Yes Ta Yes Ta closed by \&Ac -.It \&Bc Ta Yes Ta Yes Ta closed by \&Bo -.It \&Bo Ta Yes Ta Yes Ta opened by \&Bc -.It \&Brc Ta Yes Ta Yes Ta opened by \&Bro -.It \&Bro Ta Yes Ta Yes Ta closed by \&Brc -.It \&Dc Ta Yes Ta Yes Ta opened by \&Do -.It \&Do Ta Yes Ta Yes Ta closed by \&Dc -.It \&Ec Ta Yes Ta Yes Ta opened by \&Eo -.It \&Eo Ta Yes Ta Yes Ta closed by \&Ec -.It \&Fc Ta Yes Ta Yes Ta opened by \&Fo -.It \&Fo Ta \&No Ta \&No Ta closed by \&Fc -.It \&Oc Ta Yes Ta Yes Ta closed by \&Oo -.It \&Oo Ta Yes Ta Yes Ta opened by \&Oc -.It \&Pc Ta Yes Ta Yes Ta closed by \&Po -.It \&Po Ta Yes Ta Yes Ta opened by \&Pc -.It \&Qc Ta Yes Ta Yes Ta opened by \&Oo -.It \&Qo Ta Yes Ta Yes Ta closed by \&Oc -.It \&Re Ta \&No Ta \&No Ta opened by \&Rs -.It \&Rs Ta \&No Ta \&No Ta closed by \&Re -.It \&Sc Ta Yes Ta Yes Ta opened by \&So -.It \&So Ta Yes Ta Yes Ta closed by \&Sc -.It \&Xc Ta Yes Ta Yes Ta opened by \&Xo -.It \&Xo Ta Yes Ta Yes Ta closed by \&Xc +.It Sx \&Ac Ta Yes Ta Yes Ta opened by Sx \&Ao +.It Sx \&Ao Ta Yes Ta Yes Ta closed by Sx \&Ac +.It Sx \&Bc Ta Yes Ta Yes Ta closed by Sx \&Bo +.It Sx \&Bo Ta Yes Ta Yes Ta opened by Sx \&Bc +.It Sx \&Brc Ta Yes Ta Yes Ta opened by Sx \&Bro +.It Sx \&Bro Ta Yes Ta Yes Ta closed by Sx \&Brc +.It Sx \&Dc Ta Yes Ta Yes Ta opened by Sx \&Do +.It Sx \&Do Ta Yes Ta Yes Ta closed by Sx \&Dc +.It Sx \&Ec Ta Yes Ta Yes Ta opened by Sx \&Eo +.It Sx \&Eo Ta Yes Ta Yes Ta closed by Sx \&Ec +.It Sx \&Fc Ta Yes Ta Yes Ta opened by Sx \&Fo +.It Sx \&Fo Ta \&No Ta \&No Ta closed by Sx \&Fc +.It Sx \&Oc Ta Yes Ta Yes Ta closed by Sx \&Oo +.It Sx \&Oo Ta Yes Ta Yes Ta opened by Sx \&Oc +.It Sx \&Pc Ta Yes Ta Yes Ta closed by Sx \&Po +.It Sx \&Po Ta Yes Ta Yes Ta opened by Sx \&Pc +.It Sx \&Qc Ta Yes Ta Yes Ta opened by Sx \&Oo +.It Sx \&Qo Ta Yes Ta Yes Ta closed by Sx \&Oc +.It Sx \&Re Ta \&No Ta \&No Ta opened by Sx \&Rs +.It Sx \&Rs Ta \&No Ta \&No Ta closed by Sx \&Re +.It Sx \&Sc Ta Yes Ta Yes Ta opened by Sx \&So +.It Sx \&So Ta Yes Ta Yes Ta closed by Sx \&Sc +.It Sx \&Xc Ta Yes Ta Yes Ta opened by Sx \&Xo +.It Sx \&Xo Ta Yes Ta Yes Ta closed by Sx \&Xc .El . . @@ -423,17 +569,17 @@ or end of line. .Pp .Bl -column "MacroX" "CallableX" "ParsableX" -compact -offset indent .It Em Macro Ta Em Callable Ta Em Parsable -.It \&Aq Ta Yes Ta Yes -.It \&Bq Ta Yes Ta Yes -.It \&Brq Ta Yes Ta Yes -.It \&D1 Ta \&No Ta \&Yes -.It \&Dl Ta \&No Ta Yes -.It \&Dq Ta Yes Ta Yes -.It \&Op Ta Yes Ta Yes -.It \&Pq Ta Yes Ta Yes -.It \&Ql Ta Yes Ta Yes -.It \&Qq Ta Yes Ta Yes -.It \&Sq Ta Yes Ta Yes +.It Sx \&Aq Ta Yes Ta Yes +.It Sx \&Bq Ta Yes Ta Yes +.It Sx \&Brq Ta Yes Ta Yes +.It Sx \&D1 Ta \&No Ta \&Yes +.It Sx \&Dl Ta \&No Ta Yes +.It Sx \&Dq Ta Yes Ta Yes +.It Sx \&Op Ta Yes Ta Yes +.It Sx \&Pq Ta Yes Ta Yes +.It Sx \&Ql Ta Yes Ta Yes +.It Sx \&Qq Ta Yes Ta Yes +.It Sx \&Sq Ta Yes Ta Yes .El . . @@ -456,81 +602,1026 @@ then the macro accepts an arbitrary number of arguments. .Pp .Bl -column "MacroX" "CallableX" "ParsableX" "Arguments" -compact -offset indent .It Em Macro Ta Em Callable Ta Em Parsable Ta Em Arguments -.It \&%A Ta \&No Ta \&No Ta >0 -.It \&%B Ta \&No Ta \&No Ta >0 -.It \&%C Ta \&No Ta \&No Ta >0 -.It \&%D Ta \&No Ta \&No Ta >0 -.It \&%I Ta \&No Ta \&No Ta >0 -.It \&%J Ta \&No Ta \&No Ta >0 -.It \&%N Ta \&No Ta \&No Ta >0 -.It \&%O Ta \&No Ta \&No Ta >0 -.It \&%P Ta \&No Ta \&No Ta >0 -.It \&%R Ta \&No Ta \&No Ta >0 -.It \&%T Ta \&No Ta \&No Ta >0 -.It \&%V Ta \&No Ta \&No Ta >0 -.It \&Ad Ta Yes Ta Yes Ta n -.It \&An Ta Yes Ta Yes Ta n -.It \&Ap Ta Yes Ta Yes Ta 0 -.It \&Ar Ta Yes Ta Yes Ta n -.It \&At Ta Yes Ta Yes Ta 1 -.It \&Bsx Ta Yes Ta Yes Ta n -.It \&Bt Ta \&No Ta \&No Ta 0 -.It \&Bx Ta Yes Ta Yes Ta n -.It \&Cd Ta Yes Ta Yes Ta >0 -.It \&Cm Ta Yes Ta Yes Ta n -.It \&Db Ta \&No Ta \&No Ta 1 -.It \&Dd Ta \&No Ta \&No Ta >0 -.It \&Dt Ta \&No Ta \&No Ta n -.It \&Dv Ta Yes Ta Yes Ta n -.It \&Dx Ta Yes Ta Yes Ta n -.It \&Em Ta Yes Ta Yes Ta >0 -.It \&En Ta \&No Ta \&No Ta 0 -.It \&Er Ta Yes Ta Yes Ta >0 -.It \&Es Ta \&No Ta \&No Ta 0 -.It \&Ev Ta Yes Ta Yes Ta n -.It \&Ex Ta \&No Ta \&No Ta n -.It \&Fa Ta Yes Ta Yes Ta n -.It \&Fd Ta \&No Ta \&No Ta >0 -.It \&Fl Ta Yes Ta Yes Ta n -.It \&Fn Ta Yes Ta Yes Ta >0 -.It \&Fr Ta \&No Ta \&No Ta n -.It \&Ft Ta Yes Ta Yes Ta n -.It \&Fx Ta Yes Ta Yes Ta n -.It \&Hf Ta \&No Ta \&No Ta n -.It \&Ic Ta Yes Ta Yes Ta >0 -.It \&In Ta \&No Ta \&No Ta n -.It \&Lb Ta \&No Ta \&No Ta 1 -.It \&Li Ta Yes Ta Yes Ta n -.It \&Lk Ta Yes Ta Yes Ta n -.It \&Lp Ta \&No Ta \&No Ta 0 -.It \&Ms Ta Yes Ta Yes Ta >0 -.It \&Mt Ta Yes Ta Yes Ta >0 -.It \&Nm Ta Yes Ta Yes Ta n -.It \&No Ta Yes Ta Yes Ta 0 -.It \&Ns Ta Yes Ta Yes Ta 0 -.It \&Nx Ta Yes Ta Yes Ta n -.It \&Os Ta \&No Ta \&No Ta n -.It \&Ot Ta \&No Ta \&No Ta n -.It \&Ox Ta Yes Ta Yes Ta n -.It \&Pa Ta Yes Ta Yes Ta n -.It \&Pf Ta \&No Ta Yes Ta 1 -.It \&Pp Ta \&No Ta \&No Ta 0 -.It \&Rv Ta \&No Ta \&No Ta n -.It \&Sm Ta \&No Ta \&No Ta 1 -.It \&St Ta \&No Ta Yes Ta 1 -.It \&Sx Ta Yes Ta Yes Ta >0 -.It \&Sy Ta Yes Ta Yes Ta >0 -.It \&Tn Ta Yes Ta Yes Ta >0 -.It \&Ud Ta \&No Ta \&No Ta 0 -.It \&Ux Ta Yes Ta Yes Ta n -.It \&Va Ta Yes Ta Yes Ta n -.It \&Vt Ta Yes Ta Yes Ta >0 -.It \&Xr Ta Yes Ta Yes Ta >0, <3 -.It \&br Ta \&No Ta \&No Ta 0 -.It \&sp Ta \&No Ta \&No Ta 1 +.It Sx \&%A Ta \&No Ta \&No Ta >0 +.It Sx \&%B Ta \&No Ta \&No Ta >0 +.It Sx \&%C Ta \&No Ta \&No Ta >0 +.It Sx \&%D Ta \&No Ta \&No Ta >0 +.It Sx \&%I Ta \&No Ta \&No Ta >0 +.It Sx \&%J Ta \&No Ta \&No Ta >0 +.It Sx \&%N Ta \&No Ta \&No Ta >0 +.It Sx \&%O Ta \&No Ta \&No Ta >0 +.It Sx \&%P Ta \&No Ta \&No Ta >0 +.It Sx \&%R Ta \&No Ta \&No Ta >0 +.It Sx \&%T Ta \&No Ta \&No Ta >0 +.It Sx \&%V Ta \&No Ta \&No Ta >0 +.It Sx \&Ad Ta Yes Ta Yes Ta n +.It Sx \&An Ta Yes Ta Yes Ta n +.It Sx \&Ap Ta Yes Ta Yes Ta 0 +.It Sx \&Ar Ta Yes Ta Yes Ta n +.It Sx \&At Ta Yes Ta Yes Ta 1 +.It Sx \&Bsx Ta Yes Ta Yes Ta n +.It Sx \&Bt Ta \&No Ta \&No Ta 0 +.It Sx \&Bx Ta Yes Ta Yes Ta n +.It Sx \&Cd Ta Yes Ta Yes Ta >0 +.It Sx \&Cm Ta Yes Ta Yes Ta n +.It Sx \&Db Ta \&No Ta \&No Ta 1 +.It Sx \&Dd Ta \&No Ta \&No Ta >0 +.It Sx \&Dt Ta \&No Ta \&No Ta n +.It Sx \&Dv Ta Yes Ta Yes Ta n +.It Sx \&Dx Ta Yes Ta Yes Ta n +.It Sx \&Em Ta Yes Ta Yes Ta >0 +.It Sx \&En Ta \&No Ta \&No Ta 0 +.It Sx \&Er Ta Yes Ta Yes Ta >0 +.It Sx \&Es Ta \&No Ta \&No Ta 0 +.It Sx \&Ev Ta Yes Ta Yes Ta n +.It Sx \&Ex Ta \&No Ta \&No Ta n +.It Sx \&Fa Ta Yes Ta Yes Ta n +.It Sx \&Fd Ta \&No Ta \&No Ta >0 +.It Sx \&Fl Ta Yes Ta Yes Ta n +.It Sx \&Fn Ta Yes Ta Yes Ta >0 +.It Sx \&Fr Ta \&No Ta \&No Ta n +.It Sx \&Ft Ta Yes Ta Yes Ta n +.It Sx \&Fx Ta Yes Ta Yes Ta n +.It Sx \&Hf Ta \&No Ta \&No Ta n +.It Sx \&Ic Ta Yes Ta Yes Ta >0 +.It Sx \&In Ta \&No Ta \&No Ta n +.It Sx \&Lb Ta \&No Ta \&No Ta 1 +.It Sx \&Li Ta Yes Ta Yes Ta n +.It Sx \&Lk Ta Yes Ta Yes Ta n +.It Sx \&Lp Ta \&No Ta \&No Ta 0 +.It Sx \&Ms Ta Yes Ta Yes Ta >0 +.It Sx \&Mt Ta Yes Ta Yes Ta >0 +.It Sx \&Nm Ta Yes Ta Yes Ta n +.It Sx \&No Ta Yes Ta Yes Ta 0 +.It Sx \&Ns Ta Yes Ta Yes Ta 0 +.It Sx \&Nx Ta Yes Ta Yes Ta n +.It Sx \&Os Ta \&No Ta \&No Ta n +.It Sx \&Ot Ta \&No Ta \&No Ta n +.It Sx \&Ox Ta Yes Ta Yes Ta n +.It Sx \&Pa Ta Yes Ta Yes Ta n +.It Sx \&Pf Ta \&No Ta Yes Ta 1 +.It Sx \&Pp Ta \&No Ta \&No Ta 0 +.It Sx \&Rv Ta \&No Ta \&No Ta n +.It Sx \&Sm Ta \&No Ta \&No Ta 1 +.It Sx \&St Ta \&No Ta Yes Ta 1 +.It Sx \&Sx Ta Yes Ta Yes Ta >0 +.It Sx \&Sy Ta Yes Ta Yes Ta >0 +.It Sx \&Tn Ta Yes Ta Yes Ta >0 +.It Sx \&Ud Ta \&No Ta \&No Ta 0 +.It Sx \&Ux Ta Yes Ta Yes Ta n +.It Sx \&Va Ta Yes Ta Yes Ta n +.It Sx \&Vt Ta Yes Ta Yes Ta >0 +.It Sx \&Xr Ta Yes Ta Yes Ta >0, <3 +.It Sx \&br Ta \&No Ta \&No Ta 0 +.It Sx \&sp Ta \&No Ta \&No Ta 1 .El . . +.Sh REFERENCE +This section is a canonical reference of all macros, arranged +alphabetically. For the scoping of individual macros, see +.Sx MACRO SYNTAX . +. +.Ss \&%A +Author name of an +.Sx \&Rs +block. Multiple authors should each be accorded their own +.Sx \%%A +line. Author names should be ordered with full or abbreviated +forename(s) first, then full surname. +. +.Ss \&%B +Book title of an +.Sx \&Rs +block. This macro may also be used in a non-bibliographic context when +referring to book titles. +. +.Ss \&%C +Publication city or location of an +.Sx \&Rs +block. +.Pp +.Em Remarks : +this macro is not implemented in +.Xr groff 1 . +. +.Ss \&%D +Publication date of an +.Sx \&Rs +block. This should follow the reduced syntax for +.Sx Dates . +Canonical or non-canonical form is not necessary since publications are +often referenced only by year, or month and year. +. +.Ss \&%I +Publisher or issuer name of an +.Sx \&Rs +block. +. +.Ss \&%J +Journal name of an +.Sx \&Rs +block. +. +.Ss \&%N +Issue number (usually for journals) of an +.Sx \&Rs +block. +. +.Ss \&%O +Optional information of an +.Sx \&Rs +block. +. +.Ss \&%P +Book or journal page number of an +.Sx \&Rs +block. +. +.Ss \&%Q +Institutional author (school, government, etc.) of an +.Sx \&Rs +block. Multiple institutional authors should each be accorded their own +.Sx \&%Q +line. +. +.Ss \&%R +Technical report name of an +.Sx \&Rs +block. +. +.Ss \&%T +Article title of an +.Sx \&Rs +block. This macro may also be used in a non-bibliographical context +when referring to article titles. +. +.Ss \&%V +Volume number of an +.Sx \&Rs +block. +. +.Ss \&Ac +Closes an +.Sx \&Ao +block. Does not have any tail arguments. +. +.Ss \&Ad +Address construct: usually in the context of an computational address in +memory, not a physical (post) address. +.Pp +Examples: +.Bd -literal -offset indent +\&.Ad [0,$] +\&.Ad 0x00000000 +.Ed +. +.Ss \&An +Author name. This macro may alternatively accepts the following +arguments, although these may not be specified along with a parameter: +.Bl -tag -width 12n -offset indent +.It Fl split +Renders a line break before each author listing. +.It Fl nosplit +The opposite of +.Fl split . +.El +.Pp +In the AUTHORS section, the default is not to split the first author +listing, but all subsequent author listings, whether or not they're +interspersed by other macros or text, are split. Thus, specifying +.Fl split +will cause the first listing also to be split. If not in the AUTHORS +section, the default is not to split. +.Pp +Examples: +.Bd -literal -offset indent +\&.An -nosplit +\&.An J. E. Hopcraft , +\&.An J. D. Ullman . +.Ed +.Pp +.Em Remarks : +the effects of +.Fl split +or +.Fl nosplit +are re-set when entering the AUTHORS section, so if one specifies +.Sx \&An Fl nosplit +in the general document body, it must be re-specified in the AUTHORS +section. +. +.Ss \&Ao +Begins a block enclosed by angled brackets. Does not have any head +arguments. +.Pp +Examples: +.Bd -literal -offset indent +\&.Fl -key= Ns Ao Ar val Ac +.Ed +.Pp +See also +.Sx \&Aq . +. +.Ss \&Ap +Inserts an apostrophe without any surrounding white-space. This is +generally used as a grammatic device when referring to the verb form of +a function: +.Bd -literal -offset indent +\&.Fn execve Ap d +.Ed +. +.Ss \&Aq +Encloses its arguments in angled brackets. +.Pp +Examples: +.Bd -literal -offset indent +\&.Fl -key= Ns Aq Ar val +.Ed +.Pp +.Em Remarks : +this macro is often abused for rendering URIs, which should instead use +.Sx \&Lk +or +.Sx \&Mt , +or to note pre-processor +.Dq Li #include +statements, which should use +.Sx \&In . +.Pp +See also +.Sx \&Ao . +. +.Ss \&Ar +Command arguments. If an argument is not provided, the string +.Dq file ... +is used as a default. +.Pp +Examples: +.Bd -literal -offset indent +\&.Fl o Ns Ar file1 +\&.Ar +\&.Ar arg1 , arg2 . +.Ed +. +.Ss \&At +Formats an AT&T version. Accepts at most one parameter: +.Bl -tag -width 12n -offset indent +.It Cm v[1-7] | 32v +A version of +.At . +.It Cm V[.[1-4]]? +A system version of +.At . +.El +.Pp +Note that these parameters do not begin with a hyphen. +.Pp +Examples: +.Bd -literal -offset indent +\&.At +\&.At V.1 +.Ed +.Pp +See also +.Sx \&Bsx , +.Sx \&Bx , +.Sx \&Dx , +.Sx \&Fx , +.Sx \&Nx , +.Sx \&Ox , +and +.Sx \&Ux . +. +.Ss \&Bc +Closes a +.Sx \&Bo +block. Does not have any tail arguments. +. +.Ss \&Bd +Begins a display block. A display is collection of macros or text which +may be collectively offset or justified in a manner different from that +of the enclosing context. By default, the block is preceded by a +vertical space. +.Pp +Each display is associated with a type, which must be one of the +following arguments: +.Bl -tag -width 12n -offset indent +.It Fl ragged +Only left-justify the block. +.It Fl unfilled +Do not justify the block at all. +.It Fl filled +Left- and right-justify the block. +.It Fl literal +Alias for +.Fl unfilled . +.It Fl centered +Centre-justify each line. +.El +.Pp +The type must be provided first. Secondary arguments are as follows: +.Bl -tag -width 12n -offset indent +.It Fl offset Ar width +Offset by the value of +.Ar width , +which is interpreted as one of the following, specified in order: +.Bl -item +.It +As one of the pre-defined strings +.Ar indent , +the width of standard indentation; +.Ar indent-two , +twice +.Ar indent ; +.Ar left , +which has no effect ; +.Ar right , +which justifies to the right margin; and +.Ar center , +which aligns around an imagined centre axis. +.It +As a precalculated width for a named macro. The most popular is the +imaginary macro +.Ar Ds , +which resolves to +.Ar 6n . +.It +As a scaling unit following the syntax described in +.Sx Scaling Widths . +.It +As the calculated string length of the opaque string. +.El +.Pp +If unset, it will revert to the value of +.Ar 8n +as described in +.Sx Scaling Widths . +.It Fl compact +Do not assert a vertical space before the block. +.It Fl file Ar file +Prepend the file +.Ar file +before any text or macros within the block. +.El +.Pp +Examples: +.Bd -literal -offset indent +\&.Bd \-unfilled \-offset two-indent \-compact + Hello world. +\&.Ed +.Ed +.Pp +See also +.Sx \&D1 +and +.Sx \&Dl . +. +.Ss \&Bf +.Ss \&Bk +.Ss \&Bl +. +.Ss \&Bo +Begins a block enclosed by square brackets. Does not have any head +arguments. +.Pp +Examples: +.Bd -literal -offset indent +\&.Bo 1 , +\&.Dv BUFSIZ Bc +.Ed +.Pp +See also +.Sx \&Bq . +. +.Ss \&Bq +Encloses its arguments in square brackets. +.Pp +Examples: +.Bd -literal -offset indent +\&.Bq 1 , Dv BUFSIZ +.Ed +.Pp +.Em Remarks : +this macro is sometimes abused to emulate optional arguments for +commands; the correct macros to use for this purpose are +.Sx \&Op , +.Sx \&Oo , +and +.Sx \&Oc . +.Pp +See also +.Sx \&Bo . +. +.Ss \&Brc +Closes a +.Sx \&Bro +block. Does not have any tail arguments. +. +.Ss \&Bro +Begins a block enclosed by curly braces. Does not have any head +arguments. +.Pp +Examples: +.Bd -literal -offset indent +\&.Bro 1 , ... , +\&.Va n Brc +.Ed +.Pp +See also +.Sx \&Brq . +. +.Ss \&Brq +Encloses its arguments in curly braces. +.Pp +Examples: +.Bd -literal -offset indent +\&.Brq 1 , ... , Va n +.Ed +.Pp +See also +.Sx \&Bro . +. +.Ss \&Bsx +Format the BSD/OS version provided as an argument, or a default value if +no argument is provided. +.Pp +Examples: +.Bd -literal -offset indent +\&.Bsx 1.0 +\&.Bsx +.Ed +.Pp +See also +.Sx \&At , +.Sx \&Bx , +.Sx \&Dx , +.Sx \&Fx , +.Sx \&Nx , +.Sx \&Ox , +and +.Sx \&Ux . +. +.Ss \&Bt +Prints +.Dq is currently in beta test. +. +.Ss \&Bx +Format the BSD version provided as an argument, or a default value if no +argument is provided. +.Pp +Examples: +.Bd -literal -offset indent +\&.Bx 4.4 +\&.Bx +.Ed +.Pp +See also +.Sx \&At , +.Sx \&Bsx , +.Sx \&Dx , +.Sx \&Fx , +.Sx \&Nx , +.Sx \&Ox , +and +.Sx \&Ux . +. +.Ss \&Cd +Configuration declaration (suggested for use only in section four +manuals). This denotes strings accepted by +.Xr config 8 . +.Pp +Examples: +.Bd -literal -offset indent +\&.Cd device le0 at scode? +.Ed +.Pp +.Em Remarks : +this macro is commonly abused by using quoted literals to retain +white-space and align consecutive +.Sx \&Cd +declarations. This practise is discouraged. +. +.Ss \&Cm +Command modifiers. Useful when specifying configuration options or +keys. +.Pp +Examples: +.Bd -literal -offset indent +\&.Cm ControlPath +\&.Cm ControlMaster +.Ed +.Pp +See also +.Sx \&Fl . +. +.Ss \&D1 +One-line indented display. This is formatted by the default rules and +is useful for simple indented statements. It is followed by a newline. +.Pp +Examples: +.Bd -literal -offset indent +\&.D1 Fl abcdefgh +.Ed +.Pp +See also +.Sx \&Bd +and +.Sx \&Dl . +. +.Ss \&Db +.Ss \&Dc +Closes a +.Sx \&Do +block. Does not have any tail arguments. +. +.Ss \&Dd +Document date. This is the mandatory first macro of any +.Nm +manual. Its calling syntax is as follows: +.Pp +.D1 \. Ns Sx \&Dd Cm date +.Pp +The +.Cm date +field may be either +.Ar $\&Mdocdate$ , +which signifies the current manual revision date dictated by +.Xr cvs 1 +or instead a valid canonical date as specified by +.Sx Dates . +.Pp +Examples: +.Bd -literal -offset indent +\&.Dd $\&Mdocdate$ +\&.Dd $\&Mdocdate: July 21 2007$ +\&.Dd July 21, 2007 +.Ed +.Pp +See also +.Sx \&Dt +and +.Sx \&Os . +. +.Ss \&Dl +One-line intended display. This is formatted as literal text and is +useful for commands and invocations. It is followed by a newline. +.Pp +Examples: +.Bd -literal -offset indent +\&.Dl % mandoc mdoc.7 | less +.Ed +.Pp +See also +.Sx \&Bd +and +.Sx \&D1 . +. +.Ss \&Do +Begins a block enclosed by double quotes. Does not have any head +arguments. +.Pp +Examples: +.Bd -literal -offset indent +\&.D1 Do April is the cruellest month Dc \e(em T.S. Eliot +.Ed +.Pp +See also +.Sx \&Dq . +. +.Ss \&Dq +Encloses its arguments in double quotes. +.Pp +Examples: +.Bd -literal -offset indent +\&.Dq April is the cruellest month +\e(em T.S. Eliot +.Ed +.Pp +See also +.Sx \&Do . +. +.Ss \&Dt +Document title. This is the mandatory second macro of any +.Nm +file. Its calling syntax is as follows: +.Pp +.D1 \. Ns Sx \&Dt Cm title section Op Cm volume | arch +.Pp +Its arguments are as follows: +.Bl -tag -width Ds -offset Ds +.It Cm title +The document's title (name). This should be capitalised and is +required. +.It Cm section +The manual section. This may be one of +.Ar 1 +.Pq utilities , +.Ar 2 +.Pq system calls , +.Ar 3 +.Pq libraries , +.Ar 3p +.Pq Perl libraries , +.Ar 4 +.Pq devices , +.Ar 5 +.Pq file formats , +.Ar 6 +.Pq games , +.Ar 7 +.Pq miscellaneous , +.Ar 8 +.Pq system utilities , +.Ar 9 +.Pq kernel functions , +.Ar X11 +.Pq X Window System , +.Ar X11R6 +.Pq X Window System , +.Ar unass +.Pq unassociated , +.Ar local +.Pq local system , +.Ar draft +.Pq draft manual , +or +.Ar paper +.Pq paper . +It is also required and should correspond to the manual's filename +suffix. +.It Cm volume +This overrides the volume inferred from +.Ar section . +This field is optional, and if specified, must be one of +.Ar USD +.Pq users' supplementary documents , +.Ar PS1 +.Pq programmers' supplementary documents , +.Ar AMD +.Pq administrators' supplementary documents , +.Ar SMM +.Pq system managers' manuals , +.Ar URM +.Pq users' reference manuals , +.Ar PRM +.Pq programmers' reference manuals , +.Ar KM +.Pq kernel manuals , +.Ar IND +.Pq master index , +.Ar MMI +.Pq master index , +.Ar LOCAL +.Pq local manuals , +.Ar LOC +.Pq local manuals , +or +.Ar CON +.Pq contributed manuals . +.It Cm arch +This specifies a specific relevant architecture. If +.Cm volume +is not provided, it may be used in its place, else it may be used +subsequent that. It, too, is optional. It must be one of +.Ar alpha , +.Ar amd64 , +.Ar amiga , +.Ar arc , +.Ar arm , +.Ar armish , +.Ar aviion , +.Ar hp300 , +.Ar hppa , +.Ar hppa64 , +.Ar i386 , +.Ar landisk , +.Ar luna88k , +.Ar mac68k , +.Ar macppc , +.Ar mvme68k , +.Ar mvme88k , +.Ar mvmeppc , +.Ar pmax , +.Ar sgi , +.Ar socppc , +.Ar sparc , +.Ar sparc64 , +.Ar sun3 , +.Ar vax , +or +.Ar zaurus . +.El +.Pp +Examples: +.Bd -literal -offset indent +\&.Dt FOO 1 +\&.Dt FOO 4 KM +\&.Dt FOO 9 i386 +\&.Dt FOO 9 KM i386 +.Ed +.Pp +See also +.Sx \&Dd +and +.Sx \&Os . +. +.Ss \&Dv +Defined variables such as preprocessor constants. +.Pp +Examples: +.Bd -literal -offset indent +\&.Dv BUFSIZ +\&.Dv STDOUT_FILENO +.Ed +.Pp +See also +.Sx \&Er . +. +.Ss \&Dx +Format the DragonFlyBSD version provided as an argument, or a default +value if no argument is provided. +.Pp +Examples: +.Bd -literal -offset indent +\&.Dx 2.4.1 +\&.Dx +.Ed +.Pp +See also +.Sx \&At , +.Sx \&Bsx , +.Sx \&Bx , +.Sx \&Fx , +.Sx \&Nx , +.Sx \&Ox , +and +.Sx \&Ux . +. +.Ss \&Ec +.Ss \&Ed +.Ss \&Ef +.Ss \&Ek +.Ss \&El +.Ss \&Em +Denotes text that should be emphasised. Note that this is a +presentation term and should not be used for stylistically decorating +technical terms. +.Pp +Examples: +.Bd -literal -offset indent +\&.Ed Warnings! +\&.Ed Remarks : +.Ed +. +.Ss \&En +.Ss \&Eo +.Ss \&Er +Error constants (suggested for use only in section two manuals). +.Pp +Examples: +.Bd -literal -offset indent +\&.Er EPERM +\&.Er ENOENT +.Ed +.Pp +See also +.Sx \&Dv . +. +.Ss \&Es +. +.Ss \&Ev +Environmental variables such as those specified in +.Xr environ 7 . +.Pp +Examples: +.Bd -literal -offset indent +\&.Ev DISPLAY +\&.Ev PATH +.Ed +. +.Ss \&Ex +Inserts text regarding a utility's exit values. This macro must have +first the +.Fl std +argument specified, then an optional +.Ar utility . +If +.Ar utility +is not provided, the document's name as stipulated in +.Sx \&Nm +is provided. +.Ss \&Fa +.Ss \&Fc +.Ss \&Fd +.Ss \&Fl +.Ss \&Fn +.Ss \&Fo +.Ss \&Fr +.Ss \&Ft +.Ss \&Fx +Format the FreeBSD version provided as an argument, or a default value +if no argument is provided. +.Pp +Examples: +.Bd -literal -offset indent +\&.Fx 7.1 +\&.Fx +.Ed +.Pp +See also +.Sx \&At , +.Sx \&Bsx , +.Sx \&Bx , +.Sx \&Dx , +.Sx \&Nx , +.Sx \&Ox , +and +.Sx \&Ux . +. +.Ss \&Hf +.Ss \&Ic +.Ss \&In +.Ss \&It +.Ss \&Lb +.Ss \&Li +.Ss \&Lk +.Ss \&Lp +.Ss \&Ms +.Ss \&Mt +.Ss \&Nd +.Ss \&Nm +.Ss \&No +.Ss \&Ns +.Ss \&Nx +Format the NetBSD version provided as an argument, or a default value if +no argument is provided. +.Pp +Examples: +.Bd -literal -offset indent +\&.Nx 5.01 +\&.Nx +.Ed +.Pp +See also +.Sx \&At , +.Sx \&Bsx , +.Sx \&Bx , +.Sx \&Dx , +.Sx \&Fx , +.Sx \&Ox , +and +.Sx \&Ux . +. +.Ss \&Oc +.Ss \&Oo +.Ss \&Op +.Ss \&Os +Document operating system version. This is the mandatory third macro of +any +.Nm +file. Its calling syntax is as follows: +.Pp +.D1 \. Ns Sx \&Os Op Cm system +.Pp +The optional +.Cm system +parameter specifies the relevant operating system or environment. Left +unspecified, it defaults to the local operating system version. This is +the suggested form. +.Pp +Examples: +.Bd -literal -offset indent +\&.Os +\&.Os KTH/CSC/TCS +\&.Os BSD 4.3 +.Ed +.Pp +See also +.Sx \&Dd +and +.Sx \&Dt . +. +.Ss \&Ot +Unknown usage. +.Pp +.Em Remarks : +this macro has been deprecated. +. +.Ss \&Ox +Format the OpenBSD version provided as an argument, or a default value +if no argument is provided. +.Pp +Examples: +.Bd -literal -offset indent +\&.Ox 4.5 +\&.Ox +.Ed +.Pp +See also +.Sx \&At , +.Sx \&Bsx , +.Sx \&Bx , +.Sx \&Dx , +.Sx \&Fx , +.Sx \&Nx , +and +.Sx \&Ux . +. +.Ss \&Pa +.Ss \&Pc +.Ss \&Pf +.Ss \&Po +.Ss \&Pp +.Ss \&Pq +.Ss \&Qc +.Ss \&Ql +.Ss \&Qo +.Ss \&Qq +. +.Ss \&Re +Closes a +.Sx \&Rs +block. Does not have any tail arguments. +. +.Ss \&Rs +Begins a bibliographic +.Pq Dq reference +block. Does not have any head arguments. The block macro and may only +contain +.Sx \&%A , +.Sx \&%B , +.Sx \&%C , +.Sx \&%D , +.Sx \&%I , +.Sx \&%J , +.Sx \&%N , +.Sx \&%O , +.Sx \&%P , +.Sx \&%Q , +.Sx \&%R , +.Sx \&%T , +and +.Sx \&%V +child macros (at least one must be specified). +.Pp +Examples: +.Bd -literal -offset indent +\&.Rs +\&.%A J. E. Hopcroft +\&.%A J. D. Ullman +\&.%B Introduction to Automata Theory, Languages, and Computation +\&.%I Addison-Wesley +\&.%C Reading, Massachusettes +\&.%D 1979 +\&.Re +.Ed +.Pp +If an +.Sx \&Rs +block is used within a SEE ALSO section, a vertical space is asserted +before the rendered output, else the block continues on the current +line. +. +.Ss \&Rv +.Ss \&Sc +.Ss \&Sh +.Ss \&Sm +.Ss \&So +.Ss \&Sq +.Ss \&Ss +.Ss \&St +.Ss \&Sx +.Ss \&Sy +.Ss \&Tn +.Ss \&Ud +.Ss \&Ux +Format the UNIX name. Accepts no argument. +.Pp +Examples: +.Bd -literal -offset indent +\&.Ux +.Ed +.Pp +See also +.Sx \&At , +.Sx \&Bsx , +.Sx \&Bx , +.Sx \&Dx , +.Sx \&Fx , +.Sx \&Nx , +and +.Sx \&Ox . +. +.Ss \&Va +.Ss \&Vt +.Ss \&Xc +.Ss \&Xo +.Ss \&Xr +.Ss \&br +.Ss \&sp +. +. .Sh COMPATIBILITY This section documents compatibility with other roff implementations, at this time limited to @@ -545,22 +1636,33 @@ file re-write .Pp .Bl -dash -compact .It -The -.Sq \-split -or -.Sq \-nosplit -argument to -.Sq \&An -applies to the whole document, not just to the current section as it -does in groff. +Negative scaling units are now truncated to zero instead of creating +interesting conditions, such as with +.Sq \&sp -1i . +Furthermore, the +.Sq f +scaling unit, while accepted, is rendered as the default unit. .It In quoted literals, groff allowed pair-wise double-quotes to produce a standalone double-quote in formatted output. This idiosyncratic behaviour is no longer applicable. .It +Display types +.Sx \&Bd Fl center +and +.Fl right +are aliases for +.Fl left . The -.Sq \&sp -macro does not accept negative numbers. +.Fl file Ar file +argument is ignored. Since text is not right-justified, +.Fl ragged +and +.Fl filled +are aliases, as are +.Fl literal +and +.Fl unfilled . .It Blocks of whitespace are stripped from both macro and free-form text lines (except when in literal mode), while groff would retain whitespace @@ -576,27 +1678,19 @@ made historic groff .Qq go orbital but is a proper delimiter in this implementation. .It -.Sq \&It \-nested +.Sx \&It Fl nested is assumed for all lists (it wasn't in historic groff): any list may be nested and -.Sq \-enum +.Fl enum lists will restart the sequence only for the sub-list. .It -.Sq \&It \-column -syntax where column widths may be preceded by other arguments (instead -of proceeded) is not supported. -.It -The -.Sq \&At -macro only accepts a single parameter. -.It Some manuals use -.Sq \&Li +.Sx \&Li incorrectly by following it with a reserved character and expecting the delimiter to render. This is not supported. .It In groff, the -.Sq \&Fo +.Sx \&Fo macro only produces the first parameter. This is no longer the case. .El . @@ -611,69 +1705,71 @@ The .Nm reference was written by .An Kristaps Dzonsons Aq kristaps@kth.se . -. -. -.Sh CAVEATS -There are many ambiguous parts of mdoc. -. -.Pp -.Bl -dash -compact -.It -.Sq \&Fa -should be -.Sq \&Va -as function arguments are variables. -.It -.Sq \&Ft -should be -.Sq \&Vt -as function return types are still types. Furthermore, the -.Sq \&Ft -should be removed and -.Sq \&Fo , -which ostensibly follows it, should follow the same convention as -.Sq \&Va . -.It -.Sq \&Va -should formalise that only one or two arguments are acceptable: a -variable name and optional, preceding type. -.It -.Sq \&Fd -is ambiguous. It's commonly used to indicate an include file in the -synopsis section. -.Sq \&In -should be used, instead. -.It -Only the -.Sq \-literal -argument to -.Sq \&Bd -makes sense. The remaining ones should be removed. -.It -The -.Sq \&Xo -and -.Sq \&Xc -macros should be deprecated. -.It -The -.Sq \&Dt -macro lacks clarity. It should be absolutely clear which title will -render when formatting the manual page. -.It -A -.Sq \&Lx -should be provided for Linux (\(`a la -.Sq \&Ox , -.Sq \&Nx -etc.). -.It -There's no way to refer to references in -.Sq \&Rs/Re -blocks. -.It -The \-split and \-nosplit dictates via -.Sq \&An -are re-set when entering and leaving the AUTHORS section. -.El -. +.\" +.\" XXX: this really isn't the place for these caveats. +.\" . +.\" . +.\" .Sh CAVEATS +.\" There are many ambiguous parts of mdoc. +.\" . +.\" .Pp +.\" .Bl -dash -compact +.\" .It +.\" .Sq \&Fa +.\" should be +.\" .Sq \&Va +.\" as function arguments are variables. +.\" .It +.\" .Sq \&Ft +.\" should be +.\" .Sq \&Vt +.\" as function return types are still types. Furthermore, the +.\" .Sq \&Ft +.\" should be removed and +.\" .Sq \&Fo , +.\" which ostensibly follows it, should follow the same convention as +.\" .Sq \&Va . +.\" .It +.\" .Sq \&Va +.\" should formalise that only one or two arguments are acceptable: a +.\" variable name and optional, preceding type. +.\" .It +.\" .Sq \&Fd +.\" is ambiguous. It's commonly used to indicate an include file in the +.\" synopsis section. +.\" .Sq \&In +.\" should be used, instead. +.\" .It +.\" Only the +.\" .Sq \-literal +.\" argument to +.\" .Sq \&Bd +.\" makes sense. The remaining ones should be removed. +.\" .It +.\" The +.\" .Sq \&Xo +.\" and +.\" .Sq \&Xc +.\" macros should be deprecated. +.\" .It +.\" The +.\" .Sq \&Dt +.\" macro lacks clarity. It should be absolutely clear which title will +.\" render when formatting the manual page. +.\" .It +.\" A +.\" .Sq \&Lx +.\" should be provided for Linux (\(`a la +.\" .Sq \&Ox , +.\" .Sq \&Nx +.\" etc.). +.\" .It +.\" There's no way to refer to references in +.\" .Sq \&Rs/Re +.\" blocks. +.\" .It +.\" The \-split and \-nosplit dictates via +.\" .Sq \&An +.\" are re-set when entering and leaving the AUTHORS section. +.\" .El +.\" . diff --git a/usr.bin/mandoc/mdoc.c b/usr.bin/mandoc/mdoc.c index 64b1ca0a0af..ecaf7219f63 100644 --- a/usr.bin/mandoc/mdoc.c +++ b/usr.bin/mandoc/mdoc.c @@ -1,4 +1,4 @@ -/* $Id: mdoc.c,v 1.29 2009/10/19 16:27:52 schwarze Exp $ */ +/* $Id: mdoc.c,v 1.30 2009/10/21 19:13:50 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -78,6 +78,7 @@ const char *const __mdoc_merrnames[MERRMAX] = { "closure macro without prior context", /* ENOCTX */ "no description found for library", /* ELIB */ "bad child for parent context", /* EBADCHILD */ + "list arguments preceding type", /* ENOTYPE */ }; const char *const __mdoc_macronames[MDOC_MAX] = { @@ -127,7 +128,7 @@ const char *const __mdoc_argnames[MDOC_ARG_MAX] = { "ohang", "inset", "column", "width", "compact", "std", "filled", "words", "emphasis", - "symbolic", "nested" + "symbolic", "nested", "centered" }; const char * const *mdoc_macronames = __mdoc_macronames; diff --git a/usr.bin/mandoc/mdoc.h b/usr.bin/mandoc/mdoc.h index 8c5498a7267..0a8bdfeb674 100644 --- a/usr.bin/mandoc/mdoc.h +++ b/usr.bin/mandoc/mdoc.h @@ -1,4 +1,4 @@ -/* $Id: mdoc.h,v 1.13 2009/08/22 22:11:24 schwarze Exp $ */ +/* $Id: mdoc.h,v 1.14 2009/10/21 19:13:50 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -179,7 +179,8 @@ #define MDOC_Emphasis 23 #define MDOC_Symbolic 24 #define MDOC_Nested 25 -#define MDOC_ARG_MAX 26 +#define MDOC_Centred 26 +#define MDOC_ARG_MAX 27 /* Type of a syntax node. */ enum mdoc_type { diff --git a/usr.bin/mandoc/mdoc_argv.c b/usr.bin/mandoc/mdoc_argv.c index 6357eedef72..2905ca6e36f 100644 --- a/usr.bin/mandoc/mdoc_argv.c +++ b/usr.bin/mandoc/mdoc_argv.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_argv.c,v 1.16 2009/10/19 21:00:43 schwarze Exp $ */ +/* $Id: mdoc_argv.c,v 1.17 2009/10/21 19:13:50 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -59,7 +59,7 @@ static int mdoc_argvflags[MDOC_ARG_MAX] = { ARGV_NONE, /* MDOC_Ragged */ ARGV_NONE, /* MDOC_Unfilled */ ARGV_NONE, /* MDOC_Literal */ - ARGV_NONE, /* MDOC_File */ + ARGV_SINGLE, /* MDOC_File */ ARGV_OPT_SINGLE, /* MDOC_Offset */ ARGV_NONE, /* MDOC_Bullet */ ARGV_NONE, /* MDOC_Dash */ @@ -591,6 +591,8 @@ argv_a2arg(int tok, const char *p) return(MDOC_Offset); else if (0 == strcmp(p, "compact")) return(MDOC_Compact); + else if (0 == strcmp(p, "centered")) + return(MDOC_Centred); break; case (MDOC_Bf): diff --git a/usr.bin/mandoc/mdoc_html.c b/usr.bin/mandoc/mdoc_html.c new file mode 100644 index 00000000000..af53616b7a6 --- /dev/null +++ b/usr.bin/mandoc/mdoc_html.c @@ -0,0 +1,2217 @@ +/* $Id: mdoc_html.c,v 1.1 2009/10/21 19:13:50 schwarze Exp $ */ +/* + * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> + * + * 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. + */ +#include <sys/types.h> +#include <sys/param.h> +#include <sys/queue.h> + +#include <assert.h> +#include <ctype.h> +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "out.h" +#include "html.h" +#include "mdoc.h" +#include "main.h" + +#define INDENT 5 +#define HALFINDENT 3 + +#define MDOC_ARGS const struct mdoc_meta *m, \ + const struct mdoc_node *n, \ + struct html *h + +struct htmlmdoc { + int (*pre)(MDOC_ARGS); + void (*post)(MDOC_ARGS); +}; + +static void print_mdoc(MDOC_ARGS); +static void print_mdoc_head(MDOC_ARGS); +static void print_mdoc_node(MDOC_ARGS); +static void print_mdoc_nodelist(MDOC_ARGS); + +static void a2width(const char *, struct roffsu *); +static void a2offs(const char *, struct roffsu *); + +static int a2list(const struct mdoc_node *); + +static void mdoc_root_post(MDOC_ARGS); +static int mdoc_root_pre(MDOC_ARGS); + +static void mdoc__x_post(MDOC_ARGS); +static int mdoc__x_pre(MDOC_ARGS); +static int mdoc_ad_pre(MDOC_ARGS); +static int mdoc_an_pre(MDOC_ARGS); +static int mdoc_ap_pre(MDOC_ARGS); +static void mdoc_aq_post(MDOC_ARGS); +static int mdoc_aq_pre(MDOC_ARGS); +static int mdoc_ar_pre(MDOC_ARGS); +static int mdoc_bd_pre(MDOC_ARGS); +static int mdoc_bf_pre(MDOC_ARGS); +static void mdoc_bl_post(MDOC_ARGS); +static int mdoc_bl_pre(MDOC_ARGS); +static void mdoc_bq_post(MDOC_ARGS); +static int mdoc_bq_pre(MDOC_ARGS); +static void mdoc_brq_post(MDOC_ARGS); +static int mdoc_brq_pre(MDOC_ARGS); +static int mdoc_bt_pre(MDOC_ARGS); +static int mdoc_bx_pre(MDOC_ARGS); +static int mdoc_cd_pre(MDOC_ARGS); +static int mdoc_d1_pre(MDOC_ARGS); +static void mdoc_dq_post(MDOC_ARGS); +static int mdoc_dq_pre(MDOC_ARGS); +static int mdoc_dv_pre(MDOC_ARGS); +static int mdoc_fa_pre(MDOC_ARGS); +static int mdoc_fd_pre(MDOC_ARGS); +static int mdoc_fl_pre(MDOC_ARGS); +static int mdoc_fn_pre(MDOC_ARGS); +static int mdoc_ft_pre(MDOC_ARGS); +static int mdoc_em_pre(MDOC_ARGS); +static int mdoc_er_pre(MDOC_ARGS); +static int mdoc_ev_pre(MDOC_ARGS); +static int mdoc_ex_pre(MDOC_ARGS); +static void mdoc_fo_post(MDOC_ARGS); +static int mdoc_fo_pre(MDOC_ARGS); +static int mdoc_ic_pre(MDOC_ARGS); +static int mdoc_in_pre(MDOC_ARGS); +static int mdoc_it_block_pre(MDOC_ARGS, int, int, + struct roffsu *, struct roffsu *); +static int mdoc_it_head_pre(MDOC_ARGS, int, + struct roffsu *); +static int mdoc_it_body_pre(MDOC_ARGS, int); +static int mdoc_it_pre(MDOC_ARGS); +static int mdoc_lb_pre(MDOC_ARGS); +static int mdoc_li_pre(MDOC_ARGS); +static int mdoc_lk_pre(MDOC_ARGS); +static int mdoc_mt_pre(MDOC_ARGS); +static int mdoc_ms_pre(MDOC_ARGS); +static int mdoc_nd_pre(MDOC_ARGS); +static int mdoc_nm_pre(MDOC_ARGS); +static int mdoc_ns_pre(MDOC_ARGS); +static void mdoc_op_post(MDOC_ARGS); +static int mdoc_op_pre(MDOC_ARGS); +static int mdoc_pa_pre(MDOC_ARGS); +static void mdoc_pf_post(MDOC_ARGS); +static int mdoc_pf_pre(MDOC_ARGS); +static void mdoc_pq_post(MDOC_ARGS); +static int mdoc_pq_pre(MDOC_ARGS); +static int mdoc_rs_pre(MDOC_ARGS); +static int mdoc_rv_pre(MDOC_ARGS); +static int mdoc_sh_pre(MDOC_ARGS); +static int mdoc_sp_pre(MDOC_ARGS); +static void mdoc_sq_post(MDOC_ARGS); +static int mdoc_sq_pre(MDOC_ARGS); +static int mdoc_ss_pre(MDOC_ARGS); +static int mdoc_sx_pre(MDOC_ARGS); +static int mdoc_sy_pre(MDOC_ARGS); +static int mdoc_ud_pre(MDOC_ARGS); +static int mdoc_va_pre(MDOC_ARGS); +static int mdoc_vt_pre(MDOC_ARGS); +static int mdoc_xr_pre(MDOC_ARGS); +static int mdoc_xx_pre(MDOC_ARGS); + +static const struct htmlmdoc mdocs[MDOC_MAX] = { + {mdoc_ap_pre, NULL}, /* Ap */ + {NULL, NULL}, /* Dd */ + {NULL, NULL}, /* Dt */ + {NULL, NULL}, /* Os */ + {mdoc_sh_pre, NULL }, /* Sh */ + {mdoc_ss_pre, NULL }, /* Ss */ + {mdoc_sp_pre, NULL}, /* Pp */ + {mdoc_d1_pre, NULL}, /* D1 */ + {mdoc_d1_pre, NULL}, /* Dl */ + {mdoc_bd_pre, NULL}, /* Bd */ + {NULL, NULL}, /* Ed */ + {mdoc_bl_pre, mdoc_bl_post}, /* Bl */ + {NULL, NULL}, /* El */ + {mdoc_it_pre, NULL}, /* It */ + {mdoc_ad_pre, NULL}, /* Ad */ + {mdoc_an_pre, NULL}, /* An */ + {mdoc_ar_pre, NULL}, /* Ar */ + {mdoc_cd_pre, NULL}, /* Cd */ + {mdoc_fl_pre, NULL}, /* Cm */ + {mdoc_dv_pre, NULL}, /* Dv */ + {mdoc_er_pre, NULL}, /* Er */ + {mdoc_ev_pre, NULL}, /* Ev */ + {mdoc_ex_pre, NULL}, /* Ex */ + {mdoc_fa_pre, NULL}, /* Fa */ + {mdoc_fd_pre, NULL}, /* Fd */ + {mdoc_fl_pre, NULL}, /* Fl */ + {mdoc_fn_pre, NULL}, /* Fn */ + {mdoc_ft_pre, NULL}, /* Ft */ + {mdoc_ic_pre, NULL}, /* Ic */ + {mdoc_in_pre, NULL}, /* In */ + {mdoc_li_pre, NULL}, /* Li */ + {mdoc_nd_pre, NULL}, /* Nd */ + {mdoc_nm_pre, NULL}, /* Nm */ + {mdoc_op_pre, mdoc_op_post}, /* Op */ + {NULL, NULL}, /* Ot */ + {mdoc_pa_pre, NULL}, /* Pa */ + {mdoc_rv_pre, NULL}, /* Rv */ + {NULL, NULL}, /* St */ + {mdoc_va_pre, NULL}, /* Va */ + {mdoc_vt_pre, NULL}, /* Vt */ + {mdoc_xr_pre, NULL}, /* Xr */ + {mdoc__x_pre, mdoc__x_post}, /* %A */ + {mdoc__x_pre, mdoc__x_post}, /* %B */ + {mdoc__x_pre, mdoc__x_post}, /* %D */ + {mdoc__x_pre, mdoc__x_post}, /* %I */ + {mdoc__x_pre, mdoc__x_post}, /* %J */ + {mdoc__x_pre, mdoc__x_post}, /* %N */ + {mdoc__x_pre, mdoc__x_post}, /* %O */ + {mdoc__x_pre, mdoc__x_post}, /* %P */ + {mdoc__x_pre, mdoc__x_post}, /* %R */ + {mdoc__x_pre, mdoc__x_post}, /* %T */ + {mdoc__x_pre, mdoc__x_post}, /* %V */ + {NULL, NULL}, /* Ac */ + {mdoc_aq_pre, mdoc_aq_post}, /* Ao */ + {mdoc_aq_pre, mdoc_aq_post}, /* Aq */ + {NULL, NULL}, /* At */ + {NULL, NULL}, /* Bc */ + {mdoc_bf_pre, NULL}, /* Bf */ + {mdoc_bq_pre, mdoc_bq_post}, /* Bo */ + {mdoc_bq_pre, mdoc_bq_post}, /* Bq */ + {mdoc_xx_pre, NULL}, /* Bsx */ + {mdoc_bx_pre, NULL}, /* Bx */ + {NULL, NULL}, /* Db */ + {NULL, NULL}, /* Dc */ + {mdoc_dq_pre, mdoc_dq_post}, /* Do */ + {mdoc_dq_pre, mdoc_dq_post}, /* Dq */ + {NULL, NULL}, /* Ec */ + {NULL, NULL}, /* Ef */ + {mdoc_em_pre, NULL}, /* Em */ + {NULL, NULL}, /* Eo */ + {mdoc_xx_pre, NULL}, /* Fx */ + {mdoc_ms_pre, NULL}, /* Ms */ /* FIXME: convert to symbol? */ + {NULL, NULL}, /* No */ + {mdoc_ns_pre, NULL}, /* Ns */ + {mdoc_xx_pre, NULL}, /* Nx */ + {mdoc_xx_pre, NULL}, /* Ox */ + {NULL, NULL}, /* Pc */ + {mdoc_pf_pre, mdoc_pf_post}, /* Pf */ + {mdoc_pq_pre, mdoc_pq_post}, /* Po */ + {mdoc_pq_pre, mdoc_pq_post}, /* Pq */ + {NULL, NULL}, /* Qc */ + {mdoc_sq_pre, mdoc_sq_post}, /* Ql */ + {mdoc_dq_pre, mdoc_dq_post}, /* Qo */ + {mdoc_dq_pre, mdoc_dq_post}, /* Qq */ + {NULL, NULL}, /* Re */ + {mdoc_rs_pre, NULL}, /* Rs */ + {NULL, NULL}, /* Sc */ + {mdoc_sq_pre, mdoc_sq_post}, /* So */ + {mdoc_sq_pre, mdoc_sq_post}, /* Sq */ + {NULL, NULL}, /* Sm */ /* FIXME - no idea. */ + {mdoc_sx_pre, NULL}, /* Sx */ + {mdoc_sy_pre, NULL}, /* Sy */ + {NULL, NULL}, /* Tn */ + {mdoc_xx_pre, NULL}, /* Ux */ + {NULL, NULL}, /* Xc */ + {NULL, NULL}, /* Xo */ + {mdoc_fo_pre, mdoc_fo_post}, /* Fo */ + {NULL, NULL}, /* Fc */ + {mdoc_op_pre, mdoc_op_post}, /* Oo */ + {NULL, NULL}, /* Oc */ + {NULL, NULL}, /* Bk */ + {NULL, NULL}, /* Ek */ + {mdoc_bt_pre, NULL}, /* Bt */ + {NULL, NULL}, /* Hf */ + {NULL, NULL}, /* Fr */ + {mdoc_ud_pre, NULL}, /* Ud */ + {mdoc_lb_pre, NULL}, /* Lb */ + {mdoc_sp_pre, NULL}, /* Lp */ + {mdoc_lk_pre, NULL}, /* Lk */ + {mdoc_mt_pre, NULL}, /* Mt */ + {mdoc_brq_pre, mdoc_brq_post}, /* Brq */ + {mdoc_brq_pre, mdoc_brq_post}, /* Bro */ + {NULL, NULL}, /* Brc */ + {mdoc__x_pre, mdoc__x_post}, /* %C */ + {NULL, NULL}, /* Es */ /* TODO */ + {NULL, NULL}, /* En */ /* TODO */ + {mdoc_xx_pre, NULL}, /* Dx */ + {mdoc__x_pre, mdoc__x_post}, /* %Q */ + {mdoc_sp_pre, NULL}, /* br */ + {mdoc_sp_pre, NULL}, /* sp */ +}; + + +void +html_mdoc(void *arg, const struct mdoc *m) +{ + struct html *h; + struct tag *t; + + h = (struct html *)arg; + + print_gen_doctype(h); + t = print_otag(h, TAG_HTML, 0, NULL); + print_mdoc(mdoc_meta(m), mdoc_node(m), h); + print_tagq(h, t); + + printf("\n"); +} + + +/* + * Return the list type for `Bl', e.g., `Bl -column' returns + * MDOC_Column. This can ONLY be run for lists; it will abort() if no + * list type is found. + */ +static int +a2list(const struct mdoc_node *n) +{ + int i; + + assert(n->args); + for (i = 0; i < (int)n->args->argc; i++) + switch (n->args->argv[i].arg) { + case (MDOC_Enum): + /* FALLTHROUGH */ + case (MDOC_Dash): + /* FALLTHROUGH */ + case (MDOC_Hyphen): + /* FALLTHROUGH */ + case (MDOC_Bullet): + /* FALLTHROUGH */ + case (MDOC_Tag): + /* FALLTHROUGH */ + case (MDOC_Hang): + /* FALLTHROUGH */ + case (MDOC_Inset): + /* FALLTHROUGH */ + case (MDOC_Diag): + /* FALLTHROUGH */ + case (MDOC_Item): + /* FALLTHROUGH */ + case (MDOC_Column): + /* FALLTHROUGH */ + case (MDOC_Ohang): + return(n->args->argv[i].arg); + default: + break; + } + + abort(); + /* NOTREACHED */ +} + + +/* + * Calculate the scaling unit passed in a `-width' argument. This uses + * either a native scaling unit (e.g., 1i, 2m) or the string length of + * the value. + */ +static void +a2width(const char *p, struct roffsu *su) +{ + + if ( ! a2roffsu(p, su, SCALE_MAX)) { + su->unit = SCALE_EM; + su->scale = (int)strlen(p); + } +} + + +/* + * Calculate the scaling unit passed in an `-offset' argument. This + * uses either a native scaling unit (e.g., 1i, 2m), one of a set of + * predefined strings (indent, etc.), or the string length of the value. + */ +static void +a2offs(const char *p, struct roffsu *su) +{ + + /* FIXME: "right"? */ + + if (0 == strcmp(p, "left")) + SCALE_HS_INIT(su, 0); + else if (0 == strcmp(p, "indent")) + SCALE_HS_INIT(su, INDENT); + else if (0 == strcmp(p, "indent-two")) + SCALE_HS_INIT(su, INDENT * 2); + else if ( ! a2roffsu(p, su, SCALE_MAX)) { + su->unit = SCALE_EM; + su->scale = (int)strlen(p); + } +} + + +static void +print_mdoc(MDOC_ARGS) +{ + struct tag *t; + struct htmlpair tag; + + t = print_otag(h, TAG_HEAD, 0, NULL); + print_mdoc_head(m, n, h); + print_tagq(h, t); + + t = print_otag(h, TAG_BODY, 0, NULL); + + tag.key = ATTR_CLASS; + tag.val = "body"; + print_otag(h, TAG_DIV, 1, &tag); + + print_mdoc_nodelist(m, n, h); + print_tagq(h, t); +} + + +/* ARGSUSED */ +static void +print_mdoc_head(MDOC_ARGS) +{ + + print_gen_head(h); + bufinit(h); + buffmt(h, "%s(%d)", m->title, m->msec); + + if (m->arch) { + bufcat(h, " ("); + bufcat(h, m->arch); + bufcat(h, ")"); + } + + print_otag(h, TAG_TITLE, 0, NULL); + print_text(h, h->buf); +} + + +static void +print_mdoc_nodelist(MDOC_ARGS) +{ + + print_mdoc_node(m, n, h); + if (n->next) + print_mdoc_nodelist(m, n->next, h); +} + + +static void +print_mdoc_node(MDOC_ARGS) +{ + int child; + struct tag *t; + + child = 1; + t = SLIST_FIRST(&h->tags); + + bufinit(h); + switch (n->type) { + case (MDOC_ROOT): + child = mdoc_root_pre(m, n, h); + break; + case (MDOC_TEXT): + print_text(h, n->string); + break; + default: + if (mdocs[n->tok].pre) + child = (*mdocs[n->tok].pre)(m, n, h); + break; + } + + if (child && n->child) + print_mdoc_nodelist(m, n->child, h); + + print_stagq(h, t); + + bufinit(h); + switch (n->type) { + case (MDOC_ROOT): + mdoc_root_post(m, n, h); + break; + case (MDOC_TEXT): + break; + default: + if (mdocs[n->tok].post) + (*mdocs[n->tok].post)(m, n, h); + break; + } +} + + +/* ARGSUSED */ +static void +mdoc_root_post(MDOC_ARGS) +{ + struct tm tm; + struct htmlpair tag[2]; + struct tag *t, *tt; + char b[BUFSIZ]; + + /* + * XXX: this should use divs, but in Firefox, divs with nested + * divs for some reason puke when trying to put a border line + * below. So I use tables, instead. + */ + + (void)localtime_r(&m->date, &tm); + + if (0 == strftime(b, BUFSIZ - 1, "%B %e, %Y", &tm)) + err(EXIT_FAILURE, "strftime"); + + PAIR_CLASS_INIT(&tag[0], "footer"); + bufcat_style(h, "width", "100%"); + PAIR_STYLE_INIT(&tag[1], h); + t = print_otag(h, TAG_TABLE, 2, tag); + tt = print_otag(h, TAG_TR, 0, NULL); + + bufinit(h); + bufcat_style(h, "width", "50%"); + PAIR_STYLE_INIT(&tag[0], h); + print_otag(h, TAG_TD, 1, tag); + print_text(h, b); + print_stagq(h, tt); + + bufinit(h); + bufcat_style(h, "width", "50%"); + bufcat_style(h, "text-align", "right"); + PAIR_STYLE_INIT(&tag[0], h); + print_otag(h, TAG_TD, 1, tag); + print_text(h, m->os); + print_tagq(h, t); +} + + +/* ARGSUSED */ +static int +mdoc_root_pre(MDOC_ARGS) +{ + struct htmlpair tag[2]; + struct tag *t, *tt; + char b[BUFSIZ], title[BUFSIZ]; + + (void)strlcpy(b, m->vol, BUFSIZ); + + if (m->arch) { + (void)strlcat(b, " (", BUFSIZ); + (void)strlcat(b, m->arch, BUFSIZ); + (void)strlcat(b, ")", BUFSIZ); + } + + (void)snprintf(title, BUFSIZ - 1, + "%s(%d)", m->title, m->msec); + + /* XXX: see note in mdoc_root_post() about divs. */ + + PAIR_CLASS_INIT(&tag[0], "header"); + bufcat_style(h, "width", "100%"); + PAIR_STYLE_INIT(&tag[1], h); + t = print_otag(h, TAG_TABLE, 2, tag); + tt = print_otag(h, TAG_TR, 0, NULL); + + bufinit(h); + bufcat_style(h, "width", "10%"); + PAIR_STYLE_INIT(&tag[0], h); + print_otag(h, TAG_TD, 1, tag); + print_text(h, title); + print_stagq(h, tt); + + bufinit(h); + bufcat_style(h, "text-align", "center"); + bufcat_style(h, "white-space", "nowrap"); + bufcat_style(h, "width", "80%"); + PAIR_STYLE_INIT(&tag[0], h); + print_otag(h, TAG_TD, 1, tag); + print_text(h, b); + print_stagq(h, tt); + + bufinit(h); + bufcat_style(h, "text-align", "right"); + bufcat_style(h, "width", "10%"); + PAIR_STYLE_INIT(&tag[0], h); + print_otag(h, TAG_TD, 1, tag); + print_text(h, title); + print_tagq(h, t); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_sh_pre(MDOC_ARGS) +{ + struct htmlpair tag[2]; + const struct mdoc_node *nn; + char lbuf[BUFSIZ]; + struct roffsu su; + + if (MDOC_BODY == n->type) { + SCALE_HS_INIT(&su, INDENT); + bufcat_su(h, "margin-left", &su); + PAIR_CLASS_INIT(&tag[0], "sec-body"); + PAIR_STYLE_INIT(&tag[1], h); + print_otag(h, TAG_DIV, 2, tag); + return(1); + } else if (MDOC_BLOCK == n->type) { + PAIR_CLASS_INIT(&tag[0], "sec-block"); + if (n->prev && NULL == n->prev->body->child) { + print_otag(h, TAG_DIV, 1, tag); + return(1); + } + + SCALE_VS_INIT(&su, 1); + bufcat_su(h, "margin-top", &su); + if (NULL == n->next) + bufcat_su(h, "margin-bottom", &su); + + PAIR_STYLE_INIT(&tag[1], h); + print_otag(h, TAG_DIV, 2, tag); + return(1); + } + + lbuf[0] = 0; + for (nn = n->child; nn; nn = nn->next) { + (void)strlcat(lbuf, nn->string, BUFSIZ); + if (nn->next) + (void)strlcat(lbuf, "_", BUFSIZ); + } + + /* + * TODO: make sure there are no duplicates, as HTML does not + * allow for multiple `id' tags of the same name. + */ + + PAIR_CLASS_INIT(&tag[0], "sec-head"); + tag[1].key = ATTR_ID; + tag[1].val = lbuf; + print_otag(h, TAG_DIV, 2, tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_ss_pre(MDOC_ARGS) +{ + struct htmlpair tag[3]; + const struct mdoc_node *nn; + char lbuf[BUFSIZ]; + struct roffsu su; + + SCALE_VS_INIT(&su, 1); + + if (MDOC_BODY == n->type) { + PAIR_CLASS_INIT(&tag[0], "ssec-body"); + if (n->parent->next && n->child) { + bufcat_su(h, "margin-bottom", &su); + PAIR_STYLE_INIT(&tag[1], h); + print_otag(h, TAG_DIV, 2, tag); + } else + print_otag(h, TAG_DIV, 1, tag); + return(1); + } else if (MDOC_BLOCK == n->type) { + PAIR_CLASS_INIT(&tag[0], "ssec-block"); + if (n->prev) { + bufcat_su(h, "margin-top", &su); + PAIR_STYLE_INIT(&tag[1], h); + print_otag(h, TAG_DIV, 2, tag); + } else + print_otag(h, TAG_DIV, 1, tag); + return(1); + } + + /* TODO: see note in mdoc_sh_pre() about duplicates. */ + + lbuf[0] = 0; + for (nn = n->child; nn; nn = nn->next) { + (void)strlcat(lbuf, nn->string, BUFSIZ); + if (nn->next) + (void)strlcat(lbuf, "_", BUFSIZ); + } + + SCALE_HS_INIT(&su, INDENT - HALFINDENT); + su.scale = -su.scale; + bufcat_su(h, "margin-left", &su); + + PAIR_CLASS_INIT(&tag[0], "ssec-head"); + PAIR_STYLE_INIT(&tag[1], h); + tag[2].key = ATTR_ID; + tag[2].val = lbuf; + print_otag(h, TAG_DIV, 3, tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_fl_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + PAIR_CLASS_INIT(&tag, "flag"); + print_otag(h, TAG_SPAN, 1, &tag); + if (MDOC_Fl == n->tok) { + print_text(h, "\\-"); + h->flags |= HTML_NOSPACE; + } + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_nd_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + if (MDOC_BODY != n->type) + return(1); + + /* XXX: this tag in theory can contain block elements. */ + + print_text(h, "\\(em"); + PAIR_CLASS_INIT(&tag, "desc-body"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_op_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + if (MDOC_BODY != n->type) + return(1); + + /* XXX: this tag in theory can contain block elements. */ + + print_text(h, "\\(lB"); + h->flags |= HTML_NOSPACE; + PAIR_CLASS_INIT(&tag, "opt"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static void +mdoc_op_post(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return; + h->flags |= HTML_NOSPACE; + print_text(h, "\\(rB"); +} + + +static int +mdoc_nm_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + if ( ! (HTML_NEWLINE & h->flags)) + if (SEC_SYNOPSIS == n->sec) { + bufcat_style(h, "clear", "both"); + PAIR_STYLE_INIT(&tag, h); + print_otag(h, TAG_BR, 1, &tag); + } + + PAIR_CLASS_INIT(&tag, "name"); + print_otag(h, TAG_SPAN, 1, &tag); + if (NULL == n->child) + print_text(h, m->name); + + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_xr_pre(MDOC_ARGS) +{ + struct htmlpair tag[2]; + const struct mdoc_node *nn; + + PAIR_CLASS_INIT(&tag[0], "link-man"); + + if (h->base_man) { + buffmt_man(h, n->child->string, + n->child->next ? + n->child->next->string : NULL); + tag[1].key = ATTR_HREF; + tag[1].val = h->buf; + print_otag(h, TAG_A, 2, tag); + } else + print_otag(h, TAG_A, 1, tag); + + nn = n->child; + print_text(h, nn->string); + + if (NULL == (nn = nn->next)) + return(0); + + h->flags |= HTML_NOSPACE; + print_text(h, "("); + h->flags |= HTML_NOSPACE; + print_text(h, nn->string); + h->flags |= HTML_NOSPACE; + print_text(h, ")"); + return(0); +} + + +/* ARGSUSED */ +static int +mdoc_ns_pre(MDOC_ARGS) +{ + + h->flags |= HTML_NOSPACE; + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_ar_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + PAIR_CLASS_INIT(&tag, "arg"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_xx_pre(MDOC_ARGS) +{ + const char *pp; + struct htmlpair tag; + + switch (n->tok) { + case (MDOC_Bsx): + pp = "BSDI BSD/OS"; + break; + case (MDOC_Dx): + pp = "DragonFlyBSD"; + break; + case (MDOC_Fx): + pp = "FreeBSD"; + break; + case (MDOC_Nx): + pp = "NetBSD"; + break; + case (MDOC_Ox): + pp = "OpenBSD"; + break; + case (MDOC_Ux): + pp = "UNIX"; + break; + default: + return(1); + } + + PAIR_CLASS_INIT(&tag, "unix"); + print_otag(h, TAG_SPAN, 1, &tag); + print_text(h, pp); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_bx_pre(MDOC_ARGS) +{ + const struct mdoc_node *nn; + struct htmlpair tag; + + PAIR_CLASS_INIT(&tag, "unix"); + print_otag(h, TAG_SPAN, 1, &tag); + + for (nn = n->child; nn; nn = nn->next) + print_mdoc_node(m, nn, h); + + if (n->child) + h->flags |= HTML_NOSPACE; + + print_text(h, "BSD"); + return(0); +} + + +/* ARGSUSED */ +static int +mdoc_it_block_pre(MDOC_ARGS, int type, int comp, + struct roffsu *offs, struct roffsu *width) +{ + struct htmlpair tag; + const struct mdoc_node *nn; + struct roffsu su; + + nn = n->parent->parent; + assert(nn->args); + + /* XXX: see notes in mdoc_it_pre(). */ + + if (MDOC_Column == type) { + /* Don't width-pad on the left. */ + SCALE_HS_INIT(width, 0); + /* Also disallow non-compact. */ + comp = 1; + } + if (MDOC_Diag == type) + /* Mandate non-compact with empty prior. */ + if (n->prev && NULL == n->prev->body->child) + comp = 1; + + bufcat_style(h, "clear", "both"); + if (offs->scale > 0) + bufcat_su(h, "margin-left", offs); + if (width->scale > 0) + bufcat_su(h, "padding-left", width); + + PAIR_STYLE_INIT(&tag, h); + + /* Mandate compact following `Ss' and `Sh' starts. */ + + for (nn = n; nn && ! comp; nn = nn->parent) { + if (MDOC_BLOCK != nn->type) + continue; + if (MDOC_Ss == nn->tok || MDOC_Sh == nn->tok) + comp = 1; + if (nn->prev) + break; + } + + if ( ! comp) { + SCALE_VS_INIT(&su, 1); + bufcat_su(h, "padding-top", &su); + } + + PAIR_STYLE_INIT(&tag, h); + print_otag(h, TAG_DIV, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_it_body_pre(MDOC_ARGS, int type) +{ + struct htmlpair tag; + struct roffsu su; + + switch (type) { + case (MDOC_Item): + /* FALLTHROUGH */ + case (MDOC_Ohang): + /* FALLTHROUGH */ + case (MDOC_Column): + break; + default: + /* + * XXX: this tricks CSS into aligning the bodies with + * the right-padding in the head. + */ + SCALE_HS_INIT(&su, 2); + bufcat_su(h, "margin-left", &su); + PAIR_STYLE_INIT(&tag, h); + print_otag(h, TAG_DIV, 1, &tag); + break; + } + + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_it_head_pre(MDOC_ARGS, int type, struct roffsu *width) +{ + struct htmlpair tag; + struct ord *ord; + char nbuf[BUFSIZ]; + + switch (type) { + case (MDOC_Item): + /* FALLTHROUGH */ + case (MDOC_Ohang): + print_otag(h, TAG_DIV, 0, NULL); + break; + case (MDOC_Column): + bufcat_su(h, "min-width", width); + bufcat_style(h, "clear", "none"); + if (n->next && MDOC_HEAD == n->next->type) + bufcat_style(h, "float", "left"); + PAIR_STYLE_INIT(&tag, h); + print_otag(h, TAG_DIV, 1, &tag); + break; + default: + bufcat_su(h, "min-width", width); + SCALE_INVERT(width); + bufcat_su(h, "margin-left", width); + if (n->next && n->next->child) + bufcat_style(h, "float", "left"); + + /* XXX: buffer if we run into body. */ + SCALE_HS_INIT(width, 1); + bufcat_su(h, "margin-right", width); + PAIR_STYLE_INIT(&tag, h); + print_otag(h, TAG_DIV, 1, &tag); + break; + } + + switch (type) { + case (MDOC_Diag): + PAIR_CLASS_INIT(&tag, "diag"); + print_otag(h, TAG_SPAN, 1, &tag); + break; + case (MDOC_Enum): + ord = SLIST_FIRST(&h->ords); + assert(ord); + nbuf[BUFSIZ - 1] = 0; + (void)snprintf(nbuf, BUFSIZ - 1, "%d.", ord->pos++); + print_text(h, nbuf); + return(0); + case (MDOC_Dash): + print_text(h, "\\(en"); + return(0); + case (MDOC_Hyphen): + print_text(h, "\\(hy"); + return(0); + case (MDOC_Bullet): + print_text(h, "\\(bu"); + return(0); + default: + break; + } + + return(1); +} + + +static int +mdoc_it_pre(MDOC_ARGS) +{ + int i, type, wp, comp; + const struct mdoc_node *bl, *nn; + struct roffsu width, offs; + + /* + * XXX: be very careful in changing anything, here. Lists in + * mandoc have many peculiarities; furthermore, they don't + * translate well into HTML and require a bit of mangling. + */ + + bl = n->parent->parent; + if (MDOC_BLOCK != n->type) + bl = bl->parent; + + type = a2list(bl); + + /* Set default width and offset. */ + + SCALE_HS_INIT(&offs, 0); + + switch (type) { + case (MDOC_Enum): + /* FALLTHROUGH */ + case (MDOC_Dash): + /* FALLTHROUGH */ + case (MDOC_Hyphen): + /* FALLTHROUGH */ + case (MDOC_Bullet): + SCALE_HS_INIT(&width, 2); + break; + default: + SCALE_HS_INIT(&width, INDENT); + break; + } + + /* Get width, offset, and compact arguments. */ + + for (wp = -1, comp = i = 0; i < (int)bl->args->argc; i++) + switch (bl->args->argv[i].arg) { + case (MDOC_Column): + wp = i; /* Save for later. */ + break; + case (MDOC_Width): + a2width(bl->args->argv[i].value[0], &width); + break; + case (MDOC_Offset): + a2offs(bl->args->argv[i].value[0], &offs); + break; + case (MDOC_Compact): + comp = 1; + break; + default: + break; + } + + /* Override width in some cases. */ + + switch (type) { + case (MDOC_Item): + /* FALLTHROUGH */ + case (MDOC_Inset): + /* FALLTHROUGH */ + case (MDOC_Diag): + SCALE_HS_INIT(&width, 0); + break; + default: + if (0 == width.scale) + SCALE_HS_INIT(&width, INDENT); + break; + } + + /* Flip to body/block processing. */ + + if (MDOC_BODY == n->type) + return(mdoc_it_body_pre(m, n, h, type)); + if (MDOC_BLOCK == n->type) + return(mdoc_it_block_pre(m, n, h, type, comp, + &offs, &width)); + + /* Override column widths. */ + + if (MDOC_Column == type) { + nn = n->parent->child; + for (i = 0; nn && nn != n; nn = nn->next, i++) + /* Counter... */ ; + if (i < (int)bl->args->argv[wp].sz) + a2width(bl->args->argv[wp].value[i], &width); + } + + return(mdoc_it_head_pre(m, n, h, type, &width)); +} + + +/* ARGSUSED */ +static int +mdoc_bl_pre(MDOC_ARGS) +{ + struct ord *ord; + + if (MDOC_BLOCK != n->type) + return(1); + if (MDOC_Enum != a2list(n)) + return(1); + + ord = malloc(sizeof(struct ord)); + if (NULL == ord) + err(EXIT_FAILURE, "malloc"); + ord->cookie = n; + ord->pos = 1; + SLIST_INSERT_HEAD(&h->ords, ord, entry); + return(1); +} + + +/* ARGSUSED */ +static void +mdoc_bl_post(MDOC_ARGS) +{ + struct ord *ord; + + if (MDOC_BLOCK != n->type) + return; + if (MDOC_Enum != a2list(n)) + return; + + ord = SLIST_FIRST(&h->ords); + assert(ord); + SLIST_REMOVE_HEAD(&h->ords, entry); + free(ord); +} + + +/* ARGSUSED */ +static int +mdoc_ex_pre(MDOC_ARGS) +{ + const struct mdoc_node *nn; + struct tag *t; + struct htmlpair tag; + + PAIR_CLASS_INIT(&tag, "utility"); + + print_text(h, "The"); + for (nn = n->child; nn; nn = nn->next) { + t = print_otag(h, TAG_SPAN, 1, &tag); + print_text(h, nn->string); + print_tagq(h, t); + + h->flags |= HTML_NOSPACE; + + if (nn->next && NULL == nn->next->next) + print_text(h, ", and"); + else if (nn->next) + print_text(h, ","); + else + h->flags &= ~HTML_NOSPACE; + } + + if (n->child->next) + print_text(h, "utilities exit"); + else + print_text(h, "utility exits"); + + print_text(h, "0 on success, and >0 if an error occurs."); + return(0); +} + + +/* ARGSUSED */ +static int +mdoc_dq_pre(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return(1); + print_text(h, "\\(lq"); + h->flags |= HTML_NOSPACE; + return(1); +} + + +/* ARGSUSED */ +static void +mdoc_dq_post(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return; + h->flags |= HTML_NOSPACE; + print_text(h, "\\(rq"); +} + + +/* ARGSUSED */ +static int +mdoc_pq_pre(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return(1); + print_text(h, "\\&("); + h->flags |= HTML_NOSPACE; + return(1); +} + + +/* ARGSUSED */ +static void +mdoc_pq_post(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return; + print_text(h, ")"); +} + + +/* ARGSUSED */ +static int +mdoc_sq_pre(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return(1); + print_text(h, "\\(oq"); + h->flags |= HTML_NOSPACE; + return(1); +} + + +/* ARGSUSED */ +static void +mdoc_sq_post(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return; + h->flags |= HTML_NOSPACE; + print_text(h, "\\(aq"); +} + + +/* ARGSUSED */ +static int +mdoc_em_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + PAIR_CLASS_INIT(&tag, "emph"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_d1_pre(MDOC_ARGS) +{ + struct htmlpair tag[2]; + struct roffsu su; + + if (MDOC_BLOCK != n->type) + return(1); + + /* FIXME: D1 shouldn't be literal. */ + + SCALE_VS_INIT(&su, INDENT - 2); + bufcat_su(h, "margin-left", &su); + PAIR_CLASS_INIT(&tag[0], "lit"); + PAIR_STYLE_INIT(&tag[1], h); + print_otag(h, TAG_DIV, 2, tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_sx_pre(MDOC_ARGS) +{ + struct htmlpair tag[2]; + const struct mdoc_node *nn; + char buf[BUFSIZ]; + + /* FIXME: duplicates? */ + + (void)strlcpy(buf, "#", BUFSIZ); + for (nn = n->child; nn; nn = nn->next) { + (void)strlcat(buf, nn->string, BUFSIZ); + if (nn->next) + (void)strlcat(buf, "_", BUFSIZ); + } + + PAIR_CLASS_INIT(&tag[0], "link-sec"); + tag[1].key = ATTR_HREF; + tag[1].val = buf; + + print_otag(h, TAG_A, 2, tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_aq_pre(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return(1); + print_text(h, "\\(la"); + h->flags |= HTML_NOSPACE; + return(1); +} + + +/* ARGSUSED */ +static void +mdoc_aq_post(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return; + h->flags |= HTML_NOSPACE; + print_text(h, "\\(ra"); +} + + +/* ARGSUSED */ +static int +mdoc_bd_pre(MDOC_ARGS) +{ + struct htmlpair tag[2]; + int type, comp, i; + const struct mdoc_node *bl, *nn; + struct roffsu su; + + if (MDOC_BLOCK == n->type) + bl = n; + else if (MDOC_HEAD == n->type) + return(0); + else + bl = n->parent; + + SCALE_VS_INIT(&su, 0); + + type = comp = 0; + for (i = 0; i < (int)bl->args->argc; i++) + switch (bl->args->argv[i].arg) { + case (MDOC_Offset): + a2offs(bl->args->argv[i].value[0], &su); + break; + case (MDOC_Compact): + comp = 1; + break; + case (MDOC_Centred): + /* FALLTHROUGH */ + case (MDOC_Ragged): + /* FALLTHROUGH */ + case (MDOC_Filled): + /* FALLTHROUGH */ + case (MDOC_Unfilled): + /* FALLTHROUGH */ + case (MDOC_Literal): + type = bl->args->argv[i].arg; + break; + default: + break; + } + + /* FIXME: -centered, etc. formatting. */ + + if (MDOC_BLOCK == n->type) { + bufcat_su(h, "margin-left", &su); + for (nn = n; nn && ! comp; nn = nn->parent) { + if (MDOC_BLOCK != nn->type) + continue; + if (MDOC_Ss == nn->tok || MDOC_Sh == nn->tok) + comp = 1; + if (nn->prev) + break; + } + if (comp) { + print_otag(h, TAG_DIV, 0, tag); + return(1); + } + SCALE_VS_INIT(&su, 1); + bufcat_su(h, "margin-top", &su); + PAIR_STYLE_INIT(&tag[0], h); + print_otag(h, TAG_DIV, 1, tag); + return(1); + } + + if (MDOC_Unfilled != type && MDOC_Literal != type) + return(1); + + PAIR_CLASS_INIT(&tag[0], "lit"); + bufcat_style(h, "white-space", "pre"); + PAIR_STYLE_INIT(&tag[1], h); + print_otag(h, TAG_DIV, 2, tag); + + for (nn = n->child; nn; nn = nn->next) { + h->flags |= HTML_NOSPACE; + print_mdoc_node(m, nn, h); + if (NULL == nn->next) + continue; + if (nn->prev && nn->prev->line < nn->line) + print_text(h, "\n"); + else if (NULL == nn->prev) + print_text(h, "\n"); + } + + return(0); +} + + +/* ARGSUSED */ +static int +mdoc_pa_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + PAIR_CLASS_INIT(&tag, "file"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_ad_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + PAIR_CLASS_INIT(&tag, "addr"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_an_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + /* TODO: -split and -nosplit (see termp_an_pre()). */ + + PAIR_CLASS_INIT(&tag, "author"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_cd_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + print_otag(h, TAG_DIV, 0, NULL); + PAIR_CLASS_INIT(&tag, "config"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_dv_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + PAIR_CLASS_INIT(&tag, "define"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_ev_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + PAIR_CLASS_INIT(&tag, "env"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_er_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + PAIR_CLASS_INIT(&tag, "errno"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_fa_pre(MDOC_ARGS) +{ + const struct mdoc_node *nn; + struct htmlpair tag; + struct tag *t; + + PAIR_CLASS_INIT(&tag, "farg"); + if (n->parent->tok != MDOC_Fo) { + print_otag(h, TAG_SPAN, 1, &tag); + return(1); + } + + for (nn = n->child; nn; nn = nn->next) { + t = print_otag(h, TAG_SPAN, 1, &tag); + print_text(h, nn->string); + print_tagq(h, t); + if (nn->next) + print_text(h, ","); + } + + if (n->child && n->next && n->next->tok == MDOC_Fa) + print_text(h, ","); + + return(0); +} + + +/* ARGSUSED */ +static int +mdoc_fd_pre(MDOC_ARGS) +{ + struct htmlpair tag; + struct roffsu su; + + if (SEC_SYNOPSIS == n->sec) { + if (n->next && MDOC_Fd != n->next->tok) { + SCALE_VS_INIT(&su, 1); + bufcat_su(h, "margin-bottom", &su); + PAIR_STYLE_INIT(&tag, h); + print_otag(h, TAG_DIV, 1, &tag); + } else + print_otag(h, TAG_DIV, 0, NULL); + } + + PAIR_CLASS_INIT(&tag, "macro"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_vt_pre(MDOC_ARGS) +{ + struct htmlpair tag; + struct roffsu su; + + if (SEC_SYNOPSIS == n->sec) { + if (n->next && MDOC_Vt != n->next->tok) { + SCALE_VS_INIT(&su, 1); + bufcat_su(h, "margin-bottom", &su); + PAIR_STYLE_INIT(&tag, h); + print_otag(h, TAG_DIV, 1, &tag); + } else + print_otag(h, TAG_DIV, 0, NULL); + } + + PAIR_CLASS_INIT(&tag, "type"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_ft_pre(MDOC_ARGS) +{ + struct htmlpair tag; + struct roffsu su; + + if (SEC_SYNOPSIS == n->sec) { + if (n->prev && MDOC_Fo == n->prev->tok) { + SCALE_VS_INIT(&su, 1); + bufcat_su(h, "margin-top", &su); + PAIR_STYLE_INIT(&tag, h); + print_otag(h, TAG_DIV, 1, &tag); + } else + print_otag(h, TAG_DIV, 0, NULL); + } + + PAIR_CLASS_INIT(&tag, "ftype"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_fn_pre(MDOC_ARGS) +{ + struct tag *t; + struct htmlpair tag[2]; + const struct mdoc_node *nn; + char nbuf[BUFSIZ]; + const char *sp, *ep; + int sz, i; + struct roffsu su; + + if (SEC_SYNOPSIS == n->sec) { + SCALE_HS_INIT(&su, INDENT); + bufcat_su(h, "margin-left", &su); + su.scale = -su.scale; + bufcat_su(h, "text-indent", &su); + if (n->next) { + SCALE_VS_INIT(&su, 1); + bufcat_su(h, "margin-bottom", &su); + } + PAIR_STYLE_INIT(&tag[0], h); + print_otag(h, TAG_DIV, 1, tag); + } + + /* Split apart into type and name. */ + assert(n->child->string); + sp = n->child->string; + + ep = strchr(sp, ' '); + if (NULL != ep) { + PAIR_CLASS_INIT(&tag[0], "ftype"); + t = print_otag(h, TAG_SPAN, 1, tag); + + while (ep) { + sz = MIN((int)(ep - sp), BUFSIZ - 1); + (void)memcpy(nbuf, sp, (size_t)sz); + nbuf[sz] = '\0'; + print_text(h, nbuf); + sp = ++ep; + ep = strchr(sp, ' '); + } + print_tagq(h, t); + } + + PAIR_CLASS_INIT(&tag[0], "fname"); + t = print_otag(h, TAG_SPAN, 1, tag); + + if (sp) { + (void)strlcpy(nbuf, sp, BUFSIZ); + print_text(h, nbuf); + } + + print_tagq(h, t); + + h->flags |= HTML_NOSPACE; + print_text(h, "("); + + bufinit(h); + PAIR_CLASS_INIT(&tag[0], "farg"); + bufcat_style(h, "white-space", "nowrap"); + PAIR_STYLE_INIT(&tag[1], h); + + for (nn = n->child->next; nn; nn = nn->next) { + i = 1; + if (SEC_SYNOPSIS == n->sec) + i = 2; + t = print_otag(h, TAG_SPAN, i, tag); + print_text(h, nn->string); + print_tagq(h, t); + if (nn->next) + print_text(h, ","); + } + + print_text(h, ")"); + if (SEC_SYNOPSIS == n->sec) + print_text(h, ";"); + + return(0); +} + + +/* ARGSUSED */ +static int +mdoc_sp_pre(MDOC_ARGS) +{ + int len; + struct htmlpair tag; + struct roffsu su; + + switch (n->tok) { + case (MDOC_sp): + /* FIXME: can this have a scaling indicator? */ + len = n->child ? atoi(n->child->string) : 1; + break; + case (MDOC_br): + len = 0; + break; + default: + len = 1; + break; + } + + SCALE_VS_INIT(&su, len); + bufcat_su(h, "height", &su); + PAIR_STYLE_INIT(&tag, h); + print_otag(h, TAG_DIV, 1, &tag); + return(1); + +} + + +/* ARGSUSED */ +static int +mdoc_brq_pre(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return(1); + print_text(h, "\\(lC"); + h->flags |= HTML_NOSPACE; + return(1); +} + + +/* ARGSUSED */ +static void +mdoc_brq_post(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return; + h->flags |= HTML_NOSPACE; + print_text(h, "\\(rC"); +} + + +/* ARGSUSED */ +static int +mdoc_lk_pre(MDOC_ARGS) +{ + const struct mdoc_node *nn; + struct htmlpair tag[2]; + + nn = n->child; + + PAIR_CLASS_INIT(&tag[0], "link-ext"); + tag[1].key = ATTR_HREF; + tag[1].val = nn->string; + print_otag(h, TAG_A, 2, tag); + + for (nn = nn->next; nn; nn = nn->next) + print_text(h, nn->string); + + return(0); +} + + +/* ARGSUSED */ +static int +mdoc_mt_pre(MDOC_ARGS) +{ + struct htmlpair tag[2]; + struct tag *t; + const struct mdoc_node *nn; + + PAIR_CLASS_INIT(&tag[0], "link-mail"); + + for (nn = n->child; nn; nn = nn->next) { + bufinit(h); + bufcat(h, "mailto:"); + bufcat(h, nn->string); + PAIR_STYLE_INIT(&tag[1], h); + t = print_otag(h, TAG_A, 2, tag); + print_text(h, nn->string); + print_tagq(h, t); + } + + return(0); +} + + +/* ARGSUSED */ +static int +mdoc_fo_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + if (MDOC_BODY == n->type) { + h->flags |= HTML_NOSPACE; + print_text(h, "("); + h->flags |= HTML_NOSPACE; + return(1); + } else if (MDOC_BLOCK == n->type) + return(1); + + PAIR_CLASS_INIT(&tag, "fname"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static void +mdoc_fo_post(MDOC_ARGS) +{ + if (MDOC_BODY != n->type) + return; + h->flags |= HTML_NOSPACE; + print_text(h, ")"); + h->flags |= HTML_NOSPACE; + print_text(h, ";"); +} + + +/* ARGSUSED */ +static int +mdoc_in_pre(MDOC_ARGS) +{ + const struct mdoc_node *nn; + struct tag *t; + struct htmlpair tag[2]; + int i; + struct roffsu su; + + if (SEC_SYNOPSIS == n->sec) { + if (n->next && MDOC_In != n->next->tok) { + SCALE_VS_INIT(&su, 1); + bufcat_su(h, "margin-bottom", &su); + PAIR_STYLE_INIT(&tag[0], h); + print_otag(h, TAG_DIV, 1, tag); + } else + print_otag(h, TAG_DIV, 0, NULL); + } + + /* FIXME: there's a buffer bug in here somewhere. */ + + PAIR_CLASS_INIT(&tag[0], "includes"); + print_otag(h, TAG_SPAN, 1, tag); + + if (SEC_SYNOPSIS == n->sec) + print_text(h, "#include"); + + print_text(h, "<"); + h->flags |= HTML_NOSPACE; + + /* XXX -- see warning in termp_in_post(). */ + + for (nn = n->child; nn; nn = nn->next) { + PAIR_CLASS_INIT(&tag[0], "link-includes"); + i = 1; + if (h->base_includes) { + buffmt_includes(h, nn->string); + tag[i].key = ATTR_HREF; + tag[i++].val = h->buf; + } + t = print_otag(h, TAG_A, i, tag); + print_mdoc_node(m, nn, h); + print_tagq(h, t); + } + + h->flags |= HTML_NOSPACE; + print_text(h, ">"); + + return(0); +} + + +/* ARGSUSED */ +static int +mdoc_ic_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + PAIR_CLASS_INIT(&tag, "cmd"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_rv_pre(MDOC_ARGS) +{ + const struct mdoc_node *nn; + struct htmlpair tag; + struct tag *t; + + print_otag(h, TAG_DIV, 0, NULL); + print_text(h, "The"); + + for (nn = n->child; nn; nn = nn->next) { + PAIR_CLASS_INIT(&tag, "fname"); + t = print_otag(h, TAG_SPAN, 1, &tag); + print_text(h, nn->string); + print_tagq(h, t); + + h->flags |= HTML_NOSPACE; + if (nn->next && NULL == nn->next->next) + print_text(h, "(), and"); + else if (nn->next) + print_text(h, "(),"); + else + print_text(h, "()"); + } + + if (n->child->next) + print_text(h, "functions return"); + else + print_text(h, "function returns"); + + print_text(h, "the value 0 if successful; otherwise the value " + "-1 is returned and the global variable"); + + PAIR_CLASS_INIT(&tag, "var"); + t = print_otag(h, TAG_SPAN, 1, &tag); + print_text(h, "errno"); + print_tagq(h, t); + print_text(h, "is set to indicate the error."); + return(0); +} + + +/* ARGSUSED */ +static int +mdoc_va_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + PAIR_CLASS_INIT(&tag, "var"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_bq_pre(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return(1); + print_text(h, "\\(lB"); + h->flags |= HTML_NOSPACE; + return(1); +} + + +/* ARGSUSED */ +static void +mdoc_bq_post(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return; + h->flags |= HTML_NOSPACE; + print_text(h, "\\(rB"); +} + + +/* ARGSUSED */ +static int +mdoc_ap_pre(MDOC_ARGS) +{ + + h->flags |= HTML_NOSPACE; + print_text(h, "\\(aq"); + h->flags |= HTML_NOSPACE; + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_bf_pre(MDOC_ARGS) +{ + int i; + struct htmlpair tag[2]; + struct roffsu su; + + if (MDOC_HEAD == n->type) + return(0); + else if (MDOC_BLOCK != n->type) + return(1); + + PAIR_CLASS_INIT(&tag[0], "lit"); + + if (n->head->child) { + if ( ! strcmp("Em", n->head->child->string)) + PAIR_CLASS_INIT(&tag[0], "emph"); + else if ( ! strcmp("Sy", n->head->child->string)) + PAIR_CLASS_INIT(&tag[0], "symb"); + else if ( ! strcmp("Li", n->head->child->string)) + PAIR_CLASS_INIT(&tag[0], "lit"); + } else { + assert(n->args); + for (i = 0; i < (int)n->args->argc; i++) + switch (n->args->argv[i].arg) { + case (MDOC_Symbolic): + PAIR_CLASS_INIT(&tag[0], "symb"); + break; + case (MDOC_Literal): + PAIR_CLASS_INIT(&tag[0], "lit"); + break; + case (MDOC_Emphasis): + PAIR_CLASS_INIT(&tag[0], "emph"); + break; + default: + break; + } + } + + /* FIXME: div's have spaces stripped--we want them. */ + + bufcat_style(h, "display", "inline"); + SCALE_HS_INIT(&su, 1); + bufcat_su(h, "margin-right", &su); + PAIR_STYLE_INIT(&tag[1], h); + print_otag(h, TAG_DIV, 2, tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_ms_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + PAIR_CLASS_INIT(&tag, "symb"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_pf_pre(MDOC_ARGS) +{ + + h->flags |= HTML_IGNDELIM; + return(1); +} + + +/* ARGSUSED */ +static void +mdoc_pf_post(MDOC_ARGS) +{ + + h->flags &= ~HTML_IGNDELIM; + h->flags |= HTML_NOSPACE; +} + + +/* ARGSUSED */ +static int +mdoc_rs_pre(MDOC_ARGS) +{ + struct htmlpair tag; + struct roffsu su; + + if (MDOC_BLOCK != n->type) + return(1); + + if (n->prev && SEC_SEE_ALSO == n->sec) { + SCALE_VS_INIT(&su, 1); + bufcat_su(h, "margin-top", &su); + PAIR_STYLE_INIT(&tag, h); + print_otag(h, TAG_DIV, 1, &tag); + } + + PAIR_CLASS_INIT(&tag, "ref"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + + +/* ARGSUSED */ +static int +mdoc_li_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + PAIR_CLASS_INIT(&tag, "lit"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_sy_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + PAIR_CLASS_INIT(&tag, "symb"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_bt_pre(MDOC_ARGS) +{ + + print_text(h, "is currently in beta test."); + return(0); +} + + +/* ARGSUSED */ +static int +mdoc_ud_pre(MDOC_ARGS) +{ + + print_text(h, "currently under development."); + return(0); +} + + +/* ARGSUSED */ +static int +mdoc_lb_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + if (SEC_SYNOPSIS == n->sec) + print_otag(h, TAG_DIV, 0, NULL); + PAIR_CLASS_INIT(&tag, "lib"); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc__x_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + switch (n->tok) { + case(MDOC__A): + PAIR_CLASS_INIT(&tag, "ref-auth"); + break; + case(MDOC__B): + PAIR_CLASS_INIT(&tag, "ref-book"); + break; + case(MDOC__C): + PAIR_CLASS_INIT(&tag, "ref-city"); + break; + case(MDOC__D): + PAIR_CLASS_INIT(&tag, "ref-date"); + break; + case(MDOC__I): + PAIR_CLASS_INIT(&tag, "ref-issue"); + break; + case(MDOC__J): + PAIR_CLASS_INIT(&tag, "ref-jrnl"); + break; + case(MDOC__N): + PAIR_CLASS_INIT(&tag, "ref-num"); + break; + case(MDOC__O): + PAIR_CLASS_INIT(&tag, "ref-opt"); + break; + case(MDOC__P): + PAIR_CLASS_INIT(&tag, "ref-page"); + break; + case(MDOC__Q): + PAIR_CLASS_INIT(&tag, "ref-corp"); + break; + case(MDOC__R): + PAIR_CLASS_INIT(&tag, "ref-rep"); + break; + case(MDOC__T): + PAIR_CLASS_INIT(&tag, "ref-title"); + print_text(h, "\\(lq"); + h->flags |= HTML_NOSPACE; + break; + case(MDOC__V): + PAIR_CLASS_INIT(&tag, "ref-vol"); + break; + default: + abort(); + /* NOTREACHED */ + } + + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static void +mdoc__x_post(MDOC_ARGS) +{ + + h->flags |= HTML_NOSPACE; + switch (n->tok) { + case (MDOC__T): + print_text(h, "\\(rq"); + h->flags |= HTML_NOSPACE; + break; + default: + break; + } + print_text(h, n->next ? "," : "."); +} diff --git a/usr.bin/mandoc/mdoc_term.c b/usr.bin/mandoc/mdoc_term.c index 1251c29fd05..8a3812b0a08 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.60 2009/10/19 21:35:43 schwarze Exp $ */ +/* $Id: mdoc_term.c,v 1.61 2009/10/21 19:13:50 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -23,43 +23,11 @@ #include <stdlib.h> #include <string.h> +#include "out.h" #include "term.h" #include "mdoc.h" - -/* FIXME: check HANG lists: they seem to be broken... : - * .Bl -hang -width Ds - * .It a - * b - * .It Fl f Ns Ar option... - * Override default compiler behaviour. See - * .Sx Compiler Options - * for details. - * Override default compiler behaviour. See - * .Sx Compiler Options - * for details. - * Override default compiler behaviour. See - * .Sx Compiler Options - * for details. - * Override default compiler behaviour. See - * .Sx Compiler Options - * for details. - * . - * .It a sasd fasd as afsd sfad sfds sadfs sd sfd ssfad asfd - * Override default compiler behaviour. See - * .Sx Compiler Options - * for details. - * Override default compiler behaviour. See - * .Sx Compiler Options - * for details. - * Override default compiler behaviour. See - * .Sx Compiler Options - * for details. - * Override default compiler behaviour. See - * .Sx Compiler Options - * for details. - * .El - * - */ +#include "chars.h" +#include "main.h" #define INDENT 5 #define HALFINDENT 3 @@ -270,14 +238,16 @@ static const struct termact termacts[MDOC_MAX] = { { termp_sp_pre, NULL }, /* sp */ }; +static size_t arg2width(const struct mdoc_argv *, int); +static size_t arg2height(const struct mdoc_node *); +static size_t arg2offs(const struct mdoc_argv *); + static int arg_hasattr(int, const struct mdoc_node *); static int arg_getattrs(const int *, int *, size_t, const struct mdoc_node *); static int arg_getattr(int, const struct mdoc_node *); -static size_t arg_offset(const struct mdoc_argv *); -static size_t arg_width(const struct mdoc_argv *, int); static int arg_listtype(const struct mdoc_node *); -static void fmt_block_vspace(struct termp *, +static void print_bvspace(struct termp *, const struct mdoc_node *, const struct mdoc_node *); static void print_node(DECL_ARGS); @@ -287,10 +257,23 @@ static void print_foot(DECL_ARGS); void -mdoc_run(struct termp *p, const struct mdoc *mdoc) +terminal_mdoc(void *arg, const struct mdoc *mdoc) { const struct mdoc_node *n; const struct mdoc_meta *m; + struct termp *p; + + p = (struct termp *)arg; + + if (NULL == p->symtab) + switch (p->enc) { + case (TERMENC_ASCII): + p->symtab = chars_init(CHARS_ASCII); + break; + default: + abort(); + /* NOTREACHED */ + } n = mdoc_node(mdoc); m = mdoc_meta(mdoc); @@ -485,34 +468,34 @@ print_head(DECL_ARGS) } -/* FIXME: put in utility file for front-ends. */ static size_t -arg_width(const struct mdoc_argv *arg, int pos) +arg2height(const struct mdoc_node *n) { - int i, len; - const char *p; + struct roffsu su; - assert(pos < (int)arg->sz && pos >= 0); - assert(arg->value[pos]); + assert(MDOC_TEXT == n->type); + assert(n->string); + if ( ! a2roffsu(n->string, &su, SCALE_VS)) + SCALE_VS_INIT(&su, strlen(n->string)); - p = arg->value[pos]; + return(term_vspan(&su)); +} - if (0 == (len = (int)strlen(p))) - return(0); - for (i = 0; i < len - 1; i++) - if ( ! isdigit((u_char)p[i])) - break; +static size_t +arg2width(const struct mdoc_argv *arg, int pos) +{ + struct roffsu su; - if (i == len - 1) - if ('n' == p[len - 1] || 'm' == p[len - 1]) - return((size_t)atoi(p) + 2); + assert(arg->value[pos]); + if ( ! a2roffsu(arg->value[pos], &su, SCALE_MAX)) + SCALE_HS_INIT(&su, strlen(arg->value[pos])); - return((size_t)len + 2); + /* XXX: pachemu? */ + return(term_hspan(&su) + 2); } -/* FIXME: put in utility file for front-ends. */ static int arg_listtype(const struct mdoc_node *n) { @@ -554,35 +537,23 @@ arg_listtype(const struct mdoc_node *n) } -/* FIXME: put in utility file for front-ends. */ static size_t -arg_offset(const struct mdoc_argv *arg) +arg2offs(const struct mdoc_argv *arg) { - int len, i; - const char *p; - - assert(*arg->value); - p = *arg->value; + struct roffsu su; - if (0 == strcmp(p, "left")) + if ('\0' == arg->value[0][0]) return(0); - if (0 == strcmp(p, "indent")) + else if (0 == strcmp(arg->value[0], "left")) + return(0); + else if (0 == strcmp(arg->value[0], "indent")) return(INDENT + 1); - if (0 == strcmp(p, "indent-two")) + else if (0 == strcmp(arg->value[0], "indent-two")) return((INDENT + 1) * 2); + else if ( ! a2roffsu(arg->value[0], &su, SCALE_MAX)) + SCALE_HS_INIT(&su, strlen(arg->value[0])); - if (0 == (len = (int)strlen(p))) - return(0); - - for (i = 0; i < len - 1; i++) - if ( ! isdigit((u_char)p[i])) - break; - - if (i == len - 1) - if ('n' == p[len - 1] || 'm' == p[len - 1]) - return((size_t)atoi(p)); - - return((size_t)len); + return(term_hspan(&su)); } @@ -622,9 +593,8 @@ arg_getattrs(const int *keys, int *vals, } -/* ARGSUSED */ static void -fmt_block_vspace(struct termp *p, +print_bvspace(struct termp *p, const struct mdoc_node *bl, const struct mdoc_node *n) { @@ -704,7 +674,7 @@ termp_it_pre(DECL_ARGS) size_t width, offset; if (MDOC_BLOCK == n->type) { - fmt_block_vspace(p, n->parent->parent, n); + print_bvspace(p, n->parent->parent, n); return(1); } @@ -747,23 +717,23 @@ termp_it_pre(DECL_ARGS) for (i = 0, nn = n->prev; nn && i < (int)bl->args->argv[vals[2]].sz; nn = nn->prev, i++) - offset += arg_width + offset += arg2width (&bl->args->argv[vals[2]], i); /* Whether exceeds maximum column. */ if (i < (int)bl->args->argv[vals[2]].sz) - width = arg_width(&bl->args->argv[vals[2]], i); + width = arg2width(&bl->args->argv[vals[2]], i); else width = 0; if (vals[1] >= 0) - offset += arg_offset(&bl->args->argv[vals[1]]); + offset += arg2offs(&bl->args->argv[vals[1]]); break; default: if (vals[0] >= 0) - width = arg_width(&bl->args->argv[vals[0]], 0); + width = arg2width(&bl->args->argv[vals[0]], 0); if (vals[1] >= 0) - offset += arg_offset(&bl->args->argv[vals[1]]); + offset += arg2offs(&bl->args->argv[vals[1]]); break; } @@ -1565,7 +1535,7 @@ termp_bd_pre(DECL_ARGS) const struct mdoc_node *nn; if (MDOC_BLOCK == n->type) { - fmt_block_vspace(p, n, n); + print_bvspace(p, n, n); return(1); } else if (MDOC_BODY != n->type) return(1); @@ -1574,6 +1544,8 @@ termp_bd_pre(DECL_ARGS) for (type = -1, i = 0; i < (int)nn->args->argc; i++) { switch (nn->args->argv[i].arg) { + case (MDOC_Centred): + /* FALLTHROUGH */ case (MDOC_Ragged): /* FALLTHROUGH */ case (MDOC_Filled): @@ -1584,7 +1556,7 @@ termp_bd_pre(DECL_ARGS) type = nn->args->argv[i].arg; break; case (MDOC_Offset): - p->offset += arg_offset(&nn->args->argv[i]); + p->offset += arg2offs(&nn->args->argv[i]); break; default: break; @@ -1835,11 +1807,11 @@ termp_in_post(DECL_ARGS) static int termp_sp_pre(DECL_ARGS) { - int i, len; + size_t i, len; switch (n->tok) { case (MDOC_sp): - len = n->child ? atoi(n->child->string) : 1; + len = n->child ? arg2height(n->child) : 1; break; case (MDOC_br): len = 0; diff --git a/usr.bin/mandoc/mdoc_validate.c b/usr.bin/mandoc/mdoc_validate.c index 6eb0a89b100..417dba3d672 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.36 2009/10/19 16:27:52 schwarze Exp $ */ +/* $Id: mdoc_validate.c,v 1.37 2009/10/21 19:13:51 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -70,6 +70,7 @@ static int eerr_eq0(POST_ARGS); static int eerr_eq1(POST_ARGS); static int eerr_ge1(POST_ARGS); static int eerr_le2(POST_ARGS); +static int eerr_le1(POST_ARGS); static int ewarn_ge1(POST_ARGS); static int herr_eq0(POST_ARGS); static int herr_ge1(POST_ARGS); @@ -89,7 +90,6 @@ 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_sp(POST_ARGS); static int post_st(POST_ARGS); static int pre_an(PRE_ARGS); static int pre_bd(PRE_ARGS); @@ -124,7 +124,7 @@ static v_post posts_notext[] = { eerr_eq0, NULL }; static v_post posts_pf[] = { eerr_eq1, 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[] = { post_sp, 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_text[] = { eerr_ge1, NULL }; @@ -191,7 +191,7 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, posts_text }, /* Vt */ { NULL, posts_xr }, /* Xr */ { NULL, posts_text }, /* %A */ - { NULL, posts_text }, /* %B */ + { NULL, posts_text }, /* %B */ /* FIXME: can be used outside Rs/Re. */ { NULL, posts_text }, /* %D */ { NULL, posts_text }, /* %I */ { NULL, posts_text }, /* %J */ @@ -199,7 +199,7 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, posts_text }, /* %O */ { NULL, posts_text }, /* %P */ { NULL, posts_text }, /* %R */ - { NULL, posts_text }, /* %T */ + { NULL, posts_text }, /* %T */ /* FIXME: can be used outside Rs/Re. */ { NULL, posts_text }, /* %V */ { NULL, NULL }, /* Ac */ { NULL, NULL }, /* Ao */ @@ -404,6 +404,7 @@ CHECK_BODY_DEFN(ge1, err, err_child_gt, 0) /* berr_ge1() */ CHECK_ELEM_DEFN(ge1, warn, warn_child_gt, 0) /* ewarn_gt1() */ CHECK_ELEM_DEFN(eq1, err, err_child_eq, 1) /* eerr_eq1() */ CHECK_ELEM_DEFN(le2, err, err_child_lt, 3) /* eerr_le2() */ +CHECK_ELEM_DEFN(le1, err, err_child_lt, 2) /* eerr_le1() */ CHECK_ELEM_DEFN(eq0, err, err_child_eq, 0) /* eerr_eq0() */ CHECK_ELEM_DEFN(ge1, err, err_child_gt, 0) /* eerr_ge1() */ CHECK_HEAD_DEFN(eq0, err, err_child_eq, 0) /* herr_eq0() */ @@ -617,25 +618,33 @@ pre_bl(PRE_ARGS) case (MDOC_Inset): /* FALLTHROUGH */ case (MDOC_Column): - if (-1 != type) + if (type >= 0) return(mdoc_nerr(mdoc, n, EMULTILIST)); type = n->args->argv[pos].arg; break; + case (MDOC_Compact): + if (type < 0 && ! mdoc_nwarn(mdoc, n, ENOTYPE)) + return(0); + break; case (MDOC_Width): - if (-1 != width) + if (width >= 0) return(mdoc_nerr(mdoc, n, EARGREP)); + if (type < 0 && ! mdoc_nwarn(mdoc, n, ENOTYPE)) + return(0); width = n->args->argv[pos].arg; break; case (MDOC_Offset): - if (-1 != offset) + if (offset >= 0) return(mdoc_nerr(mdoc, n, EARGREP)); + if (type < 0 && ! mdoc_nwarn(mdoc, n, ENOTYPE)) + return(0); offset = n->args->argv[pos].arg; break; default: break; } - if (-1 == type) + if (type < 0) return(mdoc_nerr(mdoc, n, ELISTTYPE)); /* @@ -646,7 +655,7 @@ pre_bl(PRE_ARGS) switch (type) { case (MDOC_Tag): - if (-1 == width && ! mdoc_nwarn(mdoc, n, EMISSWIDTH)) + if (width < 0 && ! mdoc_nwarn(mdoc, n, EMISSWIDTH)) return(0); break; case (MDOC_Column): @@ -656,7 +665,7 @@ pre_bl(PRE_ARGS) case (MDOC_Inset): /* FALLTHROUGH */ case (MDOC_Item): - if (-1 != width && ! mdoc_nwarn(mdoc, n, ENOWIDTH)) + if (width >= 0 && ! mdoc_nwarn(mdoc, n, ENOWIDTH)) return(0); break; default: @@ -690,8 +699,6 @@ pre_bd(PRE_ARGS) case (MDOC_Filled): /* FALLTHROUGH */ case (MDOC_Literal): - /* FALLTHROUGH */ - case (MDOC_File): if (0 == type++) break; return(mdoc_nerr(mdoc, n, EMULTIDISP)); @@ -1123,37 +1130,6 @@ post_root(POST_ARGS) static int -post_sp(POST_ARGS) -{ - long lval; - char *ep, *buf; - - if (NULL == mdoc->last->child) - return(1); - else if ( ! eerr_eq1(mdoc)) - return(0); - - assert(MDOC_TEXT == mdoc->last->child->type); - buf = mdoc->last->child->string; - assert(buf); - - /* From OpenBSD's strtol(3). */ - errno = 0; - lval = strtol(buf, &ep, 10); - if (buf[0] == '\0' || *ep != '\0') - return(mdoc_nerr(mdoc, mdoc->last->child, ENUMFMT)); - - if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) || - (lval > INT_MAX || lval < 0)) - return(mdoc_nerr(mdoc, mdoc->last->child, ENUMFMT)); - - return(1); -} - - - - -static int post_st(POST_ARGS) { diff --git a/usr.bin/mandoc/out.c b/usr.bin/mandoc/out.c new file mode 100644 index 00000000000..58455410c78 --- /dev/null +++ b/usr.bin/mandoc/out.c @@ -0,0 +1,119 @@ +/* $Id: out.c,v 1.1 2009/10/21 19:13:51 schwarze Exp $ */ +/* + * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> + * + * 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. + */ +#include <sys/types.h> + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> + +#include "out.h" + + +/* + * Convert a `scaling unit' to a consistent form, or fail. Scaling + * units are documented in groff.7, mdoc.7, man.7. + */ +int +a2roffsu(const char *src, struct roffsu *dst, enum roffscale def) +{ + char buf[BUFSIZ], hasd; + int i; + enum roffscale unit; + + if ('\0' == *src) + return(0); + + i = hasd = 0; + + switch (*src) { + case ('+'): + src++; + break; + case ('-'): + buf[i++] = *src++; + break; + default: + break; + } + + if ('\0' == *src) + return(0); + + while (i < BUFSIZ) { + if ( ! isdigit((u_char)*src)) { + if ('.' != *src) + break; + else if (hasd) + break; + else + hasd = 1; + } + buf[i++] = *src++; + } + + if (BUFSIZ == i || (*src && *(src + 1))) + return(0); + + buf[i] = '\0'; + + switch (*src) { + case ('c'): + unit = SCALE_CM; + break; + case ('i'): + unit = SCALE_IN; + break; + case ('P'): + unit = SCALE_PC; + break; + case ('p'): + unit = SCALE_PT; + break; + case ('f'): + unit = SCALE_FS; + break; + case ('v'): + unit = SCALE_VS; + break; + case ('m'): + unit = SCALE_EM; + break; + case ('\0'): + if (SCALE_MAX == def) + return(0); + unit = SCALE_BU; + break; + case ('u'): + unit = SCALE_BU; + break; + case ('M'): + unit = SCALE_MM; + break; + case ('n'): + unit = SCALE_EN; + break; + default: + return(0); + } + + if ((dst->scale = atof(buf)) < 0) + dst->scale = 0; + dst->unit = unit; + dst->pt = hasd; + + return(1); +} diff --git a/usr.bin/mandoc/out.h b/usr.bin/mandoc/out.h new file mode 100644 index 00000000000..672b9959fd6 --- /dev/null +++ b/usr.bin/mandoc/out.h @@ -0,0 +1,58 @@ +/* $Id: out.h,v 1.1 2009/10/21 19:13:51 schwarze Exp $ */ +/* + * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se> + * + * 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 OUT_H +#define OUT_H + +__BEGIN_DECLS + +enum roffscale { + SCALE_CM, + SCALE_IN, + SCALE_PC, + SCALE_PT, + SCALE_EM, + SCALE_MM, + SCALE_EN, + SCALE_BU, + SCALE_VS, + SCALE_FS, + SCALE_MAX +}; + +struct roffsu { + enum roffscale unit; + double scale; + int pt; +}; + +#define SCALE_INVERT(p) \ + do { (p)->scale = -(p)->scale; } while (/*CONSTCOND*/0) +#define SCALE_VS_INIT(p, v) \ + do { (p)->unit = SCALE_VS; \ + (p)->scale = (v); \ + (p)->pt = 0; } while (/*CONSTCOND*/0) +#define SCALE_HS_INIT(p, v) \ + do { (p)->unit = SCALE_BU; \ + (p)->scale = (v); \ + (p)->pt = 0; } while (/*CONSTCOND*/0) + +int a2roffsu(const char *, + struct roffsu *, enum roffscale); + +__END_DECLS + +#endif /*!HTML_H*/ diff --git a/usr.bin/mandoc/term.c b/usr.bin/mandoc/term.c index c61f3ac193b..ec03fe78027 100644 --- a/usr.bin/mandoc/term.c +++ b/usr.bin/mandoc/term.c @@ -1,4 +1,4 @@ -/* $Id: term.c,v 1.15 2009/10/19 09:16:58 schwarze Exp $ */ +/* $Id: term.c,v 1.16 2009/10/21 19:13:51 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -21,14 +21,14 @@ #include <string.h> #include "chars.h" +#include "out.h" #include "term.h" #include "man.h" #include "mdoc.h" +#include "main.h" -extern void man_run(struct termp *, - const struct man *); -extern void mdoc_run(struct termp *, - const struct mdoc *); +/* FIXME: accomodate non-breaking, non-collapsing white-space. */ +/* FIXME: accomodate non-breaking, collapsing white-space. */ static struct termp *term_alloc(enum termenc); static void term_free(struct termp *); @@ -51,32 +51,6 @@ ascii_alloc(void) void -terminal_man(void *arg, const struct man *man) -{ - struct termp *p; - - p = (struct termp *)arg; - if (NULL == p->symtab) - p->symtab = chars_init(CHARS_ASCII); - - man_run(p, man); -} - - -void -terminal_mdoc(void *arg, const struct mdoc *mdoc) -{ - struct termp *p; - - p = (struct termp *)arg; - if (NULL == p->symtab) - p->symtab = chars_init(CHARS_ASCII); - - mdoc_run(p, mdoc); -} - - -void terminal_free(void *arg) { @@ -156,7 +130,7 @@ void term_flushln(struct termp *p) { int i, j; - size_t vbl, vsz, vis, maxvis, mmax, bp; + size_t vbl, vsz, vis, maxvis, mmax, bp, os; static int overstep = 0; /* @@ -169,6 +143,9 @@ term_flushln(struct termp *p) assert(p->offset < p->rmargin); assert((int)(p->rmargin - p->offset) - overstep > 0); + /* Save the overstep. */ + os = (size_t)overstep; + maxvis = /* LINTED */ p->rmargin - p->offset - overstep; mmax = /* LINTED */ @@ -230,6 +207,9 @@ term_flushln(struct termp *p) putchar(' '); vis = 0; } + /* Remove the overstep width. */ + bp += os; + os = 0; } else { for (j = 0; j < (int)vbl; j++) putchar(' '); @@ -579,3 +559,80 @@ encode(struct termp *p, char c) } buffer(p, c); } + + +size_t +term_vspan(const struct roffsu *su) +{ + double r; + + switch (su->unit) { + case (SCALE_CM): + r = su->scale * 2; + break; + case (SCALE_IN): + r = su->scale * 6; + break; + case (SCALE_PC): + r = su->scale; + break; + case (SCALE_PT): + r = su->scale / 8; + break; + case (SCALE_MM): + r = su->scale / 1000; + break; + case (SCALE_VS): + r = su->scale; + break; + default: + r = su->scale - 1; + break; + } + + if (r < 0.0) + r = 0.0; + return(/* LINTED */(size_t) + r); +} + + +size_t +term_hspan(const struct roffsu *su) +{ + double r; + + /* XXX: CM, IN, and PT are approximations. */ + + switch (su->unit) { + case (SCALE_CM): + r = 4 * su->scale; + break; + case (SCALE_IN): + /* XXX: this is an approximation. */ + r = 10 * su->scale; + break; + case (SCALE_PC): + r = (10 * su->scale) / 6; + break; + case (SCALE_PT): + r = (10 * su->scale) / 72; + break; + case (SCALE_MM): + r = su->scale / 1000; /* FIXME: double-check. */ + break; + case (SCALE_VS): + r = su->scale * 2 - 1; /* FIXME: double-check. */ + break; + default: + r = su->scale; + break; + } + + if (r < 0.0) + r = 0.0; + return((size_t)/* LINTED */ + r); +} + + diff --git a/usr.bin/mandoc/term.h b/usr.bin/mandoc/term.h index 61e5a5a3876..594f99959df 100644 --- a/usr.bin/mandoc/term.h +++ b/usr.bin/mandoc/term.h @@ -1,4 +1,4 @@ -/* $Id: term.h,v 1.11 2009/10/19 09:16:58 schwarze Exp $ */ +/* $Id: term.h,v 1.12 2009/10/21 19:13:51 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -53,6 +53,9 @@ void term_vspace(struct termp *); void term_word(struct termp *, const char *); void term_flushln(struct termp *); +size_t term_hspan(const struct roffsu *); +size_t term_vspan(const struct roffsu *); + __END_DECLS #endif /*!TERM_H*/ diff --git a/usr.bin/mandoc/tree.c b/usr.bin/mandoc/tree.c index 70e9d64b763..b243df2a246 100644 --- a/usr.bin/mandoc/tree.c +++ b/usr.bin/mandoc/tree.c @@ -1,4 +1,4 @@ -/* $Id: tree.c,v 1.4 2009/09/21 20:57:57 schwarze Exp $ */ +/* $Id: tree.c,v 1.5 2009/10/21 19:13:51 schwarze Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se> * @@ -21,6 +21,7 @@ #include "mdoc.h" #include "man.h" +#include "main.h" static void print_mdoc(const struct mdoc_node *, int); static void print_man(const struct man_node *, int); |