diff options
author | Garrett D'Amore <garrett@damore.org> | 2014-07-25 14:50:37 -0700 |
---|---|---|
committer | Garrett D'Amore <garrett@damore.org> | 2014-08-02 00:19:34 -0700 |
commit | 698f87a48e2e945bfe5493ce168e0d0ae1cedd5c (patch) | |
tree | 385784d73d5e580be0ffca40abad0dabf0e6084d /usr/src | |
parent | 7f18da4c54210b682e105b0e7be5195c60f98d20 (diff) | |
download | illumos-gate-698f87a48e2e945bfe5493ce168e0d0ae1cedd5c.tar.gz |
5051 import mdocml-1.12.3
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Approved by: Rich Lowe <richlowe@richlowe.net>
Diffstat (limited to 'usr/src')
49 files changed, 4062 insertions, 2437 deletions
diff --git a/usr/src/cmd/mandoc/Makefile.common b/usr/src/cmd/mandoc/Makefile.common index 0969995b72..b1a67b3805 100644 --- a/usr/src/cmd/mandoc/Makefile.common +++ b/usr/src/cmd/mandoc/Makefile.common @@ -29,5 +29,4 @@ preconv_OBJS = preconv.o CFLAGS += $(CC_VERBOSE) CPPFLAGS += -DHAVE_CONFIG_H -DUSE_WCHAR \ - -DOSNAME="\"illumos\"" \ - -DVERSION="\"1.12.1\"" + -DOSNAME="\"illumos\"" diff --git a/usr/src/cmd/mandoc/arch.in b/usr/src/cmd/mandoc/arch.in index 5113446e46..d0c445f308 100644 --- a/usr/src/cmd/mandoc/arch.in +++ b/usr/src/cmd/mandoc/arch.in @@ -1,4 +1,4 @@ -/* $Id: arch.in,v 1.12 2012/01/28 14:02:17 joerg Exp $ */ +/* $Id: arch.in,v 1.14 2013/09/16 22:12:57 schwarze Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -38,9 +38,9 @@ LINE("arm", "ARM") LINE("arm26", "ARM26") LINE("arm32", "ARM32") LINE("armish", "ARMISH") +LINE("armv7", "ARMv7") LINE("aviion", "AViiON") LINE("atari", "ATARI") -LINE("beagle", "Beagle") LINE("bebox", "BeBox") LINE("cats", "cats") LINE("cesfic", "CESFIC") @@ -81,6 +81,7 @@ LINE("netwinder", "NetWinder") LINE("news68k", "NeWS68k") LINE("newsmips", "NeWSMIPS") LINE("next68k", "NeXT68k") +LINE("octeon", "OCTEON") LINE("ofppc", "OFPPC") LINE("palm", "Palm") LINE("pc532", "PC532") diff --git a/usr/src/cmd/mandoc/chars.c b/usr/src/cmd/mandoc/chars.c index ce03347b5d..3ad1f57471 100644 --- a/usr/src/cmd/mandoc/chars.c +++ b/usr/src/cmd/mandoc/chars.c @@ -1,4 +1,4 @@ -/* $Id: chars.c,v 1.52 2011/11/08 00:15:23 kristaps Exp $ */ +/* $Id: chars.c,v 1.54 2013/06/20 22:39:30 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> @@ -37,7 +37,7 @@ struct ln { int unicode; }; -#define LINES_MAX 328 +#define LINES_MAX 329 #define CHAR(in, ch, code) \ { NULL, (in), (ch), (code) }, @@ -77,7 +77,7 @@ mchars_alloc(void) */ tab = mandoc_malloc(sizeof(struct mchars)); - htab = mandoc_calloc(PRINT_HI - PRINT_LO + 1, sizeof(struct ln **)); + htab = mandoc_calloc(PRINT_HI - PRINT_LO + 1, sizeof(struct ln *)); for (i = 0; i < LINES_MAX; i++) { hash = (int)lines[i].code[0] - PRINT_LO; diff --git a/usr/src/cmd/mandoc/chars.in b/usr/src/cmd/mandoc/chars.in index a4c45b3c43..cc6549e7e5 100644 --- a/usr/src/cmd/mandoc/chars.in +++ b/usr/src/cmd/mandoc/chars.in @@ -1,4 +1,4 @@ -/* $Id: chars.in,v 1.42 2011/10/02 10:02:26 kristaps Exp $ */ +/* $Id: chars.in,v 1.43 2013/06/20 22:39:30 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -42,6 +42,7 @@ CHAR("&", "", 0) CHAR("^", "", 0) CHAR("|", "", 0) CHAR("}", "", 0) +CHAR("t", "", 0) /* Accents. */ CHAR("a\"", "\"", 779) diff --git a/usr/src/cmd/mandoc/config.h b/usr/src/cmd/mandoc/config.h index 969e1b49bf..7f4f1edf09 100644 --- a/usr/src/cmd/mandoc/config.h +++ b/usr/src/cmd/mandoc/config.h @@ -7,10 +7,12 @@ #include <stdio.h> +#define VERSION "1.12.3" #define HAVE_STRPTIME #define HAVE_GETSUBOPT #define HAVE_STRLCAT #define HAVE_STRLCPY +#define HAVE_MMAP #include <sys/types.h> @@ -29,14 +31,16 @@ # endif #endif -#if defined(__APPLE__) -# define htobe32(x) OSSwapHostToBigInt32(x) -# define betoh32(x) OSSwapBigToHostInt32(x) -# define htobe64(x) OSSwapHostToBigInt64(x) -# define betoh64(x) OSSwapBigToHostInt64(x) -#elif defined(__linux__) -# define betoh32(x) be32toh(x) -# define betoh64(x) be64toh(x) +#ifndef HAVE_BETOH64 +# if defined(__APPLE__) +# define betoh64(x) OSSwapBigToHostInt64(x) +# define htobe64(x) OSSwapHostToBigInt64(x) +# elif defined(__sun) +# define betoh64(x) BE_64(x) +# define htobe64(x) BE_64(x) +# else +# define betoh64(x) be64toh(x) +# endif #endif #ifndef HAVE_STRLCAT diff --git a/usr/src/cmd/mandoc/html.c b/usr/src/cmd/mandoc/html.c index 326df035fc..9d28b4270e 100644 --- a/usr/src/cmd/mandoc/html.c +++ b/usr/src/cmd/mandoc/html.c @@ -1,7 +1,7 @@ -/* $Id: html.c,v 1.150 2011/10/05 21:35:17 kristaps Exp $ */ +/* $Id: html.c,v 1.152 2013/08/08 20:07:47 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -235,6 +235,9 @@ print_metaf(struct html *h, enum mandoc_esc deco) case (ESCAPE_FONTBOLD): font = HTMLFONT_BOLD; break; + case (ESCAPE_FONTBI): + font = HTMLFONT_BI; + break; case (ESCAPE_FONT): /* FALLTHROUGH */ case (ESCAPE_FONTROMAN): @@ -253,17 +256,27 @@ print_metaf(struct html *h, enum mandoc_esc deco) h->metal = h->metac; h->metac = font; - if (HTMLFONT_NONE != font) - h->metaf = HTMLFONT_BOLD == font ? - print_otag(h, TAG_B, 0, NULL) : - print_otag(h, TAG_I, 0, NULL); + switch (font) { + case (HTMLFONT_ITALIC): + h->metaf = print_otag(h, TAG_I, 0, NULL); + break; + case (HTMLFONT_BOLD): + h->metaf = print_otag(h, TAG_B, 0, NULL); + break; + case (HTMLFONT_BI): + h->metaf = print_otag(h, TAG_B, 0, NULL); + print_otag(h, TAG_I, 0, NULL); + break; + default: + break; + } } int html_strlen(const char *cp) { - int ssz, sz; - const char *seq, *p; + size_t rsz; + int skip, sz; /* * Account for escaped sequences within string length @@ -274,10 +287,21 @@ html_strlen(const char *cp) */ sz = 0; - while (NULL != (p = strchr(cp, '\\'))) { - sz += (int)(p - cp); - ++cp; - switch (mandoc_escape(&cp, &seq, &ssz)) { + skip = 0; + while (1) { + rsz = strcspn(cp, "\\"); + if (rsz) { + cp += rsz; + if (skip) { + skip = 0; + rsz--; + } + sz += rsz; + } + if ('\0' == *cp) + break; + cp++; + switch (mandoc_escape(&cp, NULL, NULL)) { case (ESCAPE_ERROR): return(sz); case (ESCAPE_UNICODE): @@ -285,15 +309,19 @@ html_strlen(const char *cp) case (ESCAPE_NUMBERED): /* FALLTHROUGH */ case (ESCAPE_SPECIAL): - sz++; + if (skip) + skip = 0; + else + sz++; + break; + case (ESCAPE_SKIPCHAR): + skip = 1; break; default: break; } } - - assert(sz >= 0); - return(sz + strlen(cp)); + return(sz); } static int @@ -308,6 +336,12 @@ print_encode(struct html *h, const char *p, int norecurse) nospace = 0; while ('\0' != *p) { + if (HTML_SKIPCHAR & h->flags && '\\' != *p) { + h->flags &= ~HTML_SKIPCHAR; + p++; + continue; + } + sz = strcspn(p, rejs); fwrite(p, 1, sz, stdout); @@ -338,6 +372,33 @@ print_encode(struct html *h, const char *p, int norecurse) break; switch (esc) { + case (ESCAPE_FONT): + /* FALLTHROUGH */ + case (ESCAPE_FONTPREV): + /* FALLTHROUGH */ + case (ESCAPE_FONTBOLD): + /* FALLTHROUGH */ + case (ESCAPE_FONTITALIC): + /* FALLTHROUGH */ + case (ESCAPE_FONTBI): + /* FALLTHROUGH */ + case (ESCAPE_FONTROMAN): + if (0 == norecurse) + print_metaf(h, esc); + continue; + case (ESCAPE_SKIPCHAR): + h->flags |= HTML_SKIPCHAR; + continue; + default: + break; + } + + if (h->flags & HTML_SKIPCHAR) { + h->flags &= ~HTML_SKIPCHAR; + continue; + } + + switch (esc) { case (ESCAPE_UNICODE): /* Skip passed "u" header. */ c = mchars_num2uc(seq + 1, len - 1); @@ -356,19 +417,6 @@ print_encode(struct html *h, const char *p, int norecurse) else if (-1 == c && 1 == len) putchar((int)*seq); break; - case (ESCAPE_FONT): - /* FALLTHROUGH */ - case (ESCAPE_FONTPREV): - /* FALLTHROUGH */ - case (ESCAPE_FONTBOLD): - /* FALLTHROUGH */ - case (ESCAPE_FONTITALIC): - /* FALLTHROUGH */ - case (ESCAPE_FONTROMAN): - if (norecurse) - break; - print_metaf(h, esc); - break; case (ESCAPE_NOSPACE): if ('\0' == *p) nospace = 1; @@ -511,10 +559,20 @@ print_text(struct html *h, const char *word) } assert(NULL == h->metaf); - if (HTMLFONT_NONE != h->metac) - h->metaf = HTMLFONT_BOLD == h->metac ? - print_otag(h, TAG_B, 0, NULL) : - print_otag(h, TAG_I, 0, NULL); + switch (h->metac) { + case (HTMLFONT_ITALIC): + h->metaf = print_otag(h, TAG_I, 0, NULL); + break; + case (HTMLFONT_BOLD): + h->metaf = print_otag(h, TAG_B, 0, NULL); + break; + case (HTMLFONT_BI): + h->metaf = print_otag(h, TAG_B, 0, NULL); + print_otag(h, TAG_I, 0, NULL); + break; + default: + break; + } assert(word); if ( ! print_encode(h, word, 0)) { diff --git a/usr/src/cmd/mandoc/html.h b/usr/src/cmd/mandoc/html.h index 60960702f1..894cfc4cff 100644 --- a/usr/src/cmd/mandoc/html.h +++ b/usr/src/cmd/mandoc/html.h @@ -1,4 +1,4 @@ -/* $Id: html.h,v 1.47 2011/10/05 21:35:17 kristaps Exp $ */ +/* $Id: html.h,v 1.49 2013/08/08 20:07:47 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -75,6 +75,7 @@ enum htmlfont { HTMLFONT_NONE = 0, HTMLFONT_BOLD, HTMLFONT_ITALIC, + HTMLFONT_BI, HTMLFONT_MAX }; @@ -117,6 +118,7 @@ struct html { #define HTML_PREKEEP (1 << 3) #define HTML_NONOSPACE (1 << 4) /* never add spaces */ #define HTML_LITERAL (1 << 5) /* literal (e.g., <PRE>) context */ +#define HTML_SKIPCHAR (1 << 6) /* skip the next character */ struct tagq tags; /* stack of open tags */ struct rofftbl tbl; /* current table */ struct tag *tblt; /* current open table scope */ diff --git a/usr/src/cmd/mandoc/lib.in b/usr/src/cmd/mandoc/lib.in index 1e4567714b..d80f0a293c 100644 --- a/usr/src/cmd/mandoc/lib.in +++ b/usr/src/cmd/mandoc/lib.in @@ -10,9 +10,71 @@ */ /* - * Copyright 2012 Nexenta Systems, Inc. All rights reserved. + * Copyright 2014 Garrett D'Amore <garrett@damore.org> */ /* - * TBD + * Note that we don't document "legacy" libraries that have moved into + * libc. While there will be section 3lib man pages for them, they + * won't be referenced in other man pages. */ +LINE("libadm", "General Administrative Library (libadm, \\-ladm)") +LINE("libbsdmalloc", "BSD Memory Allocation Library (libbsdmalloc, -lbsdmalloc)") +LINE("libbsm", "Security and Auditing Library (libbsm, \\lbsm)") +LINE("libc", "Standard C Library (libc, \\-lc)") +LINE("libc_db", "Threads Debugging Library (libc_db, \\-lc_db)") +LINE("libcfgadm", "Configuration Adminstration Library (libcfgadm, \\-lcfgadm)") +LINE("libcommputil", "Communication Protocol Parser Utilities Library (libpcommutil, \\-lcommputil)") +LINE("libcontract", "Contract Management Library (libcontract, \\-lcontract)") +LINE("libcpc", "CPU Performance Counters Library (libcpc, \\-lcpc)") +LINE("libcurses", "Curses Library (libcurses, \\-lcurses)") +LINE("libdat", "Direct Access Transport Library (libdat, \\-ldat)") +LINE("libdevid", "Device ID Library (libdevid, \\-ldevid)") +LINE("libdevinfo", "Device Information Library (libdevinfo, \\-ldevinfo)") +LINE("libdlpi", "Data Link Provider Interface (DLPI) Library (libdlp, \\-ldlpi)") +LINE("libdns_sd", "DNS Service Discovery Library (libdns_sd, \\-ldns_sd)") +LINE("libelf", "ELF Access Library (libelf, \\-lelf)") +LINE("libexacct", "Extended Accounting File Access Library (libexacct, \\-lexacct)") +LINE("libfcoe", "FCoE Port Management Library (libfcoe, \\-lfcoe)") +LINE("libfstyp", "File System Type Identification Library (libfstyp, \\-lfstyp \\-lnvpair)") +LINE("libgen", "String Pattern Matching Library (libgen, \\-lgen)") +LINE("libgss", "Generic Security Services Library (libgss, \\-lgss)") +LINE("libiscsit", "iSCSI Management Library (libiscsit, \\-liscsit)") +LINE("libkstat", "Kernel Statistics Library (libkstat, \\-lkstat)") +LINE("libkvm", "Kernel VM Library (libkvm, \\-lkvm)") +LINE("libldap", "LDAP Library (libldap, \\-lldap)") +LINE("liblgrp", "Locality Group Library (liblgrp, -llgrp)") +LINE("libm", "Mathematical Library (libm, -lm)") +LINE("libmail", "User Mailbox Library (libmail, -lmail)") +LINE("libmalloc", "Memory Allocation Library (libmalloc, -lmalloc)") +LINE("libmd", "Message Digest Library (libmd, -lmd)") +LINE("libmp", "Multiple Precision Library (libmp, -lmp)") +LINE("libmpapi", "Common Multipath Management Library (libmpapi, -lMPAPI)") +LINE("libnsl", "Network Services Library (libnsl, \\-lnsl)") +LINE("libnvpair", "Name-Value Pair Library (libnvpair, \\-lnvpair)") +LINE("libpam", "PAM (Pluggable Authentication Module) Library (libpam, \\-lpam)") +LINE("libpicl", "PICL Library (libpicl, \\-lpicl)") +LINE("libpicltree", "PICL Plug-In Library (libpicltree, \\-lpicltree)") +LINE("libpkcs11", "PKCS#11 Cryptographic Framework Library (libpkcs11, \\-lpkcs11)") +LINE("libpool", "Pool Configuration Manipulation Library (libpool, \\-lpool)") +LINE("libproc", "Process Control Library (libproc, \\-lproc)") +LINE("libproject", "Project Database Access Library (libproject, \\-lproject)") +LINE("libresolv", "Resolver Library (libresolv, \\-lresolv \\-lsocket \\-lnsl)") +LINE("librpc", "RPC Service Library (librpcsvc, \\-lrpc)") +LINE("librsm", "Remote Shared Memory Interface Library (librsm, \\-lrsm)") +LINE("libsasl", "Simple Authentication and Security Library (libsasl, \\-lsasl)") +LINE("libscf", "Service Configuration Facility Library (libscf, \\-lscf)") +LINE("libsec", "File Access Control Library (libsec, \\-lsec)") +LINE("libsecdb", "Security Attributes Database Library (libsecdb, \\-lsecdb)") +LINE("libsip", "Session Initiation Protocol Library (libsip, \\-lsip)") +LINE("libslp", "Service Location Protocol Library (libslp, \\-lslp)") +LINE("libsocket", "Sockets Library (libsocket, \\-lsocket)") +LINE("libstmf", "SCSI Target Mode Framework Library (libstmf, \\-lstmf)") +LINE("libsysevet", "System Event Inteface Library (libsysevent, \\-lsysevent)") +LINE("libtecla", "Interactive Command Line Input Library (libtecla, \\-ltecla)") +LINE("libtnfctl", "TNF Probe Control Library (libtnfctl, \\-ltnfctl)") +LINE("libtsol", "Trusted Extensions Library (libtsol, \\-ltsol)") +LINE("libuuid", "UUID Library (libuuid, \\-luuid)") +LINE("libvolmgt", "Volume Management Library (libvolmgt, \\-lvolmgt)") +LINE("libxcurses", "X/Open Curses Library (libxcurses, \\-lxcurses)") +LINE("libxnet", "X/Open Networking Library (libxnet, \\-lxnet)") diff --git a/usr/src/cmd/mandoc/libman.h b/usr/src/cmd/mandoc/libman.h index 4bc5128204..f2ba6a1256 100644 --- a/usr/src/cmd/mandoc/libman.h +++ b/usr/src/cmd/mandoc/libman.h @@ -1,4 +1,4 @@ -/* $Id: libman.h,v 1.55 2011/11/07 01:24:40 schwarze Exp $ */ +/* $Id: libman.h,v 1.56 2012/11/17 00:26:33 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -39,7 +39,7 @@ struct man { struct roff *roff; }; -#define MACRO_PROT_ARGS struct man *m, \ +#define MACRO_PROT_ARGS struct man *man, \ enum mant tok, \ int line, \ int ppos, \ @@ -61,10 +61,10 @@ extern const struct man_macro *const man_macros; __BEGIN_DECLS -#define man_pmsg(m, l, p, t) \ - mandoc_msg((t), (m)->parse, (l), (p), NULL) -#define man_nmsg(m, n, t) \ - mandoc_msg((t), (m)->parse, (n)->line, (n)->pos, NULL) +#define man_pmsg(man, l, p, t) \ + mandoc_msg((t), (man)->parse, (l), (p), NULL) +#define man_nmsg(man, n, t) \ + mandoc_msg((t), (man)->parse, (n)->line, (n)->pos, NULL) int man_word_alloc(struct man *, int, int, const char *); int man_block_alloc(struct man *, int, int, enum mant); int man_head_alloc(struct man *, int, int, enum mant); diff --git a/usr/src/cmd/mandoc/libmandoc.h b/usr/src/cmd/mandoc/libmandoc.h index de422884a2..3c005e106d 100644 --- a/usr/src/cmd/mandoc/libmandoc.h +++ b/usr/src/cmd/mandoc/libmandoc.h @@ -1,6 +1,7 @@ -/* $Id: libmandoc.h,v 1.29 2011/12/02 01:37:14 schwarze Exp $ */ +/* $Id: libmandoc.h,v 1.35 2013/12/15 21:23:52 schwarze Exp $ */ /* - * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -29,11 +30,6 @@ enum rofferr { ROFF_ERR /* badness: puke and stop */ }; -enum regs { - REG_nS = 0, /* nS register */ - REG__MAX -}; - __BEGIN_DECLS struct roff; @@ -47,12 +43,11 @@ void mandoc_vmsg(enum mandocerr, struct mparse *, char *mandoc_getarg(struct mparse *, char **, int, int *); char *mandoc_normdate(struct mparse *, char *, int, int); int mandoc_eos(const char *, size_t, int); -int mandoc_getcontrol(const char *, int *); int mandoc_strntoi(const char *, size_t, int); const char *mandoc_a2msec(const char*); void mdoc_free(struct mdoc *); -struct mdoc *mdoc_alloc(struct roff *, struct mparse *); +struct mdoc *mdoc_alloc(struct roff *, struct mparse *, char *); void mdoc_reset(struct mdoc *); int mdoc_parseln(struct mdoc *, int, char *, int); int mdoc_endparse(struct mdoc *); @@ -68,15 +63,16 @@ int man_addspan(struct man *, const struct tbl_span *); int man_addeqn(struct man *, const struct eqn *); void roff_free(struct roff *); -struct roff *roff_alloc(struct mparse *); +struct roff *roff_alloc(enum mparset, struct mparse *); void roff_reset(struct roff *); enum rofferr roff_parseln(struct roff *, int, char **, size_t *, int, int *); void roff_endparse(struct roff *); -int roff_regisset(const struct roff *, enum regs); -unsigned int roff_regget(const struct roff *, enum regs); -void roff_regunset(struct roff *, enum regs); +void roff_setreg(struct roff *, const char *, int, char sign); +int roff_getreg(const struct roff *, const char *); char *roff_strdup(const struct roff *, const char *); +int roff_getcontrol(const struct roff *, + const char *, int *); #if 0 char roff_eqndelim(const struct roff *); void roff_openeqn(struct roff *, const char *, diff --git a/usr/src/cmd/mandoc/libmdoc.h b/usr/src/cmd/mandoc/libmdoc.h index af1729268a..3f14519d3b 100644 --- a/usr/src/cmd/mandoc/libmdoc.h +++ b/usr/src/cmd/mandoc/libmdoc.h @@ -1,6 +1,7 @@ -/* $Id: libmdoc.h,v 1.78 2011/12/02 01:37:14 schwarze Exp $ */ +/* $Id: libmdoc.h,v 1.82 2013/10/21 23:47:58 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -24,6 +25,7 @@ enum mdoc_next { struct mdoc { struct mparse *parse; /* parse pointer */ + char *defos; /* default argument for .Os */ int flags; /* parse flags */ #define MDOC_HALT (1 << 0) /* error in parse: halt */ #define MDOC_LITERAL (1 << 1) /* in a literal scope */ @@ -33,6 +35,8 @@ struct mdoc { #define MDOC_PPHRASE (1 << 5) /* within a partial phrase */ #define MDOC_FREECOL (1 << 6) /* `It' invocation should close */ #define MDOC_SYNOPSIS (1 << 7) /* SYNOPSIS-style formatting */ +#define MDOC_KEEP (1 << 8) /* in a word keep */ +#define MDOC_SMOFF (1 << 9) /* spacing is off */ enum mdoc_next next; /* where to put the next node */ struct mdoc_node *last; /* the last node parsed */ struct mdoc_node *first; /* the first node parsed */ @@ -42,7 +46,7 @@ struct mdoc { struct roff *roff; }; -#define MACRO_PROT_ARGS struct mdoc *m, \ +#define MACRO_PROT_ARGS struct mdoc *mdoc, \ enum mdoct tok, \ int line, \ int ppos, \ @@ -56,8 +60,8 @@ struct mdoc_macro { #define MDOC_PARSED (1 << 1) #define MDOC_EXPLICIT (1 << 2) #define MDOC_PROLOGUE (1 << 3) -#define MDOC_IGNDELIM (1 << 4) - /* Reserved words in arguments treated as text. */ +#define MDOC_IGNDELIM (1 << 4) +#define MDOC_JOIN (1 << 5) }; enum margserr { @@ -99,13 +103,14 @@ extern const struct mdoc_macro *const mdoc_macros; __BEGIN_DECLS -#define mdoc_pmsg(m, l, p, t) \ - mandoc_msg((t), (m)->parse, (l), (p), NULL) -#define mdoc_nmsg(m, n, t) \ - mandoc_msg((t), (m)->parse, (n)->line, (n)->pos, NULL) +#define mdoc_pmsg(mdoc, l, p, t) \ + mandoc_msg((t), (mdoc)->parse, (l), (p), NULL) +#define mdoc_nmsg(mdoc, n, t) \ + mandoc_msg((t), (mdoc)->parse, (n)->line, (n)->pos, NULL) int mdoc_macro(MACRO_PROT_ARGS); int mdoc_word_alloc(struct mdoc *, int, int, const char *); +void mdoc_word_append(struct mdoc *, const char *); int mdoc_elem_alloc(struct mdoc *, int, int, enum mdoct, struct mdoc_arg *); int mdoc_block_alloc(struct mdoc *, int, int, @@ -113,10 +118,10 @@ int mdoc_block_alloc(struct mdoc *, int, int, int mdoc_head_alloc(struct mdoc *, int, int, enum mdoct); int mdoc_tail_alloc(struct mdoc *, int, int, enum mdoct); int mdoc_body_alloc(struct mdoc *, int, int, enum mdoct); -int mdoc_endbody_alloc(struct mdoc *m, int line, int pos, - enum mdoct tok, struct mdoc_node *body, - enum mdoc_endbody end); +int mdoc_endbody_alloc(struct mdoc *, int, int, enum mdoct, + struct mdoc_node *, enum mdoc_endbody); void mdoc_node_delete(struct mdoc *, struct mdoc_node *); +int mdoc_node_relink(struct mdoc *, struct mdoc_node *); void mdoc_hash_init(void); enum mdoct mdoc_hash_find(const char *); const char *mdoc_a2att(const char *); diff --git a/usr/src/cmd/mandoc/libroff.h b/usr/src/cmd/mandoc/libroff.h index 0bdd5a3604..5b84c5fc45 100644 --- a/usr/src/cmd/mandoc/libroff.h +++ b/usr/src/cmd/mandoc/libroff.h @@ -1,4 +1,4 @@ -/* $Id: libroff.h,v 1.27 2011/07/25 15:37:00 kristaps Exp $ */ +/* $Id: libroff.h,v 1.28 2013/05/31 21:37:17 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -31,7 +31,7 @@ struct tbl_node { int pos; /* invocation column */ int line; /* invocation line */ enum tbl_part part; - struct tbl opts; + struct tbl_opts opts; struct tbl_row *first_row; struct tbl_row *last_row; struct tbl_span *first_span; diff --git a/usr/src/cmd/mandoc/main.c b/usr/src/cmd/mandoc/main.c index fec83fba51..7e5c7a98ae 100644 --- a/usr/src/cmd/mandoc/main.c +++ b/usr/src/cmd/mandoc/main.c @@ -1,7 +1,7 @@ -/* $Id: main.c,v 1.165 2011/10/06 22:29:12 kristaps Exp $ */ +/* $Id: main.c,v 1.167 2012/11/19 17:22:26 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010, 2011, 2012 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -85,6 +85,7 @@ main(int argc, char *argv[]) struct curparse curp; enum mparset type; enum mandoclevel rc; + char *defos; progname = strrchr(argv[0], '/'); if (progname == NULL) @@ -97,10 +98,24 @@ main(int argc, char *argv[]) type = MPARSE_AUTO; curp.outtype = OUTT_ASCII; curp.wlevel = MANDOCLEVEL_FATAL; + defos = NULL; /* LINTED */ - while (-1 != (c = getopt(argc, argv, "m:O:T:VW:"))) + while (-1 != (c = getopt(argc, argv, "I:m:O:T:VW:"))) switch (c) { + case ('I'): + if (strncmp(optarg, "os=", 3)) { + fprintf(stderr, "-I%s: Bad argument\n", + optarg); + return((int)MANDOCLEVEL_BADARG); + } + if (defos) { + fprintf(stderr, "-I%s: Duplicate argument\n", + optarg); + return((int)MANDOCLEVEL_BADARG); + } + defos = mandoc_strdup(optarg + 3); + break; case ('m'): if ( ! moptions(&type, optarg)) return((int)MANDOCLEVEL_BADARG); @@ -125,7 +140,7 @@ main(int argc, char *argv[]) /* NOTREACHED */ } - curp.mp = mparse_alloc(type, curp.wlevel, mmsg, &curp); + curp.mp = mparse_alloc(type, curp.wlevel, mmsg, &curp, defos); /* * Conditionally start up the lookaside buffer before parsing. @@ -152,6 +167,7 @@ main(int argc, char *argv[]) (*curp.outfree)(curp.outdata); if (curp.mp) mparse_free(curp.mp); + free(defos); return((int)rc); } @@ -170,12 +186,12 @@ usage(void) fprintf(stderr, "usage: %s " "[-V] " - "[-foption] " + "[-Ios=name] " "[-mformat] " "[-Ooption] " "[-Toutput] " - "[-Wlevel] " - "[file...]\n", + "[-Wlevel]\n" + "\t [file ...]\n", progname); exit((int)MANDOCLEVEL_BADARG); diff --git a/usr/src/cmd/mandoc/man.c b/usr/src/cmd/mandoc/man.c index 1bea5610e3..e6e1c28992 100644 --- a/usr/src/cmd/mandoc/man.c +++ b/usr/src/cmd/mandoc/man.c @@ -1,4 +1,4 @@ -/* $Id: man.c,v 1.115 2012/01/03 15:16:24 kristaps Exp $ */ +/* $Id: man.c,v 1.121 2013/11/10 22:54:40 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -40,7 +40,8 @@ const char *const __man_macronames[MAN_MAX] = { "RI", "na", "sp", "nf", "fi", "RE", "RS", "DT", "UC", "PD", "AT", "in", - "ft", "OP" + "ft", "OP", "EX", "EE", + "UR", "UE" }; const char * const *man_macronames = __man_macronames; @@ -60,20 +61,20 @@ static int man_descope(struct man *, int, int); const struct man_node * -man_node(const struct man *m) +man_node(const struct man *man) { - assert( ! (MAN_HALT & m->flags)); - return(m->first); + assert( ! (MAN_HALT & man->flags)); + return(man->first); } const struct man_meta * -man_meta(const struct man *m) +man_meta(const struct man *man) { - assert( ! (MAN_HALT & m->flags)); - return(&m->meta); + assert( ! (MAN_HALT & man->flags)); + return(&man->meta); } @@ -112,28 +113,28 @@ man_alloc(struct roff *roff, struct mparse *parse) int -man_endparse(struct man *m) +man_endparse(struct man *man) { - assert( ! (MAN_HALT & m->flags)); - if (man_macroend(m)) + assert( ! (MAN_HALT & man->flags)); + if (man_macroend(man)) return(1); - m->flags |= MAN_HALT; + man->flags |= MAN_HALT; return(0); } int -man_parseln(struct man *m, int ln, char *buf, int offs) +man_parseln(struct man *man, int ln, char *buf, int offs) { - m->flags |= MAN_NEWLINE; + man->flags |= MAN_NEWLINE; - assert( ! (MAN_HALT & m->flags)); + assert( ! (MAN_HALT & man->flags)); - return (mandoc_getcontrol(buf, &offs) ? - man_pmacro(m, ln, buf, offs) : - man_ptext(m, ln, buf, offs)); + return (roff_getcontrol(man->roff, buf, &offs) ? + man_pmacro(man, ln, buf, offs) : + man_ptext(man, ln, buf, offs)); } @@ -157,16 +158,16 @@ man_free1(struct man *man) static void -man_alloc1(struct man *m) +man_alloc1(struct man *man) { - memset(&m->meta, 0, sizeof(struct man_meta)); - m->flags = 0; - m->last = mandoc_calloc(1, sizeof(struct man_node)); - m->first = m->last; - m->last->type = MAN_ROOT; - m->last->tok = MAN_MAX; - m->next = MAN_NEXT_CHILD; + memset(&man->meta, 0, sizeof(struct man_meta)); + man->flags = 0; + man->last = mandoc_calloc(1, sizeof(struct man_node)); + man->first = man->last; + man->last->type = MAN_ROOT; + man->last->tok = MAN_MAX; + man->next = MAN_NEXT_CHILD; } @@ -234,7 +235,7 @@ man_node_append(struct man *man, struct man_node *p) static struct man_node * -man_node_alloc(struct man *m, int line, int pos, +man_node_alloc(struct man *man, int line, int pos, enum man_type type, enum mant tok) { struct man_node *p; @@ -245,89 +246,89 @@ man_node_alloc(struct man *m, int line, int pos, p->type = type; p->tok = tok; - if (MAN_NEWLINE & m->flags) + if (MAN_NEWLINE & man->flags) p->flags |= MAN_LINE; - m->flags &= ~MAN_NEWLINE; + man->flags &= ~MAN_NEWLINE; return(p); } int -man_elem_alloc(struct man *m, int line, int pos, enum mant tok) +man_elem_alloc(struct man *man, int line, int pos, enum mant tok) { struct man_node *p; - p = man_node_alloc(m, line, pos, MAN_ELEM, tok); - if ( ! man_node_append(m, p)) + p = man_node_alloc(man, line, pos, MAN_ELEM, tok); + if ( ! man_node_append(man, p)) return(0); - m->next = MAN_NEXT_CHILD; + man->next = MAN_NEXT_CHILD; return(1); } int -man_tail_alloc(struct man *m, int line, int pos, enum mant tok) +man_tail_alloc(struct man *man, int line, int pos, enum mant tok) { struct man_node *p; - p = man_node_alloc(m, line, pos, MAN_TAIL, tok); - if ( ! man_node_append(m, p)) + p = man_node_alloc(man, line, pos, MAN_TAIL, tok); + if ( ! man_node_append(man, p)) return(0); - m->next = MAN_NEXT_CHILD; + man->next = MAN_NEXT_CHILD; return(1); } int -man_head_alloc(struct man *m, int line, int pos, enum mant tok) +man_head_alloc(struct man *man, int line, int pos, enum mant tok) { struct man_node *p; - p = man_node_alloc(m, line, pos, MAN_HEAD, tok); - if ( ! man_node_append(m, p)) + p = man_node_alloc(man, line, pos, MAN_HEAD, tok); + if ( ! man_node_append(man, p)) return(0); - m->next = MAN_NEXT_CHILD; + man->next = MAN_NEXT_CHILD; return(1); } int -man_body_alloc(struct man *m, int line, int pos, enum mant tok) +man_body_alloc(struct man *man, int line, int pos, enum mant tok) { struct man_node *p; - p = man_node_alloc(m, line, pos, MAN_BODY, tok); - if ( ! man_node_append(m, p)) + p = man_node_alloc(man, line, pos, MAN_BODY, tok); + if ( ! man_node_append(man, p)) return(0); - m->next = MAN_NEXT_CHILD; + man->next = MAN_NEXT_CHILD; return(1); } int -man_block_alloc(struct man *m, int line, int pos, enum mant tok) +man_block_alloc(struct man *man, int line, int pos, enum mant tok) { struct man_node *p; - p = man_node_alloc(m, line, pos, MAN_BLOCK, tok); - if ( ! man_node_append(m, p)) + p = man_node_alloc(man, line, pos, MAN_BLOCK, tok); + if ( ! man_node_append(man, p)) return(0); - m->next = MAN_NEXT_CHILD; + man->next = MAN_NEXT_CHILD; return(1); } int -man_word_alloc(struct man *m, int line, int pos, const char *word) +man_word_alloc(struct man *man, int line, int pos, const char *word) { struct man_node *n; - n = man_node_alloc(m, line, pos, MAN_TEXT, MAN_MAX); - n->string = roff_strdup(m->roff, word); + n = man_node_alloc(man, line, pos, MAN_TEXT, MAN_MAX); + n->string = roff_strdup(man->roff, word); - if ( ! man_node_append(m, n)) + if ( ! man_node_append(man, n)) return(0); - m->next = MAN_NEXT_SIBLING; + man->next = MAN_NEXT_SIBLING; return(1); } @@ -347,52 +348,52 @@ man_node_free(struct man_node *p) void -man_node_delete(struct man *m, struct man_node *p) +man_node_delete(struct man *man, struct man_node *p) { while (p->child) - man_node_delete(m, p->child); + man_node_delete(man, p->child); - man_node_unlink(m, p); + man_node_unlink(man, p); man_node_free(p); } int -man_addeqn(struct man *m, const struct eqn *ep) +man_addeqn(struct man *man, const struct eqn *ep) { struct man_node *n; - assert( ! (MAN_HALT & m->flags)); + assert( ! (MAN_HALT & man->flags)); - n = man_node_alloc(m, ep->ln, ep->pos, MAN_EQN, MAN_MAX); + n = man_node_alloc(man, ep->ln, ep->pos, MAN_EQN, MAN_MAX); n->eqn = ep; - if ( ! man_node_append(m, n)) + if ( ! man_node_append(man, n)) return(0); - m->next = MAN_NEXT_SIBLING; - return(man_descope(m, ep->ln, ep->pos)); + man->next = MAN_NEXT_SIBLING; + return(man_descope(man, ep->ln, ep->pos)); } int -man_addspan(struct man *m, const struct tbl_span *sp) +man_addspan(struct man *man, const struct tbl_span *sp) { struct man_node *n; - assert( ! (MAN_HALT & m->flags)); + assert( ! (MAN_HALT & man->flags)); - n = man_node_alloc(m, sp->line, 0, MAN_TBL, MAN_MAX); + n = man_node_alloc(man, sp->line, 0, MAN_TBL, MAN_MAX); n->span = sp; - if ( ! man_node_append(m, n)) + if ( ! man_node_append(man, n)) return(0); - m->next = MAN_NEXT_SIBLING; - return(man_descope(m, sp->line, 0)); + man->next = MAN_NEXT_SIBLING; + return(man_descope(man, sp->line, 0)); } static int -man_descope(struct man *m, int line, int offs) +man_descope(struct man *man, int line, int offs) { /* * Co-ordinate what happens with having a next-line scope open: @@ -400,44 +401,51 @@ man_descope(struct man *m, int line, int offs) * out the block scope (also if applicable). */ - if (MAN_ELINE & m->flags) { - m->flags &= ~MAN_ELINE; - if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX)) + if (MAN_ELINE & man->flags) { + man->flags &= ~MAN_ELINE; + if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX)) return(0); } - if ( ! (MAN_BLINE & m->flags)) + if ( ! (MAN_BLINE & man->flags)) return(1); - m->flags &= ~MAN_BLINE; + man->flags &= ~MAN_BLINE; - if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX)) + if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX)) return(0); - return(man_body_alloc(m, line, offs, m->last->tok)); + return(man_body_alloc(man, line, offs, man->last->tok)); } static int -man_ptext(struct man *m, int line, char *buf, int offs) +man_ptext(struct man *man, int line, char *buf, int offs) { int i; /* Literal free-form text whitespace is preserved. */ - if (MAN_LITERAL & m->flags) { - if ( ! man_word_alloc(m, line, offs, buf + offs)) + if (MAN_LITERAL & man->flags) { + if ( ! man_word_alloc(man, line, offs, buf + offs)) return(0); - return(man_descope(m, line, offs)); + return(man_descope(man, line, offs)); } - /* Pump blank lines directly into the backend. */ - for (i = offs; ' ' == buf[i]; i++) /* Skip leading whitespace. */ ; + /* + * Blank lines are ignored right after headings + * but add a single vertical space elsewhere. + */ + if ('\0' == buf[i]) { /* Allocate a blank entry. */ - if ( ! man_word_alloc(m, line, offs, "")) - return(0); - return(man_descope(m, line, offs)); + if (MAN_SH != man->last->tok && + MAN_SS != man->last->tok) { + if ( ! man_elem_alloc(man, line, offs, MAN_sp)) + return(0); + man->next = MAN_NEXT_SIBLING; + } + return(1); } /* @@ -450,7 +458,7 @@ man_ptext(struct man *m, int line, char *buf, int offs) if (' ' == buf[i - 1] || '\t' == buf[i - 1]) { if (i > 1 && '\\' != buf[i - 2]) - man_pmsg(m, line, i - 1, MANDOCERR_EOLNSPACE); + man_pmsg(man, line, i - 1, MANDOCERR_EOLNSPACE); for (--i; i && ' ' == buf[i]; i--) /* Spin back to non-space. */ ; @@ -461,7 +469,7 @@ man_ptext(struct man *m, int line, char *buf, int offs) buf[i] = '\0'; } - if ( ! man_word_alloc(m, line, offs, buf + offs)) + if ( ! man_word_alloc(man, line, offs, buf + offs)) return(0); /* @@ -472,13 +480,13 @@ man_ptext(struct man *m, int line, char *buf, int offs) assert(i); if (mandoc_eos(buf, (size_t)i, 0)) - m->last->flags |= MAN_EOS; + man->last->flags |= MAN_EOS; - return(man_descope(m, line, offs)); + return(man_descope(man, line, offs)); } static int -man_pmacro(struct man *m, int ln, char *buf, int offs) +man_pmacro(struct man *man, int ln, char *buf, int offs) { int i, ppos; enum mant tok; @@ -486,7 +494,7 @@ man_pmacro(struct man *m, int ln, char *buf, int offs) struct man_node *n; if ('"' == buf[offs]) { - man_pmsg(m, ln, offs, MANDOCERR_BADCOMMENT); + man_pmsg(man, ln, offs, MANDOCERR_BADCOMMENT); return(1); } else if ('\0' == buf[offs]) return(1); @@ -508,7 +516,7 @@ man_pmacro(struct man *m, int ln, char *buf, int offs) tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX; if (MAN_MAX == tok) { - mandoc_vmsg(MANDOCERR_MACRO, m->parse, ln, + mandoc_vmsg(MANDOCERR_MACRO, man->parse, ln, ppos, "%s", buf + ppos - 1); return(1); } @@ -524,7 +532,7 @@ man_pmacro(struct man *m, int ln, char *buf, int offs) */ if ('\0' == buf[offs] && ' ' == buf[offs - 1]) - man_pmsg(m, ln, offs - 1, MANDOCERR_EOLNSPACE); + man_pmsg(man, ln, offs - 1, MANDOCERR_EOLNSPACE); /* * Remove prior ELINE macro, as it's being clobbered by a new @@ -533,8 +541,8 @@ man_pmacro(struct man *m, int ln, char *buf, int offs) */ if ( ! (MAN_NSCOPED & man_macros[tok].flags) && - m->flags & MAN_ELINE) { - n = m->last; + man->flags & MAN_ELINE) { + n = man->last; assert(MAN_TEXT != n->type); /* Remove repeated NSCOPED macros causing ELINE. */ @@ -542,20 +550,20 @@ man_pmacro(struct man *m, int ln, char *buf, int offs) if (MAN_NSCOPED & man_macros[n->tok].flags) n = n->parent; - mandoc_vmsg(MANDOCERR_LINESCOPE, m->parse, n->line, + mandoc_vmsg(MANDOCERR_LINESCOPE, man->parse, n->line, n->pos, "%s breaks %s", man_macronames[tok], man_macronames[n->tok]); - man_node_delete(m, n); - m->flags &= ~MAN_ELINE; + man_node_delete(man, n); + man->flags &= ~MAN_ELINE; } /* * Remove prior BLINE macro that is being clobbered. */ - if ((m->flags & MAN_BLINE) && + if ((man->flags & MAN_BLINE) && (MAN_BSCOPE & man_macros[tok].flags)) { - n = m->last; + n = man->last; /* Might be a text node like 8 in * .TP 8 @@ -573,12 +581,12 @@ man_pmacro(struct man *m, int ln, char *buf, int offs) assert(MAN_BLOCK == n->type); assert(MAN_SCOPED & man_macros[n->tok].flags); - mandoc_vmsg(MANDOCERR_LINESCOPE, m->parse, n->line, + mandoc_vmsg(MANDOCERR_LINESCOPE, man->parse, n->line, n->pos, "%s breaks %s", man_macronames[tok], man_macronames[n->tok]); - man_node_delete(m, n); - m->flags &= ~MAN_BLINE; + man_node_delete(man, n); + man->flags &= ~MAN_BLINE; } /* @@ -587,13 +595,13 @@ man_pmacro(struct man *m, int ln, char *buf, int offs) * when they exit. */ - if (MAN_BLINE & m->flags) - m->flags |= MAN_BPLINE; + if (MAN_BLINE & man->flags) + man->flags |= MAN_BPLINE; /* Call to handler... */ assert(man_macros[tok].fp); - if ( ! (*man_macros[tok].fp)(m, tok, ln, ppos, &offs, buf)) + if ( ! (*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf)) goto err; /* @@ -601,19 +609,19 @@ man_pmacro(struct man *m, int ln, char *buf, int offs) * above-parsed macro, so return. */ - if ( ! (MAN_BPLINE & m->flags)) { - m->flags &= ~MAN_ILINE; + if ( ! (MAN_BPLINE & man->flags)) { + man->flags &= ~MAN_ILINE; return(1); } - m->flags &= ~MAN_BPLINE; + man->flags &= ~MAN_BPLINE; /* * If we're in a block scope, then allow this macro to slip by * without closing scope around it. */ - if (MAN_ILINE & m->flags) { - m->flags &= ~MAN_ILINE; + if (MAN_ILINE & man->flags) { + man->flags &= ~MAN_ILINE; return(1); } @@ -622,30 +630,30 @@ man_pmacro(struct man *m, int ln, char *buf, int offs) * now, as the next line will close out the block scope. */ - if (MAN_ELINE & m->flags) + if (MAN_ELINE & man->flags) return(1); /* Close out the block scope opened in the prior line. */ - assert(MAN_BLINE & m->flags); - m->flags &= ~MAN_BLINE; + assert(MAN_BLINE & man->flags); + man->flags &= ~MAN_BLINE; - if ( ! man_unscope(m, m->last->parent, MANDOCERR_MAX)) + if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX)) return(0); - return(man_body_alloc(m, ln, ppos, m->last->tok)); + return(man_body_alloc(man, ln, ppos, man->last->tok)); err: /* Error out. */ - m->flags |= MAN_HALT; + man->flags |= MAN_HALT; return(0); } /* - * Unlink a node from its context. If "m" is provided, the last parse + * Unlink a node from its context. If "man" is provided, the last parse * point will also be adjusted accordingly. */ static void -man_node_unlink(struct man *m, struct man_node *n) +man_node_unlink(struct man *man, struct man_node *n) { /* Adjust siblings. */ @@ -665,26 +673,26 @@ man_node_unlink(struct man *m, struct man_node *n) /* Adjust parse point, if applicable. */ - if (m && m->last == n) { + if (man && man->last == n) { /*XXX: this can occur when bailing from validation. */ /*assert(NULL == n->next);*/ if (n->prev) { - m->last = n->prev; - m->next = MAN_NEXT_SIBLING; + man->last = n->prev; + man->next = MAN_NEXT_SIBLING; } else { - m->last = n->parent; - m->next = MAN_NEXT_CHILD; + man->last = n->parent; + man->next = MAN_NEXT_CHILD; } } - if (m && m->first == n) - m->first = NULL; + if (man && man->first == n) + man->first = NULL; } const struct mparse * -man_mparse(const struct man *m) +man_mparse(const struct man *man) { - assert(m && m->parse); - return(m->parse); + assert(man && man->parse); + return(man->parse); } diff --git a/usr/src/cmd/mandoc/man.h b/usr/src/cmd/mandoc/man.h index 4fc3934e6f..ef9480f276 100644 --- a/usr/src/cmd/mandoc/man.h +++ b/usr/src/cmd/mandoc/man.h @@ -1,4 +1,4 @@ -/* $Id: man.h,v 1.60 2012/01/03 15:16:24 kristaps Exp $ */ +/* $Id: man.h,v 1.62 2013/10/17 20:54:58 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -52,6 +52,10 @@ enum mant { MAN_in, MAN_ft, MAN_OP, + MAN_EX, + MAN_EE, + MAN_UR, + MAN_UE, MAN_MAX }; diff --git a/usr/src/cmd/mandoc/man_html.c b/usr/src/cmd/mandoc/man_html.c index a76ea2d707..2c4e220a11 100644 --- a/usr/src/cmd/mandoc/man_html.c +++ b/usr/src/cmd/mandoc/man_html.c @@ -1,6 +1,7 @@ -/* $Id: man_html.c,v 1.86 2012/01/03 15:16:24 kristaps Exp $ */ +/* $Id: man_html.c,v 1.90 2013/10/17 20:54:58 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -37,7 +38,7 @@ #define INDENT 5 -#define MAN_ARGS const struct man_meta *m, \ +#define MAN_ARGS const struct man_meta *man, \ const struct man_node *n, \ struct mhtml *mh, \ struct html *h @@ -70,6 +71,7 @@ static int man_RS_pre(MAN_ARGS); static int man_SH_pre(MAN_ARGS); static int man_SM_pre(MAN_ARGS); static int man_SS_pre(MAN_ARGS); +static int man_UR_pre(MAN_ARGS); static int man_alt_pre(MAN_ARGS); static int man_br_pre(MAN_ARGS); static int man_ign_pre(MAN_ARGS); @@ -113,6 +115,10 @@ static const struct htmlman mans[MAN_MAX] = { { man_in_pre, NULL }, /* in */ { man_ign_pre, NULL }, /* ft */ { man_OP_pre, NULL }, /* OP */ + { man_literal_pre, NULL }, /* EX */ + { man_literal_pre, NULL }, /* EE */ + { man_UR_pre, NULL }, /* UR */ + { NULL, NULL }, /* UE */ }; /* @@ -139,12 +145,12 @@ print_bvspace(struct html *h, const struct man_node *n) } void -html_man(void *arg, const struct man *m) +html_man(void *arg, const struct man *man) { struct mhtml mh; memset(&mh, 0, sizeof(struct mhtml)); - print_man(man_meta(m), man_node(m), &mh, (struct html *)arg); + print_man(man_meta(man), man_node(man), &mh, (struct html *)arg); putchar('\n'); } @@ -160,14 +166,14 @@ print_man(MAN_ARGS) print_gen_decls(h); t = print_otag(h, TAG_HTML, 0, NULL); tt = print_otag(h, TAG_HEAD, 0, NULL); - print_man_head(m, n, mh, h); + print_man_head(man, n, mh, h); print_tagq(h, tt); print_otag(h, TAG_BODY, 0, NULL); print_otag(h, TAG_DIV, 1, &tag); } else t = print_otag(h, TAG_DIV, 1, &tag); - print_man_nodelist(m, n, mh, h); + print_man_nodelist(man, n, mh, h); print_tagq(h, t); } @@ -178,9 +184,9 @@ print_man_head(MAN_ARGS) { print_gen_head(h); - assert(m->title); - assert(m->msec); - bufcat_fmt(h, "%s(%s)", m->title, m->msec); + assert(man->title); + assert(man->msec); + bufcat_fmt(h, "%s(%s)", man->title, man->msec); print_otag(h, TAG_TITLE, 0, NULL); print_text(h, h->buf); } @@ -190,9 +196,9 @@ static void print_man_nodelist(MAN_ARGS) { - print_man_node(m, n, mh, h); + print_man_node(man, n, mh, h); if (n->next) - print_man_nodelist(m, n->next, mh, h); + print_man_nodelist(man, n->next, mh, h); } @@ -207,7 +213,7 @@ print_man_node(MAN_ARGS) switch (n->type) { case (MAN_ROOT): - man_root_pre(m, n, mh, h); + man_root_pre(man, n, mh, h); break; case (MAN_TEXT): /* @@ -258,25 +264,25 @@ print_man_node(MAN_ARGS) t = h->tags.head; } if (mans[n->tok].pre) - child = (*mans[n->tok].pre)(m, n, mh, h); + child = (*mans[n->tok].pre)(man, n, mh, h); break; } if (child && n->child) - print_man_nodelist(m, n->child, mh, h); + print_man_nodelist(man, n->child, mh, h); /* This will automatically close out any font scope. */ print_stagq(h, t); switch (n->type) { case (MAN_ROOT): - man_root_post(m, n, mh, h); + man_root_post(man, n, mh, h); break; case (MAN_EQN): break; default: if (mans[n->tok].post) - (*mans[n->tok].post)(m, n, mh, h); + (*mans[n->tok].post)(man, n, mh, h); break; } } @@ -304,12 +310,12 @@ man_root_pre(MAN_ARGS) char b[BUFSIZ], title[BUFSIZ]; b[0] = 0; - if (m->vol) - (void)strlcat(b, m->vol, BUFSIZ); + if (man->vol) + (void)strlcat(b, man->vol, BUFSIZ); - assert(m->title); - assert(m->msec); - snprintf(title, BUFSIZ - 1, "%s(%s)", m->title, m->msec); + assert(man->title); + assert(man->msec); + snprintf(title, BUFSIZ - 1, "%s(%s)", man->title, man->msec); PAIR_SUMMARY_INIT(&tag[0], "Document Header"); PAIR_CLASS_INIT(&tag[1], "head"); @@ -363,16 +369,16 @@ man_root_post(MAN_ARGS) PAIR_CLASS_INIT(&tag[0], "foot-date"); print_otag(h, TAG_TD, 1, tag); - assert(m->date); - print_text(h, m->date); + assert(man->date); + print_text(h, man->date); print_stagq(h, tt); PAIR_CLASS_INIT(&tag[0], "foot-os"); PAIR_INIT(&tag[1], ATTR_ALIGN, "right"); print_otag(h, TAG_TD, 2, tag); - if (m->source) - print_text(h, m->source); + if (man->source) + print_text(h, man->source); print_tagq(h, t); } @@ -468,7 +474,7 @@ man_alt_pre(MAN_ARGS) if (TAG_MAX != fp) t = print_otag(h, fp, 0, NULL); - print_man_node(m, nn, mh, h); + print_man_node(man, nn, mh, h); if (t) print_tagq(h, t); @@ -543,14 +549,14 @@ man_IP_pre(MAN_ARGS) /* For IP, only print the first header element. */ if (MAN_IP == n->tok && n->child) - print_man_node(m, n->child, mh, h); + print_man_node(man, n->child, mh, h); /* For TP, only print next-line header elements. */ if (MAN_TP == n->tok) for (nn = n->child; nn; nn = nn->next) if (nn->line > n->line) - print_man_node(m, nn, mh, h); + print_man_node(man, nn, mh, h); return(0); } @@ -638,7 +644,7 @@ static int man_literal_pre(MAN_ARGS) { - if (MAN_nf != n->tok) { + if (MAN_fi == n->tok || MAN_EE == n->tok) { print_otag(h, TAG_BR, 0, NULL); mh->fl &= ~MANH_LITERAL; } else @@ -686,3 +692,27 @@ man_RS_pre(MAN_ARGS) print_otag(h, TAG_DIV, 1, &tag); return(1); } + +/* ARGSUSED */ +static int +man_UR_pre(MAN_ARGS) +{ + struct htmlpair tag[2]; + + n = n->child; + assert(MAN_HEAD == n->type); + if (n->nchild) { + assert(MAN_TEXT == n->child->type); + PAIR_CLASS_INIT(&tag[0], "link-ext"); + PAIR_HREF_INIT(&tag[1], n->child->string); + print_otag(h, TAG_A, 2, tag); + } + + assert(MAN_BODY == n->next->type); + if (n->next->nchild) + n = n->next; + + print_man_nodelist(man, n->child, mh, h); + + return(0); +} diff --git a/usr/src/cmd/mandoc/man_macro.c b/usr/src/cmd/mandoc/man_macro.c index 4bbbc4fa7f..479d0484c4 100644 --- a/usr/src/cmd/mandoc/man_macro.c +++ b/usr/src/cmd/mandoc/man_macro.c @@ -1,6 +1,8 @@ -/* $Id: man_macro.c,v 1.71 2012/01/03 15:16:24 kristaps Exp $ */ +/* $Id: man_macro.c,v 1.79 2013/12/25 00:50:05 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -77,7 +79,7 @@ const struct man_macro __man_macros[MAN_MAX] = { { in_line_eoln, MAN_BSCOPE }, /* nf */ { in_line_eoln, MAN_BSCOPE }, /* fi */ { blk_close, 0 }, /* RE */ - { blk_exp, MAN_EXPLICIT }, /* RS */ + { blk_exp, MAN_BSCOPE | MAN_EXPLICIT }, /* RS */ { in_line_eoln, 0 }, /* DT */ { in_line_eoln, 0 }, /* UC */ { in_line_eoln, 0 }, /* PD */ @@ -85,6 +87,10 @@ const struct man_macro __man_macros[MAN_MAX] = { { in_line_eoln, 0 }, /* in */ { in_line_eoln, 0 }, /* ft */ { in_line_eoln, 0 }, /* OP */ + { in_line_eoln, MAN_BSCOPE }, /* EX */ + { in_line_eoln, MAN_BSCOPE }, /* EE */ + { blk_exp, MAN_BSCOPE | MAN_EXPLICIT }, /* UR */ + { blk_close, 0 }, /* UE */ }; const struct man_macro * const man_macros = __man_macros; @@ -94,7 +100,7 @@ const struct man_macro * const man_macros = __man_macros; * Warn when "n" is an explicit non-roff macro. */ static void -rew_warn(struct man *m, struct man_node *n, enum mandocerr er) +rew_warn(struct man *man, struct man_node *n, enum mandocerr er) { if (er == MANDOCERR_MAX || MAN_BLOCK != n->type) @@ -105,7 +111,7 @@ rew_warn(struct man *m, struct man_node *n, enum mandocerr er) return; assert(er < MANDOCERR_FATAL); - man_nmsg(m, n, er); + man_nmsg(man, n, er); } @@ -114,33 +120,33 @@ rew_warn(struct man *m, struct man_node *n, enum mandocerr er) * will be used if an explicit block scope is being closed out. */ int -man_unscope(struct man *m, const struct man_node *to, +man_unscope(struct man *man, const struct man_node *to, enum mandocerr er) { struct man_node *n; assert(to); - m->next = MAN_NEXT_SIBLING; + man->next = MAN_NEXT_SIBLING; /* LINTED */ - while (m->last != to) { + while (man->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 + * man->last node in the post-validation phase and reset + * it to man->last->parent, causing a step in the closing * out to be lost. */ - n = m->last->parent; - rew_warn(m, m->last, er); - if ( ! man_valid_post(m)) + n = man->last->parent; + rew_warn(man, man->last, er); + if ( ! man_valid_post(man)) return(0); - m->last = n; - assert(m->last); + man->last = n; + assert(man->last); } - rew_warn(m, m->last, er); - if ( ! man_valid_post(m)) + rew_warn(man, man->last, er); + if ( ! man_valid_post(man)) return(0); return(1); @@ -183,8 +189,12 @@ rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n) return(REW_NOHALT); /* First: rewind to ourselves. */ - if (type == n->type && tok == n->tok) - return(REW_REWIND); + if (type == n->type && tok == n->tok) { + if (MAN_EXPLICIT & man_macros[n->tok].flags) + return(REW_HALT); + else + return(REW_REWIND); + } /* * Next follow the implicit scope-smashings as defined by man.7: @@ -200,6 +210,10 @@ rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n) return(c); break; case (MAN_RS): + /* Preserve empty paragraphs before RS. */ + if (0 == n->nchild && (MAN_P == n->tok || + MAN_PP == n->tok || MAN_LP == n->tok)) + return(REW_HALT); /* Rewind to a subsection, if a block. */ if (REW_NOHALT != (c = rew_block(MAN_SS, type, n))) return(c); @@ -230,13 +244,13 @@ rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n) * scopes. When a scope is closed, it must be validated and actioned. */ static int -rew_scope(enum man_type type, struct man *m, enum mant tok) +rew_scope(enum man_type type, struct man *man, enum mant tok) { struct man_node *n; enum rew c; /* LINTED */ - for (n = m->last; n; n = n->parent) { + for (n = man->last; n; n = n->parent) { /* * Whether we should stop immediately (REW_HALT), stop * and rewind until this point (REW_REWIND), or keep @@ -255,7 +269,7 @@ rew_scope(enum man_type type, struct man *m, enum mant tok) */ assert(n); - return(man_unscope(m, n, MANDOCERR_MAX)); + return(man_unscope(man, n, MANDOCERR_MAX)); } @@ -273,22 +287,24 @@ blk_close(MACRO_PROT_ARGS) case (MAN_RE): ntok = MAN_RS; break; + case (MAN_UE): + ntok = MAN_UR; + break; default: abort(); /* NOTREACHED */ } - for (nn = m->last->parent; nn; nn = nn->parent) - if (ntok == nn->tok) + for (nn = man->last->parent; nn; nn = nn->parent) + if (ntok == nn->tok && MAN_BLOCK == nn->type) break; - if (NULL == nn) - man_pmsg(m, line, ppos, MANDOCERR_NOSCOPE); - - if ( ! rew_scope(MAN_BODY, m, ntok)) - return(0); - if ( ! rew_scope(MAN_BLOCK, m, ntok)) - return(0); + if (NULL == nn) { + man_pmsg(man, line, ppos, MANDOCERR_NOSCOPE); + if ( ! rew_scope(MAN_BLOCK, man, MAN_PP)) + return(0); + } else + man_unscope(man, nn, MANDOCERR_MAX); return(1); } @@ -298,34 +314,40 @@ blk_close(MACRO_PROT_ARGS) int blk_exp(MACRO_PROT_ARGS) { + struct man_node *n; int la; char *p; - /* - * Close out prior scopes. "Regular" explicit macros cannot be - * nested, but we allow roff macros to be placed just about - * anywhere. - */ + /* Close out prior implicit scopes. */ - if ( ! man_block_alloc(m, line, ppos, tok)) + if ( ! rew_scope(MAN_BLOCK, man, tok)) return(0); - if ( ! man_head_alloc(m, line, ppos, tok)) + + if ( ! man_block_alloc(man, line, ppos, tok)) + return(0); + if ( ! man_head_alloc(man, line, ppos, tok)) return(0); for (;;) { la = *pos; - if ( ! man_args(m, line, pos, buf, &p)) + if ( ! man_args(man, line, pos, buf, &p)) break; - if ( ! man_word_alloc(m, line, la, p)) + if ( ! man_word_alloc(man, line, la, p)) return(0); } - assert(m); + assert(man); assert(tok != MAN_MAX); - if ( ! rew_scope(MAN_HEAD, m, tok)) - return(0); - return(man_body_alloc(m, line, ppos, tok)); + for (n = man->last; n; n = n->parent) { + if (n->tok != tok) + continue; + assert(MAN_HEAD == n->type); + man_unscope(man, n, MANDOCERR_MAX); + break; + } + + return(man_body_alloc(man, line, ppos, tok)); } @@ -346,27 +368,27 @@ blk_imp(MACRO_PROT_ARGS) /* Close out prior scopes. */ - if ( ! rew_scope(MAN_BODY, m, tok)) + if ( ! rew_scope(MAN_BODY, man, tok)) return(0); - if ( ! rew_scope(MAN_BLOCK, m, tok)) + if ( ! rew_scope(MAN_BLOCK, man, tok)) return(0); /* Allocate new block & head scope. */ - if ( ! man_block_alloc(m, line, ppos, tok)) + if ( ! man_block_alloc(man, line, ppos, tok)) return(0); - if ( ! man_head_alloc(m, line, ppos, tok)) + if ( ! man_head_alloc(man, line, ppos, tok)) return(0); - n = m->last; + n = man->last; /* Add line arguments. */ for (;;) { la = *pos; - if ( ! man_args(m, line, pos, buf, &p)) + if ( ! man_args(man, line, pos, buf, &p)) break; - if ( ! man_word_alloc(m, line, la, p)) + if ( ! man_word_alloc(man, line, la, p)) return(0); } @@ -375,17 +397,17 @@ blk_imp(MACRO_PROT_ARGS) if (MAN_SCOPED & man_macros[tok].flags) { /* If we're forcing scope (`TP'), keep it open. */ if (MAN_FSCOPED & man_macros[tok].flags) { - m->flags |= MAN_BLINE; + man->flags |= MAN_BLINE; return(1); - } else if (n == m->last) { - m->flags |= MAN_BLINE; + } else if (n == man->last) { + man->flags |= MAN_BLINE; return(1); } } - if ( ! rew_scope(MAN_HEAD, m, tok)) + if ( ! rew_scope(MAN_HEAD, man, tok)) return(0); - return(man_body_alloc(m, line, ppos, tok)); + return(man_body_alloc(man, line, ppos, tok)); } @@ -397,28 +419,37 @@ in_line_eoln(MACRO_PROT_ARGS) char *p; struct man_node *n; - if ( ! man_elem_alloc(m, line, ppos, tok)) + if ( ! man_elem_alloc(man, line, ppos, tok)) return(0); - n = m->last; + n = man->last; for (;;) { la = *pos; - if ( ! man_args(m, line, pos, buf, &p)) + if ( ! man_args(man, line, pos, buf, &p)) break; - if ( ! man_word_alloc(m, line, la, p)) + if ( ! man_word_alloc(man, line, la, p)) return(0); } /* + * Append MAN_EOS in case the last snipped argument + * ends with a dot, e.g. `.IR syslog (3).' + */ + + if (n != man->last && + mandoc_eos(man->last->string, strlen(man->last->string), 0)) + man->last->flags |= MAN_EOS; + + /* * If no arguments are specified and this is MAN_SCOPED (i.e., * next-line scoped), then set our mode to indicate that we're * waiting for terms to load into our context. */ - if (n == m->last && MAN_SCOPED & man_macros[tok].flags) { + if (n == man->last && MAN_SCOPED & man_macros[tok].flags) { assert( ! (MAN_NSCOPED & man_macros[tok].flags)); - m->flags |= MAN_ELINE; + man->flags |= MAN_ELINE; return(1); } @@ -426,11 +457,11 @@ in_line_eoln(MACRO_PROT_ARGS) if (MAN_NSCOPED & man_macros[tok].flags) { assert( ! (MAN_SCOPED & man_macros[tok].flags)); - m->flags |= MAN_ILINE; + man->flags |= MAN_ILINE; } - assert(MAN_ROOT != m->last->type); - m->next = MAN_NEXT_SIBLING; + assert(MAN_ROOT != man->last->type); + man->next = MAN_NEXT_SIBLING; /* * Rewind our element scope. Note that when TH is pruned, we'll @@ -438,22 +469,22 @@ in_line_eoln(MACRO_PROT_ARGS) * its sibling. */ - for ( ; m->last; m->last = m->last->parent) { - if (m->last == n) + for ( ; man->last; man->last = man->last->parent) { + if (man->last == n) break; - if (m->last->type == MAN_ROOT) + if (man->last->type == MAN_ROOT) break; - if ( ! man_valid_post(m)) + if ( ! man_valid_post(man)) return(0); } - assert(m->last); + assert(man->last); /* * Same here regarding whether we're back at the root. */ - if (m->last->type != MAN_ROOT && ! man_valid_post(m)) + if (man->last->type != MAN_ROOT && ! man_valid_post(man)) return(0); return(1); @@ -461,14 +492,14 @@ in_line_eoln(MACRO_PROT_ARGS) int -man_macroend(struct man *m) +man_macroend(struct man *man) { - return(man_unscope(m, m->first, MANDOCERR_SCOPEEXIT)); + return(man_unscope(man, man->first, MANDOCERR_SCOPEEXIT)); } static int -man_args(struct man *m, int line, int *pos, char *buf, char **v) +man_args(struct man *man, int line, int *pos, char *buf, char **v) { char *start; @@ -479,6 +510,6 @@ man_args(struct man *m, int line, int *pos, char *buf, char **v) if ('\0' == *start) return(0); - *v = mandoc_getarg(m->parse, v, line, pos); + *v = mandoc_getarg(man->parse, v, line, pos); return(1); } diff --git a/usr/src/cmd/mandoc/man_term.c b/usr/src/cmd/mandoc/man_term.c index 69c5c95e44..4bd62443b4 100644 --- a/usr/src/cmd/mandoc/man_term.c +++ b/usr/src/cmd/mandoc/man_term.c @@ -1,7 +1,7 @@ -/* $Id: man_term.c,v 1.127 2012/01/03 15:16:24 kristaps Exp $ */ +/* $Id: man_term.c,v 1.139 2013/12/22 23:34:13 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -35,8 +35,6 @@ #define MAXMARGINS 64 /* maximum number of indented scopes */ -/* FIXME: have PD set the default vspace width. */ - struct mtermp { int fl; #define MANT_LITERAL (1 << 0) @@ -44,12 +42,13 @@ struct mtermp { int lmargincur; /* index of current margin */ int lmarginsz; /* actual number of nested margins */ size_t offset; /* default offset to visible page */ + int pardist; /* vert. space before par., unit: [v] */ }; #define DECL_ARGS struct termp *p, \ struct mtermp *mt, \ const struct man_node *n, \ - const struct man_meta *m + const struct man_meta *meta struct termact { int (*pre)(DECL_ARGS); @@ -66,18 +65,20 @@ static void print_man_node(DECL_ARGS); static void print_man_head(struct termp *, const void *); static void print_man_foot(struct termp *, const void *); static void print_bvspace(struct termp *, - const struct man_node *); + const struct man_node *, int); static int pre_B(DECL_ARGS); static int pre_HP(DECL_ARGS); static int pre_I(DECL_ARGS); static int pre_IP(DECL_ARGS); static int pre_OP(DECL_ARGS); +static int pre_PD(DECL_ARGS); static int pre_PP(DECL_ARGS); static int pre_RS(DECL_ARGS); static int pre_SH(DECL_ARGS); static int pre_SS(DECL_ARGS); static int pre_TP(DECL_ARGS); +static int pre_UR(DECL_ARGS); static int pre_alternate(DECL_ARGS); static int pre_ft(DECL_ARGS); static int pre_ign(DECL_ARGS); @@ -91,6 +92,7 @@ static void post_RS(DECL_ARGS); static void post_SH(DECL_ARGS); static void post_SS(DECL_ARGS); static void post_TP(DECL_ARGS); +static void post_UR(DECL_ARGS); static const struct termact termacts[MAN_MAX] = { { pre_sp, NULL, MAN_NOTEXT }, /* br */ @@ -122,11 +124,15 @@ static const struct termact termacts[MAN_MAX] = { { pre_RS, post_RS, 0 }, /* RS */ { pre_ign, NULL, 0 }, /* DT */ { pre_ign, NULL, 0 }, /* UC */ - { pre_ign, NULL, 0 }, /* PD */ + { pre_PD, NULL, MAN_NOTEXT }, /* PD */ { pre_ign, NULL, 0 }, /* AT */ { pre_in, NULL, MAN_NOTEXT }, /* in */ { pre_ft, NULL, MAN_NOTEXT }, /* ft */ { pre_OP, NULL, 0 }, /* OP */ + { pre_literal, NULL, 0 }, /* EX */ + { pre_literal, NULL, 0 }, /* EE */ + { pre_UR, post_UR, 0 }, /* UR */ + { NULL, NULL, 0 }, /* UE */ }; @@ -136,7 +142,7 @@ terminal_man(void *arg, const struct man *man) { struct termp *p; const struct man_node *n; - const struct man_meta *m; + const struct man_meta *meta; struct mtermp mt; p = (struct termp *)arg; @@ -152,18 +158,19 @@ terminal_man(void *arg, const struct man *man) p->symtab = mchars_alloc(); n = man_node(man); - m = man_meta(man); + meta = man_meta(man); - term_begin(p, print_man_head, print_man_foot, m); + term_begin(p, print_man_head, print_man_foot, meta); p->flags |= TERMP_NOSPACE; memset(&mt, 0, sizeof(struct mtermp)); mt.lmargin[mt.lmargincur] = term_len(p, p->defindent); mt.offset = term_len(p, p->defindent); + mt.pardist = 1; if (n->child) - print_man_nodelist(p, &mt, n->child, m); + print_man_nodelist(p, &mt, n->child, meta); term_end(p); } @@ -201,8 +208,9 @@ a2width(const struct termp *p, const char *cp) * first, print it. */ static void -print_bvspace(struct termp *p, const struct man_node *n) +print_bvspace(struct termp *p, const struct man_node *n, int pardist) { + int i; term_newln(p); @@ -214,7 +222,8 @@ print_bvspace(struct termp *p, const struct man_node *n) if (NULL == n->prev) return; - term_vspace(p); + for (i = 0; i < pardist; i++) + term_vspace(p); } /* ARGSUSED */ @@ -243,7 +252,7 @@ pre_literal(DECL_ARGS) term_newln(p); - if (MAN_nf == n->tok) + if (MAN_nf == n->tok || MAN_EX == n->tok) mt->fl |= MANT_LITERAL; else mt->fl &= ~MANT_LITERAL; @@ -256,7 +265,8 @@ pre_literal(DECL_ARGS) if (MAN_HP == n->parent->tok && p->rmargin < p->maxrmargin) { p->offset = p->rmargin; p->rmargin = p->maxrmargin; - p->flags &= ~(TERMP_NOBREAK | TERMP_TWOSPACE); + p->trailspace = 0; + p->flags &= ~TERMP_NOBREAK; p->flags |= TERMP_NOSPACE; } @@ -265,6 +275,21 @@ pre_literal(DECL_ARGS) /* ARGSUSED */ static int +pre_PD(DECL_ARGS) +{ + + n = n->child; + if (0 == n) { + mt->pardist = 1; + return(0); + } + assert(MAN_TEXT == n->type); + mt->pardist = atoi(n->string); + return(0); +} + +/* ARGSUSED */ +static int pre_alternate(DECL_ARGS) { enum termfont font[2]; @@ -307,7 +332,7 @@ pre_alternate(DECL_ARGS) term_fontrepl(p, font[i]); if (savelit && NULL == nn->next) mt->fl |= MANT_LITERAL; - print_man_node(p, mt, nn, m); + print_man_node(p, mt, nn, meta); if (nn->next) p->flags |= TERMP_NOSPACE; } @@ -438,28 +463,54 @@ pre_in(DECL_ARGS) static int pre_sp(DECL_ARGS) { + char *s; size_t i, len; + int neg; if ((NULL == n->prev && n->parent)) { - if (MAN_SS == n->parent->tok) - return(0); - if (MAN_SH == n->parent->tok) + switch (n->parent->tok) { + case (MAN_SH): + /* FALLTHROUGH */ + case (MAN_SS): + /* FALLTHROUGH */ + case (MAN_PP): + /* FALLTHROUGH */ + case (MAN_LP): + /* FALLTHROUGH */ + case (MAN_P): + /* FALLTHROUGH */ return(0); + default: + break; + } } + neg = 0; switch (n->tok) { case (MAN_br): len = 0; break; default: - len = n->child ? a2height(p, n->child->string) : 1; + if (NULL == n->child) { + len = 1; + break; + } + s = n->child->string; + if ('-' == *s) { + neg = 1; + s++; + } + len = a2height(p, s); break; } if (0 == len) term_newln(p); - for (i = 0; i < len; i++) - term_vspace(p); + else if (neg) + p->skipvsp += len; + else + for (i = 0; i < len; i++) + term_vspace(p); return(0); } @@ -475,16 +526,19 @@ pre_HP(DECL_ARGS) switch (n->type) { case (MAN_BLOCK): - print_bvspace(p, n); + print_bvspace(p, n, mt->pardist); return(1); case (MAN_BODY): - p->flags |= TERMP_NOBREAK; - p->flags |= TERMP_TWOSPACE; break; default: return(0); } + if ( ! (MANT_LITERAL & mt->fl)) { + p->flags |= TERMP_NOBREAK; + p->trailspace = 2; + } + len = mt->lmargin[mt->lmargincur]; ival = -1; @@ -514,13 +568,10 @@ post_HP(DECL_ARGS) { switch (n->type) { - case (MAN_BLOCK): - term_flushln(p); - break; case (MAN_BODY): - term_flushln(p); + term_newln(p); p->flags &= ~TERMP_NOBREAK; - p->flags &= ~TERMP_TWOSPACE; + p->trailspace = 0; p->offset = mt->offset; p->rmargin = p->maxrmargin; break; @@ -538,7 +589,7 @@ pre_PP(DECL_ARGS) switch (n->type) { case (MAN_BLOCK): mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); - print_bvspace(p, n); + print_bvspace(p, n, mt->pardist); break; default: p->offset = mt->offset; @@ -563,9 +614,10 @@ pre_IP(DECL_ARGS) break; case (MAN_HEAD): p->flags |= TERMP_NOBREAK; + p->trailspace = 1; break; case (MAN_BLOCK): - print_bvspace(p, n); + print_bvspace(p, n, mt->pardist); /* FALLTHROUGH */ default: return(1); @@ -598,7 +650,7 @@ pre_IP(DECL_ARGS) mt->fl &= ~MANT_LITERAL; if (n->child) - print_man_node(p, mt, n->child, m); + print_man_node(p, mt, n->child, meta); if (savelit) mt->fl |= MANT_LITERAL; @@ -625,10 +677,12 @@ post_IP(DECL_ARGS) case (MAN_HEAD): term_flushln(p); p->flags &= ~TERMP_NOBREAK; + p->trailspace = 0; p->rmargin = p->maxrmargin; break; case (MAN_BODY): term_newln(p); + p->offset = mt->offset; break; default: break; @@ -647,12 +701,13 @@ pre_TP(DECL_ARGS) switch (n->type) { case (MAN_HEAD): p->flags |= TERMP_NOBREAK; + p->trailspace = 1; break; case (MAN_BODY): p->flags |= TERMP_NOSPACE; break; case (MAN_BLOCK): - print_bvspace(p, n); + print_bvspace(p, n, mt->pardist); /* FALLTHROUGH */ default: return(1); @@ -683,7 +738,7 @@ pre_TP(DECL_ARGS) /* Don't print same-line elements. */ for (nn = n->child; nn; nn = nn->next) if (nn->line > n->line) - print_man_node(p, mt, nn, m); + print_man_node(p, mt, nn, meta); if (savelit) mt->fl |= MANT_LITERAL; @@ -694,6 +749,8 @@ pre_TP(DECL_ARGS) case (MAN_BODY): p->offset = mt->offset + len; p->rmargin = p->maxrmargin; + p->trailspace = 0; + p->flags &= ~TERMP_NOBREAK; break; default: break; @@ -711,12 +768,10 @@ post_TP(DECL_ARGS) switch (n->type) { case (MAN_HEAD): term_flushln(p); - p->flags &= ~TERMP_NOBREAK; - p->flags &= ~TERMP_TWOSPACE; - p->rmargin = p->maxrmargin; break; case (MAN_BODY): term_newln(p); + p->offset = mt->offset; break; default: break; @@ -728,6 +783,7 @@ post_TP(DECL_ARGS) static int pre_SS(DECL_ARGS) { + int i; switch (n->type) { case (MAN_BLOCK): @@ -740,11 +796,12 @@ pre_SS(DECL_ARGS) break; if (NULL == n->prev) break; - term_vspace(p); + for (i = 0; i < mt->pardist; i++) + term_vspace(p); break; case (MAN_HEAD): term_fontrepl(p, TERMFONT_BOLD); - p->offset = term_len(p, p->defindent/2); + p->offset = term_len(p, 3); break; case (MAN_BODY): p->offset = mt->offset; @@ -779,6 +836,7 @@ post_SS(DECL_ARGS) static int pre_SH(DECL_ARGS) { + int i; switch (n->type) { case (MAN_BLOCK): @@ -792,7 +850,8 @@ pre_SH(DECL_ARGS) /* If the first macro, no vspae. */ if (NULL == n->prev) break; - term_vspace(p); + for (i = 0; i < mt->pardist; i++) + term_vspace(p); break; case (MAN_HEAD): term_fontrepl(p, TERMFONT_BOLD); @@ -890,6 +949,32 @@ post_RS(DECL_ARGS) mt->lmargincur = mt->lmarginsz; } +/* ARGSUSED */ +static int +pre_UR(DECL_ARGS) +{ + + return (MAN_HEAD != n->type); +} + +/* ARGSUSED */ +static void +post_UR(DECL_ARGS) +{ + + if (MAN_BLOCK != n->type) + return; + + term_word(p, "<"); + p->flags |= TERMP_NOSPACE; + + if (NULL != n->child->child) + print_man_node(p, mt, n->child->child, meta); + + p->flags |= TERMP_NOSPACE; + term_word(p, ">"); +} + static void print_man_node(DECL_ARGS) { @@ -910,29 +995,8 @@ print_man_node(DECL_ARGS) term_newln(p); term_word(p, n->string); + goto out; - /* - * If we're in a literal context, make sure that words - * togehter on the same line stay together. This is a - * POST-printing call, so we check the NEXT word. Since - * -man doesn't have nested macros, we don't need to be - * more specific than this. - */ - if (MANT_LITERAL & mt->fl && ! (TERMP_NOBREAK & p->flags) && - (NULL == n->next || - n->next->line > n->line)) { - rm = p->rmargin; - rmax = p->maxrmargin; - p->rmargin = p->maxrmargin = TERM_MAXMARGIN; - p->flags |= TERMP_NOSPACE; - term_flushln(p); - p->rmargin = rm; - p->maxrmargin = rmax; - } - - if (MAN_EOS & n->flags) - p->flags |= TERMP_SENTENCE; - return; case (MAN_EQN): term_eqn(p, n->eqn); return; @@ -954,16 +1018,41 @@ print_man_node(DECL_ARGS) c = 1; if (termacts[n->tok].pre) - c = (*termacts[n->tok].pre)(p, mt, n, m); + c = (*termacts[n->tok].pre)(p, mt, n, meta); if (c && n->child) - print_man_nodelist(p, mt, n->child, m); + print_man_nodelist(p, mt, n->child, meta); if (termacts[n->tok].post) - (*termacts[n->tok].post)(p, mt, n, m); + (*termacts[n->tok].post)(p, mt, n, meta); if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) term_fontrepl(p, TERMFONT_NONE); +out: + /* + * If we're in a literal context, make sure that words + * together on the same line stay together. This is a + * POST-printing call, so we check the NEXT word. Since + * -man doesn't have nested macros, we don't need to be + * more specific than this. + */ + if (MANT_LITERAL & mt->fl && ! (TERMP_NOBREAK & p->flags) && + (NULL == n->next || n->next->line > n->line)) { + rm = p->rmargin; + rmax = p->maxrmargin; + p->rmargin = p->maxrmargin = TERM_MAXMARGIN; + p->flags |= TERMP_NOSPACE; + if (NULL != n->string && '\0' != *n->string) + term_flushln(p); + else + term_newln(p); + if (rm < rmax && n->parent->tok == MAN_HP) { + p->offset = rm; + p->rmargin = rmax; + } else + p->rmargin = rm; + p->maxrmargin = rmax; + } if (MAN_EOS & n->flags) p->flags |= TERMP_SENTENCE; } @@ -973,10 +1062,10 @@ static void print_man_nodelist(DECL_ARGS) { - print_man_node(p, mt, n, m); + print_man_node(p, mt, n, meta); if ( ! n->next) return; - print_man_nodelist(p, mt, n->next, m); + print_man_nodelist(p, mt, n->next, meta); } @@ -1016,6 +1105,7 @@ print_man_foot(struct termp *p, const void *arg) /* Bottom left corner: manual source. */ p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; + p->trailspace = 1; p->offset = 0; p->rmargin = (p->maxrmargin - datelen + term_len(p, 1)) / 2; @@ -1038,6 +1128,7 @@ print_man_foot(struct termp *p, const void *arg) p->flags &= ~TERMP_NOBREAK; p->flags |= TERMP_NOSPACE; + p->trailspace = 0; p->offset = p->rmargin; p->rmargin = p->maxrmargin; @@ -1051,24 +1142,25 @@ print_man_head(struct termp *p, const void *arg) { char buf[BUFSIZ], title[BUFSIZ]; size_t buflen, titlen; - const struct man_meta *m; + const struct man_meta *meta; - m = (const struct man_meta *)arg; - assert(m->title); - assert(m->msec); + meta = (const struct man_meta *)arg; + assert(meta->title); + assert(meta->msec); - if (m->vol) - strlcpy(buf, m->vol, BUFSIZ); + if (meta->vol) + strlcpy(buf, meta->vol, BUFSIZ); else buf[0] = '\0'; buflen = term_strlen(p, buf); /* Top left corner: manual title and section. */ - snprintf(title, BUFSIZ, "%s(%s)", m->title, m->msec); + snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec); titlen = term_strlen(p, title); p->flags |= TERMP_NOBREAK | TERMP_NOSPACE; + p->trailspace = 1; p->offset = 0; p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ? (p->maxrmargin - @@ -1091,6 +1183,7 @@ print_man_head(struct termp *p, const void *arg) /* Top right corner: title and section, again. */ p->flags &= ~TERMP_NOBREAK; + p->trailspace = 0; if (p->rmargin + titlen <= p->maxrmargin) { p->flags |= TERMP_NOSPACE; p->offset = p->rmargin; diff --git a/usr/src/cmd/mandoc/man_validate.c b/usr/src/cmd/mandoc/man_validate.c index e40b089f53..da2e557ebb 100644 --- a/usr/src/cmd/mandoc/man_validate.c +++ b/usr/src/cmd/mandoc/man_validate.c @@ -1,7 +1,7 @@ -/* $Id: man_validate.c,v 1.80 2012/01/03 15:16:24 kristaps Exp $ */ +/* $Id: man_validate.c,v 1.86 2013/10/17 20:54:58 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -35,7 +35,7 @@ #include "libman.h" #include "libmandoc.h" -#define CHKARGS struct man *m, struct man_node *n +#define CHKARGS struct man *man, struct man_node *n typedef int (*v_check)(CHKARGS); @@ -49,12 +49,14 @@ static int check_eq2(CHKARGS); static int check_le1(CHKARGS); static int check_ge2(CHKARGS); static int check_le5(CHKARGS); +static int check_head1(CHKARGS); static int check_par(CHKARGS); static int check_part(CHKARGS); static int check_root(CHKARGS); static void check_text(CHKARGS); static int post_AT(CHKARGS); +static int post_IP(CHKARGS); static int post_vs(CHKARGS); static int post_fi(CHKARGS); static int post_ft(CHKARGS); @@ -70,6 +72,8 @@ static v_check posts_eq0[] = { check_eq0, NULL }; static v_check posts_eq2[] = { check_eq2, NULL }; static v_check posts_fi[] = { check_eq0, post_fi, NULL }; static v_check posts_ft[] = { post_ft, NULL }; +static v_check posts_ip[] = { post_IP, NULL }; +static v_check posts_le1[] = { check_le1, NULL }; static v_check posts_nf[] = { check_eq0, post_nf, NULL }; static v_check posts_par[] = { check_par, NULL }; static v_check posts_part[] = { check_part, NULL }; @@ -77,6 +81,7 @@ static v_check posts_sec[] = { post_sec, NULL }; static v_check posts_sp[] = { post_vs, check_le1, NULL }; static v_check posts_th[] = { check_ge2, check_le5, post_TH, NULL }; static v_check posts_uc[] = { post_UC, NULL }; +static v_check posts_ur[] = { check_head1, check_part, NULL }; static v_check pres_sec[] = { pre_sec, NULL }; static const struct man_valid man_valids[MAN_MAX] = { @@ -88,7 +93,7 @@ static const struct man_valid man_valids[MAN_MAX] = { { NULL, posts_par }, /* LP */ { NULL, posts_par }, /* PP */ { NULL, posts_par }, /* P */ - { NULL, NULL }, /* IP */ + { NULL, posts_ip }, /* IP */ { NULL, NULL }, /* HP */ { NULL, NULL }, /* SM */ { NULL, NULL }, /* SB */ @@ -109,16 +114,20 @@ static const struct man_valid man_valids[MAN_MAX] = { { NULL, posts_part }, /* RS */ { NULL, NULL }, /* DT */ { NULL, posts_uc }, /* UC */ - { NULL, NULL }, /* PD */ + { NULL, posts_le1 }, /* PD */ { NULL, posts_at }, /* AT */ { NULL, NULL }, /* in */ { NULL, posts_ft }, /* ft */ { NULL, posts_eq2 }, /* OP */ + { NULL, posts_nf }, /* EX */ + { NULL, posts_fi }, /* EE */ + { NULL, posts_ur }, /* UR */ + { NULL, NULL }, /* UE */ }; int -man_valid_pre(struct man *m, struct man_node *n) +man_valid_pre(struct man *man, struct man_node *n) { v_check *cp; @@ -138,27 +147,27 @@ man_valid_pre(struct man *m, struct man_node *n) if (NULL == (cp = man_valids[n->tok].pres)) return(1); for ( ; *cp; cp++) - if ( ! (*cp)(m, n)) + if ( ! (*cp)(man, n)) return(0); return(1); } int -man_valid_post(struct man *m) +man_valid_post(struct man *man) { v_check *cp; - if (MAN_VALID & m->last->flags) + if (MAN_VALID & man->last->flags) return(1); - m->last->flags |= MAN_VALID; + man->last->flags |= MAN_VALID; - switch (m->last->type) { + switch (man->last->type) { case (MAN_TEXT): - check_text(m, m->last); + check_text(man, man->last); return(1); case (MAN_ROOT): - return(check_root(m, m->last)); + return(check_root(man, man->last)); case (MAN_EQN): /* FALLTHROUGH */ case (MAN_TBL): @@ -167,10 +176,10 @@ man_valid_post(struct man *m) break; } - if (NULL == (cp = man_valids[m->last->tok].posts)) + if (NULL == (cp = man_valids[man->last->tok].posts)) return(1); for ( ; *cp; cp++) - if ( ! (*cp)(m, m->last)) + if ( ! (*cp)(man, man->last)) return(0); return(1); @@ -181,29 +190,29 @@ static int check_root(CHKARGS) { - if (MAN_BLINE & m->flags) - man_nmsg(m, n, MANDOCERR_SCOPEEXIT); - else if (MAN_ELINE & m->flags) - man_nmsg(m, n, MANDOCERR_SCOPEEXIT); + if (MAN_BLINE & man->flags) + man_nmsg(man, n, MANDOCERR_SCOPEEXIT); + else if (MAN_ELINE & man->flags) + man_nmsg(man, n, MANDOCERR_SCOPEEXIT); - m->flags &= ~MAN_BLINE; - m->flags &= ~MAN_ELINE; + man->flags &= ~MAN_BLINE; + man->flags &= ~MAN_ELINE; - if (NULL == m->first->child) { - man_nmsg(m, n, MANDOCERR_NODOCBODY); + if (NULL == man->first->child) { + man_nmsg(man, n, MANDOCERR_NODOCBODY); return(0); - } else if (NULL == m->meta.title) { - man_nmsg(m, n, MANDOCERR_NOTITLE); + } else if (NULL == man->meta.title) { + man_nmsg(man, n, MANDOCERR_NOTITLE); /* * If a title hasn't been set, do so now (by * implication, date and section also aren't set). */ - m->meta.title = mandoc_strdup("unknown"); - m->meta.msec = mandoc_strdup("1"); - m->meta.date = mandoc_normdate - (m->parse, NULL, n->line, n->pos); + man->meta.title = mandoc_strdup("unknown"); + man->meta.msec = mandoc_strdup("1"); + man->meta.date = mandoc_normdate + (man->parse, NULL, n->line, n->pos); } return(1); @@ -214,12 +223,12 @@ check_text(CHKARGS) { char *cp, *p; - if (MAN_LITERAL & m->flags) + if (MAN_LITERAL & man->flags) return; cp = n->string; for (p = cp; NULL != (p = strchr(p, '\t')); p++) - man_pmsg(m, n->line, (int)(p - cp), MANDOCERR_BADTAB); + man_pmsg(man, n->line, (int)(p - cp), MANDOCERR_BADTAB); } #define INEQ_DEFINE(x, ineq, name) \ @@ -228,7 +237,7 @@ check_##name(CHKARGS) \ { \ if (n->nchild ineq (x)) \ return(1); \ - mandoc_vmsg(MANDOCERR_ARGCOUNT, m->parse, n->line, n->pos, \ + mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line, n->pos, \ "line arguments %s %d (have %d)", \ #ineq, (x), n->nchild); \ return(1); \ @@ -241,6 +250,17 @@ INEQ_DEFINE(2, >=, ge2) INEQ_DEFINE(5, <=, le5) static int +check_head1(CHKARGS) +{ + + if (MAN_HEAD == n->type && 1 != n->nchild) + mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line, + n->pos, "line arguments eq 1 (have %d)", n->nchild); + + return(1); +} + +static int post_ft(CHKARGS) { char *cp; @@ -282,14 +302,14 @@ post_ft(CHKARGS) if (0 == ok) { mandoc_vmsg - (MANDOCERR_BADFONT, m->parse, + (MANDOCERR_BADFONT, man->parse, n->line, n->pos, "%s", cp); *cp = '\0'; } if (1 < n->nchild) mandoc_vmsg - (MANDOCERR_ARGCOUNT, m->parse, n->line, + (MANDOCERR_ARGCOUNT, man->parse, n->line, n->pos, "want one child (have %d)", n->nchild); @@ -301,7 +321,7 @@ pre_sec(CHKARGS) { if (MAN_BLOCK == n->type) - m->flags &= ~MAN_LITERAL; + man->flags &= ~MAN_LITERAL; return(1); } @@ -312,7 +332,7 @@ post_sec(CHKARGS) if ( ! (MAN_HEAD == n->type && 0 == n->nchild)) return(1); - man_nmsg(m, n, MANDOCERR_SYNTARGCOUNT); + man_nmsg(man, n, MANDOCERR_SYNTARGCOUNT); return(0); } @@ -321,7 +341,7 @@ check_part(CHKARGS) { if (MAN_BODY == n->type && 0 == n->nchild) - mandoc_msg(MANDOCERR_ARGCWARN, m->parse, n->line, + mandoc_msg(MANDOCERR_ARGCWARN, man->parse, n->line, n->pos, "want children (have none)"); return(1); @@ -335,15 +355,15 @@ check_par(CHKARGS) switch (n->type) { case (MAN_BLOCK): if (0 == n->body->nchild) - man_node_delete(m, n); + man_node_delete(man, n); break; case (MAN_BODY): if (0 == n->nchild) - man_nmsg(m, n, MANDOCERR_IGNPAR); + man_nmsg(man, n, MANDOCERR_IGNPAR); break; case (MAN_HEAD): if (n->nchild) - man_nmsg(m, n, MANDOCERR_ARGSLOST); + man_nmsg(man, n, MANDOCERR_ARGSLOST); break; default: break; @@ -352,6 +372,24 @@ check_par(CHKARGS) return(1); } +static int +post_IP(CHKARGS) +{ + + switch (n->type) { + case (MAN_BLOCK): + if (0 == n->head->nchild && 0 == n->body->nchild) + man_node_delete(man, n); + break; + case (MAN_BODY): + if (0 == n->parent->head->nchild && 0 == n->nchild) + man_nmsg(man, n, MANDOCERR_IGNPAR); + break; + default: + break; + } + return(1); +} static int post_TH(CHKARGS) @@ -359,21 +397,16 @@ post_TH(CHKARGS) const char *p; int line, pos; - if (m->meta.title) - free(m->meta.title); - if (m->meta.vol) - free(m->meta.vol); - if (m->meta.source) - free(m->meta.source); - if (m->meta.msec) - free(m->meta.msec); - if (m->meta.date) - free(m->meta.date); + free(man->meta.title); + free(man->meta.vol); + free(man->meta.source); + free(man->meta.msec); + free(man->meta.date); line = n->line; pos = n->pos; - m->meta.title = m->meta.vol = m->meta.date = - m->meta.msec = m->meta.source = NULL; + man->meta.title = man->meta.vol = man->meta.date = + man->meta.msec = man->meta.source = NULL; /* ->TITLE<- MSEC DATE SOURCE VOL */ @@ -383,22 +416,22 @@ post_TH(CHKARGS) /* Only warn about this once... */ if (isalpha((unsigned char)*p) && ! isupper((unsigned char)*p)) { - man_nmsg(m, n, MANDOCERR_UPPERCASE); + man_nmsg(man, n, MANDOCERR_UPPERCASE); break; } } - m->meta.title = mandoc_strdup(n->string); + man->meta.title = mandoc_strdup(n->string); } else - m->meta.title = mandoc_strdup(""); + man->meta.title = mandoc_strdup(""); /* TITLE ->MSEC<- DATE SOURCE VOL */ if (n) n = n->next; if (n && n->string) - m->meta.msec = mandoc_strdup(n->string); + man->meta.msec = mandoc_strdup(n->string); else - m->meta.msec = mandoc_strdup(""); + man->meta.msec = mandoc_strdup(""); /* TITLE MSEC ->DATE<- SOURCE VOL */ @@ -406,30 +439,30 @@ post_TH(CHKARGS) n = n->next; if (n && n->string && '\0' != n->string[0]) { pos = n->pos; - m->meta.date = mandoc_normdate - (m->parse, n->string, line, pos); + man->meta.date = mandoc_normdate + (man->parse, n->string, line, pos); } else - m->meta.date = mandoc_strdup(""); + man->meta.date = mandoc_strdup(""); /* TITLE MSEC DATE ->SOURCE<- VOL */ if (n && (n = n->next)) - m->meta.source = mandoc_strdup(n->string); + man->meta.source = mandoc_strdup(n->string); /* TITLE MSEC DATE SOURCE ->VOL<- */ /* If missing, use the default VOL name for MSEC. */ if (n && (n = n->next)) - m->meta.vol = mandoc_strdup(n->string); - else if ('\0' != m->meta.msec[0] && - (NULL != (p = mandoc_a2msec(m->meta.msec)))) - m->meta.vol = mandoc_strdup(p); + man->meta.vol = mandoc_strdup(n->string); + else if ('\0' != man->meta.msec[0] && + (NULL != (p = mandoc_a2msec(man->meta.msec)))) + man->meta.vol = mandoc_strdup(p); /* * Remove the `TH' node after we've processed it for our * meta-data. */ - man_node_delete(m, m->last); + man_node_delete(man, man->last); return(1); } @@ -437,10 +470,10 @@ static int post_nf(CHKARGS) { - if (MAN_LITERAL & m->flags) - man_nmsg(m, n, MANDOCERR_SCOPEREP); + if (MAN_LITERAL & man->flags) + man_nmsg(man, n, MANDOCERR_SCOPEREP); - m->flags |= MAN_LITERAL; + man->flags |= MAN_LITERAL; return(1); } @@ -448,10 +481,10 @@ static int post_fi(CHKARGS) { - if ( ! (MAN_LITERAL & m->flags)) - man_nmsg(m, n, MANDOCERR_WNOSCOPE); + if ( ! (MAN_LITERAL & man->flags)) + man_nmsg(man, n, MANDOCERR_WNOSCOPE); - m->flags &= ~MAN_LITERAL; + man->flags &= ~MAN_LITERAL; return(1); } @@ -488,10 +521,8 @@ post_UC(CHKARGS) p = bsd_versions[0]; } - if (m->meta.source) - free(m->meta.source); - - m->meta.source = mandoc_strdup(p); + free(man->meta.source); + man->meta.source = mandoc_strdup(p); return(1); } @@ -528,10 +559,8 @@ post_AT(CHKARGS) p = unix_versions[0]; } - if (m->meta.source) - free(m->meta.source); - - m->meta.source = mandoc_strdup(p); + free(man->meta.source); + man->meta.source = mandoc_strdup(p); return(1); } @@ -539,12 +568,25 @@ static int post_vs(CHKARGS) { - /* - * Don't warn about this because it occurs in pod2man and would - * cause considerable (unfixable) warnage. - */ - if (NULL == n->prev && MAN_ROOT == n->parent->type) - man_node_delete(m, n); + if (NULL != n->prev) + return(1); + + switch (n->parent->tok) { + case (MAN_SH): + /* FALLTHROUGH */ + case (MAN_SS): + man_nmsg(man, n, MANDOCERR_IGNPAR); + /* FALLTHROUGH */ + case (MAN_MAX): + /* + * Don't warn about this because it occurs in pod2man + * and would cause considerable (unfixable) warnage. + */ + man_node_delete(man, n); + break; + default: + break; + } return(1); } diff --git a/usr/src/cmd/mandoc/mandoc.c b/usr/src/cmd/mandoc/mandoc.c index 604bb67e6a..da738f20fa 100644 --- a/usr/src/cmd/mandoc/mandoc.c +++ b/usr/src/cmd/mandoc/mandoc.c @@ -1,7 +1,7 @@ -/* $Id: mandoc.c,v 1.62 2011/12/03 16:08:51 schwarze Exp $ */ +/* $Id: mandoc.c,v 1.74 2013/12/30 18:30:32 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -37,83 +37,38 @@ static int a2time(time_t *, const char *, const char *); static char *time2a(time_t); -static int numescape(const char *); -/* - * Pass over recursive numerical expressions. This context of this - * function is important: it's only called within character-terminating - * escapes (e.g., \s[xxxyyy]), so all we need to do is handle initial - * recursion: we don't care about what's in these blocks. - * This returns the number of characters skipped or -1 if an error - * occurs (the caller should bail). - */ -static int -numescape(const char *start) -{ - int i; - size_t sz; - const char *cp; - i = 0; - - /* The expression consists of a subexpression. */ - - if ('\\' == start[i]) { - cp = &start[++i]; - /* - * Read past the end of the subexpression. - * Bail immediately on errors. - */ - if (ESCAPE_ERROR == mandoc_escape(&cp, NULL, NULL)) - return(-1); - return(i + cp - &start[i]); - } - - if ('(' != start[i++]) - return(0); +enum mandoc_esc +mandoc_escape(const char **end, const char **start, int *sz) +{ + const char *local_start; + int local_sz; + char term; + enum mandoc_esc gly; /* - * A parenthesised subexpression. Read until the closing - * parenthesis, making sure to handle any nested subexpressions - * that might ruin our parse. + * When the caller doesn't provide return storage, + * use local storage. */ - while (')' != start[i]) { - sz = strcspn(&start[i], ")\\"); - i += (int)sz; - - if ('\0' == start[i]) - return(-1); - else if ('\\' != start[i]) - continue; - - cp = &start[++i]; - if (ESCAPE_ERROR == mandoc_escape(&cp, NULL, NULL)) - return(-1); - i += cp - &start[i]; - } - - /* Read past the terminating ')'. */ - return(++i); -} + if (NULL == start) + start = &local_start; + if (NULL == sz) + sz = &local_sz; -enum mandoc_esc -mandoc_escape(const char **end, const char **start, int *sz) -{ - char c, term, numeric; - int i, lim, ssz, rlim; - const char *cp, *rstart; - enum mandoc_esc gly; + /* + * Beyond the backslash, at least one input character + * is part of the escape sequence. With one exception + * (see below), that character won't be returned. + */ - cp = *end; - rstart = cp; - if (start) - *start = rstart; - i = lim = 0; gly = ESCAPE_ERROR; - term = numeric = '\0'; + *start = ++*end; + *sz = 0; + term = '\0'; - switch ((c = cp[i++])) { + switch ((*start)[-1]) { /* * First the glyphs. There are several different forms of * these, but each eventually returns a substring of the glyph @@ -121,7 +76,7 @@ mandoc_escape(const char **end, const char **start, int *sz) */ case ('('): gly = ESCAPE_SPECIAL; - lim = 2; + *sz = 2; break; case ('['): gly = ESCAPE_SPECIAL; @@ -131,18 +86,39 @@ mandoc_escape(const char **end, const char **start, int *sz) * Unicode codepoint. Here, however, only check whether * it's not a zero-width escape. */ - if ('u' == cp[i] && ']' != cp[i + 1]) + if ('u' == (*start)[0] && ']' != (*start)[1]) gly = ESCAPE_UNICODE; term = ']'; break; case ('C'): - if ('\'' != cp[i]) + if ('\'' != **start) return(ESCAPE_ERROR); - gly = ESCAPE_SPECIAL; + *start = ++*end; + if ('u' == (*start)[0] && '\'' != (*start)[1]) + gly = ESCAPE_UNICODE; + else + gly = ESCAPE_SPECIAL; term = '\''; break; /* + * Escapes taking no arguments at all. + */ + case ('d'): + /* FALLTHROUGH */ + case ('u'): + return(ESCAPE_IGNORE); + + /* + * The \z escape is supposed to output the following + * character without advancing the cursor position. + * Since we are mostly dealing with terminal mode, + * let us just skip the next character. + */ + case ('z'): + return(ESCAPE_SKIPCHAR); + + /* * Handle all triggers matching \X(xy, \Xx, and \X[xxxx], where * 'X' is the trigger. These have opaque sub-strings. */ @@ -166,21 +142,17 @@ mandoc_escape(const char **end, const char **start, int *sz) case ('f'): if (ESCAPE_ERROR == gly) gly = ESCAPE_FONT; - - rstart= &cp[i]; - if (start) - *start = rstart; - - switch (cp[i++]) { + switch (**start) { case ('('): - lim = 2; + *start = ++*end; + *sz = 2; break; case ('['): + *start = ++*end; term = ']'; break; default: - lim = 1; - i--; + *sz = 1; break; } break; @@ -193,18 +165,23 @@ mandoc_escape(const char **end, const char **start, int *sz) /* FALLTHROUGH */ case ('b'): /* FALLTHROUGH */ + case ('B'): + /* FALLTHROUGH */ case ('D'): /* FALLTHROUGH */ case ('o'): /* FALLTHROUGH */ case ('R'): /* FALLTHROUGH */ + case ('w'): + /* FALLTHROUGH */ case ('X'): /* FALLTHROUGH */ case ('Z'): - if ('\'' != cp[i++]) + if ('\'' != **start) return(ESCAPE_ERROR); gly = ESCAPE_IGNORE; + *start = ++*end; term = '\''; break; @@ -212,8 +189,6 @@ mandoc_escape(const char **end, const char **start, int *sz) * These escapes are of the form \X'N', where 'X' is the trigger * and 'N' resolves to a numerical expression. */ - case ('B'): - /* FALLTHROUGH */ case ('h'): /* FALLTHROUGH */ case ('H'): @@ -221,20 +196,17 @@ mandoc_escape(const char **end, const char **start, int *sz) case ('L'): /* FALLTHROUGH */ case ('l'): - gly = ESCAPE_NUMBERED; /* FALLTHROUGH */ case ('S'): /* FALLTHROUGH */ case ('v'): /* FALLTHROUGH */ - case ('w'): - /* FALLTHROUGH */ case ('x'): - if (ESCAPE_ERROR == gly) - gly = ESCAPE_IGNORE; - if ('\'' != cp[i++]) + if ('\'' != **start) return(ESCAPE_ERROR); - term = numeric = '\''; + gly = ESCAPE_IGNORE; + *start = ++*end; + term = '\''; break; /* @@ -242,17 +214,17 @@ mandoc_escape(const char **end, const char **start, int *sz) * XXX Do any other escapes need similar handling? */ case ('N'): - if ('\0' == cp[i]) + if ('\0' == **start) return(ESCAPE_ERROR); - *end = &cp[++i]; - if (isdigit((unsigned char)cp[i-1])) + (*end)++; + if (isdigit((unsigned char)**start)) { + *sz = 1; return(ESCAPE_IGNORE); + } + (*start)++; while (isdigit((unsigned char)**end)) (*end)++; - if (start) - *start = &cp[i]; - if (sz) - *sz = *end - &cp[i]; + *sz = *end - *start; if ('\0' != **end) (*end)++; return(ESCAPE_NUMBERED); @@ -263,122 +235,93 @@ mandoc_escape(const char **end, const char **start, int *sz) case ('s'): gly = ESCAPE_IGNORE; - rstart = &cp[i]; - if (start) - *start = rstart; - /* See +/- counts as a sign. */ - c = cp[i]; - if ('+' == c || '-' == c || ASCII_HYPH == c) - ++i; + if ('+' == **end || '-' == **end || ASCII_HYPH == **end) + (*end)++; - switch (cp[i++]) { + switch (**end) { case ('('): - lim = 2; + *start = ++*end; + *sz = 2; break; case ('['): - term = numeric = ']'; + *start = ++*end; + term = ']'; break; case ('\''): - term = numeric = '\''; + *start = ++*end; + term = '\''; break; default: - lim = 1; - i--; + *sz = 1; break; } - /* See +/- counts as a sign. */ - c = cp[i]; - if ('+' == c || '-' == c || ASCII_HYPH == c) - ++i; - break; /* * Anything else is assumed to be a glyph. + * In this case, pass back the character after the backslash. */ default: gly = ESCAPE_SPECIAL; - lim = 1; - i--; + *start = --*end; + *sz = 1; break; } assert(ESCAPE_ERROR != gly); - rstart = &cp[i]; - if (start) - *start = rstart; - /* - * If a terminating block has been specified, we need to - * handle the case of recursion, which could have their - * own terminating blocks that mess up our parse. This, by the - * way, means that the "start" and "size" values will be - * effectively meaningless. - */ - - ssz = 0; - if (numeric && -1 == (ssz = numescape(&cp[i]))) - return(ESCAPE_ERROR); - - i += ssz; - rlim = -1; - - /* - * We have a character terminator. Try to read up to that - * character. If we can't (i.e., we hit the nil), then return - * an error; if we can, calculate our length, read past the - * terminating character, and exit. + * Read up to the terminating character, + * paying attention to nested escapes. */ if ('\0' != term) { - *end = strchr(&cp[i], term); - if ('\0' == *end) + while (**end != term) { + switch (**end) { + case ('\0'): + return(ESCAPE_ERROR); + case ('\\'): + (*end)++; + if (ESCAPE_ERROR == + mandoc_escape(end, NULL, NULL)) + return(ESCAPE_ERROR); + break; + default: + (*end)++; + break; + } + } + *sz = (*end)++ - *start; + } else { + assert(*sz > 0); + if ((size_t)*sz > strlen(*start)) return(ESCAPE_ERROR); - - rlim = *end - &cp[i]; - if (sz) - *sz = rlim; - (*end)++; - goto out; + *end += *sz; } - assert(lim > 0); - - /* - * We have a numeric limit. If the string is shorter than that, - * stop and return an error. Else adjust our endpoint, length, - * and return the current glyph. - */ - - if ((size_t)lim > strlen(&cp[i])) - return(ESCAPE_ERROR); - - rlim = lim; - if (sz) - *sz = rlim; - - *end = &cp[i] + lim; - -out: - assert(rlim >= 0 && rstart); - /* Run post-processors. */ switch (gly) { case (ESCAPE_FONT): - /* - * Pretend that the constant-width font modes are the - * same as the regular font modes. - */ - if (2 == rlim && 'C' == *rstart) - rstart++; - else if (1 != rlim) + if (2 == *sz) { + if ('C' == **start) { + /* + * Treat constant-width font modes + * just like regular font modes. + */ + (*start)++; + (*sz)--; + } else { + if ('B' == (*start)[0] && 'I' == (*start)[1]) + gly = ESCAPE_FONTBI; + break; + } + } else if (1 != *sz) break; - switch (*rstart) { + switch (**start) { case ('3'): /* FALLTHROUGH */ case ('B'): @@ -400,9 +343,7 @@ out: } break; case (ESCAPE_SPECIAL): - if (1 != rlim) - break; - if ('c' == *rstart) + if (1 == *sz && 'c' == **start) gly = ESCAPE_NOSPACE; break; default: @@ -484,10 +425,10 @@ mandoc_strdup(const char *ptr) * Parse a quoted or unquoted roff-style request or macro argument. * Return a pointer to the parsed argument, which is either the original * pointer or advanced by one byte in case the argument is quoted. - * Null-terminate the argument in place. + * NUL-terminate the argument in place. * Collapse pairs of quotes inside quoted arguments. * Advance the argument pointer to the next argument, - * or to the null byte terminating the argument line. + * or to the NUL byte terminating the argument line. */ char * mandoc_getarg(struct mparse *parse, char **cpp, int ln, int *pos) @@ -506,17 +447,35 @@ mandoc_getarg(struct mparse *parse, char **cpp, int ln, int *pos) pairs = 0; white = 0; for (cp = start; '\0' != *cp; cp++) { - /* Move left after quoted quotes and escaped backslashes. */ + + /* + * Move the following text left + * after quoted quotes and after "\\" and "\t". + */ if (pairs) cp[-pairs] = cp[0]; + if ('\\' == cp[0]) { - if ('\\' == cp[1]) { - /* Poor man's copy mode. */ + /* + * In copy mode, translate double to single + * backslashes and backslash-t to literal tabs. + */ + switch (cp[1]) { + case ('t'): + cp[0] = '\t'; + /* FALLTHROUGH */ + case ('\\'): pairs++; cp++; - } else if (0 == quoted && ' ' == cp[1]) + break; + case (' '): /* Skip escaped blanks. */ - cp++; + if (0 == quoted) + cp++; + break; + default: + break; + } } else if (0 == quoted) { if (' ' == cp[0]) { /* Unescaped blanks end unquoted args. */ @@ -540,7 +499,7 @@ mandoc_getarg(struct mparse *parse, char **cpp, int ln, int *pos) if (1 == quoted) mandoc_msg(MANDOCERR_BADQUOTE, parse, ln, *pos, NULL); - /* Null-terminate this argument and move to the next one. */ + /* NUL-terminate this argument and move to the next one. */ if (pairs) cp[-pairs] = '\0'; if ('\0' != *cp) { @@ -678,32 +637,6 @@ mandoc_eos(const char *p, size_t sz, int enclosed) } /* - * Find out whether a line is a macro line or not. If it is, adjust the - * current position and return one; if it isn't, return zero and don't - * change the current position. - */ -int -mandoc_getcontrol(const char *cp, int *ppos) -{ - int pos; - - pos = *ppos; - - if ('\\' == cp[pos] && '.' == cp[pos + 1]) - pos += 2; - else if ('.' == cp[pos] || '\'' == cp[pos]) - pos++; - else - return(0); - - while (' ' == cp[pos] || '\t' == cp[pos]) - pos++; - - *ppos = pos; - return(1); -} - -/* * Convert a string to a long that may not be <0. * If the string is invalid, or is less than 0, return -1. */ diff --git a/usr/src/cmd/mandoc/mandoc.h b/usr/src/cmd/mandoc/mandoc.h index a37effc5f5..4c6a32f7a6 100644 --- a/usr/src/cmd/mandoc/mandoc.h +++ b/usr/src/cmd/mandoc/mandoc.h @@ -1,6 +1,7 @@ -/* $Id: mandoc.h,v 1.99 2012/02/16 20:51:31 joerg Exp $ */ +/* $Id: mandoc.h,v 1.112 2013/12/30 18:30:32 schwarze Exp $ */ /* * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -50,6 +51,7 @@ enum mandocerr { MANDOCERR_NOTITLE, /* no title in document */ MANDOCERR_UPPERCASE, /* document title should be all caps */ MANDOCERR_BADMSEC, /* unknown manual section */ + MANDOCERR_BADVOLARCH, /* unknown manual volume or arch */ MANDOCERR_NODATE, /* date missing, using today's date */ MANDOCERR_BADDATE, /* cannot parse date, using it verbatim */ MANDOCERR_PROLOGOOO, /* prologue macros out of order */ @@ -61,14 +63,14 @@ enum mandocerr { MANDOCERR_SO, /* .so is fragile, better use ln(1) */ MANDOCERR_NAMESECFIRST, /* NAME section must come first */ MANDOCERR_BADNAMESEC, /* bad NAME section contents */ - MANDOCERR_NONAME, /* manual name not yet set */ MANDOCERR_SECOOO, /* sections out of conventional order */ MANDOCERR_SECREP, /* duplicate section name */ - MANDOCERR_SECMSEC, /* section not in conventional manual section */ + MANDOCERR_SECMSEC, /* section header suited to sections ... */ /* related to macros and nesting */ MANDOCERR_MACROOBS, /* skipping obsolete macro */ MANDOCERR_IGNPAR, /* skipping paragraph macro */ + MANDOCERR_MOVEPAR, /* moving paragraph macro out of list */ MANDOCERR_IGNNS, /* skipping no-space macro */ MANDOCERR_SCOPENEST, /* blocks badly nested */ MANDOCERR_CHILD, /* child violates parent syntax */ @@ -129,10 +131,12 @@ enum mandocerr { MANDOCERR_ROFFLOOP, /* input stack limit exceeded, infinite loop? */ MANDOCERR_BADCHAR, /* skipping bad character */ MANDOCERR_NAMESC, /* escaped character not allowed in a name */ + MANDOCERR_NONAME, /* manual name not yet set */ MANDOCERR_NOTEXT, /* skipping text before the first section header */ MANDOCERR_MACRO, /* skipping unknown macro */ MANDOCERR_REQUEST, /* NOT IMPLEMENTED: skipping request */ MANDOCERR_ARGCOUNT, /* argument count wrong */ + MANDOCERR_STRAYTA, /* skipping column outside column list */ MANDOCERR_NOSCOPE, /* skipping end of block that is not open */ MANDOCERR_SCOPEBROKEN, /* missing end of block */ MANDOCERR_SCOPEEXIT, /* scope open on exit */ @@ -141,6 +145,7 @@ enum mandocerr { MANDOCERR_NOARGS, /* macro requires line argument(s) */ MANDOCERR_NOBODY, /* macro requires body argument(s) */ MANDOCERR_NOARGV, /* macro requires argument(s) */ + MANDOCERR_NUMERIC, /* request requires a numeric argument */ MANDOCERR_LISTTYPE, /* missing list type */ MANDOCERR_ARGSLOST, /* line argument(s) will be lost */ MANDOCERR_BODYLOST, /* body argument(s) will be lost */ @@ -160,7 +165,7 @@ enum mandocerr { MANDOCERR_MAX }; -struct tbl { +struct tbl_opts { char tab; /* cell-separator */ char decimal; /* decimal point */ int linesize; @@ -175,20 +180,14 @@ struct tbl { int cols; /* number of columns */ }; -enum tbl_headt { - TBL_HEAD_DATA, /* plug in data from tbl_dat */ - TBL_HEAD_VERT, /* vertical spacer */ - TBL_HEAD_DVERT /* double-vertical spacer */ -}; - /* * The head of a table specifies all of its columns. When formatting a * tbl_span, iterate over these and plug in data from the tbl_span when * appropriate, using tbl_cell as a guide to placement. */ struct tbl_head { - enum tbl_headt pos; int ident; /* 0 <= unique id < cols */ + int vert; /* width of preceding vertical line */ struct tbl_head *next; struct tbl_head *prev; }; @@ -203,8 +202,6 @@ enum tbl_cellt { TBL_CELL_DOWN, /* ^ */ TBL_CELL_HORIZ, /* _, - */ TBL_CELL_DHORIZ, /* = */ - TBL_CELL_VERT, /* | */ - TBL_CELL_DVERT, /* || */ TBL_CELL_MAX }; @@ -213,6 +210,7 @@ enum tbl_cellt { */ struct tbl_cell { struct tbl_cell *next; + int vert; /* width of preceding vertical line */ enum tbl_cellt pos; size_t spacing; int flags; @@ -266,7 +264,7 @@ enum tbl_spant { * A row of data in a table. */ struct tbl_span { - struct tbl *tbl; + struct tbl_opts *opts; struct tbl_head *head; struct tbl_row *layout; /* layout row */ struct tbl_dat *first; @@ -382,11 +380,13 @@ enum mandoc_esc { ESCAPE_FONT, /* a generic font mode */ ESCAPE_FONTBOLD, /* bold font mode */ ESCAPE_FONTITALIC, /* italic font mode */ + ESCAPE_FONTBI, /* bold italic font mode */ ESCAPE_FONTROMAN, /* roman font mode */ ESCAPE_FONTPREV, /* previous font mode */ ESCAPE_NUMBERED, /* a numbered glyph */ ESCAPE_UNICODE, /* a unicode codepoint */ - ESCAPE_NOSPACE /* suppress space if the last on a line */ + ESCAPE_NOSPACE, /* suppress space if the last on a line */ + ESCAPE_SKIPCHAR /* skip the next character */ }; typedef void (*mandocmsg)(enum mandocerr, enum mandoclevel, @@ -413,8 +413,8 @@ int mchars_spec2cp(const struct mchars *, const char *, size_t); const char *mchars_spec2str(const struct mchars *, const char *, size_t, size_t *); -struct mparse *mparse_alloc(enum mparset, - enum mandoclevel, mandocmsg, void *); +struct mparse *mparse_alloc(enum mparset, enum mandoclevel, + mandocmsg, void *, char *); void mparse_free(struct mparse *); void mparse_keep(struct mparse *); enum mandoclevel mparse_readfd(struct mparse *, int, const char *); diff --git a/usr/src/cmd/mandoc/mdoc.c b/usr/src/cmd/mandoc/mdoc.c index 81a4ffc96f..87b358797b 100644 --- a/usr/src/cmd/mandoc/mdoc.c +++ b/usr/src/cmd/mandoc/mdoc.c @@ -1,7 +1,7 @@ -/* $Id: mdoc.c,v 1.196 2011/09/30 00:13:28 schwarze Exp $ */ +/* $Id: mdoc.c,v 1.206 2013/12/24 19:11:46 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -104,20 +104,20 @@ static int mdoc_ptext(struct mdoc *, int, char *, int); static int mdoc_pmacro(struct mdoc *, int, char *, int); const struct mdoc_node * -mdoc_node(const struct mdoc *m) +mdoc_node(const struct mdoc *mdoc) { - assert( ! (MDOC_HALT & m->flags)); - return(m->first); + assert( ! (MDOC_HALT & mdoc->flags)); + return(mdoc->first); } const struct mdoc_meta * -mdoc_meta(const struct mdoc *m) +mdoc_meta(const struct mdoc *mdoc) { - assert( ! (MDOC_HALT & m->flags)); - return(&m->meta); + assert( ! (MDOC_HALT & mdoc->flags)); + return(&mdoc->meta); } @@ -197,13 +197,14 @@ mdoc_free(struct mdoc *mdoc) * Allocate volatile and non-volatile parse resources. */ struct mdoc * -mdoc_alloc(struct roff *roff, struct mparse *parse) +mdoc_alloc(struct roff *roff, struct mparse *parse, char *defos) { struct mdoc *p; p = mandoc_calloc(1, sizeof(struct mdoc)); p->parse = parse; + p->defos = defos; p->roff = roff; mdoc_hash_init(); @@ -217,61 +218,61 @@ mdoc_alloc(struct roff *roff, struct mparse *parse) * through to macro_end() in macro.c. */ int -mdoc_endparse(struct mdoc *m) +mdoc_endparse(struct mdoc *mdoc) { - assert( ! (MDOC_HALT & m->flags)); - if (mdoc_macroend(m)) + assert( ! (MDOC_HALT & mdoc->flags)); + if (mdoc_macroend(mdoc)) return(1); - m->flags |= MDOC_HALT; + mdoc->flags |= MDOC_HALT; return(0); } int -mdoc_addeqn(struct mdoc *m, const struct eqn *ep) +mdoc_addeqn(struct mdoc *mdoc, const struct eqn *ep) { struct mdoc_node *n; - assert( ! (MDOC_HALT & m->flags)); + assert( ! (MDOC_HALT & mdoc->flags)); /* No text before an initial macro. */ - if (SEC_NONE == m->lastnamed) { - mdoc_pmsg(m, ep->ln, ep->pos, MANDOCERR_NOTEXT); + if (SEC_NONE == mdoc->lastnamed) { + mdoc_pmsg(mdoc, ep->ln, ep->pos, MANDOCERR_NOTEXT); return(1); } - n = node_alloc(m, ep->ln, ep->pos, MDOC_MAX, MDOC_EQN); + n = node_alloc(mdoc, ep->ln, ep->pos, MDOC_MAX, MDOC_EQN); n->eqn = ep; - if ( ! node_append(m, n)) + if ( ! node_append(mdoc, n)) return(0); - m->next = MDOC_NEXT_SIBLING; + mdoc->next = MDOC_NEXT_SIBLING; return(1); } int -mdoc_addspan(struct mdoc *m, const struct tbl_span *sp) +mdoc_addspan(struct mdoc *mdoc, const struct tbl_span *sp) { struct mdoc_node *n; - assert( ! (MDOC_HALT & m->flags)); + assert( ! (MDOC_HALT & mdoc->flags)); /* No text before an initial macro. */ - if (SEC_NONE == m->lastnamed) { - mdoc_pmsg(m, sp->line, 0, MANDOCERR_NOTEXT); + if (SEC_NONE == mdoc->lastnamed) { + mdoc_pmsg(mdoc, sp->line, 0, MANDOCERR_NOTEXT); return(1); } - n = node_alloc(m, sp->line, 0, MDOC_MAX, MDOC_TBL); + n = node_alloc(mdoc, sp->line, 0, MDOC_MAX, MDOC_TBL); n->span = sp; - if ( ! node_append(m, n)) + if ( ! node_append(mdoc, n)) return(0); - m->next = MDOC_NEXT_SIBLING; + mdoc->next = MDOC_NEXT_SIBLING; return(1); } @@ -281,12 +282,12 @@ mdoc_addspan(struct mdoc *m, const struct tbl_span *sp) * the macro (mdoc_pmacro()) or text parser (mdoc_ptext()). */ int -mdoc_parseln(struct mdoc *m, int ln, char *buf, int offs) +mdoc_parseln(struct mdoc *mdoc, int ln, char *buf, int offs) { - assert( ! (MDOC_HALT & m->flags)); + assert( ! (MDOC_HALT & mdoc->flags)); - m->flags |= MDOC_NEWLINE; + mdoc->flags |= MDOC_NEWLINE; /* * Let the roff nS register switch SYNOPSIS mode early, @@ -294,16 +295,14 @@ mdoc_parseln(struct mdoc *m, int ln, char *buf, int offs) * whether this mode is on or off. * Note that this mode is also switched by the Sh macro. */ - if (roff_regisset(m->roff, REG_nS)) { - if (roff_regget(m->roff, REG_nS)) - m->flags |= MDOC_SYNOPSIS; - else - m->flags &= ~MDOC_SYNOPSIS; - } + if (roff_getreg(mdoc->roff, "nS")) + mdoc->flags |= MDOC_SYNOPSIS; + else + mdoc->flags &= ~MDOC_SYNOPSIS; - return(mandoc_getcontrol(buf, &offs) ? - mdoc_pmacro(m, ln, buf, offs) : - mdoc_ptext(m, ln, buf, offs)); + return(roff_getcontrol(mdoc->roff, buf, &offs) ? + mdoc_pmacro(mdoc, ln, buf, offs) : + mdoc_ptext(mdoc, ln, buf, offs)); } int @@ -314,31 +313,31 @@ mdoc_macro(MACRO_PROT_ARGS) /* If we're in the body, deny prologue calls. */ if (MDOC_PROLOGUE & mdoc_macros[tok].flags && - MDOC_PBODY & m->flags) { - mdoc_pmsg(m, line, ppos, MANDOCERR_BADBODY); + MDOC_PBODY & mdoc->flags) { + mdoc_pmsg(mdoc, line, ppos, MANDOCERR_BADBODY); return(1); } /* If we're in the prologue, deny "body" macros. */ if ( ! (MDOC_PROLOGUE & mdoc_macros[tok].flags) && - ! (MDOC_PBODY & m->flags)) { - mdoc_pmsg(m, line, ppos, MANDOCERR_BADPROLOG); - if (NULL == m->meta.msec) - m->meta.msec = mandoc_strdup("1"); - if (NULL == m->meta.title) - m->meta.title = mandoc_strdup("UNKNOWN"); - if (NULL == m->meta.vol) - m->meta.vol = mandoc_strdup("LOCAL"); - if (NULL == m->meta.os) - m->meta.os = mandoc_strdup("LOCAL"); - if (NULL == m->meta.date) - m->meta.date = mandoc_normdate - (m->parse, NULL, line, ppos); - m->flags |= MDOC_PBODY; + ! (MDOC_PBODY & mdoc->flags)) { + mdoc_pmsg(mdoc, line, ppos, MANDOCERR_BADPROLOG); + if (NULL == mdoc->meta.msec) + mdoc->meta.msec = mandoc_strdup("1"); + if (NULL == mdoc->meta.title) + mdoc->meta.title = mandoc_strdup("UNKNOWN"); + if (NULL == mdoc->meta.vol) + mdoc->meta.vol = mandoc_strdup("LOCAL"); + if (NULL == mdoc->meta.os) + mdoc->meta.os = mandoc_strdup("LOCAL"); + if (NULL == mdoc->meta.date) + mdoc->meta.date = mandoc_normdate + (mdoc->parse, NULL, line, ppos); + mdoc->flags |= MDOC_PBODY; } - return((*mdoc_macros[tok].fp)(m, tok, line, ppos, pos, buf)); + return((*mdoc_macros[tok].fp)(mdoc, tok, line, ppos, pos, buf)); } @@ -374,6 +373,8 @@ node_append(struct mdoc *mdoc, struct mdoc_node *p) switch (p->type) { case (MDOC_BODY): + if (ENDBODY_NOT != p->end) + break; /* FALLTHROUGH */ case (MDOC_TAIL): /* FALLTHROUGH */ @@ -424,97 +425,99 @@ node_append(struct mdoc *mdoc, struct mdoc_node *p) static struct mdoc_node * -node_alloc(struct mdoc *m, int line, int pos, +node_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok, enum mdoc_type type) { struct mdoc_node *p; p = mandoc_calloc(1, sizeof(struct mdoc_node)); - p->sec = m->lastsec; + p->sec = mdoc->lastsec; p->line = line; p->pos = pos; + p->lastline = line; p->tok = tok; p->type = type; /* Flag analysis. */ - if (MDOC_SYNOPSIS & m->flags) + if (MDOC_SYNOPSIS & mdoc->flags) p->flags |= MDOC_SYNPRETTY; else p->flags &= ~MDOC_SYNPRETTY; - if (MDOC_NEWLINE & m->flags) + if (MDOC_NEWLINE & mdoc->flags) p->flags |= MDOC_LINE; - m->flags &= ~MDOC_NEWLINE; + mdoc->flags &= ~MDOC_NEWLINE; return(p); } int -mdoc_tail_alloc(struct mdoc *m, int line, int pos, enum mdoct tok) +mdoc_tail_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok) { struct mdoc_node *p; - p = node_alloc(m, line, pos, tok, MDOC_TAIL); - if ( ! node_append(m, p)) + p = node_alloc(mdoc, line, pos, tok, MDOC_TAIL); + if ( ! node_append(mdoc, p)) return(0); - m->next = MDOC_NEXT_CHILD; + mdoc->next = MDOC_NEXT_CHILD; return(1); } int -mdoc_head_alloc(struct mdoc *m, int line, int pos, enum mdoct tok) +mdoc_head_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok) { struct mdoc_node *p; - assert(m->first); - assert(m->last); + assert(mdoc->first); + assert(mdoc->last); - p = node_alloc(m, line, pos, tok, MDOC_HEAD); - if ( ! node_append(m, p)) + p = node_alloc(mdoc, line, pos, tok, MDOC_HEAD); + if ( ! node_append(mdoc, p)) return(0); - m->next = MDOC_NEXT_CHILD; + mdoc->next = MDOC_NEXT_CHILD; return(1); } int -mdoc_body_alloc(struct mdoc *m, int line, int pos, enum mdoct tok) +mdoc_body_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok) { struct mdoc_node *p; - p = node_alloc(m, line, pos, tok, MDOC_BODY); - if ( ! node_append(m, p)) + p = node_alloc(mdoc, line, pos, tok, MDOC_BODY); + if ( ! node_append(mdoc, p)) return(0); - m->next = MDOC_NEXT_CHILD; + mdoc->next = MDOC_NEXT_CHILD; return(1); } int -mdoc_endbody_alloc(struct mdoc *m, int line, int pos, enum mdoct tok, +mdoc_endbody_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok, struct mdoc_node *body, enum mdoc_endbody end) { struct mdoc_node *p; - p = node_alloc(m, line, pos, tok, MDOC_BODY); + p = node_alloc(mdoc, line, pos, tok, MDOC_BODY); p->pending = body; + p->norm = body->norm; p->end = end; - if ( ! node_append(m, p)) + if ( ! node_append(mdoc, p)) return(0); - m->next = MDOC_NEXT_SIBLING; + mdoc->next = MDOC_NEXT_SIBLING; return(1); } int -mdoc_block_alloc(struct mdoc *m, int line, int pos, +mdoc_block_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok, struct mdoc_arg *args) { struct mdoc_node *p; - p = node_alloc(m, line, pos, tok, MDOC_BLOCK); + p = node_alloc(mdoc, line, pos, tok, MDOC_BLOCK); p->args = args; if (p->args) (args->refcnt)++; @@ -533,20 +536,20 @@ mdoc_block_alloc(struct mdoc *m, int line, int pos, break; } - if ( ! node_append(m, p)) + if ( ! node_append(mdoc, p)) return(0); - m->next = MDOC_NEXT_CHILD; + mdoc->next = MDOC_NEXT_CHILD; return(1); } int -mdoc_elem_alloc(struct mdoc *m, int line, int pos, +mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok, struct mdoc_arg *args) { struct mdoc_node *p; - p = node_alloc(m, line, pos, tok, MDOC_ELEM); + p = node_alloc(mdoc, line, pos, tok, MDOC_ELEM); p->args = args; if (p->args) (args->refcnt)++; @@ -559,27 +562,44 @@ mdoc_elem_alloc(struct mdoc *m, int line, int pos, break; } - if ( ! node_append(m, p)) + if ( ! node_append(mdoc, p)) return(0); - m->next = MDOC_NEXT_CHILD; + mdoc->next = MDOC_NEXT_CHILD; return(1); } int -mdoc_word_alloc(struct mdoc *m, int line, int pos, const char *p) +mdoc_word_alloc(struct mdoc *mdoc, int line, int pos, const char *p) { struct mdoc_node *n; - n = node_alloc(m, line, pos, MDOC_MAX, MDOC_TEXT); - n->string = roff_strdup(m->roff, p); + n = node_alloc(mdoc, line, pos, MDOC_MAX, MDOC_TEXT); + n->string = roff_strdup(mdoc->roff, p); - if ( ! node_append(m, n)) + if ( ! node_append(mdoc, n)) return(0); - m->next = MDOC_NEXT_SIBLING; + mdoc->next = MDOC_NEXT_SIBLING; return(1); } +void +mdoc_word_append(struct mdoc *mdoc, const char *p) +{ + struct mdoc_node *n; + char *addstr, *newstr; + + n = mdoc->last; + addstr = roff_strdup(mdoc->roff, p); + if (-1 == asprintf(&newstr, "%s %s", n->string, addstr)) { + perror(NULL); + exit((int)MANDOCLEVEL_SYSERR); + } + free(addstr); + free(n->string); + n->string = newstr; + mdoc->next = MDOC_NEXT_SIBLING; +} static void mdoc_node_free(struct mdoc_node *p) @@ -596,7 +616,7 @@ mdoc_node_free(struct mdoc_node *p) static void -mdoc_node_unlink(struct mdoc *m, struct mdoc_node *n) +mdoc_node_unlink(struct mdoc *mdoc, struct mdoc_node *n) { /* Adjust siblings. */ @@ -618,35 +638,43 @@ mdoc_node_unlink(struct mdoc *m, struct mdoc_node *n) /* Adjust parse point, if applicable. */ - if (m && m->last == n) { + if (mdoc && mdoc->last == n) { if (n->prev) { - m->last = n->prev; - m->next = MDOC_NEXT_SIBLING; + mdoc->last = n->prev; + mdoc->next = MDOC_NEXT_SIBLING; } else { - m->last = n->parent; - m->next = MDOC_NEXT_CHILD; + mdoc->last = n->parent; + mdoc->next = MDOC_NEXT_CHILD; } } - if (m && m->first == n) - m->first = NULL; + if (mdoc && mdoc->first == n) + mdoc->first = NULL; } void -mdoc_node_delete(struct mdoc *m, struct mdoc_node *p) +mdoc_node_delete(struct mdoc *mdoc, struct mdoc_node *p) { while (p->child) { assert(p->nchild); - mdoc_node_delete(m, p->child); + mdoc_node_delete(mdoc, p->child); } assert(0 == p->nchild); - mdoc_node_unlink(m, p); + mdoc_node_unlink(mdoc, p); mdoc_node_free(p); } +int +mdoc_node_relink(struct mdoc *mdoc, struct mdoc_node *p) +{ + + mdoc_node_unlink(mdoc, p); + return(node_append(mdoc, p)); +} + #if 0 /* * Pre-treat a text line. @@ -658,7 +686,7 @@ mdoc_node_delete(struct mdoc *m, struct mdoc_node *p) * the end-of-line, i.e., will re-enter in the next roff parse. */ static int -mdoc_preptext(struct mdoc *m, int line, char *buf, int offs) +mdoc_preptext(struct mdoc *mdoc, int line, char *buf, int offs) { char *start, *end; char delim; @@ -666,12 +694,12 @@ mdoc_preptext(struct mdoc *m, int line, char *buf, int offs) while ('\0' != buf[offs]) { /* Mark starting position if eqn is set. */ start = NULL; - if ('\0' != (delim = roff_eqndelim(m->roff))) + if ('\0' != (delim = roff_eqndelim(mdoc->roff))) if (NULL != (start = strchr(buf + offs, delim))) *start++ = '\0'; /* Parse text as normal. */ - if ( ! mdoc_ptext(m, line, buf, offs)) + if ( ! mdoc_ptext(mdoc, line, buf, offs)) return(0); /* Continue only if an equation exists. */ @@ -688,11 +716,11 @@ mdoc_preptext(struct mdoc *m, int line, char *buf, int offs) } /* Parse the equation itself. */ - roff_openeqn(m->roff, NULL, line, offs, buf); + roff_openeqn(mdoc->roff, NULL, line, offs, buf); /* Process a finished equation? */ - if (roff_closeeqn(m->roff)) - if ( ! mdoc_addeqn(m, roff_eqn(m->roff))) + if (roff_closeeqn(mdoc->roff)) + if ( ! mdoc_addeqn(mdoc, roff_eqn(mdoc->roff))) return(0); offs += (end - (buf + offs)); } @@ -706,20 +734,20 @@ mdoc_preptext(struct mdoc *m, int line, char *buf, int offs) * control character. */ static int -mdoc_ptext(struct mdoc *m, int line, char *buf, int offs) +mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs) { char *c, *ws, *end; struct mdoc_node *n; /* No text before an initial macro. */ - if (SEC_NONE == m->lastnamed) { - mdoc_pmsg(m, line, offs, MANDOCERR_NOTEXT); + if (SEC_NONE == mdoc->lastnamed) { + mdoc_pmsg(mdoc, line, offs, MANDOCERR_NOTEXT); return(1); } - assert(m->last); - n = m->last; + assert(mdoc->last); + n = mdoc->last; /* * Divert directly to list processing if we're encountering a @@ -731,8 +759,8 @@ mdoc_ptext(struct mdoc *m, int line, char *buf, int offs) if (MDOC_Bl == n->tok && MDOC_BODY == n->type && LIST_column == n->norm->Bl.type) { /* `Bl' is open without any children. */ - m->flags |= MDOC_FREECOL; - return(mdoc_macro(m, MDOC_It, line, offs, &offs, buf)); + mdoc->flags |= MDOC_FREECOL; + return(mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf)); } if (MDOC_It == n->tok && MDOC_BLOCK == n->type && @@ -740,8 +768,8 @@ mdoc_ptext(struct mdoc *m, int line, char *buf, int offs) MDOC_Bl == n->parent->tok && LIST_column == n->parent->norm->Bl.type) { /* `Bl' has block-level `It' children. */ - m->flags |= MDOC_FREECOL; - return(mdoc_macro(m, MDOC_It, line, offs, &offs, buf)); + mdoc->flags |= MDOC_FREECOL; + return(mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf)); } /* @@ -769,7 +797,7 @@ mdoc_ptext(struct mdoc *m, int line, char *buf, int offs) * Strip trailing tabs in literal context only; * outside, they affect the next line. */ - if (MDOC_LITERAL & m->flags) + if (MDOC_LITERAL & mdoc->flags) continue; break; case '\\': @@ -786,27 +814,28 @@ mdoc_ptext(struct mdoc *m, int line, char *buf, int offs) *end = '\0'; if (ws) - mdoc_pmsg(m, line, (int)(ws-buf), MANDOCERR_EOLNSPACE); + mdoc_pmsg(mdoc, line, (int)(ws-buf), MANDOCERR_EOLNSPACE); - if ('\0' == buf[offs] && ! (MDOC_LITERAL & m->flags)) { - mdoc_pmsg(m, line, (int)(c-buf), MANDOCERR_NOBLANKLN); + if ('\0' == buf[offs] && ! (MDOC_LITERAL & mdoc->flags)) { + mdoc_pmsg(mdoc, line, (int)(c-buf), MANDOCERR_NOBLANKLN); /* * Insert a `sp' in the case of a blank line. Technically, * blank lines aren't allowed, but enough manuals assume this * behaviour that we want to work around it. */ - if ( ! mdoc_elem_alloc(m, line, offs, MDOC_sp, NULL)) + if ( ! mdoc_elem_alloc(mdoc, line, offs, MDOC_sp, NULL)) return(0); - m->next = MDOC_NEXT_SIBLING; - return(1); + mdoc->next = MDOC_NEXT_SIBLING; + + return(mdoc_valid_post(mdoc)); } - if ( ! mdoc_word_alloc(m, line, offs, buf+offs)) + if ( ! mdoc_word_alloc(mdoc, line, offs, buf+offs)) return(0); - if (MDOC_LITERAL & m->flags) + if (MDOC_LITERAL & mdoc->flags) return(1); /* @@ -818,7 +847,7 @@ mdoc_ptext(struct mdoc *m, int line, char *buf, int offs) assert(buf < end); if (mandoc_eos(buf+offs, (size_t)(end-buf-offs), 0)) - m->last->flags |= MDOC_EOS; + mdoc->last->flags |= MDOC_EOS; return(1); } @@ -829,7 +858,7 @@ mdoc_ptext(struct mdoc *m, int line, char *buf, int offs) * character. */ static int -mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs) +mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs) { enum mdoct tok; int i, sv; @@ -839,7 +868,7 @@ mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs) /* Empty post-control lines are ignored. */ if ('"' == buf[offs]) { - mdoc_pmsg(m, ln, offs, MANDOCERR_BADCOMMENT); + mdoc_pmsg(mdoc, ln, offs, MANDOCERR_BADCOMMENT); return(1); } else if ('\0' == buf[offs]) return(1); @@ -861,7 +890,7 @@ mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs) tok = (i > 1 || i < 4) ? mdoc_hash_find(mac) : MDOC_MAX; if (MDOC_MAX == tok) { - mandoc_vmsg(MANDOCERR_MACRO, m->parse, + mandoc_vmsg(MANDOCERR_MACRO, mdoc->parse, ln, sv, "%s", buf + sv - 1); return(1); } @@ -882,21 +911,21 @@ mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs) */ if ('\0' == buf[offs] && ' ' == buf[offs - 1]) - mdoc_pmsg(m, ln, offs - 1, MANDOCERR_EOLNSPACE); + mdoc_pmsg(mdoc, ln, offs - 1, MANDOCERR_EOLNSPACE); /* * If an initial macro or a list invocation, divert directly * into macro processing. */ - if (NULL == m->last || MDOC_It == tok || MDOC_El == tok) { - if ( ! mdoc_macro(m, tok, ln, sv, &offs, buf)) + if (NULL == mdoc->last || MDOC_It == tok || MDOC_El == tok) { + if ( ! mdoc_macro(mdoc, tok, ln, sv, &offs, buf)) goto err; return(1); } - n = m->last; - assert(m->last); + n = mdoc->last; + assert(mdoc->last); /* * If the first macro of a `Bl -column', open an `It' block @@ -905,8 +934,8 @@ mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs) if (MDOC_Bl == n->tok && MDOC_BODY == n->type && LIST_column == n->norm->Bl.type) { - m->flags |= MDOC_FREECOL; - if ( ! mdoc_macro(m, MDOC_It, ln, sv, &sv, buf)) + mdoc->flags |= MDOC_FREECOL; + if ( ! mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf)) goto err; return(1); } @@ -921,22 +950,22 @@ mdoc_pmacro(struct mdoc *m, int ln, char *buf, int offs) NULL != n->parent && MDOC_Bl == n->parent->tok && LIST_column == n->parent->norm->Bl.type) { - m->flags |= MDOC_FREECOL; - if ( ! mdoc_macro(m, MDOC_It, ln, sv, &sv, buf)) + mdoc->flags |= MDOC_FREECOL; + if ( ! mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf)) goto err; return(1); } /* Normal processing of a macro. */ - if ( ! mdoc_macro(m, tok, ln, sv, &offs, buf)) + if ( ! mdoc_macro(mdoc, tok, ln, sv, &offs, buf)) goto err; return(1); err: /* Error out. */ - m->flags |= MDOC_HALT; + mdoc->flags |= MDOC_HALT; return(0); } @@ -980,7 +1009,7 @@ mdoc_isdelim(const char *p) if (0 == strcmp(p + 1, ".")) return(DELIM_CLOSE); - if (0 == strcmp(p + 1, "*(Ba")) + if (0 == strcmp(p + 1, "fR|\\fP")) return(DELIM_MIDDLE); return(DELIM_NONE); diff --git a/usr/src/cmd/mandoc/mdoc.h b/usr/src/cmd/mandoc/mdoc.h index 9cee098e7f..d0153b4480 100644 --- a/usr/src/cmd/mandoc/mdoc.h +++ b/usr/src/cmd/mandoc/mdoc.h @@ -1,4 +1,4 @@ -/* $Id: mdoc.h,v 1.122 2011/03/22 14:05:45 kristaps Exp $ */ +/* $Id: mdoc.h,v 1.125 2013/12/24 19:11:45 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -311,6 +311,7 @@ struct mdoc_bl { int comp; /* -compact */ size_t ncols; /* -column arg count */ const char **cols; /* -column val ptr */ + int count; /* -enum counter */ }; struct mdoc_bf { @@ -350,6 +351,7 @@ struct mdoc_node { int nchild; /* number children */ int line; /* parse line */ int pos; /* parse column */ + int lastline; /* the node ends on this line */ enum mdoct tok; /* tok or MDOC__MAX if none */ int flags; #define MDOC_VALID (1 << 0) /* has been validated */ @@ -362,6 +364,7 @@ struct mdoc_node { enum mdoc_type type; /* AST node type */ enum mdoc_sec sec; /* current named section */ union mdoc_data *norm; /* normalised args */ + const void *prev_font; /* before entering this node */ /* FIXME: these can be union'd to shave a few bytes. */ struct mdoc_arg *args; /* BLOCK/ELEM */ struct mdoc_node *pending; /* BLOCK */ diff --git a/usr/src/cmd/mandoc/mdoc_argv.c b/usr/src/cmd/mandoc/mdoc_argv.c index 08386e09b1..bb9bc6c339 100644 --- a/usr/src/cmd/mandoc/mdoc_argv.c +++ b/usr/src/cmd/mandoc/mdoc_argv.c @@ -1,6 +1,7 @@ -/* $Id: mdoc_argv.c,v 1.82 2012/03/23 05:50:24 kristaps Exp $ */ +/* $Id: mdoc_argv.c,v 1.89 2013/12/25 00:50:05 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2012 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -42,8 +43,7 @@ enum argsflag { enum argvflag { ARGV_NONE, /* no args to flag (e.g., -split) */ ARGV_SINGLE, /* one arg to flag (e.g., -file xxx) */ - ARGV_MULTI, /* multiple args (e.g., -column xxx yyy) */ - ARGV_OPT_SINGLE /* optional arg (e.g., -offset [xxx]) */ + ARGV_MULTI /* multiple args (e.g., -column xxx yyy) */ }; struct mdocarg { @@ -57,8 +57,6 @@ static enum margserr args(struct mdoc *, int, int *, static int args_checkpunct(const char *, int); static int argv_multi(struct mdoc *, int, struct mdoc_argv *, int *, char *); -static int argv_opt_single(struct mdoc *, int, - struct mdoc_argv *, int *, char *); static int argv_single(struct mdoc *, int, struct mdoc_argv *, int *, char *); @@ -69,7 +67,7 @@ static const enum argvflag argvflags[MDOC_ARG_MAX] = { ARGV_NONE, /* MDOC_Unfilled */ ARGV_NONE, /* MDOC_Literal */ ARGV_SINGLE, /* MDOC_File */ - ARGV_OPT_SINGLE, /* MDOC_Offset */ + ARGV_SINGLE, /* MDOC_Offset */ ARGV_NONE, /* MDOC_Bullet */ ARGV_NONE, /* MDOC_Dash */ ARGV_NONE, /* MDOC_Hyphen */ @@ -81,7 +79,7 @@ static const enum argvflag argvflags[MDOC_ARG_MAX] = { ARGV_NONE, /* MDOC_Ohang */ ARGV_NONE, /* MDOC_Inset */ ARGV_MULTI, /* MDOC_Column */ - ARGV_OPT_SINGLE, /* MDOC_Width */ + ARGV_SINGLE, /* MDOC_Width */ ARGV_NONE, /* MDOC_Compact */ ARGV_NONE, /* MDOC_Std */ ARGV_NONE, /* MDOC_Filled */ @@ -146,7 +144,7 @@ static const enum mdocargt args_Bl[] = { }; static const struct mdocarg mdocargs[MDOC_MAX] = { - { ARGSFL_NONE, NULL }, /* Ap */ + { ARGSFL_DELIM, NULL }, /* Ap */ { ARGSFL_NONE, NULL }, /* Dd */ { ARGSFL_NONE, NULL }, /* Dt */ { ARGSFL_NONE, NULL }, /* Os */ @@ -163,7 +161,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = { { ARGSFL_DELIM, NULL }, /* Ad */ { ARGSFL_DELIM, args_An }, /* An */ { ARGSFL_DELIM, NULL }, /* Ar */ - { ARGSFL_NONE, NULL }, /* Cd */ + { ARGSFL_DELIM, NULL }, /* Cd */ { ARGSFL_DELIM, NULL }, /* Cm */ { ARGSFL_DELIM, NULL }, /* Dv */ { ARGSFL_DELIM, NULL }, /* Er */ @@ -175,7 +173,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = { { ARGSFL_DELIM, NULL }, /* Fn */ { ARGSFL_DELIM, NULL }, /* Ft */ { ARGSFL_DELIM, NULL }, /* Ic */ - { ARGSFL_NONE, NULL }, /* In */ + { ARGSFL_DELIM, NULL }, /* In */ { ARGSFL_DELIM, NULL }, /* Li */ { ARGSFL_NONE, NULL }, /* Nd */ { ARGSFL_DELIM, NULL }, /* Nm */ @@ -243,7 +241,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = { { ARGSFL_DELIM, NULL }, /* Xc */ { ARGSFL_NONE, NULL }, /* Xo */ { ARGSFL_NONE, NULL }, /* Fo */ - { ARGSFL_NONE, NULL }, /* Fc */ + { ARGSFL_DELIM, NULL }, /* Fc */ { ARGSFL_NONE, NULL }, /* Oo */ { ARGSFL_DELIM, NULL }, /* Oc */ { ARGSFL_NONE, args_Bk }, /* Bk */ @@ -252,7 +250,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = { { ARGSFL_NONE, NULL }, /* Hf */ { ARGSFL_NONE, NULL }, /* Fr */ { ARGSFL_NONE, NULL }, /* Ud */ - { ARGSFL_NONE, NULL }, /* Lb */ + { ARGSFL_DELIM, NULL }, /* Lb */ { ARGSFL_NONE, NULL }, /* Lp */ { ARGSFL_DELIM, NULL }, /* Lk */ { ARGSFL_DELIM, NULL }, /* Mt */ @@ -262,7 +260,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = { { ARGSFL_NONE, NULL }, /* %C */ { ARGSFL_NONE, NULL }, /* Es */ { ARGSFL_NONE, NULL }, /* En */ - { ARGSFL_NONE, NULL }, /* Dx */ + { ARGSFL_DELIM, NULL }, /* Dx */ { ARGSFL_NONE, NULL }, /* %Q */ { ARGSFL_NONE, NULL }, /* br */ { ARGSFL_NONE, NULL }, /* sp */ @@ -277,7 +275,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = { * one mandatory value, an optional single value, or no value. */ enum margverr -mdoc_argv(struct mdoc *m, int line, enum mdoct tok, +mdoc_argv(struct mdoc *mdoc, int line, enum mdoct tok, struct mdoc_arg **v, int *pos, char *buf) { char *p, sv; @@ -344,15 +342,11 @@ mdoc_argv(struct mdoc *m, int line, enum mdoct tok, switch (argvflags[tmp.arg]) { case (ARGV_SINGLE): - if ( ! argv_single(m, line, &tmp, pos, buf)) + if ( ! argv_single(mdoc, line, &tmp, pos, buf)) return(ARGV_ERROR); break; case (ARGV_MULTI): - if ( ! argv_multi(m, line, &tmp, pos, buf)) - return(ARGV_ERROR); - break; - case (ARGV_OPT_SINGLE): - if ( ! argv_opt_single(m, line, &tmp, pos, buf)) + if ( ! argv_multi(mdoc, line, &tmp, pos, buf)) return(ARGV_ERROR); break; case (ARGV_NONE): @@ -413,14 +407,14 @@ argn_free(struct mdoc_arg *p, int iarg) } enum margserr -mdoc_zargs(struct mdoc *m, int line, int *pos, char *buf, char **v) +mdoc_zargs(struct mdoc *mdoc, int line, int *pos, char *buf, char **v) { - return(args(m, line, pos, buf, ARGSFL_NONE, v)); + return(args(mdoc, line, pos, buf, ARGSFL_NONE, v)); } enum margserr -mdoc_args(struct mdoc *m, int line, int *pos, +mdoc_args(struct mdoc *mdoc, int line, int *pos, char *buf, enum mdoct tok, char **v) { enum argsflag fl; @@ -429,7 +423,7 @@ mdoc_args(struct mdoc *m, int line, int *pos, fl = mdocargs[tok].flags; if (MDOC_It != tok) - return(args(m, line, pos, buf, fl, v)); + return(args(mdoc, line, pos, buf, fl, v)); /* * We know that we're in an `It', so it's reasonable to expect @@ -438,35 +432,36 @@ mdoc_args(struct mdoc *m, int line, int *pos, * safe fall-back into the default behaviour. */ - for (n = m->last; n; n = n->parent) + for (n = mdoc->last; n; n = n->parent) if (MDOC_Bl == n->tok) if (LIST_column == n->norm->Bl.type) { fl = ARGSFL_TABSEP; break; } - return(args(m, line, pos, buf, fl, v)); + return(args(mdoc, line, pos, buf, fl, v)); } static enum margserr -args(struct mdoc *m, int line, int *pos, +args(struct mdoc *mdoc, int line, int *pos, char *buf, enum argsflag fl, char **v) { char *p, *pp; + int pairs; enum margserr rc; if ('\0' == buf[*pos]) { - if (MDOC_PPHRASE & m->flags) + if (MDOC_PPHRASE & mdoc->flags) return(ARGS_EOLN); /* * If we're not in a partial phrase and the flag for * being a phrase literal is still set, the punctuation * is unterminated. */ - if (MDOC_PHRASELIT & m->flags) - mdoc_pmsg(m, line, *pos, MANDOCERR_BADQUOTE); + if (MDOC_PHRASELIT & mdoc->flags) + mdoc_pmsg(mdoc, line, *pos, MANDOCERR_BADQUOTE); - m->flags &= ~MDOC_PHRASELIT; + mdoc->flags &= ~MDOC_PHRASELIT; return(ARGS_EOLN); } @@ -489,7 +484,7 @@ args(struct mdoc *m, int line, int *pos, pp = NULL; /* Scan ahead to unescaped `Ta'. */ - if ( ! (MDOC_PHRASELIT & m->flags)) + if ( ! (MDOC_PHRASELIT & mdoc->flags)) for (pp = *v; ; pp++) { if (NULL == (pp = strstr(pp, "Ta"))) break; @@ -523,7 +518,7 @@ args(struct mdoc *m, int line, int *pos, /* Whitespace check for eoln case... */ if ('\0' == *p && ' ' == *(p - 1)) - mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE); + mdoc_pmsg(mdoc, line, *pos, MANDOCERR_EOLNSPACE); *pos += (int)(p - *v); @@ -541,37 +536,48 @@ args(struct mdoc *m, int line, int *pos, /* Skip ahead. */ ; return(rc); - } + } - /* + /* * Process a quoted literal. A quote begins with a double-quote * and ends with a double-quote NOT preceded by a double-quote. + * NUL-terminate the literal in place. + * Collapse pairs of quotes inside quoted literals. * Whitespace is NOT involved in literal termination. */ - if (MDOC_PHRASELIT & m->flags || '\"' == buf[*pos]) { - if ( ! (MDOC_PHRASELIT & m->flags)) + if (MDOC_PHRASELIT & mdoc->flags || '\"' == buf[*pos]) { + if ( ! (MDOC_PHRASELIT & mdoc->flags)) *v = &buf[++(*pos)]; - if (MDOC_PPHRASE & m->flags) - m->flags |= MDOC_PHRASELIT; + if (MDOC_PPHRASE & mdoc->flags) + mdoc->flags |= MDOC_PHRASELIT; + pairs = 0; for ( ; buf[*pos]; (*pos)++) { + /* Move following text left after quoted quotes. */ + if (pairs) + buf[*pos - pairs] = buf[*pos]; if ('\"' != buf[*pos]) continue; + /* Unquoted quotes end quoted args. */ if ('\"' != buf[*pos + 1]) break; + /* Quoted quotes collapse. */ + pairs++; (*pos)++; } + if (pairs) + buf[*pos - pairs] = '\0'; if ('\0' == buf[*pos]) { - if (MDOC_PPHRASE & m->flags) + if (MDOC_PPHRASE & mdoc->flags) return(ARGS_QWORD); - mdoc_pmsg(m, line, *pos, MANDOCERR_BADQUOTE); + mdoc_pmsg(mdoc, line, *pos, MANDOCERR_BADQUOTE); return(ARGS_QWORD); } - m->flags &= ~MDOC_PHRASELIT; + mdoc->flags &= ~MDOC_PHRASELIT; buf[(*pos)++] = '\0'; if ('\0' == buf[*pos]) @@ -581,13 +587,13 @@ args(struct mdoc *m, int line, int *pos, (*pos)++; if ('\0' == buf[*pos]) - mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE); + mdoc_pmsg(mdoc, line, *pos, MANDOCERR_EOLNSPACE); return(ARGS_QWORD); } p = &buf[*pos]; - *v = mandoc_getarg(m->parse, &p, line, pos); + *v = mandoc_getarg(mdoc->parse, &p, line, pos); return(ARGS_WORD); } @@ -643,7 +649,7 @@ args_checkpunct(const char *buf, int i) } static int -argv_multi(struct mdoc *m, int line, +argv_multi(struct mdoc *mdoc, int line, struct mdoc_argv *v, int *pos, char *buf) { enum margserr ac; @@ -652,7 +658,7 @@ argv_multi(struct mdoc *m, int line, for (v->sz = 0; ; v->sz++) { if ('-' == buf[*pos]) break; - ac = args(m, line, pos, buf, ARGSFL_NONE, &p); + ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p); if (ARGS_ERROR == ac) return(0); else if (ARGS_EOLN == ac) @@ -669,16 +675,13 @@ argv_multi(struct mdoc *m, int line, } static int -argv_opt_single(struct mdoc *m, int line, +argv_single(struct mdoc *mdoc, int line, struct mdoc_argv *v, int *pos, char *buf) { enum margserr ac; char *p; - if ('-' == buf[*pos]) - return(1); - - ac = args(m, line, pos, buf, ARGSFL_NONE, &p); + ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p); if (ARGS_ERROR == ac) return(0); if (ARGS_EOLN == ac) @@ -690,27 +693,3 @@ argv_opt_single(struct mdoc *m, int line, return(1); } - -static int -argv_single(struct mdoc *m, int line, - struct mdoc_argv *v, int *pos, char *buf) -{ - int ppos; - enum margserr ac; - char *p; - - ppos = *pos; - - ac = args(m, line, pos, buf, ARGSFL_NONE, &p); - if (ARGS_EOLN == ac) { - mdoc_pmsg(m, line, ppos, MANDOCERR_SYNTARGVCOUNT); - return(0); - } else if (ARGS_ERROR == ac) - return(0); - - v->sz = 1; - v->value = mandoc_malloc(sizeof(char *)); - v->value[0] = mandoc_strdup(p); - - return(1); -} diff --git a/usr/src/cmd/mandoc/mdoc_html.c b/usr/src/cmd/mandoc/mdoc_html.c index 60ea6dc738..a7aa722d94 100644 --- a/usr/src/cmd/mandoc/mdoc_html.c +++ b/usr/src/cmd/mandoc/mdoc_html.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_html.c,v 1.182 2011/11/03 20:37:00 schwarze Exp $ */ +/* $Id: mdoc_html.c,v 1.186 2013/12/24 20:45:27 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -35,7 +35,7 @@ #define INDENT 5 -#define MDOC_ARGS const struct mdoc_meta *m, \ +#define MDOC_ARGS const struct mdoc_meta *meta, \ const struct mdoc_node *n, \ struct html *h @@ -260,10 +260,11 @@ static const char * const lists[LIST_MAX] = { }; void -html_mdoc(void *arg, const struct mdoc *m) +html_mdoc(void *arg, const struct mdoc *mdoc) { - print_mdoc(mdoc_meta(m), mdoc_node(m), (struct html *)arg); + print_mdoc(mdoc_meta(mdoc), mdoc_node(mdoc), + (struct html *)arg); putchar('\n'); } @@ -361,14 +362,14 @@ print_mdoc(MDOC_ARGS) print_gen_decls(h); t = print_otag(h, TAG_HTML, 0, NULL); tt = print_otag(h, TAG_HEAD, 0, NULL); - print_mdoc_head(m, n, h); + print_mdoc_head(meta, n, h); print_tagq(h, tt); print_otag(h, TAG_BODY, 0, NULL); print_otag(h, TAG_DIV, 1, &tag); } else t = print_otag(h, TAG_DIV, 1, &tag); - print_mdoc_nodelist(m, n, h); + print_mdoc_nodelist(meta, n, h); print_tagq(h, t); } @@ -380,10 +381,10 @@ print_mdoc_head(MDOC_ARGS) print_gen_head(h); bufinit(h); - bufcat_fmt(h, "%s(%s)", m->title, m->msec); + bufcat_fmt(h, "%s(%s)", meta->title, meta->msec); - if (m->arch) - bufcat_fmt(h, " (%s)", m->arch); + if (meta->arch) + bufcat_fmt(h, " (%s)", meta->arch); print_otag(h, TAG_TITLE, 0, NULL); print_text(h, h->buf); @@ -394,9 +395,9 @@ static void print_mdoc_nodelist(MDOC_ARGS) { - print_mdoc_node(m, n, h); + print_mdoc_node(meta, n, h); if (n->next) - print_mdoc_nodelist(m, n->next, h); + print_mdoc_nodelist(meta, n->next, h); } @@ -411,7 +412,7 @@ print_mdoc_node(MDOC_ARGS) switch (n->type) { case (MDOC_ROOT): - child = mdoc_root_pre(m, n, h); + child = mdoc_root_pre(meta, n, h); break; case (MDOC_TEXT): /* No tables in this mode... */ @@ -454,36 +455,32 @@ print_mdoc_node(MDOC_ARGS) assert(NULL == h->tblt); if (mdocs[n->tok].pre && ENDBODY_NOT == n->end) - child = (*mdocs[n->tok].pre)(m, n, h); + child = (*mdocs[n->tok].pre)(meta, n, h); break; } if (HTML_KEEP & h->flags) { - if (n->prev && n->prev->line != n->line) { + if (n->prev ? (n->prev->lastline != n->line) : + (n->parent && n->parent->line != n->line)) { h->flags &= ~HTML_KEEP; h->flags |= HTML_PREKEEP; - } else if (NULL == n->prev) { - if (n->parent && n->parent->line != n->line) { - h->flags &= ~HTML_KEEP; - h->flags |= HTML_PREKEEP; - } } } if (child && n->child) - print_mdoc_nodelist(m, n->child, h); + print_mdoc_nodelist(meta, n->child, h); print_stagq(h, t); switch (n->type) { case (MDOC_ROOT): - mdoc_root_post(m, n, h); + mdoc_root_post(meta, n, h); break; case (MDOC_EQN): break; default: if (mdocs[n->tok].post && ENDBODY_NOT == n->end) - (*mdocs[n->tok].post)(m, n, h); + (*mdocs[n->tok].post)(meta, n, h); break; } } @@ -509,13 +506,13 @@ mdoc_root_post(MDOC_ARGS) PAIR_CLASS_INIT(&tag[0], "foot-date"); print_otag(h, TAG_TD, 1, tag); - print_text(h, m->date); + print_text(h, meta->date); print_stagq(h, tt); PAIR_CLASS_INIT(&tag[0], "foot-os"); PAIR_INIT(&tag[1], ATTR_ALIGN, "right"); print_otag(h, TAG_TD, 2, tag); - print_text(h, m->os); + print_text(h, meta->os); print_tagq(h, t); } @@ -528,15 +525,15 @@ mdoc_root_pre(MDOC_ARGS) struct tag *t, *tt; char b[BUFSIZ], title[BUFSIZ]; - strlcpy(b, m->vol, BUFSIZ); + strlcpy(b, meta->vol, BUFSIZ); - if (m->arch) { + if (meta->arch) { strlcat(b, " (", BUFSIZ); - strlcat(b, m->arch, BUFSIZ); + strlcat(b, meta->arch, BUFSIZ); strlcat(b, ")", BUFSIZ); } - snprintf(title, BUFSIZ - 1, "%s(%s)", m->title, m->msec); + snprintf(title, BUFSIZ - 1, "%s(%s)", meta->title, meta->msec); PAIR_SUMMARY_INIT(&tag[0], "Document Header"); PAIR_CLASS_INIT(&tag[1], "head"); @@ -689,13 +686,13 @@ mdoc_nm_pre(MDOC_ARGS) synopsis_pre(h, n); PAIR_CLASS_INIT(&tag, "name"); print_otag(h, TAG_B, 1, &tag); - if (NULL == n->child && m->name) - print_text(h, m->name); + if (NULL == n->child && meta->name) + print_text(h, meta->name); return(1); case (MDOC_HEAD): print_otag(h, TAG_TD, 0, NULL); - if (NULL == n->child && m->name) - print_text(h, m->name); + if (NULL == n->child && meta->name) + print_text(h, meta->name); return(1); case (MDOC_BODY): print_otag(h, TAG_TD, 0, NULL); @@ -712,8 +709,8 @@ mdoc_nm_pre(MDOC_ARGS) if (MDOC_TEXT == n->type) len += html_strlen(n->string); - if (0 == len && m->name) - len = html_strlen(m->name); + if (0 == len && meta->name) + len = html_strlen(meta->name); SCALE_HS_INIT(&su, (double)len); bufinit(h); @@ -981,8 +978,6 @@ mdoc_bl_pre(MDOC_ARGS) struct roffsu su; char buf[BUFSIZ]; - bufinit(h); - if (MDOC_BODY == n->type) { if (LIST_column == n->norm->Bl.type) print_otag(h, TAG_TBODY, 0, NULL); @@ -1001,6 +996,7 @@ mdoc_bl_pre(MDOC_ARGS) */ for (i = 0; i < (int)n->norm->Bl.ncols; i++) { + bufinit(h); a2width(n->norm->Bl.cols[i], &su); if (i < (int)n->norm->Bl.ncols - 1) bufcat_su(h, "width", &su); @@ -1014,6 +1010,7 @@ mdoc_bl_pre(MDOC_ARGS) } SCALE_VS_INIT(&su, 0); + bufinit(h); bufcat_su(h, "margin-top", &su); bufcat_su(h, "margin-bottom", &su); PAIR_STYLE_INIT(&tag[0], h); @@ -1225,7 +1222,7 @@ mdoc_bd_pre(MDOC_ARGS) h->flags |= HTML_LITERAL; for (nn = n->child; nn; nn = nn->next) { - print_mdoc_node(m, nn, h); + print_mdoc_node(meta, nn, h); /* * If the printed node flushes its own line, then we * needn't do it here as well. This is hacky, but the @@ -2273,7 +2270,7 @@ mdoc_quote_post(MDOC_ARGS) case (MDOC_So): /* FALLTHROUGH */ case (MDOC_Sq): - print_text(h, "\\(aq"); + print_text(h, "\\(cq"); break; default: abort(); diff --git a/usr/src/cmd/mandoc/mdoc_macro.c b/usr/src/cmd/mandoc/mdoc_macro.c index 11d147399e..2a63ca92e3 100644 --- a/usr/src/cmd/mandoc/mdoc_macro.c +++ b/usr/src/cmd/mandoc/mdoc_macro.c @@ -1,7 +1,7 @@ -/* $Id: mdoc_macro.c,v 1.115 2012/01/05 00:43:51 schwarze Exp $ */ +/* $Id: mdoc_macro.c,v 1.125 2013/12/24 20:45:27 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -51,8 +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 dword(struct mdoc *, int, int, const char *, + enum mdelim, int); static int append_delims(struct mdoc *, int, int *, char *); static enum mdoct lookup(enum mdoct, const char *); @@ -70,128 +70,147 @@ static int rew_sub(enum mdoc_type, struct mdoc *, enum mdoct, int, int); const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { - { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ap */ + { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ap */ { in_line_eoln, MDOC_PROLOGUE }, /* Dd */ { in_line_eoln, MDOC_PROLOGUE }, /* Dt */ { in_line_eoln, MDOC_PROLOGUE }, /* Os */ - { blk_full, MDOC_PARSED }, /* Sh */ - { blk_full, MDOC_PARSED }, /* Ss */ - { in_line_eoln, 0 }, /* Pp */ - { blk_part_imp, MDOC_PARSED }, /* D1 */ - { blk_part_imp, MDOC_PARSED }, /* Dl */ + { blk_full, MDOC_PARSED | MDOC_JOIN }, /* Sh */ + { blk_full, MDOC_PARSED | MDOC_JOIN }, /* Ss */ + { in_line_eoln, 0 }, /* Pp */ + { blk_part_imp, MDOC_PARSED | MDOC_JOIN }, /* D1 */ + { blk_part_imp, MDOC_PARSED | MDOC_JOIN }, /* Dl */ { blk_full, MDOC_EXPLICIT }, /* Bd */ - { blk_exp_close, MDOC_EXPLICIT }, /* Ed */ + { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ed */ { blk_full, MDOC_EXPLICIT }, /* Bl */ - { blk_exp_close, MDOC_EXPLICIT }, /* El */ - { blk_full, MDOC_PARSED }, /* It */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* An */ + { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* El */ + { blk_full, MDOC_PARSED | MDOC_JOIN }, /* It */ + { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */ + { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* An */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cd */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Er */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ev */ + { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */ + { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Er */ + { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ev */ { in_line_eoln, 0 }, /* Ex */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fa */ - { in_line_eoln, 0 }, /* Fd */ + { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fa */ + { in_line_eoln, 0 }, /* Fd */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fl */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fn */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ft */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ic */ + { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fn */ + { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ft */ + { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ic */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* In */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Li */ - { blk_full, 0 }, /* Nd */ - { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */ + { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Li */ + { blk_full, MDOC_JOIN }, /* Nd */ + { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */ { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Op */ { obsolete, 0 }, /* Ot */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */ { in_line_eoln, 0 }, /* Rv */ - { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* St */ + { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* St */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Va */ - { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */ + { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Xr */ - { in_line_eoln, 0 }, /* %A */ - { in_line_eoln, 0 }, /* %B */ - { in_line_eoln, 0 }, /* %D */ - { in_line_eoln, 0 }, /* %I */ - { in_line_eoln, 0 }, /* %J */ + { in_line_eoln, MDOC_JOIN }, /* %A */ + { in_line_eoln, MDOC_JOIN }, /* %B */ + { in_line_eoln, MDOC_JOIN }, /* %D */ + { in_line_eoln, MDOC_JOIN }, /* %I */ + { in_line_eoln, MDOC_JOIN }, /* %J */ { in_line_eoln, 0 }, /* %N */ - { in_line_eoln, 0 }, /* %O */ + { in_line_eoln, MDOC_JOIN }, /* %O */ { in_line_eoln, 0 }, /* %P */ - { in_line_eoln, 0 }, /* %R */ - { in_line_eoln, 0 }, /* %T */ + { in_line_eoln, MDOC_JOIN }, /* %R */ + { in_line_eoln, MDOC_JOIN }, /* %T */ { in_line_eoln, 0 }, /* %V */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ac */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ao */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Aq */ + { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | + MDOC_EXPLICIT | MDOC_JOIN }, /* Ac */ + { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | + MDOC_EXPLICIT | MDOC_JOIN }, /* Ao */ + { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Aq */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* At */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Bc */ - { blk_full, MDOC_EXPLICIT }, /* Bf */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bo */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Bq */ + { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | + MDOC_EXPLICIT | MDOC_JOIN }, /* Bc */ + { blk_full, MDOC_EXPLICIT }, /* Bf */ + { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | + MDOC_EXPLICIT | MDOC_JOIN }, /* Bo */ + { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Bq */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bsx */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bx */ { in_line_eoln, 0 }, /* Db */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Dc */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Do */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Dq */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ec */ - { blk_exp_close, MDOC_EXPLICIT }, /* Ef */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Em */ + { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | + MDOC_EXPLICIT | MDOC_JOIN }, /* Dc */ + { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | + MDOC_EXPLICIT | MDOC_JOIN }, /* Do */ + { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Dq */ + { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ec */ + { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ef */ + { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Em */ { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Eo */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Fx */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ms */ - { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* No */ - { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* Ns */ + { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | + MDOC_IGNDELIM | MDOC_JOIN }, /* No */ + { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | + MDOC_IGNDELIM | MDOC_JOIN }, /* Ns */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Nx */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ox */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Pc */ + { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | + MDOC_EXPLICIT | MDOC_JOIN }, /* Pc */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* Pf */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Po */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Pq */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Qc */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Ql */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Qo */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Qq */ - { blk_exp_close, MDOC_EXPLICIT }, /* Re */ + { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | + MDOC_EXPLICIT | MDOC_JOIN }, /* Po */ + { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Pq */ + { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | + MDOC_EXPLICIT | MDOC_JOIN }, /* Qc */ + { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ql */ + { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | + MDOC_EXPLICIT | MDOC_JOIN }, /* Qo */ + { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Qq */ + { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Re */ { blk_full, MDOC_EXPLICIT }, /* Rs */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Sc */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* So */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Sq */ + { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | + MDOC_EXPLICIT | MDOC_JOIN }, /* Sc */ + { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | + MDOC_EXPLICIT | MDOC_JOIN }, /* So */ + { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sq */ { in_line_eoln, 0 }, /* Sm */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sx */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sy */ + { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sx */ + { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sy */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Tn */ - { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ux */ + { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ux */ { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Xc */ { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Xo */ - { blk_full, MDOC_EXPLICIT | MDOC_CALLABLE }, /* Fo */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Fc */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Oo */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Oc */ + { blk_full, MDOC_EXPLICIT | MDOC_CALLABLE }, /* Fo */ + { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | + MDOC_EXPLICIT | MDOC_JOIN }, /* Fc */ + { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | + MDOC_EXPLICIT | MDOC_JOIN }, /* Oo */ + { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | + MDOC_EXPLICIT | MDOC_JOIN }, /* Oc */ { blk_full, MDOC_EXPLICIT }, /* Bk */ - { blk_exp_close, MDOC_EXPLICIT }, /* Ek */ + { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ek */ { in_line_eoln, 0 }, /* Bt */ { in_line_eoln, 0 }, /* Hf */ { obsolete, 0 }, /* Fr */ { in_line_eoln, 0 }, /* Ud */ { in_line, 0 }, /* Lb */ - { in_line_eoln, 0 }, /* Lp */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Lk */ - { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Mt */ - { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Brq */ - { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bro */ - { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Brc */ - { in_line_eoln, 0 }, /* %C */ + { in_line_eoln, 0 }, /* Lp */ + { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Lk */ + { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Mt */ + { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Brq */ + { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | + MDOC_EXPLICIT | MDOC_JOIN }, /* Bro */ + { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | + MDOC_EXPLICIT | MDOC_JOIN }, /* Brc */ + { in_line_eoln, MDOC_JOIN }, /* %C */ { obsolete, 0 }, /* Es */ { obsolete, 0 }, /* En */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Dx */ - { in_line_eoln, 0 }, /* %Q */ + { in_line_eoln, MDOC_JOIN }, /* %Q */ { in_line_eoln, 0 }, /* br */ { in_line_eoln, 0 }, /* sp */ { in_line_eoln, 0 }, /* %U */ - { phrase_ta, MDOC_CALLABLE | MDOC_PARSED }, /* Ta */ + { phrase_ta, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ta */ }; const struct mdoc_macro * const mdoc_macros = __mdoc_macros; @@ -203,22 +222,23 @@ const struct mdoc_macro * const mdoc_macros = __mdoc_macros; * are errors. */ int -mdoc_macroend(struct mdoc *m) +mdoc_macroend(struct mdoc *mdoc) { struct mdoc_node *n; /* Scan for open explicit scopes. */ - n = MDOC_VALID & m->last->flags ? m->last->parent : m->last; + n = MDOC_VALID & mdoc->last->flags ? + mdoc->last->parent : mdoc->last; for ( ; n; n = n->parent) if (MDOC_BLOCK == n->type && MDOC_EXPLICIT & mdoc_macros[n->tok].flags) - mdoc_nmsg(m, n, MANDOCERR_SCOPEEXIT); + mdoc_nmsg(mdoc, n, MANDOCERR_SCOPEEXIT); /* Rewind to the first. */ - return(rew_last(m, m->first)); + return(rew_last(mdoc, mdoc->first)); } @@ -263,8 +283,8 @@ rew_last(struct mdoc *mdoc, const struct mdoc_node *to) 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 + * mdoc->last node in the post-validation phase and reset + * it to mdoc->last->parent, causing a step in the closing * out to be lost. */ np = mdoc->last->parent; @@ -460,7 +480,7 @@ rew_elem(struct mdoc *mdoc, enum mdoct tok) */ static int make_pending(struct mdoc_node *broken, enum mdoct tok, - struct mdoc *m, int line, int ppos) + struct mdoc *mdoc, int line, int ppos) { struct mdoc_node *breaker; @@ -515,7 +535,7 @@ make_pending(struct mdoc_node *broken, enum mdoct tok, taker->pending = broken->pending; } broken->pending = breaker; - mandoc_vmsg(MANDOCERR_SCOPENEST, m->parse, line, ppos, + mandoc_vmsg(MANDOCERR_SCOPENEST, mdoc->parse, line, ppos, "%s breaks %s", mdoc_macronames[tok], mdoc_macronames[broken->tok]); return(1); @@ -530,41 +550,46 @@ make_pending(struct mdoc_node *broken, enum mdoct tok, static int -rew_sub(enum mdoc_type t, struct mdoc *m, +rew_sub(enum mdoc_type t, struct mdoc *mdoc, enum mdoct tok, int line, int ppos) { struct mdoc_node *n; - n = m->last; + n = mdoc->last; while (n) { switch (rew_dohalt(tok, t, n)) { case (REWIND_NONE): return(1); case (REWIND_THIS): + n->lastline = line - + (MDOC_NEWLINE & mdoc->flags && + ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)); break; case (REWIND_FORCE): - mandoc_vmsg(MANDOCERR_SCOPEBROKEN, m->parse, + mandoc_vmsg(MANDOCERR_SCOPEBROKEN, mdoc->parse, line, ppos, "%s breaks %s", mdoc_macronames[tok], mdoc_macronames[n->tok]); /* FALLTHROUGH */ case (REWIND_MORE): + n->lastline = line - + (MDOC_NEWLINE & mdoc->flags ? 1 : 0); n = n->parent; continue; case (REWIND_LATER): - if (make_pending(n, tok, m, line, ppos) || + if (make_pending(n, tok, mdoc, line, ppos) || MDOC_BLOCK != t) return(1); /* FALLTHROUGH */ case (REWIND_ERROR): - mdoc_pmsg(m, line, ppos, MANDOCERR_NOSCOPE); + mdoc_pmsg(mdoc, line, ppos, MANDOCERR_NOSCOPE); return(1); } break; } assert(n); - if ( ! rew_last(m, n)) + if ( ! rew_last(mdoc, n)) return(0); /* @@ -572,10 +597,10 @@ rew_sub(enum mdoc_type t, struct mdoc *m, * Now that the current block ends, close the enclosing block, too. */ while (NULL != (n = n->pending)) { - if ( ! rew_last(m, n)) + if ( ! rew_last(mdoc, n)) return(0); if (MDOC_HEAD == n->type && - ! mdoc_body_alloc(m, n->line, n->pos, n->tok)) + ! mdoc_body_alloc(mdoc, n->line, n->pos, n->tok)) return(0); } @@ -587,18 +612,26 @@ rew_sub(enum mdoc_type t, struct mdoc *m, * 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) +dword(struct mdoc *mdoc, int line, int col, const char *p, + enum mdelim d, int may_append) { if (DELIM_MAX == d) d = mdoc_isdelim(p); - if ( ! mdoc_word_alloc(m, line, col, p)) + if (may_append && + ! ((MDOC_SYNOPSIS | MDOC_KEEP | MDOC_SMOFF) & mdoc->flags) && + DELIM_NONE == d && MDOC_TEXT == mdoc->last->type && + DELIM_NONE == mdoc_isdelim(mdoc->last->string)) { + mdoc_word_append(mdoc, p); + return(1); + } + + if ( ! mdoc_word_alloc(mdoc, line, col, p)) return(0); if (DELIM_OPEN == d) - m->last->flags |= MDOC_DELIMO; + mdoc->last->flags |= MDOC_DELIMO; /* * Closing delimiters only suppress the preceding space @@ -610,15 +643,16 @@ dword(struct mdoc *m, int line, * and solve this in the code related to `No'! */ - else if (DELIM_CLOSE == d && m->last->prev && - m->last->prev->tok != MDOC_No) - m->last->flags |= MDOC_DELIMC; + else if (DELIM_CLOSE == d && mdoc->last->prev && + mdoc->last->prev->tok != MDOC_No && + mdoc->last->parent->tok != MDOC_Fd) + mdoc->last->flags |= MDOC_DELIMC; return(1); } static int -append_delims(struct mdoc *m, int line, int *pos, char *buf) +append_delims(struct mdoc *mdoc, int line, int *pos, char *buf) { int la; enum margserr ac; @@ -629,14 +663,14 @@ append_delims(struct mdoc *m, int line, int *pos, char *buf) for (;;) { la = *pos; - ac = mdoc_zargs(m, line, pos, buf, &p); + ac = mdoc_zargs(mdoc, line, pos, buf, &p); if (ARGS_ERROR == ac) return(0); else if (ARGS_EOLN == ac) break; - dword(m, line, la, p, DELIM_MAX); + dword(mdoc, line, la, p, DELIM_MAX, 1); /* * If we encounter end-of-sentence symbols, then trigger @@ -650,7 +684,7 @@ append_delims(struct mdoc *m, int line, int *pos, char *buf) * example, `. ;' shouldn't propagate the double-space. */ if (mandoc_eos(p, strlen(p), 0)) - m->last->flags |= MDOC_EOS; + mdoc->last->flags |= MDOC_EOS; } return(1); @@ -672,12 +706,14 @@ blk_exp_close(MACRO_PROT_ARGS) enum mdoct atok, ntok; char *p; - nl = MDOC_NEWLINE & m->flags; + nl = MDOC_NEWLINE & mdoc->flags; switch (tok) { case (MDOC_Ec): maxargs = 1; break; + case (MDOC_Ek): + mdoc->flags &= ~MDOC_KEEP; default: maxargs = 0; break; @@ -689,7 +725,7 @@ blk_exp_close(MACRO_PROT_ARGS) */ atok = rew_alt(tok); body = later = NULL; - for (n = m->last; n; n = n->parent) { + for (n = mdoc->last; n; n = n->parent) { if (MDOC_VALID & n->flags) continue; @@ -718,13 +754,13 @@ blk_exp_close(MACRO_PROT_ARGS) * postpone closing out the current block * until the rew_sub() closing out the sub-block. */ - make_pending(later, tok, m, line, ppos); + make_pending(later, tok, mdoc, line, ppos); /* * Mark the place where the formatting - but not * the scope - of the current block ends. */ - if ( ! mdoc_endbody_alloc(m, line, ppos, + if ( ! mdoc_endbody_alloc(mdoc, line, ppos, atok, body, ENDBODY_SPACE)) return(0); break; @@ -738,37 +774,37 @@ blk_exp_close(MACRO_PROT_ARGS) if (later && MDOC_EXPLICIT & mdoc_macros[later->tok].flags) continue; - if (MDOC_CALLABLE & mdoc_macros[n->tok].flags) + if (MDOC_It != n->tok) later = n; } if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) { /* FIXME: do this in validate */ if (buf[*pos]) - mdoc_pmsg(m, line, ppos, MANDOCERR_ARGSLOST); + mdoc_pmsg(mdoc, line, ppos, MANDOCERR_ARGSLOST); - if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos)) return(0); - return(rew_sub(MDOC_BLOCK, m, tok, line, ppos)); + return(rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)); } - if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos)) return(0); if (NULL == later && maxargs > 0) - if ( ! mdoc_tail_alloc(m, line, ppos, rew_alt(tok))) + if ( ! mdoc_tail_alloc(mdoc, line, ppos, rew_alt(tok))) return(0); for (flushed = j = 0; ; j++) { lastarg = *pos; if (j == maxargs && ! flushed) { - if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) return(0); flushed = 1; } - ac = mdoc_args(m, line, pos, buf, tok, &p); + ac = mdoc_args(mdoc, line, pos, buf, tok, &p); if (ARGS_ERROR == ac) return(0); @@ -780,27 +816,31 @@ blk_exp_close(MACRO_PROT_ARGS) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); if (MDOC_MAX == ntok) { - if ( ! dword(m, line, lastarg, p, DELIM_MAX)) + if ( ! dword(mdoc, line, lastarg, p, DELIM_MAX, + MDOC_JOIN & mdoc_macros[tok].flags)) return(0); continue; } if ( ! flushed) { - if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) return(0); flushed = 1; } - if ( ! mdoc_macro(m, ntok, line, lastarg, pos, buf)) + + mdoc->flags &= ~MDOC_NEWLINE; + + if ( ! mdoc_macro(mdoc, ntok, line, lastarg, pos, buf)) return(0); break; } - if ( ! flushed && ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) + if ( ! flushed && ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) return(0); if ( ! nl) return(1); - return(append_delims(m, line, pos, buf)); + return(append_delims(mdoc, line, pos, buf)); } @@ -815,7 +855,7 @@ in_line(MACRO_PROT_ARGS) struct mdoc_arg *arg; char *p; - nl = MDOC_NEWLINE & m->flags; + nl = MDOC_NEWLINE & mdoc->flags; /* * Whether we allow ignored elements (those without content, @@ -843,7 +883,7 @@ in_line(MACRO_PROT_ARGS) for (arg = NULL;; ) { la = *pos; - av = mdoc_argv(m, line, tok, &arg, pos, buf); + av = mdoc_argv(mdoc, line, tok, &arg, pos, buf); if (ARGV_WORD == av) { *pos = la; @@ -860,7 +900,7 @@ in_line(MACRO_PROT_ARGS) for (cnt = scope = 0;; ) { la = *pos; - ac = mdoc_args(m, line, pos, buf, tok, &p); + ac = mdoc_args(mdoc, line, pos, buf, tok, &p); if (ARGS_ERROR == ac) return(0); @@ -879,23 +919,25 @@ in_line(MACRO_PROT_ARGS) */ if (MDOC_MAX != ntok) { - if (scope && ! rew_elem(m, tok)) + if (scope && ! rew_elem(mdoc, tok)) return(0); if (nc && 0 == cnt) { - if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) + if ( ! mdoc_elem_alloc(mdoc, line, + ppos, tok, arg)) return(0); - if ( ! rew_last(m, m->last)) + if ( ! rew_last(mdoc, mdoc->last)) return(0); } else if ( ! nc && 0 == cnt) { mdoc_argv_free(arg); - mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY); + mdoc_pmsg(mdoc, line, ppos, + MANDOCERR_MACROEMPTY); } - if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) + if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf)) return(0); if ( ! nl) return(1); - return(append_delims(m, line, pos, buf)); + return(append_delims(mdoc, line, pos, buf)); } /* @@ -917,7 +959,8 @@ in_line(MACRO_PROT_ARGS) */ if (0 == cnt && (nc || MDOC_Li == tok) && DELIM_CLOSE == d && ! scope) { - if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) + if ( ! mdoc_elem_alloc(mdoc, line, + ppos, tok, arg)) return(0); if (MDOC_Ar == tok || MDOC_Li == tok || MDOC_Fl == tok) @@ -928,11 +971,11 @@ in_line(MACRO_PROT_ARGS) * Close out our scope, if one is open, before * any punctuation. */ - if (scope && ! rew_elem(m, tok)) + if (scope && ! rew_elem(mdoc, tok)) return(0); scope = 0; } else if ( ! scope) { - if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) + if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg)) return(0); scope = 1; } @@ -940,7 +983,8 @@ in_line(MACRO_PROT_ARGS) if (DELIM_NONE == d) cnt++; - if ( ! dword(m, line, la, p, d)) + if ( ! dword(mdoc, line, la, p, d, + MDOC_JOIN & mdoc_macros[tok].flags)) return(0); /* @@ -949,13 +993,13 @@ in_line(MACRO_PROT_ARGS) * having to parse out spaces. */ if (scope && MDOC_Fl == tok) { - if ( ! rew_elem(m, tok)) + if ( ! rew_elem(mdoc, tok)) return(0); scope = 0; } } - if (scope && ! rew_elem(m, tok)) + if (scope && ! rew_elem(mdoc, tok)) return(0); /* @@ -965,18 +1009,18 @@ in_line(MACRO_PROT_ARGS) */ if (nc && 0 == cnt) { - if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) + if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg)) return(0); - if ( ! rew_last(m, m->last)) + if ( ! rew_last(mdoc, mdoc->last)) return(0); } else if ( ! nc && 0 == cnt) { mdoc_argv_free(arg); - mdoc_pmsg(m, line, ppos, MANDOCERR_MACROEMPTY); + mdoc_pmsg(mdoc, line, ppos, MANDOCERR_MACROEMPTY); } if ( ! nl) return(1); - return(append_delims(m, line, pos, buf)); + return(append_delims(mdoc, line, pos, buf)); } @@ -994,14 +1038,14 @@ blk_full(MACRO_PROT_ARGS) enum margverr av; char *p; - nl = MDOC_NEWLINE & m->flags; + nl = MDOC_NEWLINE & mdoc->flags; /* Close out prior implicit scope. */ if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) { - if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos)) return(0); - if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) return(0); } @@ -1016,7 +1060,7 @@ blk_full(MACRO_PROT_ARGS) for (arg = NULL;; ) { la = *pos; - av = mdoc_argv(m, line, tok, &arg, pos, buf); + av = mdoc_argv(mdoc, line, tok, &arg, pos, buf); if (ARGV_WORD == av) { *pos = la; @@ -1032,7 +1076,7 @@ blk_full(MACRO_PROT_ARGS) return(0); } - if ( ! mdoc_block_alloc(m, line, ppos, tok, arg)) + if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, arg)) return(0); head = body = NULL; @@ -1042,8 +1086,8 @@ blk_full(MACRO_PROT_ARGS) * parsed, even though `It' macros in general are parsed. */ nparsed = MDOC_It == tok && - MDOC_Bl == m->last->parent->tok && - LIST_diag == m->last->parent->norm->Bl.type; + MDOC_Bl == mdoc->last->parent->tok && + LIST_diag == mdoc->last->parent->norm->Bl.type; /* * The `Nd' macro has all arguments in its body: it's a hybrid @@ -1051,15 +1095,18 @@ blk_full(MACRO_PROT_ARGS) */ if (MDOC_Nd == tok) { - if ( ! mdoc_head_alloc(m, line, ppos, tok)) + if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) return(0); - head = m->last; - if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) + head = mdoc->last; + if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos)) return(0); - if ( ! mdoc_body_alloc(m, line, ppos, tok)) + if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) return(0); - body = m->last; - } + body = mdoc->last; + } + + if (MDOC_Bk == tok) + mdoc->flags |= MDOC_KEEP; ac = ARGS_ERROR; @@ -1067,7 +1114,7 @@ blk_full(MACRO_PROT_ARGS) la = *pos; /* Initialise last-phrase-type with ARGS_PEND. */ lac = ARGS_ERROR == ac ? ARGS_PEND : ac; - ac = mdoc_args(m, line, pos, buf, tok, &p); + ac = mdoc_args(mdoc, line, pos, buf, tok, &p); if (ARGS_PUNCT == ac) break; @@ -1085,11 +1132,11 @@ blk_full(MACRO_PROT_ARGS) * reopen our scope if the last parse was a * phrase or partial phrase. */ - if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos)) return(0); - if ( ! mdoc_body_alloc(m, line, ppos, tok)) + if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) return(0); - body = m->last; + body = mdoc->last; break; } @@ -1104,7 +1151,7 @@ blk_full(MACRO_PROT_ARGS) ARGS_PPHRASE != ac && ARGS_QWORD != ac && DELIM_OPEN == mdoc_isdelim(p)) { - if ( ! dword(m, line, la, p, DELIM_OPEN)) + if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0)) return(0); continue; } @@ -1112,9 +1159,9 @@ blk_full(MACRO_PROT_ARGS) /* Open a head if one hasn't been opened. */ if (NULL == head) { - if ( ! mdoc_head_alloc(m, line, ppos, tok)) + if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) return(0); - head = m->last; + head = mdoc->last; } if (ARGS_PHRASE == ac || @@ -1126,14 +1173,14 @@ blk_full(MACRO_PROT_ARGS) */ mtt = body ? MDOC_BODY : MDOC_HEAD; - if ( ! rew_sub(mtt, m, tok, line, ppos)) + if ( ! rew_sub(mtt, mdoc, tok, line, ppos)) return(0); /* Then allocate our body context. */ - if ( ! mdoc_body_alloc(m, line, ppos, tok)) + if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) return(0); - body = m->last; + body = mdoc->last; /* * Process phrases: set whether we're in a @@ -1142,14 +1189,14 @@ blk_full(MACRO_PROT_ARGS) */ if (ARGS_PPHRASE == ac) - m->flags |= MDOC_PPHRASE; + mdoc->flags |= MDOC_PPHRASE; if (ARGS_PEND == ac && ARGS_PPHRASE == lac) - m->flags |= MDOC_PPHRASE; + mdoc->flags |= MDOC_PPHRASE; - if ( ! phrase(m, line, la, buf)) + if ( ! phrase(mdoc, line, la, buf)) return(0); - m->flags &= ~MDOC_PPHRASE; + mdoc->flags &= ~MDOC_PPHRASE; continue; } @@ -1157,23 +1204,24 @@ blk_full(MACRO_PROT_ARGS) MDOC_MAX : lookup(tok, p); if (MDOC_MAX == ntok) { - if ( ! dword(m, line, la, p, DELIM_MAX)) + if ( ! dword(mdoc, line, la, p, DELIM_MAX, + MDOC_JOIN & mdoc_macros[tok].flags)) return(0); continue; } - if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) + if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf)) return(0); break; } if (NULL == head) { - if ( ! mdoc_head_alloc(m, line, ppos, tok)) + if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) return(0); - head = m->last; + head = mdoc->last; } - if (nl && ! append_delims(m, line, pos, buf)) + if (nl && ! append_delims(mdoc, line, pos, buf)) return(0); /* If we've already opened our body, exit now. */ @@ -1187,7 +1235,7 @@ blk_full(MACRO_PROT_ARGS) * head to body until the rew_sub() call closing out that * sub-block. */ - for (n = m->last; n && n != head; n = n->parent) { + for (n = mdoc->last; n && n != head; n = n->parent) { if (MDOC_BLOCK == n->type && MDOC_EXPLICIT & mdoc_macros[n->tok].flags && ! (MDOC_VALID & n->flags)) { @@ -1198,21 +1246,21 @@ blk_full(MACRO_PROT_ARGS) /* Close out scopes to remain in a consistent state. */ - if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos)) return(0); - if ( ! mdoc_body_alloc(m, line, ppos, tok)) + if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) return(0); out: - if ( ! (MDOC_FREECOL & m->flags)) + if ( ! (MDOC_FREECOL & mdoc->flags)) return(1); - if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos)) return(0); - if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) return(0); - m->flags &= ~MDOC_FREECOL; + mdoc->flags &= ~MDOC_FREECOL; return(1); } @@ -1228,7 +1276,7 @@ blk_part_imp(MACRO_PROT_ARGS) struct mdoc_node *body; /* saved body context */ struct mdoc_node *n; - nl = MDOC_NEWLINE & m->flags; + nl = MDOC_NEWLINE & mdoc->flags; /* * A macro that spans to the end of the line. This is generally @@ -1239,14 +1287,14 @@ blk_part_imp(MACRO_PROT_ARGS) * or more closing punctuation nodes. */ - if ( ! mdoc_block_alloc(m, line, ppos, tok, NULL)) + if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL)) return(0); - blk = m->last; + blk = mdoc->last; - if ( ! mdoc_head_alloc(m, line, ppos, tok)) + if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) return(0); - if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos)) return(0); /* @@ -1257,7 +1305,7 @@ blk_part_imp(MACRO_PROT_ARGS) for (body = NULL; ; ) { la = *pos; - ac = mdoc_args(m, line, pos, buf, tok, &p); + ac = mdoc_args(mdoc, line, pos, buf, tok, &p); if (ARGS_ERROR == ac) return(0); @@ -1268,26 +1316,27 @@ blk_part_imp(MACRO_PROT_ARGS) if (NULL == body && ARGS_QWORD != ac && DELIM_OPEN == mdoc_isdelim(p)) { - if ( ! dword(m, line, la, p, DELIM_OPEN)) + if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0)) return(0); continue; - } + } if (NULL == body) { - if ( ! mdoc_body_alloc(m, line, ppos, tok)) + if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) return(0); - body = m->last; + body = mdoc->last; } ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); if (MDOC_MAX == ntok) { - if ( ! dword(m, line, la, p, DELIM_MAX)) + if ( ! dword(mdoc, line, la, p, DELIM_MAX, + MDOC_JOIN & mdoc_macros[tok].flags)) return(0); continue; } - if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) + if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf)) return(0); break; } @@ -1295,9 +1344,9 @@ blk_part_imp(MACRO_PROT_ARGS) /* Clean-ups to leave in a consistent state. */ if (NULL == body) { - if ( ! mdoc_body_alloc(m, line, ppos, tok)) + if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) return(0); - body = m->last; + body = mdoc->last; } for (n = body->child; n && n->next; n = n->next) @@ -1324,12 +1373,13 @@ blk_part_imp(MACRO_PROT_ARGS) * postpone closing out the current block * until the rew_sub() call closing out the sub-block. */ - for (n = m->last; n && n != body && n != blk->parent; n = n->parent) { + for (n = mdoc->last; n && n != body && n != blk->parent; + n = n->parent) { if (MDOC_BLOCK == n->type && MDOC_EXPLICIT & mdoc_macros[n->tok].flags && ! (MDOC_VALID & n->flags)) { - make_pending(n, tok, m, line, ppos); - if ( ! mdoc_endbody_alloc(m, line, ppos, + make_pending(n, tok, mdoc, line, ppos); + if ( ! mdoc_endbody_alloc(mdoc, line, ppos, tok, body, ENDBODY_NOSPACE)) return(0); return(1); @@ -1343,22 +1393,29 @@ blk_part_imp(MACRO_PROT_ARGS) * crufty use of `Op' breakage. */ if (n != body) - mandoc_vmsg(MANDOCERR_SCOPENEST, m->parse, line, ppos, + mandoc_vmsg(MANDOCERR_SCOPENEST, mdoc->parse, line, ppos, "%s broken", mdoc_macronames[tok]); - if (n && ! rew_sub(MDOC_BODY, m, tok, line, ppos)) + if (n && ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos)) return(0); /* Standard appending of delimiters. */ - if (nl && ! append_delims(m, line, pos, buf)) + if (nl && ! append_delims(mdoc, line, pos, buf)) return(0); /* Rewind scope, if applicable. */ - if (n && ! rew_sub(MDOC_BLOCK, m, tok, line, ppos)) + if (n && ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos)) return(0); + /* Move trailing .Ns out of scope. */ + + for (n = body->child; n && n->next; n = n->next) + /* Do nothing. */ ; + if (n && MDOC_Ns == n->tok) + mdoc_node_relink(mdoc, n); + return(1); } @@ -1373,7 +1430,7 @@ blk_part_exp(MACRO_PROT_ARGS) char *p; enum mdoct ntok; - nl = MDOC_NEWLINE & m->flags; + nl = MDOC_NEWLINE & mdoc->flags; /* * The opening of an explicit macro having zero or more leading @@ -1381,12 +1438,12 @@ blk_part_exp(MACRO_PROT_ARGS) * case of `Eo'); and a body that may be empty. */ - if ( ! mdoc_block_alloc(m, line, ppos, tok, NULL)) + if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL)) return(0); for (head = body = NULL; ; ) { la = *pos; - ac = mdoc_args(m, line, pos, buf, tok, &p); + ac = mdoc_args(mdoc, line, pos, buf, tok, &p); if (ARGS_ERROR == ac) return(0); @@ -1400,16 +1457,16 @@ blk_part_exp(MACRO_PROT_ARGS) if (NULL == head && ARGS_QWORD != ac && DELIM_OPEN == mdoc_isdelim(p)) { assert(NULL == body); - if ( ! dword(m, line, la, p, DELIM_OPEN)) + if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0)) return(0); continue; - } + } if (NULL == head) { assert(NULL == body); - if ( ! mdoc_head_alloc(m, line, ppos, tok)) + if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) return(0); - head = m->last; + head = mdoc->last; } /* @@ -1421,14 +1478,14 @@ blk_part_exp(MACRO_PROT_ARGS) assert(head); /* No check whether it's a macro! */ if (MDOC_Eo == tok) - if ( ! dword(m, line, la, p, DELIM_MAX)) + if ( ! dword(mdoc, line, la, p, DELIM_MAX, 0)) return(0); - if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos)) return(0); - if ( ! mdoc_body_alloc(m, line, ppos, tok)) + if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) return(0); - body = m->last; + body = mdoc->last; if (MDOC_Eo == tok) continue; @@ -1439,12 +1496,13 @@ blk_part_exp(MACRO_PROT_ARGS) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); if (MDOC_MAX == ntok) { - if ( ! dword(m, line, la, p, DELIM_MAX)) + if ( ! dword(mdoc, line, la, p, DELIM_MAX, + MDOC_JOIN & mdoc_macros[tok].flags)) return(0); continue; } - if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) + if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf)) return(0); break; } @@ -1452,13 +1510,13 @@ blk_part_exp(MACRO_PROT_ARGS) /* Clean-up to leave in a consistent state. */ if (NULL == head) - if ( ! mdoc_head_alloc(m, line, ppos, tok)) + if ( ! mdoc_head_alloc(mdoc, line, ppos, tok)) return(0); if (NULL == body) { - if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos)) + if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos)) return(0); - if ( ! mdoc_body_alloc(m, line, ppos, tok)) + if ( ! mdoc_body_alloc(mdoc, line, ppos, tok)) return(0); } @@ -1466,7 +1524,7 @@ blk_part_exp(MACRO_PROT_ARGS) if ( ! nl) return(1); - return(append_delims(m, line, pos, buf)); + return(append_delims(mdoc, line, pos, buf)); } @@ -1481,7 +1539,7 @@ in_line_argn(MACRO_PROT_ARGS) char *p; enum mdoct ntok; - nl = MDOC_NEWLINE & m->flags; + nl = MDOC_NEWLINE & mdoc->flags; /* * A line macro that has a fixed number of arguments (maxargs). @@ -1513,7 +1571,7 @@ in_line_argn(MACRO_PROT_ARGS) for (arg = NULL; ; ) { la = *pos; - av = mdoc_argv(m, line, tok, &arg, pos, buf); + av = mdoc_argv(mdoc, line, tok, &arg, pos, buf); if (ARGV_WORD == av) { *pos = la; @@ -1531,7 +1589,7 @@ in_line_argn(MACRO_PROT_ARGS) for (flushed = j = 0; ; ) { la = *pos; - ac = mdoc_args(m, line, pos, buf, tok, &p); + ac = mdoc_args(mdoc, line, pos, buf, tok, &p); if (ARGS_ERROR == ac) return(0); @@ -1543,15 +1601,15 @@ in_line_argn(MACRO_PROT_ARGS) if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) && ARGS_QWORD != ac && 0 == j && DELIM_OPEN == mdoc_isdelim(p)) { - if ( ! dword(m, line, la, p, DELIM_OPEN)) + if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0)) return(0); continue; } else if (0 == j) - if ( ! mdoc_elem_alloc(m, line, la, tok, arg)) + if ( ! mdoc_elem_alloc(mdoc, line, la, tok, arg)) return(0); if (j == maxargs && ! flushed) { - if ( ! rew_elem(m, tok)) + if ( ! rew_elem(mdoc, tok)) return(0); flushed = 1; } @@ -1559,10 +1617,10 @@ in_line_argn(MACRO_PROT_ARGS) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); if (MDOC_MAX != ntok) { - if ( ! flushed && ! rew_elem(m, tok)) + if ( ! flushed && ! rew_elem(mdoc, tok)) return(0); flushed = 1; - if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) + if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf)) return(0); j++; break; @@ -1572,26 +1630,27 @@ in_line_argn(MACRO_PROT_ARGS) ARGS_QWORD != ac && ! flushed && DELIM_NONE != mdoc_isdelim(p)) { - if ( ! rew_elem(m, tok)) + if ( ! rew_elem(mdoc, tok)) return(0); flushed = 1; } - if ( ! dword(m, line, la, p, DELIM_MAX)) + if ( ! dword(mdoc, line, la, p, DELIM_MAX, + MDOC_JOIN & mdoc_macros[tok].flags)) return(0); j++; } - if (0 == j && ! mdoc_elem_alloc(m, line, la, tok, arg)) + if (0 == j && ! mdoc_elem_alloc(mdoc, line, la, tok, arg)) return(0); /* Close out in a consistent state. */ - if ( ! flushed && ! rew_elem(m, tok)) + if ( ! flushed && ! rew_elem(mdoc, tok)) return(0); if ( ! nl) return(1); - return(append_delims(m, line, pos, buf)); + return(append_delims(mdoc, line, pos, buf)); } @@ -1608,13 +1667,13 @@ in_line_eoln(MACRO_PROT_ARGS) assert( ! (MDOC_PARSED & mdoc_macros[tok].flags)); if (tok == MDOC_Pp) - rew_sub(MDOC_BLOCK, m, MDOC_Nm, line, ppos); + rew_sub(MDOC_BLOCK, mdoc, MDOC_Nm, line, ppos); /* Parse macro arguments. */ for (arg = NULL; ; ) { la = *pos; - av = mdoc_argv(m, line, tok, &arg, pos, buf); + av = mdoc_argv(mdoc, line, tok, &arg, pos, buf); if (ARGV_WORD == av) { *pos = la; @@ -1631,14 +1690,14 @@ in_line_eoln(MACRO_PROT_ARGS) /* Open element scope. */ - if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg)) + if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg)) return(0); /* Parse argument terms. */ for (;;) { la = *pos; - ac = mdoc_args(m, line, pos, buf, tok, &p); + ac = mdoc_args(mdoc, line, pos, buf, tok, &p); if (ARGS_ERROR == ac) return(0); @@ -1648,19 +1707,20 @@ in_line_eoln(MACRO_PROT_ARGS) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p); if (MDOC_MAX == ntok) { - if ( ! dword(m, line, la, p, DELIM_MAX)) + if ( ! dword(mdoc, line, la, p, DELIM_MAX, + MDOC_JOIN & mdoc_macros[tok].flags)) return(0); continue; } - if ( ! rew_elem(m, tok)) + if ( ! rew_elem(mdoc, tok)) return(0); - return(mdoc_macro(m, ntok, line, la, pos, buf)); + return(mdoc_macro(mdoc, ntok, line, la, pos, buf)); } /* Close out (no delimiters). */ - return(rew_elem(m, tok)); + return(rew_elem(mdoc, tok)); } @@ -1670,15 +1730,15 @@ ctx_synopsis(MACRO_PROT_ARGS) { int nl; - nl = MDOC_NEWLINE & m->flags; + nl = MDOC_NEWLINE & mdoc->flags; /* If we're not in the SYNOPSIS, go straight to in-line. */ - if ( ! (MDOC_SYNOPSIS & m->flags)) - return(in_line(m, tok, line, ppos, pos, buf)); + if ( ! (MDOC_SYNOPSIS & mdoc->flags)) + return(in_line(mdoc, tok, line, ppos, pos, buf)); /* If we're a nested call, same place. */ if ( ! nl) - return(in_line(m, tok, line, ppos, pos, buf)); + return(in_line(mdoc, tok, line, ppos, pos, buf)); /* * XXX: this will open a block scope; however, if later we end @@ -1686,9 +1746,9 @@ ctx_synopsis(MACRO_PROT_ARGS) * the formatting. Be careful. */ if (MDOC_Nm == tok) - return(blk_full(m, tok, line, ppos, pos, buf)); + return(blk_full(mdoc, tok, line, ppos, pos, buf)); assert(MDOC_Vt == tok); - return(blk_part_imp(m, tok, line, ppos, pos, buf)); + return(blk_part_imp(mdoc, tok, line, ppos, pos, buf)); } @@ -1697,7 +1757,7 @@ static int obsolete(MACRO_PROT_ARGS) { - mdoc_pmsg(m, line, ppos, MANDOCERR_MACROOBS); + mdoc_pmsg(mdoc, line, ppos, MANDOCERR_MACROOBS); return(1); } @@ -1708,7 +1768,7 @@ obsolete(MACRO_PROT_ARGS) * macro is encountered. */ static int -phrase(struct mdoc *m, int line, int ppos, char *buf) +phrase(struct mdoc *mdoc, int line, int ppos, char *buf) { int la, pos; enum margserr ac; @@ -1718,7 +1778,7 @@ phrase(struct mdoc *m, int line, int ppos, char *buf) for (pos = ppos; ; ) { la = pos; - ac = mdoc_zargs(m, line, &pos, buf, &p); + ac = mdoc_zargs(mdoc, line, &pos, buf, &p); if (ARGS_ERROR == ac) return(0); @@ -1728,14 +1788,14 @@ phrase(struct mdoc *m, int line, int ppos, char *buf) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p); if (MDOC_MAX == ntok) { - if ( ! dword(m, line, la, p, DELIM_MAX)) + if ( ! dword(mdoc, line, la, p, DELIM_MAX, 1)) return(0); continue; } - if ( ! mdoc_macro(m, ntok, line, la, &pos, buf)) + if ( ! mdoc_macro(mdoc, ntok, line, la, &pos, buf)) return(0); - return(append_delims(m, line, &pos, buf)); + return(append_delims(mdoc, line, &pos, buf)); } return(1); @@ -1746,24 +1806,30 @@ phrase(struct mdoc *m, int line, int ppos, char *buf) static int phrase_ta(MACRO_PROT_ARGS) { + struct mdoc_node *n; int la; enum mdoct ntok; enum margserr ac; char *p; - /* - * FIXME: this is overly restrictive: if the `Ta' is unexpected, - * it should simply error out with ARGSLOST. - */ + /* Make sure we are in a column list or ignore this macro. */ + n = mdoc->last; + while (NULL != n && MDOC_Bl != n->tok) + n = n->parent; + if (NULL == n || LIST_column != n->norm->Bl.type) { + mdoc_pmsg(mdoc, line, ppos, MANDOCERR_STRAYTA); + return(1); + } - if ( ! rew_sub(MDOC_BODY, m, MDOC_It, line, ppos)) + /* Advance to the next column. */ + if ( ! rew_sub(MDOC_BODY, mdoc, MDOC_It, line, ppos)) return(0); - if ( ! mdoc_body_alloc(m, line, ppos, MDOC_It)) + if ( ! mdoc_body_alloc(mdoc, line, ppos, MDOC_It)) return(0); for (;;) { la = *pos; - ac = mdoc_zargs(m, line, pos, buf, &p); + ac = mdoc_zargs(mdoc, line, pos, buf, &p); if (ARGS_ERROR == ac) return(0); @@ -1773,14 +1839,15 @@ phrase_ta(MACRO_PROT_ARGS) ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p); if (MDOC_MAX == ntok) { - if ( ! dword(m, line, la, p, DELIM_MAX)) + if ( ! dword(mdoc, line, la, p, DELIM_MAX, + MDOC_JOIN & mdoc_macros[tok].flags)) return(0); continue; } - if ( ! mdoc_macro(m, ntok, line, la, pos, buf)) + if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf)) return(0); - return(append_delims(m, line, pos, buf)); + return(append_delims(mdoc, line, pos, buf)); } return(1); diff --git a/usr/src/cmd/mandoc/mdoc_man.c b/usr/src/cmd/mandoc/mdoc_man.c index 9d7d2ca238..6ee8b3abf4 100644 --- a/usr/src/cmd/mandoc/mdoc_man.c +++ b/usr/src/cmd/mandoc/mdoc_man.c @@ -1,6 +1,6 @@ -/* $Id: mdoc_man.c,v 1.9 2011/10/24 21:47:59 schwarze Exp $ */ +/* $Id: mdoc_man.c,v 1.57 2013/12/25 22:00:45 schwarze Exp $ */ /* - * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -18,22 +18,18 @@ #include "config.h" #endif +#include <assert.h> #include <stdio.h> #include <string.h> #include "mandoc.h" +#include "out.h" #include "man.h" #include "mdoc.h" #include "main.h" -#define DECL_ARGS const struct mdoc_meta *m, \ - const struct mdoc_node *n, \ - struct mman *mm - -struct mman { - int need_space; /* next word needs prior ws */ - int need_nl; /* next word needs prior nl */ -}; +#define DECL_ARGS const struct mdoc_meta *meta, \ + const struct mdoc_node *n struct manact { int (*cond)(DECL_ARGS); /* DON'T run actions */ @@ -45,29 +41,74 @@ struct manact { static int cond_body(DECL_ARGS); static int cond_head(DECL_ARGS); +static void font_push(char); +static void font_pop(void); +static void mid_it(void); +static void post__t(DECL_ARGS); static void post_bd(DECL_ARGS); +static void post_bf(DECL_ARGS); +static void post_bk(DECL_ARGS); +static void post_bl(DECL_ARGS); static void post_dl(DECL_ARGS); static void post_enc(DECL_ARGS); +static void post_eo(DECL_ARGS); +static void post_fa(DECL_ARGS); +static void post_fd(DECL_ARGS); +static void post_fl(DECL_ARGS); +static void post_fn(DECL_ARGS); +static void post_fo(DECL_ARGS); +static void post_font(DECL_ARGS); +static void post_in(DECL_ARGS); +static void post_it(DECL_ARGS); +static void post_lb(DECL_ARGS); static void post_nm(DECL_ARGS); static void post_percent(DECL_ARGS); static void post_pf(DECL_ARGS); static void post_sect(DECL_ARGS); static void post_sp(DECL_ARGS); +static void post_vt(DECL_ARGS); +static int pre__t(DECL_ARGS); +static int pre_an(DECL_ARGS); static int pre_ap(DECL_ARGS); static int pre_bd(DECL_ARGS); +static int pre_bf(DECL_ARGS); +static int pre_bk(DECL_ARGS); +static int pre_bl(DECL_ARGS); static int pre_br(DECL_ARGS); static int pre_bx(DECL_ARGS); static int pre_dl(DECL_ARGS); static int pre_enc(DECL_ARGS); +static int pre_em(DECL_ARGS); +static int pre_fa(DECL_ARGS); +static int pre_fd(DECL_ARGS); +static int pre_fl(DECL_ARGS); +static int pre_fn(DECL_ARGS); +static int pre_fo(DECL_ARGS); +static int pre_ft(DECL_ARGS); +static int pre_in(DECL_ARGS); static int pre_it(DECL_ARGS); +static int pre_lk(DECL_ARGS); +static int pre_li(DECL_ARGS); static int pre_nm(DECL_ARGS); +static int pre_no(DECL_ARGS); static int pre_ns(DECL_ARGS); static int pre_pp(DECL_ARGS); +static int pre_rs(DECL_ARGS); +static int pre_sm(DECL_ARGS); static int pre_sp(DECL_ARGS); static int pre_sect(DECL_ARGS); +static int pre_sy(DECL_ARGS); +static void pre_syn(const struct mdoc_node *); +static int pre_vt(DECL_ARGS); static int pre_ux(DECL_ARGS); static int pre_xr(DECL_ARGS); -static void print_word(struct mman *, const char *); +static void print_word(const char *); +static void print_line(const char *, int); +static void print_block(const char *, int); +static void print_offs(const char *); +static void print_width(const char *, + const struct mdoc_node *, size_t); +static void print_count(int *); static void print_node(DECL_ARGS); static const struct manact manacts[MDOC_MAX + 1] = { @@ -82,74 +123,74 @@ static const struct manact manacts[MDOC_MAX + 1] = { { cond_body, pre_dl, post_dl, NULL, NULL }, /* Dl */ { cond_body, pre_bd, post_bd, NULL, NULL }, /* Bd */ { NULL, NULL, NULL, NULL, NULL }, /* Ed */ - { NULL, NULL, NULL, NULL, NULL }, /* Bl */ + { cond_body, pre_bl, post_bl, NULL, NULL }, /* Bl */ { NULL, NULL, NULL, NULL, NULL }, /* El */ - { NULL, pre_it, NULL, NULL, NULL }, /* _It */ - { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Ad */ - { NULL, NULL, NULL, NULL, NULL }, /* _An */ - { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Ar */ - { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Cd */ - { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Cm */ - { NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Dv */ - { NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Er */ - { NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Ev */ + { NULL, pre_it, post_it, NULL, NULL }, /* It */ + { NULL, pre_em, post_font, NULL, NULL }, /* Ad */ + { NULL, pre_an, NULL, NULL, NULL }, /* An */ + { NULL, pre_em, post_font, NULL, NULL }, /* Ar */ + { NULL, pre_sy, post_font, NULL, NULL }, /* Cd */ + { NULL, pre_sy, post_font, NULL, NULL }, /* Cm */ + { NULL, pre_li, post_font, NULL, NULL }, /* Dv */ + { NULL, pre_li, post_font, NULL, NULL }, /* Er */ + { NULL, pre_li, post_font, NULL, NULL }, /* Ev */ { NULL, pre_enc, post_enc, "The \\fB", "\\fP\nutility exits 0 on success, and >0 if an error occurs." }, /* Ex */ - { NULL, NULL, NULL, NULL, NULL }, /* _Fa */ - { NULL, NULL, NULL, NULL, NULL }, /* _Fd */ - { NULL, pre_enc, post_enc, "\\fB-", "\\fP" }, /* Fl */ - { NULL, NULL, NULL, NULL, NULL }, /* _Fn */ - { NULL, NULL, NULL, NULL, NULL }, /* _Ft */ - { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Ic */ - { NULL, NULL, NULL, NULL, NULL }, /* _In */ - { NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Li */ + { NULL, pre_fa, post_fa, NULL, NULL }, /* Fa */ + { NULL, pre_fd, post_fd, NULL, NULL }, /* Fd */ + { NULL, pre_fl, post_fl, NULL, NULL }, /* Fl */ + { NULL, pre_fn, post_fn, NULL, NULL }, /* Fn */ + { NULL, pre_ft, post_font, NULL, NULL }, /* Ft */ + { NULL, pre_sy, post_font, NULL, NULL }, /* Ic */ + { NULL, pre_in, post_in, NULL, NULL }, /* In */ + { NULL, pre_li, post_font, NULL, NULL }, /* Li */ { cond_head, pre_enc, NULL, "\\- ", NULL }, /* Nd */ { NULL, pre_nm, post_nm, NULL, NULL }, /* Nm */ { cond_body, pre_enc, post_enc, "[", "]" }, /* Op */ { NULL, NULL, NULL, NULL, NULL }, /* Ot */ - { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Pa */ + { NULL, pre_em, post_font, NULL, NULL }, /* Pa */ { NULL, pre_enc, post_enc, "The \\fB", "\\fP\nfunction returns the value 0 if successful;\n" "otherwise the value -1 is returned and the global\n" "variable \\fIerrno\\fP is set to indicate the error." }, /* Rv */ { NULL, NULL, NULL, NULL, NULL }, /* St */ - { NULL, NULL, NULL, NULL, NULL }, /* _Va */ - { NULL, NULL, NULL, NULL, NULL }, /* _Vt */ + { NULL, pre_em, post_font, NULL, NULL }, /* Va */ + { NULL, pre_vt, post_vt, NULL, NULL }, /* Vt */ { NULL, pre_xr, NULL, NULL, NULL }, /* Xr */ - { NULL, NULL, post_percent, NULL, NULL }, /* _%A */ - { NULL, NULL, NULL, NULL, NULL }, /* _%B */ - { NULL, NULL, post_percent, NULL, NULL }, /* _%D */ - { NULL, NULL, NULL, NULL, NULL }, /* _%I */ - { NULL, pre_enc, post_percent, "\\fI", "\\fP" }, /* %J */ - { NULL, NULL, NULL, NULL, NULL }, /* _%N */ - { NULL, NULL, NULL, NULL, NULL }, /* _%O */ - { NULL, NULL, NULL, NULL, NULL }, /* _%P */ - { NULL, NULL, NULL, NULL, NULL }, /* _%R */ - { NULL, pre_enc, post_percent, "\"", "\"" }, /* %T */ - { NULL, NULL, NULL, NULL, NULL }, /* _%V */ + { NULL, NULL, post_percent, NULL, NULL }, /* %A */ + { NULL, pre_em, post_percent, NULL, NULL }, /* %B */ + { NULL, NULL, post_percent, NULL, NULL }, /* %D */ + { NULL, pre_em, post_percent, NULL, NULL }, /* %I */ + { NULL, pre_em, post_percent, NULL, NULL }, /* %J */ + { NULL, NULL, post_percent, NULL, NULL }, /* %N */ + { NULL, NULL, post_percent, NULL, NULL }, /* %O */ + { NULL, NULL, post_percent, NULL, NULL }, /* %P */ + { NULL, NULL, post_percent, NULL, NULL }, /* %R */ + { NULL, pre__t, post__t, NULL, NULL }, /* %T */ + { NULL, NULL, post_percent, NULL, NULL }, /* %V */ { NULL, NULL, NULL, NULL, NULL }, /* Ac */ { cond_body, pre_enc, post_enc, "<", ">" }, /* Ao */ { cond_body, pre_enc, post_enc, "<", ">" }, /* Aq */ { NULL, NULL, NULL, NULL, NULL }, /* At */ { NULL, NULL, NULL, NULL, NULL }, /* Bc */ - { NULL, NULL, NULL, NULL, NULL }, /* _Bf */ + { NULL, pre_bf, post_bf, NULL, NULL }, /* Bf */ { cond_body, pre_enc, post_enc, "[", "]" }, /* Bo */ { cond_body, pre_enc, post_enc, "[", "]" }, /* Bq */ { NULL, pre_ux, NULL, "BSD/OS", NULL }, /* Bsx */ { NULL, pre_bx, NULL, NULL, NULL }, /* Bx */ { NULL, NULL, NULL, NULL, NULL }, /* Db */ { NULL, NULL, NULL, NULL, NULL }, /* Dc */ - { cond_body, pre_enc, post_enc, "``", "''" }, /* Do */ - { cond_body, pre_enc, post_enc, "``", "''" }, /* Dq */ - { NULL, NULL, NULL, NULL, NULL }, /* _Ec */ - { NULL, NULL, NULL, NULL, NULL }, /* _Ef */ - { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Em */ - { NULL, NULL, NULL, NULL, NULL }, /* _Eo */ + { cond_body, pre_enc, post_enc, "\\(lq", "\\(rq" }, /* Do */ + { cond_body, pre_enc, post_enc, "\\(lq", "\\(rq" }, /* Dq */ + { NULL, NULL, NULL, NULL, NULL }, /* Ec */ + { NULL, NULL, NULL, NULL, NULL }, /* Ef */ + { NULL, pre_em, post_font, NULL, NULL }, /* Em */ + { NULL, NULL, post_eo, NULL, NULL }, /* Eo */ { NULL, pre_ux, NULL, "FreeBSD", NULL }, /* Fx */ - { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Ms */ - { NULL, NULL, NULL, NULL, NULL }, /* No */ + { NULL, pre_sy, post_font, NULL, NULL }, /* Ms */ + { NULL, pre_no, NULL, NULL, NULL }, /* No */ { NULL, pre_ns, NULL, NULL, NULL }, /* Ns */ { NULL, pre_ux, NULL, "NetBSD", NULL }, /* Nx */ { NULL, pre_ux, NULL, "OpenBSD", NULL }, /* Ox */ @@ -158,91 +199,324 @@ static const struct manact manacts[MDOC_MAX + 1] = { { cond_body, pre_enc, post_enc, "(", ")" }, /* Po */ { cond_body, pre_enc, post_enc, "(", ")" }, /* Pq */ { NULL, NULL, NULL, NULL, NULL }, /* Qc */ - { cond_body, pre_enc, post_enc, "`", "'" }, /* Ql */ + { cond_body, pre_enc, post_enc, "\\(oq", "\\(cq" }, /* Ql */ { cond_body, pre_enc, post_enc, "\"", "\"" }, /* Qo */ { cond_body, pre_enc, post_enc, "\"", "\"" }, /* Qq */ { NULL, NULL, NULL, NULL, NULL }, /* Re */ - { cond_body, pre_pp, NULL, NULL, NULL }, /* Rs */ + { cond_body, pre_rs, NULL, NULL, NULL }, /* Rs */ { NULL, NULL, NULL, NULL, NULL }, /* Sc */ - { cond_body, pre_enc, post_enc, "`", "'" }, /* So */ - { cond_body, pre_enc, post_enc, "`", "'" }, /* Sq */ - { NULL, NULL, NULL, NULL, NULL }, /* _Sm */ - { NULL, pre_enc, post_enc, "\\fI", "\\fP" }, /* Sx */ - { NULL, pre_enc, post_enc, "\\fB", "\\fP" }, /* Sy */ - { NULL, pre_enc, post_enc, "\\fR", "\\fP" }, /* Tn */ + { cond_body, pre_enc, post_enc, "\\(oq", "\\(cq" }, /* So */ + { cond_body, pre_enc, post_enc, "\\(oq", "\\(cq" }, /* Sq */ + { NULL, pre_sm, NULL, NULL, NULL }, /* Sm */ + { NULL, pre_em, post_font, NULL, NULL }, /* Sx */ + { NULL, pre_sy, post_font, NULL, NULL }, /* Sy */ + { NULL, pre_li, post_font, NULL, NULL }, /* Tn */ { NULL, pre_ux, NULL, "UNIX", NULL }, /* Ux */ - { NULL, NULL, NULL, NULL, NULL }, /* _Xc */ - { NULL, NULL, NULL, NULL, NULL }, /* _Xo */ - { NULL, NULL, NULL, NULL, NULL }, /* _Fo */ - { NULL, NULL, NULL, NULL, NULL }, /* _Fc */ + { NULL, NULL, NULL, NULL, NULL }, /* Xc */ + { NULL, NULL, NULL, NULL, NULL }, /* Xo */ + { NULL, pre_fo, post_fo, NULL, NULL }, /* Fo */ + { NULL, NULL, NULL, NULL, NULL }, /* Fc */ { cond_body, pre_enc, post_enc, "[", "]" }, /* Oo */ { NULL, NULL, NULL, NULL, NULL }, /* Oc */ - { NULL, NULL, NULL, NULL, NULL }, /* _Bk */ - { NULL, NULL, NULL, NULL, NULL }, /* _Ek */ + { NULL, pre_bk, post_bk, NULL, NULL }, /* Bk */ + { NULL, NULL, NULL, NULL, NULL }, /* Ek */ { NULL, pre_ux, NULL, "is currently in beta test.", NULL }, /* Bt */ { NULL, NULL, NULL, NULL, NULL }, /* Hf */ { NULL, NULL, NULL, NULL, NULL }, /* Fr */ { NULL, pre_ux, NULL, "currently under development.", NULL }, /* Ud */ - { NULL, NULL, NULL, NULL, NULL }, /* _Lb */ + { NULL, NULL, post_lb, NULL, NULL }, /* Lb */ { NULL, pre_pp, NULL, NULL, NULL }, /* Lp */ - { NULL, NULL, NULL, NULL, NULL }, /* _Lk */ - { NULL, NULL, NULL, NULL, NULL }, /* _Mt */ + { NULL, pre_lk, NULL, NULL, NULL }, /* Lk */ + { NULL, pre_em, post_font, NULL, NULL }, /* Mt */ { cond_body, pre_enc, post_enc, "{", "}" }, /* Brq */ { cond_body, pre_enc, post_enc, "{", "}" }, /* Bro */ { NULL, NULL, NULL, NULL, NULL }, /* Brc */ - { NULL, NULL, NULL, NULL, NULL }, /* _%C */ - { NULL, NULL, NULL, NULL, NULL }, /* _Es */ - { NULL, NULL, NULL, NULL, NULL }, /* _En */ + { NULL, NULL, post_percent, NULL, NULL }, /* %C */ + { NULL, NULL, NULL, NULL, NULL }, /* Es */ + { NULL, NULL, NULL, NULL, NULL }, /* En */ { NULL, pre_ux, NULL, "DragonFly", NULL }, /* Dx */ - { NULL, NULL, NULL, NULL, NULL }, /* _%Q */ + { NULL, NULL, post_percent, NULL, NULL }, /* %Q */ { NULL, pre_br, NULL, NULL, NULL }, /* br */ { NULL, pre_sp, post_sp, NULL, NULL }, /* sp */ - { NULL, NULL, NULL, NULL, NULL }, /* _%U */ - { NULL, NULL, NULL, NULL, NULL }, /* _Ta */ + { NULL, NULL, post_percent, NULL, NULL }, /* %U */ + { NULL, NULL, NULL, NULL, NULL }, /* Ta */ { NULL, NULL, NULL, NULL, NULL }, /* ROOT */ }; +static int outflags; +#define MMAN_spc (1 << 0) /* blank character before next word */ +#define MMAN_spc_force (1 << 1) /* even before trailing punctuation */ +#define MMAN_nl (1 << 2) /* break man(7) code line */ +#define MMAN_br (1 << 3) /* break output line */ +#define MMAN_sp (1 << 4) /* insert a blank output line */ +#define MMAN_PP (1 << 5) /* reset indentation etc. */ +#define MMAN_Sm (1 << 6) /* horizontal spacing mode */ +#define MMAN_Bk (1 << 7) /* word keep mode */ +#define MMAN_Bk_susp (1 << 8) /* suspend this (after a macro) */ +#define MMAN_An_split (1 << 9) /* author mode is "split" */ +#define MMAN_An_nosplit (1 << 10) /* author mode is "nosplit" */ +#define MMAN_PD (1 << 11) /* inter-paragraph spacing disabled */ +#define MMAN_nbrword (1 << 12) /* do not break the next word */ + +#define BL_STACK_MAX 32 + +static size_t Bl_stack[BL_STACK_MAX]; /* offsets [chars] */ +static int Bl_stack_post[BL_STACK_MAX]; /* add final .RE */ +static int Bl_stack_len; /* number of nested Bl blocks */ +static int TPremain; /* characters before tag is full */ + +static struct { + char *head; + char *tail; + size_t size; +} fontqueue; + +static void +font_push(char newfont) +{ + + if (fontqueue.head + fontqueue.size <= ++fontqueue.tail) { + fontqueue.size += 8; + fontqueue.head = mandoc_realloc(fontqueue.head, + fontqueue.size); + } + *fontqueue.tail = newfont; + print_word(""); + printf("\\f"); + putchar(newfont); + outflags &= ~MMAN_spc; +} + +static void +font_pop(void) +{ + + if (fontqueue.tail > fontqueue.head) + fontqueue.tail--; + outflags &= ~MMAN_spc; + print_word(""); + printf("\\f"); + putchar(*fontqueue.tail); +} + static void -print_word(struct mman *mm, const char *s) +print_word(const char *s) { - if (mm->need_nl) { + if ((MMAN_PP | MMAN_sp | MMAN_br | MMAN_nl) & outflags) { /* * If we need a newline, print it now and start afresh. */ - putchar('\n'); - mm->need_space = 0; - mm->need_nl = 0; - } else if (mm->need_space && '\0' != s[0]) + if (MMAN_PP & outflags) { + if (MMAN_sp & outflags) { + if (MMAN_PD & outflags) { + printf("\n.PD"); + outflags &= ~MMAN_PD; + } + } else if ( ! (MMAN_PD & outflags)) { + printf("\n.PD 0"); + outflags |= MMAN_PD; + } + printf("\n.PP\n"); + } else if (MMAN_sp & outflags) + printf("\n.sp\n"); + else if (MMAN_br & outflags) + printf("\n.br\n"); + else if (MMAN_nl & outflags) + putchar('\n'); + outflags &= ~(MMAN_PP|MMAN_sp|MMAN_br|MMAN_nl|MMAN_spc); + if (1 == TPremain) + printf(".br\n"); + TPremain = 0; + } else if (MMAN_spc & outflags) { /* - * If we need a space, only print it before - * (1) a nonzero length word; - * (2) a word that is non-punctuation; and - * (3) if punctuation, non-terminating puncutation. + * If we need a space, only print it if + * (1) it is forced by `No' or + * (2) what follows is not terminating punctuation or + * (3) what follows is longer than one character. */ - if (NULL == strchr(".,:;)]?!", s[0]) || '\0' != s[1]) + if (MMAN_spc_force & outflags || '\0' == s[0] || + NULL == strchr(".,:;)]?!", s[0]) || '\0' != s[1]) { + if (MMAN_Bk & outflags && + ! (MMAN_Bk_susp & outflags)) + putchar('\\'); putchar(' '); + if (TPremain) + TPremain--; + } + } /* * Reassign needing space if we're not following opening * punctuation. */ - mm->need_space = - ('(' != s[0] && '[' != s[0]) || '\0' != s[1]; + if (MMAN_Sm & outflags && ('\0' == s[0] || + (('(' != s[0] && '[' != s[0]) || '\0' != s[1]))) + outflags |= MMAN_spc; + else + outflags &= ~MMAN_spc; + outflags &= ~(MMAN_spc_force | MMAN_Bk_susp); for ( ; *s; s++) { switch (*s) { case (ASCII_NBRSP): - printf("\\~"); + printf("\\ "); break; case (ASCII_HYPH): putchar('-'); break; + case (' '): + if (MMAN_nbrword & outflags) { + printf("\\ "); + break; + } + /* FALLTHROUGH */ default: putchar((unsigned char)*s); break; } + if (TPremain) + TPremain--; + } + outflags &= ~MMAN_nbrword; +} + +static void +print_line(const char *s, int newflags) +{ + + outflags &= ~MMAN_br; + outflags |= MMAN_nl; + print_word(s); + outflags |= newflags; +} + +static void +print_block(const char *s, int newflags) +{ + + outflags &= ~MMAN_PP; + if (MMAN_sp & outflags) { + outflags &= ~(MMAN_sp | MMAN_br); + if (MMAN_PD & outflags) { + print_line(".PD", 0); + outflags &= ~MMAN_PD; + } + } else if (! (MMAN_PD & outflags)) + print_line(".PD 0", MMAN_PD); + outflags |= MMAN_nl; + print_word(s); + outflags |= MMAN_Bk_susp | newflags; +} + +static void +print_offs(const char *v) +{ + char buf[24]; + struct roffsu su; + size_t sz; + + print_line(".RS", MMAN_Bk_susp); + + /* Convert v into a number (of characters). */ + if (NULL == v || '\0' == *v || 0 == strcmp(v, "left")) + sz = 0; + else if (0 == strcmp(v, "indent")) + sz = 6; + else if (0 == strcmp(v, "indent-two")) + sz = 12; + else if (a2roffsu(v, &su, SCALE_MAX)) { + if (SCALE_EN == su.unit) + sz = su.scale; + else { + /* + * XXX + * If we are inside an enclosing list, + * there is no easy way to add the two + * indentations because they are provided + * in terms of different units. + */ + print_word(v); + outflags |= MMAN_nl; + return; + } + } else + sz = strlen(v); + + /* + * We are inside an enclosing list. + * Add the two indentations. + */ + if (Bl_stack_len) + sz += Bl_stack[Bl_stack_len - 1]; + + snprintf(buf, sizeof(buf), "%zun", sz); + print_word(buf); + outflags |= MMAN_nl; +} + +/* + * Set up the indentation for a list item; used from pre_it(). + */ +void +print_width(const char *v, const struct mdoc_node *child, size_t defsz) +{ + char buf[24]; + struct roffsu su; + size_t sz, chsz; + int numeric, remain; + + numeric = 1; + remain = 0; + + /* Convert v into a number (of characters). */ + if (NULL == v) + sz = defsz; + else if (a2roffsu(v, &su, SCALE_MAX)) { + if (SCALE_EN == su.unit) + sz = su.scale; + else { + sz = 0; + numeric = 0; + } + } else + sz = strlen(v); + + /* XXX Rough estimation, might have multiple parts. */ + chsz = (NULL != child && MDOC_TEXT == child->type) ? + strlen(child->string) : 0; + + /* Maybe we are inside an enclosing list? */ + mid_it(); + + /* + * Save our own indentation, + * such that child lists can use it. + */ + Bl_stack[Bl_stack_len++] = sz + 2; + + /* Set up the current list. */ + if (defsz && chsz > sz) + print_block(".HP", 0); + else { + print_block(".TP", 0); + remain = sz + 2; } + if (numeric) { + snprintf(buf, sizeof(buf), "%zun", sz + 2); + print_word(buf); + } else + print_word(v); + TPremain = remain; +} + +void +print_count(int *count) +{ + char buf[12]; + + snprintf(buf, sizeof(buf), "%d.", ++*count); + print_word(buf); } void @@ -261,37 +535,42 @@ man_man(void *arg, const struct man *man) void man_mdoc(void *arg, const struct mdoc *mdoc) { - const struct mdoc_meta *m; + const struct mdoc_meta *meta; const struct mdoc_node *n; - struct mman mm; - m = mdoc_meta(mdoc); + meta = mdoc_meta(mdoc); n = mdoc_node(mdoc); - printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"", - m->title, m->msec, m->date, m->os, m->vol); + printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n", + meta->title, meta->msec, meta->date, + meta->os, meta->vol); - memset(&mm, 0, sizeof(struct mman)); + /* Disable hyphenation and if nroff, disable justification. */ + printf(".nh\n.if n .ad l"); - mm.need_nl = 1; - print_node(m, n, &mm); + outflags = MMAN_nl | MMAN_Sm; + if (0 == fontqueue.size) { + fontqueue.size = 8; + fontqueue.head = fontqueue.tail = mandoc_malloc(8); + *fontqueue.tail = 'R'; + } + print_node(meta, n); putchar('\n'); } static void print_node(DECL_ARGS) { - const struct mdoc_node *prev, *sub; + const struct mdoc_node *sub; const struct manact *act; int cond, do_sub; - + /* * Break the line if we were parsed subsequent the current node. * This makes the page structure be more consistent. */ - prev = n->prev ? n->prev : n->parent; - if (prev && prev->line < n->line) - mm->need_nl = 1; + if (MMAN_spc & outflags && MDOC_LINE & n->flags) + outflags |= MMAN_nl; act = NULL; cond = 0; @@ -302,21 +581,22 @@ print_node(DECL_ARGS) * Make sure that we don't happen to start with a * control character at the start of a line. */ - if (mm->need_nl && ('.' == *n->string || + if (MMAN_nl & outflags && ('.' == *n->string || '\'' == *n->string)) { - print_word(mm, "\\&"); - mm->need_space = 0; + print_word(""); + printf("\\&"); + outflags &= ~MMAN_spc; } - print_word(mm, n->string); + print_word(n->string); } else { /* * Conditionally run the pre-node action handler for a * node. */ act = manacts + n->tok; - cond = NULL == act->cond || (*act->cond)(m, n, mm); + cond = NULL == act->cond || (*act->cond)(meta, n); if (cond && act->pre) - do_sub = (*act->pre)(m, n, mm); + do_sub = (*act->pre)(meta, n); } /* @@ -326,13 +606,13 @@ print_node(DECL_ARGS) */ if (do_sub) for (sub = n->child; sub; sub = sub->next) - print_node(m, sub, mm); + print_node(meta, sub); /* * Lastly, conditionally run the post-node handler. */ if (cond && act->post) - (*act->post)(m, n, mm); + (*act->post)(meta, n); } static int @@ -349,10 +629,6 @@ cond_body(DECL_ARGS) return(MDOC_BODY == n->type); } -/* - * Output a font encoding before a node, e.g., \fR. - * This obviously has no trailing space. - */ static int pre_enc(DECL_ARGS) { @@ -361,14 +637,11 @@ pre_enc(DECL_ARGS) prefix = manacts[n->tok].prefix; if (NULL == prefix) return(1); - print_word(mm, prefix); - mm->need_space = 0; + print_word(prefix); + outflags &= ~MMAN_spc; return(1); } -/* - * Output a font encoding subsequent a node, e.g., \fP. - */ static void post_enc(DECL_ARGS) { @@ -377,28 +650,62 @@ post_enc(DECL_ARGS) suffix = manacts[n->tok].suffix; if (NULL == suffix) return; - mm->need_space = 0; - print_word(mm, suffix); + outflags &= ~MMAN_spc; + print_word(suffix); +} + +static void +post_font(DECL_ARGS) +{ + + font_pop(); } -/* - * Used in listings (percent = %A, e.g.). - * FIXME: this is incomplete. - * It doesn't print a nice ", and" for lists. - */ static void post_percent(DECL_ARGS) { - post_enc(m, n, mm); - if (n->next) - print_word(mm, ","); - else { - print_word(mm, "."); - mm->need_nl = 1; + if (pre_em == manacts[n->tok].pre) + font_pop(); + if (n->next) { + print_word(","); + if (n->prev && n->prev->tok == n->tok && + n->next->tok == n->tok) + print_word("and"); + } else { + print_word("."); + outflags |= MMAN_nl; } } +static int +pre__t(DECL_ARGS) +{ + + if (n->parent && MDOC_Rs == n->parent->tok && + n->parent->norm->Rs.quote_T) { + print_word(""); + putchar('\"'); + outflags &= ~MMAN_spc; + } else + font_push('I'); + return(1); +} + +static void +post__t(DECL_ARGS) +{ + + if (n->parent && MDOC_Rs == n->parent->tok && + n->parent->norm->Rs.quote_T) { + outflags &= ~MMAN_spc; + print_word(""); + putchar('\"'); + } else + font_pop(); + post_percent(meta, n); +} + /* * Print before a section header. */ @@ -406,12 +713,13 @@ static int pre_sect(DECL_ARGS) { - if (MDOC_HEAD != n->type) - return(1); - mm->need_nl = 1; - print_word(mm, manacts[n->tok].prefix); - print_word(mm, "\""); - mm->need_space = 0; + if (MDOC_HEAD == n->type) { + outflags |= MMAN_sp; + print_block(manacts[n->tok].prefix, 0); + print_word(""); + putchar('\"'); + outflags &= ~MMAN_spc; + } return(1); } @@ -424,18 +732,84 @@ post_sect(DECL_ARGS) if (MDOC_HEAD != n->type) return; - mm->need_space = 0; - print_word(mm, "\""); - mm->need_nl = 1; + outflags &= ~MMAN_spc; + print_word(""); + putchar('\"'); + outflags |= MMAN_nl; + if (MDOC_Sh == n->tok && SEC_AUTHORS == n->sec) + outflags &= ~(MMAN_An_split | MMAN_An_nosplit); +} + +/* See mdoc_term.c, synopsis_pre() for comments. */ +static void +pre_syn(const struct mdoc_node *n) +{ + + if (NULL == n->prev || ! (MDOC_SYNPRETTY & n->flags)) + return; + + if (n->prev->tok == n->tok && + MDOC_Ft != n->tok && + MDOC_Fo != n->tok && + MDOC_Fn != n->tok) { + outflags |= MMAN_br; + return; + } + + switch (n->prev->tok) { + case (MDOC_Fd): + /* FALLTHROUGH */ + case (MDOC_Fn): + /* FALLTHROUGH */ + case (MDOC_Fo): + /* FALLTHROUGH */ + case (MDOC_In): + /* FALLTHROUGH */ + case (MDOC_Vt): + outflags |= MMAN_sp; + break; + case (MDOC_Ft): + if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) { + outflags |= MMAN_sp; + break; + } + /* FALLTHROUGH */ + default: + outflags |= MMAN_br; + break; + } +} + +static int +pre_an(DECL_ARGS) +{ + + switch (n->norm->An.auth) { + case (AUTH_split): + outflags &= ~MMAN_An_nosplit; + outflags |= MMAN_An_split; + return(0); + case (AUTH_nosplit): + outflags &= ~MMAN_An_split; + outflags |= MMAN_An_nosplit; + return(0); + default: + if (MMAN_An_split & outflags) + outflags |= MMAN_br; + else if (SEC_AUTHORS == n->sec && + ! (MMAN_An_nosplit & outflags)) + outflags |= MMAN_An_split; + return(1); + } } static int pre_ap(DECL_ARGS) { - mm->need_space = 0; - print_word(mm, "'"); - mm->need_space = 0; + outflags &= ~MMAN_spc; + print_word("'"); + outflags &= ~MMAN_spc; return(0); } @@ -443,12 +817,14 @@ static int pre_bd(DECL_ARGS) { + outflags &= ~(MMAN_PP | MMAN_sp | MMAN_br); + if (DISP_unfilled == n->norm->Bd.type || - DISP_literal == n->norm->Bd.type) { - mm->need_nl = 1; - print_word(mm, ".nf"); - } - mm->need_nl = 1; + DISP_literal == n->norm->Bd.type) + print_line(".nf", 0); + if (0 == n->norm->Bd.comp && NULL != n->parent->prev) + outflags |= MMAN_sp; + print_offs(n->norm->Bd.offs); return(1); } @@ -456,21 +832,143 @@ static void post_bd(DECL_ARGS) { + /* Close out this display. */ + print_line(".RE", MMAN_nl); if (DISP_unfilled == n->norm->Bd.type || - DISP_literal == n->norm->Bd.type) { - mm->need_nl = 1; - print_word(mm, ".fi"); + DISP_literal == n->norm->Bd.type) + print_line(".fi", MMAN_nl); + + /* Maybe we are inside an enclosing list? */ + if (NULL != n->parent->next) + mid_it(); +} + +static int +pre_bf(DECL_ARGS) +{ + + switch (n->type) { + case (MDOC_BLOCK): + return(1); + case (MDOC_BODY): + break; + default: + return(0); + } + switch (n->norm->Bf.font) { + case (FONT_Em): + font_push('I'); + break; + case (FONT_Sy): + font_push('B'); + break; + default: + font_push('R'); + break; } - mm->need_nl = 1; + return(1); +} + +static void +post_bf(DECL_ARGS) +{ + + if (MDOC_BODY == n->type) + font_pop(); +} + +static int +pre_bk(DECL_ARGS) +{ + + switch (n->type) { + case (MDOC_BLOCK): + return(1); + case (MDOC_BODY): + outflags |= MMAN_Bk; + return(1); + default: + return(0); + } +} + +static void +post_bk(DECL_ARGS) +{ + + if (MDOC_BODY == n->type) + outflags &= ~MMAN_Bk; +} + +static int +pre_bl(DECL_ARGS) +{ + size_t icol; + + /* + * print_offs() will increase the -offset to account for + * a possible enclosing .It, but any enclosed .It blocks + * just nest and do not add up their indentation. + */ + if (n->norm->Bl.offs) { + print_offs(n->norm->Bl.offs); + Bl_stack[Bl_stack_len++] = 0; + } + + switch (n->norm->Bl.type) { + case (LIST_enum): + n->norm->Bl.count = 0; + return(1); + case (LIST_column): + break; + default: + return(1); + } + + print_line(".TS", MMAN_nl); + for (icol = 0; icol < n->norm->Bl.ncols; icol++) + print_word("l"); + print_word("."); + outflags |= MMAN_nl; + return(1); +} + +static void +post_bl(DECL_ARGS) +{ + + switch (n->norm->Bl.type) { + case (LIST_column): + print_line(".TE", 0); + break; + case (LIST_enum): + n->norm->Bl.count = 0; + break; + default: + break; + } + + if (n->norm->Bl.offs) { + print_line(".RE", MMAN_nl); + assert(Bl_stack_len); + Bl_stack_len--; + assert(0 == Bl_stack[Bl_stack_len]); + } else { + outflags |= MMAN_PP | MMAN_nl; + outflags &= ~(MMAN_sp | MMAN_br); + } + + /* Maybe we are inside an enclosing list? */ + if (NULL != n->parent->next) + mid_it(); + } static int pre_br(DECL_ARGS) { - mm->need_nl = 1; - print_word(mm, ".br"); - mm->need_nl = 1; + outflags |= MMAN_br; return(0); } @@ -480,17 +978,17 @@ pre_bx(DECL_ARGS) n = n->child; if (n) { - print_word(mm, n->string); - mm->need_space = 0; + print_word(n->string); + outflags &= ~MMAN_spc; n = n->next; } - print_word(mm, "BSD"); + print_word("BSD"); if (NULL == n) return(0); - mm->need_space = 0; - print_word(mm, "-"); - mm->need_space = 0; - print_word(mm, n->string); + outflags &= ~MMAN_spc; + print_word("-"); + outflags &= ~MMAN_spc; + print_word(n->string); return(0); } @@ -498,9 +996,7 @@ static int pre_dl(DECL_ARGS) { - mm->need_nl = 1; - print_word(mm, ".RS 6n"); - mm->need_nl = 1; + print_offs("6n"); return(1); } @@ -508,9 +1004,213 @@ static void post_dl(DECL_ARGS) { - mm->need_nl = 1; - print_word(mm, ".RE"); - mm->need_nl = 1; + print_line(".RE", MMAN_nl); + + /* Maybe we are inside an enclosing list? */ + if (NULL != n->parent->next) + mid_it(); +} + +static int +pre_em(DECL_ARGS) +{ + + font_push('I'); + return(1); +} + +static void +post_eo(DECL_ARGS) +{ + + if (MDOC_HEAD == n->type || MDOC_BODY == n->type) + outflags &= ~MMAN_spc; +} + +static int +pre_fa(DECL_ARGS) +{ + int am_Fa; + + am_Fa = MDOC_Fa == n->tok; + + if (am_Fa) + n = n->child; + + while (NULL != n) { + font_push('I'); + if (am_Fa || MDOC_SYNPRETTY & n->flags) + outflags |= MMAN_nbrword; + print_node(meta, n); + font_pop(); + if (NULL != (n = n->next)) + print_word(","); + } + return(0); +} + +static void +post_fa(DECL_ARGS) +{ + + if (NULL != n->next && MDOC_Fa == n->next->tok) + print_word(","); +} + +static int +pre_fd(DECL_ARGS) +{ + + pre_syn(n); + font_push('B'); + return(1); +} + +static void +post_fd(DECL_ARGS) +{ + + font_pop(); + outflags |= MMAN_br; +} + +static int +pre_fl(DECL_ARGS) +{ + + font_push('B'); + print_word("\\-"); + outflags &= ~MMAN_spc; + return(1); +} + +static void +post_fl(DECL_ARGS) +{ + + font_pop(); + if (0 == n->nchild && NULL != n->next && + n->next->line == n->line) + outflags &= ~MMAN_spc; +} + +static int +pre_fn(DECL_ARGS) +{ + + pre_syn(n); + + n = n->child; + if (NULL == n) + return(0); + + if (MDOC_SYNPRETTY & n->flags) + print_block(".HP 4n", MMAN_nl); + + font_push('B'); + print_node(meta, n); + font_pop(); + outflags &= ~MMAN_spc; + print_word("("); + outflags &= ~MMAN_spc; + + n = n->next; + if (NULL != n) + pre_fa(meta, n); + return(0); +} + +static void +post_fn(DECL_ARGS) +{ + + print_word(")"); + if (MDOC_SYNPRETTY & n->flags) { + print_word(";"); + outflags |= MMAN_PP; + } +} + +static int +pre_fo(DECL_ARGS) +{ + + switch (n->type) { + case (MDOC_BLOCK): + pre_syn(n); + break; + case (MDOC_HEAD): + if (MDOC_SYNPRETTY & n->flags) + print_block(".HP 4n", MMAN_nl); + font_push('B'); + break; + case (MDOC_BODY): + outflags &= ~MMAN_spc; + print_word("("); + outflags &= ~MMAN_spc; + break; + default: + break; + } + return(1); +} + +static void +post_fo(DECL_ARGS) +{ + + switch (n->type) { + case (MDOC_HEAD): + font_pop(); + break; + case (MDOC_BODY): + post_fn(meta, n); + break; + default: + break; + } +} + +static int +pre_ft(DECL_ARGS) +{ + + pre_syn(n); + font_push('I'); + return(1); +} + +static int +pre_in(DECL_ARGS) +{ + + if (MDOC_SYNPRETTY & n->flags) { + pre_syn(n); + font_push('B'); + print_word("#include <"); + outflags &= ~MMAN_spc; + } else { + print_word("<"); + outflags &= ~MMAN_spc; + font_push('I'); + } + return(1); +} + +static void +post_in(DECL_ARGS) +{ + + if (MDOC_SYNPRETTY & n->flags) { + outflags &= ~MMAN_spc; + print_word(">"); + font_pop(); + outflags |= MMAN_br; + } else { + font_pop(); + outflags &= ~MMAN_spc; + print_word(">"); + } } static int @@ -518,36 +1218,221 @@ pre_it(DECL_ARGS) { const struct mdoc_node *bln; - if (MDOC_HEAD == n->type) { - mm->need_nl = 1; - print_word(mm, ".TP"); - bln = n->parent->parent->prev; + switch (n->type) { + case (MDOC_HEAD): + outflags |= MMAN_PP | MMAN_nl; + bln = n->parent->parent; + if (0 == bln->norm->Bl.comp || + (NULL == n->parent->prev && + NULL == bln->parent->prev)) + outflags |= MMAN_sp; + outflags &= ~MMAN_br; switch (bln->norm->Bl.type) { + case (LIST_item): + return(0); + case (LIST_inset): + /* FALLTHROUGH */ + case (LIST_diag): + /* FALLTHROUGH */ + case (LIST_ohang): + if (bln->norm->Bl.type == LIST_diag) + print_line(".B \"", 0); + else + print_line(".R \"", 0); + outflags &= ~MMAN_spc; + return(1); case (LIST_bullet): - print_word(mm, "4n"); - mm->need_nl = 1; - print_word(mm, "\\fBo\\fP"); + /* FALLTHROUGH */ + case (LIST_dash): + /* FALLTHROUGH */ + case (LIST_hyphen): + print_width(bln->norm->Bl.width, NULL, 0); + TPremain = 0; + outflags |= MMAN_nl; + font_push('B'); + if (LIST_bullet == bln->norm->Bl.type) + print_word("o"); + else + print_word("-"); + font_pop(); + break; + case (LIST_enum): + print_width(bln->norm->Bl.width, NULL, 0); + TPremain = 0; + outflags |= MMAN_nl; + print_count(&bln->norm->Bl.count); + break; + case (LIST_hang): + print_width(bln->norm->Bl.width, n->child, 6); + TPremain = 0; + break; + case (LIST_tag): + print_width(bln->norm->Bl.width, n->child, 0); + putchar('\n'); + outflags &= ~MMAN_spc; + return(1); + default: + return(1); + } + outflags |= MMAN_nl; + default: + break; + } + return(1); +} + +/* + * This function is called after closing out an indented block. + * If we are inside an enclosing list, restore its indentation. + */ +static void +mid_it(void) +{ + char buf[24]; + + /* Nothing to do outside a list. */ + if (0 == Bl_stack_len || 0 == Bl_stack[Bl_stack_len - 1]) + return; + + /* The indentation has already been set up. */ + if (Bl_stack_post[Bl_stack_len - 1]) + return; + + /* Restore the indentation of the enclosing list. */ + print_line(".RS", MMAN_Bk_susp); + snprintf(buf, sizeof(buf), "%zun", Bl_stack[Bl_stack_len - 1]); + print_word(buf); + + /* Remeber to close out this .RS block later. */ + Bl_stack_post[Bl_stack_len - 1] = 1; +} + +static void +post_it(DECL_ARGS) +{ + const struct mdoc_node *bln; + + bln = n->parent->parent; + + switch (n->type) { + case (MDOC_HEAD): + switch (bln->norm->Bl.type) { + case (LIST_diag): + outflags &= ~MMAN_spc; + print_word("\\ "); + break; + case (LIST_ohang): + outflags |= MMAN_br; + break; + default: + break; + } + break; + case (MDOC_BODY): + switch (bln->norm->Bl.type) { + case (LIST_bullet): + /* FALLTHROUGH */ + case (LIST_dash): + /* FALLTHROUGH */ + case (LIST_hyphen): + /* FALLTHROUGH */ + case (LIST_enum): + /* FALLTHROUGH */ + case (LIST_hang): + /* FALLTHROUGH */ + case (LIST_tag): + assert(Bl_stack_len); + Bl_stack[--Bl_stack_len] = 0; + + /* + * Our indentation had to be restored + * after a child display or child list. + * Close out that indentation block now. + */ + if (Bl_stack_post[Bl_stack_len]) { + print_line(".RE", MMAN_nl); + Bl_stack_post[Bl_stack_len] = 0; + } + break; + case (LIST_column): + if (NULL != n->next) { + putchar('\t'); + outflags &= ~MMAN_spc; + } break; default: - if (bln->norm->Bl.width) - print_word(mm, bln->norm->Bl.width); break; } - mm->need_nl = 1; + break; + default: + break; } +} + +static void +post_lb(DECL_ARGS) +{ + + if (SEC_LIBRARY == n->sec) + outflags |= MMAN_br; +} + +static int +pre_lk(DECL_ARGS) +{ + const struct mdoc_node *link, *descr; + + if (NULL == (link = n->child)) + return(0); + + if (NULL != (descr = link->next)) { + font_push('I'); + while (NULL != descr) { + print_word(descr->string); + descr = descr->next; + } + print_word(":"); + font_pop(); + } + + font_push('B'); + print_word(link->string); + font_pop(); + return(0); +} + +static int +pre_li(DECL_ARGS) +{ + + font_push('R'); return(1); } static int pre_nm(DECL_ARGS) { + char *name; + if (MDOC_BLOCK == n->type) { + outflags |= MMAN_Bk; + pre_syn(n); + } if (MDOC_ELEM != n->type && MDOC_HEAD != n->type) return(1); - print_word(mm, "\\fB"); - mm->need_space = 0; + name = n->child ? n->child->string : meta->name; + if (NULL == name) + return(0); + if (MDOC_HEAD == n->type) { + if (NULL == n->parent->prev) + outflags |= MMAN_sp; + print_block(".HP", 0); + printf(" %zun", strlen(name) + 1); + outflags |= MMAN_nl; + } + font_push('B'); if (NULL == n->child) - print_word(mm, m->name); + print_word(meta->name); return(1); } @@ -555,17 +1440,33 @@ static void post_nm(DECL_ARGS) { - if (MDOC_ELEM != n->type && MDOC_HEAD != n->type) - return; - mm->need_space = 0; - print_word(mm, "\\fP"); + switch (n->type) { + case (MDOC_BLOCK): + outflags &= ~MMAN_Bk; + break; + case (MDOC_HEAD): + /* FALLTHROUGH */ + case (MDOC_ELEM): + font_pop(); + break; + default: + break; + } +} + +static int +pre_no(DECL_ARGS) +{ + + outflags |= MMAN_spc_force; + return(1); } static int pre_ns(DECL_ARGS) { - mm->need_space = 0; + outflags &= ~MMAN_spc; return(0); } @@ -573,28 +1474,52 @@ static void post_pf(DECL_ARGS) { - mm->need_space = 0; + outflags &= ~MMAN_spc; } static int pre_pp(DECL_ARGS) { - mm->need_nl = 1; - if (MDOC_It == n->parent->tok) - print_word(mm, ".sp"); - else - print_word(mm, ".PP"); - mm->need_nl = 1; + if (MDOC_It != n->parent->tok) + outflags |= MMAN_PP; + outflags |= MMAN_sp | MMAN_nl; + outflags &= ~MMAN_br; + return(0); +} + +static int +pre_rs(DECL_ARGS) +{ + + if (SEC_SEE_ALSO == n->sec) { + outflags |= MMAN_PP | MMAN_sp | MMAN_nl; + outflags &= ~MMAN_br; + } return(1); } static int +pre_sm(DECL_ARGS) +{ + + assert(n->child && MDOC_TEXT == n->child->type); + if (0 == strcmp("on", n->child->string)) + outflags |= MMAN_Sm | MMAN_spc; + else + outflags &= ~MMAN_Sm; + return(0); +} + +static int pre_sp(DECL_ARGS) { - mm->need_nl = 1; - print_word(mm, ".sp"); + if (MMAN_PP & outflags) { + outflags &= ~MMAN_PP; + print_line(".PP", 0); + } else + print_line(".sp", 0); return(1); } @@ -602,7 +1527,43 @@ static void post_sp(DECL_ARGS) { - mm->need_nl = 1; + outflags |= MMAN_nl; +} + +static int +pre_sy(DECL_ARGS) +{ + + font_push('B'); + return(1); +} + +static int +pre_vt(DECL_ARGS) +{ + + if (MDOC_SYNPRETTY & n->flags) { + switch (n->type) { + case (MDOC_BLOCK): + pre_syn(n); + return(1); + case (MDOC_BODY): + break; + default: + return(0); + } + } + font_push('I'); + return(1); +} + +static void +post_vt(DECL_ARGS) +{ + + if (MDOC_SYNPRETTY & n->flags && MDOC_BODY != n->type) + return; + font_pop(); } static int @@ -612,14 +1573,14 @@ pre_xr(DECL_ARGS) n = n->child; if (NULL == n) return(0); - print_node(m, n, mm); + print_node(meta, n); n = n->next; if (NULL == n) return(0); - mm->need_space = 0; - print_word(mm, "("); - print_node(m, n, mm); - print_word(mm, ")"); + outflags &= ~MMAN_spc; + print_word("("); + print_node(meta, n); + print_word(")"); return(0); } @@ -627,11 +1588,11 @@ static int pre_ux(DECL_ARGS) { - print_word(mm, manacts[n->tok].prefix); + print_word(manacts[n->tok].prefix); if (NULL == n->child) return(0); - mm->need_space = 0; - print_word(mm, "\\~"); - mm->need_space = 0; + outflags &= ~MMAN_spc; + print_word("\\ "); + outflags &= ~MMAN_spc; return(1); } diff --git a/usr/src/cmd/mandoc/mdoc_term.c b/usr/src/cmd/mandoc/mdoc_term.c index 5333566444..268fcae006 100644 --- a/usr/src/cmd/mandoc/mdoc_term.c +++ b/usr/src/cmd/mandoc/mdoc_term.c @@ -1,7 +1,8 @@ -/* $Id: mdoc_term.c,v 1.238 2011/11/13 13:15:14 schwarze Exp $ */ +/* $Id: mdoc_term.c,v 1.258 2013/12/25 21:24:12 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -41,8 +42,8 @@ struct termpair { #define DECL_ARGS struct termp *p, \ struct termpair *pair, \ - const struct mdoc_meta *m, \ - const struct mdoc_node *n + const struct mdoc_meta *meta, \ + struct mdoc_node *n struct termact { int (*pre)(DECL_ARGS); @@ -69,7 +70,7 @@ 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_d1_post(DECL_ARGS); +static void termp_fd_post(DECL_ARGS); static void termp_fo_post(DECL_ARGS); static void termp_in_post(DECL_ARGS); static void termp_it_post(DECL_ARGS); @@ -100,7 +101,6 @@ static int termp_fl_pre(DECL_ARGS); static int termp_fn_pre(DECL_ARGS); static int termp_fo_pre(DECL_ARGS); static int termp_ft_pre(DECL_ARGS); -static int termp_igndelim_pre(DECL_ARGS); static int termp_in_pre(DECL_ARGS); static int termp_it_pre(DECL_ARGS); static int termp_li_pre(DECL_ARGS); @@ -129,8 +129,8 @@ static const struct termact termacts[MDOC_MAX] = { { termp_sh_pre, termp_sh_post }, /* Sh */ { termp_ss_pre, termp_ss_post }, /* Ss */ { termp_sp_pre, NULL }, /* Pp */ - { termp_d1_pre, termp_d1_post }, /* D1 */ - { termp_d1_pre, termp_d1_post }, /* Dl */ + { termp_d1_pre, termp_bl_post }, /* D1 */ + { termp_d1_pre, termp_bl_post }, /* Dl */ { termp_bd_pre, termp_bd_post }, /* Bd */ { NULL, NULL }, /* Ed */ { termp_bl_pre, termp_bl_post }, /* Bl */ @@ -146,7 +146,7 @@ static const struct termact termacts[MDOC_MAX] = { { NULL, NULL }, /* Ev */ { termp_ex_pre, NULL }, /* Ex */ { termp_fa_pre, NULL }, /* Fa */ - { termp_fd_pre, NULL }, /* Fd */ + { termp_fd_pre, termp_fd_post }, /* Fd */ { termp_fl_pre, NULL }, /* Fl */ { termp_fn_pre, NULL }, /* Fn */ { termp_ft_pre, NULL }, /* Ft */ @@ -194,12 +194,12 @@ static const struct termact termacts[MDOC_MAX] = { { termp_quote_pre, termp_quote_post }, /* Eo */ { termp_xx_pre, NULL }, /* Fx */ { termp_bold_pre, NULL }, /* Ms */ - { termp_igndelim_pre, NULL }, /* No */ + { NULL, NULL }, /* No */ { termp_ns_pre, NULL }, /* Ns */ { termp_xx_pre, NULL }, /* Nx */ { termp_xx_pre, NULL }, /* Ox */ { NULL, NULL }, /* Pc */ - { termp_igndelim_pre, termp_pf_post }, /* Pf */ + { NULL, termp_pf_post }, /* Pf */ { termp_quote_pre, termp_quote_post }, /* Po */ { termp_quote_pre, termp_quote_post }, /* Pq */ { NULL, NULL }, /* Qc */ @@ -242,7 +242,7 @@ static const struct termact termacts[MDOC_MAX] = { { NULL, termp____post }, /* %Q */ { termp_sp_pre, NULL }, /* br */ { termp_sp_pre, NULL }, /* sp */ - { termp_under_pre, termp____post }, /* %U */ + { NULL, termp____post }, /* %U */ { NULL, NULL }, /* Ta */ }; @@ -251,7 +251,7 @@ void terminal_mdoc(void *arg, const struct mdoc *mdoc) { const struct mdoc_node *n; - const struct mdoc_meta *m; + const struct mdoc_meta *meta; struct termp *p; p = (struct termp *)arg; @@ -267,12 +267,12 @@ terminal_mdoc(void *arg, const struct mdoc *mdoc) p->symtab = mchars_alloc(); n = mdoc_node(mdoc); - m = mdoc_meta(mdoc); + meta = mdoc_meta(mdoc); - term_begin(p, print_mdoc_head, print_mdoc_foot, m); + term_begin(p, print_mdoc_head, print_mdoc_foot, meta); if (n->child) - print_mdoc_nodelist(p, NULL, m, n->child); + print_mdoc_nodelist(p, NULL, meta, n->child); term_end(p); } @@ -282,9 +282,9 @@ static void print_mdoc_nodelist(DECL_ARGS) { - print_mdoc_node(p, pair, m, n); + print_mdoc_node(p, pair, meta, n); if (n->next) - print_mdoc_nodelist(p, pair, m, n->next); + print_mdoc_nodelist(p, pair, meta, n->next); } @@ -293,14 +293,13 @@ static void print_mdoc_node(DECL_ARGS) { int chld; - const void *font; struct termpair npair; size_t offset, rmargin; chld = 1; offset = p->offset; rmargin = p->rmargin; - font = term_fontq(p); + n->prev_font = term_fontq(p); memset(&npair, 0, sizeof(struct termpair)); npair.ppair = pair; @@ -308,34 +307,17 @@ print_mdoc_node(DECL_ARGS) /* * Keeps only work until the end of a line. If a keep was * invoked in a prior line, revert it to PREKEEP. - * - * Also let SYNPRETTY sections behave as if they were wrapped - * in a `Bk' block. */ - if (TERMP_KEEP & p->flags || MDOC_SYNPRETTY & n->flags) { - if (n->prev && n->prev->line != n->line) { + if (TERMP_KEEP & p->flags) { + if (n->prev ? (n->prev->lastline != n->line) : + (n->parent && n->parent->line != n->line)) { p->flags &= ~TERMP_KEEP; p->flags |= TERMP_PREKEEP; - } else if (NULL == n->prev) { - if (n->parent && n->parent->line != n->line) { - p->flags &= ~TERMP_KEEP; - p->flags |= TERMP_PREKEEP; - } } } /* - * Since SYNPRETTY sections aren't "turned off" with `Ek', - * we have to intuit whether we should disable formatting. - */ - - if ( ! (MDOC_SYNPRETTY & n->flags) && - ((n->prev && MDOC_SYNPRETTY & n->prev->flags) || - (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. */ @@ -359,14 +341,15 @@ print_mdoc_node(DECL_ARGS) default: if (termacts[n->tok].pre && ENDBODY_NOT == n->end) chld = (*termacts[n->tok].pre) - (p, &npair, m, n); + (p, &npair, meta, n); break; } if (chld && n->child) - print_mdoc_nodelist(p, &npair, m, n->child); + print_mdoc_nodelist(p, &npair, meta, n->child); - term_fontpopq(p, font); + term_fontpopq(p, + (ENDBODY_NOT == n->end ? n : n->pending)->prev_font); switch (n->type) { case (MDOC_TEXT): @@ -378,7 +361,7 @@ print_mdoc_node(DECL_ARGS) default: if ( ! termacts[n->tok].post || MDOC_ENDED & n->flags) break; - (void)(*termacts[n->tok].post)(p, &npair, m, n); + (void)(*termacts[n->tok].post)(p, &npair, meta, n); /* * Explicit end tokens not only call the post @@ -409,9 +392,9 @@ print_mdoc_node(DECL_ARGS) static void print_mdoc_foot(struct termp *p, const void *arg) { - const struct mdoc_meta *m; + const struct mdoc_meta *meta; - m = (const struct mdoc_meta *)arg; + meta = (const struct mdoc_meta *)arg; term_fontrepl(p, TERMFONT_NONE); @@ -427,25 +410,27 @@ print_mdoc_foot(struct termp *p, const void *arg) p->offset = 0; p->rmargin = (p->maxrmargin - - term_strlen(p, m->date) + term_len(p, 1)) / 2; + term_strlen(p, meta->date) + term_len(p, 1)) / 2; + p->trailspace = 1; p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; - term_word(p, m->os); + term_word(p, meta->os); term_flushln(p); p->offset = p->rmargin; - p->rmargin = p->maxrmargin - term_strlen(p, m->os); + p->rmargin = p->maxrmargin - term_strlen(p, meta->os); p->flags |= TERMP_NOSPACE; - term_word(p, m->date); + term_word(p, meta->date); term_flushln(p); p->offset = p->rmargin; p->rmargin = p->maxrmargin; + p->trailspace = 0; p->flags &= ~TERMP_NOBREAK; p->flags |= TERMP_NOSPACE; - term_word(p, m->os); + term_word(p, meta->os); term_flushln(p); p->offset = 0; @@ -459,9 +444,9 @@ print_mdoc_head(struct termp *p, const void *arg) { char buf[BUFSIZ], title[BUFSIZ]; size_t buflen, titlen; - const struct mdoc_meta *m; + const struct mdoc_meta *meta; - m = (const struct mdoc_meta *)arg; + meta = (const struct mdoc_meta *)arg; /* * The header is strange. It has three components, which are @@ -479,20 +464,21 @@ print_mdoc_head(struct termp *p, const void *arg) p->offset = 0; p->rmargin = p->maxrmargin; - assert(m->vol); - strlcpy(buf, m->vol, BUFSIZ); + assert(meta->vol); + strlcpy(buf, meta->vol, BUFSIZ); buflen = term_strlen(p, buf); - if (m->arch) { + if (meta->arch) { strlcat(buf, " (", BUFSIZ); - strlcat(buf, m->arch, BUFSIZ); + strlcat(buf, meta->arch, BUFSIZ); strlcat(buf, ")", BUFSIZ); } - snprintf(title, BUFSIZ, "%s(%s)", m->title, m->msec); + snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec); titlen = term_strlen(p, title); p->flags |= TERMP_NOBREAK | TERMP_NOSPACE; + p->trailspace = 1; p->offset = 0; p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ? (p->maxrmargin - @@ -511,6 +497,7 @@ print_mdoc_head(struct termp *p, const void *arg) term_flushln(p); p->flags &= ~TERMP_NOBREAK; + p->trailspace = 0; if (p->rmargin + titlen <= p->maxrmargin) { p->flags |= TERMP_NOSPACE; p->offset = p->rmargin; @@ -727,12 +714,10 @@ termp_it_pre(DECL_ARGS) case (LIST_dash): /* FALLTHROUGH */ case (LIST_hyphen): - if (width < term_len(p, 4)) - width = term_len(p, 4); - break; + /* FALLTHROUGH */ case (LIST_enum): - if (width < term_len(p, 5)) - width = term_len(p, 5); + if (width < term_len(p, 2)) + width = term_len(p, 2); break; case (LIST_hang): if (0 == width) @@ -787,20 +772,26 @@ termp_it_pre(DECL_ARGS) */ switch (type) { + case (LIST_enum): + /* + * Weird special case. + * Very narrow enum lists actually hang. + */ + if (width == term_len(p, 2)) + p->flags |= TERMP_HANG; + /* FALLTHROUGH */ case (LIST_bullet): /* FALLTHROUGH */ case (LIST_dash): /* FALLTHROUGH */ - case (LIST_enum): - /* FALLTHROUGH */ case (LIST_hyphen): - if (MDOC_HEAD == n->type) - p->flags |= TERMP_NOBREAK; + if (MDOC_HEAD != n->type) + break; + p->flags |= TERMP_NOBREAK; + p->trailspace = 1; break; case (LIST_hang): - if (MDOC_HEAD == n->type) - p->flags |= TERMP_NOBREAK; - else + if (MDOC_HEAD != n->type) break; /* @@ -812,16 +803,18 @@ termp_it_pre(DECL_ARGS) if (n->next->child && (MDOC_Bl == n->next->child->tok || MDOC_Bd == n->next->child->tok)) - p->flags &= ~TERMP_NOBREAK; - else - p->flags |= TERMP_HANG; + break; + + p->flags |= TERMP_NOBREAK | TERMP_HANG; + p->trailspace = 1; break; case (LIST_tag): - if (MDOC_HEAD == n->type) - p->flags |= TERMP_NOBREAK | TERMP_TWOSPACE; - if (MDOC_HEAD != n->type) break; + + p->flags |= TERMP_NOBREAK; + p->trailspace = 2; + if (NULL == n->next || NULL == n->next->child) p->flags |= TERMP_DANGLE; break; @@ -829,15 +822,20 @@ termp_it_pre(DECL_ARGS) if (MDOC_HEAD == n->type) break; - if (NULL == n->next) + if (NULL == n->next) { p->flags &= ~TERMP_NOBREAK; - else + p->trailspace = 0; + } else { p->flags |= TERMP_NOBREAK; + p->trailspace = 1; + } break; case (LIST_diag): - if (MDOC_HEAD == n->type) - p->flags |= TERMP_NOBREAK; + if (MDOC_HEAD != n->type) + break; + p->flags |= TERMP_NOBREAK; + p->trailspace = 1; break; default: break; @@ -989,8 +987,8 @@ termp_it_post(DECL_ARGS) p->flags &= ~TERMP_DANGLE; p->flags &= ~TERMP_NOBREAK; - p->flags &= ~TERMP_TWOSPACE; p->flags &= ~TERMP_HANG; + p->trailspace = 0; } @@ -999,22 +997,25 @@ static int termp_nm_pre(DECL_ARGS) { - if (MDOC_BLOCK == n->type) + if (MDOC_BLOCK == n->type) { + p->flags |= TERMP_PREKEEP; return(1); + } if (MDOC_BODY == n->type) { if (NULL == n->child) return(0); p->flags |= TERMP_NOSPACE; p->offset += term_len(p, 1) + - (NULL == n->prev->child ? term_strlen(p, m->name) : + (NULL == n->prev->child ? + term_strlen(p, meta->name) : MDOC_TEXT == n->prev->child->type ? - term_strlen(p, n->prev->child->string) : + term_strlen(p, n->prev->child->string) : term_len(p, 5)); return(1); } - if (NULL == n->child && NULL == m->name) + if (NULL == n->child && NULL == meta->name) return(0); if (MDOC_HEAD == n->type) @@ -1022,9 +1023,10 @@ termp_nm_pre(DECL_ARGS) if (MDOC_HEAD == n->type && n->next->child) { p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; + p->trailspace = 1; p->rmargin = p->offset + term_len(p, 1); if (NULL == n->child) { - p->rmargin += term_strlen(p, m->name); + p->rmargin += term_strlen(p, meta->name); } else if (MDOC_TEXT == n->child->type) { p->rmargin += term_strlen(p, n->child->string); if (n->child->next) @@ -1037,7 +1039,7 @@ termp_nm_pre(DECL_ARGS) term_fontpush(p, TERMFONT_BOLD); if (NULL == n->child) - term_word(p, m->name); + term_word(p, meta->name); return(1); } @@ -1047,9 +1049,12 @@ static void termp_nm_post(DECL_ARGS) { - if (MDOC_HEAD == n->type && n->next->child) { + if (MDOC_BLOCK == n->type) { + p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP); + } else if (MDOC_HEAD == n->type && n->next->child) { term_flushln(p); p->flags &= ~(TERMP_NOBREAK | TERMP_HANG); + p->trailspace = 0; } else if (MDOC_BODY == n->type && n->child) term_flushln(p); } @@ -1375,14 +1380,14 @@ termp_vt_pre(DECL_ARGS) if (MDOC_ELEM == n->type) { synopsis_pre(p, n); - return(termp_under_pre(p, pair, m, n)); + return(termp_under_pre(p, pair, meta, n)); } else if (MDOC_BLOCK == n->type) { synopsis_pre(p, n); return(1); } else if (MDOC_HEAD == n->type) return(0); - return(termp_under_pre(p, pair, m, n)); + return(termp_under_pre(p, pair, meta, n)); } @@ -1402,7 +1407,16 @@ termp_fd_pre(DECL_ARGS) { synopsis_pre(p, n); - return(termp_bold_pre(p, pair, m, n)); + return(termp_bold_pre(p, pair, meta, n)); +} + + +/* ARGSUSED */ +static void +termp_fd_post(DECL_ARGS) +{ + + term_newln(p); } @@ -1425,6 +1439,8 @@ termp_sh_pre(DECL_ARGS) break; case (MDOC_BODY): p->offset = term_len(p, p->defindent); + if (SEC_AUTHORS == n->sec) + p->flags &= ~(TERMP_SPLIT|TERMP_NOSPLIT); break; default: break; @@ -1498,17 +1514,6 @@ termp_d1_pre(DECL_ARGS) /* ARGSUSED */ -static void -termp_d1_post(DECL_ARGS) -{ - - if (MDOC_BLOCK != n->type) - return; - term_newln(p); -} - - -/* ARGSUSED */ static int termp_ft_pre(DECL_ARGS) { @@ -1524,6 +1529,7 @@ termp_ft_pre(DECL_ARGS) static int termp_fn_pre(DECL_ARGS) { + size_t rmargin = 0; int pretty; pretty = MDOC_SYNPRETTY & n->flags; @@ -1533,11 +1539,24 @@ termp_fn_pre(DECL_ARGS) if (NULL == (n = n->child)) return(0); + if (pretty) { + rmargin = p->rmargin; + p->rmargin = p->offset + term_len(p, 4); + p->flags |= TERMP_NOBREAK | TERMP_HANG; + } + assert(MDOC_TEXT == n->type); term_fontpush(p, TERMFONT_BOLD); term_word(p, n->string); term_fontpop(p); + if (pretty) { + term_flushln(p); + p->flags &= ~(TERMP_NOBREAK | TERMP_HANG); + p->offset = p->rmargin; + p->rmargin = rmargin; + } + p->flags |= TERMP_NOSPACE; term_word(p, "("); p->flags |= TERMP_NOSPACE; @@ -1545,6 +1564,8 @@ termp_fn_pre(DECL_ARGS) for (n = n->next; n; n = n->next) { assert(MDOC_TEXT == n->type); term_fontpush(p, TERMFONT_UNDER); + if (pretty) + p->flags |= TERMP_NBRWORD; term_word(p, n->string); term_fontpop(p); @@ -1560,6 +1581,7 @@ termp_fn_pre(DECL_ARGS) if (pretty) { p->flags |= TERMP_NOSPACE; term_word(p, ";"); + term_flushln(p); } return(0); @@ -1579,20 +1601,16 @@ termp_fa_pre(DECL_ARGS) for (nn = n->child; nn; nn = nn->next) { term_fontpush(p, TERMFONT_UNDER); + p->flags |= TERMP_NBRWORD; term_word(p, nn->string); term_fontpop(p); - if (nn->next) { + if (nn->next || (n->next && n->next->tok == MDOC_Fa)) { p->flags |= TERMP_NOSPACE; term_word(p, ","); } } - if (n->child && n->next && n->next->tok == MDOC_Fa) { - p->flags |= TERMP_NOSPACE; - term_word(p, ","); - } - return(0); } @@ -1602,7 +1620,7 @@ static int termp_bd_pre(DECL_ARGS) { size_t tabwidth, rm, rmax; - const struct mdoc_node *nn; + struct mdoc_node *nn; if (MDOC_BLOCK == n->type) { print_bvspace(p, n, n); @@ -1634,7 +1652,7 @@ termp_bd_pre(DECL_ARGS) p->rmargin = p->maxrmargin = TERM_MAXMARGIN; for (nn = n->child; nn; nn = nn->next) { - print_mdoc_node(p, pair, m, nn); + print_mdoc_node(p, pair, meta, nn); /* * If the printed node flushes its own line, then we * needn't do it here as well. This is hacky, but the @@ -1751,7 +1769,8 @@ termp_xx_pre(DECL_ARGS) pp = "UNIX"; break; default: - break; + abort(); + /* NOTREACHED */ } term_word(p, pp); @@ -1766,16 +1785,6 @@ termp_xx_pre(DECL_ARGS) /* ARGSUSED */ -static int -termp_igndelim_pre(DECL_ARGS) -{ - - p->flags |= TERMP_IGNDELIM; - return(1); -} - - -/* ARGSUSED */ static void termp_pf_post(DECL_ARGS) { @@ -1923,7 +1932,7 @@ termp_quote_pre(DECL_ARGS) case (MDOC_Do): /* FALLTHROUGH */ case (MDOC_Dq): - term_word(p, "``"); + term_word(p, "\\(lq"); break; case (MDOC_Eo): break; @@ -1944,7 +1953,7 @@ termp_quote_pre(DECL_ARGS) case (MDOC_So): /* FALLTHROUGH */ case (MDOC_Sq): - term_word(p, "`"); + term_word(p, "\\(oq"); break; default: abort(); @@ -1989,7 +1998,7 @@ termp_quote_post(DECL_ARGS) case (MDOC_Do): /* FALLTHROUGH */ case (MDOC_Dq): - term_word(p, "''"); + term_word(p, "\\(rq"); break; case (MDOC_Eo): break; @@ -2010,7 +2019,7 @@ termp_quote_post(DECL_ARGS) case (MDOC_So): /* FALLTHROUGH */ case (MDOC_Sq): - term_word(p, "'"); + term_word(p, "\\(cq"); break; default: abort(); @@ -2023,16 +2032,31 @@ termp_quote_post(DECL_ARGS) static int termp_fo_pre(DECL_ARGS) { + size_t rmargin = 0; + int pretty; + + pretty = MDOC_SYNPRETTY & n->flags; if (MDOC_BLOCK == n->type) { synopsis_pre(p, n); return(1); } else if (MDOC_BODY == n->type) { + if (pretty) { + rmargin = p->rmargin; + p->rmargin = p->offset + term_len(p, 4); + p->flags |= TERMP_NOBREAK | TERMP_HANG; + } p->flags |= TERMP_NOSPACE; term_word(p, "("); p->flags |= TERMP_NOSPACE; + if (pretty) { + term_flushln(p); + p->flags &= ~(TERMP_NOBREAK | TERMP_HANG); + p->offset = p->rmargin; + p->rmargin = rmargin; + } return(1); - } + } if (NULL == n->child) return(0); @@ -2060,6 +2084,7 @@ termp_fo_post(DECL_ARGS) if (MDOC_SYNPRETTY & n->flags) { p->flags |= TERMP_NOSPACE; term_word(p, ";"); + term_flushln(p); } } @@ -2071,7 +2096,7 @@ termp_bf_pre(DECL_ARGS) if (MDOC_HEAD == n->type) return(0); - else if (MDOC_BLOCK != n->type) + else if (MDOC_BODY != n->type) return(1); if (FONT_Em == n->norm->Bf.font) @@ -2157,25 +2182,24 @@ termp_li_pre(DECL_ARGS) static int termp_lk_pre(DECL_ARGS) { - const struct mdoc_node *nn, *sv; - - term_fontpush(p, TERMFONT_UNDER); + const struct mdoc_node *link, *descr; - nn = sv = n->child; - - if (NULL == nn || NULL == nn->next) - return(1); - - for (nn = nn->next; nn; nn = nn->next) - term_word(p, nn->string); - - term_fontpop(p); + if (NULL == (link = n->child)) + return(0); - p->flags |= TERMP_NOSPACE; - term_word(p, ":"); + if (NULL != (descr = link->next)) { + term_fontpush(p, TERMFONT_UNDER); + while (NULL != descr) { + term_word(p, descr->string); + descr = descr->next; + } + p->flags |= TERMP_NOSPACE; + term_word(p, ":"); + term_fontpop(p); + } term_fontpush(p, TERMFONT_BOLD); - term_word(p, sv->string); + term_word(p, link->string); term_fontpop(p); return(0); @@ -2225,9 +2249,9 @@ termp__t_post(DECL_ARGS) */ if (n->parent && MDOC_Rs == n->parent->tok && n->parent->norm->Rs.quote_T) - termp_quote_post(p, pair, m, n); + termp_quote_post(p, pair, meta, n); - termp____post(p, pair, m, n); + termp____post(p, pair, meta, n); } /* ARGSUSED */ @@ -2241,7 +2265,7 @@ termp__t_pre(DECL_ARGS) */ if (n->parent && MDOC_Rs == n->parent->tok && n->parent->norm->Rs.quote_T) - return(termp_quote_pre(p, pair, m, n)); + return(termp_quote_pre(p, pair, meta, n)); term_fontpush(p, TERMFONT_UNDER); return(1); diff --git a/usr/src/cmd/mandoc/mdoc_validate.c b/usr/src/cmd/mandoc/mdoc_validate.c index 060ccdadec..4cfd620448 100644 --- a/usr/src/cmd/mandoc/mdoc_validate.c +++ b/usr/src/cmd/mandoc/mdoc_validate.c @@ -1,7 +1,7 @@ -/* $Id: mdoc_validate.c,v 1.182 2012/03/23 05:50:25 kristaps Exp $ */ +/* $Id: mdoc_validate.c,v 1.198 2013/12/15 21:23:52 schwarze Exp $ */ /* - * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,7 +19,7 @@ #include "config.h" #endif -#ifndef OSNAME +#ifndef OSNAME #include <sys/utsname.h> #endif @@ -97,17 +97,19 @@ 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_defaults(POST_ARGS); static int post_dd(POST_ARGS); static int post_dt(POST_ARGS); -static int post_defaults(POST_ARGS); -static int post_literal(POST_ARGS); static int post_eoln(POST_ARGS); +static int post_hyph(POST_ARGS); +static int post_ignpar(POST_ARGS); static int post_it(POST_ARGS); static int post_lb(POST_ARGS); +static int post_literal(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_par(POST_ARGS); static int post_prol(POST_ARGS); static int post_root(POST_ARGS); static int post_rs(POST_ARGS); @@ -141,27 +143,30 @@ 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_d1[] = { bwarn_ge1, post_hyph, 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 }; +static v_post posts_hyph[] = { post_hyph, NULL }; +static v_post posts_hyphtext[] = { ewarn_ge1, post_hyph, NULL }; static v_post posts_it[] = { post_it, NULL }; static v_post posts_lb[] = { post_lb, NULL }; -static v_post posts_nd[] = { berr_ge1, NULL }; +static v_post posts_nd[] = { berr_ge1, post_hyph, 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_pp[] = { post_par, ewarn_eq0, NULL }; static v_post posts_rs[] = { post_rs, NULL }; -static v_post posts_sh[] = { post_ignpar, hwarn_ge1, post_sh, NULL }; -static v_post posts_sp[] = { ewarn_le1, NULL }; -static v_post posts_ss[] = { post_ignpar, hwarn_ge1, NULL }; +static v_post posts_sh[] = { post_ignpar,hwarn_ge1,post_sh,post_hyph,NULL }; +static v_post posts_sp[] = { post_par, ewarn_le1, NULL }; +static v_post posts_ss[] = { post_ignpar, hwarn_ge1, post_hyph, NULL }; static v_post posts_st[] = { post_st, NULL }; static v_post posts_std[] = { post_std, 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_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 }; @@ -169,8 +174,6 @@ static v_pre pres_d1[] = { pre_display, NULL }; static v_pre pres_dl[] = { pre_literal, pre_display, NULL }; static v_pre pres_dd[] = { pre_dd, NULL }; static v_pre pres_dt[] = { pre_dt, NULL }; -static v_pre pres_er[] = { NULL, NULL }; -static v_pre pres_fd[] = { NULL, NULL }; static v_pre pres_it[] = { pre_it, pre_par, NULL }; static v_pre pres_os[] = { pre_os, NULL }; static v_pre pres_pp[] = { pre_par, NULL }; @@ -185,8 +188,8 @@ static const struct valids mdoc_valids[MDOC_MAX] = { { pres_os, posts_os }, /* Os */ { pres_sh, posts_sh }, /* Sh */ { pres_ss, posts_ss }, /* Ss */ - { pres_pp, posts_notext }, /* Pp */ - { pres_d1, posts_wline }, /* D1 */ + { pres_pp, posts_pp }, /* Pp */ + { pres_d1, posts_d1 }, /* D1 */ { pres_dl, posts_dl }, /* Dl */ { pres_bd, posts_bd }, /* Bd */ { NULL, NULL }, /* Ed */ @@ -199,11 +202,11 @@ static const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* Cd */ { NULL, NULL }, /* Cm */ { NULL, NULL }, /* Dv */ - { pres_er, NULL }, /* Er */ + { NULL, NULL }, /* Er */ { NULL, NULL }, /* Ev */ { pres_std, posts_std }, /* Ex */ { NULL, NULL }, /* Fa */ - { pres_fd, posts_text }, /* Fd */ + { NULL, posts_text }, /* Fd */ { NULL, NULL }, /* Fl */ { NULL, NULL }, /* Fn */ { NULL, NULL }, /* Ft */ @@ -221,15 +224,15 @@ static const struct valids mdoc_valids[MDOC_MAX] = { { NULL, posts_vt }, /* Vt */ { NULL, posts_text }, /* Xr */ { NULL, posts_text }, /* %A */ - { NULL, posts_text }, /* %B */ /* FIXME: can be used outside Rs/Re. */ + { NULL, posts_hyphtext }, /* %B */ /* FIXME: can be used outside Rs/Re. */ { NULL, posts_text }, /* %D */ { NULL, posts_text }, /* %I */ { NULL, posts_text }, /* %J */ - { NULL, posts_text }, /* %N */ - { NULL, posts_text }, /* %O */ + { NULL, posts_hyphtext }, /* %N */ + { NULL, posts_hyphtext }, /* %O */ { NULL, posts_text }, /* %P */ - { NULL, posts_text }, /* %R */ - { NULL, posts_text }, /* %T */ /* FIXME: can be used outside Rs/Re. */ + { NULL, posts_hyphtext }, /* %R */ + { NULL, posts_hyphtext }, /* %T */ /* FIXME: can be used outside Rs/Re. */ { NULL, posts_text }, /* %V */ { NULL, NULL }, /* Ac */ { NULL, NULL }, /* Ao */ @@ -269,7 +272,7 @@ static const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* So */ { NULL, NULL }, /* Sq */ { NULL, posts_bool }, /* Sm */ - { NULL, NULL }, /* Sx */ + { NULL, posts_hyph }, /* Sx */ { NULL, NULL }, /* Sy */ { NULL, NULL }, /* Tn */ { NULL, NULL }, /* Ux */ @@ -286,7 +289,7 @@ static const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* Fr */ { NULL, posts_eoln }, /* Ud */ { NULL, posts_lb }, /* Lb */ - { NULL, posts_notext }, /* Lp */ + { pres_pp, posts_pp }, /* Lp */ { NULL, NULL }, /* Lk */ { NULL, posts_defaults }, /* Mt */ { NULL, NULL }, /* Brq */ @@ -297,8 +300,8 @@ static const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* En */ { NULL, NULL }, /* Dx */ { NULL, posts_text }, /* %Q */ - { NULL, posts_notext }, /* br */ - { pres_pp, posts_sp }, /* sp */ + { NULL, posts_pp }, /* br */ + { NULL, posts_sp }, /* sp */ { NULL, posts_text1 }, /* %U */ { NULL, NULL }, /* Ta */ }; @@ -314,12 +317,12 @@ static const enum mdoct rsord[RSORD_MAX] = { MDOC__R, MDOC__N, MDOC__V, + MDOC__U, MDOC__P, MDOC__Q, - MDOC__D, - MDOC__O, MDOC__C, - MDOC__U + MDOC__D, + MDOC__O }; static const char * const secnames[SEC__MAX] = { @@ -414,29 +417,29 @@ mdoc_valid_post(struct mdoc *mdoc) } static int -check_count(struct mdoc *m, enum mdoc_type type, +check_count(struct mdoc *mdoc, enum mdoc_type type, enum check_lvl lvl, enum check_ineq ineq, int val) { const char *p; enum mandocerr t; - if (m->last->type != type) + if (mdoc->last->type != type) return(1); switch (ineq) { case (CHECK_LT): p = "less than "; - if (m->last->nchild < val) + if (mdoc->last->nchild < val) return(1); break; case (CHECK_GT): p = "more than "; - if (m->last->nchild > val) + if (mdoc->last->nchild > val) return(1); break; case (CHECK_EQ): p = ""; - if (val == m->last->nchild) + if (val == mdoc->last->nchild) return(1); break; default: @@ -445,9 +448,9 @@ check_count(struct mdoc *m, enum mdoc_type type, } t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT; - mandoc_vmsg(t, m->parse, m->last->line, m->last->pos, + mandoc_vmsg(t, mdoc->parse, mdoc->last->line, mdoc->last->pos, "want %s%d children (have %d)", - p, val, m->last->nchild); + p, val, mdoc->last->nchild); return(1); } @@ -513,7 +516,7 @@ hwarn_le1(POST_ARGS) } static void -check_args(struct mdoc *m, struct mdoc_node *n) +check_args(struct mdoc *mdoc, struct mdoc_node *n) { int i; @@ -522,34 +525,34 @@ check_args(struct mdoc *m, struct mdoc_node *n) assert(n->args->argc); for (i = 0; i < (int)n->args->argc; i++) - check_argv(m, n, &n->args->argv[i]); + check_argv(mdoc, n, &n->args->argv[i]); } static void -check_argv(struct mdoc *m, struct mdoc_node *n, struct mdoc_argv *v) +check_argv(struct mdoc *mdoc, struct mdoc_node *n, struct mdoc_argv *v) { int i; for (i = 0; i < (int)v->sz; i++) - check_text(m, v->line, v->pos, v->value[i]); + check_text(mdoc, v->line, v->pos, v->value[i]); /* FIXME: move to post_std(). */ if (MDOC_Std == v->arg) - if ( ! (v->sz || m->meta.name)) - mdoc_nmsg(m, n, MANDOCERR_NONAME); + if ( ! (v->sz || mdoc->meta.name)) + mdoc_nmsg(mdoc, n, MANDOCERR_NONAME); } static void -check_text(struct mdoc *m, int ln, int pos, char *p) +check_text(struct mdoc *mdoc, int ln, int pos, char *p) { char *cp; - if (MDOC_LITERAL & m->flags) + if (MDOC_LITERAL & mdoc->flags) return; for (cp = p; NULL != (p = strchr(p, '\t')); p++) - mdoc_pmsg(m, ln, pos + (int)(p - cp), MANDOCERR_BADTAB); + mdoc_pmsg(mdoc, ln, pos + (int)(p - cp), MANDOCERR_BADTAB); } static int @@ -733,14 +736,14 @@ pre_bl(PRE_ARGS) /* * Validate the width field. Some list types don't need width * types and should be warned about them. Others should have it - * and must also be warned. + * and must also be warned. Yet others have a default and need + * no warning. */ switch (n->norm->Bl.type) { case (LIST_tag): - if (n->norm->Bl.width) - break; - mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG); + if (NULL == n->norm->Bl.width) + mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG); break; case (LIST_column): /* FALLTHROUGH */ @@ -754,6 +757,18 @@ pre_bl(PRE_ARGS) if (n->norm->Bl.width) mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV); break; + case (LIST_bullet): + /* FALLTHROUGH */ + case (LIST_dash): + /* FALLTHROUGH */ + case (LIST_hyphen): + if (NULL == n->norm->Bl.width) + n->norm->Bl.width = "2n"; + break; + case (LIST_enum): + if (NULL == n->norm->Bl.width) + n->norm->Bl.width = "3n"; + break; default: break; } @@ -874,8 +889,6 @@ pre_sh(PRE_ARGS) if (MDOC_BLOCK != n->type) return(1); - - roff_regunset(mdoc->roff, REG_nS); return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT)); } @@ -1111,24 +1124,29 @@ post_nm(POST_ARGS) char buf[BUFSIZ]; int c; - /* If no child specified, make sure we have the meta name. */ - - if (NULL == mdoc->last->child && NULL == mdoc->meta.name) { - mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME); - return(1); - } else if (mdoc->meta.name) + if (NULL != mdoc->meta.name) return(1); - /* If no meta name, set it from the child. */ + /* Try to use our children for setting the meta name. */ - buf[0] = '\0'; - if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) { + if (NULL != mdoc->last->child) { + buf[0] = '\0'; + c = concat(buf, mdoc->last->child, BUFSIZ); + } else + c = 0; + + switch (c) { + case (-1): mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM); return(0); + case (0): + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME); + mdoc->meta.name = mandoc_strdup("UNKNOWN"); + break; + default: + mdoc->meta.name = mandoc_strdup(buf); + break; } - - assert(c); - mdoc->meta.name = mandoc_strdup(buf); return(1); } @@ -1334,7 +1352,7 @@ post_it(POST_ARGS) static int post_bl_block(POST_ARGS) { - struct mdoc_node *n; + struct mdoc_node *n, *ni, *nc; /* * These are fairly complicated, so we've broken them into two @@ -1350,13 +1368,42 @@ post_bl_block(POST_ARGS) NULL == n->norm->Bl.width) { if ( ! post_bl_block_tag(mdoc)) return(0); + assert(n->norm->Bl.width); } else if (NULL != n->norm->Bl.width) { if ( ! post_bl_block_width(mdoc)) return(0); - } else - return(1); + assert(n->norm->Bl.width); + } - assert(n->norm->Bl.width); + for (ni = n->body->child; ni; ni = ni->next) { + if (NULL == ni->body) + continue; + nc = ni->body->last; + while (NULL != nc) { + switch (nc->tok) { + case (MDOC_Pp): + /* FALLTHROUGH */ + case (MDOC_Lp): + /* FALLTHROUGH */ + case (MDOC_br): + break; + default: + nc = NULL; + continue; + } + if (NULL == ni->next) { + mdoc_nmsg(mdoc, nc, MANDOCERR_MOVEPAR); + if ( ! mdoc_node_relink(mdoc, nc)) + return(0); + } else if (0 == n->norm->Bl.comp && + LIST_column != n->norm->Bl.type) { + mdoc_nmsg(mdoc, nc, MANDOCERR_IGNPAR); + mdoc_node_delete(mdoc, nc); + } else + break; + nc = ni->body->last; + } + } return(1); } @@ -1544,32 +1591,71 @@ post_bl_head(POST_ARGS) static int post_bl(POST_ARGS) { - struct mdoc_node *n; + struct mdoc_node *nparent, *nprev; /* of the Bl block */ + struct mdoc_node *nblock, *nbody; /* of the Bl */ + struct mdoc_node *nchild, *nnext; /* of the Bl body */ - if (MDOC_HEAD == mdoc->last->type) - return(post_bl_head(mdoc)); - if (MDOC_BLOCK == mdoc->last->type) + nbody = mdoc->last; + switch (nbody->type) { + case (MDOC_BLOCK): return(post_bl_block(mdoc)); - if (MDOC_BODY != mdoc->last->type) + case (MDOC_HEAD): + return(post_bl_head(mdoc)); + case (MDOC_BODY): + break; + default: return(1); + } - for (n = mdoc->last->child; n; n = n->next) { - switch (n->tok) { - case (MDOC_Lp): - /* FALLTHROUGH */ - case (MDOC_Pp): - mdoc_nmsg(mdoc, n, MANDOCERR_CHILD); - /* FALLTHROUGH */ - case (MDOC_It): - /* FALLTHROUGH */ - case (MDOC_Sm): + nchild = nbody->child; + while (NULL != nchild) { + if (MDOC_It == nchild->tok || MDOC_Sm == nchild->tok) { + nchild = nchild->next; continue; - default: - break; } - mdoc_nmsg(mdoc, n, MANDOCERR_SYNTCHILD); - return(0); + mdoc_nmsg(mdoc, nchild, MANDOCERR_CHILD); + + /* + * Move the node out of the Bl block. + * First, collect all required node pointers. + */ + + nblock = nbody->parent; + nprev = nblock->prev; + nparent = nblock->parent; + nnext = nchild->next; + + /* + * Unlink this child. + */ + + assert(NULL == nchild->prev); + if (0 == --nbody->nchild) { + nbody->child = NULL; + nbody->last = NULL; + assert(NULL == nnext); + } else { + nbody->child = nnext; + nnext->prev = NULL; + } + + /* + * Relink this child. + */ + + nchild->parent = nparent; + nchild->prev = nprev; + nchild->next = nblock; + + nblock->prev = nchild; + nparent->nchild++; + if (NULL == nprev) + nparent->child = nchild; + else + nprev->next = nchild; + + nchild = nnext; } return(1); @@ -1588,10 +1674,16 @@ ebool(struct mdoc *mdoc) assert(MDOC_TEXT == mdoc->last->child->type); - if (0 == strcmp(mdoc->last->child->string, "on")) + if (0 == strcmp(mdoc->last->child->string, "on")) { + if (MDOC_Sm == mdoc->last->tok) + mdoc->flags &= ~MDOC_SMOFF; return(1); - if (0 == strcmp(mdoc->last->child->string, "off")) + } + if (0 == strcmp(mdoc->last->child->string, "off")) { + if (MDOC_Sm == mdoc->last->tok) + mdoc->flags |= MDOC_SMOFF; return(1); + } mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL); return(1); @@ -1771,6 +1863,47 @@ post_rs(POST_ARGS) return(1); } +/* + * For some arguments of some macros, + * convert all breakable hyphens into ASCII_HYPH. + */ +static int +post_hyph(POST_ARGS) +{ + struct mdoc_node *n, *nch; + char *cp; + + n = mdoc->last; + switch (n->type) { + case (MDOC_HEAD): + if (MDOC_Sh == n->tok || MDOC_Ss == n->tok) + break; + return(1); + case (MDOC_BODY): + if (MDOC_D1 == n->tok || MDOC_Nd == n->tok) + break; + return(1); + case (MDOC_ELEM): + break; + default: + return(1); + } + + for (nch = n->child; nch; nch = nch->next) { + if (MDOC_TEXT != nch->type) + continue; + cp = nch->string; + if (3 > strnlen(cp, 3)) + continue; + while ('\0' != *(++cp)) + if ('-' == *cp && + isalpha((unsigned char)cp[-1]) && + isalpha((unsigned char)cp[1])) + *cp = ASCII_HYPH; + } + return(1); +} + static int post_ns(POST_ARGS) { @@ -1857,10 +1990,13 @@ post_sh_head(POST_ARGS) /* The SYNOPSIS gets special attention in other areas. */ - if (SEC_SYNOPSIS == sec) + if (SEC_SYNOPSIS == sec) { + roff_setreg(mdoc->roff, "nS", 1, '='); mdoc->flags |= MDOC_SYNOPSIS; - else + } else { + roff_setreg(mdoc->roff, "nS", 0, '='); mdoc->flags &= ~MDOC_SYNOPSIS; + } /* Mark our last section. */ @@ -1916,7 +2052,8 @@ post_sh_head(POST_ARGS) break; if (*mdoc->meta.msec == '9') break; - mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECMSEC); + mandoc_msg(MANDOCERR_SECMSEC, mdoc->parse, + mdoc->last->line, mdoc->last->pos, buf); break; default: break; @@ -1962,7 +2099,9 @@ pre_par(PRE_ARGS) * block: `Lp', `Pp', or non-compact `Bd' or `Bl'. */ - if (MDOC_Pp != mdoc->last->tok && MDOC_Lp != mdoc->last->tok) + if (MDOC_Pp != mdoc->last->tok && + MDOC_Lp != mdoc->last->tok && + MDOC_br != mdoc->last->tok) return(1); if (MDOC_Bl == n->tok && n->norm->Bl.comp) return(1); @@ -1977,6 +2116,32 @@ pre_par(PRE_ARGS) } static int +post_par(POST_ARGS) +{ + + if (MDOC_ELEM != mdoc->last->type && + MDOC_BLOCK != mdoc->last->type) + return(1); + + if (NULL == mdoc->last->prev) { + if (MDOC_Sh != mdoc->last->parent->tok && + MDOC_Ss != mdoc->last->parent->tok) + return(1); + } else { + if (MDOC_Pp != mdoc->last->prev->tok && + MDOC_Lp != mdoc->last->prev->tok && + (MDOC_br != mdoc->last->tok || + (MDOC_sp != mdoc->last->prev->tok && + MDOC_br != mdoc->last->prev->tok))) + return(1); + } + + mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR); + mdoc_node_delete(mdoc, mdoc->last); + return(1); +} + +static int pre_literal(PRE_ARGS) { @@ -2129,9 +2294,9 @@ post_dt(POST_ARGS) free(mdoc->meta.vol); mdoc->meta.vol = mandoc_strdup(cp); } else { - /* FIXME: warn about bad arch. */ cp = mdoc_a2arch(nn->string); if (NULL == cp) { + mdoc_nmsg(mdoc, nn, MANDOCERR_BADVOLARCH); free(mdoc->meta.vol); mdoc->meta.vol = mandoc_strdup(nn->string); } else @@ -2192,14 +2357,15 @@ post_os(POST_ARGS) n = mdoc->last; /* - * Set the operating system by way of the `Os' macro. Note that - * if an argument isn't provided and -DOSNAME="\"foo\"" is - * provided during compilation, this value will be used instead - * of filling in "sysname release" from uname(). + * Set the operating system by way of the `Os' macro. + * The order of precedence is: + * 1. the argument of the `Os' macro, unless empty + * 2. the -Ios=foo command line argument, if provided + * 3. -DOSNAME="\"foo\"", if provided during compilation + * 4. "sysname release" from uname(3) */ - if (mdoc->meta.os) - free(mdoc->meta.os); + free(mdoc->meta.os); buf[0] = '\0'; if (-1 == (c = concat(buf, n->child, BUFSIZ))) { @@ -2209,11 +2375,11 @@ post_os(POST_ARGS) assert(c); - /* XXX: yes, these can all be dynamically-adjusted buffers, but - * it's really not worth the extra hackery. - */ - if ('\0' == buf[0]) { + if (mdoc->defos) { + mdoc->meta.os = mandoc_strdup(mdoc->defos); + return(1); + } #ifdef OSNAME if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) { mdoc_nmsg(mdoc, n, MANDOCERR_MEM); diff --git a/usr/src/cmd/mandoc/msec.in b/usr/src/cmd/mandoc/msec.in index e4cf09df3b..0aee249bd7 100644 --- a/usr/src/cmd/mandoc/msec.in +++ b/usr/src/cmd/mandoc/msec.in @@ -14,231 +14,96 @@ */ LINE("1", "User Commands") -LINE("1B", "illumos/BSD Compatibility Package Commands") -LINE("1b", "illumos/BSD Compatibility Package Commands") +LINE("1B", "BSD Compatibility Package Commands") LINE("1C", "Communication Commands") -LINE("1c", "Communication Commands") -LINE("1F", "FMLI Commands") -LINE("1f", "FMLI Commands") -LINE("1G", "Graphics and CAD Commands") -LINE("1g", "Graphics and CAD Commands") LINE("1HAS", "User Commands") -LINE("1has", "User Commands") LINE("1M", "Maintenance Commands") -LINE("1m", "Maintenance Commands") LINE("1S", "illumos Specific Commands") -LINE("1s", "illumos Specific Commands") LINE("2", "System Calls") LINE("3", "Introduction to Library Functions") -LINE("3AIO", "Asynchronous I/O Library Functions") -LINE("3aio", "Asynchronous I/O Library Functions") +LINE("3BSDMALLOC", "BSD Memory Allocation Library") LINE("3BSM", "Security and Auditing Library Functions") -LINE("3bsm", "Security and Auditing Library Functions") LINE("3C", "Standard C Library Functions") -LINE("3c", "Standard C Library Functions") +LINE("3C++", "C++ Library Functions") LINE("3C_DB", "Threads Debugging Library Functions") -LINE("3C_db", "Threads Debugging Library Functions") LINE("3CFGADM", "Configuration Administration Library Functions") -LINE("3cfgadm", "Configuration Administration Library Functions") -LINE("3COMPPUTIL", "Communication Protocol Parser Utilities Library Functions") -LINE("3compputil", "Communication Protocol Parser Utilities Library Functions") +LINE("3COMMPUTIL", "Communication Protocol Parser Utilities Library Functions") LINE("3CONTRACT", "Contract Management Library Functions") -LINE("3contract", "Contract Management Library Functions") LINE("3CPC", "CPU Performance Counters Library Functions") -LINE("3cpc", "CPU Performance Counters Library Functions") LINE("3CURSES", "Curses Library Functions") -LINE("3curses", "Curses Library Functions") LINE("3DAT", "Direct Access Transport Library Functions") -LINE("3dat", "Direct Access Transport Library Functions") LINE("3DEVID", "Device ID Library Functions") -LINE("3devid", "Device ID Library Functions") LINE("3DEVINFO", "Device Information Library Functions") -LINE("3devinfo", "Device Information Library Functions") -LINE("3DL", "Dynamic Linking Library Functions") -LINE("3dl", "Dynamic Linking Library Functions") LINE("3DLPI", "Data Link Provider Interface Library Functions") -LINE("3dlpi", "Data Link Provider Interface Library Functions") -LINE("3DMI", "DMI Library Functions") -LINE("3dmi", "DMI Library Functions") LINE("3DNS_SD", "DNS Service Discovery Library Functions") -LINE("3dns_sd", "DNS Service Discovery Library Functions") LINE("3DOOR", "Door Library Functions") -LINE("3door", "Door Library Functions") LINE("3ELF", "ELF Library Functions") -LINE("3elf", "ELF Library Functions") LINE("3EXACCT", "Extended Accounting File Access Library Functions") -LINE("3exacct", "Extended Accounting File Access Library Functions") LINE("3EXT", "Extended Library Functions") -LINE("3ext", "Extended Library Functions") LINE("3FCOE", "FCoE Port Management Library Functions") -LINE("3fcoe", "FCoE Port Management Library Functions") LINE("3FSTYP", "File System Type Identification Library Functions") -LINE("3fstyp", "File System Type Identification Library Functions") LINE("3GEN", "String Pattern-Matching Library Functions") -LINE("3gen", "String Pattern-Matching Library Functions") LINE("3GSS", "Generic Security Services API Library Functions") -LINE("3gss", "Generic Security Services API Library Functions") LINE("3HEAD", "Headers") -LINE("3head", "Headers") LINE("3ISCSIT", "iSCSI Management Library Functions") -LINE("3iscsit", "iSCSI Management Library Functions") LINE("3KRB", "Kerberos Library Functions") -LINE("3krb", "Kerberos Library Functions") +LINE("3KRB5", "MIT Kerberos 5 Library Functions") LINE("3KSTAT", "Kernel Statistics Library Functions") -LINE("3kstat", "Kernel Statistics Library Functions") LINE("3KVM", "Kernel VM Library Functions") -LINE("3kvm", "Kernel VM Library Functions") LINE("3LDAP", "LDAP Library Functions") -LINE("3ldap", "LDAP Library Functions") LINE("3LGRP", "Locality Group Library Functions") -LINE("3lgrp", "Locality Group Library Functions") LINE("3LIB", "Interface Libraries") -LINE("3lib", "Interface Libraries") -LINE("3LIBUCB", "illumos/BSD Compatibility Interface Libraries") -LINE("3libucb", "illumos/BSD Compatibility Interface Libraries") LINE("3M", "Mathematical Library Functions") -LINE("3m", "Mathematical Library Functions") LINE("3MAIL", "User Mailbox Library Functions") -LINE("3mail", "User Mailbox Library Functions") LINE("3MALLOC", "Memory Allocation Library Functions") -LINE("3malloc", "Memory Allocation Library Functions") LINE("3MP", "Multiple Precision Library Functions") -LINE("3mp", "Multiple Precision Library Functions") LINE("3MPAPI", "Common Multipath Management Library Functions") -LINE("3mpapi", "Common Multipath Management Library Functions") LINE("3NSL", "Networking Services Library Functions") -LINE("3nsl", "Networking Services Library Functions") LINE("3NVPAIR", "Name-value Pair Library Functions") -LINE("3nvpair", "Name-value Pair Library Functions") LINE("3PAM", "PAM Library Functions") -LINE("3pam", "PAM Library Functions") LINE("3PAPI", "PAPI Library Functions") -LINE("3papi", "PAPI Library Functions") LINE("3PERL", "Perl Library Functions") -LINE("3perl", "Perl Library Functions") LINE("3PICL", "PICL Library Functions") -LINE("3picl", "PICL Library Functions") LINE("3PICLTREE", "PICL Plug-In Library Functions") -LINE("3picltree", "PICL Plug-In Library Functions") -LINE("3PLOT", "Graphics Interface Library Functions") -LINE("3plot", "Graphics Interface Library Functions") LINE("3POOL", "Pool Configuration Manipulation Library Functions") -LINE("3pool", "Pool Configuration Manipulation Library Functions") LINE("3PROC", "Process Control Library Functions") -LINE("3proc", "Process Control Library Functions") LINE("3PROJECT", "Project Database Access Library Functions") -LINE("3project", "Project Database Access Library Functions") LINE("3RAC", "Remote Asynchronous Calls Library Functions") -LINE("3rac", "Remote Asynchronous Calls Library Functions") LINE("3RESOLV", "Resolver Library Functions") -LINE("3resolv", "Resolver Library Functions") LINE("3RPC", "RPC Library Functions") -LINE("3rpc", "RPC Library Functions") LINE("3RSM", "Remote Shared Memory Library Functions") -LINE("3rsm", "Remote Shared Memory Library Functions") LINE("3RT", "Realtime Library Functions") -LINE("3rt", "Realtime Library Functions") LINE("3SASL", "Simple Authentication Security Layer Library Functions") -LINE("3sasl", "Simple Authentication Security Layer Library Functions") LINE("3SCF", "Service Configuration Facility Library Functions") -LINE("3scf", "Service Configuration Facility Library Functions") -LINE("3SCHED", "LWP Scheduling Library Functions") -LINE("3sched", "LWP Scheduling Library Functions") LINE("3SEC", "File Access Control Library Functions") -LINE("3sec", "File Access Control Library Functions") LINE("3SECDB", "Security Attributes Database Library Functions") -LINE("3secdb", "Security Attributes Database Library Functions") LINE("3SIP", "Session Initiation Protocol Library Functions") -LINE("3sip", "Session Initiation Protocol Library Functions") LINE("3SLP", "Service Location Protocol Library Functions") -LINE("3slp", "Service Location Protocol Library Functions") -LINE("3SNMP", "SNMP Library Functions") -LINE("3snmp", "SNMP Library Functions") LINE("3SOCKET", "Sockets Library Functions") -LINE("3socket", "Sockets Library Functions") LINE("3STMF", "SCSI Target Mode Framework Library Functions") -LINE("3stmf", "SCSI Target Mode Framework Library Functions") LINE("3SYSEVENT", "System Event Library Functions") -LINE("3sysevent", "System Event Library Functions") LINE("3TECLA", "Interactive Command-line Input Library Functions") -LINE("3tecla", "Interactive Command-line Input Library Functions") -LINE("3THR", "Threads Library Functions") -LINE("3thr", "Threads Library Functions") LINE("3TNF", "TNF Library Functions") -LINE("3tnf", "TNF Library Functions") LINE("3TSOL", "Trusted Extensions Library Functions") -LINE("3tsol", "Trusted Extensions Library Functions") -LINE("3UCB", "illumos/BSD Compatibility Library Functions") -LINE("3ucb", "illumos/BSD Compatibility Library Functions") LINE("3UUID", "Universally Unique Identifier Library Functions") -LINE("3uuid", "Universally Unique Identifier Library Functions") LINE("3VOLMGT", "Volume Management Library Functions") -LINE("3volmgt", "Volume Management Library Functions") LINE("3XCURSES", "X/Open Curses Library Functions") -LINE("3xcurses", "X/Open Curses Library Functions") -LINE("3XFN", "XFN Interface Library Functions") -LINE("3xfn", "XFN Interface Library Functions") LINE("3XNET", "X/Open Networking Services Library Functions") -LINE("3xnet", "X/Open Networking Services Library Functions") -LINE("3B", "illumos/BSD Compatibility Library Functions") -LINE("3b", "illumos/BSD Compatibility Library Functions") -LINE("3E", "C Library Functions") -LINE("3e", "C Library Functions") LINE("3F", "Fortran Library Routines") -LINE("3f", "Fortran Library Routines") -LINE("3G", "C Library Functions") -LINE("3g", "C Library Functions") -LINE("3K", "Kernel VM Library Functions") -LINE("3k", "Kernel VM Library Functions") -LINE("3L", "Lightweight Processes Library") -LINE("3l", "Lightweight Processes Library") -LINE("3N", "Network Functions") -LINE("3n", "Network Functions") -LINE("3R", "Realtime Library") -LINE("3r", "Realtime Library") -LINE("3S", "Standard I/O Functions") -LINE("3s", "Standard I/O Functions") -LINE("3T", "Threads Library") -LINE("3t", "Threads Library") -LINE("3W", "C Library Functions") -LINE("3w", "C Library Functions") LINE("3X", "Miscellaneous Library Functions") -LINE("3x", "Miscellaneous Library Functions") -LINE("3XC", "X/Open Curses Library Functions") -LINE("3xc", "X/Open Curses Library Functions") -LINE("3XN", "X/Open Networking Services Library Functions") -LINE("3xn", "X/Open Networking Services Library Functions") LINE("4", "File Formats") -LINE("4B", "illumos/BSD Compatibility Package File Formats") -LINE("4b", "illumos/BSD Compatibility Package File Formats") LINE("5", "Standards, Environments, and Macros") LINE("6", "Games and Demos") LINE("7", "Device and Network Interfaces") -LINE("7B", "illumos/BSD Compatibility Special Files") -LINE("7b", "illumos/BSD Compatibility Special Files") LINE("7D", "Devices") -LINE("7d", "Devices") LINE("7FS", "File Systems") -LINE("7fs", "File Systems") LINE("7I", "Ioctl Requests") -LINE("7i", "Ioctl Requests") LINE("7IPP", "IP Quality of Service Modules") -LINE("7ipp", "IP Quality of Service Modules") LINE("7M", "STREAMS Modules") -LINE("7m", "STREAMS Modules") LINE("7P", "Protocols") -LINE("7p", "Protocols") LINE("8", "Maintenance Procedures") -LINE("8C", "Maintenance Procedures") -LINE("8c", "Maintenance Procedures") -LINE("8S", "Maintenance Procedures") -LINE("8s", "Maintenance Procedures") LINE("9", "Device Driver Interfaces") LINE("9E", "Driver Entry Points") -LINE("9e", "Driver Entry Points") LINE("9F", "Kernel Functions for Drivers") -LINE("9f", "Kernel Functions for Drivers") LINE("9P", "Kernel Properties for Drivers") -LINE("9p", "Kernel Properties for Drivers") LINE("9S", "Data Structures for Drivers") -LINE("9s", "Data Structures for Drivers") diff --git a/usr/src/cmd/mandoc/out.c b/usr/src/cmd/mandoc/out.c index 8dbd68ac11..c931664977 100644 --- a/usr/src/cmd/mandoc/out.c +++ b/usr/src/cmd/mandoc/out.c @@ -1,4 +1,4 @@ -/* $Id: out.c,v 1.43 2011/09/20 23:05:49 schwarze Exp $ */ +/* $Id: out.c,v 1.46 2013/10/05 20:30:05 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> @@ -32,11 +32,11 @@ #include "out.h" static void tblcalc_data(struct rofftbl *, struct roffcol *, - const struct tbl *, const struct tbl_dat *); + const struct tbl_opts *, const struct tbl_dat *); static void tblcalc_literal(struct rofftbl *, struct roffcol *, const struct tbl_dat *); static void tblcalc_number(struct rofftbl *, struct roffcol *, - const struct tbl *, const struct tbl_dat *); + const struct tbl_opts *, const struct tbl_dat *); /* * Convert a `scaling unit' to a consistent form, or fail. Scaling @@ -142,7 +142,6 @@ void tblcalc(struct rofftbl *tbl, const struct tbl_span *sp) { const struct tbl_dat *dp; - const struct tbl_head *hp; struct roffcol *col; int spans; @@ -154,9 +153,7 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp) assert(NULL == tbl->cols); tbl->cols = mandoc_calloc - ((size_t)sp->tbl->cols, sizeof(struct roffcol)); - - hp = sp->head; + ((size_t)sp->opts->cols, sizeof(struct roffcol)); for ( ; sp; sp = sp->next) { if (TBL_SPAN_DATA != sp->pos) @@ -175,33 +172,14 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp) continue; assert(dp->layout); col = &tbl->cols[dp->layout->head->ident]; - tblcalc_data(tbl, col, sp->tbl, dp); - } - } - - /* - * Calculate width of the spanners. These get one space for a - * vertical line, two for a double-vertical line. - */ - - for ( ; hp; hp = hp->next) { - col = &tbl->cols[hp->ident]; - switch (hp->pos) { - case (TBL_HEAD_VERT): - col->width = (*tbl->len)(1, tbl->arg); - break; - case (TBL_HEAD_DVERT): - col->width = (*tbl->len)(2, tbl->arg); - break; - default: - break; + tblcalc_data(tbl, col, sp->opts, dp); } } } static void tblcalc_data(struct rofftbl *tbl, struct roffcol *col, - const struct tbl *tp, const struct tbl_dat *dp) + const struct tbl_opts *opts, const struct tbl_dat *dp) { size_t sz; @@ -225,7 +203,7 @@ tblcalc_data(struct rofftbl *tbl, struct roffcol *col, tblcalc_literal(tbl, col, dp); break; case (TBL_CELL_NUMBER): - tblcalc_number(tbl, col, tp, dp); + tblcalc_number(tbl, col, opts, dp); break; case (TBL_CELL_DOWN): break; @@ -251,7 +229,7 @@ tblcalc_literal(struct rofftbl *tbl, struct roffcol *col, static void tblcalc_number(struct rofftbl *tbl, struct roffcol *col, - const struct tbl *tp, const struct tbl_dat *dp) + const struct tbl_opts *opts, const struct tbl_dat *dp) { int i; size_t sz, psz, ssz, d; @@ -273,12 +251,12 @@ tblcalc_number(struct rofftbl *tbl, struct roffcol *col, /* FIXME: TBL_DATA_HORIZ et al.? */ - buf[0] = tp->decimal; + buf[0] = opts->decimal; buf[1] = '\0'; psz = (*tbl->slen)(buf, tbl->arg); - if (NULL != (cp = strrchr(str, tp->decimal))) { + if (NULL != (cp = strrchr(str, opts->decimal))) { buf[1] = '\0'; for (ssz = 0, i = 0; cp != &str[i]; i++) { buf[0] = str[i]; diff --git a/usr/src/cmd/mandoc/preconv.c b/usr/src/cmd/mandoc/preconv.c index a0b2d6415e..7595887dd2 100644 --- a/usr/src/cmd/mandoc/preconv.c +++ b/usr/src/cmd/mandoc/preconv.c @@ -1,4 +1,4 @@ -/* $Id: preconv.c,v 1.5 2011/07/24 18:15:14 kristaps Exp $ */ +/* $Id: preconv.c,v 1.6 2013/06/02 03:52:21 schwarze Exp $ */ /* * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -32,13 +32,9 @@ /* * The read_whole_file() and resize_buf() functions are copied from - * read.c, including all dependency code (MAP_FILE, etc.). + * read.c, including all dependency code. */ -#ifndef MAP_FILE -#define MAP_FILE 0 -#endif - enum enc { ENC_UTF_8, /* UTF-8 */ ENC_US_ASCII, /* US-ASCII */ @@ -271,8 +267,7 @@ read_whole_file(const char *f, int fd, if (S_ISREG(st.st_mode)) { *with_mmap = 1; fb->sz = (size_t)st.st_size; - fb->buf = mmap(NULL, fb->sz, PROT_READ, - MAP_FILE|MAP_SHARED, fd, 0); + fb->buf = mmap(NULL, fb->sz, PROT_READ, MAP_SHARED, fd, 0); if (fb->buf != MAP_FAILED) return(1); } diff --git a/usr/src/cmd/mandoc/predefs.in b/usr/src/cmd/mandoc/predefs.in index 70074bb617..d1690e3568 100644 --- a/usr/src/cmd/mandoc/predefs.in +++ b/usr/src/cmd/mandoc/predefs.in @@ -1,4 +1,4 @@ -/* $Id: predefs.in,v 1.3 2011/07/31 11:36:49 schwarze Exp $ */ +/* $Id: predefs.in,v 1.4 2012/07/18 10:39:19 schwarze Exp $ */ /* * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -26,7 +26,7 @@ */ PREDEF("Am", "&") -PREDEF("Ba", "|") +PREDEF("Ba", "\\fR|\\fP") PREDEF("Ge", "\\(>=") PREDEF("Gt", ">") PREDEF("If", "infinity") diff --git a/usr/src/cmd/mandoc/read.c b/usr/src/cmd/mandoc/read.c index 5b14e357d2..511ba7dc46 100644 --- a/usr/src/cmd/mandoc/read.c +++ b/usr/src/cmd/mandoc/read.c @@ -1,7 +1,7 @@ -/* $Id: read.c,v 1.28 2012/02/16 20:51:31 joerg Exp $ */ +/* $Id: read.c,v 1.39 2013/09/16 00:25:07 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -40,10 +40,6 @@ #include "man.h" #include "main.h" -#ifndef MAP_FILE -#define MAP_FILE 0 -#endif - #define REPARSE_LIMIT 1000 struct buf { @@ -66,14 +62,16 @@ struct mparse { void *arg; /* argument to mmsg */ const char *file; struct buf *secondary; + char *defos; /* default operating system */ }; 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 int read_whole_file(const char *, int, struct buf *, int *); static void mparse_end(struct mparse *); +static void mparse_parse_buffer(struct mparse *, struct buf, + const char *); static const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = { MANDOCERR_OK, @@ -94,6 +92,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { "no title in document", "document title should be all caps", "unknown manual section", + "unknown manual volume or arch", "date missing, using today's date", "cannot parse date, using it verbatim", "prologue macros out of order", @@ -105,14 +104,14 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { ".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", + "section header suited to sections 2, 3, and 9 only", /* related to macros and nesting */ "skipping obsolete macro", "skipping paragraph macro", + "moving paragraph macro out of list", "skipping no-space macro", "blocks badly nested", "child violates parent syntax", @@ -173,10 +172,12 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { "input stack limit exceeded, infinite loop?", "skipping bad character", "escaped character not allowed in a name", + "manual name not yet set", "skipping text before the first section header", "skipping unknown macro", "NOT IMPLEMENTED, please use groff: skipping request", "argument count wrong", + "skipping column outside column list", "skipping end of block that is not open", "missing end of block", "scope open on exit", @@ -184,6 +185,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { "macro requires line argument(s)", "macro requires body argument(s)", "macro requires argument(s)", + "request requires a numeric argument", "missing list type", "line argument(s) will be lost", "body argument(s) will be lost", @@ -247,7 +249,8 @@ pset(const char *buf, int pos, struct mparse *curp) switch (curp->inttype) { case (MPARSE_MDOC): if (NULL == curp->pmdoc) - curp->pmdoc = mdoc_alloc(curp->roff, curp); + curp->pmdoc = mdoc_alloc(curp->roff, curp, + curp->defos); assert(curp->pmdoc); curp->mdoc = curp->pmdoc; return; @@ -263,7 +266,8 @@ pset(const char *buf, int pos, struct mparse *curp) if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3)) { if (NULL == curp->pmdoc) - curp->pmdoc = mdoc_alloc(curp->roff, curp); + curp->pmdoc = mdoc_alloc(curp->roff, curp, + curp->defos); assert(curp->pmdoc); curp->mdoc = curp->pmdoc; return; @@ -322,6 +326,15 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start) break; } + /* + * Make sure we have space for at least + * one backslash and one other character + * and the trailing NUL byte. + */ + + if (pos + 2 >= (int)ln.sz) + resize_buf(&ln, 256); + /* * Warn about bogus characters. If you're using * non-ASCII encoding, you're screwing your @@ -338,8 +351,6 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start) mandoc_msg(MANDOCERR_BADCHAR, curp, curp->line, pos, NULL); i++; - if (pos >= (int)ln.sz) - resize_buf(&ln, 256); ln.buf[pos++] = '?'; continue; } @@ -347,8 +358,6 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start) /* 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; } @@ -390,10 +399,20 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start) break; } - /* Some other escape sequence, copy & cont. */ + /* Catch escaped bogus characters. */ - if (pos + 1 >= (int)ln.sz) - resize_buf(&ln, 256); + c = (unsigned char) blk.buf[i+1]; + + if ( ! (isascii(c) && + (isgraph(c) || isblank(c)))) { + mandoc_msg(MANDOCERR_BADCHAR, curp, + curp->line, pos, NULL); + i += 2; + ln.buf[pos++] = '?'; + continue; + } + + /* Some other escape sequence, copy & cont. */ ln.buf[pos++] = blk.buf[i++]; ln.buf[pos++] = blk.buf[i++]; @@ -469,7 +488,7 @@ rerun: */ if (curp->secondary) curp->secondary->sz -= pos + 1; - mparse_readfd_r(curp, -1, ln.buf + of, 1); + mparse_readfd(curp, -1, ln.buf + of); if (MANDOCLEVEL_FATAL <= curp->file_status) break; pos = 0; @@ -575,8 +594,7 @@ read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap) } *with_mmap = 1; fb->sz = (size_t)st.st_size; - fb->buf = mmap(NULL, fb->sz, PROT_READ, - MAP_FILE|MAP_SHARED, fd, 0); + fb->buf = mmap(NULL, fb->sz, PROT_READ, MAP_SHARED, fd, 0); if (fb->buf != MAP_FAILED) return(1); } @@ -643,19 +661,25 @@ mparse_end(struct mparse *curp) } static void -mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file, - int re) +mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file) { const char *svfile; + static int recursion_depth; + + if (64 < recursion_depth) { + mandoc_msg(MANDOCERR_ROFFLOOP, curp, curp->line, 0, NULL); + return; + } /* Line number is per-file. */ svfile = curp->file; curp->file = file; curp->line = 1; + recursion_depth++; mparse_buf_r(curp, blk, 1); - if (0 == re && MANDOCLEVEL_FATAL > curp->file_status) + if (0 == --recursion_depth && MANDOCLEVEL_FATAL > curp->file_status) mparse_end(curp); curp->file = svfile; @@ -670,12 +694,12 @@ mparse_readmem(struct mparse *curp, const void *buf, size_t len, blk.buf = UNCONST(buf); blk.sz = len; - mparse_parse_buffer(curp, blk, file, 0); + mparse_parse_buffer(curp, blk, file); return(curp->file_status); } -static void -mparse_readfd_r(struct mparse *curp, int fd, const char *file, int re) +enum mandoclevel +mparse_readfd(struct mparse *curp, int fd, const char *file) { struct buf blk; int with_mmap; @@ -684,7 +708,7 @@ mparse_readfd_r(struct mparse *curp, int fd, const char *file, int re) if (-1 == (fd = open(file, O_RDONLY, 0))) { perror(file); curp->file_status = MANDOCLEVEL_SYSERR; - return; + goto out; } /* * Run for each opened file; may be called more than once for @@ -695,10 +719,10 @@ mparse_readfd_r(struct mparse *curp, int fd, const char *file, int re) if ( ! read_whole_file(file, fd, &blk, &with_mmap)) { curp->file_status = MANDOCLEVEL_SYSERR; - return; + goto out; } - mparse_parse_buffer(curp, blk, file, re); + mparse_parse_buffer(curp, blk, file); #ifdef HAVE_MMAP if (with_mmap) @@ -709,18 +733,13 @@ mparse_readfd_r(struct mparse *curp, int fd, const char *file, int re) if (STDIN_FILENO != fd && -1 == close(fd)) perror(file); -} - -enum mandoclevel -mparse_readfd(struct mparse *curp, int fd, const char *file) -{ - - mparse_readfd_r(curp, fd, file, 0); +out: return(curp->file_status); } struct mparse * -mparse_alloc(enum mparset inttype, enum mandoclevel wlevel, mandocmsg mmsg, void *arg) +mparse_alloc(enum mparset inttype, enum mandoclevel wlevel, + mandocmsg mmsg, void *arg, char *defos) { struct mparse *curp; @@ -732,8 +751,9 @@ mparse_alloc(enum mparset inttype, enum mandoclevel wlevel, mandocmsg mmsg, void curp->mmsg = mmsg; curp->arg = arg; curp->inttype = inttype; + curp->defos = defos; - curp->roff = roff_alloc(curp); + curp->roff = roff_alloc(inttype, curp); return(curp); } diff --git a/usr/src/cmd/mandoc/roff.c b/usr/src/cmd/mandoc/roff.c index b479cc298c..42240d21fe 100644 --- a/usr/src/cmd/mandoc/roff.c +++ b/usr/src/cmd/mandoc/roff.c @@ -1,7 +1,7 @@ -/* $Id: roff.c,v 1.172 2011/10/24 21:41:45 schwarze Exp $ */ +/* $Id: roff.c,v 1.189 2013/12/30 18:44:06 schwarze Exp $ */ /* - * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -21,6 +21,7 @@ #include <assert.h> #include <ctype.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> @@ -39,11 +40,14 @@ enum rofft { ROFF_am, ROFF_ami, ROFF_am1, + ROFF_cc, ROFF_de, ROFF_dei, ROFF_de1, ROFF_ds, ROFF_el, + ROFF_fam, + ROFF_hw, ROFF_hy, ROFF_ie, ROFF_if, @@ -58,6 +62,8 @@ enum rofft { ROFF_so, ROFF_ta, ROFF_tr, + ROFF_Dd, + ROFF_TH, ROFF_TS, ROFF_TE, ROFF_T_, @@ -70,18 +76,8 @@ enum rofft { }; enum roffrule { - ROFFRULE_ALLOW, - ROFFRULE_DENY -}; - -/* - * A single register entity. If "set" is zero, the value of the - * register should be the default one, which is per-register. - * Registers are assumed to be unsigned ints for now. - */ -struct reg { - int set; /* whether set or not */ - unsigned int u; /* unsigned integer */ + ROFFRULE_DENY, + ROFFRULE_ALLOW }; /* @@ -101,12 +97,23 @@ struct roffkv { struct roffkv *next; /* next in list */ }; +/* + * A single number register as part of a singly-linked list. + */ +struct roffreg { + struct roffstr key; + int val; + struct roffreg *next; +}; + struct roff { + enum mparset parsetype; /* requested parse type */ struct mparse *parse; /* parse point */ struct roffnode *last; /* leaf of stack */ enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */ + char control; /* control character */ int rstackpos; /* position in rstack */ - struct reg regs[REG__MAX]; + struct roffreg *regtab; /* number registers */ struct roffkv *strtab; /* user-defined strings & macros */ struct roffkv *xmbtab; /* multi-byte trans table (`tr') */ struct roffstr *xtab; /* single-byte trans table (`tr') */ @@ -169,6 +176,7 @@ static enum rofferr roff_block(ROFF_ARGS); static enum rofferr roff_block_text(ROFF_ARGS); static enum rofferr roff_block_sub(ROFF_ARGS); static enum rofferr roff_cblock(ROFF_ARGS); +static enum rofferr roff_cc(ROFF_ARGS); static enum rofferr roff_ccond(ROFF_ARGS); static enum rofferr roff_cond(ROFF_ARGS); static enum rofferr roff_cond_text(ROFF_ARGS); @@ -176,16 +184,22 @@ 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_free1(struct roff *); +static void roff_freereg(struct roffreg *); static void roff_freestr(struct roffkv *); static char *roff_getname(struct roff *, char **, int, int); +static int roff_getnum(const char *, int *, int *); +static int roff_getop(const char *, int *, char *); +static int roff_getregn(const struct roff *, + const char *, size_t); static const char *roff_getstrn(const struct roff *, const char *, size_t); +static enum rofferr roff_it(ROFF_ARGS); static enum rofferr roff_line_ignore(ROFF_ARGS); static enum rofferr roff_nr(ROFF_ARGS); static void roff_openeqn(struct roff *, const char *, int, int, const char *); static enum rofft roff_parse(struct roff *, const char *, int *); -static enum rofferr roff_parsetext(char *); +static enum rofferr roff_parsetext(char **, size_t *, int, int *); static enum rofferr roff_res(struct roff *, char **, size_t *, int, int); static enum rofferr roff_rm(ROFF_ARGS); @@ -195,6 +209,8 @@ static void roff_setstrn(struct roffkv **, const char *, size_t, const char *, size_t, int); static enum rofferr roff_so(ROFF_ARGS); static enum rofferr roff_tr(ROFF_ARGS); +static enum rofferr roff_Dd(ROFF_ARGS); +static enum rofferr roff_TH(ROFF_ARGS); static enum rofferr roff_TE(ROFF_ARGS); static enum rofferr roff_TS(ROFF_ARGS); static enum rofferr roff_EQ(ROFF_ARGS); @@ -215,16 +231,19 @@ static struct roffmac roffs[ROFF_MAX] = { { "am", roff_block, roff_block_text, roff_block_sub, 0, NULL }, { "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL }, { "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL }, + { "cc", roff_cc, NULL, NULL, 0, NULL }, { "de", roff_block, roff_block_text, roff_block_sub, 0, NULL }, { "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL }, { "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL }, { "ds", roff_ds, NULL, NULL, 0, NULL }, { "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL }, + { "fam", roff_line_ignore, NULL, NULL, 0, NULL }, + { "hw", roff_line_ignore, NULL, NULL, 0, NULL }, { "hy", roff_line_ignore, NULL, NULL, 0, NULL }, { "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 }, + { "it", roff_it, 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 }, @@ -234,6 +253,8 @@ static struct roffmac roffs[ROFF_MAX] = { { "so", roff_so, NULL, NULL, 0, NULL }, { "ta", roff_line_ignore, NULL, NULL, 0, NULL }, { "tr", roff_tr, NULL, NULL, 0, NULL }, + { "Dd", roff_Dd, NULL, NULL, 0, NULL }, + { "TH", roff_TH, 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 }, @@ -244,6 +265,37 @@ static struct roffmac roffs[ROFF_MAX] = { { NULL, roff_userdef, NULL, NULL, 0, NULL }, }; +const char *const __mdoc_reserved[] = { + "Ac", "Ad", "An", "Ao", "Ap", "Aq", "Ar", "At", + "Bc", "Bd", "Bf", "Bk", "Bl", "Bo", "Bq", + "Brc", "Bro", "Brq", "Bsx", "Bt", "Bx", + "Cd", "Cm", "Db", "Dc", "Dd", "Dl", "Do", "Dq", + "Ds", "Dt", "Dv", "Dx", "D1", + "Ec", "Ed", "Ef", "Ek", "El", "Em", "em", + "En", "Eo", "Eq", "Er", "Es", "Ev", "Ex", + "Fa", "Fc", "Fd", "Fl", "Fn", "Fo", "Fr", "Ft", "Fx", + "Hf", "Ic", "In", "It", "Lb", "Li", "Lk", "Lp", "LP", + "Me", "Ms", "Mt", "Nd", "Nm", "No", "Ns", "Nx", + "Oc", "Oo", "Op", "Os", "Ot", "Ox", + "Pa", "Pc", "Pf", "Po", "Pp", "PP", "pp", "Pq", + "Qc", "Ql", "Qo", "Qq", "Or", "Rd", "Re", "Rs", "Rv", + "Sc", "Sf", "Sh", "SH", "Sm", "So", "Sq", + "Ss", "St", "Sx", "Sy", + "Ta", "Tn", "Ud", "Ux", "Va", "Vt", "Xc", "Xo", "Xr", + "%A", "%B", "%D", "%I", "%J", "%N", "%O", + "%P", "%Q", "%R", "%T", "%U", "%V", + NULL +}; + +const char *const __man_reserved[] = { + "AT", "B", "BI", "BR", "BT", "DE", "DS", "DT", + "EE", "EN", "EQ", "EX", "HF", "HP", "I", "IB", "IP", "IR", + "LP", "ME", "MT", "OP", "P", "PD", "PP", "PT", + "R", "RB", "RE", "RI", "RS", "SB", "SH", "SM", "SS", "SY", + "TE", "TH", "TP", "TQ", "TS", "T&", "UC", "UE", "UR", "YS", + NULL +}; + /* Array of injected predefined strings. */ #define PREDEFS_MAX 38 static const struct predef predefs[PREDEFS_MAX] = { @@ -253,6 +305,9 @@ static const struct predef predefs[PREDEFS_MAX] = { /* See roffhash_find() */ #define ROFF_HASH(p) (p[0] - ASCII_LO) +static int roffit_lines; /* number of lines to delay */ +static char *roffit_macro; /* nil-terminated macro line */ + static void roffhash_init(void) { @@ -351,13 +406,13 @@ roffnode_push(struct roff *r, enum rofft tok, const char *name, static void roff_free1(struct roff *r) { - struct tbl_node *t; + struct tbl_node *tbl; struct eqn_node *e; int i; - while (NULL != (t = r->first_tbl)) { - r->first_tbl = t->next; - tbl_free(t); + while (NULL != (tbl = r->first_tbl)) { + r->first_tbl = tbl->next; + tbl_free(tbl); } r->first_tbl = r->last_tbl = r->tbl = NULL; @@ -377,6 +432,10 @@ roff_free1(struct roff *r) r->strtab = r->xmbtab = NULL; + roff_freereg(r->regtab); + + r->regtab = NULL; + if (r->xtab) for (i = 0; i < 128; i++) free(r->xtab[i].p); @@ -392,7 +451,7 @@ roff_reset(struct roff *r) roff_free1(r); - memset(&r->regs, 0, sizeof(struct reg) * REG__MAX); + r->control = 0; for (i = 0; i < PREDEFS_MAX; i++) roff_setstr(r, predefs[i].name, predefs[i].str, 0); @@ -409,12 +468,13 @@ roff_free(struct roff *r) struct roff * -roff_alloc(struct mparse *parse) +roff_alloc(enum mparset type, struct mparse *parse) { struct roff *r; int i; r = mandoc_calloc(1, sizeof(struct roff)); + r->parsetype = type; r->parse = parse; r->rstackpos = -1; @@ -427,22 +487,23 @@ roff_alloc(struct mparse *parse) } /* - * Pre-filter each and every line for reserved words (one beginning with - * `\*', e.g., `\*(ab'). These must be handled before the actual line - * is processed. - * This also checks the syntax of regular escapes. + * In the current line, expand user-defined strings ("\*") + * and references to number registers ("\n"). + * Also check the syntax of other escape sequences. */ static enum rofferr roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos) { - enum mandoc_esc esc; + char ubuf[12]; /* buffer to print the number */ const char *stesc; /* start of an escape sequence ('\\') */ const char *stnam; /* start of the name, after "[(*" */ const char *cp; /* end of the name, e.g. before ']' */ const char *res; /* the string to be substituted */ - int i, maxl, expand_count; - size_t nsz; - char *n; + char *nbuf; /* new buffer to copy bufp to */ + size_t nsz; /* size of the new buffer */ + size_t maxl; /* expected length of the escape name */ + size_t naml; /* actual length of the escape name */ + int expand_count; /* to avoid infinite loops */ expand_count = 0; @@ -452,7 +513,7 @@ again: stesc = cp++; /* - * The second character must be an asterisk. + * The second character must be an asterisk or an n. * If it isn't, skip it anyway: It is escaped, * so it can't start another escape sequence. */ @@ -460,12 +521,16 @@ again: if ('\0' == *cp) return(ROFF_CONT); - if ('*' != *cp) { - res = cp; - esc = mandoc_escape(&cp, NULL, NULL); - if (ESCAPE_ERROR != esc) + switch (*cp) { + case ('*'): + res = NULL; + break; + case ('n'): + res = ubuf; + break; + default: + if (ESCAPE_ERROR != mandoc_escape(&cp, NULL, NULL)) continue; - cp = res; mandoc_msg (MANDOCERR_BADESCAPE, r->parse, ln, (int)(stesc - *bufp), NULL); @@ -476,7 +541,7 @@ again: /* * The third character decides the length - * of the name of the string. + * of the name of the string or register. * Save a pointer to the name. */ @@ -499,7 +564,7 @@ again: /* Advance to the end of the name. */ - for (i = 0; 0 == maxl || i < maxl; i++, cp++) { + for (naml = 0; 0 == maxl || naml < maxl; naml++, cp++) { if ('\0' == *cp) { mandoc_msg (MANDOCERR_BADESCAPE, @@ -516,7 +581,11 @@ again: * undefined, resume searching for escapes. */ - res = roff_getstrn(r, stnam, (size_t)i); + if (NULL == res) + res = roff_getstrn(r, stnam, naml); + else + snprintf(ubuf, sizeof(ubuf), "%d", + roff_getregn(r, stnam, naml)); if (NULL == res) { mandoc_msg @@ -530,15 +599,15 @@ again: pos = stesc - *bufp; nsz = *szp + strlen(res) + 1; - n = mandoc_malloc(nsz); + nbuf = mandoc_malloc(nsz); - strlcpy(n, *bufp, (size_t)(stesc - *bufp + 1)); - strlcat(n, res, nsz); - strlcat(n, cp + (maxl ? 0 : 1), nsz); + strlcpy(nbuf, *bufp, (size_t)(stesc - *bufp + 1)); + strlcat(nbuf, res, nsz); + strlcat(nbuf, cp + (maxl ? 0 : 1), nsz); free(*bufp); - *bufp = n; + *bufp = nbuf; *szp = nsz; if (EXPAND_LIMIT >= ++expand_count) @@ -552,16 +621,20 @@ again: } /* - * Process text streams: convert all breakable hyphens into ASCII_HYPH. + * Process text streams: + * Convert all breakable hyphens into ASCII_HYPH. + * Decrement and spring input line trap. */ static enum rofferr -roff_parsetext(char *p) +roff_parsetext(char **bufp, size_t *szp, int pos, int *offs) { size_t sz; const char *start; + char *p; + int isz; enum mandoc_esc esc; - start = p; + start = p = *bufp + pos; while ('\0' != *p) { sz = strcspn(p, "-\\"); @@ -573,8 +646,7 @@ roff_parsetext(char *p) if ('\\' == *p) { /* Skip over escapes. */ p++; - esc = mandoc_escape - ((const char **)&p, NULL, NULL); + esc = mandoc_escape((const char **)&p, NULL, NULL); if (ESCAPE_ERROR == esc) break; continue; @@ -589,6 +661,22 @@ roff_parsetext(char *p) p++; } + /* Spring the input line trap. */ + if (1 == roffit_lines) { + isz = asprintf(&p, "%s\n.%s", *bufp, roffit_macro); + if (-1 == isz) { + perror(NULL); + exit((int)MANDOCLEVEL_SYSERR); + } + free(*bufp); + *bufp = p; + *szp = isz + 1; + *offs = 0; + free(roffit_macro); + roffit_lines = 0; + return(ROFF_REPARSE); + } else if (1 < roffit_lines) + --roffit_lines; return(ROFF_CONT); } @@ -611,7 +699,7 @@ roff_parseln(struct roff *r, int ln, char **bufp, assert(ROFF_CONT == e); ppos = pos; - ctl = mandoc_getcontrol(*bufp, &pos); + ctl = roff_getcontrol(r, *bufp, &pos); /* * First, if a scope is open and we're not a macro, pass the @@ -629,19 +717,14 @@ roff_parseln(struct roff *r, int ln, char **bufp, assert(ROFF_IGN == e || ROFF_CONT == e); if (ROFF_CONT != e) return(e); - if (r->eqn) - return(eqn_read(&r->eqn, ln, *bufp, pos, offs)); - if (r->tbl) - return(tbl_read(r->tbl, ln, *bufp, pos)); - return(roff_parsetext(*bufp + pos)); - } else if ( ! ctl) { - if (r->eqn) - return(eqn_read(&r->eqn, ln, *bufp, pos, offs)); + } + if (r->eqn) + return(eqn_read(&r->eqn, ln, *bufp, ppos, offs)); + if ( ! ctl) { if (r->tbl) return(tbl_read(r->tbl, ln, *bufp, pos)); - return(roff_parsetext(*bufp + pos)); - } else if (r->eqn) - return(eqn_read(&r->eqn, ln, *bufp, ppos, offs)); + return(roff_parsetext(bufp, szp, pos, offs)); + } /* * If a scope is open, go to the child handler for that macro, @@ -778,7 +861,7 @@ roffnode_cleanscope(struct roff *r) { while (r->last) { - if (--r->last->endspan < 0) + if (--r->last->endspan != 0) break; roffnode_pop(r); } @@ -984,57 +1067,45 @@ roff_cond_sub(ROFF_ARGS) rr = r->last->rule; roffnode_cleanscope(r); + t = roff_parse(r, *bufp, &pos); /* - * If the macro is unknown, first check if it contains a closing - * delimiter `\}'. If it does, close out our scope and return - * the currently-scoped rule (ignore or continue). Else, drop - * into the currently-scoped rule. + * Fully handle known macros when they are structurally + * required or when the conditional evaluated to true. */ - if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos))) { - ep = &(*bufp)[pos]; - for ( ; NULL != (ep = strchr(ep, '\\')); ep++) { - ep++; - if ('}' != *ep) - continue; - - /* - * Make the \} go away. - * This is a little haphazard, as it's not quite - * clear how nroff does this. - * If we're at the end of line, then just chop - * off the \} and resize the buffer. - * If we aren't, then conver it to spaces. - */ + if ((ROFF_MAX != t) && + (ROFF_ccond == t || ROFFRULE_ALLOW == rr || + ROFFMAC_STRUCT & roffs[t].flags)) { + assert(roffs[t].proc); + return((*roffs[t].proc)(r, t, bufp, szp, + ln, ppos, pos, offs)); + } - if ('\0' == *(ep + 1)) { - *--ep = '\0'; - *szp -= 2; - } else - *(ep - 1) = *ep = ' '; + /* Always check for the closing delimiter `\}'. */ - roff_ccond(r, ROFF_ccond, bufp, szp, - ln, pos, pos + 2, offs); - break; - } - return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); - } + ep = &(*bufp)[pos]; + while (NULL != (ep = strchr(ep, '\\'))) { + if ('}' != *(++ep)) + continue; - /* - * A denied conditional must evaluate its children if and only - * if they're either structurally required (such as loops and - * conditionals) or a closing macro. - */ + /* + * If we're at the end of line, then just chop + * off the \} and resize the buffer. + * If we aren't, then convert it to spaces. + */ - if (ROFFRULE_DENY == rr) - if ( ! (ROFFMAC_STRUCT & roffs[t].flags)) - if (ROFF_ccond != t) - return(ROFF_IGN); + if ('\0' == *(ep + 1)) { + *--ep = '\0'; + *szp -= 2; + } else + *(ep - 1) = *ep = ' '; - assert(roffs[t].proc); - return((*roffs[t].proc)(r, t, bufp, szp, - ln, ppos, pos, offs)); + roff_ccond(r, ROFF_ccond, bufp, szp, + ln, pos, pos + 2, offs); + break; + } + return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); } /* ARGSUSED */ @@ -1059,9 +1130,61 @@ roff_cond_text(ROFF_ARGS) return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT); } +static int +roff_getnum(const char *v, int *pos, int *res) +{ + int p, n; + + p = *pos; + n = v[p] == '-'; + if (n) + p++; + + for (*res = 0; isdigit((unsigned char)v[p]); p++) + *res += 10 * *res + v[p] - '0'; + if (p == *pos + n) + return 0; + + if (n) + *res = -*res; + + *pos = p; + return 1; +} + +static int +roff_getop(const char *v, int *pos, char *res) +{ + int e; + + *res = v[*pos]; + e = v[*pos + 1] == '='; + + switch (*res) { + case '=': + break; + case '>': + if (e) + *res = 'g'; + break; + case '<': + if (e) + *res = 'l'; + break; + default: + return(0); + } + + *pos += 1 + e; + + return(*res); +} + static enum roffrule roff_evalcond(const char *v, int *pos) { + int not, lh, rh; + char op; switch (v[*pos]) { case ('n'): @@ -1074,13 +1197,47 @@ roff_evalcond(const char *v, int *pos) case ('t'): (*pos)++; return(ROFFRULE_DENY); + case ('!'): + (*pos)++; + not = 1; + break; default: + not = 0; break; } - while (v[*pos] && ' ' != v[*pos]) - (*pos)++; - return(ROFFRULE_DENY); + if (!roff_getnum(v, pos, &lh)) + return ROFFRULE_DENY; + if (!roff_getop(v, pos, &op)) { + if (lh < 0) + lh = 0; + goto out; + } + if (!roff_getnum(v, pos, &rh)) + return ROFFRULE_DENY; + switch (op) { + case 'g': + lh = lh >= rh; + break; + case 'l': + lh = lh <= rh; + break; + case '=': + lh = lh == rh; + break; + case '>': + lh = lh > rh; + break; + case '<': + lh = lh < rh; + break; + default: + return ROFFRULE_DENY; + } +out: + if (not) + lh = !lh; + return lh ? ROFFRULE_ALLOW : ROFFRULE_DENY; } /* ARGSUSED */ @@ -1088,9 +1245,6 @@ static enum rofferr roff_line_ignore(ROFF_ARGS) { - if (ROFF_it == tok) - mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos, "it"); - return(ROFF_IGN); } @@ -1098,8 +1252,8 @@ roff_line_ignore(ROFF_ARGS) static enum rofferr roff_cond(ROFF_ARGS) { - int sv; - enum roffrule rule; + + roffnode_push(r, tok, NULL, ln, ppos); /* * An `.el' has no conditional body: it will consume the value @@ -1109,31 +1263,11 @@ roff_cond(ROFF_ARGS) * If we're not an `el', however, then evaluate the conditional. */ - rule = ROFF_el == tok ? + r->last->rule = ROFF_el == tok ? (r->rstackpos < 0 ? ROFFRULE_DENY : r->rstack[r->rstackpos--]) : roff_evalcond(*bufp, &pos); - sv = pos; - while (' ' == (*bufp)[pos]) - pos++; - - /* - * Roff is weird. If we have just white-space after the - * conditional, it's considered the BODY and we exit without - * really doing anything. Warn about this. It's probably - * wrong. - */ - - if ('\0' == (*bufp)[pos] && sv != pos) { - mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL); - return(ROFF_IGN); - } - - roffnode_push(r, tok, NULL, ln, ppos); - - r->last->rule = rule; - /* * An if-else will put the NEGATION of the current evaluated * conditional into the stack of rules. @@ -1156,28 +1290,39 @@ roff_cond(ROFF_ARGS) r->last->rule = ROFFRULE_DENY; /* - * Determine scope. If we're invoked with "\{" trailing the - * conditional, then we're in a multiline scope. Else our scope - * expires on the next line. + * Determine scope. + * If there is nothing on the line after the conditional, + * not even whitespace, use next-line scope. */ - r->last->endspan = 1; + if ('\0' == (*bufp)[pos]) { + r->last->endspan = 2; + goto out; + } + + while (' ' == (*bufp)[pos]) + pos++; + + /* An opening brace requests multiline scope. */ if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) { r->last->endspan = -1; pos += 2; + goto out; } /* - * If there are no arguments on the line, the next-line scope is - * assumed. + * Anything else following the conditional causes + * single-line scope. Warn if the scope contains + * nothing but trailing whitespace. */ if ('\0' == (*bufp)[pos]) - return(ROFF_IGN); + mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL); - /* Otherwise re-run the roff parser after recalculating. */ + r->last->endspan = 1; +out: *offs = pos; return(ROFF_RERUN); } @@ -1213,25 +1358,71 @@ roff_ds(ROFF_ARGS) return(ROFF_IGN); } +void +roff_setreg(struct roff *r, const char *name, int val, char sign) +{ + struct roffreg *reg; + + /* Search for an existing register with the same name. */ + reg = r->regtab; + + while (reg && strcmp(name, reg->key.p)) + reg = reg->next; + + if (NULL == reg) { + /* Create a new register. */ + reg = mandoc_malloc(sizeof(struct roffreg)); + reg->key.p = mandoc_strdup(name); + reg->key.sz = strlen(name); + reg->val = 0; + reg->next = r->regtab; + r->regtab = reg; + } + + if ('+' == sign) + reg->val += val; + else if ('-' == sign) + reg->val -= val; + else + reg->val = val; +} + int -roff_regisset(const struct roff *r, enum regs reg) +roff_getreg(const struct roff *r, const char *name) { + struct roffreg *reg; + + for (reg = r->regtab; reg; reg = reg->next) + if (0 == strcmp(name, reg->key.p)) + return(reg->val); - return(r->regs[(int)reg].set); + return(0); } -unsigned int -roff_regget(const struct roff *r, enum regs reg) +static int +roff_getregn(const struct roff *r, const char *name, size_t len) { + struct roffreg *reg; - return(r->regs[(int)reg].u); + for (reg = r->regtab; reg; reg = reg->next) + if (len == reg->key.sz && + 0 == strncmp(name, reg->key.p, len)) + return(reg->val); + + return(0); } -void -roff_regunset(struct roff *r, enum regs reg) +static void +roff_freereg(struct roffreg *reg) { + struct roffreg *old_reg; - r->regs[(int)reg].set = 0; + while (NULL != reg) { + free(reg->key.p); + old_reg = reg; + reg = reg->next; + free(old_reg); + } } /* ARGSUSED */ @@ -1240,18 +1431,21 @@ roff_nr(ROFF_ARGS) { const char *key; char *val; + size_t sz; int iv; + char sign; val = *bufp + pos; key = roff_getname(r, &val, ln, pos); - if (0 == strcmp(key, "nS")) { - r->regs[(int)REG_nS].set = 1; - if ((iv = mandoc_strntoi(val, strlen(val), 10)) >= 0) - r->regs[(int)REG_nS].u = (unsigned)iv; - else - r->regs[(int)REG_nS].u = 0u; - } + sign = *val; + if ('+' == sign || '-' == sign) + val++; + + sz = strspn(val, "0123456789"); + iv = sz ? mandoc_strntoi(val, sz, 10) : 0; + + roff_setreg(r, key, iv, sign); return(ROFF_IGN); } @@ -1274,6 +1468,57 @@ roff_rm(ROFF_ARGS) /* ARGSUSED */ static enum rofferr +roff_it(ROFF_ARGS) +{ + char *cp; + size_t len; + int iv; + + /* Parse the number of lines. */ + cp = *bufp + pos; + len = strcspn(cp, " \t"); + cp[len] = '\0'; + if ((iv = mandoc_strntoi(cp, len, 10)) <= 0) { + mandoc_msg(MANDOCERR_NUMERIC, r->parse, + ln, ppos, *bufp + 1); + return(ROFF_IGN); + } + cp += len + 1; + + /* Arm the input line trap. */ + roffit_lines = iv; + roffit_macro = mandoc_strdup(cp); + return(ROFF_IGN); +} + +/* ARGSUSED */ +static enum rofferr +roff_Dd(ROFF_ARGS) +{ + const char *const *cp; + + if (MPARSE_MDOC != r->parsetype) + for (cp = __mdoc_reserved; *cp; cp++) + roff_setstr(r, *cp, NULL, 0); + + return(ROFF_CONT); +} + +/* ARGSUSED */ +static enum rofferr +roff_TH(ROFF_ARGS) +{ + const char *const *cp; + + if (MPARSE_MDOC != r->parsetype) + for (cp = __man_reserved; *cp; cp++) + roff_setstr(r, *cp, NULL, 0); + + return(ROFF_CONT); +} + +/* ARGSUSED */ +static enum rofferr roff_TE(ROFF_ARGS) { @@ -1352,21 +1597,38 @@ roff_EN(ROFF_ARGS) static enum rofferr roff_TS(ROFF_ARGS) { - struct tbl_node *t; + struct tbl_node *tbl; if (r->tbl) { mandoc_msg(MANDOCERR_SCOPEBROKEN, r->parse, ln, ppos, NULL); tbl_end(&r->tbl); } - t = tbl_alloc(ppos, ln, r->parse); + tbl = tbl_alloc(ppos, ln, r->parse); if (r->last_tbl) - r->last_tbl->next = t; + r->last_tbl->next = tbl; else - r->first_tbl = r->last_tbl = t; + r->first_tbl = r->last_tbl = tbl; + + r->tbl = r->last_tbl = tbl; + return(ROFF_IGN); +} + +/* ARGSUSED */ +static enum rofferr +roff_cc(ROFF_ARGS) +{ + const char *p; + + p = *bufp + pos; + + if ('\0' == *p || '.' == (r->control = *p++)) + r->control = 0; + + if ('\0' != *p) + mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, ln, ppos, NULL); - r->tbl = r->last_tbl = t; return(ROFF_IGN); } @@ -1470,7 +1732,7 @@ roff_userdef(ROFF_ARGS) /* * Collect pointers to macro argument strings - * and null-terminate them. + * and NUL-terminate them. */ cp = *bufp + pos; for (i = 0; i < 9; i++) @@ -1766,3 +2028,38 @@ roff_strdup(const struct roff *r, const char *p) res[(int)ssz] = '\0'; return(res); } + +/* + * Find out whether a line is a macro line or not. + * If it is, adjust the current position and return one; if it isn't, + * return zero and don't change the current position. + * If the control character has been set with `.cc', then let that grain + * precedence. + * This is slighly contrary to groff, where using the non-breaking + * control character when `cc' has been invoked will cause the + * non-breaking macro contents to be printed verbatim. + */ +int +roff_getcontrol(const struct roff *r, const char *cp, int *ppos) +{ + int pos; + + pos = *ppos; + + if (0 != r->control && cp[pos] == r->control) + pos++; + else if (0 != r->control) + return(0); + else if ('\\' == cp[pos] && '.' == cp[pos + 1]) + pos += 2; + else if ('.' == cp[pos] || '\'' == cp[pos]) + pos++; + else + return(0); + + while (' ' == cp[pos] || '\t' == cp[pos]) + pos++; + + *ppos = pos; + return(1); +} diff --git a/usr/src/cmd/mandoc/st.in b/usr/src/cmd/mandoc/st.in index 3ba41dd359..c52ddab9ba 100644 --- a/usr/src/cmd/mandoc/st.in +++ b/usr/src/cmd/mandoc/st.in @@ -1,4 +1,4 @@ -/* $Id: st.in,v 1.19 2012/02/26 21:47:09 schwarze Exp $ */ +/* $Id: st.in,v 1.22 2013/12/25 14:09:32 schwarze Exp $ */ /* * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -35,16 +35,19 @@ LINE("-p1003.1-2001", "IEEE Std 1003.1-2001 (\\(lqPOSIX.1\\(rq)") LINE("-p1003.1-2004", "IEEE Std 1003.1-2004 (\\(lqPOSIX.1\\(rq)") LINE("-p1003.1-2008", "IEEE Std 1003.1-2008 (\\(lqPOSIX.1\\(rq)") LINE("-p1003.1", "IEEE Std 1003.1 (\\(lqPOSIX.1\\(rq)") -LINE("-p1003.1b", "IEEE Std 1003.1b (\\(lqPOSIX.1\\(rq)") -LINE("-p1003.1b-93", "IEEE Std 1003.1b-1993 (\\(lqPOSIX.1\\(rq)") -LINE("-p1003.1c-95", "IEEE Std 1003.1c-1995 (\\(lqPOSIX.1\\(rq)") -LINE("-p1003.1g-2000", "IEEE Std 1003.1g-2000 (\\(lqPOSIX.1\\(rq)") -LINE("-p1003.1i-95", "IEEE Std 1003.1i-1995 (\\(lqPOSIX.1\\(rq)") +LINE("-p1003.1b", "IEEE Std 1003.1b (\\(lqPOSIX.1b\\(rq)") +LINE("-p1003.1b-93", "IEEE Std 1003.1b-1993 (\\(lqPOSIX.1b\\(rq)") +LINE("-p1003.1c-95", "IEEE Std 1003.1c-1995 (\\(lqPOSIX.1c\\(rq)") +LINE("-p1003.1d-99", "IEEE Std 1003.1d-1999 (\\(lqPOSIX.1d\\(rq)") +LINE("-p1003.1g-2000", "IEEE Std 1003.1g-2000 (\\(lqPOSIX.1g\\(rq)") +LINE("-p1003.1i-95", "IEEE Std 1003.1i-1995 (\\(lqPOSIX.1i\\(rq)") +LINE("-p1003.1j-2000", "IEEE Std 1003.1j-2000 (\\(lqPOSIX.1j\\(rq)") +LINE("-p1003.1q-2000", "IEEE Std 1003.1q-2000 (\\(lqPOSIX.1q\\(rq)") +LINE("-p1003.2", "IEEE Std 1003.2 (\\(lqPOSIX.2\\(rq)") LINE("-p1003.2-92", "IEEE Std 1003.2-1992 (\\(lqPOSIX.2\\(rq)") LINE("-p1003.2a-92", "IEEE Std 1003.2a-1992 (\\(lqPOSIX.2\\(rq)") -LINE("-p1387.2-95", "IEEE Std 1387.2-1995 (\\(lqPOSIX.7.2\\(rq)") -LINE("-p1003.2", "IEEE Std 1003.2 (\\(lqPOSIX.2\\(rq)") LINE("-p1387.2", "IEEE Std 1387.2 (\\(lqPOSIX.7.2\\(rq)") +LINE("-p1387.2-95", "IEEE Std 1387.2-1995 (\\(lqPOSIX.7.2\\(rq)") LINE("-isoC", "ISO/IEC 9899:1990 (\\(lqISO\\~C90\\(rq)") LINE("-isoC-90", "ISO/IEC 9899:1990 (\\(lqISO\\~C90\\(rq)") LINE("-isoC-amd1", "ISO/IEC 9899/AMD1:1995 (\\(lqISO\\~C90, Amendment 1\\(rq)") @@ -68,11 +71,12 @@ LINE("-xpg4.2", "X/Open Portability Guide Issue\\~4, Version\\~2 (\\(lqXPG4.2\\ LINE("-xpg4.3", "X/Open Portability Guide Issue\\~4, Version\\~3 (\\(lqXPG4.3\\(rq)") LINE("-xbd5", "X/Open Base Definitions Issue\\~5 (\\(lqXBD5\\(rq)") LINE("-xcu5", "X/Open Commands and Utilities Issue\\~5 (\\(lqXCU5\\(rq)") +LINE("-xsh4.2", "X/Open System Interfaces and Headers Issue\\~4, Version\\~2 (\\(lqXSH4.2\\(rq)") LINE("-xsh5", "X/Open System Interfaces and Headers Issue\\~5 (\\(lqXSH5\\(rq)") LINE("-xns5", "X/Open Networking Services Issue\\~5 (\\(lqXNS5\\(rq)") LINE("-xns5.2", "X/Open Networking Services Issue\\~5.2 (\\(lqXNS5.2\\(rq)") LINE("-xns5.2d2.0", "X/Open Networking Services Issue\\~5.2 Draft\\~2.0 (\\(lqXNS5.2D2.0\\(rq)") LINE("-xcurses4.2", "X/Open Curses Issue\\~4, Version\\~2 (\\(lqXCURSES4.2\\(rq)") -LINE("-susv2", "Version\\~2 of the Single UNIX Specification") -LINE("-susv3", "Version\\~3 of the Single UNIX Specification") +LINE("-susv2", "Version\\~2 of the Single UNIX Specification (\\(lqSUSv2\\(rq)") +LINE("-susv3", "Version\\~3 of the Single UNIX Specification (\\(lqSUSv3\\(rq)") LINE("-svid4", "System\\~V Interface Definition, Fourth Edition (\\(lqSVID4\\(rq)") diff --git a/usr/src/cmd/mandoc/tbl.c b/usr/src/cmd/mandoc/tbl.c index b3d651be07..b244ac80ac 100644 --- a/usr/src/cmd/mandoc/tbl.c +++ b/usr/src/cmd/mandoc/tbl.c @@ -1,4 +1,4 @@ -/* $Id: tbl.c,v 1.26 2011/07/25 15:37:00 kristaps Exp $ */ +/* $Id: tbl.c,v 1.27 2013/05/31 22:08:09 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> @@ -72,21 +72,21 @@ tbl_read(struct tbl_node *tbl, int ln, const char *p, int offs) struct tbl_node * 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->parse = parse; - p->part = TBL_PART_OPTS; - p->opts.tab = '\t'; - p->opts.linesize = 12; - p->opts.decimal = '.'; - return(p); + struct tbl_node *tbl; + + tbl = mandoc_calloc(1, sizeof(struct tbl_node)); + tbl->line = line; + tbl->pos = pos; + tbl->parse = parse; + tbl->part = TBL_PART_OPTS; + tbl->opts.tab = '\t'; + tbl->opts.linesize = 12; + tbl->opts.decimal = '.'; + return(tbl); } void -tbl_free(struct tbl_node *p) +tbl_free(struct tbl_node *tbl) { struct tbl_row *rp; struct tbl_cell *cp; @@ -94,8 +94,8 @@ tbl_free(struct tbl_node *p) struct tbl_dat *dp; struct tbl_head *hp; - while (NULL != (rp = p->first_row)) { - p->first_row = rp->next; + while (NULL != (rp = tbl->first_row)) { + tbl->first_row = rp->next; while (rp->first) { cp = rp->first; rp->first = cp->next; @@ -104,8 +104,8 @@ tbl_free(struct tbl_node *p) free(rp); } - while (NULL != (sp = p->first_span)) { - p->first_span = sp->next; + while (NULL != (sp = tbl->first_span)) { + tbl->first_span = sp->next; while (sp->first) { dp = sp->first; sp->first = dp->next; @@ -116,12 +116,12 @@ tbl_free(struct tbl_node *p) free(sp); } - while (NULL != (hp = p->first_head)) { - p->first_head = hp->next; + while (NULL != (hp = tbl->first_head)) { + tbl->first_head = hp->next; free(hp); } - free(p); + free(tbl); } void diff --git a/usr/src/cmd/mandoc/tbl_data.c b/usr/src/cmd/mandoc/tbl_data.c index 129695d8bb..7413aa2d83 100644 --- a/usr/src/cmd/mandoc/tbl_data.c +++ b/usr/src/cmd/mandoc/tbl_data.c @@ -1,4 +1,4 @@ -/* $Id: tbl_data.c,v 1.24 2011/03/20 16:02:05 kristaps Exp $ */ +/* $Id: tbl_data.c,v 1.27 2013/06/01 04:56:50 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> @@ -49,13 +49,11 @@ data(struct tbl_node *tbl, struct tbl_span *dp, cp = dp->layout->first; /* - * Skip over spanners and vertical lines to data formats, since + * Skip over spanners, since * we want to match data with data layout cells in the header. */ - while (cp && (TBL_CELL_VERT == cp->pos || - TBL_CELL_DVERT == cp->pos || - TBL_CELL_SPAN == cp->pos)) + while (cp && TBL_CELL_SPAN == cp->pos) cp = cp->next; /* @@ -104,7 +102,7 @@ data(struct tbl_node *tbl, struct tbl_span *dp, if (*pos - sv == 2 && 'T' == p[sv] && '{' == p[sv + 1]) { tbl->part = TBL_PART_CDATA; - return(0); + return(1); } assert(*pos - sv >= 0); @@ -187,7 +185,7 @@ newspan(struct tbl_node *tbl, int line, struct tbl_row *rp) dp = mandoc_calloc(1, sizeof(struct tbl_span)); dp->line = line; - dp->tbl = &tbl->opts; + dp->opts = &tbl->opts; dp->layout = rp; dp->head = tbl->first_head; diff --git a/usr/src/cmd/mandoc/tbl_html.c b/usr/src/cmd/mandoc/tbl_html.c index 8e7dc05de0..6b8ced716b 100644 --- a/usr/src/cmd/mandoc/tbl_html.c +++ b/usr/src/cmd/mandoc/tbl_html.c @@ -1,4 +1,4 @@ -/* $Id: tbl_html.c,v 1.9 2011/09/18 14:14:15 schwarze Exp $ */ +/* $Id: tbl_html.c,v 1.10 2012/05/27 17:54:54 schwarze Exp $ */ /* * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -119,20 +119,12 @@ print_tbl(struct html *h, const struct tbl_span *sp) 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; + if (NULL == dp) break; - } + if (TBL_CELL_DOWN != dp->layout->pos) + if (dp->string) + print_text(h, dp->string); + dp = dp->next; } break; } diff --git a/usr/src/cmd/mandoc/tbl_layout.c b/usr/src/cmd/mandoc/tbl_layout.c index 7601f146ca..6cce977fa2 100644 --- a/usr/src/cmd/mandoc/tbl_layout.c +++ b/usr/src/cmd/mandoc/tbl_layout.c @@ -1,6 +1,7 @@ -/* $Id: tbl_layout.c,v 1.22 2011/09/18 14:14:15 schwarze Exp $ */ +/* $Id: tbl_layout.c,v 1.23 2012/05/27 17:54:54 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2012 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -51,8 +52,7 @@ static const struct tbl_phrase keys[KEYS_MAX] = { { '^', TBL_CELL_DOWN }, { '-', TBL_CELL_HORIZ }, { '_', TBL_CELL_HORIZ }, - { '=', TBL_CELL_DHORIZ }, - { '|', TBL_CELL_VERT } + { '=', TBL_CELL_DHORIZ } }; static int mods(struct tbl_node *, struct tbl_cell *, @@ -60,10 +60,8 @@ static int mods(struct tbl_node *, struct tbl_cell *, static int cell(struct tbl_node *, struct tbl_row *, int, const char *, int *); static void row(struct tbl_node *, int, const char *, int *); -static struct tbl_cell *cell_alloc(struct tbl_node *, - struct tbl_row *, enum tbl_cellt); -static void head_adjust(const struct tbl_cell *, - struct tbl_head *); +static struct tbl_cell *cell_alloc(struct tbl_node *, struct tbl_row *, + enum tbl_cellt, int vert); static int mods(struct tbl_node *tbl, struct tbl_cell *cp, @@ -80,10 +78,6 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp, case (TBL_CELL_HORIZ): /* FALLTHROUGH */ case (TBL_CELL_DHORIZ): - /* FALLTHROUGH */ - case (TBL_CELL_VERT): - /* FALLTHROUGH */ - case (TBL_CELL_DVERT): return(1); default: break; @@ -214,10 +208,17 @@ static int cell(struct tbl_node *tbl, struct tbl_row *rp, int ln, const char *p, int *pos) { - int i; + int vert, i; enum tbl_cellt c; - /* Parse the column position (`r', `R', `|', ...). */ + /* Handle vertical lines. */ + + for (vert = 0; '|' == p[*pos]; ++*pos) + vert++; + while (' ' == p[*pos]) + (*pos)++; + + /* Parse the column position (`c', `l', `r', ...). */ for (i = 0; i < KEYS_MAX; i++) if (tolower((unsigned char)p[*pos]) == keys[i].name) @@ -246,8 +247,6 @@ cell(struct tbl_node *tbl, struct tbl_row *rp, 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, @@ -270,25 +269,16 @@ cell(struct tbl_node *tbl, struct tbl_row *rp, (*pos)++; - /* Extra check for the double-vertical. */ - - if (TBL_CELL_VERT == c && '|' == p[*pos]) { - (*pos)++; - c = TBL_CELL_DVERT; - } - /* Disallow adjacent spacers. */ - if (rp->last && (TBL_CELL_VERT == c || TBL_CELL_DVERT == c) && - (TBL_CELL_VERT == rp->last->pos || - TBL_CELL_DVERT == rp->last->pos)) { + if (vert > 2) { mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, ln, *pos - 1, NULL); return(0); } /* Allocate cell then parse its modifiers. */ - return(mods(tbl, cell_alloc(tbl, rp, c), ln, p, pos)); + return(mods(tbl, cell_alloc(tbl, rp, c, vert), ln, p, pos)); } @@ -308,11 +298,11 @@ row: /* */ rp = mandoc_calloc(1, sizeof(struct tbl_row)); - if (tbl->last_row) { + if (tbl->last_row) tbl->last_row->next = rp; - tbl->last_row = rp; - } else - tbl->last_row = tbl->first_row = rp; + else + tbl->first_row = rp; + tbl->last_row = rp; cell: while (isspace((unsigned char)p[*pos])) @@ -357,7 +347,8 @@ tbl_layout(struct tbl_node *tbl, int ln, const char *p) } static struct tbl_cell * -cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos) +cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos, + int vert) { struct tbl_cell *p, *pp; struct tbl_head *h, *hp; @@ -365,108 +356,35 @@ cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos) p = mandoc_calloc(1, sizeof(struct tbl_cell)); if (NULL != (pp = rp->last)) { - rp->last->next = p; - rp->last = p; - } else - rp->last = rp->first = p; + pp->next = p; + h = pp->head->next; + } else { + rp->first = p; + h = tbl->first_head; + } + rp->last = p; p->pos = pos; + p->vert = vert; - /* - * This is a little bit complicated. Here we determine the - * header the corresponds to a cell. We add headers dynamically - * when need be or re-use them, otherwise. As an example, given - * the following: - * - * 1 c || l - * 2 | c | l - * 3 l l - * 3 || c | l |. - * - * We first add the new headers (as there are none) in (1); then - * in (2) we insert the first spanner (as it doesn't match up - * with the header); then we re-use the prior data headers, - * skipping over the spanners; then we re-use everything and add - * a last spanner. Note that VERT headers are made into DVERT - * ones. - */ - - h = pp ? pp->head->next : tbl->first_head; + /* Re-use header. */ if (h) { - /* Re-use data header. */ - if (TBL_HEAD_DATA == h->pos && - (TBL_CELL_VERT != p->pos && - TBL_CELL_DVERT != p->pos)) { - p->head = h; - return(p); - } - - /* Re-use spanner header. */ - if (TBL_HEAD_DATA != h->pos && - (TBL_CELL_VERT == p->pos || - TBL_CELL_DVERT == p->pos)) { - head_adjust(p, h); - p->head = h; - return(p); - } - - /* Right-shift headers with a new spanner. */ - if (TBL_HEAD_DATA == h->pos && - (TBL_CELL_VERT == p->pos || - TBL_CELL_DVERT == p->pos)) { - hp = mandoc_calloc(1, sizeof(struct tbl_head)); - hp->ident = tbl->opts.cols++; - hp->prev = h->prev; - if (h->prev) - h->prev->next = hp; - if (h == tbl->first_head) - tbl->first_head = hp; - h->prev = hp; - hp->next = h; - head_adjust(p, hp); - p->head = hp; - return(p); - } - - if (NULL != (h = h->next)) { - head_adjust(p, h); - p->head = h; - return(p); - } - - /* Fall through to default case... */ + p->head = h; + return(p); } hp = mandoc_calloc(1, sizeof(struct tbl_head)); hp->ident = tbl->opts.cols++; + hp->vert = vert; if (tbl->last_head) { hp->prev = tbl->last_head; tbl->last_head->next = hp; - tbl->last_head = hp; } else - tbl->last_head = tbl->first_head = hp; + tbl->first_head = hp; + tbl->last_head = hp; - head_adjust(p, hp); p->head = hp; return(p); } - -static void -head_adjust(const struct tbl_cell *cellp, struct tbl_head *head) -{ - if (TBL_CELL_VERT != cellp->pos && - TBL_CELL_DVERT != cellp->pos) { - head->pos = TBL_HEAD_DATA; - return; - } - - if (TBL_CELL_VERT == cellp->pos) - if (TBL_HEAD_DVERT != head->pos) - head->pos = TBL_HEAD_VERT; - - if (TBL_CELL_DVERT == cellp->pos) - head->pos = TBL_HEAD_DVERT; -} - diff --git a/usr/src/cmd/mandoc/tbl_term.c b/usr/src/cmd/mandoc/tbl_term.c index f1928f02cb..e8411ffece 100644 --- a/usr/src/cmd/mandoc/tbl_term.c +++ b/usr/src/cmd/mandoc/tbl_term.c @@ -1,7 +1,7 @@ -/* $Id: tbl_term.c,v 1.21 2011/09/20 23:05:49 schwarze Exp $ */ +/* $Id: tbl_term.c,v 1.25 2013/05/31 21:37:17 schwarze Exp $ */ /* * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2011, 2012 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -31,14 +31,14 @@ 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); -static void tbl_data(struct termp *, const struct tbl *, +static void tbl_data(struct termp *, const struct tbl_opts *, const struct tbl_dat *, const struct roffcol *); static size_t tbl_rulewidth(struct termp *, const struct tbl_head *); static void tbl_hframe(struct termp *, const struct tbl_span *, int); static void tbl_literal(struct termp *, const struct tbl_dat *, const struct roffcol *); -static void tbl_number(struct termp *, const struct tbl *, +static void tbl_number(struct termp *, const struct tbl_opts *, const struct tbl_dat *, const struct roffcol *); static void tbl_hrule(struct termp *, const struct tbl_span *); @@ -96,16 +96,16 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) /* Horizontal frame at the start of boxed tables. */ if (TBL_SPAN_FIRST & sp->flags) { - if (TBL_OPT_DBOX & sp->tbl->opts) + if (TBL_OPT_DBOX & sp->opts->opts) tbl_hframe(tp, sp, 1); - if (TBL_OPT_DBOX & sp->tbl->opts || - TBL_OPT_BOX & sp->tbl->opts) + if (TBL_OPT_DBOX & sp->opts->opts || + TBL_OPT_BOX & sp->opts->opts) tbl_hframe(tp, sp, 0); } /* Vertical frame at the start of each row. */ - if (TBL_OPT_BOX & sp->tbl->opts || TBL_OPT_DBOX & sp->tbl->opts) + if (TBL_OPT_BOX & sp->opts->opts || TBL_OPT_DBOX & sp->opts->opts) term_word(tp, TBL_SPAN_HORIZ == sp->pos || TBL_SPAN_DHORIZ == sp->pos ? "+" : "|"); @@ -126,49 +126,23 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) 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): - if (spans <= 0) - tbl_vrule(tp, hp); - continue; - case (TBL_HEAD_DATA): - break; - } if (--spans >= 0) continue; - /* - * All cells get a leading blank, except the - * first one and those after double rulers. - */ + /* Separate columns. */ - if (hp->prev && TBL_HEAD_DVERT != hp->prev->pos) - tbl_char(tp, ASCII_NBRSP, 1); + if (NULL != hp->prev) + tbl_vrule(tp, hp); col = &tp->tbl.cols[hp->ident]; - tbl_data(tp, sp->tbl, dp, col); - - /* No trailing blanks. */ - - if (NULL == hp->next) - break; - - /* - * Add another blank between cells, - * or two when there is no vertical ruler. - */ - - tbl_char(tp, ASCII_NBRSP, - TBL_HEAD_VERT == hp->next->pos || - TBL_HEAD_DVERT == hp->next->pos ? 1 : 2); + tbl_data(tp, sp->opts, dp, col); /* * Go to the next data cell and assign the @@ -185,7 +159,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) /* Vertical frame at the end of each row. */ - if (TBL_OPT_BOX & sp->tbl->opts || TBL_OPT_DBOX & sp->tbl->opts) + if (TBL_OPT_BOX & sp->opts->opts || TBL_OPT_DBOX & sp->opts->opts) term_word(tp, TBL_SPAN_HORIZ == sp->pos || TBL_SPAN_DHORIZ == sp->pos ? "+" : " |"); term_flushln(tp); @@ -196,11 +170,15 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) */ if (TBL_SPAN_LAST & sp->flags) { - if (TBL_OPT_DBOX & sp->tbl->opts || - TBL_OPT_BOX & sp->tbl->opts) + if (TBL_OPT_DBOX & sp->opts->opts || + TBL_OPT_BOX & sp->opts->opts) { tbl_hframe(tp, sp, 0); - if (TBL_OPT_DBOX & sp->tbl->opts) + tp->skipvsp = 1; + } + if (TBL_OPT_DBOX & sp->opts->opts) { tbl_hframe(tp, sp, 1); + tp->skipvsp = 2; + } assert(tp->tbl.cols); free(tp->tbl.cols); tp->tbl.cols = NULL; @@ -222,17 +200,14 @@ tbl_rulewidth(struct termp *tp, const struct tbl_head *hp) size_t width; width = tp->tbl.cols[hp->ident].width; - if (TBL_HEAD_DATA == hp->pos) { - /* Account for leading blanks. */ - if (hp->prev && TBL_HEAD_DVERT != hp->prev->pos) - width++; - /* Account for trailing blanks. */ - width++; - if (hp->next && - TBL_HEAD_VERT != hp->next->pos && - TBL_HEAD_DVERT != hp->next->pos) - width++; - } + + /* Account for leading blanks. */ + if (hp->prev) + width += 2 - hp->vert; + + /* Account for trailing blank. */ + width++; + return(width); } @@ -250,10 +225,11 @@ tbl_hrule(struct termp *tp, const struct tbl_span *sp) if (TBL_SPAN_DHORIZ == sp->pos) c = '='; - for (hp = sp->head; hp; hp = hp->next) - tbl_char(tp, - TBL_HEAD_DATA == hp->pos ? c : '+', - tbl_rulewidth(tp, hp)); + for (hp = sp->head; hp; hp = hp->next) { + if (hp->prev && hp->vert) + tbl_char(tp, '+', hp->vert); + tbl_char(tp, c, tbl_rulewidth(tp, hp)); + } } /* @@ -268,16 +244,17 @@ tbl_hframe(struct termp *tp, const struct tbl_span *sp, int outer) const struct tbl_head *hp; term_word(tp, "+"); - for (hp = sp->head; hp; hp = hp->next) - tbl_char(tp, - outer || TBL_HEAD_DATA == hp->pos ? '-' : '+', - tbl_rulewidth(tp, hp)); + for (hp = sp->head; hp; hp = hp->next) { + if (hp->prev && hp->vert) + tbl_char(tp, (outer ? '-' : '+'), hp->vert); + tbl_char(tp, '-', tbl_rulewidth(tp, hp)); + } term_word(tp, "+"); term_flushln(tp); } static void -tbl_data(struct termp *tp, const struct tbl *tbl, +tbl_data(struct termp *tp, const struct tbl_opts *opts, const struct tbl_dat *dp, const struct roffcol *col) { @@ -323,7 +300,7 @@ tbl_data(struct termp *tp, const struct tbl *tbl, tbl_literal(tp, dp, col); break; case (TBL_CELL_NUMBER): - tbl_number(tp, tbl, dp, col); + tbl_number(tp, opts, dp, col); break; case (TBL_CELL_DOWN): tbl_char(tp, ASCII_NBRSP, col->width); @@ -338,16 +315,11 @@ static void tbl_vrule(struct termp *tp, const struct tbl_head *hp) { - switch (hp->pos) { - case (TBL_HEAD_VERT): - term_word(tp, "|"); - break; - case (TBL_HEAD_DVERT): - term_word(tp, "||"); - break; - default: - break; - } + tbl_char(tp, ASCII_NBRSP, 1); + if (0 < hp->vert) + tbl_char(tp, '|', hp->vert); + if (2 > hp->vert) + tbl_char(tp, ASCII_NBRSP, 2 - hp->vert); } static void @@ -369,11 +341,19 @@ static void tbl_literal(struct termp *tp, const struct tbl_dat *dp, const struct roffcol *col) { - size_t len, padl, padr; + struct tbl_head *hp; + size_t width, len, padl, padr; + int spans; assert(dp->string); len = term_strlen(tp, dp->string); - padr = col->width > len ? col->width - len : 0; + + hp = dp->layout->head->next; + width = col->width; + for (spans = dp->spans; spans--; hp = hp->next) + width += tp->tbl.cols[hp->ident].width + 3; + + padr = width > len ? width - len : 0; padl = 0; switch (dp->layout->pos) { @@ -401,7 +381,7 @@ tbl_literal(struct termp *tp, const struct tbl_dat *dp, } static void -tbl_number(struct termp *tp, const struct tbl *tbl, +tbl_number(struct termp *tp, const struct tbl_opts *opts, const struct tbl_dat *dp, const struct roffcol *col) { @@ -419,12 +399,12 @@ tbl_number(struct termp *tp, const struct tbl *tbl, sz = term_strlen(tp, dp->string); - buf[0] = tbl->decimal; + buf[0] = opts->decimal; buf[1] = '\0'; psz = term_strlen(tp, buf); - if (NULL != (cp = strrchr(dp->string, tbl->decimal))) { + if (NULL != (cp = strrchr(dp->string, opts->decimal))) { buf[1] = '\0'; for (ssz = 0, i = 0; cp != &dp->string[i]; i++) { buf[0] = dp->string[i]; diff --git a/usr/src/cmd/mandoc/term.c b/usr/src/cmd/mandoc/term.c index 4ca15ed6fa..e7b9557875 100644 --- a/usr/src/cmd/mandoc/term.c +++ b/usr/src/cmd/mandoc/term.c @@ -1,7 +1,7 @@ -/* $Id: term.c,v 1.201 2011/09/21 09:57:13 schwarze Exp $ */ +/* $Id: term.c,v 1.214 2013/12/25 00:39:31 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> - * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org> + * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -33,7 +33,8 @@ #include "term.h" #include "main.h" -static void adjbuf(struct termp *p, int); +static size_t cond_width(const struct termp *, int, int *); +static void adjbuf(struct termp *p, size_t); static void bufferc(struct termp *, char); static void encode(struct termp *, const char *, size_t); static void encode1(struct termp *, int); @@ -82,9 +83,8 @@ term_end(struct termp *p) * - TERMP_NOBREAK: this is the most important and is used when making * columns. In short: don't print a newline and instead expect the * next call to do the padding up to the start of the next column. - * - * - TERMP_TWOSPACE: make sure there is room for at least two space - * characters of padding. Otherwise, rather break the line. + * p->trailspace may be set to 0, 1, or 2, depending on how many + * space characters are required at the end of the column. * * - TERMP_DANGLE: don't newline when TERMP_NOBREAK is specified and * the line is overrun, and don't pad-right if it's underrun. @@ -104,14 +104,15 @@ term_end(struct termp *p) void term_flushln(struct termp *p) { - int i; /* current input position in p->buf */ + size_t i; /* current input position in p->buf */ + int ntab; /* number of tabs to prepend */ size_t vis; /* current visual position on output */ size_t vbl; /* number of blanks to prepend to output */ size_t vend; /* end of word visual position on output */ size_t bp; /* visual right border position */ size_t dv; /* temporary for visual pos calculations */ - int j; /* temporary loop index for p->buf */ - int jhy; /* last hyph before overflow w/r/t j */ + size_t j; /* temporary loop index for p->buf */ + size_t jhy; /* last hyph before overflow w/r/t j */ size_t maxvis; /* output position of visible boundary */ size_t mmax; /* used in calculating bp */ @@ -119,7 +120,12 @@ term_flushln(struct termp *p) * First, establish the maximum columns of "visible" content. * This is usually the difference between the right-margin and * an indentation, but can be, for tagged lists or columns, a - * small set of values. + * small set of values. + * + * The following unsigned-signed subtractions look strange, + * but they are actually correct. If the int p->overstep + * is negative, it gets sign extended. Subtracting that + * very large size_t effectively adds a small number to dv. */ assert (p->rmargin >= p->offset); dv = p->rmargin - p->offset; @@ -143,10 +149,12 @@ term_flushln(struct termp *p) * Handle literal tab characters: collapse all * subsequent tabs into a single huge set of spaces. */ + ntab = 0; while (i < p->col && '\t' == p->buf[i]) { vend = (vis / p->tabwidth + 1) * p->tabwidth; vbl += vend - vis; vis = vend; + ntab++; i++; } @@ -158,7 +166,7 @@ term_flushln(struct termp *p) */ for (j = i, jhy = 0; j < p->col; j++) { - if ((j && ' ' == p->buf[j]) || '\t' == p->buf[j]) + if (' ' == p->buf[j] || '\t' == p->buf[j]) break; /* Back over the the last printed character. */ @@ -191,7 +199,16 @@ term_flushln(struct termp *p) } else vbl = p->offset; - /* Remove the p->overstep width. */ + /* use pending tabs on the new line */ + + if (0 < ntab) + vbl += ntab * p->tabwidth; + + /* + * Remove the p->overstep width. + * Again, if p->overstep is negative, + * sign extension does the right thing. + */ bp += (size_t)p->overstep; p->overstep = 0; @@ -207,7 +224,7 @@ term_flushln(struct termp *p) j = i; while (' ' == p->buf[i]) i++; - dv = (size_t)(i - j) * (*p->width)(p, ' '); + dv = (i - j) * (*p->width)(p, ' '); vbl += dv; vend += dv; break; @@ -260,20 +277,17 @@ term_flushln(struct termp *p) } if (TERMP_HANG & p->flags) { - /* We need one blank after the tag. */ - p->overstep = (int)(vis - maxvis + (*p->width)(p, ' ')); + p->overstep = (int)(vis - maxvis + + p->trailspace * (*p->width)(p, ' ')); /* - * Behave exactly the same way as groff: * If we have overstepped the margin, temporarily move * it to the right and flag the rest of the line to be * shorter. - * If we landed right at the margin, be happy. - * If we are one step before the margin, temporarily - * move it one step LEFT and flag the rest of the line - * to be longer. + * If there is a request to keep the columns together, + * allow negative overstep when the column is not full. */ - if (p->overstep < -1) + if (p->trailspace && p->overstep < 0) p->overstep = 0; return; @@ -281,8 +295,7 @@ term_flushln(struct termp *p) return; /* If the column was overrun, break the line. */ - if (maxvis <= vis + - ((TERMP_TWOSPACE & p->flags) ? (*p->width)(p, ' ') : 0)) { + if (maxvis < vis + p->trailspace * (*p->width)(p, ' ')) { (*p->endline)(p); p->viscol = 0; } @@ -316,7 +329,10 @@ term_vspace(struct termp *p) term_newln(p); p->viscol = 0; - (*p->endline)(p); + if (0 < p->skipvsp) + p->skipvsp--; + else + (*p->endline)(p); } void @@ -369,7 +385,7 @@ void term_fontpopq(struct termp *p, const void *key) { - while (p->fonti >= 0 && key != &p->fontq[p->fonti]) + while (p->fonti >= 0 && key < (void *)(p->fontq + p->fonti)) p->fonti--; assert(p->fonti >= 0); } @@ -391,6 +407,7 @@ term_fontpop(struct termp *p) void term_word(struct termp *p, const char *word) { + const char nbrsp[2] = { ASCII_NBRSP, 0 }; const char *seq, *cp; char c; int sz, uc; @@ -399,29 +416,42 @@ term_word(struct termp *p, const char *word) if ( ! (TERMP_NOSPACE & p->flags)) { if ( ! (TERMP_KEEP & p->flags)) { - if (TERMP_PREKEEP & p->flags) - p->flags |= TERMP_KEEP; bufferc(p, ' '); if (TERMP_SENTENCE & p->flags) bufferc(p, ' '); } else bufferc(p, ASCII_NBRSP); } + if (TERMP_PREKEEP & p->flags) + p->flags |= TERMP_KEEP; if ( ! (p->flags & TERMP_NONOSPACE)) p->flags &= ~TERMP_NOSPACE; else p->flags |= TERMP_NOSPACE; - p->flags &= ~(TERMP_SENTENCE | TERMP_IGNDELIM); + p->flags &= ~TERMP_SENTENCE; while ('\0' != *word) { - if ((ssz = strcspn(word, "\\")) > 0) + if ('\\' != *word) { + if (TERMP_SKIPCHAR & p->flags) { + p->flags &= ~TERMP_SKIPCHAR; + word++; + continue; + } + if (TERMP_NBRWORD & p->flags) { + if (' ' == *word) { + encode(p, nbrsp, 1); + word++; + continue; + } + ssz = strcspn(word, "\\ "); + } else + ssz = strcspn(word, "\\"); encode(p, word, ssz); - - word += (int)ssz; - if ('\\' != *word) + word += (int)ssz; continue; + } word++; esc = mandoc_escape(&word, &seq, &sz); @@ -468,6 +498,9 @@ term_word(struct termp *p, const char *word) case (ESCAPE_FONTITALIC): term_fontrepl(p, TERMFONT_UNDER); break; + case (ESCAPE_FONTBI): + term_fontrepl(p, TERMFONT_BI); + break; case (ESCAPE_FONT): /* FALLTHROUGH */ case (ESCAPE_FONTROMAN): @@ -477,17 +510,23 @@ term_word(struct termp *p, const char *word) term_fontlast(p); break; case (ESCAPE_NOSPACE): - if ('\0' == *word) + if (TERMP_SKIPCHAR & p->flags) + p->flags &= ~TERMP_SKIPCHAR; + else if ('\0' == *word) p->flags |= TERMP_NOSPACE; break; + case (ESCAPE_SKIPCHAR): + p->flags |= TERMP_SKIPCHAR; + break; default: break; } } + p->flags &= ~TERMP_NBRWORD; } static void -adjbuf(struct termp *p, int sz) +adjbuf(struct termp *p, size_t sz) { if (0 == p->maxcols) @@ -495,8 +534,7 @@ adjbuf(struct termp *p, int sz) while (sz >= p->maxcols) p->maxcols <<= 2; - p->buf = mandoc_realloc - (p->buf, sizeof(int) * (size_t)p->maxcols); + p->buf = mandoc_realloc(p->buf, sizeof(int) * p->maxcols); } static void @@ -519,31 +557,39 @@ encode1(struct termp *p, int c) { enum termfont f; - if (p->col + 4 >= p->maxcols) - adjbuf(p, p->col + 4); + if (TERMP_SKIPCHAR & p->flags) { + p->flags &= ~TERMP_SKIPCHAR; + return; + } + + if (p->col + 6 >= p->maxcols) + adjbuf(p, p->col + 6); f = term_fonttop(p); - if (TERMFONT_NONE == f) { - p->buf[p->col++] = c; - return; - } else if (TERMFONT_UNDER == f) { + if (TERMFONT_UNDER == f || TERMFONT_BI == f) { p->buf[p->col++] = '_'; - } else - p->buf[p->col++] = c; - - p->buf[p->col++] = 8; + p->buf[p->col++] = 8; + } + if (TERMFONT_BOLD == f || TERMFONT_BI == f) { + if (ASCII_HYPH == c) + p->buf[p->col++] = '-'; + else + p->buf[p->col++] = c; + p->buf[p->col++] = 8; + } p->buf[p->col++] = c; } static void encode(struct termp *p, const char *word, size_t sz) { - enum termfont f; - int i, len; + size_t i; - /* LINTED */ - len = sz; + if (TERMP_SKIPCHAR & p->flags) { + p->flags &= ~TERMP_SKIPCHAR; + return; + } /* * Encode and buffer a string of characters. If the current @@ -551,35 +597,25 @@ encode(struct termp *p, const char *word, size_t sz) * character by character. */ - if (TERMFONT_NONE == (f = term_fonttop(p))) { - if (p->col + len >= p->maxcols) - adjbuf(p, p->col + len); - for (i = 0; i < len; i++) + if (TERMFONT_NONE == term_fonttop(p)) { + if (p->col + sz >= p->maxcols) + adjbuf(p, p->col + sz); + for (i = 0; i < sz; i++) p->buf[p->col++] = word[i]; return; } /* Pre-buffer, assuming worst-case. */ - if (p->col + 1 + (len * 3) >= p->maxcols) - adjbuf(p, p->col + 1 + (len * 3)); - - for (i = 0; i < len; i++) { - if (ASCII_HYPH != word[i] && - ! isgraph((unsigned char)word[i])) { - p->buf[p->col++] = word[i]; - continue; - } + if (p->col + 1 + (sz * 5) >= p->maxcols) + adjbuf(p, p->col + 1 + (sz * 5)); - if (TERMFONT_UNDER == f) - p->buf[p->col++] = '_'; - else if (ASCII_HYPH == word[i]) - p->buf[p->col++] = '-'; + for (i = 0; i < sz; i++) { + if (ASCII_HYPH == word[i] || + isgraph((unsigned char)word[i])) + encode1(p, word[i]); else p->buf[p->col++] = word[i]; - - p->buf[p->col++] = 8; - p->buf[p->col++] = word[i]; } } @@ -590,12 +626,22 @@ term_len(const struct termp *p, size_t sz) return((*p->width)(p, ' ') * sz); } +static size_t +cond_width(const struct termp *p, int c, int *skip) +{ + + if (*skip) { + (*skip) = 0; + return(0); + } else + return((*p->width)(p, c)); +} size_t term_strlen(const struct termp *p, const char *cp) { size_t sz, rsz, i; - int ssz, c; + int ssz, skip, c; const char *seq, *rhs; enum mandoc_esc esc; static const char rej[] = { '\\', ASCII_HYPH, ASCII_NBRSP, '\0' }; @@ -607,10 +653,11 @@ term_strlen(const struct termp *p, const char *cp) */ sz = 0; + skip = 0; while ('\0' != *cp) { rsz = strcspn(cp, rej); for (i = 0; i < rsz; i++) - sz += (*p->width)(p, *cp++); + sz += cond_width(p, *cp++, &skip); c = 0; switch (*cp) { @@ -627,14 +674,14 @@ term_strlen(const struct termp *p, const char *cp) (seq + 1, ssz - 1); if ('\0' == c) break; - sz += (*p->width)(p, c); + sz += cond_width(p, c, &skip); continue; case (ESCAPE_SPECIAL): c = mchars_spec2cp (p->symtab, seq, ssz); if (c <= 0) break; - sz += (*p->width)(p, c); + sz += cond_width(p, c, &skip); continue; default: break; @@ -644,12 +691,12 @@ term_strlen(const struct termp *p, const char *cp) switch (esc) { case (ESCAPE_UNICODE): - sz += (*p->width)(p, '?'); + sz += cond_width(p, '?', &skip); break; case (ESCAPE_NUMBERED): c = mchars_num2char(seq, ssz); if ('\0' != c) - sz += (*p->width)(p, c); + sz += cond_width(p, c, &skip); break; case (ESCAPE_SPECIAL): rhs = mchars_spec2str @@ -661,6 +708,9 @@ term_strlen(const struct termp *p, const char *cp) rhs = seq; rsz = ssz; break; + case (ESCAPE_SKIPCHAR): + skip = 1; + break; default: break; } @@ -668,15 +718,20 @@ term_strlen(const struct termp *p, const char *cp) if (NULL == rhs) break; + if (skip) { + skip = 0; + break; + } + for (i = 0; i < rsz; i++) sz += (*p->width)(p, *rhs++); break; case (ASCII_NBRSP): - sz += (*p->width)(p, ' '); + sz += cond_width(p, ' ', &skip); cp++; break; case (ASCII_HYPH): - sz += (*p->width)(p, '-'); + sz += cond_width(p, '-', &skip); cp++; break; default: diff --git a/usr/src/cmd/mandoc/term.h b/usr/src/cmd/mandoc/term.h index 56d076e54a..8cad4be838 100644 --- a/usr/src/cmd/mandoc/term.h +++ b/usr/src/cmd/mandoc/term.h @@ -1,6 +1,7 @@ -/* $Id: term.h,v 1.90 2011/12/04 23:10:52 schwarze Exp $ */ +/* $Id: term.h,v 1.97 2013/12/25 00:39:31 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -37,6 +38,7 @@ enum termfont { TERMFONT_NONE = 0, TERMFONT_BOLD, TERMFONT_UNDER, + TERMFONT_BI, TERMFONT__MAX }; @@ -57,26 +59,28 @@ struct termp { size_t defrmargin; /* Right margin of the device. */ size_t rmargin; /* Current right margin. */ size_t maxrmargin; /* Max right margin. */ - int maxcols; /* Max size of buf. */ + size_t maxcols; /* Max size of buf. */ size_t offset; /* Margin offest. */ size_t tabwidth; /* Distance of tab positions. */ - int col; /* Bytes in buf. */ + size_t col; /* Bytes in buf. */ size_t viscol; /* Chars on current line. */ + size_t trailspace; /* See termp_flushln(). */ int overstep; /* See termp_flushln(). */ + int skipvsp; /* Vertical space to skip. */ int flags; #define TERMP_SENTENCE (1 << 1) /* Space before a sentence. */ #define TERMP_NOSPACE (1 << 2) /* No space before words. */ -#define TERMP_NOBREAK (1 << 4) /* See term_flushln(). */ -#define TERMP_IGNDELIM (1 << 6) /* Delims like regulars. */ -#define TERMP_NONOSPACE (1 << 7) /* No space (no autounset). */ -#define TERMP_DANGLE (1 << 8) /* See term_flushln(). */ -#define TERMP_HANG (1 << 9) /* See term_flushln(). */ -#define TERMP_TWOSPACE (1 << 10) /* See term_flushln(). */ +#define TERMP_NONOSPACE (1 << 3) /* No space (no autounset). */ +#define TERMP_NBRWORD (1 << 4) /* Make next word nonbreaking. */ +#define TERMP_KEEP (1 << 5) /* Keep words together. */ +#define TERMP_PREKEEP (1 << 6) /* ...starting with the next one. */ +#define TERMP_SKIPCHAR (1 << 7) /* Skip the next character. */ +#define TERMP_NOBREAK (1 << 8) /* See term_flushln(). */ +#define TERMP_DANGLE (1 << 9) /* See term_flushln(). */ +#define TERMP_HANG (1 << 10) /* See term_flushln(). */ #define TERMP_NOSPLIT (1 << 11) /* See termp_an_pre/post(). */ #define TERMP_SPLIT (1 << 12) /* See termp_an_pre/post(). */ #define TERMP_ANPREC (1 << 13) /* See termp_an_pre(). */ -#define TERMP_KEEP (1 << 14) /* Keep words together. */ -#define TERMP_PREKEEP (1 << 15) /* ...starting with the next one. */ int *buf; /* Output buffer. */ enum termenc enc; /* Type of encoding. */ struct mchars *symtab; /* Encoded-symbol table. */ diff --git a/usr/src/cmd/mandoc/term_ascii.c b/usr/src/cmd/mandoc/term_ascii.c index 2f114786f6..cb7ac29405 100644 --- a/usr/src/cmd/mandoc/term_ascii.c +++ b/usr/src/cmd/mandoc/term_ascii.c @@ -1,4 +1,4 @@ -/* $Id: term_ascii.c,v 1.20 2011/12/04 23:10:52 schwarze Exp $ */ +/* $Id: term_ascii.c,v 1.21 2013/06/01 14:27:20 schwarze Exp $ */ /* * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -73,7 +73,6 @@ ascii_init(enum termenc enc, char *outopts) struct termp *p; p = mandoc_calloc(1, sizeof(struct termp)); - p->enc = enc; p->tabwidth = 5; p->defrmargin = 78; @@ -93,7 +92,7 @@ ascii_init(enum termenc enc, char *outopts) if (TERMENC_ASCII != enc) { v = TERMENC_LOCALE == enc ? setlocale(LC_ALL, "") : - setlocale(LC_CTYPE, "UTF-8"); + setlocale(LC_CTYPE, "en_US.UTF-8"); if (NULL != v && MB_CUR_MAX > 1) { p->enc = enc; p->advance = locale_advance; diff --git a/usr/src/cmd/mandoc/tree.c b/usr/src/cmd/mandoc/tree.c index 1430c737e0..fdb70e1b93 100644 --- a/usr/src/cmd/mandoc/tree.c +++ b/usr/src/cmd/mandoc/tree.c @@ -1,6 +1,7 @@ -/* $Id: tree.c,v 1.47 2011/09/18 14:14:15 schwarze Exp $ */ +/* $Id: tree.c,v 1.50 2013/12/24 19:11:46 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv> + * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -58,13 +59,11 @@ print_mdoc(const struct mdoc_node *n, int indent) { const char *p, *t; int i, j; - size_t argc, sz; - char **params; + size_t argc; struct mdoc_argv *argv; argv = NULL; - argc = sz = 0; - params = NULL; + argc = 0; t = p = NULL; switch (n->type) { @@ -161,11 +160,14 @@ print_mdoc(const struct mdoc_node *n, int indent) if (argv[i].sz > 0) printf(" ]"); } - - for (i = 0; i < (int)sz; i++) - printf(" [%s]", params[i]); - printf(" %d:%d\n", n->line, n->pos); + putchar(' '); + if (MDOC_LINE & n->flags) + putchar('*'); + printf("%d:%d", n->line, n->pos); + if (n->lastline != n->line) + printf("-%d", n->lastline); + putchar('\n'); } if (n->child) diff --git a/usr/src/man/Makefile.man b/usr/src/man/Makefile.man index cf29132480..1b26bf0fb8 100644 --- a/usr/src/man/Makefile.man +++ b/usr/src/man/Makefile.man @@ -31,9 +31,16 @@ ROOTMANLINKS= $(MANLINKS:%=$(ROOTMAN)/man$(MANSECT)/%) $(ROOTMAN)/man$(MANSECT)/% $(ROOTHASMAN)/man$(MANSECT)/%: % $(INS.file) +# +# Note that new mandoc adds some checks for lots of extra whitespace. +# We don't want to check our legacy pages for that. There are thousands +# and thousands of them in our man pages. Please still check them +# manually when editing (git pbchk will do so for you.) +# $(MANCHECKS): - @$(ECHO) "checking $(@:%.check=%)"; \ - $(MANDOC) -Tlint $(@:%.check=%) + @$(EGREP) -q "^.TH" $(@:%.check=%) || \ + ( $(ECHO) "checking $(@:%.check=%)"; \ + $(MANDOC) -Tlint $(@:%.check=%) ) $(MANLINKS): $(RM) $@; $(SYMLINK) $(LINKSRC) $@ diff --git a/usr/src/man/man1/man.1 b/usr/src/man/man1/man.1 index 4bba713397..b21c113452 100644 --- a/usr/src/man/man1/man.1 +++ b/usr/src/man/man1/man.1 @@ -373,7 +373,7 @@ man page in ASCII text: .Sh CODE SET INDEPENDENCE Enabled. .Sh INTERFACE STABILITY -.Nm Committed . +.Sy Committed . .Sh SEE ALSO .Xr apropos 1 , .Xr cat 1 , diff --git a/usr/src/man/man1/mandoc.1 b/usr/src/man/man1/mandoc.1 index e1d7638d86..8f2f8b5e84 100644 --- a/usr/src/man/man1/mandoc.1 +++ b/usr/src/man/man1/mandoc.1 @@ -16,7 +16,7 @@ .\" Copyright 2012 Nexenta Systems, Inc. All rights reserved. .\" Copyright 2014 Garrett D'Amore <garrett@damore.org> .\" -.Dd Jul 16, 2014 +.Dd Jul 30, 2014 .Dt MANDOC 1 .Os .Sh NAME @@ -632,7 +632,7 @@ lists render similarly. The .Nm utility is -.Nm Committed , +.Sy Committed , but the details of specific output formats other than ASCII are .Nm Uncommitted . .Sh SEE ALSO diff --git a/usr/src/man/man5/man.5 b/usr/src/man/man5/man.5 index 819a68bdb7..eb0fad0d7b 100644 --- a/usr/src/man/man5/man.5 +++ b/usr/src/man/man5/man.5 @@ -1,9 +1,9 @@ -.\" Copryight 2014 Garrett D'Amore <garrett@damore.org> +.\" Copyright 2014 Garrett D'Amore <garrett@damore.org> .\" Copyright (c) 1995, Sun Microsystems, Inc. .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] -.Dd "Jul 19, 2014" +.Dd "Jul 30, 2014" .Dt MAN 5 .Os .Sh NAME @@ -235,7 +235,7 @@ and .Xr troff 1 , the use of multi-byte characters may not be supported. .Sh INTERFACE STABILITY -.Nm Obsolete Committed . +.Sy Obsolete Committed . The .Xr mdoc 5 package should be used instead. |