From: Sascha Wildner
-
- ) context */
struct tagq tags; /* stack of open tags */
struct rofftbl tbl; /* current table */
+ struct tag *tblt; /* current open table scope */
void *symtab; /* character-escapes */
char *base_man; /* base for manpage href */
char *base_includes; /* base for include href */
@@ -136,6 +139,7 @@ struct tag *print_otag(struct html *, enum htmltag,
void print_tagq(struct html *, const struct tag *);
void print_stagq(struct html *, const struct tag *);
void print_text(struct html *, const char *);
+void print_tblclose(struct html *);
void print_tbl(struct html *, const struct tbl_span *);
void bufcat_su(struct html *, const char *,
diff --git a/contrib/mdocml/index.sgml b/contrib/mdocml/index.sgml
index 7abc9975f2..d4fd1edc62 100644
--- a/contrib/mdocml/index.sgml
+++ b/contrib/mdocml/index.sgml
@@ -39,10 +39,9 @@
- mdocml consists of the libmdoc, libman, and libroff validating compilers; and mandoc, which interfaces with the compiler libraries to format output for UNIX - terminals, XHTML, HTML, PostScript, and PDF. It is a mdocml consists of the libmandoc validating + compiler and mandoc, which interfaces with the compiler library to format + output for UNIX terminals, XHTML, HTML, PostScript, and PDF. It is a BSD.lv project.
@@ -59,9 +58,8 @@- mdocml is architecture- and system-neutral, written in plain-old C. The most - current version is @VERSION@, dated @VDATE@. A full - ChangeLog (txt) is written with each release. + mdocml is in plain-old ANSI C and should build and run on any UNIX system. + The most current version is @VERSION@, dated @VDATE@.
- Please use the mailing lists for bug-reports, patches, questions, etc. (these require - subscription). Beyond that, contact Kristaps at TODO for known issues + before posting. + Beyond that, contact Kristaps at kris...@bsd.lv.
@@ -332,6 +322,27 @@+ 04-04-2011: + version 1.11.1 +
++ The earlier libroff, libmdoc, and libman soup have been merged into + a single library, libmandoc, which manages all aspects of + parsing real manuals (from line-handling to tbl parsing). +
++ Beyond this structural change, initial eqn functionality is in + place. For the time being, this is limited to the recognition of equation blocks; + future version of mdocml will expand upon this framework. +
++ As usual, many general fixes and improvements have also occured. In particular, a great + deal of redundancy and superfluous code has been removed with the merging of the backend + libraries. +
+
07-01-2011:
@@ -348,7 +359,7 @@
still minimal, especially for -Thtml and -Txhtml, but manages to at least display data. This means that mandoc now has built-in support for two troff preprocessors via
- libroff: soelim and tbl.
+ libroff: soelim and tbl.
) don't print the newline. + */ + if (' ' == *n->string && MDOC_LINE & n->flags) + if ( ! (HTML_LITERAL & h->flags)) + print_otag(h, TAG_BR, 0, NULL); + if (MDOC_DELIMC & n->flags) + h->flags |= HTML_NOSPACE; print_text(h, n->string); + if (MDOC_DELIMO & n->flags) + h->flags |= HTML_NOSPACE; return; + case (MDOC_EQN): + PAIR_CLASS_INIT(&tag, "eqn"); + print_otag(h, TAG_SPAN, 1, &tag); + print_text(h, n->eqn->data); + break; case (MDOC_TBL): + /* + * This will take care of initialising all of the table + * state data for the first table, then tearing it down + * for the last one. + */ print_tbl(h, n->span); - break; + return; default: + /* + * Close out the current table, if it's open, and unset + * the "meta" table state. This will be reopened on the + * next table element. + */ + if (h->tblt) { + print_tblclose(h); + t = h->tags.head; + } + + assert(NULL == h->tblt); if (mdocs[n->tok].pre && ENDBODY_NOT == n->end) child = (*mdocs[n->tok].pre)(m, n, h); break; @@ -453,7 +489,7 @@ print_mdoc_node(MDOC_ARGS) case (MDOC_ROOT): mdoc_root_post(m, n, h); break; - case (MDOC_TBL): + case (MDOC_EQN): break; default: if (mdocs[n->tok].post && ENDBODY_NOT == n->end) @@ -468,9 +504,6 @@ mdoc_root_post(MDOC_ARGS) { struct htmlpair tag[3]; struct tag *t, *tt; - char b[DATESIZ]; - - time2a(m->date, b, DATESIZ); PAIR_SUMMARY_INIT(&tag[0], "Document Footer"); PAIR_CLASS_INIT(&tag[1], "foot"); @@ -490,7 +523,7 @@ mdoc_root_post(MDOC_ARGS) PAIR_CLASS_INIT(&tag[0], "foot-date"); print_otag(h, TAG_TD, 1, tag); - print_text(h, b); + print_text(h, m->date); print_stagq(h, tt); PAIR_CLASS_INIT(&tag[0], "foot-os"); @@ -718,8 +751,7 @@ mdoc_nm_pre(MDOC_ARGS) static int mdoc_xr_pre(MDOC_ARGS) { - struct htmlpair tag[2]; - const struct mdoc_node *nn; + struct htmlpair tag[2]; if (NULL == n->child) return(0); @@ -735,16 +767,16 @@ mdoc_xr_pre(MDOC_ARGS) } else print_otag(h, TAG_A, 1, tag); - nn = n->child; - print_text(h, nn->string); + n = n->child; + print_text(h, n->string); - if (NULL == (nn = nn->next)) + if (NULL == (n = n->next)) return(0); h->flags |= HTML_NOSPACE; print_text(h, "("); h->flags |= HTML_NOSPACE; - print_text(h, nn->string); + print_text(h, n->string); h->flags |= HTML_NOSPACE; print_text(h, ")"); return(0); @@ -756,7 +788,8 @@ static int mdoc_ns_pre(MDOC_ARGS) { - h->flags |= HTML_NOSPACE; + if ( ! (MDOC_LINE & n->flags)) + h->flags |= HTML_NOSPACE; return(1); } @@ -779,6 +812,7 @@ mdoc_xx_pre(MDOC_ARGS) { const char *pp; struct htmlpair tag; + int flags; switch (n->tok) { case (MDOC_Bsx): @@ -805,8 +839,15 @@ mdoc_xx_pre(MDOC_ARGS) PAIR_CLASS_INIT(&tag, "unix"); print_otag(h, TAG_SPAN, 1, &tag); + print_text(h, pp); - return(1); + if (n->child) { + flags = h->flags; + h->flags |= HTML_KEEP; + print_text(h, n->child->string); + h->flags = flags; + } + return(0); } @@ -814,19 +855,27 @@ mdoc_xx_pre(MDOC_ARGS) static int mdoc_bx_pre(MDOC_ARGS) { - const struct mdoc_node *nn; - struct htmlpair tag; + 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 (NULL != (n = n->child)) { + print_text(h, n->string); + h->flags |= HTML_NOSPACE; + print_text(h, "BSD"); + } else { + print_text(h, "BSD"); + return(0); + } - if (n->child) + if (NULL != (n = n->next)) { + h->flags |= HTML_NOSPACE; + print_text(h, "-"); h->flags |= HTML_NOSPACE; + print_text(h, n->string); + } - print_text(h, "BSD"); return(0); } @@ -1037,9 +1086,9 @@ mdoc_bl_pre(MDOC_ARGS) static int mdoc_ex_pre(MDOC_ARGS) { - const struct mdoc_node *nn; - struct tag *t; - struct htmlpair tag; + struct tag *t; + struct htmlpair tag; + int nchild; if (n->prev) print_otag(h, TAG_BR, 0, NULL); @@ -1047,22 +1096,25 @@ mdoc_ex_pre(MDOC_ARGS) PAIR_CLASS_INIT(&tag, "utility"); print_text(h, "The"); - for (nn = n->child; nn; nn = nn->next) { + + nchild = n->nchild; + for (n = n->child; n; n = n->next) { + assert(MDOC_TEXT == n->type); + t = print_otag(h, TAG_B, 1, &tag); - print_text(h, nn->string); + print_text(h, n->string); print_tagq(h, t); - h->flags |= HTML_NOSPACE; - - if (nn->next && NULL == nn->next->next) - print_text(h, ", and"); - else if (nn->next) + if (nchild > 2 && n->next) { + h->flags |= HTML_NOSPACE; print_text(h, ","); - else - h->flags &= ~HTML_NOSPACE; + } + + if (n->next && NULL == n->next->next) + print_text(h, "and"); } - if (n->child && n->child->next) + if (nchild > 1) print_text(h, "utilities exit"); else print_text(h, "utility exits"); @@ -1118,14 +1170,13 @@ mdoc_d1_pre(MDOC_ARGS) static int mdoc_sx_pre(MDOC_ARGS) { - struct htmlpair tag[2]; - const struct mdoc_node *nn; - char buf[BUFSIZ]; + struct htmlpair tag[2]; + char buf[BUFSIZ]; strlcpy(buf, "#", BUFSIZ); - for (nn = n->child; nn; nn = nn->next) { - html_idcat(buf, nn->string, BUFSIZ); - if (nn->next) + for (n = n->child; n; n = n->next) { + html_idcat(buf, n->string, BUFSIZ); + if (n->next) html_idcat(buf, " ", BUFSIZ); } @@ -1143,7 +1194,7 @@ static int mdoc_bd_pre(MDOC_ARGS) { struct htmlpair tag[2]; - int comp; + int comp, sv; const struct mdoc_node *nn; struct roffsu su; @@ -1182,6 +1233,11 @@ mdoc_bd_pre(MDOC_ARGS) PAIR_CLASS_INIT(&tag[1], "lit display"); print_otag(h, TAG_PRE, 2, tag); + /* This can be recursive: save & set our literal state. */ + + sv = h->flags & HTML_LITERAL; + h->flags |= HTML_LITERAL; + for (nn = n->child; nn; nn = nn->next) { print_mdoc_node(m, nn, h); /* @@ -1218,6 +1274,9 @@ mdoc_bd_pre(MDOC_ARGS) h->flags |= HTML_NOSPACE; } + if (0 == sv) + h->flags &= ~HTML_LITERAL; + return(0); } @@ -1327,12 +1386,16 @@ mdoc_fa_pre(MDOC_ARGS) t = print_otag(h, TAG_I, 1, &tag); print_text(h, nn->string); print_tagq(h, t); - if (nn->next) + if (nn->next) { + h->flags |= HTML_NOSPACE; print_text(h, ","); + } } - if (n->child && n->next && n->next->tok == MDOC_Fa) + if (n->child && n->next && n->next->tok == MDOC_Fa) { + h->flags |= HTML_NOSPACE; print_text(h, ","); + } return(0); } @@ -1342,13 +1405,61 @@ mdoc_fa_pre(MDOC_ARGS) static int mdoc_fd_pre(MDOC_ARGS) { - struct htmlpair tag; + struct htmlpair tag[2]; + char buf[BUFSIZ]; + size_t sz; + int i; + struct tag *t; synopsis_pre(h, n); - PAIR_CLASS_INIT(&tag, "macro"); - print_otag(h, TAG_B, 1, &tag); - return(1); + if (NULL == (n = n->child)) + return(0); + + assert(MDOC_TEXT == n->type); + + if (strcmp(n->string, "#include")) { + PAIR_CLASS_INIT(&tag[0], "macro"); + print_otag(h, TAG_B, 1, tag); + return(1); + } + + PAIR_CLASS_INIT(&tag[0], "includes"); + print_otag(h, TAG_B, 1, tag); + print_text(h, n->string); + + if (NULL != (n = n->next)) { + assert(MDOC_TEXT == n->type); + strlcpy(buf, '<' == *n->string || '"' == *n->string ? + n->string + 1 : n->string, BUFSIZ); + + sz = strlen(buf); + if (sz && ('>' == buf[sz - 1] || '"' == buf[sz - 1])) + buf[sz - 1] = '\0'; + + PAIR_CLASS_INIT(&tag[0], "link-includes"); + bufinit(h); + + i = 1; + if (h->base_includes) { + buffmt_includes(h, buf); + PAIR_HREF_INIT(&tag[i], h->buf); + i++; + } + + t = print_otag(h, TAG_A, i, tag); + print_text(h, n->string); + print_tagq(h, t); + + n = n->next; + } + + for ( ; n; n = n->next) { + assert(MDOC_TEXT == n->type); + print_text(h, n->string); + } + + return(0); } @@ -1389,13 +1500,13 @@ mdoc_ft_pre(MDOC_ARGS) 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 tag *t; + struct htmlpair tag[2]; + char nbuf[BUFSIZ]; + const char *sp, *ep; + int sz, i, pretty; + pretty = MDOC_SYNPRETTY & n->flags; synopsis_pre(h, n); /* Split apart into type and name. */ @@ -1453,20 +1564,26 @@ mdoc_fn_pre(MDOC_ARGS) bufcat_style(h, "white-space", "nowrap"); PAIR_STYLE_INIT(&tag[1], h); - for (nn = n->child->next; nn; nn = nn->next) { + for (n = n->child->next; n; n = n->next) { i = 1; if (MDOC_SYNPRETTY & n->flags) i = 2; t = print_otag(h, TAG_I, i, tag); - print_text(h, nn->string); + print_text(h, n->string); print_tagq(h, t); - if (nn->next) + if (n->next) { + h->flags |= HTML_NOSPACE; print_text(h, ","); + } } + h->flags |= HTML_NOSPACE; print_text(h, ")"); - if (MDOC_SYNPRETTY & n->flags) + + if (pretty) { + h->flags |= HTML_NOSPACE; print_text(h, ";"); + } return(0); } @@ -1537,20 +1654,22 @@ mdoc_sp_pre(MDOC_ARGS) static int mdoc_lk_pre(MDOC_ARGS) { - const struct mdoc_node *nn; - struct htmlpair tag[2]; + struct htmlpair tag[2]; - nn = n->child; + if (NULL == (n = n->child)) + return(0); + + assert(MDOC_TEXT == n->type); PAIR_CLASS_INIT(&tag[0], "link-ext"); - PAIR_HREF_INIT(&tag[1], nn->string); - print_otag(h, TAG_A, 2, tag); + PAIR_HREF_INIT(&tag[1], n->string); - if (NULL == nn || NULL == nn->next) - return(1); + print_otag(h, TAG_A, 2, tag); - for (nn = nn->next; nn; nn = nn->next) - print_text(h, nn->string); + for (n = n->next; n; n = n->next) { + assert(MDOC_TEXT == n->type); + print_text(h, n->string); + } return(0); } @@ -1560,19 +1679,21 @@ mdoc_lk_pre(MDOC_ARGS) static int mdoc_mt_pre(MDOC_ARGS) { - struct htmlpair tag[2]; - struct tag *t; - const struct mdoc_node *nn; + struct htmlpair tag[2]; + struct tag *t; PAIR_CLASS_INIT(&tag[0], "link-mail"); - for (nn = n->child; nn; nn = nn->next) { + for (n = n->child; n; n = n->next) { + assert(MDOC_TEXT == n->type); + bufinit(h); bufcat(h, "mailto:"); - bufcat(h, nn->string); + bufcat(h, n->string); + PAIR_HREF_INIT(&tag[1], h->buf); t = print_otag(h, TAG_A, 2, tag); - print_text(h, nn->string); + print_text(h, n->string); print_tagq(h, t); } @@ -1617,7 +1738,9 @@ 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, ";"); } @@ -1626,39 +1749,57 @@ mdoc_fo_post(MDOC_ARGS) static int mdoc_in_pre(MDOC_ARGS) { - const struct mdoc_node *nn; - struct tag *t; - struct htmlpair tag[2]; - int i; + struct tag *t; + struct htmlpair tag[2]; + int i; synopsis_pre(h, n); PAIR_CLASS_INIT(&tag[0], "includes"); print_otag(h, TAG_B, 1, tag); + /* + * The first argument of the `In' gets special treatment as + * being a linked value. Subsequent values are printed + * afterward. groff does similarly. This also handles the case + * of no children. + */ + if (MDOC_SYNPRETTY & n->flags && MDOC_LINE & n->flags) print_text(h, "#include"); print_text(h, "<"); h->flags |= HTML_NOSPACE; - for (nn = n->child; nn; nn = nn->next) { + if (NULL != (n = n->child)) { + assert(MDOC_TEXT == n->type); + PAIR_CLASS_INIT(&tag[0], "link-includes"); - i = 1; bufinit(h); + + i = 1; + if (h->base_includes) { - buffmt_includes(h, nn->string); + buffmt_includes(h, n->string); PAIR_HREF_INIT(&tag[i], h->buf); i++; - } + } + t = print_otag(h, TAG_A, i, tag); - print_mdoc_node(m, nn, h); + print_text(h, n->string); print_tagq(h, t); + + n = n->next; } h->flags |= HTML_NOSPACE; print_text(h, ">"); + for ( ; n; n = n->next) { + assert(MDOC_TEXT == n->type); + print_text(h, n->string); + } + return(0); } @@ -1679,31 +1820,38 @@ mdoc_ic_pre(MDOC_ARGS) static int mdoc_rv_pre(MDOC_ARGS) { - const struct mdoc_node *nn; - struct htmlpair tag; - struct tag *t; + struct htmlpair tag; + struct tag *t; + int nchild; if (n->prev) print_otag(h, TAG_BR, 0, NULL); + PAIR_CLASS_INIT(&tag, "fname"); + print_text(h, "The"); - for (nn = n->child; nn; nn = nn->next) { - PAIR_CLASS_INIT(&tag, "fname"); + nchild = n->nchild; + for (n = n->child; n; n = n->next) { + assert(MDOC_TEXT == n->type); + t = print_otag(h, TAG_B, 1, &tag); - print_text(h, nn->string); + print_text(h, n->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, "()"); + print_text(h, "()"); + + if (nchild > 2 && n->next) { + h->flags |= HTML_NOSPACE; + print_text(h, ","); + } + + if (n->next && NULL == n->next->next) + print_text(h, "and"); } - if (n->child && n->child->next) + if (nchild > 1) print_text(h, "functions return"); else print_text(h, "function returns"); @@ -1978,6 +2126,7 @@ mdoc__x_post(MDOC_ARGS) if (NULL == n->parent || MDOC_Rs != n->parent->tok) return; + h->flags |= HTML_NOSPACE; print_text(h, n->next ? "," : "."); } diff --git a/contrib/mdocml/mdoc_macro.c b/contrib/mdocml/mdoc_macro.c index 1c97f88c95..b334b4e402 100644 --- a/contrib/mdocml/mdoc_macro.c +++ b/contrib/mdocml/mdoc_macro.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_macro.c,v 1.99 2010/12/15 23:39:40 kristaps Exp $ */ +/* $Id: mdoc_macro.c,v 1.106 2011/03/22 14:33:05 kristaps Exp $ */ /* * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons* Copyright (c) 2010 Ingo Schwarze @@ -26,6 +26,7 @@ #include #include +#include "mdoc.h" #include "mandoc.h" #include "libmdoc.h" #include "libmandoc.h" @@ -50,6 +51,8 @@ static int in_line(MACRO_PROT_ARGS); static int obsolete(MACRO_PROT_ARGS); static int phrase_ta(MACRO_PROT_ARGS); +static int dword(struct mdoc *, int, int, + const char *, enum mdelim); static int append_delims(struct mdoc *, int, int *, char *); static enum mdoct lookup(enum mdoct, const char *); @@ -252,17 +255,24 @@ lookup_raw(const char *p) static int rew_last(struct mdoc *mdoc, const struct mdoc_node *to) { - struct mdoc_node *n; + struct mdoc_node *n, *np; assert(to); mdoc->next = MDOC_NEXT_SIBLING; /* LINTED */ while (mdoc->last != to) { + /* + * Save the parent here, because we may delete the + * m->last node in the post-validation phase and reset + * it to m->last->parent, causing a step in the closing + * out to be lost. + */ + np = mdoc->last->parent; if ( ! mdoc_valid_post(mdoc)) return(0); n = mdoc->last; - mdoc->last = mdoc->last->parent; + mdoc->last = np; assert(mdoc->last); mdoc->last->last = n; } @@ -506,9 +516,9 @@ make_pending(struct mdoc_node *broken, enum mdoct tok, taker->pending = broken->pending; } broken->pending = breaker; - mdoc_vmsg(m, MANDOCERR_SCOPENEST, line, ppos, - "%s breaks %s", mdoc_macronames[tok], - mdoc_macronames[broken->tok]); + mandoc_vmsg(MANDOCERR_SCOPENEST, m->parse, line, ppos, + "%s breaks %s", mdoc_macronames[tok], + mdoc_macronames[broken->tok]); return(1); } @@ -534,9 +544,10 @@ rew_sub(enum mdoc_type t, struct mdoc *m, case (REWIND_THIS): break; case (REWIND_FORCE): - mdoc_vmsg(m, MANDOCERR_SCOPEBROKEN, line, ppos, - "%s breaks %s", mdoc_macronames[tok], - mdoc_macronames[n->tok]); + mandoc_vmsg(MANDOCERR_SCOPEBROKEN, m->parse, + line, ppos, "%s breaks %s", + mdoc_macronames[tok], + mdoc_macronames[n->tok]); /* FALLTHROUGH */ case (REWIND_MORE): n = n->parent; @@ -572,6 +583,28 @@ rew_sub(enum mdoc_type t, struct mdoc *m, return(1); } +/* + * Allocate a word and check whether it's punctuation or not. + * Punctuation consists of those tokens found in mdoc_isdelim(). + */ +static int +dword(struct mdoc *m, int line, + int col, const char *p, enum mdelim d) +{ + + if (DELIM_MAX == d) + d = mdoc_isdelim(p); + + if ( ! mdoc_word_alloc(m, line, col, p)) + return(0); + + if (DELIM_OPEN == d) + m->last->flags |= MDOC_DELIMO; + else if (DELIM_CLOSE == d) + m->last->flags |= MDOC_DELIMC; + + return(1); +} static int append_delims(struct mdoc *m, int line, int *pos, char *buf) @@ -592,9 +625,7 @@ append_delims(struct mdoc *m, int line, int *pos, char *buf) else if (ARGS_EOLN == ac) break; - assert(DELIM_NONE != mdoc_isdelim(p)); - if ( ! mdoc_word_alloc(m, line, la, p)) - return(0); + dword(m, line, la, p, DELIM_MAX); /* * If we encounter end-of-sentence symbols, then trigger @@ -703,8 +734,7 @@ blk_exp_close(MACRO_PROT_ARGS) if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) { /* FIXME: do this in validate */ if (buf[*pos]) - if ( ! mdoc_pmsg(m, line, ppos, MANDOCERR_ARGSLOST)) - return(0); + mdoc_pmsg(m, line, ppos, MANDOCERR_ARGSLOST); if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) return(0); @@ -739,7 +769,7 @@ blk_exp_close(MACRO_PROT_ARGS) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); if (MDOC_MAX == ntok) { - if ( ! mdoc_word_alloc(m, line, lastarg, p)) + if ( ! dword(m, line, lastarg, p, DELIM_MAX)) return(0); continue; } @@ -847,9 +877,9 @@ in_line(MACRO_PROT_ARGS) return(0); } else if ( ! nc && 0 == cnt) { mdoc_argv_free(arg); - if ( ! mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY)) - return(0); + mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY); } + if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) return(0); if ( ! nl) @@ -898,7 +928,8 @@ in_line(MACRO_PROT_ARGS) if (DELIM_NONE == d) cnt++; - if ( ! mdoc_word_alloc(m, line, la, p)) + + if ( ! dword(m, line, la, p, d)) return(0); /* @@ -929,8 +960,7 @@ in_line(MACRO_PROT_ARGS) return(0); } else if ( ! nc && 0 == cnt) { mdoc_argv_free(arg); - if ( ! mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY)) - return(0); + mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY); } if ( ! nl) @@ -1055,7 +1085,7 @@ blk_full(MACRO_PROT_ARGS) ARGS_PPHRASE != ac && ARGS_QWORD != ac && DELIM_OPEN == mdoc_isdelim(p)) { - if ( ! mdoc_word_alloc(m, line, la, p)) + if ( ! dword(m, line, la, p, DELIM_OPEN)) return(0); continue; } @@ -1107,7 +1137,7 @@ blk_full(MACRO_PROT_ARGS) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); if (MDOC_MAX == ntok) { - if ( ! mdoc_word_alloc(m, line, la, p)) + if ( ! dword(m, line, la, p, DELIM_MAX)) return(0); continue; } @@ -1217,8 +1247,8 @@ blk_part_imp(MACRO_PROT_ARGS) break; if (NULL == body && ARGS_QWORD != ac && - DELIM_OPEN == mdoc_isdelim(p)) { - if ( ! mdoc_word_alloc(m, line, la, p)) + DELIM_OPEN == mdoc_isdelim(p)) { + if ( ! dword(m, line, la, p, DELIM_OPEN)) return(0); continue; } @@ -1232,7 +1262,7 @@ blk_part_imp(MACRO_PROT_ARGS) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); if (MDOC_MAX == ntok) { - if ( ! mdoc_word_alloc(m, line, la, p)) + if ( ! dword(m, line, la, p, DELIM_MAX)) return(0); continue; } @@ -1292,9 +1322,9 @@ blk_part_imp(MACRO_PROT_ARGS) * is ugly behaviour nodding its head to OpenBSD's overwhelming * crufty use of `Op' breakage. */ - if (n != body && ! mdoc_vmsg(m, MANDOCERR_SCOPENEST, - line, ppos, "%s broken", mdoc_macronames[tok])) - return(0); + if (n != body) + mandoc_vmsg(MANDOCERR_SCOPENEST, m->parse, line, ppos, + "%s broken", mdoc_macronames[tok]); if (n && ! rew_sub(MDOC_BODY, m, tok, line, ppos)) return(0); @@ -1348,9 +1378,9 @@ blk_part_exp(MACRO_PROT_ARGS) /* Flush out leading punctuation. */ if (NULL == head && ARGS_QWORD != ac && - DELIM_OPEN == mdoc_isdelim(p)) { + DELIM_OPEN == mdoc_isdelim(p)) { assert(NULL == body); - if ( ! mdoc_word_alloc(m, line, la, p)) + if ( ! dword(m, line, la, p, DELIM_OPEN)) return(0); continue; } @@ -1371,7 +1401,7 @@ blk_part_exp(MACRO_PROT_ARGS) assert(head); /* No check whether it's a macro! */ if (MDOC_Eo == tok) - if ( ! mdoc_word_alloc(m, line, la, p)) + if ( ! dword(m, line, la, p, DELIM_MAX)) return(0); if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) @@ -1389,7 +1419,7 @@ blk_part_exp(MACRO_PROT_ARGS) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); if (MDOC_MAX == ntok) { - if ( ! mdoc_word_alloc(m, line, la, p)) + if ( ! dword(m, line, la, p, DELIM_MAX)) return(0); continue; } @@ -1454,6 +1484,8 @@ in_line_argn(MACRO_PROT_ARGS) case (MDOC_Ux): maxargs = 0; break; + case (MDOC_Bx): + /* FALLTHROUGH */ case (MDOC_Xr): maxargs = 2; break; @@ -1492,9 +1524,9 @@ in_line_argn(MACRO_PROT_ARGS) break; if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) && - ARGS_QWORD != ac && - 0 == j && DELIM_OPEN == mdoc_isdelim(p)) { - if ( ! mdoc_word_alloc(m, line, la, p)) + ARGS_QWORD != ac && 0 == j && + DELIM_OPEN == mdoc_isdelim(p)) { + if ( ! dword(m, line, la, p, DELIM_OPEN)) return(0); continue; } else if (0 == j) @@ -1544,7 +1576,7 @@ in_line_argn(MACRO_PROT_ARGS) } #endif - if ( ! mdoc_word_alloc(m, line, la, p)) + if ( ! dword(m, line, la, p, DELIM_MAX)) return(0); j++; } @@ -1615,7 +1647,7 @@ in_line_eoln(MACRO_PROT_ARGS) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); if (MDOC_MAX == ntok) { - if ( ! mdoc_word_alloc(m, line, la, p)) + if ( ! dword(m, line, la, p, DELIM_MAX)) return(0); continue; } @@ -1664,7 +1696,8 @@ static int obsolete(MACRO_PROT_ARGS) { - return(mdoc_pmsg(m, line, ppos, MANDOCERR_MACROOBS)); + mdoc_pmsg(m, line, ppos, MANDOCERR_MACROOBS); + return(1); } @@ -1694,7 +1727,7 @@ phrase(struct mdoc *m, int line, int ppos, char *buf) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p); if (MDOC_MAX == ntok) { - if ( ! mdoc_word_alloc(m, line, la, p)) + if ( ! dword(m, line, la, p, DELIM_MAX)) return(0); continue; } @@ -1739,7 +1772,7 @@ phrase_ta(MACRO_PROT_ARGS) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p); if (MDOC_MAX == ntok) { - if ( ! mdoc_word_alloc(m, line, la, p)) + if ( ! dword(m, line, la, p, DELIM_MAX)) return(0); continue; } diff --git a/contrib/mdocml/mdoc_strings.c b/contrib/mdocml/mdoc_strings.c deleted file mode 100644 index e7ced1fe1b..0000000000 --- a/contrib/mdocml/mdoc_strings.c +++ /dev/null @@ -1,219 +0,0 @@ -/* $Id: mdoc_strings.c,v 1.24 2010/07/31 23:52:58 schwarze Exp $ */ -/* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons - * - * 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. - */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include -#include -#include -#include -#include - -#include "mandoc.h" -#include "libmdoc.h" - -static const char * const secnames[SEC__MAX] = { - NULL, - "NAME", - "LIBRARY", - "SYNOPSIS", - "DESCRIPTION", - "IMPLEMENTATION NOTES", - "RETURN VALUES", - "ENVIRONMENT", - "FILES", - "EXIT STATUS", - "EXAMPLES", - "DIAGNOSTICS", - "COMPATIBILITY", - "ERRORS", - "SEE ALSO", - "STANDARDS", - "HISTORY", - "AUTHORS", - "CAVEATS", - "BUGS", - "SECURITY CONSIDERATIONS", - NULL -}; - -/* - * FIXME: this is repeated in print_text() (html.c) and term_word() - * (term.c). - */ -enum mdelim -mdoc_iscdelim(char p) -{ - - switch (p) { - case('('): - /* FALLTHROUGH */ - case('['): - return(DELIM_OPEN); - case('|'): - return(DELIM_MIDDLE); - case('.'): - /* FALLTHROUGH */ - case(','): - /* FALLTHROUGH */ - case(';'): - /* FALLTHROUGH */ - case(':'): - /* FALLTHROUGH */ - case('?'): - /* FALLTHROUGH */ - case('!'): - /* FALLTHROUGH */ - case(')'): - /* FALLTHROUGH */ - case(']'): - return(DELIM_CLOSE); - default: - break; - } - - return(DELIM_NONE); -} - - -enum mdelim -mdoc_isdelim(const char *p) -{ - - if ('\0' == p[0]) - return(DELIM_NONE); - if ('\0' == p[1]) - return(mdoc_iscdelim(p[0])); - - /* - * XXX; account for groff bubu where the \*(Ba reserved string - * is treated in exactly the same way as the vertical bar. This - * is the only function that checks for this. - */ - return(strcmp(p, "\\*(Ba") ? DELIM_NONE : DELIM_MIDDLE); -} - - -enum mdoc_sec -mdoc_str2sec(const char *p) -{ - int i; - - for (i = 0; i < (int)SEC__MAX; i++) - if (secnames[i] && 0 == strcmp(p, secnames[i])) - return((enum mdoc_sec)i); - - return(SEC_CUSTOM); -} - - -/* FIXME: move this into an editable .in file. */ -size_t -mdoc_macro2len(enum mdoct macro) -{ - - switch (macro) { - case(MDOC_Ad): - return(12); - case(MDOC_Ao): - return(12); - case(MDOC_An): - return(12); - case(MDOC_Aq): - return(12); - case(MDOC_Ar): - return(12); - case(MDOC_Bo): - return(12); - case(MDOC_Bq): - return(12); - case(MDOC_Cd): - return(12); - case(MDOC_Cm): - return(10); - case(MDOC_Do): - return(10); - case(MDOC_Dq): - return(12); - case(MDOC_Dv): - return(12); - case(MDOC_Eo): - return(12); - case(MDOC_Em): - return(10); - case(MDOC_Er): - return(17); - case(MDOC_Ev): - return(15); - case(MDOC_Fa): - return(12); - case(MDOC_Fl): - return(10); - case(MDOC_Fo): - return(16); - case(MDOC_Fn): - return(16); - case(MDOC_Ic): - return(10); - case(MDOC_Li): - return(16); - case(MDOC_Ms): - return(6); - case(MDOC_Nm): - return(10); - case(MDOC_No): - return(12); - case(MDOC_Oo): - return(10); - case(MDOC_Op): - return(14); - case(MDOC_Pa): - return(32); - case(MDOC_Pf): - return(12); - case(MDOC_Po): - return(12); - case(MDOC_Pq): - return(12); - case(MDOC_Ql): - return(16); - case(MDOC_Qo): - return(12); - case(MDOC_So): - return(12); - case(MDOC_Sq): - return(12); - case(MDOC_Sy): - return(6); - case(MDOC_Sx): - return(16); - case(MDOC_Tn): - return(10); - case(MDOC_Va): - return(12); - case(MDOC_Vt): - return(12); - case(MDOC_Xr): - return(10); - default: - break; - }; - return(0); -} diff --git a/contrib/mdocml/mdoc_term.c b/contrib/mdocml/mdoc_term.c index 0f699abd83..47c212489d 100644 --- a/contrib/mdocml/mdoc_term.c +++ b/contrib/mdocml/mdoc_term.c @@ -1,6 +1,6 @@ -/* $Id: mdoc_term.c,v 1.208 2011/01/06 14:05:12 kristaps Exp $ */ +/* $Id: mdoc_term.c,v 1.226 2011/04/04 16:27:03 kristaps Exp $ */ /* - * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2010 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any @@ -32,7 +32,6 @@ #include "out.h" #include "term.h" #include "mdoc.h" -#include "chars.h" #include "main.h" #define INDENT 5 @@ -73,7 +72,6 @@ static void termp_an_post(DECL_ARGS); static void termp_bd_post(DECL_ARGS); static void termp_bk_post(DECL_ARGS); static void termp_bl_post(DECL_ARGS); -static void termp_bx_post(DECL_ARGS); static void termp_d1_post(DECL_ARGS); static void termp_fo_post(DECL_ARGS); static void termp_in_post(DECL_ARGS); @@ -95,6 +93,7 @@ static int termp_bk_pre(DECL_ARGS); static int termp_bl_pre(DECL_ARGS); static int termp_bold_pre(DECL_ARGS); static int termp_bt_pre(DECL_ARGS); +static int termp_bx_pre(DECL_ARGS); static int termp_cd_pre(DECL_ARGS); static int termp_d1_pre(DECL_ARGS); static int termp_ex_pre(DECL_ARGS); @@ -187,7 +186,7 @@ static const struct termact termacts[MDOC_MAX] = { { termp_quote_pre, termp_quote_post }, /* Bo */ { termp_quote_pre, termp_quote_post }, /* Bq */ { termp_xx_pre, NULL }, /* Bsx */ - { NULL, termp_bx_post }, /* Bx */ + { termp_bx_pre, NULL }, /* Bx */ { NULL, NULL }, /* Db */ { NULL, NULL }, /* Dc */ { termp_quote_pre, termp_quote_post }, /* Do */ @@ -312,20 +311,6 @@ print_mdoc_node(DECL_ARGS) memset(&npair, 0, sizeof(struct termpair)); npair.ppair = pair; - - switch (n->type) { - case (MDOC_TEXT): - term_word(p, n->string); - break; - case (MDOC_TBL): - term_tbl(p, n->span); - break; - default: - if (termacts[n->tok].pre && ENDBODY_NOT == n->end) - chld = (*termacts[n->tok].pre) - (p, &npair, m, n); - break; - } /* * Keeps only work until the end of a line. If a keep was @@ -357,6 +342,34 @@ print_mdoc_node(DECL_ARGS) (n->parent && MDOC_SYNPRETTY & n->parent->flags))) p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP); + /* + * After the keep flags have been set up, we may now + * produce output. Note that some pre-handlers do so. + */ + + switch (n->type) { + case (MDOC_TEXT): + if (' ' == *n->string && MDOC_LINE & n->flags) + term_newln(p); + if (MDOC_DELIMC & n->flags) + p->flags |= TERMP_NOSPACE; + term_word(p, n->string); + if (MDOC_DELIMO & n->flags) + p->flags |= TERMP_NOSPACE; + break; + case (MDOC_EQN): + term_word(p, n->eqn->data); + break; + case (MDOC_TBL): + term_tbl(p, n->span); + break; + default: + if (termacts[n->tok].pre && ENDBODY_NOT == n->end) + chld = (*termacts[n->tok].pre) + (p, &npair, m, n); + break; + } + if (chld && n->child) print_mdoc_nodelist(p, &npair, m, n->child); @@ -367,6 +380,8 @@ print_mdoc_node(DECL_ARGS) break; case (MDOC_TBL): break; + case (MDOC_EQN): + break; default: if ( ! termacts[n->tok].post || MDOC_ENDED & n->flags) break; @@ -401,7 +416,6 @@ print_mdoc_node(DECL_ARGS) static void print_mdoc_foot(struct termp *p, const void *arg) { - char buf[DATESIZ], os[BUFSIZ]; const struct mdoc_meta *m; m = (const struct mdoc_meta *)arg; @@ -416,24 +430,21 @@ print_mdoc_foot(struct termp *p, const void *arg) * SYSTEM DATE SYSTEM */ - time2a(m->date, buf, DATESIZ); - strlcpy(os, m->os, BUFSIZ); - term_vspace(p); p->offset = 0; p->rmargin = (p->maxrmargin - - term_strlen(p, buf) + term_len(p, 1)) / 2; + term_strlen(p, m->date) + term_len(p, 1)) / 2; p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; - term_word(p, os); + term_word(p, m->os); term_flushln(p); p->offset = p->rmargin; - p->rmargin = p->maxrmargin - term_strlen(p, os); + p->rmargin = p->maxrmargin - term_strlen(p, m->os); p->flags |= TERMP_NOLPAD | TERMP_NOSPACE; - term_word(p, buf); + term_word(p, m->date); term_flushln(p); p->offset = p->rmargin; @@ -441,7 +452,7 @@ print_mdoc_foot(struct termp *p, const void *arg) p->flags &= ~TERMP_NOBREAK; p->flags |= TERMP_NOLPAD | TERMP_NOSPACE; - term_word(p, os); + term_word(p, m->os); term_flushln(p); p->offset = 0; @@ -1149,7 +1160,8 @@ static int termp_ns_pre(DECL_ARGS) { - p->flags |= TERMP_NOSPACE; + if ( ! (MDOC_LINE & n->flags)) + p->flags |= TERMP_NOSPACE; return(1); } @@ -1171,25 +1183,30 @@ termp_rs_pre(DECL_ARGS) static int termp_rv_pre(DECL_ARGS) { - const struct mdoc_node *nn; + int nchild; term_newln(p); term_word(p, "The"); - for (nn = n->child; nn; nn = nn->next) { + nchild = n->nchild; + for (n = n->child; n; n = n->next) { term_fontpush(p, TERMFONT_BOLD); - term_word(p, nn->string); + term_word(p, n->string); term_fontpop(p); + p->flags |= TERMP_NOSPACE; - if (nn->next && NULL == nn->next->next) - term_word(p, "(), and"); - else if (nn->next) - term_word(p, "(),"); - else - term_word(p, "()"); + term_word(p, "()"); + + if (nchild > 2 && n->next) { + p->flags |= TERMP_NOSPACE; + term_word(p, ","); + } + + if (n->next && NULL == n->next->next) + term_word(p, "and"); } - if (n->child && n->child->next) + if (nchild > 1) term_word(p, "functions return"); else term_word(p, "function returns"); @@ -1212,31 +1229,34 @@ termp_rv_pre(DECL_ARGS) static int termp_ex_pre(DECL_ARGS) { - const struct mdoc_node *nn; + int nchild; + term_newln(p); term_word(p, "The"); - for (nn = n->child; nn; nn = nn->next) { + nchild = n->nchild; + for (n = n->child; n; n = n->next) { term_fontpush(p, TERMFONT_BOLD); - term_word(p, nn->string); + term_word(p, n->string); term_fontpop(p); - p->flags |= TERMP_NOSPACE; - if (nn->next && NULL == nn->next->next) - term_word(p, ", and"); - else if (nn->next) + + if (nchild > 2 && n->next) { + p->flags |= TERMP_NOSPACE; term_word(p, ","); - else - p->flags &= ~TERMP_NOSPACE; + } + + if (n->next && NULL == n->next->next) + term_word(p, "and"); } - if (n->child && n->child->next) + if (nchild > 1) term_word(p, "utilities exit"); else term_word(p, "utility exits"); term_word(p, "0 on success, and >0 if an error occurs."); - p->flags |= TERMP_SENTENCE; + p->flags |= TERMP_SENTENCE; return(0); } @@ -1276,31 +1296,33 @@ termp_bl_post(DECL_ARGS) term_newln(p); } - /* ARGSUSED */ static int termp_xr_pre(DECL_ARGS) { - const struct mdoc_node *nn; - if (NULL == n->child) + if (NULL == (n = n->child)) return(0); - assert(MDOC_TEXT == n->child->type); - nn = n->child; + assert(MDOC_TEXT == n->type); + term_word(p, n->string); - term_word(p, nn->string); - if (NULL == (nn = nn->next)) + if (NULL == (n = n->next)) return(0); + p->flags |= TERMP_NOSPACE; term_word(p, "("); - term_word(p, nn->string); + p->flags |= TERMP_NOSPACE; + + assert(MDOC_TEXT == n->type); + term_word(p, n->string); + + p->flags |= TERMP_NOSPACE; term_word(p, ")"); return(0); } - /* * This decides how to assert whitespace before any of the SYNOPSIS set * of macros (which, as in the case of Ft/Fo and Ft/Fn, may contain @@ -1514,30 +1536,43 @@ termp_ft_pre(DECL_ARGS) static int termp_fn_pre(DECL_ARGS) { - const struct mdoc_node *nn; + int pretty; + + pretty = MDOC_SYNPRETTY & n->flags; synopsis_pre(p, n); + if (NULL == (n = n->child)) + return(0); + + assert(MDOC_TEXT == n->type); term_fontpush(p, TERMFONT_BOLD); - term_word(p, n->child->string); + term_word(p, n->string); term_fontpop(p); p->flags |= TERMP_NOSPACE; term_word(p, "("); + p->flags |= TERMP_NOSPACE; - for (nn = n->child->next; nn; nn = nn->next) { + for (n = n->next; n; n = n->next) { + assert(MDOC_TEXT == n->type); term_fontpush(p, TERMFONT_UNDER); - term_word(p, nn->string); + term_word(p, n->string); term_fontpop(p); - if (nn->next) + if (n->next) { + p->flags |= TERMP_NOSPACE; term_word(p, ","); + } } + p->flags |= TERMP_NOSPACE; term_word(p, ")"); - if (MDOC_SYNPRETTY & n->flags) + if (pretty) { + p->flags |= TERMP_NOSPACE; term_word(p, ";"); + } return(0); } @@ -1559,12 +1594,16 @@ termp_fa_pre(DECL_ARGS) term_word(p, nn->string); term_fontpop(p); - if (nn->next) + if (nn->next) { + p->flags |= TERMP_NOSPACE; term_word(p, ","); + } } - if (n->child && n->next && n->next->tok == MDOC_Fa) + if (n->child && n->next && n->next->tok == MDOC_Fa) { + p->flags |= TERMP_NOSPACE; term_word(p, ","); + } return(0); } @@ -1672,13 +1711,27 @@ termp_bd_post(DECL_ARGS) /* ARGSUSED */ -static void -termp_bx_post(DECL_ARGS) +static int +termp_bx_pre(DECL_ARGS) { - if (n->child) + if (NULL != (n = n->child)) { + term_word(p, n->string); p->flags |= TERMP_NOSPACE; - term_word(p, "BSD"); + term_word(p, "BSD"); + } else { + term_word(p, "BSD"); + return(0); + } + + if (NULL != (n = n->next)) { + p->flags |= TERMP_NOSPACE; + term_word(p, "-"); + p->flags |= TERMP_NOSPACE; + term_word(p, n->string); + } + + return(0); } @@ -1687,6 +1740,7 @@ static int termp_xx_pre(DECL_ARGS) { const char *pp; + int flags; pp = NULL; switch (n->tok) { @@ -1712,9 +1766,14 @@ termp_xx_pre(DECL_ARGS) break; } - assert(pp); term_word(p, pp); - return(1); + if (n->child) { + flags = p->flags; + p->flags |= TERMP_KEEP; + term_word(p, n->child->string); + p->flags = flags; + } + return(0); } @@ -1979,6 +2038,7 @@ termp_fo_pre(DECL_ARGS) } else if (MDOC_BODY == n->type) { p->flags |= TERMP_NOSPACE; term_word(p, "("); + p->flags |= TERMP_NOSPACE; return(1); } @@ -2002,10 +2062,13 @@ termp_fo_post(DECL_ARGS) if (MDOC_BODY != n->type) return; + p->flags |= TERMP_NOSPACE; term_word(p, ")"); - if (MDOC_SYNPRETTY & n->flags) + if (MDOC_SYNPRETTY & n->flags) { + p->flags |= TERMP_NOSPACE; term_word(p, ";"); + } } @@ -2079,6 +2142,7 @@ termp____post(DECL_ARGS) if (NULL == n->parent || MDOC_Rs != n->parent->tok) return; + p->flags |= TERMP_NOSPACE; if (NULL == n->next) { term_word(p, "."); p->flags |= TERMP_SENTENCE; @@ -2115,6 +2179,7 @@ termp_lk_pre(DECL_ARGS) term_fontpop(p); + p->flags |= TERMP_NOSPACE; term_word(p, ":"); term_fontpush(p, TERMFONT_BOLD); @@ -2166,8 +2231,8 @@ termp__t_post(DECL_ARGS) * If we're in an `Rs' and there's a journal present, then quote * us instead of underlining us (for disambiguation). */ - if (n->parent && MDOC_Rs == n->parent->tok && - n->parent->norm->Rs.child_J) + if (n->parent && MDOC_Rs == n->parent->tok && + n->parent->norm->Rs.quote_T) termp_quote_post(p, pair, m, n); termp____post(p, pair, m, n); @@ -2183,7 +2248,7 @@ termp__t_pre(DECL_ARGS) * us instead of underlining us (for disambiguation). */ if (n->parent && MDOC_Rs == n->parent->tok && - n->parent->norm->Rs.child_J) + n->parent->norm->Rs.quote_T) return(termp_quote_pre(p, pair, m, n)); term_fontpush(p, TERMFONT_UNDER); diff --git a/contrib/mdocml/mdoc_validate.c b/contrib/mdocml/mdoc_validate.c index 0146219967..707864441c 100644 --- a/contrib/mdocml/mdoc_validate.c +++ b/contrib/mdocml/mdoc_validate.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_validate.c,v 1.151 2011/01/03 23:53:51 schwarze Exp $ */ +/* $Id: mdoc_validate.c,v 1.166 2011/04/03 09:53:50 kristaps Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2010, 2011 Ingo Schwarze @@ -33,6 +33,7 @@ #include #include +#include "mdoc.h" #include "mandoc.h" #include "libmdoc.h" #include "libmandoc.h" @@ -74,11 +75,12 @@ static void check_args(struct mdoc *, struct mdoc_node *); static int concat(struct mdoc *, char *, const struct mdoc_node *, size_t); +static enum mdoc_sec a2sec(const char *); +static size_t macro2len(enum mdoct); static int ebool(POST_ARGS); static int berr_ge1(POST_ARGS); static int bwarn_ge1(POST_ARGS); -static int eerr_ge1(POST_ARGS); static int ewarn_eq0(POST_ARGS); static int ewarn_eq1(POST_ARGS); static int ewarn_ge1(POST_ARGS); @@ -96,6 +98,7 @@ static int post_bl_block(POST_ARGS); static int post_bl_block_width(POST_ARGS); static int post_bl_block_tag(POST_ARGS); static int post_bl_head(POST_ARGS); +static int post_bx(POST_ARGS); static int post_dd(POST_ARGS); static int post_dt(POST_ARGS); static int post_defaults(POST_ARGS); @@ -104,6 +107,7 @@ static int post_eoln(POST_ARGS); static int post_it(POST_ARGS); static int post_lb(POST_ARGS); static int post_nm(POST_ARGS); +static int post_ns(POST_ARGS); static int post_os(POST_ARGS); static int post_ignpar(POST_ARGS); static int post_prol(POST_ARGS); @@ -135,10 +139,11 @@ static v_post posts_bd[] = { post_literal, hwarn_eq0, bwarn_ge1, NULL }; static v_post posts_bf[] = { hwarn_le1, post_bf, NULL }; static v_post posts_bk[] = { hwarn_eq0, bwarn_ge1, NULL }; static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL }; +static v_post posts_bx[] = { post_bx, NULL }; static v_post posts_bool[] = { ebool, NULL }; static v_post posts_eoln[] = { post_eoln, NULL }; static v_post posts_defaults[] = { post_defaults, NULL }; -static v_post posts_dd[] = { ewarn_ge1, post_dd, post_prol, NULL }; +static v_post posts_dd[] = { post_dd, post_prol, NULL }; static v_post posts_dl[] = { post_literal, bwarn_ge1, NULL }; static v_post posts_dt[] = { post_dt, post_prol, NULL }; static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL }; @@ -147,6 +152,7 @@ static v_post posts_lb[] = { post_lb, NULL }; static v_post posts_nd[] = { berr_ge1, NULL }; static v_post posts_nm[] = { post_nm, NULL }; static v_post posts_notext[] = { ewarn_eq0, NULL }; +static v_post posts_ns[] = { post_ns, NULL }; static v_post posts_os[] = { post_os, post_prol, NULL }; static v_post posts_rs[] = { post_rs, NULL }; static v_post posts_sh[] = { post_ignpar, hwarn_ge1, bwarn_ge1, post_sh, NULL }; @@ -154,11 +160,10 @@ static v_post posts_sp[] = { ewarn_le1, NULL }; static v_post posts_ss[] = { post_ignpar, hwarn_ge1, bwarn_ge1, NULL }; static v_post posts_st[] = { post_st, NULL }; static v_post posts_std[] = { post_std, NULL }; -static v_post posts_text[] = { eerr_ge1, NULL }; +static v_post posts_text[] = { ewarn_ge1, NULL }; static v_post posts_text1[] = { ewarn_eq1, NULL }; static v_post posts_vt[] = { post_vt, NULL }; static v_post posts_wline[] = { bwarn_ge1, NULL }; -static v_post posts_wtext[] = { ewarn_ge1, NULL }; static v_pre pres_an[] = { pre_an, NULL }; static v_pre pres_bd[] = { pre_display, pre_bd, pre_literal, pre_par, NULL }; static v_pre pres_bl[] = { pre_bl, pre_par, NULL }; @@ -175,7 +180,7 @@ static v_pre pres_sh[] = { pre_sh, NULL }; static v_pre pres_ss[] = { pre_ss, NULL }; static v_pre pres_std[] = { pre_std, NULL }; -const struct valids mdoc_valids[MDOC_MAX] = { +static const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* Ap */ { pres_dd, posts_dd }, /* Dd */ { pres_dt, posts_dt }, /* Dt */ @@ -190,21 +195,21 @@ const struct valids mdoc_valids[MDOC_MAX] = { { pres_bl, posts_bl }, /* Bl */ { NULL, NULL }, /* El */ { pres_it, posts_it }, /* It */ - { NULL, posts_text }, /* Ad */ + { NULL, NULL }, /* Ad */ { pres_an, posts_an }, /* An */ { NULL, posts_defaults }, /* Ar */ - { NULL, posts_text }, /* Cd */ + { NULL, NULL }, /* Cd */ { NULL, NULL }, /* Cm */ { NULL, NULL }, /* Dv */ - { pres_er, posts_text }, /* Er */ + { pres_er, NULL }, /* Er */ { NULL, NULL }, /* Ev */ { pres_std, posts_std }, /* Ex */ { NULL, NULL }, /* Fa */ - { pres_fd, posts_wtext }, /* Fd */ + { pres_fd, posts_text }, /* Fd */ { NULL, NULL }, /* Fl */ - { NULL, posts_text }, /* Fn */ - { NULL, posts_wtext }, /* Ft */ - { NULL, posts_text }, /* Ic */ + { NULL, NULL }, /* Fn */ + { NULL, NULL }, /* Ft */ + { NULL, NULL }, /* Ic */ { NULL, posts_text1 }, /* In */ { NULL, posts_defaults }, /* Li */ { NULL, posts_nd }, /* Nd */ @@ -216,10 +221,10 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, posts_st }, /* St */ { NULL, NULL }, /* Va */ { NULL, posts_vt }, /* Vt */ - { NULL, posts_wtext }, /* Xr */ + { NULL, posts_text }, /* Xr */ { NULL, posts_text }, /* %A */ { NULL, posts_text }, /* %B */ /* FIXME: can be used outside Rs/Re. */ - { NULL, posts_text }, /* %D */ /* FIXME: check date with mandoc_a2time(). */ + { NULL, posts_text }, /* %D */ { NULL, posts_text }, /* %I */ { NULL, posts_text }, /* %J */ { NULL, posts_text }, /* %N */ @@ -237,7 +242,7 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* Bo */ { NULL, NULL }, /* Bq */ { NULL, NULL }, /* Bsx */ - { NULL, NULL }, /* Bx */ + { NULL, posts_bx }, /* Bx */ { NULL, posts_bool }, /* Db */ { NULL, NULL }, /* Dc */ { NULL, NULL }, /* Do */ @@ -247,9 +252,9 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* Em */ { NULL, NULL }, /* Eo */ { NULL, NULL }, /* Fx */ - { NULL, posts_text }, /* Ms */ + { NULL, NULL }, /* Ms */ { NULL, posts_notext }, /* No */ - { NULL, posts_notext }, /* Ns */ + { NULL, posts_ns }, /* Ns */ { NULL, NULL }, /* Nx */ { NULL, NULL }, /* Ox */ { NULL, NULL }, /* Pc */ @@ -266,9 +271,9 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* So */ { NULL, NULL }, /* Sq */ { NULL, posts_bool }, /* Sm */ - { NULL, posts_text }, /* Sx */ - { NULL, posts_text }, /* Sy */ - { NULL, posts_text }, /* Tn */ + { NULL, NULL }, /* Sx */ + { NULL, NULL }, /* Sy */ + { NULL, NULL }, /* Tn */ { NULL, NULL }, /* Ux */ { NULL, NULL }, /* Xc */ { NULL, NULL }, /* Xo */ @@ -284,7 +289,7 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, posts_eoln }, /* Ud */ { NULL, posts_lb }, /* Lb */ { NULL, posts_notext }, /* Lp */ - { NULL, posts_text }, /* Lk */ + { NULL, NULL }, /* Lk */ { NULL, posts_defaults }, /* Mt */ { NULL, NULL }, /* Brq */ { NULL, NULL }, /* Bro */ @@ -319,6 +324,30 @@ static const enum mdoct rsord[RSORD_MAX] = { MDOC__U }; +static const char * const secnames[SEC__MAX] = { + NULL, + "NAME", + "LIBRARY", + "SYNOPSIS", + "DESCRIPTION", + "IMPLEMENTATION NOTES", + "RETURN VALUES", + "ENVIRONMENT", + "FILES", + "EXIT STATUS", + "EXAMPLES", + "DIAGNOSTICS", + "COMPATIBILITY", + "ERRORS", + "SEE ALSO", + "STANDARDS", + "HISTORY", + "AUTHORS", + "CAVEATS", + "BUGS", + "SECURITY CONSIDERATIONS", + NULL +}; int mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n) @@ -336,6 +365,8 @@ mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n) /* FALLTHROUGH */ case (MDOC_TBL): /* FALLTHROUGH */ + case (MDOC_EQN): + /* FALLTHROUGH */ case (MDOC_ROOT): return(1); default: @@ -365,6 +396,8 @@ mdoc_valid_post(struct mdoc *mdoc) switch (mdoc->last->type) { case (MDOC_TEXT): /* FALLTHROUGH */ + case (MDOC_EQN): + /* FALLTHROUGH */ case (MDOC_TBL): return(1); case (MDOC_ROOT): @@ -414,10 +447,10 @@ check_count(struct mdoc *m, enum mdoc_type type, } t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT; - - return(mdoc_vmsg(m, t, m->last->line, m->last->pos, + mandoc_vmsg(t, m->parse, m->last->line, m->last->pos, "want %s%d children (have %d)", - p, val, m->last->nchild)); + p, val, m->last->nchild); + return(1); } static int @@ -433,12 +466,6 @@ bwarn_ge1(POST_ARGS) return(check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0)); } -static int -eerr_ge1(POST_ARGS) -{ - return(check_count(mdoc, MDOC_ELEM, CHECK_ERROR, CHECK_GT, 0)); -} - static int ewarn_eq0(POST_ARGS) { @@ -555,10 +582,9 @@ check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t) (t == n->parent->type)) return(1); - mdoc_vmsg(mdoc, MANDOCERR_SYNTCHILD, - n->line, n->pos, "want parent %s", - MDOC_ROOT == t ? " " : - mdoc_macronames[tok]); + mandoc_vmsg(MANDOCERR_SYNTCHILD, mdoc->parse, n->line, + n->pos, "want parent %s", MDOC_ROOT == t ? + " " : mdoc_macronames[tok]); return(0); } @@ -919,7 +945,7 @@ static int pre_dt(PRE_ARGS) { - if (0 == mdoc->meta.date || mdoc->meta.os) + if (NULL == mdoc->meta.date || mdoc->meta.os) mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO); if (mdoc->meta.title) @@ -932,7 +958,7 @@ static int pre_os(PRE_ARGS) { - if (NULL == mdoc->meta.title || 0 == mdoc->meta.date) + if (NULL == mdoc->meta.title || NULL == mdoc->meta.date) mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO); if (mdoc->meta.os) @@ -1079,12 +1105,11 @@ post_vt(POST_ARGS) /* * The Vt macro comes in both ELEM and BLOCK form, both of which * have different syntaxes (yet more context-sensitive - * behaviour). ELEM types must have a child; BLOCK types, + * behaviour). ELEM types must have a child, which is already + * guaranteed by the in_line parsing routine; BLOCK types, * specifically the BODY, should only have TEXT children. */ - if (MDOC_ELEM == mdoc->last->type) - return(eerr_ge1(mdoc)); if (MDOC_BODY != mdoc->last->type) return(1); @@ -1228,19 +1253,12 @@ post_an(POST_ARGS) struct mdoc_node *np; np = mdoc->last; - if (AUTH__NONE != np->norm->An.auth && np->child) { + if (AUTH__NONE == np->norm->An.auth) { + if (0 == np->child) + check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0); + } else if (np->child) check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0); - return(1); - } - /* - * FIXME: make this ewarn and make sure that the front-ends - * don't print the arguments. - */ - if (AUTH__NONE != np->norm->An.auth || np->child) - return(1); - - mdoc_nmsg(mdoc, np, MANDOCERR_NOARGS); return(1); } @@ -1248,7 +1266,7 @@ post_an(POST_ARGS) static int post_it(POST_ARGS) { - int i, cols, rc; + int i, cols; enum mdoc_list lt; struct mdoc_node *n, *c; enum mandocerr er; @@ -1314,10 +1332,10 @@ post_it(POST_ARGS) else er = MANDOCERR_SYNTARGCOUNT; - rc = mdoc_vmsg(mdoc, er, - mdoc->last->line, mdoc->last->pos, + mandoc_vmsg(er, mdoc->parse, mdoc->last->line, + mdoc->last->pos, "columns == %d (have %d)", cols, i); - return(rc); + return(MANDOCERR_ARGCOUNT == er); default: break; } @@ -1378,7 +1396,7 @@ post_bl_block_width(POST_ARGS) width = 6; else if (MDOC_MAX == (tok = mdoc_hash_find(n->norm->Bl.width))) return(1); - else if (0 == (width = mdoc_macro2len(tok))) { + else if (0 == (width = macro2len(tok))) { mdoc_nmsg(mdoc, n, MANDOCERR_BADWIDTH); return(1); } @@ -1435,7 +1453,7 @@ post_bl_block_tag(POST_ARGS) break; } - if (0 != (ssz = mdoc_macro2len(nn->tok))) + if (0 != (ssz = macro2len(nn->tok))) sz = ssz; break; @@ -1681,8 +1699,8 @@ post_rs(POST_ARGS) break; if (i < RSORD_MAX) { - if (MDOC__J == rsord[i]) - mdoc->last->norm->Rs.child_J = nn; + if (MDOC__J == rsord[i] || MDOC__B == rsord[i]) + mdoc->last->norm->Rs.quote_T++; next = nn->next; continue; } @@ -1757,6 +1775,15 @@ post_rs(POST_ARGS) return(1); } +static int +post_ns(POST_ARGS) +{ + + if (MDOC_LINE & mdoc->last->flags) + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNNS); + return(1); +} + static int post_sh(POST_ARGS) { @@ -1820,7 +1847,7 @@ post_sh_head(POST_ARGS) if ( ! concat(mdoc, buf, mdoc->last->child, BUFSIZ)) return(0); - sec = mdoc_str2sec(buf); + sec = a2sec(buf); /* The NAME should be first. */ @@ -1970,23 +1997,21 @@ post_dd(POST_ARGS) char buf[DATESIZE]; struct mdoc_node *n; - n = mdoc->last; + if (mdoc->meta.date) + free(mdoc->meta.date); - if (NULL == n->child) { - mdoc->meta.date = time(NULL); + n = mdoc->last; + if (NULL == n->child || '\0' == n->child->string[0]) { + mdoc->meta.date = mandoc_normdate + (mdoc->parse, NULL, n->line, n->pos); return(1); } if ( ! concat(mdoc, buf, n->child, DATESIZE)) return(0); - mdoc->meta.date = mandoc_a2time - (MTIME_MDOCDATE | MTIME_CANONICAL, buf); - - if (0 == mdoc->meta.date) { - mdoc_nmsg(mdoc, n, MANDOCERR_BADDATE); - mdoc->meta.date = time(NULL); - } + mdoc->meta.date = mandoc_normdate + (mdoc->parse, buf, n->line, n->pos); return(1); } @@ -2115,6 +2140,25 @@ post_prol(POST_ARGS) return(1); } +static int +post_bx(POST_ARGS) +{ + struct mdoc_node *n; + + /* + * Make `Bx's second argument always start with an uppercase + * letter. Groff checks if it's an "accepted" term, but we just + * uppercase blindly. + */ + + n = mdoc->last->child; + if (n && NULL != (n = n->next)) + *n->string = (char)toupper + ((unsigned char)*n->string); + + return(1); +} + static int post_os(POST_ARGS) { @@ -2150,7 +2194,7 @@ post_os(POST_ARGS) return(0); } #else /*!OSNAME */ - if (uname(&utsname)) { + if (-1 == uname(&utsname)) { mdoc_nmsg(mdoc, n, MANDOCERR_UNAME); mdoc->meta.os = mandoc_strdup("UNKNOWN"); return(post_prol(mdoc)); @@ -2237,3 +2281,107 @@ concat(struct mdoc *m, char *p, const struct mdoc_node *n, size_t sz) return(1); } +static enum mdoc_sec +a2sec(const char *p) +{ + int i; + + for (i = 0; i < (int)SEC__MAX; i++) + if (secnames[i] && 0 == strcmp(p, secnames[i])) + return((enum mdoc_sec)i); + + return(SEC_CUSTOM); +} + +static size_t +macro2len(enum mdoct macro) +{ + + switch (macro) { + case(MDOC_Ad): + return(12); + case(MDOC_Ao): + return(12); + case(MDOC_An): + return(12); + case(MDOC_Aq): + return(12); + case(MDOC_Ar): + return(12); + case(MDOC_Bo): + return(12); + case(MDOC_Bq): + return(12); + case(MDOC_Cd): + return(12); + case(MDOC_Cm): + return(10); + case(MDOC_Do): + return(10); + case(MDOC_Dq): + return(12); + case(MDOC_Dv): + return(12); + case(MDOC_Eo): + return(12); + case(MDOC_Em): + return(10); + case(MDOC_Er): + return(17); + case(MDOC_Ev): + return(15); + case(MDOC_Fa): + return(12); + case(MDOC_Fl): + return(10); + case(MDOC_Fo): + return(16); + case(MDOC_Fn): + return(16); + case(MDOC_Ic): + return(10); + case(MDOC_Li): + return(16); + case(MDOC_Ms): + return(6); + case(MDOC_Nm): + return(10); + case(MDOC_No): + return(12); + case(MDOC_Oo): + return(10); + case(MDOC_Op): + return(14); + case(MDOC_Pa): + return(32); + case(MDOC_Pf): + return(12); + case(MDOC_Po): + return(12); + case(MDOC_Pq): + return(12); + case(MDOC_Ql): + return(16); + case(MDOC_Qo): + return(12); + case(MDOC_So): + return(12); + case(MDOC_Sq): + return(12); + case(MDOC_Sy): + return(6); + case(MDOC_Sx): + return(16); + case(MDOC_Tn): + return(10); + case(MDOC_Va): + return(12); + case(MDOC_Vt): + return(12); + case(MDOC_Xr): + return(10); + default: + break; + }; + return(0); +} diff --git a/contrib/mdocml/msec.c b/contrib/mdocml/msec.c index ba5e8d7839..f51360e597 100644 --- a/contrib/mdocml/msec.c +++ b/contrib/mdocml/msec.c @@ -1,4 +1,4 @@ -/* $Id: msec.c,v 1.8 2010/05/17 22:11:42 kristaps Exp $ */ +/* $Id: msec.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons * @@ -21,6 +21,7 @@ #include #include +#include "mdoc.h" #include "mandoc.h" #include "libmdoc.h" diff --git a/contrib/mdocml/out.c b/contrib/mdocml/out.c index d0629e4325..eb303d5194 100644 --- a/contrib/mdocml/out.c +++ b/contrib/mdocml/out.c @@ -1,6 +1,7 @@ -/* $Id: out.c,v 1.30 2011/01/05 15:37:23 kristaps Exp $ */ +/* $Id: out.c,v 1.39 2011/03/17 08:49:34 kristaps Exp $ */ /* - * Copyright (c) 2009, 2010 Kristaps Dzonsons + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2011 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -251,6 +252,49 @@ a2roffdeco(enum roffdeco *d, const char **word, size_t *sz) break; } break; + + case ('N'): + + /* + * Sequence of characters: backslash, 'N' (i = 0), + * starting delimiter (i = 1), character number (i = 2). + */ + + *word = wp + 2; + *sz = 0; + + /* + * Cannot use a digit as a starting delimiter; + * but skip the digit anyway. + */ + + if (isdigit((int)wp[1])) + return(2); + + /* + * Any non-digit terminates the character number. + * That is, the terminating delimiter need not + * match the starting delimiter. + */ + + for (i = 2; isdigit((int)wp[i]); i++) + (*sz)++; + + /* + * This is only a numbered character + * if the character number has at least one digit. + */ + + if (*sz) + *d = DECO_NUMBERED; + + /* + * Skip the terminating delimiter, even if it does not + * match, and even if there is no character number. + */ + + return(++i); + case ('h'): /* FALLTHROUGH */ case ('v'): @@ -387,7 +431,8 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp) */ assert(NULL == tbl->cols); - tbl->cols = calloc(sp->tbl->cols, sizeof(struct roffcol)); + tbl->cols = mandoc_calloc + ((size_t)sp->tbl->cols, sizeof(struct roffcol)); hp = sp->head; @@ -399,8 +444,7 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp) * to data cells in the data section. */ for (dp = sp->first; dp; dp = dp->next) { - if (NULL == dp->layout) - continue; + assert(dp->layout); col = &tbl->cols[dp->layout->head->ident]; tblcalc_data(tbl, col, sp->tbl, dp); } @@ -454,6 +498,8 @@ tblcalc_data(struct rofftbl *tbl, struct roffcol *col, case (TBL_CELL_NUMBER): tblcalc_number(tbl, col, tp, dp); break; + case (TBL_CELL_DOWN): + break; default: abort(); /* NOTREACHED */ @@ -465,6 +511,7 @@ tblcalc_literal(struct rofftbl *tbl, struct roffcol *col, const struct tbl_dat *dp) { size_t sz, bufsz, spsz; + const char *str; /* * Calculate our width and use the spacing, with a minimum @@ -472,16 +519,18 @@ tblcalc_literal(struct rofftbl *tbl, struct roffcol *col, * either side, while right/left get a single adjacent space). */ - sz = bufsz = spsz = 0; - if (dp->string) - sz = (*tbl->slen)(dp->string, tbl->arg); + bufsz = spsz = 0; + str = dp->string ? dp->string : ""; + sz = (*tbl->slen)(str, tbl->arg); + + /* FIXME: TBL_DATA_HORIZ et al.? */ assert(dp->layout); switch (dp->layout->pos) { case (TBL_CELL_LONG): /* FALLTHROUGH */ case (TBL_CELL_CENTRE): - bufsz = (*tbl->len)(2, tbl->arg); + bufsz = (*tbl->len)(1, tbl->arg); break; default: bufsz = (*tbl->len)(1, tbl->arg); @@ -504,12 +553,10 @@ tblcalc_number(struct rofftbl *tbl, struct roffcol *col, { int i; size_t sz, psz, ssz, d; - char *cp; const char *str; + char *cp; char buf[2]; - /* TODO: use spacing modifier. */ - /* * First calculate number width and decimal place (last + 1 for * no-decimal numbers). If the stored decimal is subsequent @@ -519,18 +566,17 @@ tblcalc_number(struct rofftbl *tbl, struct roffcol *col, * Finally, re-assign the stored values. */ - str = ""; - if (dp->string) - str = dp->string; - + str = dp->string ? dp->string : ""; sz = (*tbl->slen)(str, tbl->arg); + /* FIXME: TBL_DATA_HORIZ et al.? */ + buf[0] = tp->decimal; buf[1] = '\0'; psz = (*tbl->slen)(buf, tbl->arg); - if (NULL != (cp = strchr(str, tp->decimal))) { + if (NULL != (cp = strrchr(str, tp->decimal))) { buf[1] = '\0'; for (ssz = 0, i = 0; cp != &str[i]; i++) { buf[0] = str[i]; @@ -557,6 +603,11 @@ tblcalc_number(struct rofftbl *tbl, struct roffcol *col, col->width = sz; if (d > col->decimal) col->decimal = d; + + /* Adjust for stipulated width. */ + + if (col->width < dp->layout->spacing) + col->width = dp->layout->spacing; } diff --git a/contrib/mdocml/out.h b/contrib/mdocml/out.h index f544b8e32e..9bf5357b30 100644 --- a/contrib/mdocml/out.h +++ b/contrib/mdocml/out.h @@ -1,6 +1,6 @@ -/* $Id: out.h,v 1.15 2011/01/05 15:37:23 kristaps Exp $ */ +/* $Id: out.h,v 1.18 2011/03/22 10:13:01 kristaps Exp $ */ /* - * Copyright (c) 2009 Kristaps Dzonsons + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,41 +17,23 @@ #ifndef OUT_H #define OUT_H -#define DATESIZ 24 - -__BEGIN_DECLS - -struct roffcol { - size_t width; /* width of cell */ - size_t decimal; /* decimal position in cell */ -}; - -typedef size_t (*tbl_strlen)(const char *, void *); -typedef size_t (*tbl_len)(size_t, void *); - -struct rofftbl { - tbl_strlen slen; /* calculate string length */ - tbl_len len; /* produce width of empty space */ - struct roffcol *cols; /* master column specifiers */ - void *arg; /* passed to slen and len */ -}; - enum roffscale { - SCALE_CM, - SCALE_IN, - SCALE_PC, - SCALE_PT, - SCALE_EM, - SCALE_MM, - SCALE_EN, - SCALE_BU, - SCALE_VS, - SCALE_FS, + SCALE_CM, /* centimeters (c) */ + SCALE_IN, /* inches (i) */ + SCALE_PC, /* pica (P) */ + SCALE_PT, /* points (p) */ + SCALE_EM, /* ems (m) */ + SCALE_MM, /* mini-ems (M) */ + SCALE_EN, /* ens (n) */ + SCALE_BU, /* default horizontal (u) */ + SCALE_VS, /* default vertical (v) */ + SCALE_FS, /* syn. for u (f) */ SCALE_MAX }; enum roffdeco { DECO_NONE, + DECO_NUMBERED, /* numbered character */ DECO_SPECIAL, /* special character */ DECO_SSPECIAL, /* single-char special */ DECO_RESERVED, /* reserved word */ @@ -65,11 +47,33 @@ enum roffdeco { DECO_MAX }; +enum chars { + CHARS_ASCII, /* 7-bit ascii representation */ + CHARS_HTML /* unicode values */ +}; + +struct roffcol { + size_t width; /* width of cell */ + size_t decimal; /* decimal position in cell */ +}; + struct roffsu { enum roffscale unit; double scale; }; +typedef size_t (*tbl_strlen)(const char *, void *); +typedef size_t (*tbl_len)(size_t, void *); + +struct rofftbl { + tbl_strlen slen; /* calculate string length */ + tbl_len len; /* produce width of empty space */ + struct roffcol *cols; /* master column specifiers */ + void *arg; /* passed to slen and len */ +}; + +__BEGIN_DECLS + #define SCALE_VS_INIT(p, v) \ do { (p)->unit = SCALE_VS; \ (p)->scale = (v); } \ @@ -80,10 +84,18 @@ struct roffsu { (p)->scale = (v); } \ while (/* CONSTCOND */ 0) -int a2roffsu(const char *, struct roffsu *, enum roffscale); -int a2roffdeco(enum roffdeco *, const char **, size_t *); -void time2a(time_t, char *, size_t); -void tblcalc(struct rofftbl *tbl, const struct tbl_span *); +int a2roffsu(const char *, struct roffsu *, enum roffscale); +int a2roffdeco(enum roffdeco *, const char **, size_t *); +void time2a(time_t, char *, size_t); +void tblcalc(struct rofftbl *tbl, const struct tbl_span *); + +void *chars_init(enum chars); +const char *chars_num2char(const char *, size_t); +const char *chars_spec2str(void *, const char *, size_t, size_t *); +int chars_spec2cp(void *, const char *, size_t); +const char *chars_res2str(void *, const char *, size_t, size_t *); +int chars_res2cp(void *, const char *, size_t); +void chars_free(void *); __END_DECLS diff --git a/contrib/mdocml/read.c b/contrib/mdocml/read.c new file mode 100644 index 0000000000..6c240c2bd2 --- /dev/null +++ b/contrib/mdocml/read.c @@ -0,0 +1,765 @@ +/* $Id: read.c,v 1.10 2011/04/03 10:11:25 kristaps Exp $ */ +/* + * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2010, 2011 Ingo Schwarze + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mandoc.h" +#include "libmandoc.h" +#include "mdoc.h" +#include "man.h" + +#ifndef MAP_FILE +#define MAP_FILE 0 +#endif + +#define REPARSE_LIMIT 1000 + +struct buf { + char *buf; /* binary input buffer */ + size_t sz; /* size of binary buffer */ +}; + +struct mparse { + enum mandoclevel file_status; /* status of current parse */ + enum mandoclevel wlevel; /* ignore messages below this */ + int line; /* line number in the file */ + enum mparset inttype; /* which parser to use */ + struct man *pman; /* persistent man parser */ + struct mdoc *pmdoc; /* persistent mdoc parser */ + struct man *man; /* man parser */ + struct mdoc *mdoc; /* mdoc parser */ + struct roff *roff; /* roff parser (!NULL) */ + struct regset regs; /* roff registers */ + int reparse_count; /* finite interp. stack */ + mandocmsg mmsg; /* warning/error message handler */ + void *arg; /* argument to mmsg */ + const char *file; +}; + +static void resize_buf(struct buf *, size_t); +static void mparse_buf_r(struct mparse *, struct buf, int); +static void mparse_readfd_r(struct mparse *, int, const char *, int); +static void pset(const char *, int, struct mparse *); +static void pdesc(struct mparse *, const char *, int); +static int read_whole_file(const char *, int, struct buf *, int *); +static void mparse_end(struct mparse *); + +static const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = { + MANDOCERR_OK, + MANDOCERR_WARNING, + MANDOCERR_WARNING, + MANDOCERR_ERROR, + MANDOCERR_FATAL, + MANDOCERR_MAX, + MANDOCERR_MAX +}; + +static const char * const mandocerrs[MANDOCERR_MAX] = { + "ok", + + "generic warning", + + /* related to the prologue */ + "no title in document", + "document title should be all caps", + "unknown manual section", + "date missing, using today's date", + "cannot parse date, using it verbatim", + "prologue macros out of order", + "duplicate prologue macro", + "macro not allowed in prologue", + "macro not allowed in body", + + /* related to document structure */ + ".so is fragile, better use ln(1)", + "NAME section must come first", + "bad NAME section contents", + "manual name not yet set", + "sections out of conventional order", + "duplicate section name", + "section not in conventional manual section", + + /* related to macros and nesting */ + "skipping obsolete macro", + "skipping paragraph macro", + "skipping no-space macro", + "blocks badly nested", + "child violates parent syntax", + "nested displays are not portable", + "already in literal mode", + "line scope broken", + + /* related to missing macro arguments */ + "skipping empty macro", + "argument count wrong", + "missing display type", + "list type must come first", + "tag lists require a width argument", + "missing font type", + "skipping end of block that is not open", + + /* related to bad macro arguments */ + "skipping argument", + "duplicate argument", + "duplicate display type", + "duplicate list type", + "unknown AT&T UNIX version", + "bad Boolean value", + "unknown font", + "unknown standard specifier", + "bad width argument", + + /* related to plain text */ + "blank line in non-literal context", + "tab in non-literal context", + "end of line whitespace", + "bad comment style", + "unknown escape sequence", + "unterminated quoted string", + + "generic error", + + /* related to tables */ + "bad table syntax", + "bad table option", + "bad table layout", + "no table layout cells specified", + "no table data cells specified", + "ignore data in cell", + "data block still open", + "ignoring extra data cells", + + "input stack limit exceeded, infinite loop?", + "skipping bad character", + "escaped character not allowed in a name", + "skipping text before the first section header", + "skipping unknown macro", + "NOT IMPLEMENTED, please use groff: skipping request", + "argument count wrong", + "skipping end of block that is not open", + "missing end of block", + "scope open on exit", + "uname(3) system call failed", + "macro requires line argument(s)", + "macro requires body argument(s)", + "macro requires argument(s)", + "missing list type", + "line argument(s) will be lost", + "body argument(s) will be lost", + + "generic fatal error", + + "not a manual", + "column syntax is inconsistent", + "NOT IMPLEMENTED: .Bd -file", + "line scope broken, syntax violated", + "argument count wrong, violates syntax", + "child violates parent syntax", + "argument count wrong, violates syntax", + "NOT IMPLEMENTED: .so with absolute path or \"..\"", + "no document body", + "no document prologue", + "static buffer exhausted", +}; + +static const char * const mandoclevels[MANDOCLEVEL_MAX] = { + "SUCCESS", + "RESERVED", + "WARNING", + "ERROR", + "FATAL", + "BADARG", + "SYSERR" +}; + +static void +resize_buf(struct buf *buf, size_t initial) +{ + + buf->sz = buf->sz > initial/2 ? 2 * buf->sz : initial; + buf->buf = mandoc_realloc(buf->buf, buf->sz); +} + +static void +pset(const char *buf, int pos, struct mparse *curp) +{ + int i; + + /* + * Try to intuit which kind of manual parser should be used. If + * passed in by command-line (-man, -mdoc), then use that + * explicitly. If passed as -mandoc, then try to guess from the + * line: either skip dot-lines, use -mdoc when finding `.Dt', or + * default to -man, which is more lenient. + * + * Separate out pmdoc/pman from mdoc/man: the first persists + * through all parsers, while the latter is used per-parse. + */ + + if ('.' == buf[0] || '\'' == buf[0]) { + for (i = 1; buf[i]; i++) + if (' ' != buf[i] && '\t' != buf[i]) + break; + if ('\0' == buf[i]) + return; + } + + switch (curp->inttype) { + case (MPARSE_MDOC): + if (NULL == curp->pmdoc) + curp->pmdoc = mdoc_alloc(&curp->regs, curp); + assert(curp->pmdoc); + curp->mdoc = curp->pmdoc; + return; + case (MPARSE_MAN): + if (NULL == curp->pman) + curp->pman = man_alloc(&curp->regs, curp); + assert(curp->pman); + curp->man = curp->pman; + return; + default: + break; + } + + if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3)) { + if (NULL == curp->pmdoc) + curp->pmdoc = mdoc_alloc(&curp->regs, curp); + assert(curp->pmdoc); + curp->mdoc = curp->pmdoc; + return; + } + + if (NULL == curp->pman) + curp->pman = man_alloc(&curp->regs, curp); + assert(curp->pman); + curp->man = curp->pman; +} + +/* + * Main parse routine for an opened file. This is called for each + * opened file and simply loops around the full input file, possibly + * nesting (i.e., with `so'). + */ +static void +mparse_buf_r(struct mparse *curp, struct buf blk, int start) +{ + const struct tbl_span *span; + struct buf ln; + enum rofferr rr; + int i, of, rc; + int pos; /* byte number in the ln buffer */ + int lnn; /* line number in the real file */ + unsigned char c; + + memset(&ln, 0, sizeof(struct buf)); + + lnn = curp->line; + pos = 0; + + for (i = 0; i < (int)blk.sz; ) { + if (0 == pos && '\0' == blk.buf[i]) + break; + + if (start) { + curp->line = lnn; + curp->reparse_count = 0; + } + + while (i < (int)blk.sz && (start || '\0' != blk.buf[i])) { + + /* + * When finding an unescaped newline character, + * leave the character loop to process the line. + * Skip a preceding carriage return, if any. + */ + + if ('\r' == blk.buf[i] && i + 1 < (int)blk.sz && + '\n' == blk.buf[i + 1]) + ++i; + if ('\n' == blk.buf[i]) { + ++i; + ++lnn; + break; + } + + /* + * Warn about bogus characters. If you're using + * non-ASCII encoding, you're screwing your + * readers. Since I'd rather this not happen, + * I'll be helpful and drop these characters so + * we don't display gibberish. Note to manual + * writers: use special characters. + */ + + c = (unsigned char) blk.buf[i]; + + if ( ! (isascii(c) && + (isgraph(c) || isblank(c)))) { + mandoc_msg(MANDOCERR_BADCHAR, curp, + curp->line, pos, "ignoring byte"); + i++; + continue; + } + + /* Trailing backslash = a plain char. */ + + if ('\\' != blk.buf[i] || i + 1 == (int)blk.sz) { + if (pos >= (int)ln.sz) + resize_buf(&ln, 256); + ln.buf[pos++] = blk.buf[i++]; + continue; + } + + /* + * Found escape and at least one other character. + * When it's a newline character, skip it. + * When there is a carriage return in between, + * skip that one as well. + */ + + if ('\r' == blk.buf[i + 1] && i + 2 < (int)blk.sz && + '\n' == blk.buf[i + 2]) + ++i; + if ('\n' == blk.buf[i + 1]) { + i += 2; + ++lnn; + continue; + } + + if ('"' == blk.buf[i + 1]) { + i += 2; + /* Comment, skip to end of line */ + for (; i < (int)blk.sz; ++i) { + if ('\n' == blk.buf[i]) { + ++i; + ++lnn; + break; + } + } + + /* Backout trailing whitespaces */ + for (; pos > 0; --pos) { + if (ln.buf[pos - 1] != ' ') + break; + if (pos > 2 && ln.buf[pos - 2] == '\\') + break; + } + break; + } + + /* Some other escape sequence, copy & cont. */ + + if (pos + 1 >= (int)ln.sz) + resize_buf(&ln, 256); + + ln.buf[pos++] = blk.buf[i++]; + ln.buf[pos++] = blk.buf[i++]; + } + + if (pos >= (int)ln.sz) + resize_buf(&ln, 256); + + ln.buf[pos] = '\0'; + + /* + * A significant amount of complexity is contained by + * the roff preprocessor. It's line-oriented but can be + * expressed on one line, so we need at times to + * readjust our starting point and re-run it. The roff + * preprocessor can also readjust the buffers with new + * data, so we pass them in wholesale. + */ + + of = 0; + +rerun: + rr = roff_parseln + (curp->roff, curp->line, + &ln.buf, &ln.sz, of, &of); + + switch (rr) { + case (ROFF_REPARSE): + if (REPARSE_LIMIT >= ++curp->reparse_count) + mparse_buf_r(curp, ln, 0); + else + mandoc_msg(MANDOCERR_ROFFLOOP, curp, + curp->line, pos, NULL); + pos = 0; + continue; + case (ROFF_APPEND): + pos = (int)strlen(ln.buf); + continue; + case (ROFF_RERUN): + goto rerun; + case (ROFF_IGN): + pos = 0; + continue; + case (ROFF_ERR): + assert(MANDOCLEVEL_FATAL <= curp->file_status); + break; + case (ROFF_SO): + mparse_readfd_r(curp, -1, ln.buf + of, 1); + if (MANDOCLEVEL_FATAL <= curp->file_status) + break; + pos = 0; + continue; + default: + break; + } + + /* + * If we encounter errors in the recursive parse, make + * sure we don't continue parsing. + */ + + if (MANDOCLEVEL_FATAL <= curp->file_status) + break; + + /* + * If input parsers have not been allocated, do so now. + * We keep these instanced betwen parsers, but set them + * locally per parse routine since we can use different + * parsers with each one. + */ + + if ( ! (curp->man || curp->mdoc)) + pset(ln.buf + of, pos - of, curp); + + /* + * Lastly, push down into the parsers themselves. One + * of these will have already been set in the pset() + * routine. + * If libroff returns ROFF_TBL, then add it to the + * currently open parse. Since we only get here if + * there does exist data (see tbl_data.c), we're + * guaranteed that something's been allocated. + * Do the same for ROFF_EQN. + */ + + rc = -1; + + if (ROFF_TBL == rr) + while (NULL != (span = roff_span(curp->roff))) { + rc = curp->man ? + man_addspan(curp->man, span) : + mdoc_addspan(curp->mdoc, span); + if (0 == rc) + break; + } + else if (ROFF_EQN == rr) + rc = curp->mdoc ? + mdoc_addeqn(curp->mdoc, + roff_eqn(curp->roff)) : + man_addeqn(curp->man, + roff_eqn(curp->roff)); + else if (curp->man || curp->mdoc) + rc = curp->man ? + man_parseln(curp->man, + curp->line, ln.buf, of) : + mdoc_parseln(curp->mdoc, + curp->line, ln.buf, of); + + if (0 == rc) { + assert(MANDOCLEVEL_FATAL <= curp->file_status); + break; + } + + /* Temporary buffers typically are not full. */ + + if (0 == start && '\0' == blk.buf[i]) + break; + + /* Start the next input line. */ + + pos = 0; + } + + free(ln.buf); +} + +static void +pdesc(struct mparse *curp, const char *file, int fd) +{ + struct buf blk; + int with_mmap; + + /* + * Run for each opened file; may be called more than once for + * each full parse sequence if the opened file is nested (i.e., + * from `so'). Simply sucks in the whole file and moves into + * the parse phase for the file. + */ + + if ( ! read_whole_file(file, fd, &blk, &with_mmap)) { + curp->file_status = MANDOCLEVEL_SYSERR; + return; + } + + /* Line number is per-file. */ + + curp->line = 1; + + mparse_buf_r(curp, blk, 1); + + if (with_mmap) + munmap(blk.buf, blk.sz); + else + free(blk.buf); +} + +static int +read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap) +{ + struct stat st; + size_t off; + ssize_t ssz; + + if (-1 == fstat(fd, &st)) { + perror(file); + return(0); + } + + /* + * If we're a regular file, try just reading in the whole entry + * via mmap(). This is faster than reading it into blocks, and + * since each file is only a few bytes to begin with, I'm not + * concerned that this is going to tank any machines. + */ + + if (S_ISREG(st.st_mode)) { + if (st.st_size >= (1U << 31)) { + fprintf(stderr, "%s: input too large\n", file); + return(0); + } + *with_mmap = 1; + fb->sz = (size_t)st.st_size; + fb->buf = mmap(NULL, fb->sz, PROT_READ, + MAP_FILE|MAP_SHARED, fd, 0); + if (fb->buf != MAP_FAILED) + return(1); + } + + /* + * If this isn't a regular file (like, say, stdin), then we must + * go the old way and just read things in bit by bit. + */ + + *with_mmap = 0; + off = 0; + fb->sz = 0; + fb->buf = NULL; + for (;;) { + if (off == fb->sz) { + if (fb->sz == (1U << 31)) { + fprintf(stderr, "%s: input too large\n", file); + break; + } + resize_buf(fb, 65536); + } + ssz = read(fd, fb->buf + (int)off, fb->sz - off); + if (ssz == 0) { + fb->sz = off; + return(1); + } + if (ssz == -1) { + perror(file); + break; + } + off += (size_t)ssz; + } + + free(fb->buf); + fb->buf = NULL; + return(0); +} + +static void +mparse_end(struct mparse *curp) +{ + + if (MANDOCLEVEL_FATAL <= curp->file_status) + return; + + if (curp->mdoc && ! mdoc_endparse(curp->mdoc)) { + assert(MANDOCLEVEL_FATAL <= curp->file_status); + return; + } + + if (curp->man && ! man_endparse(curp->man)) { + assert(MANDOCLEVEL_FATAL <= curp->file_status); + return; + } + + if ( ! (curp->man || curp->mdoc)) { + mandoc_msg(MANDOCERR_NOTMANUAL, curp, 1, 0, NULL); + curp->file_status = MANDOCLEVEL_FATAL; + return; + } + + roff_endparse(curp->roff); +} + +static void +mparse_readfd_r(struct mparse *curp, int fd, const char *file, int re) +{ + const char *svfile; + + if (-1 == fd) + if (-1 == (fd = open(file, O_RDONLY, 0))) { + perror(file); + curp->file_status = MANDOCLEVEL_SYSERR; + return; + } + + svfile = curp->file; + curp->file = file; + + pdesc(curp, file, fd); + + if (0 == re && MANDOCLEVEL_FATAL > curp->file_status) + mparse_end(curp); + + if (STDIN_FILENO != fd && -1 == close(fd)) + perror(file); + + curp->file = svfile; +} + +enum mandoclevel +mparse_readfd(struct mparse *curp, int fd, const char *file) +{ + + mparse_readfd_r(curp, fd, file, 0); + return(curp->file_status); +} + +struct mparse * +mparse_alloc(enum mparset inttype, enum mandoclevel wlevel, mandocmsg mmsg, void *arg) +{ + struct mparse *curp; + + assert(wlevel <= MANDOCLEVEL_FATAL); + + curp = mandoc_calloc(1, sizeof(struct mparse)); + + curp->wlevel = wlevel; + curp->mmsg = mmsg; + curp->arg = arg; + curp->inttype = inttype; + + curp->roff = roff_alloc(&curp->regs, curp); + return(curp); +} + +void +mparse_reset(struct mparse *curp) +{ + + memset(&curp->regs, 0, sizeof(struct regset)); + + roff_reset(curp->roff); + + if (curp->mdoc) + mdoc_reset(curp->mdoc); + if (curp->man) + man_reset(curp->man); + + curp->file_status = MANDOCLEVEL_OK; + curp->mdoc = NULL; + curp->man = NULL; +} + +void +mparse_free(struct mparse *curp) +{ + + if (curp->pmdoc) + mdoc_free(curp->pmdoc); + if (curp->pman) + man_free(curp->pman); + if (curp->roff) + roff_free(curp->roff); + + free(curp); +} + +void +mparse_result(struct mparse *curp, struct mdoc **mdoc, struct man **man) +{ + + if (mdoc) + *mdoc = curp->mdoc; + if (man) + *man = curp->man; +} + +void +mandoc_vmsg(enum mandocerr t, struct mparse *m, + int ln, int pos, const char *fmt, ...) +{ + char buf[256]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf) - 1, fmt, ap); + va_end(ap); + + mandoc_msg(t, m, ln, pos, buf); +} + +void +mandoc_msg(enum mandocerr er, struct mparse *m, + int ln, int col, const char *msg) +{ + enum mandoclevel level; + + level = MANDOCLEVEL_FATAL; + while (er < mandoclimits[level]) + level--; + + if (level < m->wlevel) + return; + + if (m->mmsg) + (*m->mmsg)(er, level, m->file, ln, col, msg); + + if (m->file_status < level) + m->file_status = level; +} + +const char * +mparse_strerror(enum mandocerr er) +{ + + return(mandocerrs[er]); +} + +const char * +mparse_strlevel(enum mandoclevel lvl) +{ + return(mandoclevels[lvl]); +} diff --git a/contrib/mdocml/roff.3 b/contrib/mdocml/roff.3 deleted file mode 100644 index 7d8bff5c1b..0000000000 --- a/contrib/mdocml/roff.3 +++ /dev/null @@ -1,177 +0,0 @@ -.\" $Id: roff.3,v 1.10 2011/01/01 16:18:39 kristaps Exp $ -.\" -.\" Copyright (c) 2010 Kristaps Dzonsons -.\" -.\" 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. -.\" -.Dd $Mdocdate: January 1 2011 $ -.Dt ROFF 3 -.Os -.Sh NAME -.Nm roff , -.Nm roff_alloc , -.Nm roff_endparse , -.Nm roff_free , -.Nm roff_parseln , -.Nm roff_reset , -.Nm roff_span -.Nd roff macro compiler library -.Sh SYNOPSIS -.In mandoc.h -.In roff.h -.Ft "struct roff *" -.Fo roff_alloc -.Fa "struct regset *regs" -.Fa "void *data" -.Fa "mandocmsg msgs" -.Fc -.Ft void -.Fn roff_endparse "struct roff *roff" -.Ft void -.Fn roff_free "struct roff *roff" -.Ft "enum rofferr" -.Fo roff_parseln -.Fa "struct roff *roff" -.Fa "int line" -.Fa "char **bufp" -.Fa "size_t *bufsz" -.Fa "int pos" -.Fa "int *offs" -.Fc -.Ft void -.Fn roff_reset "struct roff *roff" -.Ft "const struct tbl_span *" -.Fn roff_span "const struct roff *roff" -.Sh DESCRIPTION -The -.Nm -library processes lines of -.Xr roff 7 -input. -.Pp -In general, applications initiate a parsing sequence with -.Fn roff_alloc , -parse each line in a document with -.Fn roff_parseln , -close the parsing session with -.Fn roff_endparse , -and finally free all allocated memory with -.Fn roff_free . -The -.Fn roff_reset -function may be used in order to reset the parser for another input -sequence. -.Pp -The -.Fn roff_parseln -function should be invoked before passing a line into the -.Xr mdoc 3 -or -.Xr man 3 -libraries. -.Pp -See the -.Sx EXAMPLES -section for a full example. -.Sh REFERENCE -This section further defines the -.Sx Types -and -.Sx Functions -available to programmers. -.Ss Types -Functions (see -.Sx Functions ) -may use the following types: -.Bl -ohang -.It Vt "enum rofferr" -Instructions for further processing to the caller of -.Fn roff_parseln . -.It Vt struct roff -An opaque type defined in -.Pa roff.c . -Its values are only used privately within the library. -.It Vt mandocmsg -A function callback type defined in -.Pa mandoc.h . -.El -.Ss Functions -Function descriptions follow: -.Bl -ohang -.It Fn roff_alloc -Allocates a parsing structure. -The -.Fa data -pointer is passed to -.Fa msgs . -Returns NULL on failure. -If non-NULL, the pointer must be freed with -.Fn roff_free . -.It Fn roff_reset -Reset the parser for another parse routine. -After its use, -.Fn roff_parseln -behaves as if invoked for the first time. -.It Fn roff_free -Free all resources of a parser. -The pointer is no longer valid after invocation. -.It Fn roff_parseln -Parse a nil-terminated line of input. -The character array -.Fa bufp -may be modified or reallocated within this function. -In the latter case, -.Fa bufsz -will be modified accordingly. -The -.Fa offs -pointer will be modified if the line start during subsequent processing -of the line is not at the zeroth index. -This line should not contain the trailing newline. -Returns 0 on failure, 1 on success. -.It Fn roff_endparse -Signals that the parse is complete. -.It Fn roff_span -If -.Fn roff_parseln -returned -.Va ROFF_TBL , -return the last parsed table row. -Returns NULL otherwise. -.El -.Sh EXAMPLES -See -.Pa main.c -in the source distribution for an example of usage. -.Sh SEE ALSO -.Xr mandoc 1 , -.Xr man 3 , -.Xr mdoc 3 , -.Xr roff 7 -.Sh AUTHORS -The -.Nm -library was written by -.An Kristaps Dzonsons Aq kristaps@bsd.lv . -.Sh BUGS -The implementation of user-defined strings needs improvement: -.Bl -dash -.It -String values are taken literally and are not interpreted. -.It -Parsing of quoted strings is incomplete. -.It -The stings are stored internally using a singly linked list, -which is fine for small numbers of strings, -but ineffient when handling many strings. -.El diff --git a/contrib/mdocml/roff.7 b/contrib/mdocml/roff.7 index 052edf7874..8f40d96cbe 100644 --- a/contrib/mdocml/roff.7 +++ b/contrib/mdocml/roff.7 @@ -1,4 +1,4 @@ -.\" $Id: roff.7,v 1.23 2011/01/04 23:32:21 kristaps Exp $ +.\" $Id: roff.7,v 1.27 2011/02/09 10:03:02 kristaps Exp $ .\" .\" Copyright (c) 2010 Kristaps Dzonsons .\" Copyright (c) 2010 Ingo Schwarze @@ -15,7 +15,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: January 4 2011 $ +.Dd $Mdocdate: February 9 2011 $ .Dt ROFF 7 .Os .Sh NAME @@ -57,10 +57,6 @@ To produce other characters in the output, use the escape sequences documented in the .Xr mandoc_char 7 manual. -.Pp -All manuals must have -.Ux -line terminators. .Sh REQUEST SYNTAX A request or macro line consists of: .Pp @@ -86,6 +82,38 @@ Thus, the following request lines are all equivalent: \&.ig end \&. ig end .Ed +.Sh MACRO SYNTAX +Macros can be defined by the +.Sx \&de +request. +When called, they follow the same syntax as requests, except that +macro arguments may optionally be quoted by enclosing them +in double quote characters +.Pq Sq \(dq . +To be recognized as the beginning of a quoted argument, the opening +quote character must be preceded by a space character. +.Pp +A quoted argument may contain whitespace, and pairs of double quote +characters +.Pq Sq Qq +resolve to single double quote characters. +A quoted argument extends to the next double quote character that is not +part of a pair, or to the end of the input line, whichever comes earlier. +Leaving out the terminating double quote character at the end of the line +is discouraged. +For clarity, if more arguments follow on the same input line, +it is recommended to follow the terminating double quote character +by a space character; in case the next character after the terminating +double quote character is anything else, it is regarded as the beginning +of the next, unquoted argument. +.Pp +Both in quoted and unquoted arguments, pairs of backslashes +.Pq Sq \e\e +resolve to single backslashes. +In unquoted arguments, space characters can alternatively be included +by preceding them with a backslash +.Pq Sq \e\~ , +but quoting is usually better for clarity. .Sh REQUEST REFERENCE The .Xr mandoc 1 @@ -174,12 +202,9 @@ The macro can be invoked later using the syntax .Pp .D1 Pf . Ar name Op Ar argument Op Ar argument ... .Pp -Arguments are separated by blank characters and can be quoted -using double-quotes -.Pq Sq \(dq -to allow inclusion of blank characters into arguments. -To include the double-quote character into a quoted argument, -escape it from ending the argument by doubling it. +Regarding argument parsing, see +.Sx MACRO SYNTAX +above. .Pp The line invoking the macro will be replaced in the input stream by the @@ -319,6 +344,15 @@ then false is assumed. The syntax of this request is similar to .Sx \&if except that the conditional is missing. +.Ss \&EN +End an equation block. +See +.Sx \&EQ . +.Ss \&EQ +Begin an equation block. +See +.Xr eqn 7 +for a description of the equation language. .Ss \&hy Set automatic hyphenation mode. This line-scoped request is currently ignored. @@ -512,6 +546,16 @@ section with the .Cm \&Sh macro will reset this register. .El +.Ss \&ns +Turn on no-space mode. +This line-scoped request is intended to take no arguments. +Currently, it is ignored including its arguments, +and the number of arguments is not checked. +.Ss \&ps +Change point size. +This line-scoped request is intended to take one numerical argument. +Currently, it is ignored including its arguments, +and the number of arguments is not checked. .Ss \&so Include a source file. Its syntax is as follows: @@ -529,6 +573,10 @@ only accepts relative paths not containing the strings .Qq ../ and .Qq /.. . +.Ss \&ta +Set tab stops. +This line-scoped request can take an arbitrary number of arguments. +Currently, it is ignored including its arguments. .Ss \&tr Output character translation. This request is intended to have one argument, @@ -560,6 +608,19 @@ refers to groff version 1.15. .Pp .Bl -dash -compact .It +In mandoc, the +.Sx \&EQ , +.Sx \&TE , +.Sx \&TS , +and +.Sx \&T& , +macros are considered regular macros. +In all other +.Nm +implementations, these are special macros that must be specified without +spacing between the control character (which must be a period) and the +macro name. +.It The .Cm nS register is only compatible with OpenBSD's groff-1.15. @@ -577,6 +638,7 @@ using the next-line syntax. .El .Sh SEE ALSO .Xr mandoc 1 , +.Xr eqn 7 , .Xr man 7 , .Xr mandoc_char 7 , .Xr mdoc 7 , diff --git a/contrib/mdocml/roff.c b/contrib/mdocml/roff.c index 5053bef514..3aa3972b6d 100644 --- a/contrib/mdocml/roff.c +++ b/contrib/mdocml/roff.c @@ -1,4 +1,4 @@ -/* $Id: roff.c,v 1.120 2011/01/03 23:24:16 schwarze Exp $ */ +/* $Id: roff.c,v 1.130 2011/03/29 09:00:48 kristaps Exp $ */ /* * Copyright (c) 2010, 2011 Kristaps Dzonsons * Copyright (c) 2010, 2011 Ingo Schwarze @@ -28,15 +28,11 @@ #include #include "mandoc.h" -#include "roff.h" #include "libroff.h" #include "libmandoc.h" #define RSTACK_MAX 128 -#define ROFF_CTL(c) \ - ('.' == (c) || '\'' == (c)) - enum rofft { ROFF_ad, ROFF_am, @@ -51,15 +47,21 @@ enum rofft { ROFF_ie, ROFF_if, ROFF_ig, + ROFF_it, ROFF_ne, ROFF_nh, ROFF_nr, + ROFF_ns, + ROFF_ps, ROFF_rm, ROFF_so, + ROFF_ta, ROFF_tr, ROFF_TS, ROFF_TE, ROFF_T_, + ROFF_EQ, + ROFF_EN, ROFF_cblock, ROFF_ccond, /* FIXME: remove this. */ ROFF_USERDEF, @@ -78,9 +80,8 @@ struct roffstr { }; struct roff { + struct mparse *parse; /* parse point */ struct roffnode *last; /* leaf of stack */ - mandocmsg msg; /* err/warn/fatal messages */ - void *data; /* privdata for messages */ enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */ int rstackpos; /* position in rstack */ struct regset *regs; /* read/writable registers */ @@ -89,6 +90,9 @@ struct roff { struct tbl_node *first_tbl; /* first table parsed */ struct tbl_node *last_tbl; /* last table parsed */ struct tbl_node *tbl; /* current table being parsed */ + struct eqn_node *last_eqn; /* last equation parsed */ + struct eqn_node *first_eqn; /* first equation parsed */ + struct eqn_node *eqn; /* current equation being parsed */ }; struct roffnode { @@ -134,18 +138,21 @@ static enum rofferr roff_cond_sub(ROFF_ARGS); static enum rofferr roff_ds(ROFF_ARGS); static enum roffrule roff_evalcond(const char *, int *); static void roff_freestr(struct roff *); +static char *roff_getname(struct roff *, char **, int, int); static const char *roff_getstrn(const struct roff *, const char *, size_t); static enum rofferr roff_line_ignore(ROFF_ARGS); -static enum rofferr roff_line_error(ROFF_ARGS); static enum rofferr roff_nr(ROFF_ARGS); static int roff_res(struct roff *, char **, size_t *, int); +static enum rofferr roff_rm(ROFF_ARGS); static void roff_setstr(struct roff *, const char *, const char *, int); static enum rofferr roff_so(ROFF_ARGS); static enum rofferr roff_TE(ROFF_ARGS); static enum rofferr roff_TS(ROFF_ARGS); +static enum rofferr roff_EQ(ROFF_ARGS); +static enum rofferr roff_EN(ROFF_ARGS); static enum rofferr roff_T_(ROFF_ARGS); static enum rofferr roff_userdef(ROFF_ARGS); @@ -171,15 +178,21 @@ static struct roffmac roffs[ROFF_MAX] = { { "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, { "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, { "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL }, + { "it", roff_line_ignore, NULL, NULL, 0, NULL }, { "ne", roff_line_ignore, NULL, NULL, 0, NULL }, { "nh", roff_line_ignore, NULL, NULL, 0, NULL }, { "nr", roff_nr, NULL, NULL, 0, NULL }, - { "rm", roff_line_error, NULL, NULL, 0, NULL }, + { "ns", roff_line_ignore, NULL, NULL, 0, NULL }, + { "ps", roff_line_ignore, NULL, NULL, 0, NULL }, + { "rm", roff_rm, NULL, NULL, 0, NULL }, { "so", roff_so, NULL, NULL, 0, NULL }, + { "ta", roff_line_ignore, NULL, NULL, 0, NULL }, { "tr", roff_line_ignore, NULL, NULL, 0, NULL }, { "TS", roff_TS, NULL, NULL, 0, NULL }, { "TE", roff_TE, NULL, NULL, 0, NULL }, { "T&", roff_T_, NULL, NULL, 0, NULL }, + { "EQ", roff_EQ, NULL, NULL, 0, NULL }, + { "EN", roff_EN, NULL, NULL, 0, NULL }, { ".", roff_cblock, NULL, NULL, 0, NULL }, { "\\}", roff_ccond, NULL, NULL, 0, NULL }, { NULL, roff_userdef, NULL, NULL, 0, NULL }, @@ -302,15 +315,22 @@ static void roff_free1(struct roff *r) { struct tbl_node *t; + struct eqn_node *e; - while (r->first_tbl) { - t = r->first_tbl; + while (NULL != (t = r->first_tbl)) { r->first_tbl = t->next; tbl_free(t); } r->first_tbl = r->last_tbl = r->tbl = NULL; + while (NULL != (e = r->first_eqn)) { + r->first_eqn = e->next; + eqn_free(e); + } + + r->first_eqn = r->last_eqn = r->eqn = NULL; + while (r->last) roffnode_pop(r); @@ -336,14 +356,13 @@ roff_free(struct roff *r) struct roff * -roff_alloc(struct regset *regs, void *data, const mandocmsg msg) +roff_alloc(struct regset *regs, struct mparse *parse) { struct roff *r; r = mandoc_calloc(1, sizeof(struct roff)); r->regs = regs; - r->msg = msg; - r->data = data; + r->parse = parse; r->rstackpos = -1; roff_hash_init(); @@ -454,7 +473,7 @@ roff_parseln(struct roff *r, int ln, char **bufp, { enum rofft t; enum rofferr e; - int ppos; + int ppos, ctl; /* * Run the reserved-word filter only if we have some reserved @@ -464,30 +483,43 @@ roff_parseln(struct roff *r, int ln, char **bufp, if (r->first_string && ! roff_res(r, bufp, szp, pos)) return(ROFF_REPARSE); + ppos = pos; + ctl = mandoc_getcontrol(*bufp, &pos); + /* * First, if a scope is open and we're not a macro, pass the * text through the macro's filter. If a scope isn't open and * we're not a macro, just let it through. + * Finally, if there's an equation scope open, divert it into it + * no matter our state. */ - if (r->last && ! ROFF_CTL((*bufp)[pos])) { + if (r->last && ! ctl) { t = r->last->tok; assert(roffs[t].text); e = (*roffs[t].text) (r, t, bufp, szp, ln, pos, pos, offs); assert(ROFF_IGN == e || ROFF_CONT == e); - if (ROFF_CONT == e && r->tbl) - return(tbl_read(r->tbl, ln, *bufp, *offs)); - return(e); - } else if ( ! ROFF_CTL((*bufp)[pos])) { + if (ROFF_CONT != e) + return(e); + if (r->eqn) + return(eqn_read(&r->eqn, ln, *bufp, pos)); if (r->tbl) - return(tbl_read(r->tbl, ln, *bufp, *offs)); + return(tbl_read(r->tbl, ln, *bufp, pos)); return(ROFF_CONT); - } + } else if ( ! ctl) { + if (r->eqn) + return(eqn_read(&r->eqn, ln, *bufp, pos)); + if (r->tbl) + return(tbl_read(r->tbl, ln, *bufp, pos)); + return(ROFF_CONT); + } else if (r->eqn) + return(eqn_read(&r->eqn, ln, *bufp, ppos)); /* * If a scope is open, go to the child handler for that macro, * as it may want to preprocess before doing anything with it. + * Don't do so if an equation is open. */ if (r->last) { @@ -495,7 +527,7 @@ roff_parseln(struct roff *r, int ln, char **bufp, assert(roffs[t].sub); return((*roffs[t].sub) (r, t, bufp, szp, - ln, pos, pos, offs)); + ln, ppos, pos, offs)); } /* @@ -504,7 +536,6 @@ roff_parseln(struct roff *r, int ln, char **bufp, * the compilers handle it. */ - ppos = pos; if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos))) return(ROFF_CONT); @@ -520,18 +551,24 @@ roff_endparse(struct roff *r) { if (r->last) - (*r->msg)(MANDOCERR_SCOPEEXIT, r->data, + mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse, r->last->line, r->last->col, NULL); + if (r->eqn) { + mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse, + r->eqn->eqn.line, r->eqn->eqn.pos, NULL); + eqn_end(r->eqn); + r->eqn = NULL; + } + if (r->tbl) { - (*r->msg)(MANDOCERR_SCOPEEXIT, r->data, + mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse, r->tbl->line, r->tbl->pos, NULL); tbl_end(r->tbl); r->tbl = NULL; } } - /* * Parse a roff node's type from the input buffer. This must be in the * form of ".foo xxx" in the usual way. @@ -543,13 +580,7 @@ roff_parse(struct roff *r, const char *buf, int *pos) size_t maclen; enum rofft t; - assert(ROFF_CTL(buf[*pos])); - (*pos)++; - - while (' ' == buf[*pos] || '\t' == buf[*pos]) - (*pos)++; - - if ('\0' == buf[*pos]) + if ('\0' == buf[*pos] || '"' == buf[*pos]) return(ROFF_MAX); mac = buf + *pos; @@ -558,7 +589,8 @@ roff_parse(struct roff *r, const char *buf, int *pos) t = (r->current_string = roff_getstrn(r, mac, maclen)) ? ROFF_USERDEF : roff_hash_find(mac, maclen); - *pos += maclen; + *pos += (int)maclen; + while (buf[*pos] && ' ' == buf[*pos]) (*pos)++; @@ -597,7 +629,7 @@ roff_cblock(ROFF_ARGS) */ if (NULL == r->last) { - (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); + mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); return(ROFF_IGN); } @@ -616,12 +648,12 @@ roff_cblock(ROFF_ARGS) case (ROFF_ig): break; default: - (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); + mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); return(ROFF_IGN); } if ((*bufp)[pos]) - (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL); + mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL); roffnode_pop(r); roffnode_cleanscope(r); @@ -648,7 +680,7 @@ roff_ccond(ROFF_ARGS) { if (NULL == r->last) { - (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); + mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); return(ROFF_IGN); } @@ -660,17 +692,17 @@ roff_ccond(ROFF_ARGS) case (ROFF_if): break; default: - (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); + mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); return(ROFF_IGN); } if (r->last->endspan > -1) { - (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); + mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); return(ROFF_IGN); } if ((*bufp)[pos]) - (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL); + mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL); roffnode_pop(r); roffnode_cleanscope(r); @@ -690,7 +722,7 @@ roff_block(ROFF_ARGS) if (ROFF_ig != tok) { if ('\0' == (*bufp)[pos]) { - (*r->msg)(MANDOCERR_NOARGS, r->data, ln, ppos, NULL); + mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL); return(ROFF_IGN); } @@ -704,7 +736,7 @@ roff_block(ROFF_ARGS) if (ROFF_de == tok) name = *bufp + pos; else - (*r->msg)(MANDOCERR_REQUEST, r->data, ln, ppos, + mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos, roffs[tok].name); while ((*bufp)[pos] && ' ' != (*bufp)[pos]) @@ -754,7 +786,7 @@ roff_block(ROFF_ARGS) r->last->end[(int)sz] = '\0'; if ((*bufp)[pos]) - (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL); + mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL); return(ROFF_IGN); } @@ -777,11 +809,7 @@ roff_block_sub(ROFF_ARGS) */ if (r->last->end) { - i = pos + 1; - while (' ' == (*bufp)[i] || '\t' == (*bufp)[i]) - i++; - - for (j = 0; r->last->end[j]; j++, i++) + for (i = pos, j = 0; r->last->end[j]; j++, i++) if ((*bufp)[i] != r->last->end[j]) break; @@ -792,6 +820,10 @@ roff_block_sub(ROFF_ARGS) roffnode_pop(r); roffnode_cleanscope(r); + while (' ' == (*bufp)[i] || '\t' == (*bufp)[i]) + i++; + + pos = i; if (ROFF_MAX != roff_parse(r, *bufp, &pos)) return(ROFF_RERUN); return(ROFF_IGN); @@ -803,8 +835,8 @@ roff_block_sub(ROFF_ARGS) * pulling it out of the hashtable. */ - ppos = pos; - t = roff_parse(r, *bufp, &pos); + if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos))) + return(ROFF_IGN); /* * Macros other than block-end are only significant @@ -841,7 +873,6 @@ roff_cond_sub(ROFF_ARGS) enum rofft t; enum roffrule rr; - ppos = pos; rr = r->last->rule; /* @@ -934,15 +965,9 @@ static enum rofferr roff_line_ignore(ROFF_ARGS) { - return(ROFF_IGN); -} - -/* ARGSUSED */ -static enum rofferr -roff_line_error(ROFF_ARGS) -{ + if (ROFF_it == tok) + mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos, "it"); - (*r->msg)(MANDOCERR_REQUEST, r->data, ln, ppos, roffs[tok].name); return(ROFF_IGN); } @@ -956,7 +981,7 @@ roff_cond(ROFF_ARGS) /* Stack overflow! */ if (ROFF_ie == tok && r->rstackpos == RSTACK_MAX - 1) { - (*r->msg)(MANDOCERR_MEM, r->data, ln, ppos, NULL); + mandoc_msg(MANDOCERR_MEM, r->parse, ln, ppos, NULL); return(ROFF_ERR); } @@ -987,7 +1012,7 @@ roff_cond(ROFF_ARGS) */ if ('\0' == (*bufp)[pos] && sv != pos) { - (*r->msg)(MANDOCERR_NOARGS, r->data, ln, ppos, NULL); + mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL); return(ROFF_IGN); } @@ -1056,25 +1081,13 @@ roff_ds(ROFF_ARGS) * will have `bar " ' as its value. */ - name = *bufp + pos; + string = *bufp + pos; + name = roff_getname(r, &string, ln, pos); if ('\0' == *name) return(ROFF_IGN); - string = name; - /* Read until end of name. */ - while (*string && ' ' != *string) - string++; - - /* Nil-terminate name. */ - if (*string) - *(string++) = '\0'; - - /* Read past spaces. */ - while (*string && ' ' == *string) - string++; - - /* Read passed initial double-quote. */ - if (*string && '"' == *string) + /* Read past initial double-quote. */ + if ('"' == *string) string++; /* The rest is the value. */ @@ -1087,31 +1100,14 @@ roff_ds(ROFF_ARGS) static enum rofferr roff_nr(ROFF_ARGS) { - const char *key, *val; + const char *key; + char *val; struct reg *rg; - key = &(*bufp)[pos]; + val = *bufp + pos; + key = roff_getname(r, &val, ln, pos); rg = r->regs->regs; - /* Parse register request. */ - while ((*bufp)[pos] && ' ' != (*bufp)[pos]) - pos++; - - /* - * Set our nil terminator. Because this line is going to be - * ignored anyway, we can munge it as we please. - */ - if ((*bufp)[pos]) - (*bufp)[pos++] = '\0'; - - /* Skip whitespace to register token. */ - while ((*bufp)[pos] && ' ' == (*bufp)[pos]) - pos++; - - val = &(*bufp)[pos]; - - /* Process register token. */ - if (0 == strcmp(key, "nS")) { rg[(int)REG_nS].set = 1; if ( ! roff_parse_nat(val, &rg[(int)REG_nS].v.u)) @@ -1121,13 +1117,29 @@ roff_nr(ROFF_ARGS) return(ROFF_IGN); } +/* ARGSUSED */ +static enum rofferr +roff_rm(ROFF_ARGS) +{ + const char *name; + char *cp; + + cp = *bufp + pos; + while ('\0' != *cp) { + name = roff_getname(r, &cp, ln, (int)(cp - *bufp)); + if ('\0' != *name) + roff_setstr(r, name, NULL, 0); + } + return(ROFF_IGN); +} + /* ARGSUSED */ static enum rofferr roff_TE(ROFF_ARGS) { if (NULL == r->tbl) - (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); + mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); else tbl_end(r->tbl); @@ -1141,13 +1153,40 @@ roff_T_(ROFF_ARGS) { if (NULL == r->tbl) - (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL); + mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); else tbl_restart(ppos, ln, r->tbl); return(ROFF_IGN); } +/* ARGSUSED */ +static enum rofferr +roff_EQ(ROFF_ARGS) +{ + struct eqn_node *e; + + assert(NULL == r->eqn); + e = eqn_alloc(ppos, ln); + + if (r->last_eqn) + r->last_eqn->next = e; + else + r->first_eqn = r->last_eqn = e; + + r->eqn = r->last_eqn = e; + return(ROFF_IGN); +} + +/* ARGSUSED */ +static enum rofferr +roff_EN(ROFF_ARGS) +{ + + mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL); + return(ROFF_IGN); +} + /* ARGSUSED */ static enum rofferr roff_TS(ROFF_ARGS) @@ -1155,11 +1194,11 @@ roff_TS(ROFF_ARGS) struct tbl_node *t; if (r->tbl) { - (*r->msg)(MANDOCERR_SCOPEBROKEN, r->data, ln, ppos, NULL); + mandoc_msg(MANDOCERR_SCOPEBROKEN, r->parse, ln, ppos, NULL); tbl_end(r->tbl); } - t = tbl_alloc(ppos, ln, r->data, r->msg); + t = tbl_alloc(ppos, ln, r->parse); if (r->last_tbl) r->last_tbl->next = t; @@ -1176,7 +1215,7 @@ roff_so(ROFF_ARGS) { char *name; - (*r->msg)(MANDOCERR_SO, r->data, ln, ppos, NULL); + mandoc_msg(MANDOCERR_SO, r->parse, ln, ppos, NULL); /* * Handle `so'. Be EXTREMELY careful, as we shouldn't be @@ -1187,7 +1226,7 @@ roff_so(ROFF_ARGS) name = *bufp + pos; if ('/' == *name || strstr(name, "../") || strstr(name, "/..")) { - (*r->msg)(MANDOCERR_SOPATH, r->data, ln, pos, NULL); + mandoc_msg(MANDOCERR_SOPATH, r->parse, ln, pos, NULL); return(ROFF_ERR); } @@ -1210,7 +1249,7 @@ roff_userdef(ROFF_ARGS) cp = *bufp + pos; for (i = 0; i < 9; i++) arg[i] = '\0' == *cp ? "" : - mandoc_getarg(&cp, r->msg, r->data, ln, &pos); + mandoc_getarg(r->parse, &cp, ln, &pos); /* * Expand macro arguments. @@ -1250,6 +1289,39 @@ roff_userdef(ROFF_ARGS) ROFF_REPARSE : ROFF_APPEND); } +static char * +roff_getname(struct roff *r, char **cpp, int ln, int pos) +{ + char *name, *cp; + + name = *cpp; + if ('\0' == *name) + return(name); + + /* Read until end of name. */ + for (cp = name; '\0' != *cp && ' ' != *cp; cp++) { + if ('\\' != *cp) + continue; + cp++; + if ('\\' == *cp) + continue; + mandoc_msg(MANDOCERR_NAMESC, r->parse, ln, pos, NULL); + *cp = '\0'; + name = cp; + } + + /* Nil-terminate name. */ + if ('\0' != *cp) + *(cp++) = '\0'; + + /* Read past spaces. */ + while (' ' == *cp) + cp++; + + *cpp = cp; + return(name); +} + /* * Store *string into the user-defined string called *name. * In multiline mode, append to an existing entry and append '\n'; @@ -1289,7 +1361,7 @@ roff_setstr(struct roff *r, const char *name, const char *string, * One additional byte for the '\n' in multiline mode, * and one for the terminating '\0'. */ - newch = strlen(string) + (multiline ? 2 : 1); + newch = strlen(string) + (multiline ? 2u : 1u); if (NULL == n->string) { n->string = mandoc_malloc(newch); *n->string = '\0'; @@ -1300,7 +1372,7 @@ roff_setstr(struct roff *r, const char *name, const char *string, } /* Skip existing content in the destination buffer. */ - c = n->string + oldch; + c = n->string + (int)oldch; /* Append new content to the destination buffer. */ while (*string) { @@ -1319,7 +1391,6 @@ roff_setstr(struct roff *r, const char *name, const char *string, *c = '\0'; } - static const char * roff_getstrn(const struct roff *r, const char *name, size_t len) { @@ -1332,7 +1403,6 @@ roff_getstrn(const struct roff *r, const char *name, size_t len) return(n ? n->string : NULL); } - static void roff_freestr(struct roff *r) { @@ -1354,3 +1424,10 @@ roff_span(const struct roff *r) return(r->tbl ? tbl_span(r->tbl) : NULL); } + +const struct eqn * +roff_eqn(const struct roff *r) +{ + + return(r->last_eqn ? &r->last_eqn->eqn : NULL); +} diff --git a/contrib/mdocml/roff.h b/contrib/mdocml/roff.h deleted file mode 100644 index 141a469acb..0000000000 --- a/contrib/mdocml/roff.h +++ /dev/null @@ -1,45 +0,0 @@ -/* $Id: roff.h,v 1.22 2011/01/01 16:18:39 kristaps Exp $ */ -/* - * Copyright (c) 2010 Kristaps Dzonsons - * - * 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 ROFF_H -#define ROFF_H - -enum rofferr { - ROFF_CONT, /* continue processing line */ - ROFF_RERUN, /* re-run roff interpreter with offset */ - ROFF_APPEND, /* re-run main parser, appending next line */ - ROFF_REPARSE, /* re-run main parser on the result */ - ROFF_SO, /* include another file */ - ROFF_IGN, /* ignore current line */ - ROFF_TBL, /* a table row was successfully parsed */ - ROFF_ERR /* badness: puke and stop */ -}; - -__BEGIN_DECLS - -struct roff; - -void roff_free(struct roff *); -struct roff *roff_alloc(struct regset *, void *, mandocmsg); -void roff_reset(struct roff *); -enum rofferr roff_parseln(struct roff *, int, - char **, size_t *, int, int *); -void roff_endparse(struct roff *); -const struct tbl_span *roff_span(const struct roff *); - -__END_DECLS - -#endif /*!ROFF_H*/ diff --git a/contrib/mdocml/st.c b/contrib/mdocml/st.c index 5c6798e585..70c21a269e 100644 --- a/contrib/mdocml/st.c +++ b/contrib/mdocml/st.c @@ -1,4 +1,4 @@ -/* $Id: st.c,v 1.8 2010/06/19 20:46:28 kristaps Exp $ */ +/* $Id: st.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons * @@ -22,6 +22,7 @@ #include #include +#include "mdoc.h" #include "mandoc.h" #include "libmdoc.h" diff --git a/contrib/mdocml/style.css b/contrib/mdocml/style.css index 4fb1b5d802..b51c72191c 100644 --- a/contrib/mdocml/style.css +++ b/contrib/mdocml/style.css @@ -1,4 +1,4 @@ -/* $Id: style.css,v 1.20 2010/12/24 22:51:13 kristaps Exp $ */ +/* $Id: style.css,v 1.21 2011/02/09 09:52:47 kristaps Exp $ */ html { max-width: 800px; } body { color: #333333; @@ -30,23 +30,18 @@ h2 { margin-bottom: 0px; color: #000000; font-size: 0.93em; margin-left: -2ex; div.section { margin-bottom: 2ex; margin-left: 4ex; } /* Sections (Sh, SH). */ div.subsection { } /* Sub-sections (Ss, SS). */ table.synopsis { } /* SYNOPSIS section table. */ -table.synopsis td { vertical-align: top; } /* SYNOPSIS section table. */ /* Vertical spacing. */ p { } /* Paragraph: Pp, Lp. */ blockquote { margin-top: 0px; margin-bottom: 0px; } table { margin-top: 0px; margin-bottom: 0px; } +td { vertical-align: top; } /* SYNOPSIS section table. */ /* General font modes. */ -.lit { font-family: monospace; font-style: normal; font-weight: normal; } /* Literal: Dl, Li, Bf -literal, Bl -literal, Bl -unfilled. */ -.italic { font-style: italic; font-weight: normal; } /* Italic: BI, IB, I, (implicit). */ .emph { font-style: italic; font-weight: normal; } /* Emphasis: Em, Bl -emphasis. */ -.bold { font-style: normal; font-weight: bold; } /* Bold: SB, BI, IB, BR, RB, B, (implicit). */ .symb { font-style: normal; font-weight: bold; } /* Symbolic: Sy, Ms, Bf -symbolic. */ -.roman { font-style: normal; font-weight: normal; } /* Roman: (implicit). */ -.small { font-style: normal; font-weight: normal; font-size: smaller; } /* Small: SB, SM. */ /* Block modes. */ @@ -75,6 +70,8 @@ b.fname { font-style: normal; } /* Function name (Fa, Fn, Rv). */ i.ftype { font-weight: normal; } /* Function types (Ft, Fn). */ b.includes { font-style: normal; } /* Header includes (In). */ span.lib { } /* Library (Lb). */ +i.link-sec { font-weight: normal; } /* Section links (Sx). */ +code.lit { font-style: normal; font-weight: normal; } /* Literal: Dl, Li, Bf -literal, Bl -literal, Bl -unfilled. */ b.macro { font-style: normal; } /* Macro-ish thing (Fd). */ b.name { color: blue; font-style: normal; } /* Name of utility (Nm). */ span.opt { } /* Options (Op, Oo/Oc). */ @@ -144,3 +141,11 @@ li.list-item { } ol.list-enum { padding-left: 2em; } li.list-enum { } + +/* Equation modes. See eqn(7). */ + +span.eqn { } + +/* Table modes. See tbl(7). */ + +table.tbl { } diff --git a/contrib/mdocml/tbl.7 b/contrib/mdocml/tbl.7 index 3c7f0c6100..52039bf0e8 100644 --- a/contrib/mdocml/tbl.7 +++ b/contrib/mdocml/tbl.7 @@ -1,6 +1,6 @@ -.\" $Id: tbl.7,v 1.4 2011/01/07 14:59:52 kristaps Exp $ +.\" $Id: tbl.7,v 1.13 2011/03/17 15:12:42 kristaps Exp $ .\" -.\" Copyright (c) 2010 Kristaps Dzonsons +.\" Copyright (c) 2010, 2011 Kristaps Dzonsons .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -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: January 7 2011 $ +.Dd $Mdocdate: March 17 2011 $ .Dt TBL 7 .Os .Sh NAME @@ -69,6 +69,13 @@ c5 c5 c5. 4:5:6 .TE .Ed +.Pp +The +.Nm +implementation in +.Xr mandoc 1 +is +.Ud .Sh TABLE STRUCTURE Tables are enclosed by the .Sq TS @@ -180,8 +187,6 @@ Accepts a single-character argument. This character will be used as the decimal point with the .Cm n layout key. -This option is not supported by -.Xr mandoc 1 . .It Cm nospaces This option is not supported by .Xr mandoc 1 . @@ -205,18 +210,29 @@ Right-justify a literal string within its column. .It Cm l Left-justify a literal string within its column. .It Cm n -Justify a number around its decimal point. +Justify a number around its last decimal point. If the decimal point is not found on the number, it's assumed to trail the number. .It Cm s +Horizontally span columns from the last +.No non- Ns Cm s +data cell. +It is an error if spanning columns follow a +.Cm \- +or +.Cm \(ba +cell, or come first. This option is not supported by .Xr mandoc 1 . .It Cm a -This option is not supported by -.Xr mandoc 1 . +Left-justify a literal string and pad with one space. .It Cm ^ -This option is not supported by -.Xr mandoc 1 . +Vertically span rows from the last +.No non- Ns Cm ^ +data cell. +It is an error to invoke a vertical span on the first layout row. +Unlike a horizontal spanner, you must specify an empty cell (if it not +empty, the data is discarded) in the corresponding data cell. .It Cm \- Replace the data cell (its contents will be lost) with a single horizontal line. @@ -231,16 +247,9 @@ Emit a vertical bar instead of data. Emit a double-vertical bar instead of data. .El .Pp -For example, the following layout specifies a centre-justified column of -minimum width 10, followed by vertical bar, followed by a left-justified -column of minimum width 10, another vertical bar, then a column -justified about the decimal point in numbers: -.Pp -.Dl c10 | l10 | n -.Pp Keys may be followed by a set of modifiers. A modifier is either a modifier key or a natural number for specifying -spacing. +the minimum width of a column. The following case-insensitive modifier keys are available: .Cm z , .Cm u , @@ -255,6 +264,13 @@ and .Cm i . All of these are ignored by .Xr mandoc 1 . +.Pp +For example, the following layout specifies a centre-justified column of +minimum width 10, followed by vertical bar, followed by a left-justified +column of minimum width 10, another vertical bar, then a column +justified about the decimal point in numbers: +.Pp +.Dl c10 | l10 | n .Ss Data The data section follows the last layout row. By default, cells in a data section are delimited by a tab. diff --git a/contrib/mdocml/tbl.c b/contrib/mdocml/tbl.c index ba591ceb6e..9b331e86bf 100644 --- a/contrib/mdocml/tbl.c +++ b/contrib/mdocml/tbl.c @@ -1,6 +1,7 @@ -/* $Id: tbl.c,v 1.21 2011/01/04 15:02:00 kristaps Exp $ */ +/* $Id: tbl.c,v 1.24 2011/03/22 09:48:13 kristaps Exp $ */ /* - * Copyright (c) 2009, 2010 Kristaps Dzonsons + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2011 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -21,7 +22,6 @@ #include #include "mandoc.h" -#include "roff.h" #include "libmandoc.h" #include "libroff.h" @@ -66,15 +66,14 @@ tbl_read(struct tbl_node *tbl, int ln, const char *p, int offs) } struct tbl_node * -tbl_alloc(int pos, int line, void *data, const mandocmsg msg) +tbl_alloc(int pos, int line, struct mparse *parse) { struct tbl_node *p; p = mandoc_calloc(1, sizeof(struct tbl_node)); p->line = line; p->pos = pos; - p->data = data; - p->msg = msg; + p->parse = parse; p->part = TBL_PART_OPTS; p->opts.tab = '\t'; p->opts.linesize = 12; @@ -125,22 +124,29 @@ void tbl_restart(int line, int pos, struct tbl_node *tbl) { if (TBL_PART_CDATA == tbl->part) - TBL_MSG(tbl, MANDOCERR_TBLBLOCK, tbl->line, tbl->pos); + mandoc_msg(MANDOCERR_TBLBLOCK, tbl->parse, + tbl->line, tbl->pos, NULL); tbl->part = TBL_PART_LAYOUT; tbl->line = line; tbl->pos = pos; if (NULL == tbl->first_span || NULL == tbl->first_span->first) - TBL_MSG(tbl, MANDOCERR_TBLNODATA, tbl->line, tbl->pos); + mandoc_msg(MANDOCERR_TBLNODATA, tbl->parse, + tbl->line, tbl->pos, NULL); } const struct tbl_span * -tbl_span(const struct tbl_node *tbl) +tbl_span(struct tbl_node *tbl) { + struct tbl_span *span; assert(tbl); - return(tbl->last_span); + span = tbl->current_span ? tbl->current_span->next + : tbl->first_span; + if (span) + tbl->current_span = span; + return(span); } void @@ -148,12 +154,14 @@ tbl_end(struct tbl_node *tbl) { if (NULL == tbl->first_span || NULL == tbl->first_span->first) - TBL_MSG(tbl, MANDOCERR_TBLNODATA, tbl->line, tbl->pos); + mandoc_msg(MANDOCERR_TBLNODATA, tbl->parse, + tbl->line, tbl->pos, NULL); if (tbl->last_span) tbl->last_span->flags |= TBL_SPAN_LAST; if (TBL_PART_CDATA == tbl->part) - TBL_MSG(tbl, MANDOCERR_TBLBLOCK, tbl->line, tbl->pos); + mandoc_msg(MANDOCERR_TBLBLOCK, tbl->parse, + tbl->line, tbl->pos, NULL); } diff --git a/contrib/mdocml/tbl_data.c b/contrib/mdocml/tbl_data.c index f53e109952..129695d8bb 100644 --- a/contrib/mdocml/tbl_data.c +++ b/contrib/mdocml/tbl_data.c @@ -1,6 +1,7 @@ -/* $Id: tbl_data.c,v 1.14 2011/01/07 14:59:52 kristaps Exp $ */ +/* $Id: tbl_data.c,v 1.24 2011/03/20 16:02:05 kristaps Exp $ */ /* - * Copyright (c) 2009, 2010 Kristaps Dzonsons + * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2011 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -28,8 +29,10 @@ #include "libmandoc.h" #include "libroff.h" -static int data(struct tbl_node *, struct tbl_span *, - int, const char *, int *); +static int data(struct tbl_node *, struct tbl_span *, + int, const char *, int *); +static struct tbl_span *newspan(struct tbl_node *, int, + struct tbl_row *); static int data(struct tbl_node *tbl, struct tbl_span *dp, @@ -37,7 +40,7 @@ data(struct tbl_node *tbl, struct tbl_span *dp, { struct tbl_dat *dat; struct tbl_cell *cp; - int sv; + int sv, spans; cp = NULL; if (dp->last && dp->last->layout) @@ -55,12 +58,33 @@ data(struct tbl_node *tbl, struct tbl_span *dp, TBL_CELL_SPAN == cp->pos)) cp = cp->next; + /* + * Stop processing when we reach the end of the available layout + * cells. This means that we have extra input. + */ + + if (NULL == cp) { + mandoc_msg(MANDOCERR_TBLEXTRADAT, + tbl->parse, ln, *pos, NULL); + /* Skip to the end... */ + while (p[*pos]) + (*pos)++; + return(1); + } + dat = mandoc_calloc(1, sizeof(struct tbl_dat)); dat->layout = cp; dat->pos = TBL_DATA_NONE; - if (NULL == dat->layout) - TBL_MSG(tbl, MANDOCERR_TBLEXTRADAT, ln, *pos); + assert(TBL_CELL_SPAN != cp->pos); + + for (spans = 0, cp = cp->next; cp; cp = cp->next) + if (TBL_CELL_SPAN == cp->pos) + spans++; + else + break; + + dat->spans = spans; if (dp->last) { dp->last->next = dat; @@ -83,8 +107,10 @@ data(struct tbl_node *tbl, struct tbl_span *dp, return(0); } - dat->string = mandoc_malloc(*pos - sv + 1); - memcpy(dat->string, &p[sv], *pos - sv); + assert(*pos - sv >= 0); + + dat->string = mandoc_malloc((size_t)(*pos - sv + 1)); + memcpy(dat->string, &p[sv], (size_t)(*pos - sv)); dat->string[*pos - sv] = '\0'; if (p[*pos]) @@ -101,13 +127,12 @@ data(struct tbl_node *tbl, struct tbl_span *dp, else dat->pos = TBL_DATA_DATA; - if (NULL == dat->layout) - return(1); - if (TBL_CELL_HORIZ == dat->layout->pos || - TBL_CELL_DHORIZ == dat->layout->pos) + TBL_CELL_DHORIZ == dat->layout->pos || + TBL_CELL_DOWN == dat->layout->pos) if (TBL_DATA_DATA == dat->pos && '\0' != *dat->string) - TBL_MSG(tbl, MANDOCERR_TBLIGNDATA, ln, sv); + mandoc_msg(MANDOCERR_TBLIGNDATA, + tbl->parse, ln, sv, NULL); return(1); } @@ -123,7 +148,6 @@ tbl_cdata(struct tbl_node *tbl, int ln, const char *p) pos = 0; dat = tbl->last_span->last; - dat->pos = TBL_DATA_DATA; if (p[pos] == 'T' && p[pos + 1] == '}') { pos += 2; @@ -139,6 +163,8 @@ tbl_cdata(struct tbl_node *tbl, int ln, const char *p) /* Fallthrough: T} is part of a word. */ } + dat->pos = TBL_DATA_DATA; + if (dat->string) { sz = strlen(p) + strlen(dat->string) + 2; dat->string = mandoc_realloc(dat->string, sz); @@ -147,9 +173,36 @@ tbl_cdata(struct tbl_node *tbl, int ln, const char *p) } else dat->string = mandoc_strdup(p); + if (TBL_CELL_DOWN == dat->layout->pos) + mandoc_msg(MANDOCERR_TBLIGNDATA, + tbl->parse, ln, pos, NULL); + return(0); } +static struct tbl_span * +newspan(struct tbl_node *tbl, int line, struct tbl_row *rp) +{ + struct tbl_span *dp; + + dp = mandoc_calloc(1, sizeof(struct tbl_span)); + dp->line = line; + dp->tbl = &tbl->opts; + dp->layout = rp; + dp->head = tbl->first_head; + + if (tbl->last_span) { + tbl->last_span->next = dp; + tbl->last_span = dp; + } else { + tbl->last_span = tbl->first_span = dp; + tbl->current_span = NULL; + dp->flags |= TBL_SPAN_FIRST; + } + + return(dp); +} + int tbl_data(struct tbl_node *tbl, int ln, const char *p) { @@ -160,37 +213,48 @@ tbl_data(struct tbl_node *tbl, int ln, const char *p) pos = 0; if ('\0' == p[pos]) { - TBL_MSG(tbl, MANDOCERR_TBL, ln, pos); + mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, pos, NULL); return(0); } /* * Choose a layout row: take the one following the last parsed * span's. If that doesn't exist, use the last parsed span's. - * If there's no last parsed span, use the first row. This can - * be NULL! + * If there's no last parsed span, use the first row. Lastly, + * if the last span was a horizontal line, use the same layout + * (it doesn't "consume" the layout). */ if (tbl->last_span) { assert(tbl->last_span->layout); - rp = tbl->last_span->layout->next; + if (tbl->last_span->pos == TBL_SPAN_DATA) { + for (rp = tbl->last_span->layout->next; + rp && rp->first; rp = rp->next) { + switch (rp->first->pos) { + case (TBL_CELL_HORIZ): + dp = newspan(tbl, ln, rp); + dp->pos = TBL_SPAN_HORIZ; + continue; + case (TBL_CELL_DHORIZ): + dp = newspan(tbl, ln, rp); + dp->pos = TBL_SPAN_DHORIZ; + continue; + default: + break; + } + break; + } + } else + rp = tbl->last_span->layout; + if (NULL == rp) rp = tbl->last_span->layout; } else rp = tbl->first_row; - dp = mandoc_calloc(1, sizeof(struct tbl_span)); - dp->tbl = &tbl->opts; - dp->layout = rp; - dp->head = tbl->first_head; + assert(rp); - if (tbl->last_span) { - tbl->last_span->next = dp; - tbl->last_span = dp; - } else { - tbl->last_span = tbl->first_span = dp; - dp->flags |= TBL_SPAN_FIRST; - } + dp = newspan(tbl, ln, rp); if ( ! strcmp(p, "_")) { dp->pos = TBL_SPAN_HORIZ; diff --git a/contrib/mdocml/tbl_html.c b/contrib/mdocml/tbl_html.c index 7594dfc961..68d3f9c534 100644 --- a/contrib/mdocml/tbl_html.c +++ b/contrib/mdocml/tbl_html.c @@ -1,4 +1,4 @@ -/* $Id: tbl_html.c,v 1.5 2011/01/06 12:31:39 kristaps Exp $ */ +/* $Id: tbl_html.c,v 1.7 2011/01/13 14:30:13 kristaps Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons * @@ -27,6 +27,7 @@ #include "out.h" #include "html.h" +static void html_tblopen(struct html *, const struct tbl_span *); static size_t html_tbl_len(size_t, void *); static size_t html_tbl_strlen(const char *, void *); @@ -46,81 +47,105 @@ html_tbl_strlen(const char *p, void *arg) return(strlen(p)); } +static void +html_tblopen(struct html *h, const struct tbl_span *sp) +{ + const struct tbl_head *hp; + struct htmlpair tag; + struct roffsu su; + struct roffcol *col; + + if (TBL_SPAN_FIRST & sp->flags) { + h->tbl.len = html_tbl_len; + h->tbl.slen = html_tbl_strlen; + tblcalc(&h->tbl, sp); + } + + assert(NULL == h->tblt); + PAIR_CLASS_INIT(&tag, "tbl"); + h->tblt = print_otag(h, TAG_TABLE, 1, &tag); + + for (hp = sp->head; hp; hp = hp->next) { + bufinit(h); + col = &h->tbl.cols[hp->ident]; + SCALE_HS_INIT(&su, col->width); + bufcat_su(h, "width", &su); + PAIR_STYLE_INIT(&tag, h); + print_otag(h, TAG_COL, 1, &tag); + } + + print_otag(h, TAG_TBODY, 0, NULL); +} + +void +print_tblclose(struct html *h) +{ + + assert(h->tblt); + print_tagq(h, h->tblt); + h->tblt = NULL; +} + void print_tbl(struct html *h, const struct tbl_span *sp) { const struct tbl_head *hp; const struct tbl_dat *dp; - struct tag *tt; struct htmlpair tag; - struct roffsu su; - struct roffcol *col; + struct tag *tt; /* Inhibit printing of spaces: we do padding ourselves. */ + if (NULL == h->tblt) + html_tblopen(h, sp); + + assert(h->tblt); + h->flags |= HTML_NONOSPACE; h->flags |= HTML_NOSPACE; - /* First pass: calculate widths. */ - - if (TBL_SPAN_FIRST & sp->flags) { - h->tbl.len = html_tbl_len; - h->tbl.slen = html_tbl_strlen; - tblcalc(&h->tbl, sp); - } + tt = print_otag(h, TAG_TR, 0, NULL); switch (sp->pos) { case (TBL_SPAN_HORIZ): /* FALLTHROUGH */ case (TBL_SPAN_DHORIZ): + PAIR_INIT(&tag, ATTR_COLSPAN, "0"); + print_otag(h, TAG_TD, 1, &tag); break; default: - PAIR_CLASS_INIT(&tag, "tbl"); - print_otag(h, TAG_TABLE, 1, &tag); - print_otag(h, TAG_TR, 0, NULL); - - /* Iterate over template headers. */ - dp = sp->first; for (hp = sp->head; hp; hp = hp->next) { + print_stagq(h, tt); + print_otag(h, TAG_TD, 0, NULL); + switch (hp->pos) { case (TBL_HEAD_VERT): /* FALLTHROUGH */ case (TBL_HEAD_DVERT): continue; case (TBL_HEAD_DATA): + if (NULL == dp) + break; + if (TBL_CELL_DOWN != dp->layout->pos) + if (dp->string) + print_text(h, dp->string); + dp = dp->next; break; } - - /* - * For the time being, use the simplest possible - * table styling: setting the widths of data - * columns. - */ - - col = &h->tbl.cols[hp->ident]; - SCALE_HS_INIT(&su, col->width); - bufcat_su(h, "width", &su); - PAIR_STYLE_INIT(&tag, h); - tt = print_otag(h, TAG_TD, 1, &tag); - - if (dp && dp->string) - print_text(h, dp->string); - if (dp) - dp = dp->next; - - print_tagq(h, tt); } break; } - h->flags &= ~HTML_NONOSPACE; + print_tagq(h, tt); - /* Close out column specifiers on the last span. */ + h->flags &= ~HTML_NONOSPACE; if (TBL_SPAN_LAST & sp->flags) { assert(h->tbl.cols); free(h->tbl.cols); h->tbl.cols = NULL; + print_tblclose(h); } + } diff --git a/contrib/mdocml/tbl_layout.c b/contrib/mdocml/tbl_layout.c index fc03086bec..8245003b1d 100644 --- a/contrib/mdocml/tbl_layout.c +++ b/contrib/mdocml/tbl_layout.c @@ -1,4 +1,4 @@ -/* $Id: tbl_layout.c,v 1.12 2011/01/07 14:59:52 kristaps Exp $ */ +/* $Id: tbl_layout.c,v 1.17 2011/03/20 16:02:05 kristaps Exp $ */ /* * Copyright (c) 2009, 2010 Kristaps Dzonsons * @@ -100,7 +100,8 @@ mod: (*pos)++; goto mod; } - TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos); + mandoc_msg(MANDOCERR_TBLLAYOUT, + tbl->parse, ln, *pos, NULL); return(0); } @@ -117,12 +118,13 @@ mod: /* No greater than 4 digits. */ if (4 == i) { - TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos); + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, + ln, *pos, NULL); return(0); } *pos += i; - cp->spacing = atoi(buf); + cp->spacing = (size_t)atoi(buf); goto mod; /* NOTREACHED */ @@ -130,7 +132,7 @@ mod: /* TODO: GNU has many more extensions. */ - switch (tolower(p[(*pos)++])) { + switch (tolower((unsigned char)p[(*pos)++])) { case ('z'): cp->flags |= TBL_CELL_WIGN; goto mod; @@ -156,11 +158,12 @@ mod: (*pos)--; break; default: - TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos - 1); + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, + ln, *pos - 1, NULL); return(0); } - switch (tolower(p[(*pos)++])) { + switch (tolower((unsigned char)p[(*pos)++])) { case ('b'): cp->flags |= TBL_CELL_BOLD; goto mod; @@ -171,7 +174,8 @@ mod: break; } - TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos - 1); + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, + ln, *pos - 1, NULL); return(0); } @@ -185,11 +189,12 @@ cell(struct tbl_node *tbl, struct tbl_row *rp, /* Parse the column position (`r', `R', `|', ...). */ for (i = 0; i < KEYS_MAX; i++) - if (tolower(p[*pos]) == keys[i].name) + if (tolower((unsigned char)p[*pos]) == keys[i].name) break; if (KEYS_MAX == i) { - TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos); + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, + ln, *pos, NULL); return(0); } @@ -197,11 +202,38 @@ cell(struct tbl_node *tbl, struct tbl_row *rp, /* * If a span cell is found first, raise a warning and abort the - * parse. FIXME: recover from this somehow? + * parse. If a span cell is found and the last layout element + * isn't a "normal" layout, bail. + * + * FIXME: recover from this somehow? + */ + + if (TBL_CELL_SPAN == c) { + if (NULL == rp->first) { + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, + ln, *pos, NULL); + return(0); + } else if (rp->last) + switch (rp->last->pos) { + case (TBL_CELL_VERT): + case (TBL_CELL_DVERT): + case (TBL_CELL_HORIZ): + case (TBL_CELL_DHORIZ): + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, + ln, *pos, NULL); + return(0); + default: + break; + } + } + + /* + * If a vertical spanner is found, we may not be in the first + * row. */ - if (NULL == rp->first && TBL_CELL_SPAN == c) { - TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos); + if (TBL_CELL_DOWN == c && rp == tbl->first_row) { + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, ln, *pos, NULL); return(0); } @@ -219,7 +251,7 @@ cell(struct tbl_node *tbl, struct tbl_row *rp, if (rp->last && (TBL_CELL_VERT == c || TBL_CELL_DVERT == c) && (TBL_CELL_VERT == rp->last->pos || TBL_CELL_DVERT == rp->last->pos)) { - TBL_MSG(tbl, MANDOCERR_TBLLAYOUT, ln, *pos - 1); + mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, ln, *pos - 1, NULL); return(0); } @@ -260,7 +292,8 @@ cell: if ('.' == p[*pos]) { tbl->part = TBL_PART_DATA; if (NULL == tbl->first_row) - TBL_MSG(tbl, MANDOCERR_TBLNOLAYOUT, ln, *pos); + mandoc_msg(MANDOCERR_TBLNOLAYOUT, tbl->parse, + ln, *pos, NULL); (*pos)++; return; } diff --git a/contrib/mdocml/tbl_opts.c b/contrib/mdocml/tbl_opts.c index b93886764a..dbdcaa81b7 100644 --- a/contrib/mdocml/tbl_opts.c +++ b/contrib/mdocml/tbl_opts.c @@ -1,4 +1,4 @@ -/* $Id: tbl_opts.c,v 1.7 2011/01/07 13:20:58 kristaps Exp $ */ +/* $Id: tbl_opts.c,v 1.10 2011/03/20 16:02:05 kristaps Exp $ */ /* * Copyright (c) 2009, 2010 Kristaps Dzonsons * @@ -20,6 +20,7 @@ #include #include "mandoc.h" +#include "libmandoc.h" #include "libroff.h" enum tbl_ident { @@ -88,7 +89,8 @@ arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key) /* Arguments always begin with a parenthesis. */ if ('(' != p[*pos]) { - TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos); + mandoc_msg(MANDOCERR_TBL, tbl->parse, + ln, *pos, NULL); return(0); } @@ -103,12 +105,14 @@ arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key) switch (key) { case (KEY_DELIM): if ('\0' == p[(*pos)++]) { - TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos - 1); + mandoc_msg(MANDOCERR_TBL, tbl->parse, + ln, *pos - 1, NULL); return(0); } if ('\0' == p[(*pos)++]) { - TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos - 1); + mandoc_msg(MANDOCERR_TBL, tbl->parse, + ln, *pos - 1, NULL); return(0); } break; @@ -116,7 +120,8 @@ arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key) if ('\0' != (tbl->opts.tab = p[(*pos)++])) break; - TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos - 1); + mandoc_msg(MANDOCERR_TBL, tbl->parse, + ln, *pos - 1, NULL); return(0); case (KEY_LINESIZE): for (i = 0; i < KEY_MAXNUMSZ && p[*pos]; i++, (*pos)++) { @@ -131,13 +136,14 @@ arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key) break; } - (*tbl->msg)(MANDOCERR_TBL, tbl->data, ln, *pos, NULL); + mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos, NULL); return(0); case (KEY_DPOINT): if ('\0' != (tbl->opts.decimal = p[(*pos)++])) break; - TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos - 1); + mandoc_msg(MANDOCERR_TBL, tbl->parse, + ln, *pos - 1, NULL); return(0); default: abort(); @@ -149,7 +155,7 @@ arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key) if (')' == p[(*pos)++]) return(1); - TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos - 1); + mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos - 1, NULL); return(0); } @@ -188,7 +194,7 @@ again: /* /* Copy up to first non-alpha character. */ for (sv = *pos, i = 0; i < KEY_MAXNAME; i++, (*pos)++) { - buf[i] = tolower(p[*pos]); + buf[i] = (char)tolower((unsigned char)p[*pos]); if ( ! isalpha((unsigned char)buf[i])) break; } @@ -196,7 +202,7 @@ again: /* /* Exit if buffer is empty (or overrun). */ if (KEY_MAXNAME == i || 0 == i) { - TBL_MSG(tbl, MANDOCERR_TBL, ln, *pos); + mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos, NULL); return; } @@ -235,7 +241,7 @@ again: /* */ if (KEY_MAXKEYS == i) - TBL_MSG(tbl, MANDOCERR_TBLOPT, ln, sv); + mandoc_msg(MANDOCERR_TBLOPT, tbl->parse, ln, sv, NULL); goto again; /* NOTREACHED */ diff --git a/contrib/mdocml/tbl_term.c b/contrib/mdocml/tbl_term.c index a30e723504..1e567c690e 100644 --- a/contrib/mdocml/tbl_term.c +++ b/contrib/mdocml/tbl_term.c @@ -1,6 +1,7 @@ -/* $Id: tbl_term.c,v 1.13 2011/01/07 14:59:52 kristaps Exp $ */ +/* $Id: tbl_term.c,v 1.19 2011/01/25 12:07:30 schwarze Exp $ */ /* - * Copyright (c) 2009 Kristaps Dzonsons + * Copyright (c) 2009, 2011 Kristaps Dzonsons + * Copyright (c) 2011 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -27,9 +28,6 @@ #include "out.h" #include "term.h" -/* FIXME: `n' modifier doesn't always do the right thing. */ -/* FIXME: `n' modifier doesn't use the cell-spacing buffer. */ - static size_t term_tbl_len(size_t, void *); static size_t term_tbl_strlen(const char *, void *); static void tbl_char(struct termp *, char, size_t); @@ -67,6 +65,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) const struct tbl_head *hp; const struct tbl_dat *dp; struct roffcol *col; + int spans; size_t rmargin, maxrmargin; rmargin = tp->rmargin; @@ -118,23 +117,39 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) case (TBL_SPAN_DATA): /* Iterate over template headers. */ dp = sp->first; + spans = 0; for (hp = sp->head; hp; hp = hp->next) { + /* + * If the current data header is invoked during + * a spanner ("spans" > 0), don't emit anything + * at all. + */ switch (hp->pos) { case (TBL_HEAD_VERT): /* FALLTHROUGH */ case (TBL_HEAD_DVERT): - tbl_vrule(tp, hp); + if (spans <= 0) + tbl_vrule(tp, hp); continue; case (TBL_HEAD_DATA): break; } + if (--spans >= 0) + continue; + col = &tp->tbl.cols[hp->ident]; tbl_data(tp, sp->tbl, dp, col); - /* Go to the next data cell. */ - if (dp) + /* + * Go to the next data cell and assign the + * number of subsequent spans, if applicable. + */ + + if (dp) { + spans = dp->spans; dp = dp->next; + } } break; } @@ -183,6 +198,8 @@ tbl_hrule(struct termp *tp, const struct tbl_span *sp) width = tp->tbl.cols[hp->ident].width; switch (hp->pos) { case (TBL_HEAD_DATA): + if (hp->next) + width += 2; tbl_char(tp, c, width); break; case (TBL_HEAD_DVERT): @@ -247,12 +264,12 @@ tbl_data(struct termp *tp, const struct tbl *tbl, const struct tbl_dat *dp, const struct roffcol *col) { - enum tbl_cellt pos; if (NULL == dp) { tbl_char(tp, ASCII_NBRSP, col->width); return; } + assert(dp->layout); switch (dp->pos) { case (TBL_DATA_NONE): @@ -272,9 +289,7 @@ tbl_data(struct termp *tp, const struct tbl *tbl, break; } - pos = dp && dp->layout ? dp->layout->pos : TBL_CELL_LEFT; - - switch (pos) { + switch (dp->layout->pos) { case (TBL_CELL_HORIZ): tbl_char(tp, '-', col->width); break; @@ -293,6 +308,9 @@ tbl_data(struct termp *tp, const struct tbl *tbl, case (TBL_CELL_NUMBER): tbl_number(tp, tbl, dp, col); break; + case (TBL_CELL_DOWN): + tbl_char(tp, ASCII_NBRSP, col->width); + break; default: abort(); /* NOTREACHED */ @@ -343,39 +361,36 @@ tbl_literal(struct termp *tp, const struct tbl_dat *dp, const struct roffcol *col) { size_t padl, padr, ssz; - enum tbl_cellt pos; - const char *str; padl = padr = 0; - pos = dp && dp->layout ? dp->layout->pos : TBL_CELL_LEFT; - str = dp && dp->string ? dp->string : ""; + assert(dp->string); ssz = term_len(tp, 1); - switch (pos) { + switch (dp->layout->pos) { case (TBL_CELL_LONG): padl = ssz; - padr = col->width - term_strlen(tp, str) - ssz; + padr = col->width - term_strlen(tp, dp->string) - ssz; break; case (TBL_CELL_CENTRE): - padl = col->width - term_strlen(tp, str); - if (padl % 2) - padr++; - padl /= 2; - padr += padl; + padr = col->width - term_strlen(tp, dp->string); + if (3 > padr) + break; + padl = (padr - 1) / 2; + padr -= padl; break; case (TBL_CELL_RIGHT): - padl = col->width - term_strlen(tp, str); + padl = col->width - term_strlen(tp, dp->string); break; default: - padr = col->width - term_strlen(tp, str); + padr = col->width - term_strlen(tp, dp->string); break; } tbl_char(tp, ASCII_NBRSP, padl); - term_word(tp, str); - tbl_char(tp, ASCII_NBRSP, padr); + term_word(tp, dp->string); + tbl_char(tp, ASCII_NBRSP, padr + 2); } static void @@ -385,7 +400,6 @@ tbl_number(struct termp *tp, const struct tbl *tbl, { char *cp; char buf[2]; - const char *str; size_t sz, psz, ssz, d, padl; int i; @@ -394,19 +408,19 @@ tbl_number(struct termp *tp, const struct tbl *tbl, * and the maximum decimal; right-pad by the remaining amount. */ - str = dp && dp->string ? dp->string : ""; + assert(dp->string); - sz = term_strlen(tp, str); + sz = term_strlen(tp, dp->string); buf[0] = tbl->decimal; buf[1] = '\0'; psz = term_strlen(tp, buf); - if (NULL != (cp = strchr(str, tbl->decimal))) { + if (NULL != (cp = strrchr(dp->string, tbl->decimal))) { buf[1] = '\0'; - for (ssz = 0, i = 0; cp != &str[i]; i++) { - buf[0] = str[i]; + for (ssz = 0, i = 0; cp != &dp->string[i]; i++) { + buf[0] = dp->string[i]; ssz += term_strlen(tp, buf); } d = ssz + psz; @@ -419,7 +433,7 @@ tbl_number(struct termp *tp, const struct tbl *tbl, padl = col->decimal - d; tbl_char(tp, ASCII_NBRSP, padl); - term_word(tp, str); + term_word(tp, dp->string); tbl_char(tp, ASCII_NBRSP, col->width - sz - padl); } diff --git a/contrib/mdocml/term.c b/contrib/mdocml/term.c index ba54c31d2a..b0ddd1ed5f 100644 --- a/contrib/mdocml/term.c +++ b/contrib/mdocml/term.c @@ -1,7 +1,7 @@ -/* $Id: term.c,v 1.176 2011/01/04 13:14:26 kristaps Exp $ */ +/* $Id: term.c,v 1.183 2011/04/04 21:14:12 kristaps Exp $ */ /* * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons - * Copyright (c) 2010 Ingo Schwarze + * Copyright (c) 2010, 2011 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -29,7 +29,6 @@ #include #include "mandoc.h" -#include "chars.h" #include "out.h" #include "term.h" #include "main.h" @@ -80,12 +79,7 @@ term_alloc(enum termenc enc) { struct termp *p; - p = calloc(1, sizeof(struct termp)); - if (NULL == p) { - perror(NULL); - exit((int)MANDOCLEVEL_SYSERR); - } - + p = mandoc_calloc(1, sizeof(struct termp)); p->enc = enc; return(p); } @@ -352,6 +346,17 @@ term_vspace(struct termp *p) } +static void +numbered(struct termp *p, const char *word, size_t len) +{ + const char *rhs; + + rhs = chars_num2char(word, len); + if (rhs) + encode(p, rhs, 1); +} + + static void spec(struct termp *p, enum roffdeco d, const char *word, size_t len) { @@ -451,36 +456,10 @@ term_fontpop(struct termp *p) void term_word(struct termp *p, const char *word) { - const char *sv, *seq; + const char *seq; size_t ssz; enum roffdeco deco; - sv = word; - - if (word[0] && '\0' == word[1]) - switch (word[0]) { - case('.'): - /* FALLTHROUGH */ - case(','): - /* FALLTHROUGH */ - case(';'): - /* FALLTHROUGH */ - case(':'): - /* FALLTHROUGH */ - case('?'): - /* FALLTHROUGH */ - case('!'): - /* FALLTHROUGH */ - case(')'): - /* FALLTHROUGH */ - case(']'): - if ( ! (TERMP_IGNDELIM & p->flags)) - p->flags |= TERMP_NOSPACE; - break; - default: - break; - } - if ( ! (TERMP_NOSPACE & p->flags)) { if ( ! (TERMP_KEEP & p->flags)) { if (TERMP_PREKEEP & p->flags) @@ -503,7 +482,7 @@ term_word(struct termp *p, const char *word) if ((ssz = strcspn(word, "\\")) > 0) encode(p, word, ssz); - word += ssz; + word += (int)ssz; if ('\\' != *word) continue; @@ -511,6 +490,9 @@ term_word(struct termp *p, const char *word) word += a2roffdeco(&deco, &seq, &ssz); switch (deco) { + case (DECO_NUMBERED): + numbered(p, seq, ssz); + break; case (DECO_RESERVED): res(p, seq, ssz); break; @@ -538,21 +520,6 @@ term_word(struct termp *p, const char *word) if (DECO_NOSPACE == deco && '\0' == *word) p->flags |= TERMP_NOSPACE; } - - /* - * Note that we don't process the pipe: the parser sees it as - * punctuation, but we don't in terms of typography. - */ - if (sv[0] && '\0' == sv[1]) - switch (sv[0]) { - case('('): - /* FALLTHROUGH */ - case('['): - p->flags |= TERMP_NOSPACE; - break; - default: - break; - } } @@ -565,11 +532,7 @@ adjbuf(struct termp *p, size_t sz) while (sz >= p->maxcols) p->maxcols <<= 2; - p->buf = realloc(p->buf, p->maxcols); - if (NULL == p->buf) { - perror(NULL); - exit((int)MANDOCLEVEL_SYSERR); - } + p->buf = mandoc_realloc(p->buf, p->maxcols); } diff --git a/contrib/mdocml/term_ascii.c b/contrib/mdocml/term_ascii.c index b926a5b378..374a2a02e0 100644 --- a/contrib/mdocml/term_ascii.c +++ b/contrib/mdocml/term_ascii.c @@ -1,4 +1,4 @@ -/* $Id: term_ascii.c,v 1.11 2011/01/02 12:21:07 kristaps Exp $ */ +/* $Id: term_ascii.c,v 1.12 2011/01/25 17:32:04 kristaps Exp $ */ /* * Copyright (c) 2010 Kristaps Dzonsons * @@ -48,8 +48,7 @@ ascii_alloc(char *outopts) const char *toks[2]; char *v; - if (NULL == (p = term_alloc(TERMENC_ASCII))) - return(NULL); + p = term_alloc(TERMENC_ASCII); p->tabwidth = 5; p->defrmargin = 78; diff --git a/contrib/mdocml/term_ps.c b/contrib/mdocml/term_ps.c index fa2f68fe26..233118b819 100644 --- a/contrib/mdocml/term_ps.c +++ b/contrib/mdocml/term_ps.c @@ -1,4 +1,4 @@ -/* $Id: term_ps.c,v 1.45 2010/09/27 23:03:44 schwarze Exp $ */ +/* $Id: term_ps.c,v 1.48 2011/03/17 08:49:34 kristaps Exp $ */ /* * Copyright (c) 2010 Kristaps Dzonsons * @@ -366,14 +366,9 @@ ps_growbuf(struct termp *p, size_t sz) p->engine.ps.psmargsz += sz; - p->engine.ps.psmarg = realloc + p->engine.ps.psmarg = mandoc_realloc (p->engine.ps.psmarg, p->engine.ps.psmargsz); - - if (NULL == p->engine.ps.psmarg) { - perror(NULL); - exit((int)MANDOCLEVEL_SYSERR); - } } static double ps_hspan(const struct termp *, @@ -428,8 +423,7 @@ pspdf_alloc(char *outopts) const char *pp; char *v; - if (NULL == (p = term_alloc(TERMENC_ASCII))) - return(NULL); + p = term_alloc(TERMENC_ASCII); p->advance = ps_advance; p->begin = ps_begin; @@ -789,7 +783,6 @@ ps_begin(struct termp *p) if (TERMTYPE_PS == p->type) { ps_printf(p, "%%!PS-Adobe-3.0\n"); - ps_printf(p, "%%%%Creator: mandoc-%s\n", VERSION); ps_printf(p, "%%%%CreationDate: %s", ctime(&t)); ps_printf(p, "%%%%DocumentData: Clean7Bit\n"); ps_printf(p, "%%%%Orientation: Portrait\n"); @@ -809,7 +802,6 @@ ps_begin(struct termp *p) ps_printf(p, "%%PDF-1.1\n"); pdf_obj(p, 1); ps_printf(p, "<<\n"); - ps_printf(p, "/Creator mandoc-%s\n", VERSION); ps_printf(p, ">>\n"); ps_printf(p, "endobj\n"); diff --git a/contrib/mdocml/tree.c b/contrib/mdocml/tree.c index 70bd73d9ef..fecad80ed9 100644 --- a/contrib/mdocml/tree.c +++ b/contrib/mdocml/tree.c @@ -1,4 +1,4 @@ -/* $Id: tree.c,v 1.31 2011/01/03 13:59:21 kristaps Exp $ */ +/* $Id: tree.c,v 1.37 2011/03/23 12:33:01 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -92,6 +92,9 @@ print_mdoc(const struct mdoc_node *n, int indent) case (MDOC_TBL): t = "tbl"; break; + case (MDOC_EQN): + t = "eqn"; + break; default: abort(); /* NOTREACHED */ @@ -128,6 +131,9 @@ print_mdoc(const struct mdoc_node *n, int indent) break; case (MDOC_TBL): break; + case (MDOC_EQN): + p = n->eqn->data; + break; case (MDOC_ROOT): p = "root"; break; @@ -195,9 +201,15 @@ print_man(const struct man_node *n, int indent) case (MAN_BODY): t = "block-body"; break; + case (MAN_TAIL): + t = "block-tail"; + break; case (MAN_TBL): t = "tbl"; break; + case (MAN_EQN): + t = "eqn"; + break; default: abort(); /* NOTREACHED */ @@ -215,6 +227,8 @@ print_man(const struct man_node *n, int indent) /* FALLTHROUGH */ case (MAN_HEAD): /* FALLTHROUGH */ + case (MAN_TAIL): + /* FALLTHROUGH */ case (MAN_BODY): p = man_macronames[n->tok]; break; @@ -223,6 +237,9 @@ print_man(const struct man_node *n, int indent) break; case (MAN_TBL): break; + case (MAN_EQN): + p = n->eqn->data; + break; default: abort(); /* NOTREACHED */ @@ -254,8 +271,6 @@ print_span(const struct tbl_span *sp, int indent) for (i = 0; i < indent; i++) putchar('\t'); - printf("tbl: "); - switch (sp->pos) { case (TBL_SPAN_HORIZ): putchar('-'); @@ -282,8 +297,14 @@ print_span(const struct tbl_span *sp, int indent) default: break; } - printf("[%s%s]", dp->string, dp->layout ? "" : "*"); - if (dp->next) - putchar(' '); + printf("[\"%s\"", dp->string ? dp->string : ""); + if (dp->spans) + printf("(%d)", dp->spans); + if (NULL == dp->layout) + putchar('*'); + putchar(']'); + putchar(' '); } + + printf("(tbl) %d:1", sp->line); } diff --git a/contrib/mdocml/vol.c b/contrib/mdocml/vol.c index 144d363ff6..3ea7441a42 100644 --- a/contrib/mdocml/vol.c +++ b/contrib/mdocml/vol.c @@ -1,4 +1,4 @@ -/* $Id: vol.c,v 1.8 2010/06/19 20:46:28 kristaps Exp $ */ +/* $Id: vol.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons * @@ -22,6 +22,7 @@ #include #include +#include "mdoc.h" #include "mandoc.h" #include "libmdoc.h"