\n" + "This web interface is documented in the\n" + "man.cgi\n" + "manual, and the\n" + "apropos\n" + "manual explains the query syntax.\n" + "
\n", + scriptname, scriptname); + resp_end_html(); +} + +static void +pg_noresult(const struct req *req, const char *msg) +{ + resp_begin_html(200, NULL); + resp_searchform(req); + puts(""); + puts(msg); + puts("
"); + resp_end_html(); +} + +static void +pg_error_badrequest(const char *msg) +{ + + resp_begin_html(400, "Bad Request"); + puts("\n"); + puts(msg); + printf("Try again from the\n" + "main page.\n" + "
", scriptname); + resp_end_html(); +} + +static void +pg_error_internal(void) +{ + resp_begin_html(500, "Internal Server Error"); + puts("Internal Server Error
"); + resp_end_html(); +} + +static void +pg_searchres(const struct req *req, struct manpage *r, size_t sz) +{ + char *arch, *archend; + size_t i, iuse, isec; + int archprio, archpriouse; + int prio, priouse; + char sec; + + for (i = 0; i < sz; i++) { + if (validate_filename(r[i].file)) + continue; + fprintf(stderr, "invalid filename %s in %s database\n", + r[i].file, req->q.manpath); + pg_error_internal(); + return; + } + + if (1 == sz) { + /* + * If we have just one result, then jump there now + * without any delay. + */ + printf("Status: 303 See Other\r\n"); + printf("Location: http://%s%s/%s/%s?", + HTTP_HOST, scriptname, req->q.manpath, r[0].file); + http_printquery(req, "&"); + printf("\r\n" + "Content-Type: text/html; charset=utf-8\r\n" + "\r\n"); + return; + } + + resp_begin_html(200, NULL); + resp_searchform(req); + puts("| \n" + "q.manpath, r[i].file); + http_printquery(req, "&"); + printf("\">"); + html_print(r[i].names); + printf("\n" + " | \n" + ""); + html_print(r[i].output); + puts(" | \n" + "
You specified an invalid manual file.
"); + return; + } + + puts("");
+
+ while (NULL != (p = fgetln(f, &len))) {
+ bold = italic = 0;
+ for (i = 0; i < (int)len - 1; i++) {
+ /*
+ * This means that the catpage is out of state.
+ * Ignore it and keep going (although the
+ * catpage is bogus).
+ */
+
+ if ('\b' == p[i] || '\n' == p[i])
+ continue;
+
+ /*
+ * Print a regular character.
+ * Close out any bold/italic scopes.
+ * If we're in back-space mode, make sure we'll
+ * have something to enter when we backspace.
+ */
+
+ if ('\b' != p[i + 1]) {
+ if (italic)
+ printf("");
+ if (bold)
+ printf("");
+ italic = bold = 0;
+ html_putchar(p[i]);
+ continue;
+ } else if (i + 2 >= (int)len)
+ continue;
+
+ /* Italic mode. */
+
+ if ('_' == p[i]) {
+ if (bold)
+ printf("");
+ if ( ! italic)
+ printf("");
+ bold = 0;
+ italic = 1;
+ i += 2;
+ html_putchar(p[i]);
+ continue;
+ }
+
+ /*
+ * Handle funny behaviour troff-isms.
+ * These grok'd from the original man2html.c.
+ */
+
+ if (('+' == p[i] && 'o' == p[i + 2]) ||
+ ('o' == p[i] && '+' == p[i + 2]) ||
+ ('|' == p[i] && '=' == p[i + 2]) ||
+ ('=' == p[i] && '|' == p[i + 2]) ||
+ ('*' == p[i] && '=' == p[i + 2]) ||
+ ('=' == p[i] && '*' == p[i + 2]) ||
+ ('*' == p[i] && '|' == p[i + 2]) ||
+ ('|' == p[i] && '*' == p[i + 2])) {
+ if (italic)
+ printf("");
+ if (bold)
+ printf("");
+ italic = bold = 0;
+ putchar('*');
+ i += 2;
+ continue;
+ } else if (('|' == p[i] && '-' == p[i + 2]) ||
+ ('-' == p[i] && '|' == p[i + 1]) ||
+ ('+' == p[i] && '-' == p[i + 1]) ||
+ ('-' == p[i] && '+' == p[i + 1]) ||
+ ('+' == p[i] && '|' == p[i + 1]) ||
+ ('|' == p[i] && '+' == p[i + 1])) {
+ if (italic)
+ printf("");
+ if (bold)
+ printf("");
+ italic = bold = 0;
+ putchar('+');
+ i += 2;
+ continue;
+ }
+
+ /* Bold mode. */
+
+ if (italic)
+ printf("");
+ if ( ! bold)
+ printf("");
+ bold = 1;
+ italic = 0;
+ i += 2;
+ html_putchar(p[i]);
+ }
+
+ /*
+ * Clean up the last character.
+ * We can get to a newline; don't print that.
+ */
+
+ if (italic)
+ printf("");
+ if (bold)
+ printf("");
+
+ if (i == (int)len - 1 && '\n' != p[i])
+ html_putchar(p[i]);
+
+ putchar('\n');
+ }
+
+ puts("\n"
+ "You specified an invalid manual file.
"); + return; + } + + mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_FATAL, NULL, + req->q.manpath); + rc = mparse_readfd(mp, fd, file); + close(fd); + + if (rc >= MANDOCLEVEL_FATAL) { + fprintf(stderr, "fatal mandoc error: %s/%s\n", + req->q.manpath, file); + pg_error_internal(); + return; + } + + usepath = strcmp(req->q.manpath, req->p[0]); + mandoc_asprintf(&opts, + "fragment,man=%s?query=%%N&sec=%%S%s%s%s%s", + scriptname, + req->q.arch ? "&arch=" : "", + req->q.arch ? req->q.arch : "", + usepath ? "&manpath=" : "", + usepath ? req->q.manpath : ""); + + mparse_result(mp, &mdoc, &man, NULL); + if (NULL == man && NULL == mdoc) { + fprintf(stderr, "fatal mandoc error: %s/%s\n", + req->q.manpath, file); + pg_error_internal(); + mparse_free(mp); + return; + } + + vp = html_alloc(opts); + + if (NULL != mdoc) + html_mdoc(vp, mdoc); + else + html_man(vp, man); + + html_free(vp); + mparse_free(mp); + free(opts); +} + +static void +resp_show(const struct req *req, const char *file) +{ + + if ('.' == file[0] && '/' == file[1]) + file += 2; + + if ('c' == *file) + catman(req, file); + else + format(req, file); +} + +static void +pg_show(struct req *req, const char *fullpath) +{ + char *manpath; + const char *file; + + if ((file = strchr(fullpath, '/')) == NULL) { + pg_error_badrequest( + "You did not specify a page to show."); + return; + } + manpath = mandoc_strndup(fullpath, file - fullpath); + file++; + + if ( ! validate_manpath(req, manpath)) { + pg_error_badrequest( + "You specified an invalid manpath."); + free(manpath); + return; + } + + /* + * Begin by chdir()ing into the manpath. + * This way we can pick up the database files, which are + * relative to the manpath root. + */ + + if (chdir(manpath) == -1) { + fprintf(stderr, "chdir %s: %s\n", + manpath, strerror(errno)); + pg_error_internal(); + free(manpath); + return; + } + + if (strcmp(manpath, "mandoc")) { + free(req->q.manpath); + req->q.manpath = manpath; + } else + free(manpath); + + if ( ! validate_filename(file)) { + pg_error_badrequest( + "You specified an invalid manual file."); + return; + } + + resp_begin_html(200, NULL); + resp_searchform(req); + resp_show(req, file); + resp_end_html(); +} + +static void +pg_search(const struct req *req) +{ + struct mansearch search; + struct manpaths paths; + struct manpage *res; + char **cp; + const char *ep, *start; + size_t ressz; + int i, sz; + + /* + * Begin by chdir()ing into the root of the manpath. + * This way we can pick up the database files, which are + * relative to the manpath root. + */ + + if (-1 == (chdir(req->q.manpath))) { + fprintf(stderr, "chdir %s: %s\n", + req->q.manpath, strerror(errno)); + pg_error_internal(); + return; + } + + search.arch = req->q.arch; + search.sec = req->q.sec; + search.deftype = req->q.equal ? TYPE_Nm : (TYPE_Nm | TYPE_Nd); + search.flags = req->q.equal ? MANSEARCH_MAN : 0; + + paths.sz = 1; + paths.paths = mandoc_malloc(sizeof(char *)); + paths.paths[0] = mandoc_strdup("."); + + /* + * Poor man's tokenisation: just break apart by spaces. + * Yes, this is half-ass. But it works for now. + */ + + ep = req->q.query; + while (ep && isspace((unsigned char)*ep)) + ep++; + + sz = 0; + cp = NULL; + while (ep && '\0' != *ep) { + cp = mandoc_reallocarray(cp, sz + 1, sizeof(char *)); + start = ep; + while ('\0' != *ep && ! isspace((unsigned char)*ep)) + ep++; + cp[sz] = mandoc_malloc((ep - start) + 1); + memcpy(cp[sz], start, ep - start); + cp[sz++][ep - start] = '\0'; + while (isspace((unsigned char)*ep)) + ep++; + } + + if (0 == mansearch(&search, &paths, sz, cp, "Nd", &res, &ressz)) + pg_noresult(req, "You entered an invalid query."); + else if (0 == ressz) + pg_noresult(req, "No results found."); + else + pg_searchres(req, res, ressz); + + for (i = 0; i < sz; i++) + free(cp[i]); + free(cp); + + for (i = 0; i < (int)ressz; i++) { + free(res[i].file); + free(res[i].names); + free(res[i].output); + } + free(res); + + free(paths.paths[0]); + free(paths.paths); +} + +int +main(void) +{ + struct req req; + const char *path; + const char *querystring; + int i; + + /* Scan our run-time environment. */ + + if (NULL == (scriptname = getenv("SCRIPT_NAME"))) + scriptname = ""; + + if ( ! validate_urifrag(scriptname)) { + fprintf(stderr, "unsafe SCRIPT_NAME \"%s\"\n", + scriptname); + pg_error_internal(); + return(EXIT_FAILURE); + } + + /* + * First we change directory into the MAN_DIR so that + * subsequent scanning for manpath directories is rooted + * relative to the same position. + */ + + if (-1 == chdir(MAN_DIR)) { + fprintf(stderr, "MAN_DIR: %s: %s\n", + MAN_DIR, strerror(errno)); + pg_error_internal(); + return(EXIT_FAILURE); + } + + memset(&req, 0, sizeof(struct req)); + pathgen(&req); + + /* Next parse out the query string. */ + + if (NULL != (querystring = getenv("QUERY_STRING"))) + http_parse(&req, querystring); + + if ( ! (NULL == req.q.manpath || + validate_manpath(&req, req.q.manpath))) { + pg_error_badrequest( + "You specified an invalid manpath."); + return(EXIT_FAILURE); + } + + if ( ! (NULL == req.q.arch || validate_urifrag(req.q.arch))) { + pg_error_badrequest( + "You specified an invalid architecture."); + return(EXIT_FAILURE); + } + + /* Dispatch to the three different pages. */ + + path = getenv("PATH_INFO"); + if (NULL == path) + path = ""; + else if ('/' == *path) + path++; + + if ('\0' != *path) + pg_show(&req, path); + else if (NULL != req.q.query) + pg_search(&req); + else + pg_index(&req); + + free(req.q.manpath); + free(req.q.arch); + free(req.q.sec); + free(req.q.query); + for (i = 0; i < (int)req.psz; i++) + free(req.p[i]); + free(req.p); + return(EXIT_SUCCESS); +} + +/* + * Scan for indexable paths. + */ +static void +pathgen(struct req *req) +{ + FILE *fp; + char *dp; + size_t dpsz; + + if (NULL == (fp = fopen("manpath.conf", "r"))) { + fprintf(stderr, "%s/manpath.conf: %s\n", + MAN_DIR, strerror(errno)); + pg_error_internal(); + exit(EXIT_FAILURE); + } + + while (NULL != (dp = fgetln(fp, &dpsz))) { + if ('\n' == dp[dpsz - 1]) + dpsz--; + req->p = mandoc_realloc(req->p, + (req->psz + 1) * sizeof(char *)); + dp = mandoc_strndup(dp, dpsz); + if ( ! validate_urifrag(dp)) { + fprintf(stderr, "%s/manpath.conf contains " + "unsafe path \"%s\"\n", MAN_DIR, dp); + pg_error_internal(); + exit(EXIT_FAILURE); + } + if (NULL != strchr(dp, '/')) { + fprintf(stderr, "%s/manpath.conf contains " + "path with slash \"%s\"\n", MAN_DIR, dp); + pg_error_internal(); + exit(EXIT_FAILURE); + } + req->p[req->psz++] = dp; + } + + if ( req->p == NULL ) { + fprintf(stderr, "%s/manpath.conf is empty\n", MAN_DIR); + pg_error_internal(); + exit(EXIT_FAILURE); + } +} Property changes on: head/contrib/mdocml/cgi.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/mdocml/cgi.h.example =================================================================== --- head/contrib/mdocml/cgi.h.example (nonexistent) +++ head/contrib/mdocml/cgi.h.example (revision 274880) @@ -0,0 +1,9 @@ +/* Example compile-time configuration file for man.cgi(8). */ + +#define HTTP_HOST "mdocml.bsd.lv" +#define MAN_DIR "/var/www/man" +#define CSS_DIR "" +#define CUSTOMIZE_TITLE "Manual pages with mandoc" +#define CUSTOMIZE_BEGIN ") 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 */ struct mchars *symtab; /* character-escapes */ char *base_man; /* base for manpage href */ char *base_includes; /* base for include href */ char *style; /* style-sheet URI */ char buf[BUFSIZ]; /* see bufcat and friends */ - size_t buflen; + size_t buflen; struct tag *metaf; /* current open font scope */ enum htmlfont metal; /* last used font */ enum htmlfont metac; /* current font mode */ enum htmltype type; /* output media type */ int oflags; /* output options */ #define HTML_FRAGMENT (1 << 0) /* don't emit HTML/HEAD/BODY */ }; void print_gen_decls(struct html *); void print_gen_head(struct html *); -struct tag *print_otag(struct html *, enum htmltag, +struct tag *print_otag(struct html *, enum htmltag, int, const struct htmlpair *); void print_tagq(struct html *, const struct tag *); void print_stagq(struct html *, const struct tag *); void print_text(struct html *, const char *); void print_tblclose(struct html *); void print_tbl(struct html *, const struct tbl_span *); void print_eqn(struct html *, const struct eqn *); +#if __GNUC__ - 0 >= 4 +__attribute__((__format__ (__printf__, 2, 3))) +#endif void bufcat_fmt(struct html *, const char *, ...); void bufcat(struct html *, const char *); void bufcat_id(struct html *, const char *); -void bufcat_style(struct html *, +void bufcat_style(struct html *, const char *, const char *); -void bufcat_su(struct html *, const char *, +void bufcat_su(struct html *, const char *, const struct roffsu *); void bufinit(struct html *); -void buffmt_man(struct html *, +void buffmt_man(struct html *, const char *, const char *); void buffmt_includes(struct html *, const char *); int html_strlen(const char *); __END_DECLS #endif /*!HTML_H*/ Index: head/contrib/mdocml/lib.c =================================================================== --- head/contrib/mdocml/lib.c (revision 274879) +++ head/contrib/mdocml/lib.c (revision 274880) @@ -1,39 +1,36 @@ -/* $Id: lib.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */ +/* $Id: lib.c,v 1.10 2014/03/23 11:25:26 schwarze Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons* * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include #include -#include #include "mdoc.h" -#include "mandoc.h" #include "libmdoc.h" #define LINE(x, y) \ if (0 == strcmp(p, x)) return(y); const char * mdoc_a2lib(const char *p) { #include "lib.in" return(NULL); } Index: head/contrib/mdocml/lib.in =================================================================== --- head/contrib/mdocml/lib.in (revision 274879) +++ head/contrib/mdocml/lib.in (revision 274880) @@ -1,122 +1,123 @@ -/* $Id: lib.in,v 1.17 2013/10/13 15:24:03 schwarze Exp $ */ +/* $Id: lib.in,v 1.18 2014/01/06 00:53:33 schwarze Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons + * Copyright (c) 2009, 2012 Joerg Sonnenberger * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * These are all possible .Lb strings. When a new library is added, add * its short-string to the left-hand side and formatted string to the * right-hand side. * * Be sure to escape strings. */ LINE("libarchive", "Streaming Archive Library (libarchive, \\-larchive)") LINE("libarm", "ARM Architecture Library (libarm, \\-larm)") LINE("libarm32", "ARM32 Architecture Library (libarm32, \\-larm32)") LINE("libbluetooth", "Bluetooth Library (libbluetooth, \\-lbluetooth)") LINE("libbsm", "Basic Security Module Library (libbsm, \\-lbsm)") LINE("libc", "Standard C\\~Library (libc, \\-lc)") LINE("libc_r", "Reentrant C\\~Library (libc_r, \\-lc_r)") LINE("libcalendar", "Calendar Arithmetic Library (libcalendar, \\-lcalendar)") LINE("libcam", "Common Access Method User Library (libcam, \\-lcam)") LINE("libcapsicum", "Capsicum Library (libcapsicum, \\-lcapsicum)") LINE("libcdk", "Curses Development Kit Library (libcdk, \\-lcdk)") LINE("libcipher", "FreeSec Crypt Library (libcipher, \\-lcipher)") LINE("libcompat", "Compatibility Library (libcompat, \\-lcompat)") LINE("libcrypt", "Crypt Library (libcrypt, \\-lcrypt)") LINE("libcurses", "Curses Library (libcurses, \\-lcurses)") LINE("libdevattr", "Device attribute and event library (libdevattr, \\-ldevattr)") LINE("libdevinfo", "Device and Resource Information Utility Library (libdevinfo, \\-ldevinfo)") LINE("libdevstat", "Device Statistics Library (libdevstat, \\-ldevstat)") LINE("libdisk", "Interface to Slice and Partition Labels Library (libdisk, \\-ldisk)") LINE("libdm", "Device Mapper Library (libdm, \\-ldm)") LINE("libdwarf", "DWARF Access Library (libdwarf, \\-ldwarf)") LINE("libedit", "Command Line Editor Library (libedit, \\-ledit)") LINE("libefi", "EFI Runtime Services Library (libefi, \\-lefi)") LINE("libelf", "ELF Access Library (libelf, \\-lelf)") LINE("libevent", "Event Notification Library (libevent, \\-levent)") LINE("libexecinfo", "Backtrace Information Library (libexecinfo, \\-lexecinfo)") LINE("libfetch", "File Transfer Library (libfetch, \\-lfetch)") LINE("libfsid", "Filesystem Identification Library (libfsid, \\-lfsid)") LINE("libftpio", "FTP Connection Management Library (libftpio, \\-lftpio)") LINE("libform", "Curses Form Library (libform, \\-lform)") LINE("libgeom", "Userland API Library for Kernel GEOM subsystem (libgeom, \\-lgeom)") LINE("libgpib", "General-Purpose Instrument Bus (GPIB) library (libgpib, \\-lgpib)") LINE("libhammer", "HAMMER Filesystem Userland Library (libhammer, \\-lhammer)") LINE("libi386", "i386 Architecture Library (libi386, \\-li386)") LINE("libintl", "Internationalized Message Handling Library (libintl, \\-lintl)") LINE("libipsec", "IPsec Policy Control Library (libipsec, \\-lipsec)") LINE("libiscsi", "iSCSI protocol library (libiscsi, \\-liscsi)") LINE("libisns", "Internet Storage Name Service Library (libisns, \\-lisns)") LINE("libjail", "Jail Library (libjail, \\-ljail)") LINE("libkcore", "Kernel Memory Core Access Library (libkcore, \\-lkcore)") LINE("libkiconv", "Kernel-side iconv Library (libkiconv, \\-lkiconv)") LINE("libkse", "N:M Threading Library (libkse, \\-lkse)") LINE("libkvm", "Kernel Data Access Library (libkvm, \\-lkvm)") LINE("libm", "Math Library (libm, \\-lm)") LINE("libm68k", "m68k Architecture Library (libm68k, \\-lm68k)") LINE("libmagic", "Magic Number Recognition Library (libmagic, \\-lmagic)") LINE("libmandoc", "Mandoc Macro Compiler Library (libmandoc, \\-lmandoc)") LINE("libmd", "Message Digest (MD4, MD5, etc.) Support Library (libmd, \\-lmd)") LINE("libmemstat", "Kernel Memory Allocator Statistics Library (libmemstat, \\-lmemstat)") LINE("libmenu", "Curses Menu Library (libmenu, \\-lmenu)") LINE("libmj", "Minimalist JSON library (libmj, \\-lmj)") LINE("libnetgraph", "Netgraph User Library (libnetgraph, \\-lnetgraph)") LINE("libnetpgp", "Netpgp Signing, Verification, Encryption and Decryption (libnetpgp, \\-lnetpgp)") LINE("libnetpgpverify", "Netpgp Verification (libnetpgpverify, \\-lnetpgpverify)") LINE("libnpf", "NPF Packet Filter Library (libnpf, \\-lnpf)") LINE("libnv", "Name/value pairs library (libnv, \\-lnv)") LINE("libossaudio", "OSS Audio Emulation Library (libossaudio, \\-lossaudio)") LINE("libpam", "Pluggable Authentication Module Library (libpam, \\-lpam)") LINE("libpcap", "Packet Capture Library (libpcap, \\-lpcap)") LINE("libpci", "PCI Bus Access Library (libpci, \\-lpci)") LINE("libpmc", "Performance Counters Library (libpmc, \\-lpmc)") LINE("libppath", "Property-List Paths Library (libppath, \\-lppath)") LINE("libposix", "POSIX Compatibility Library (libposix, \\-lposix)") LINE("libposix1e", "POSIX.1e Security API Library (libposix1e, \\-lposix1e)") LINE("libppath", "Property-List Paths Library (libppath, \\-lppath)") LINE("libproc", "Processor Monitoring and Analysis Library (libproc, \\-lproc)") LINE("libprocstat", "Process and Files Information Retrieval (libprocstat, \\-lprocstat)") LINE("libprop", "Property Container Object Library (libprop, \\-lprop)") LINE("libpthread", "POSIX Threads Library (libpthread, \\-lpthread)") LINE("libpuffs", "puffs Convenience Library (libpuffs, \\-lpuffs)") LINE("libquota", "Disk Quota Access and Control Library (libquota, \\-lquota)") LINE("libradius", "RADIUS Client Library (libradius, \\-lradius)") LINE("librefuse", "File System in Userspace Convenience Library (librefuse, \\-lrefuse)") LINE("libresolv", "DNS Resolver Library (libresolv, \\-lresolv)") LINE("librpcsec_gss", "RPC GSS-API Authentication Library (librpcsec_gss, \\-lrpcsec_gss)") LINE("librpcsvc", "RPC Service Library (librpcsvc, \\-lrpcsvc)") LINE("librt", "POSIX Real\\-time Library (librt, \\-lrt)") LINE("librtld_db", "Run-time Linker Debugging Library (librtld_db, \\-lrtld_db)") LINE("libsaslc", "Simple Authentication and Security Layer client library (libsaslc, \\-lsaslc)") LINE("libsbuf", "Safe String Composition Library (libsbuf, \\-lsbuf)") LINE("libsdp", "Bluetooth Service Discovery Protocol User Library (libsdp, \\-lsdp)") LINE("libssp", "Buffer Overflow Protection Library (libssp, \\-lssp)") LINE("libstdthreads", "C11 Threads Library (libstdthreads, \\-lstdthreads)") LINE("libSystem", "System Library (libSystem, \\-lSystem)") LINE("libtacplus", "TACACS+ Client Library (libtacplus, \\-ltacplus)") LINE("libtcplay", "TrueCrypt-compatible API library (libtcplay, \\-ltcplay)") LINE("libtermcap", "Termcap Access Library (libtermcap, \\-ltermcap)") LINE("libterminfo", "Terminal Information Library (libterminfo, \\-lterminfo)") LINE("libthr", "1:1 Threading Library (libthr, \\-lthr)") LINE("libufs", "UFS File System Access Library (libufs, \\-lufs)") LINE("libugidfw", "File System Firewall Interface Library (libugidfw, \\-lugidfw)") LINE("libulog", "User Login Record Library (libulog, \\-lulog)") LINE("libusbhid", "USB Human Interface Devices Library (libusbhid, \\-lusbhid)") LINE("libutil", "System Utilities Library (libutil, \\-lutil)") LINE("libvgl", "Video Graphics Library (libvgl, \\-lvgl)") LINE("libx86_64", "x86_64 Architecture Library (libx86_64, \\-lx86_64)") LINE("libz", "Compression Library (libz, \\-lz)") Index: head/contrib/mdocml/libman.h =================================================================== --- head/contrib/mdocml/libman.h (revision 274879) +++ head/contrib/mdocml/libman.h (revision 274880) @@ -1,85 +1,77 @@ -/* $Id: libman.h,v 1.56 2012/11/17 00:26:33 schwarze Exp $ */ +/* $Id: libman.h,v 1.63 2014/08/01 21:24:17 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef LIBMAN_H #define LIBMAN_H enum man_next { MAN_NEXT_SIBLING = 0, MAN_NEXT_CHILD }; struct man { struct mparse *parse; /* parse pointer */ + int quick; /* abort parse early */ int flags; /* parse flags */ -#define MAN_HALT (1 << 0) /* badness happened: die */ #define MAN_ELINE (1 << 1) /* Next-line element scope. */ #define MAN_BLINE (1 << 2) /* Next-line block scope. */ -#define MAN_ILINE (1 << 3) /* Ignored in next-line scope. */ #define MAN_LITERAL (1 << 4) /* Literal input. */ -#define MAN_BPLINE (1 << 5) #define MAN_NEWLINE (1 << 6) /* first macro/text in a line */ enum man_next next; /* where to put the next node */ struct man_node *last; /* the last parsed node */ struct man_node *first; /* the first parsed node */ struct man_meta meta; /* document meta-data */ struct roff *roff; }; #define MACRO_PROT_ARGS struct man *man, \ enum mant tok, \ int line, \ int ppos, \ int *pos, \ char *buf struct man_macro { int (*fp)(MACRO_PROT_ARGS); int flags; #define MAN_SCOPED (1 << 0) #define MAN_EXPLICIT (1 << 1) /* See blk_imp(). */ #define MAN_FSCOPED (1 << 2) /* See blk_imp(). */ #define MAN_NSCOPED (1 << 3) /* See in_line_eoln(). */ #define MAN_NOCLOSE (1 << 4) /* See blk_exp(). */ #define MAN_BSCOPE (1 << 5) /* Break BLINE scope. */ }; extern const struct man_macro *const man_macros; __BEGIN_DECLS -#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); int man_tail_alloc(struct man *, int, int, enum mant); int man_body_alloc(struct man *, int, int, enum mant); int man_elem_alloc(struct man *, int, int, enum mant); void man_node_delete(struct man *, struct man_node *); void man_hash_init(void); enum mant man_hash_find(const char *); int man_macroend(struct man *); int man_valid_post(struct man *); -int man_valid_pre(struct man *, struct man_node *); -int man_unscope(struct man *, - const struct man_node *, enum mandocerr); +int man_unscope(struct man *, const struct man_node *); __END_DECLS #endif /*!LIBMAN_H*/ Index: head/contrib/mdocml/libmandoc.h =================================================================== --- head/contrib/mdocml/libmandoc.h (revision 274879) +++ head/contrib/mdocml/libmandoc.h (revision 274880) @@ -1,88 +1,92 @@ -/* $Id: libmandoc.h,v 1.35 2013/12/15 21:23:52 schwarze Exp $ */ +/* $Id: libmandoc.h,v 1.42 2014/07/09 11:31:43 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons - * Copyright (c) 2013 Ingo Schwarze + * Copyright (c) 2013, 2014 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef LIBMANDOC_H #define LIBMANDOC_H enum rofferr { ROFF_CONT, /* continue processing line */ ROFF_RERUN, /* re-run roff interpreter with offset */ ROFF_APPEND, /* re-run main parser, appending next line */ ROFF_REPARSE, /* re-run main parser on the result */ ROFF_SO, /* include another file */ ROFF_IGN, /* ignore current line */ ROFF_TBL, /* a table row was successfully parsed */ ROFF_EQN, /* an equation was successfully parsed */ ROFF_ERR /* badness: puke and stop */ }; __BEGIN_DECLS struct roff; struct mdoc; struct man; -void mandoc_msg(enum mandocerr, struct mparse *, +void mandoc_msg(enum mandocerr, struct mparse *, int, int, const char *); -void mandoc_vmsg(enum mandocerr, struct mparse *, +#if __GNUC__ - 0 >= 4 +__attribute__((__format__ (__printf__, 5, 6))) +#endif +void mandoc_vmsg(enum mandocerr, struct mparse *, int, int, const char *, ...); 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_eos(const char *, size_t); 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 *, char *); +void mdoc_free(struct mdoc *); +struct mdoc *mdoc_alloc(struct roff *, struct mparse *, + const char *, int); void mdoc_reset(struct mdoc *); -int mdoc_parseln(struct mdoc *, int, char *, int); +int mdoc_parseln(struct mdoc *, int, char *, int); int mdoc_endparse(struct mdoc *); int mdoc_addspan(struct mdoc *, const struct tbl_span *); int mdoc_addeqn(struct mdoc *, const struct eqn *); -void man_free(struct man *); -struct man *man_alloc(struct roff *, struct mparse *); +void man_free(struct man *); +struct man *man_alloc(struct roff *, struct mparse *, int); void man_reset(struct man *); -int man_parseln(struct man *, int, char *, int); +int man_parseln(struct man *, int, char *, int); int man_endparse(struct man *); 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(enum mparset, struct mparse *); +void roff_free(struct roff *); +struct roff *roff_alloc(struct mparse *, int); void roff_reset(struct roff *); -enum rofferr roff_parseln(struct roff *, int, +enum rofferr roff_parseln(struct roff *, int, char **, size_t *, int, int *); void roff_endparse(struct roff *); 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 *, +int roff_getcontrol(const struct roff *, const char *, int *); #if 0 char roff_eqndelim(const struct roff *); -void roff_openeqn(struct roff *, const char *, +void roff_openeqn(struct roff *, const char *, int, int, const char *); int roff_closeeqn(struct roff *); #endif const struct tbl_span *roff_span(const struct roff *); const struct eqn *roff_eqn(const struct roff *); __END_DECLS #endif /*!LIBMANDOC_H*/ Index: head/contrib/mdocml/libmdoc.h =================================================================== --- head/contrib/mdocml/libmdoc.h (revision 274879) +++ head/contrib/mdocml/libmdoc.h (revision 274880) @@ -1,146 +1,143 @@ -/* $Id: libmdoc.h,v 1.82 2013/10/21 23:47:58 schwarze Exp $ */ +/* $Id: libmdoc.h,v 1.88 2014/08/01 17:40:34 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2013 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef LIBMDOC_H #define LIBMDOC_H enum mdoc_next { MDOC_NEXT_SIBLING = 0, MDOC_NEXT_CHILD }; struct mdoc { struct mparse *parse; /* parse pointer */ - char *defos; /* default argument for .Os */ + const char *defos; /* default argument for .Os */ + int quick; /* abort parse early */ int flags; /* parse flags */ -#define MDOC_HALT (1 << 0) /* error in parse: halt */ #define MDOC_LITERAL (1 << 1) /* in a literal scope */ #define MDOC_PBODY (1 << 2) /* in the document body */ #define MDOC_NEWLINE (1 << 3) /* first macro/text in a line */ #define MDOC_PHRASELIT (1 << 4) /* literal within a partila phrase */ #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 */ + struct mdoc_node *last_es; /* the most recent Es node */ struct mdoc_meta meta; /* document meta-data */ enum mdoc_sec lastnamed; enum mdoc_sec lastsec; struct roff *roff; }; #define MACRO_PROT_ARGS struct mdoc *mdoc, \ enum mdoct tok, \ int line, \ int ppos, \ int *pos, \ char *buf struct mdoc_macro { int (*fp)(MACRO_PROT_ARGS); int flags; #define MDOC_CALLABLE (1 << 0) #define MDOC_PARSED (1 << 1) #define MDOC_EXPLICIT (1 << 2) #define MDOC_PROLOGUE (1 << 3) #define MDOC_IGNDELIM (1 << 4) #define MDOC_JOIN (1 << 5) }; enum margserr { ARGS_ERROR, ARGS_EOLN, /* end-of-line */ ARGS_WORD, /* normal word */ ARGS_PUNCT, /* series of punctuation */ ARGS_QWORD, /* quoted word */ ARGS_PHRASE, /* Ta'd phrase (-column) */ ARGS_PPHRASE, /* tabbed phrase (-column) */ ARGS_PEND /* last phrase (-column) */ }; enum margverr { ARGV_ERROR, ARGV_EOLN, /* end of line */ ARGV_ARG, /* valid argument */ ARGV_WORD /* normal word (or bad argument---same thing) */ }; /* * A punctuation delimiter is opening, closing, or "middle mark" * punctuation. These govern spacing. * Opening punctuation (e.g., the opening parenthesis) suppresses the * following space; closing punctuation (e.g., the closing parenthesis) * suppresses the leading space; middle punctuation (e.g., the vertical * bar) can do either. The middle punctuation delimiter bends the rules * depending on usage. */ enum mdelim { DELIM_NONE = 0, DELIM_OPEN, DELIM_MIDDLE, DELIM_CLOSE, DELIM_MAX }; extern const struct mdoc_macro *const mdoc_macros; __BEGIN_DECLS -#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 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, +int mdoc_elem_alloc(struct mdoc *, int, int, enum mdoct, struct mdoc_arg *); -int mdoc_block_alloc(struct mdoc *, int, int, +int mdoc_block_alloc(struct mdoc *, int, int, enum mdoct, struct mdoc_arg *); 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 *, 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 *); const char *mdoc_a2lib(const char *); const char *mdoc_a2st(const char *); const char *mdoc_a2arch(const char *); const char *mdoc_a2vol(const char *); int mdoc_valid_pre(struct mdoc *, struct mdoc_node *); int mdoc_valid_post(struct mdoc *); enum margverr mdoc_argv(struct mdoc *, int, enum mdoct, struct mdoc_arg **, int *, char *); void mdoc_argv_free(struct mdoc_arg *); enum margserr mdoc_args(struct mdoc *, int, int *, char *, enum mdoct, char **); -enum margserr mdoc_zargs(struct mdoc *, int, +enum margserr mdoc_zargs(struct mdoc *, int, int *, char *, char **); int mdoc_macroend(struct mdoc *); enum mdelim mdoc_isdelim(const char *); __END_DECLS #endif /*!LIBMDOC_H*/ Index: head/contrib/mdocml/libroff.h =================================================================== --- head/contrib/mdocml/libroff.h (revision 274879) +++ head/contrib/mdocml/libroff.h (revision 274880) @@ -1,84 +1,84 @@ -/* $Id: libroff.h,v 1.28 2013/05/31 21:37:17 schwarze Exp $ */ +/* $Id: libroff.h,v 1.29 2014/04/20 16:46:04 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef LIBROFF_H #define LIBROFF_H __BEGIN_DECLS enum tbl_part { TBL_PART_OPTS, /* in options (first line) */ TBL_PART_LAYOUT, /* describing layout */ TBL_PART_DATA, /* creating data rows */ TBL_PART_CDATA /* continue previous row */ }; struct tbl_node { struct mparse *parse; /* parse point */ int pos; /* invocation column */ int line; /* invocation line */ enum tbl_part part; struct tbl_opts opts; struct tbl_row *first_row; struct tbl_row *last_row; struct tbl_span *first_span; struct tbl_span *current_span; struct tbl_span *last_span; struct tbl_head *first_head; struct tbl_head *last_head; struct tbl_node *next; }; struct eqn_node { struct eqn_def *defs; size_t defsz; char *data; size_t rew; size_t cur; size_t sz; int gsize; struct eqn eqn; struct mparse *parse; struct eqn_node *next; }; struct eqn_def { char *key; size_t keysz; char *val; size_t valsz; }; struct tbl_node *tbl_alloc(int, int, struct mparse *); void tbl_restart(int, int, struct tbl_node *); void tbl_free(struct tbl_node *); void tbl_reset(struct tbl_node *); -enum rofferr tbl_read(struct tbl_node *, int, const char *, int); +enum rofferr tbl_read(struct tbl_node *, int, const char *, int); int tbl_option(struct tbl_node *, int, const char *); int tbl_layout(struct tbl_node *, int, const char *); int tbl_data(struct tbl_node *, int, const char *); int tbl_cdata(struct tbl_node *, int, const char *); const struct tbl_span *tbl_span(struct tbl_node *); void tbl_end(struct tbl_node **); struct eqn_node *eqn_alloc(const char *, int, int, struct mparse *); enum rofferr eqn_end(struct eqn_node **); void eqn_free(struct eqn_node *); -enum rofferr eqn_read(struct eqn_node **, int, +enum rofferr eqn_read(struct eqn_node **, int, const char *, int, int *); __END_DECLS #endif /*LIBROFF_H*/ Index: head/contrib/mdocml/main.c =================================================================== --- head/contrib/mdocml/main.c (revision 274879) +++ head/contrib/mdocml/main.c (revision 274880) @@ -1,417 +1,430 @@ -/* $Id: main.c,v 1.167 2012/11/19 17:22:26 schwarze Exp $ */ +/* $Id: main.c,v 1.177 2014/06/21 22:24:01 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2010, 2011, 2012 Ingo Schwarze + * Copyright (c) 2010, 2011, 2012, 2014 Ingo Schwarze + * Copyright (c) 2010 Joerg Sonnenberger * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include "mandoc.h" +#include "mandoc_aux.h" #include "main.h" #include "mdoc.h" #include "man.h" #if !defined(__GNUC__) || (__GNUC__ < 2) # if !defined(lint) # define __attribute__(x) # endif #endif /* !defined(__GNUC__) || (__GNUC__ < 2) */ typedef void (*out_mdoc)(void *, const struct mdoc *); typedef void (*out_man)(void *, const struct man *); typedef void (*out_free)(void *); enum outt { OUTT_ASCII = 0, /* -Tascii */ OUTT_LOCALE, /* -Tlocale */ OUTT_UTF8, /* -Tutf8 */ OUTT_TREE, /* -Ttree */ OUTT_MAN, /* -Tman */ OUTT_HTML, /* -Thtml */ OUTT_XHTML, /* -Txhtml */ OUTT_LINT, /* -Tlint */ OUTT_PS, /* -Tps */ OUTT_PDF /* -Tpdf */ }; struct curparse { struct mparse *mp; enum mandoclevel wlevel; /* ignore messages below this */ int wstop; /* stop after a file with a warning */ - enum outt outtype; /* which output to use */ + enum outt outtype; /* which output to use */ out_mdoc outmdoc; /* mdoc output ptr */ - out_man outman; /* man output ptr */ + out_man outman; /* man output ptr */ out_free outfree; /* free output ptr */ void *outdata; /* data for output */ char outopts[BUFSIZ]; /* buf of output opts */ }; -static int moptions(enum mparset *, char *); +static int moptions(int *, char *); static void mmsg(enum mandocerr, enum mandoclevel, const char *, int, int, const char *); -static void parse(struct curparse *, int, +static void parse(struct curparse *, int, const char *, enum mandoclevel *); static int toptions(struct curparse *, char *); static void usage(void) __attribute__((noreturn)); static void version(void) __attribute__((noreturn)); static int woptions(struct curparse *, char *); static const char *progname; + int main(int argc, char *argv[]) { int c; struct curparse curp; - enum mparset type; + int options; enum mandoclevel rc; char *defos; progname = strrchr(argv[0], '/'); if (progname == NULL) progname = argv[0]; else ++progname; memset(&curp, 0, sizeof(struct curparse)); - type = MPARSE_AUTO; + options = MPARSE_SO; curp.outtype = OUTT_ASCII; curp.wlevel = MANDOCLEVEL_FATAL; defos = NULL; - /* LINTED */ while (-1 != (c = getopt(argc, argv, "I:m:O:T:VW:"))) switch (c) { - case ('I'): + case 'I': if (strncmp(optarg, "os=", 3)) { - fprintf(stderr, "-I%s: Bad argument\n", - optarg); + fprintf(stderr, + "%s: -I%s: Bad argument\n", + progname, optarg); return((int)MANDOCLEVEL_BADARG); } if (defos) { - fprintf(stderr, "-I%s: Duplicate argument\n", - optarg); + fprintf(stderr, + "%s: -I%s: Duplicate argument\n", + progname, optarg); return((int)MANDOCLEVEL_BADARG); } defos = mandoc_strdup(optarg + 3); break; - case ('m'): - if ( ! moptions(&type, optarg)) + case 'm': + if ( ! moptions(&options, optarg)) return((int)MANDOCLEVEL_BADARG); break; - case ('O'): + case 'O': (void)strlcat(curp.outopts, optarg, BUFSIZ); (void)strlcat(curp.outopts, ",", BUFSIZ); break; - case ('T'): + case 'T': if ( ! toptions(&curp, optarg)) return((int)MANDOCLEVEL_BADARG); break; - case ('W'): + case 'W': if ( ! woptions(&curp, optarg)) return((int)MANDOCLEVEL_BADARG); break; - case ('V'): + case 'V': version(); /* NOTREACHED */ default: usage(); /* NOTREACHED */ } - curp.mp = mparse_alloc(type, curp.wlevel, mmsg, &curp, defos); + curp.mp = mparse_alloc(options, curp.wlevel, mmsg, defos); /* * Conditionally start up the lookaside buffer before parsing. */ if (OUTT_MAN == curp.outtype) mparse_keep(curp.mp); argc -= optind; argv += optind; rc = MANDOCLEVEL_OK; if (NULL == *argv) parse(&curp, STDIN_FILENO, " ", &rc); while (*argv) { parse(&curp, -1, *argv, &rc); if (MANDOCLEVEL_OK != rc && curp.wstop) break; ++argv; } if (curp.outfree) (*curp.outfree)(curp.outdata); if (curp.mp) mparse_free(curp.mp); free(defos); return((int)rc); } static void version(void) { printf("%s %s\n", progname, VERSION); exit((int)MANDOCLEVEL_OK); } static void usage(void) { fprintf(stderr, "usage: %s " "[-V] " "[-Ios=name] " "[-mformat] " "[-Ooption] " "[-Toutput] " "[-Wlevel]\n" - "\t [file ...]\n", + "\t [file ...]\n", progname); exit((int)MANDOCLEVEL_BADARG); } static void -parse(struct curparse *curp, int fd, - const char *file, enum mandoclevel *level) +parse(struct curparse *curp, int fd, const char *file, + enum mandoclevel *level) { enum mandoclevel rc; struct mdoc *mdoc; struct man *man; /* Begin by parsing the file itself. */ assert(file); assert(fd >= -1); rc = mparse_readfd(curp->mp, fd, file); /* Stop immediately if the parse has failed. */ if (MANDOCLEVEL_FATAL <= rc) goto cleanup; /* * With -Wstop and warnings or errors of at least the requested * level, do not produce output. */ if (MANDOCLEVEL_OK != rc && curp->wstop) goto cleanup; /* If unset, allocate output dev now (if applicable). */ if ( ! (curp->outman && curp->outmdoc)) { switch (curp->outtype) { - case (OUTT_XHTML): + case OUTT_XHTML: curp->outdata = xhtml_alloc(curp->outopts); curp->outfree = html_free; break; - case (OUTT_HTML): + case OUTT_HTML: curp->outdata = html_alloc(curp->outopts); curp->outfree = html_free; break; - case (OUTT_UTF8): + case OUTT_UTF8: curp->outdata = utf8_alloc(curp->outopts); curp->outfree = ascii_free; break; - case (OUTT_LOCALE): + case OUTT_LOCALE: curp->outdata = locale_alloc(curp->outopts); curp->outfree = ascii_free; break; - case (OUTT_ASCII): + case OUTT_ASCII: curp->outdata = ascii_alloc(curp->outopts); curp->outfree = ascii_free; break; - case (OUTT_PDF): + case OUTT_PDF: curp->outdata = pdf_alloc(curp->outopts); curp->outfree = pspdf_free; break; - case (OUTT_PS): + case OUTT_PS: curp->outdata = ps_alloc(curp->outopts); curp->outfree = pspdf_free; break; default: break; } switch (curp->outtype) { - case (OUTT_HTML): + case OUTT_HTML: /* FALLTHROUGH */ - case (OUTT_XHTML): + case OUTT_XHTML: curp->outman = html_man; curp->outmdoc = html_mdoc; break; - case (OUTT_TREE): + case OUTT_TREE: curp->outman = tree_man; curp->outmdoc = tree_mdoc; break; - case (OUTT_MAN): + case OUTT_MAN: curp->outmdoc = man_mdoc; curp->outman = man_man; break; - case (OUTT_PDF): + case OUTT_PDF: /* FALLTHROUGH */ - case (OUTT_ASCII): + case OUTT_ASCII: /* FALLTHROUGH */ - case (OUTT_UTF8): + case OUTT_UTF8: /* FALLTHROUGH */ - case (OUTT_LOCALE): + case OUTT_LOCALE: /* FALLTHROUGH */ - case (OUTT_PS): + case OUTT_PS: curp->outman = terminal_man; curp->outmdoc = terminal_mdoc; break; default: break; } } - mparse_result(curp->mp, &mdoc, &man); + mparse_result(curp->mp, &mdoc, &man, NULL); /* Execute the out device, if it exists. */ if (man && curp->outman) (*curp->outman)(curp->outdata, man); if (mdoc && curp->outmdoc) (*curp->outmdoc)(curp->outdata, mdoc); cleanup: mparse_reset(curp->mp); if (*level < rc) *level = rc; } static int -moptions(enum mparset *tflags, char *arg) +moptions(int *options, char *arg) { if (0 == strcmp(arg, "doc")) - *tflags = MPARSE_MDOC; + *options |= MPARSE_MDOC; else if (0 == strcmp(arg, "andoc")) - *tflags = MPARSE_AUTO; + /* nothing to do */; else if (0 == strcmp(arg, "an")) - *tflags = MPARSE_MAN; + *options |= MPARSE_MAN; else { - fprintf(stderr, "%s: Bad argument\n", arg); + fprintf(stderr, "%s: -m%s: Bad argument\n", + progname, arg); return(0); } return(1); } static int toptions(struct curparse *curp, char *arg) { if (0 == strcmp(arg, "ascii")) curp->outtype = OUTT_ASCII; else if (0 == strcmp(arg, "lint")) { curp->outtype = OUTT_LINT; curp->wlevel = MANDOCLEVEL_WARNING; } else if (0 == strcmp(arg, "tree")) curp->outtype = OUTT_TREE; else if (0 == strcmp(arg, "man")) curp->outtype = OUTT_MAN; else if (0 == strcmp(arg, "html")) curp->outtype = OUTT_HTML; else if (0 == strcmp(arg, "utf8")) curp->outtype = OUTT_UTF8; else if (0 == strcmp(arg, "locale")) curp->outtype = OUTT_LOCALE; else if (0 == strcmp(arg, "xhtml")) curp->outtype = OUTT_XHTML; else if (0 == strcmp(arg, "ps")) curp->outtype = OUTT_PS; else if (0 == strcmp(arg, "pdf")) curp->outtype = OUTT_PDF; else { - fprintf(stderr, "%s: Bad argument\n", arg); + fprintf(stderr, "%s: -T%s: Bad argument\n", + progname, arg); return(0); } return(1); } static int woptions(struct curparse *curp, char *arg) { char *v, *o; - const char *toks[6]; + const char *toks[6]; toks[0] = "stop"; toks[1] = "all"; toks[2] = "warning"; toks[3] = "error"; toks[4] = "fatal"; toks[5] = NULL; while (*arg) { o = arg; switch (getsubopt(&arg, UNCONST(toks), &v)) { - case (0): + case 0: curp->wstop = 1; break; - case (1): + case 1: /* FALLTHROUGH */ - case (2): + case 2: curp->wlevel = MANDOCLEVEL_WARNING; break; - case (3): + case 3: curp->wlevel = MANDOCLEVEL_ERROR; break; - case (4): + case 4: curp->wlevel = MANDOCLEVEL_FATAL; break; default: - fprintf(stderr, "-W%s: Bad argument\n", o); + fprintf(stderr, "%s: -W%s: Bad argument\n", + progname, o); return(0); } } return(1); } static void -mmsg(enum mandocerr t, enum mandoclevel lvl, +mmsg(enum mandocerr t, enum mandoclevel lvl, const char *file, int line, int col, const char *msg) { + const char *mparse_msg; - fprintf(stderr, "%s:%d:%d: %s: %s", - file, line, col + 1, - mparse_strlevel(lvl), - mparse_strerror(t)); + fprintf(stderr, "%s: %s:", progname, file); + + if (line) + fprintf(stderr, "%d:%d:", line, col + 1); + + fprintf(stderr, " %s", mparse_strlevel(lvl)); + + if (NULL != (mparse_msg = mparse_strerror(t))) + fprintf(stderr, ": %s", mparse_msg); if (msg) fprintf(stderr, ": %s", msg); fputc('\n', stderr); } Index: head/contrib/mdocml/main.h =================================================================== --- head/contrib/mdocml/main.h (revision 274879) +++ head/contrib/mdocml/main.h (revision 274880) @@ -1,61 +1,61 @@ -/* $Id: main.h,v 1.15 2011/10/06 22:29:12 kristaps Exp $ */ +/* $Id: main.h,v 1.16 2014/04/20 16:46:04 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef MAIN_H #define MAIN_H __BEGIN_DECLS struct mdoc; struct man; #define UNCONST(a) ((void *)(uintptr_t)(const void *)(a)) -/* +/* * Definitions for main.c-visible output device functions, e.g., -Thtml * and -Tascii. Note that ascii_alloc() is named as such in * anticipation of latin1_alloc() and so on, all of which map into the * terminal output routines with different character settings. */ void *html_alloc(char *); void *xhtml_alloc(char *); void html_mdoc(void *, const struct mdoc *); void html_man(void *, const struct man *); void html_free(void *); void tree_mdoc(void *, const struct mdoc *); void tree_man(void *, const struct man *); void man_mdoc(void *, const struct mdoc *); void man_man(void *, const struct man *); void *locale_alloc(char *); void *utf8_alloc(char *); void *ascii_alloc(char *); void ascii_free(void *); void *pdf_alloc(char *); void *ps_alloc(char *); void pspdf_free(void *); void terminal_mdoc(void *, const struct mdoc *); void terminal_man(void *, const struct man *); __END_DECLS #endif /*!MAIN_H*/ Index: head/contrib/mdocml/makewhatis.8 =================================================================== --- head/contrib/mdocml/makewhatis.8 (nonexistent) +++ head/contrib/mdocml/makewhatis.8 (revision 274880) @@ -0,0 +1,217 @@ +.\" $Id: makewhatis.8,v 1.2 2014/04/25 12:13:15 schwarze Exp $ +.\" +.\" Copyright (c) 2011, 2012 Kristaps Dzonsons +.\" Copyright (c) 2011, 2012 Ingo Schwarze +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: April 25 2014 $ +.Dt MAKEWHATIS 8 +.Os +.Sh NAME +.Nm makewhatis +.Nd index UNIX manuals +.Sh SYNOPSIS +.Nm +.Op Fl aDnpQ +.Op Fl T Cm utf8 +.Op Fl C Ar file +.Nm +.Op Fl aDnpQ +.Op Fl T Cm utf8 +.Ar dir ... +.Nm +.Op Fl DnpQ +.Op Fl T Cm utf8 +.Fl d Ar dir +.Op Ar +.Nm +.Op Fl Dnp +.Op Fl T Cm utf8 +.Fl u Ar dir +.Op Ar +.Nm +.Op Fl DQ +.Fl t Ar +.Sh DESCRIPTION +The +.Nm +utility extracts keywords from +.Ux +manuals and indexes them in a database for fast retrieval by +.Xr apropos 1 , +.Xr whatis 1 , +and +.Xr man 1 Ns 's +.Fl k +option. +.Pp +By default, +.Nm +creates a database in each +.Ar dir +using the files +.Sm off +.Sy man Ar section Li / +.Op Ar arch Li / +.Ar title . section +.Sm on +and +.Sm off +.Sy cat Ar section Li / +.Op Ar arch Li / +.Ar title . Sy 0 +.Sm on +in that directory. +Existing databases are replaced. +If +.Ar dir +is not provided, +.Nm +uses the default paths stipulated by +.Xr manpath 1 , +or +.Xr man.conf 5 . +.Pp +The arguments are as follows: +.Bl -tag -width "-C file" +.It Fl a +Use all directories and files found below +.Ar dir ... . +.It Fl C Ar file +Specify an alternative configuration +.Ar file +in +.Xr man.conf 5 +format. +.It Fl D +Display all files added or removed to the index. +With a second +.Fl D , +also show all keyswords added for each file. +.It Fl d Ar dir +Merge (remove and re-add) +.Ar +to the database in +.Ar dir . +.It Fl n +Do not create or modify any database; scan and parse only, +and print manual page names and descriptions to standard output. +.It Fl p +Print warnings about potential problems with manual pages +to the standard error output. +.It Fl Q +Quickly build reduced-size databases +by reading only the NAME sections of manuals. +The resulting databases will usually contain names and descriptions only. +.It Fl T Cm utf8 +Use UTF-8 encoding instead of ASCII for strings stored in the databases. +.It Fl t Ar +Check the given +.Ar files +for potential problems. +Implies +.Fl a , +.Fl n , +and +.Fl p . +All diagnostic messages are printed to the standard output; +the standard error output is not used. +.It Fl u Ar dir +Remove +.Ar +from the database in +.Ar dir . +.El +.Pp +If fatal parse errors are encountered while parsing, the offending file +is printed to stderr, omitted from the index, and the parse continues +with the next input file. +.Sh FILES +.Bl -tag -width Ds +.It Pa mandoc.db +A database of manpages relative to the directory of the file. +This file is portable across architectures and systems, so long as the +manpage hierarchy it indexes does not change. +.It Pa /etc/man.conf +The default +.Xr man 1 +configuration file. +.El +.Sh EXIT STATUS +The +.Nm +utility exits with one of the following values: +.Pp +.Bl -tag -width Ds -compact +.It 0 +No errors occurred. +.It 5 +Invalid command line arguments were specified. +No input files have been read. +.It 6 +An operating system error occurred, for example memory exhaustion or an +error accessing input files. +Such errors cause +.Nm +to exit at once, possibly in the middle of parsing or formatting a file. +The output databases are corrupt and should be removed. +.El +.Sh SEE ALSO +.Xr apropos 1 , +.Xr man 1 , +.Xr whatis 1 , +.Xr man.conf 5 +.Sh HISTORY +A +.Nm +utility first appeared in +.Bx 2 . +It was rewritten in +.Xr perl 1 +for +.Ox 2.7 +and in C for +.Ox 5.6 . +.Pp +The +.Ar dir +argument first appeared in +.Nx 1.0 ; +the options +.Fl dpt +in +.Ox 2.7 ; +the option +.Fl u +in +.Ox 3.4 ; +and the options +.Fl aCDnQT +in +.Ox 5.6 . +.Sh AUTHORS +.An -nosplit +.An Bill Joy +wrote the original +.Bx +.Nm +in February 1979, +.An Marc Espie +started the Perl version in 2000, +and the current version of +.Nm +was written by +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv +and +.An Ingo Schwarze Aq Mt schwarze@openbsd.org . Property changes on: head/contrib/mdocml/makewhatis.8 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/mdocml/man.7 =================================================================== --- head/contrib/mdocml/man.7 (revision 274879) +++ head/contrib/mdocml/man.7 (revision 274880) @@ -1,957 +1,953 @@ -.\" $Id: man.7,v 1.120 2013/09/16 22:58:57 schwarze Exp $ +.\" $Id: man.7,v 1.127 2014/06/22 16:39:45 schwarze Exp $ .\" .\" Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons -.\" Copyright (c) 2011, 2012 Ingo Schwarze +.\" Copyright (c) 2011, 2012, 2013 Ingo Schwarze +.\" Copyright (c) 2010 Joerg Sonnenberger .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: September 16 2013 $ +.Dd $Mdocdate: June 22 2014 $ .Dt MAN 7 .Os .Sh NAME .Nm man .Nd legacy formatting language for manual pages .Sh DESCRIPTION Traditionally, the .Nm man language has been used to write .Ux manuals for the .Xr man 1 utility. It supports limited control of presentational details like fonts, indentation and spacing. This reference document describes the structure of manual pages and the syntax and usage of the man language. .Pp .Bf -emphasis Do not use .Nm to write your manuals: .Ef It lacks support for semantic markup. Use the .Xr mdoc 7 language, instead. .Pp In a .Nm document, lines beginning with the control character .Sq \&. are called .Dq macro lines . The first word is the macro name. It usually consists of two capital letters. For a list of available macros, see .Sx MACRO OVERVIEW . The words following the macro name are arguments to the macro. .Pp Lines not beginning with the control character are called .Dq text lines . They provide free-form text to be printed; the formatting of the text depends on the respective processing context: .Bd -literal -offset indent \&.SH Macro lines change control state. Text lines are interpreted within the current state. .Ed .Pp Many aspects of the basic syntax of the .Nm language are based on the .Xr roff 7 language; see the .Em LANGUAGE SYNTAX and .Em MACRO SYNTAX sections in the .Xr roff 7 manual for details, in particular regarding comments, escape sequences, whitespace, and quoting. .Sh MANUAL STRUCTURE Each .Nm document must contain the .Sx \&TH macro describing the document's section and title. It may occur anywhere in the document, although conventionally it appears as the first macro. .Pp Beyond .Sx \&TH , at least one macro or text line must appear in the document. .Pp The following is a well-formed skeleton .Nm file for a utility .Qq progname : .Bd -literal -offset indent \&.TH PROGNAME 1 2009-10-10 \&.SH NAME -\efBprogname\efR \e(en a description goes here +\efBprogname\efR \e(en one line about what it does \&.\e\(dq .SH LIBRARY -\&.\e\(dq For sections 2 & 3 only. +\&.\e\(dq For sections 2, 3, and 9 only. \&.\e\(dq Not used in OpenBSD. \&.SH SYNOPSIS -\efBprogname\efR [\efB\e-options\efR] arguments... +\efBprogname\efR [\efB\e-options\efR] \efIfile ...\efR \&.SH DESCRIPTION -The \efBfoo\efR utility processes files... +The \efBfoo\efR utility processes files ... +\&.\e\(dq .Sh CONTEXT +\&.\e\(dq For section 9 functions only. \&.\e\(dq .SH IMPLEMENTATION NOTES \&.\e\(dq Not used in OpenBSD. \&.\e\(dq .SH RETURN VALUES -\&.\e\(dq For sections 2, 3, & 9 only. +\&.\e\(dq For sections 2, 3, and 9 function return values only. \&.\e\(dq .SH ENVIRONMENT -\&.\e\(dq For sections 1, 6, 7, & 8 only. +\&.\e\(dq For sections 1, 6, 7, and 8 only. \&.\e\(dq .SH FILES \&.\e\(dq .SH EXIT STATUS -\&.\e\(dq For sections 1, 6, & 8 only. +\&.\e\(dq For sections 1, 6, and 8 only. \&.\e\(dq .SH EXAMPLES \&.\e\(dq .SH DIAGNOSTICS -\&.\e\(dq For sections 1, 4, 6, 7, & 8 only. +\&.\e\(dq For sections 1, 4, 6, 7, 8, and 9 printf/stderr messages only. \&.\e\(dq .SH ERRORS -\&.\e\(dq For sections 2, 3, & 9 only. +\&.\e\(dq For sections 2, 3, 4, and 9 errno settings only. \&.\e\(dq .SH SEE ALSO -\&.\e\(dq .BR foo ( 1 ) +\&.\e\(dq .BR foobar ( 1 ) \&.\e\(dq .SH STANDARDS \&.\e\(dq .SH HISTORY \&.\e\(dq .SH AUTHORS \&.\e\(dq .SH CAVEATS \&.\e\(dq .SH BUGS \&.\e\(dq .SH SECURITY CONSIDERATIONS \&.\e\(dq Not used in OpenBSD. .Ed .Pp The sections in a .Nm document are conventionally ordered as they appear above. Sections should be composed as follows: .Bl -ohang -offset indent .It Em NAME The name(s) and a short description of the documented material. The syntax for this is generally as follows: .Pp .D1 \efBname\efR \e(en description .It Em LIBRARY The name of the library containing the documented material, which is assumed to be a function in a section 2 or 3 manual. For functions in the C library, this may be as follows: .Pp .D1 Standard C Library (libc, -lc) .It Em SYNOPSIS Documents the utility invocation syntax, function call syntax, or device configuration. .Pp For the first, utilities (sections 1, 6, and 8), this is generally structured as follows: .Pp .D1 \efBname\efR [-\efBab\efR] [-\efBc\efR\efIarg\efR] \efBpath\efR... .Pp For the second, function calls (sections 2, 3, 9): .Pp .D1 \&.B char *name(char *\efIarg\efR); .Pp And for the third, configurations (section 4): .Pp .D1 \&.B name* at cardbus ? function ? .Pp Manuals not in these sections generally don't need a .Em SYNOPSIS . .It Em DESCRIPTION This expands upon the brief, one-line description in .Em NAME . It usually contains a break-down of the options (if documenting a command). +.It Em CONTEXT +This section lists the contexts in which functions can be called in section 9. +The contexts are autoconf, process, or interrupt. .It Em IMPLEMENTATION NOTES Implementation-specific notes should be kept here. This is useful when implementing standard functions that may have side effects or notable algorithmic implications. .It Em RETURN VALUES This section documents the return values of functions in sections 2, 3, and 9. .It Em ENVIRONMENT Documents any usages of environment variables, e.g., .Xr environ 7 . .It Em FILES Documents files used. It's helpful to document both the file name and a short description of how the file is used (created, modified, etc.). .It Em EXIT STATUS This section documents the command exit status for section 1, 6, and 8 utilities. Historically, this information was described in .Em DIAGNOSTICS , a practise that is now discouraged. .It Em EXAMPLES Example usages. This often contains snippets of well-formed, well-tested invocations. Make sure that examples work properly! .It Em DIAGNOSTICS Documents error conditions. -This is most useful in section 4 manuals. +In section 4 and 9 manuals, these are usually messages +printed by the kernel to the console and to the kernel log. +In section 1, 6, 7, and 8, these are usually messages +printed by userland programs to the standard error output. +.Pp Historically, this section was used in place of .Em EXIT STATUS for manuals in sections 1, 6, and 8; however, this practise is discouraged. .It Em ERRORS -Documents error handling in sections 2, 3, and 9. +Documents +.Xr errno 2 +settings in sections 2, 3, 4, and 9. .It Em SEE ALSO References other manuals with related topics. This section should exist for most manuals. .Pp .D1 \&.BR bar \&( 1 \&), .Pp Cross-references should conventionally be ordered first by section, then alphabetically. .It Em STANDARDS References any standards implemented or used, such as .Pp .D1 IEEE Std 1003.2 (\e(lqPOSIX.2\e(rq) .Pp If not adhering to any standards, the .Em HISTORY section should be used. .It Em HISTORY A brief history of the subject, including where support first appeared. .It Em AUTHORS Credits to the person or persons who wrote the code and/or documentation. Authors should generally be noted by both name and email address. .It Em CAVEATS Common misuses and misunderstandings should be explained in this section. .It Em BUGS Known bugs, limitations, and work-arounds should be described in this section. .It Em SECURITY CONSIDERATIONS Documents any security precautions that operators should consider. .El .Sh MACRO OVERVIEW This overview is sorted such that macros of similar purpose are listed together, to help find the best macro for any given purpose. Deprecated macros are not included in the overview, but can be found in the alphabetical reference below. .Ss Page header and footer meta-data .Bl -column "PP, LP, P" description .It Sx TH Ta set the title: Ar title section date Op Ar source Op Ar volume .It Sx AT Ta display AT&T UNIX version in the page footer (<= 1 argument) .It Sx UC Ta display BSD version in the page footer (<= 1 argument) .El .Ss Sections and paragraphs .Bl -column "PP, LP, P" description .It Sx SH Ta section header (one line) .It Sx SS Ta subsection header (one line) .It Sx PP , LP , P Ta start an undecorated paragraph (no arguments) .It Sx RS , RE Ta reset the left margin: Op Ar width .It Sx IP Ta indented paragraph: Op Ar head Op Ar width .It Sx TP Ta tagged paragraph: Op Ar width .It Sx HP Ta hanged paragraph: Op Ar width .It Sx PD Ta set vertical paragraph distance: Op Ar height .It Sx \&br Ta force output line break in text mode (no arguments) .It Sx \&sp Ta force vertical space: Op Ar height .It Sx fi , nf Ta fill mode and no-fill mode (no arguments) .It Sx in Ta additional indent: Op Ar width .El .Ss Physical markup .Bl -column "PP, LP, P" description .It Sx B Ta boldface font .It Sx I Ta italic font .It Sx R Ta roman (default) font .It Sx SB Ta small boldface font .It Sx SM Ta small roman font .It Sx BI Ta alternate between boldface and italic fonts .It Sx BR Ta alternate between boldface and roman fonts .It Sx IB Ta alternate between italic and boldface fonts .It Sx IR Ta alternate between italic and roman fonts .It Sx RB Ta alternate between roman and boldface fonts .It Sx RI Ta alternate between roman and italic fonts .El .Sh MACRO REFERENCE This section is a canonical reference to all macros, arranged alphabetically. For the scoping of individual macros, see .Sx MACRO SYNTAX . .Ss \&AT Sets the volume for the footer for compatibility with man pages from -.Tn AT&T UNIX +.At releases. The optional arguments specify which release it is from. .Ss \&B Text is rendered in bold face. .Pp See also .Sx \&I and .Sx \&R . .Ss \&BI Text is rendered alternately in bold face and italic. Thus, .Sq .BI this word and that causes .Sq this and .Sq and to render in bold face, while .Sq word and .Sq that render in italics. Whitespace between arguments is omitted in output. .Pp Examples: .Pp .Dl \&.BI bold italic bold italic .Pp The output of this example will be emboldened .Dq bold and italicised .Dq italic , with spaces stripped between arguments. .Pp See also .Sx \&IB , .Sx \&BR , .Sx \&RB , .Sx \&RI , and .Sx \&IR . .Ss \&BR Text is rendered alternately in bold face and roman (the default font). Whitespace between arguments is omitted in output. .Pp See .Sx \&BI for an equivalent example. .Pp See also .Sx \&BI , .Sx \&IB , .Sx \&RB , .Sx \&RI , and .Sx \&IR . .Ss \&DT Has no effect. Included for compatibility. .Ss \&EE This is a non-standard GNU extension, included only for compatibility. In .Xr mandoc 1 , it does the same as .Sx \&fi . .Ss \&EX This is a non-standard GNU extension, included only for compatibility. In .Xr mandoc 1 , it does the same as .Sx \&nf . .Ss \&HP Begin a paragraph whose initial output line is left-justified, but subsequent output lines are indented, with the following syntax: .Bd -filled -offset indent .Pf \. Sx \&HP .Op Cm width .Ed .Pp The .Cm width argument is a .Xr roff 7 scaling width. If specified, it's saved for later paragraph left-margins; if unspecified, the saved or default width is used. .Pp See also .Sx \&IP , .Sx \&LP , .Sx \&P , .Sx \&PP , and .Sx \&TP . .Ss \&I Text is rendered in italics. .Pp See also .Sx \&B and .Sx \&R . .Ss \&IB Text is rendered alternately in italics and bold face. Whitespace between arguments is omitted in output. .Pp See .Sx \&BI for an equivalent example. .Pp See also .Sx \&BI , .Sx \&BR , .Sx \&RB , .Sx \&RI , and .Sx \&IR . .Ss \&IP Begin an indented paragraph with the following syntax: .Bd -filled -offset indent .Pf \. Sx \&IP .Op Cm head Op Cm width .Ed .Pp The .Cm width argument is a .Xr roff 7 scaling width defining the left margin. It's saved for later paragraph left-margins; if unspecified, the saved or default width is used. .Pp The .Cm head argument is used as a leading term, flushed to the left margin. This is useful for bulleted paragraphs and so on. .Pp See also .Sx \&HP , .Sx \&LP , .Sx \&P , .Sx \&PP , and .Sx \&TP . .Ss \&IR Text is rendered alternately in italics and roman (the default font). Whitespace between arguments is omitted in output. .Pp See .Sx \&BI for an equivalent example. .Pp See also .Sx \&BI , .Sx \&IB , .Sx \&BR , .Sx \&RB , and .Sx \&RI . .Ss \&LP Begin an undecorated paragraph. The scope of a paragraph is closed by a subsequent paragraph, sub-section, section, or end of file. The saved paragraph left-margin width is reset to the default. .Pp See also .Sx \&HP , .Sx \&IP , .Sx \&P , .Sx \&PP , and .Sx \&TP . .Ss \&OP Optional command-line argument. This is a non-standard GNU extension, included only for compatibility. It has the following syntax: .Bd -filled -offset indent .Pf \. Sx \&OP .Cm key Op Cm value .Ed .Pp The .Cm key is usually a command-line flag and .Cm value its argument. .Ss \&P Synonym for .Sx \&LP . .Pp See also .Sx \&HP , .Sx \&IP , .Sx \&LP , .Sx \&PP , and .Sx \&TP . .Ss \&PD Specify the vertical space to be inserted before each new paragraph. .br The syntax is as follows: .Bd -filled -offset indent .Pf \. Sx \&PD .Op Cm height .Ed .Pp The .Cm height argument is a .Xr roff 7 scaling width. It defaults to .Cm 1v . If the unit is omitted, .Cm v is assumed. .Pp This macro affects the spacing before any subsequent instances of .Sx \&HP , .Sx \&IP , .Sx \&LP , .Sx \&P , .Sx \&PP , .Sx \&SH , .Sx \&SS , and .Sx \&TP . .Ss \&PP Synonym for .Sx \&LP . .Pp See also .Sx \&HP , .Sx \&IP , .Sx \&LP , .Sx \&P , and .Sx \&TP . .Ss \&R Text is rendered in roman (the default font). .Pp See also .Sx \&I and .Sx \&B . .Ss \&RB Text is rendered alternately in roman (the default font) and bold face. Whitespace between arguments is omitted in output. .Pp See .Sx \&BI for an equivalent example. .Pp See also .Sx \&BI , .Sx \&IB , .Sx \&BR , .Sx \&RI , and .Sx \&IR . .Ss \&RE Explicitly close out the scope of a prior .Sx \&RS . The default left margin is restored to the state of the original .Sx \&RS invocation. .Ss \&RI Text is rendered alternately in roman (the default font) and italics. Whitespace between arguments is omitted in output. .Pp See .Sx \&BI for an equivalent example. .Pp See also .Sx \&BI , .Sx \&IB , .Sx \&BR , .Sx \&RB , and .Sx \&IR . .Ss \&RS Temporarily reset the default left margin. This has the following syntax: .Bd -filled -offset indent .Pf \. Sx \&RS .Op Cm width .Ed .Pp The .Cm width argument is a .Xr roff 7 scaling width. If not specified, the saved or default width is used. .Pp See also .Sx \&RE . .Ss \&SB Text is rendered in small size (one point smaller than the default font) bold face. .Ss \&SH Begin a section. The scope of a section is only closed by another section or the end of file. The paragraph left-margin width is reset to the default. .Ss \&SM Text is rendered in small size (one point smaller than the default font). .Ss \&SS Begin a sub-section. The scope of a sub-section is closed by a subsequent sub-section, section, or end of file. The paragraph left-margin width is reset to the default. .Ss \&TH Sets the title of the manual page with the following syntax: .Bd -filled -offset indent .Pf \. Sx \&TH .Ar title section date .Op Ar source Op Ar volume .Ed .Pp Conventionally, the document .Ar title is given in all caps. The recommended .Ar date format is .Sy YYYY-MM-DD as specified in the ISO-8601 standard; if the argument does not conform, it is printed verbatim. If the .Ar date is empty or not specified, the current date is used. The optional .Ar source string specifies the organisation providing the utility. The .Ar volume string replaces the default rendered volume, which is dictated by the manual section. .Pp Examples: .Pp .Dl \&.TH CVS 5 "1992-02-12" GNU .Ss \&TP Begin a paragraph where the head, if exceeding the indentation width, is followed by a newline; if not, the body follows on the same line after a buffer to the indentation width. Subsequent output lines are indented. The syntax is as follows: .Bd -filled -offset indent .Pf \. Sx \&TP .Op Cm width .Ed .Pp The .Cm width argument is a .Xr roff 7 scaling width. If specified, it's saved for later paragraph left-margins; if unspecified, the saved or default width is used. .Pp See also .Sx \&HP , .Sx \&IP , .Sx \&LP , .Sx \&P , and .Sx \&PP . .Ss \&UC Sets the volume for the footer for compatibility with man pages from .Bx releases. The optional first argument specifies which release it is from. +.Ss \&UE +End a uniform resource identifier block. +This is a non-standard GNU extension, included only for compatibility. +See +.Sx \&UE . +.Ss \&UR +Begin a uniform resource identifier block. +This is a non-standard GNU extension, included only for compatibility. +It has the following syntax: +.Bd -literal -offset indent +.Pf \. Sx \&UR Ar uri +link description to be shown +.Pf \. Sx UE +.Ed .Ss \&br Breaks the current line. Consecutive invocations have no further effect. .Pp See also .Sx \&sp . .Ss \&fi End literal mode begun by .Sx \&nf . -.Ss \&ft -Change the current font mode. -See -.Sx Text Decoration -for a listing of available font modes. .Ss \&in Indent relative to the current indentation: .Pp .D1 Pf \. Sx \&in Op Cm width .Pp If .Cm width is signed, the new offset is relative. Otherwise, it is absolute. This value is reset upon the next paragraph, section, or sub-section. .Ss \&na Don't align to the right margin. .Ss \&nf Begin literal mode: all subsequent free-form lines have their end of line boundaries preserved. May be ended by .Sx \&fi . Literal mode is implicitly ended by .Sx \&SH or .Sx \&SS . .Ss \&sp Insert vertical spaces into output with the following syntax: .Bd -filled -offset indent .Pf \. Sx \&sp .Op Cm height .Ed .Pp The .Cm height argument is a scaling width as described in .Xr roff 7 . If 0, this is equivalent to the .Sx \&br macro. Defaults to 1, if unspecified. .Pp See also .Sx \&br . .Sh MACRO SYNTAX The .Nm macros are classified by scope: line scope or block scope. Line macros are only scoped to the current line (and, in some situations, the subsequent line). Block macros are scoped to the current line and subsequent lines until closed by another block macro. .Ss Line Macros Line macros are generally scoped to the current line, with the body consisting of zero or more arguments. If a macro is scoped to the next line and the line arguments are empty, the next line, which must be text, is used instead. Thus: .Bd -literal -offset indent \&.I foo .Ed .Pp is equivalent to .Sq \&.I foo . If next-line macros are invoked consecutively, only the last is used. If a next-line macro is followed by a non-next-line macro, an error is raised, except for .Sx \&br , .Sx \&sp , and .Sx \&na . .Pp The syntax is as follows: .Bd -literal -offset indent \&.YO \(lBbody...\(rB \(lBbody...\(rB .Ed .Bl -column "MacroX" "ArgumentsX" "ScopeXXXXX" "CompatX" -offset indent .It Em Macro Ta Em Arguments Ta Em Scope Ta Em Notes .It Sx \&AT Ta <=1 Ta current Ta \& .It Sx \&B Ta n Ta next-line Ta \& .It Sx \&BI Ta n Ta current Ta \& .It Sx \&BR Ta n Ta current Ta \& .It Sx \&DT Ta 0 Ta current Ta \& +.It Sx \&EE Ta 0 Ta current Ta compat +.It Sx \&EX Ta 0 Ta current Ta compat .It Sx \&I Ta n Ta next-line Ta \& .It Sx \&IB Ta n Ta current Ta \& .It Sx \&IR Ta n Ta current Ta \& .It Sx \&OP Ta 0, 1 Ta current Ta compat +.It Sx \&PD Ta 1 Ta current Ta \& .It Sx \&R Ta n Ta next-line Ta \& .It Sx \&RB Ta n Ta current Ta \& .It Sx \&RI Ta n Ta current Ta \& .It Sx \&SB Ta n Ta next-line Ta \& .It Sx \&SM Ta n Ta next-line Ta \& .It Sx \&TH Ta >1, <6 Ta current Ta \& .It Sx \&UC Ta <=1 Ta current Ta \& .It Sx \&br Ta 0 Ta current Ta compat .It Sx \&fi Ta 0 Ta current Ta compat -.It Sx \&ft Ta 1 Ta current Ta compat .It Sx \&in Ta 1 Ta current Ta compat .It Sx \&na Ta 0 Ta current Ta compat .It Sx \&nf Ta 0 Ta current Ta compat .It Sx \&sp Ta 1 Ta current Ta compat .El .Pp Macros marked as .Qq compat are included for compatibility with the significant corpus of existing manuals that mix dialects of roff. These macros should not be used for portable .Nm manuals. .Ss Block Macros Block macros comprise a head and body. As with in-line macros, the head is scoped to the current line and, in one circumstance, the next line (the next-line stipulations as in .Sx Line Macros apply here as well). .Pp The syntax is as follows: .Bd -literal -offset indent \&.YO \(lBhead...\(rB \(lBhead...\(rB \(lBbody...\(rB .Ed .Pp The closure of body scope may be to the section, where a macro is closed by .Sx \&SH ; sub-section, closed by a section or .Sx \&SS ; part, closed by a section, sub-section, or .Sx \&RE ; or paragraph, closed by a section, sub-section, part, .Sx \&HP , .Sx \&IP , .Sx \&LP , .Sx \&P , .Sx \&PP , or .Sx \&TP . No closure refers to an explicit block closing macro. .Pp As a rule, block macros may not be nested; thus, calling a block macro while another block macro scope is open, and the open scope is not implicitly closed, is syntactically incorrect. .Bl -column "MacroX" "ArgumentsX" "Head ScopeX" "sub-sectionX" "compatX" -offset indent .It Em Macro Ta Em Arguments Ta Em Head Scope Ta Em Body Scope Ta Em Notes .It Sx \&HP Ta <2 Ta current Ta paragraph Ta \& .It Sx \&IP Ta <3 Ta current Ta paragraph Ta \& .It Sx \&LP Ta 0 Ta current Ta paragraph Ta \& .It Sx \&P Ta 0 Ta current Ta paragraph Ta \& .It Sx \&PP Ta 0 Ta current Ta paragraph Ta \& .It Sx \&RE Ta 0 Ta current Ta none Ta compat .It Sx \&RS Ta 1 Ta current Ta part Ta compat .It Sx \&SH Ta >0 Ta next-line Ta section Ta \& .It Sx \&SS Ta >0 Ta next-line Ta sub-section Ta \& .It Sx \&TP Ta n Ta next-line Ta paragraph Ta \& +.It Sx \&UE Ta 0 Ta current Ta none Ta compat +.It Sx \&UR Ta 1 Ta current Ta part Ta compat .El .Pp Macros marked .Qq compat are as mentioned in .Sx Line Macros . .Pp If a block macro is next-line scoped, it may only be followed by in-line macros for decorating text. .Ss Font handling In .Nm documents, both .Sx Physical markup macros and .Xr roff 7 .Ql \ef font escape sequences can be used to choose fonts. In text lines, the effect of manual font selection by escape sequences only lasts until the next macro invocation; in macro lines, it only lasts until the end of the macro scope. Note that macros like .Sx \&BR open and close a font scope for each argument. .Sh COMPATIBILITY -This section documents areas of questionable portability between +This section mentions some areas of questionable portability between implementations of the .Nm language. +More incompatibilities exist. .Pp .Bl -dash -compact .It Do not depend on .Sx \&SH or .Sx \&SS to close out a literal context opened with .Sx \&nf . This behaviour may not be portable. .It -In quoted literals, GNU troff allowed pair-wise double-quotes to produce -a standalone double-quote in formatted output. -It is not known whether this behaviour is exhibited by other formatters. -.It troff suppresses a newline before .Sq \(aq macro output; in mandoc, it is an alias for the standard .Sq \&. control character. .It -The -.Sq \eh -.Pq horizontal position , -.Sq \ev -.Pq vertical position , -.Sq \em -.Pq text colour , -.Sq \eM -.Pq text filling colour , -.Sq \ez -.Pq zero-length character , -.Sq \ew -.Pq string length , -.Sq \ek -.Pq horizontal position marker , -.Sq \eo -.Pq text overstrike , -and -.Sq \es -.Pq text size -escape sequences are all discarded in mandoc. -.It -The -.Sq \ef -scaling unit is accepted by mandoc, but rendered as the default unit. -.It -The -.Sx \&sp -macro does not accept negative values in mandoc. -In GNU troff, this would result in strange behaviour. -.It In page header lines, GNU troff versions up to and including 1.21 only print .Ar volume names explicitly specified in the .Sx \&TH macro; mandoc and newer groff print the default volume name corresponding to the .Ar section number when no .Ar volume is given, like in .Xr mdoc 7 . .El .Pp The -.Sx OP -macro is part of the extended +.Sx EE , +.Sx EX , +.Sx OP , +.Sx UE , +and +.Sx UR +macros are part of the GNU extended .Nm macro set, and may not be portable to non-GNU troff implementations. .Sh SEE ALSO .Xr man 1 , .Xr mandoc 1 , .Xr eqn 7 , .Xr mandoc_char 7 , .Xr mdoc 7 , .Xr roff 7 , .Xr tbl 7 .Sh HISTORY The .Nm language first appeared as a macro package for the roff typesetting system in .At v7 . It was later rewritten by James Clark as a macro package for groff. Eric S. Raymond wrote the extended .Nm macros for groff in 2007. The stand-alone implementation that is part of the .Xr mandoc 1 utility written by Kristaps Dzonsons appeared in .Ox 4.6 . .Sh AUTHORS This .Nm reference was written by .An Kristaps Dzonsons Aq Mt kristaps@bsd.lv . .Sh CAVEATS Do not use this language. Use .Xr mdoc 7 , instead. Index: head/contrib/mdocml/man.c =================================================================== --- head/contrib/mdocml/man.c (revision 274879) +++ head/contrib/mdocml/man.c (revision 274880) @@ -1,698 +1,704 @@ -/* $Id: man.c,v 1.121 2013/11/10 22:54:40 schwarze Exp $ */ +/* $Id: man.c,v 1.137 2014/08/01 21:24:17 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2013, 2014 Ingo Schwarze + * Copyright (c) 2011 Joerg Sonnenberger * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include +#include #include #include #include #include #include "man.h" #include "mandoc.h" +#include "mandoc_aux.h" #include "libman.h" #include "libmandoc.h" -const char *const __man_macronames[MAN_MAX] = { +const char *const __man_macronames[MAN_MAX] = { "br", "TH", "SH", "SS", - "TP", "LP", "PP", "P", + "TP", "LP", "PP", "P", "IP", "HP", "SM", "SB", "BI", "IB", "BR", "RB", "R", "B", "I", "IR", "RI", "na", "sp", "nf", "fi", "RE", "RS", "DT", "UC", "PD", "AT", "in", "ft", "OP", "EX", "EE", - "UR", "UE" + "UR", "UE", "ll" }; const char * const *man_macronames = __man_macronames; -static struct man_node *man_node_alloc(struct man *, int, int, +static struct man_node *man_node_alloc(struct man *, int, int, enum man_type, enum mant); -static int man_node_append(struct man *, +static int man_node_append(struct man *, struct man_node *); static void man_node_free(struct man_node *); -static void man_node_unlink(struct man *, +static void man_node_unlink(struct man *, struct man_node *); static int man_ptext(struct man *, int, char *, int); static int man_pmacro(struct man *, int, char *, int); static void man_free1(struct man *); static void man_alloc1(struct man *); static int man_descope(struct man *, int, int); const struct man_node * man_node(const struct man *man) { - assert( ! (MAN_HALT & man->flags)); return(man->first); } - const struct man_meta * man_meta(const struct man *man) { - assert( ! (MAN_HALT & man->flags)); return(&man->meta); } - void man_reset(struct man *man) { man_free1(man); man_alloc1(man); } - void man_free(struct man *man) { man_free1(man); free(man); } - struct man * -man_alloc(struct roff *roff, struct mparse *parse) +man_alloc(struct roff *roff, struct mparse *parse, int quick) { struct man *p; p = mandoc_calloc(1, sizeof(struct man)); man_hash_init(); p->parse = parse; + p->quick = quick; p->roff = roff; man_alloc1(p); return(p); } - int man_endparse(struct man *man) { - assert( ! (MAN_HALT & man->flags)); - if (man_macroend(man)) - return(1); - man->flags |= MAN_HALT; - return(0); + return(man_macroend(man)); } - int man_parseln(struct man *man, int ln, char *buf, int offs) { man->flags |= MAN_NEWLINE; - assert( ! (MAN_HALT & man->flags)); - return (roff_getcontrol(man->roff, buf, &offs) ? - man_pmacro(man, ln, buf, offs) : - man_ptext(man, ln, buf, offs)); + man_pmacro(man, ln, buf, offs) : + man_ptext(man, ln, buf, offs)); } - static void man_free1(struct man *man) { if (man->first) man_node_delete(man, man->first); if (man->meta.title) free(man->meta.title); if (man->meta.source) free(man->meta.source); if (man->meta.date) free(man->meta.date); if (man->meta.vol) free(man->meta.vol); if (man->meta.msec) free(man->meta.msec); } - static void man_alloc1(struct man *man) { 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; } static int man_node_append(struct man *man, struct man_node *p) { assert(man->last); assert(man->first); assert(MAN_ROOT != p->type); switch (man->next) { - case (MAN_NEXT_SIBLING): + case MAN_NEXT_SIBLING: man->last->next = p; p->prev = man->last; p->parent = man->last->parent; break; - case (MAN_NEXT_CHILD): + case MAN_NEXT_CHILD: man->last->child = p; p->parent = man->last; break; default: abort(); /* NOTREACHED */ } - + assert(p->parent); p->parent->nchild++; - if ( ! man_valid_pre(man, p)) - return(0); - switch (p->type) { - case (MAN_HEAD): + case MAN_BLOCK: + if (p->tok == MAN_SH || p->tok == MAN_SS) + man->flags &= ~MAN_LITERAL; + break; + case MAN_HEAD: assert(MAN_BLOCK == p->parent->type); p->parent->head = p; break; - case (MAN_TAIL): + case MAN_TAIL: assert(MAN_BLOCK == p->parent->type); p->parent->tail = p; break; - case (MAN_BODY): + case MAN_BODY: assert(MAN_BLOCK == p->parent->type); p->parent->body = p; break; default: break; } man->last = p; switch (p->type) { - case (MAN_TBL): + case MAN_TBL: /* FALLTHROUGH */ - case (MAN_TEXT): + case MAN_TEXT: if ( ! man_valid_post(man)) return(0); break; default: break; } return(1); } - static struct man_node * -man_node_alloc(struct man *man, 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; p = mandoc_calloc(1, sizeof(struct man_node)); p->line = line; p->pos = pos; p->type = type; p->tok = tok; if (MAN_NEWLINE & man->flags) p->flags |= MAN_LINE; man->flags &= ~MAN_NEWLINE; return(p); } - int man_elem_alloc(struct man *man, int line, int pos, enum mant tok) { struct man_node *p; p = man_node_alloc(man, line, pos, MAN_ELEM, tok); if ( ! man_node_append(man, p)) return(0); man->next = MAN_NEXT_CHILD; return(1); } - int man_tail_alloc(struct man *man, int line, int pos, enum mant tok) { struct man_node *p; p = man_node_alloc(man, line, pos, MAN_TAIL, tok); if ( ! man_node_append(man, p)) return(0); man->next = MAN_NEXT_CHILD; return(1); } - int man_head_alloc(struct man *man, int line, int pos, enum mant tok) { struct man_node *p; p = man_node_alloc(man, line, pos, MAN_HEAD, tok); if ( ! man_node_append(man, p)) return(0); man->next = MAN_NEXT_CHILD; return(1); } - int man_body_alloc(struct man *man, int line, int pos, enum mant tok) { struct man_node *p; p = man_node_alloc(man, line, pos, MAN_BODY, tok); if ( ! man_node_append(man, p)) return(0); man->next = MAN_NEXT_CHILD; return(1); } - int man_block_alloc(struct man *man, int line, int pos, enum mant tok) { struct man_node *p; p = man_node_alloc(man, line, pos, MAN_BLOCK, tok); if ( ! man_node_append(man, p)) return(0); man->next = MAN_NEXT_CHILD; return(1); } int man_word_alloc(struct man *man, int line, int pos, const char *word) { struct man_node *n; n = man_node_alloc(man, line, pos, MAN_TEXT, MAN_MAX); n->string = roff_strdup(man->roff, word); if ( ! man_node_append(man, n)) return(0); man->next = MAN_NEXT_SIBLING; return(1); } - /* * Free all of the resources held by a node. This does NOT unlink a * node from its context; for that, see man_node_unlink(). */ static void man_node_free(struct man_node *p) { if (p->string) free(p->string); free(p); } - void man_node_delete(struct man *man, struct man_node *p) { while (p->child) man_node_delete(man, p->child); man_node_unlink(man, p); man_node_free(p); } int man_addeqn(struct man *man, const struct eqn *ep) { struct man_node *n; - assert( ! (MAN_HALT & man->flags)); - n = man_node_alloc(man, ep->ln, ep->pos, MAN_EQN, MAN_MAX); n->eqn = ep; if ( ! man_node_append(man, n)) return(0); man->next = MAN_NEXT_SIBLING; return(man_descope(man, ep->ln, ep->pos)); } int man_addspan(struct man *man, const struct tbl_span *sp) { struct man_node *n; - assert( ! (MAN_HALT & man->flags)); - n = man_node_alloc(man, sp->line, 0, MAN_TBL, MAN_MAX); n->span = sp; if ( ! man_node_append(man, n)) return(0); man->next = MAN_NEXT_SIBLING; return(man_descope(man, sp->line, 0)); } static int man_descope(struct man *man, int line, int offs) { /* * Co-ordinate what happens with having a next-line scope open: * first close out the element scope (if applicable), then close * out the block scope (also if applicable). */ if (MAN_ELINE & man->flags) { man->flags &= ~MAN_ELINE; - if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX)) + if ( ! man_unscope(man, man->last->parent)) return(0); } if ( ! (MAN_BLINE & man->flags)) return(1); man->flags &= ~MAN_BLINE; - if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX)) + if ( ! man_unscope(man, man->last->parent)) return(0); return(man_body_alloc(man, line, offs, man->last->tok)); } static int man_ptext(struct man *man, int line, char *buf, int offs) { int i; /* Literal free-form text whitespace is preserved. */ if (MAN_LITERAL & man->flags) { if ( ! man_word_alloc(man, line, offs, buf + offs)) return(0); return(man_descope(man, line, offs)); } 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_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); } - /* + /* * Warn if the last un-escaped character is whitespace. Then - * strip away the remaining spaces (tabs stay!). + * strip away the remaining spaces (tabs stay!). */ i = (int)strlen(buf); assert(i); if (' ' == buf[i - 1] || '\t' == buf[i - 1]) { if (i > 1 && '\\' != buf[i - 2]) - man_pmsg(man, line, i - 1, MANDOCERR_EOLNSPACE); + mandoc_msg(MANDOCERR_SPACE_EOL, man->parse, + line, i - 1, NULL); for (--i; i && ' ' == buf[i]; i--) /* Spin back to non-space. */ ; /* Jump ahead of escaped whitespace. */ i += '\\' == buf[i] ? 2 : 1; buf[i] = '\0'; } if ( ! man_word_alloc(man, line, offs, buf + offs)) return(0); /* * End-of-sentence check. If the last character is an unescaped * EOS character, then flag the node as being the end of a * sentence. The front-end will know how to interpret this. */ assert(i); - if (mandoc_eos(buf, (size_t)i, 0)) + if (mandoc_eos(buf, (size_t)i)) man->last->flags |= MAN_EOS; return(man_descope(man, line, offs)); } static int man_pmacro(struct man *man, int ln, char *buf, int offs) { - int i, ppos; - enum mant tok; char mac[5]; struct man_node *n; + enum mant tok; + int i, ppos; + int bline; if ('"' == buf[offs]) { - man_pmsg(man, ln, offs, MANDOCERR_BADCOMMENT); + mandoc_msg(MANDOCERR_COMMENT_BAD, man->parse, + ln, offs, NULL); return(1); } else if ('\0' == buf[offs]) return(1); ppos = offs; /* * Copy the first word into a nil-terminated buffer. * Stop copying when a tab, space, or eoln is encountered. */ i = 0; - while (i < 4 && '\0' != buf[offs] && - ' ' != buf[offs] && '\t' != buf[offs]) + while (i < 4 && '\0' != buf[offs] && ' ' != buf[offs] && + '\t' != buf[offs]) mac[i++] = buf[offs++]; mac[i] = '\0'; tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX; if (MAN_MAX == tok) { - mandoc_vmsg(MANDOCERR_MACRO, man->parse, ln, - ppos, "%s", buf + ppos - 1); + mandoc_msg(MANDOCERR_MACRO, man->parse, + ln, ppos, buf + ppos - 1); return(1); } /* The macro is sane. Jump to the next word. */ while (buf[offs] && ' ' == buf[offs]) offs++; - /* + /* * Trailing whitespace. Note that tabs are allowed to be passed * into the parser as "text", so we only warn about spaces here. */ if ('\0' == buf[offs] && ' ' == buf[offs - 1]) - man_pmsg(man, ln, offs - 1, MANDOCERR_EOLNSPACE); + mandoc_msg(MANDOCERR_SPACE_EOL, man->parse, + ln, offs - 1, NULL); - /* + /* * Remove prior ELINE macro, as it's being clobbered by a new * macro. Note that NSCOPED macros do not close out ELINE * macros---they don't print text---so we let those slip by. */ if ( ! (MAN_NSCOPED & man_macros[tok].flags) && man->flags & MAN_ELINE) { n = man->last; assert(MAN_TEXT != n->type); /* Remove repeated NSCOPED macros causing ELINE. */ if (MAN_NSCOPED & man_macros[n->tok].flags) n = n->parent; - mandoc_vmsg(MANDOCERR_LINESCOPE, man->parse, n->line, + mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse, n->line, n->pos, "%s breaks %s", man_macronames[tok], man_macronames[n->tok]); man_node_delete(man, n); man->flags &= ~MAN_ELINE; } /* * Remove prior BLINE macro that is being clobbered. */ if ((man->flags & MAN_BLINE) && (MAN_BSCOPE & man_macros[tok].flags)) { n = man->last; /* Might be a text node like 8 in * .TP 8 * .SH foo */ if (MAN_TEXT == n->type) n = n->parent; /* Remove element that didn't end BLINE, if any. */ if ( ! (MAN_BSCOPE & man_macros[n->tok].flags)) n = n->parent; assert(MAN_HEAD == n->type); n = n->parent; assert(MAN_BLOCK == n->type); assert(MAN_SCOPED & man_macros[n->tok].flags); - mandoc_vmsg(MANDOCERR_LINESCOPE, man->parse, n->line, + mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse, n->line, n->pos, "%s breaks %s", man_macronames[tok], man_macronames[n->tok]); man_node_delete(man, n); man->flags &= ~MAN_BLINE; } - /* - * Save the fact that we're in the next-line for a block. In - * this way, embedded roff instructions can "remember" state - * when they exit. - */ + /* Remember whether we are in next-line scope for a block head. */ - if (MAN_BLINE & man->flags) - man->flags |= MAN_BPLINE; + bline = man->flags & MAN_BLINE; /* Call to handler... */ assert(man_macros[tok].fp); if ( ! (*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf)) - goto err; + return(0); - /* - * We weren't in a block-line scope when entering the - * above-parsed macro, so return. - */ + /* In quick mode (for mandocdb), abort after the NAME section. */ - if ( ! (MAN_BPLINE & man->flags)) { - man->flags &= ~MAN_ILINE; - return(1); + if (man->quick && MAN_SH == tok) { + n = man->last; + if (MAN_BODY == n->type && + strcmp(n->prev->child->string, "NAME")) + return(2); } - man->flags &= ~MAN_BPLINE; /* - * If we're in a block scope, then allow this macro to slip by - * without closing scope around it. + * If we are in a next-line scope for a block head, + * close it out now and switch to the body, + * unless the next-line scope is allowed to continue. */ - if (MAN_ILINE & man->flags) { - man->flags &= ~MAN_ILINE; + if ( ! bline || man->flags & MAN_ELINE || + man_macros[tok].flags & MAN_NSCOPED) return(1); - } - /* - * If we've opened a new next-line element scope, then return - * now, as the next line will close out the block scope. - */ - - if (MAN_ELINE & man->flags) - return(1); - - /* Close out the block scope opened in the prior line. */ - assert(MAN_BLINE & man->flags); man->flags &= ~MAN_BLINE; - if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX)) + if ( ! man_unscope(man, man->last->parent)) return(0); return(man_body_alloc(man, ln, ppos, man->last->tok)); - -err: /* Error out. */ - - man->flags |= MAN_HALT; - return(0); } /* * 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 *man, struct man_node *n) { /* Adjust siblings. */ if (n->prev) n->prev->next = n->next; if (n->next) n->next->prev = n->prev; /* Adjust parent. */ if (n->parent) { n->parent->nchild--; if (n->parent->child == n) n->parent->child = n->prev ? n->prev : n->next; } /* Adjust parse point, if applicable. */ if (man && man->last == n) { /*XXX: this can occur when bailing from validation. */ /*assert(NULL == n->next);*/ if (n->prev) { man->last = n->prev; man->next = MAN_NEXT_SIBLING; } else { man->last = n->parent; man->next = MAN_NEXT_CHILD; } } if (man && man->first == n) man->first = NULL; } const struct mparse * man_mparse(const struct man *man) { assert(man && man->parse); return(man->parse); +} + +void +man_deroff(char **dest, const struct man_node *n) +{ + char *cp; + size_t sz; + + if (MAN_TEXT != n->type) { + for (n = n->child; n; n = n->next) + man_deroff(dest, n); + return; + } + + /* Skip leading whitespace and escape sequences. */ + + cp = n->string; + while ('\0' != *cp) { + if ('\\' == *cp) { + cp++; + mandoc_escape((const char **)&cp, NULL, NULL); + } else if (isspace((unsigned char)*cp)) + cp++; + else + break; + } + + /* Skip trailing whitespace. */ + + for (sz = strlen(cp); sz; sz--) + if (0 == isspace((unsigned char)cp[sz-1])) + break; + + /* Skip empty strings. */ + + if (0 == sz) + return; + + if (NULL == *dest) { + *dest = mandoc_strndup(cp, sz); + return; + } + + mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp); + free(*dest); + *dest = cp; } Index: head/contrib/mdocml/man.cgi.8 =================================================================== --- head/contrib/mdocml/man.cgi.8 (nonexistent) +++ head/contrib/mdocml/man.cgi.8 (revision 274880) @@ -0,0 +1,409 @@ +.\" $Id: man.cgi.8,v 1.9 2014/07/22 18:14:13 schwarze Exp $ +.\" +.\" Copyright (c) 2014 Ingo Schwarze +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: July 22 2014 $ +.Dt MAN.CGI 8 +.Os +.Sh NAME +.Nm man.cgi +.Nd CGI program to search and display manual pages +.Sh DESCRIPTION +The +.Nm +CGI program searches for manual pages on a WWW server +and displays them to HTTP clients, +providing functionality equivalent to the +.Xr apropos 1 +and +.Xr man 1 +utilities. +It can use multiple manual trees in parallel. +.Ss HTML search interface +At the top of each generated HTML page, +.Nm +displays a search form containing these elements: +.Bl -enum +.It +An input box for search queries, expecting +either a name of a manual page or an +.Ar expression +using the syntax described in the +.Xr apropos 1 +manual; filling this in is required for each search. +.It +A +.Dq Submit +button to send a search request from the client to the server. +.It +A +.Dq Reset +button to undo any changes to the input boxes and the dropdown menus +and reset them to the values contained in the +.Ev QUERY_STRING . +.It +Radio buttons to select pages either by name like in +.Xr man 1 +or using +.Xr apropos 1 +queries. +.It +A dropdown menu to optionally select a manual section. +If one is provided, it has the same effect as the +.Xr man 1 +and +.Xr apropos 1 +.Fl s +option. +Otherwise, pages from all sections are shown. +.It +A dropdown menu to optionally select an architecture. +If one is provided, it has the same effect as the +.Xr man 1 +and +.Xr apropos 1 +.Fl S +option. +By default, pages for all architectures are shown. +.It +A dropdown menu to select a manual tree. +If the configuration file +.Pa /var/www/man/manpath.conf +contains only one manpath, the dropdown menu is not shown. +By default, the first manpath given in the file is used. +.El +.Ss Program output +The +.Nm +program generates five kinds of output pages: +.Bl -tag -width Ds +.It The index page. +This is returned when calling +.Nm +without +.Ev PATH_INFO +and without a +.Ev QUERY_STRING . +It serves as a starting point for using the program +and shows the search form only. +.It A list page. +Lists are returned when searches match more than one manual page. +The first column shows the names and section numbers of manuals +as clickable links. +The second column shows the one-line descriptions of the manuals. +.It A manual page. +This output format is used when a search matches exactly one +manual page, or when a link on a list page or an +.Ic \&Xr +link on another manual page is followed. +.It A no-result page. +This is shown when a search request returns no results - +eiher because it violates the query syntax, or because +the search does not match any manual pages. +.It \&An error page. +This cannot happen by merely clicking the +.Dq Search +button, but only by manually entering an invalid URI. +It does not show the search form, but only an error message +and a link back to the index page. +.El +.Ss Setup +For each manual tree, create one first-level subdirectory below +.Pa /var/www/man . +The name of one of these directories is called a +.Dq manpath +in the context of +.Nm . +Create a single ASCII text file +.Pa /var/www/man/manpath.conf +containing the names of these directories, one per line. +The directory given first is used as the default manpath. +.Pp +Inside each of these directories, use the same directory and file +structure as found below +.Pa /usr/share/man , +that is, second-level subdirectories +.Pa /var/www/man/*/man1 , /var/www/man/*/man2 +etc. containing source +.Xr mdoc 7 +and +.Xr man 7 +manuals with file name extensions matching the section numbers, +second-level subdirectories +.Pa /var/www/man/*/cat1 , /var/www/man/*/cat2 +etc. containing preformatted manuals with the file name extension +.Sq 0 , +and optional third-level subdirectories for architectures. +Use +.Xr makewhatis 8 +to create a +.Xr mandoc.db 5 +database inside each manpath. +.Pp +Configure your web server to execute CGI programs located in +.Pa /cgi-bin . +When using +.Xr nginx 8 , +the +.Xr slowcgi 8 +proxy daemon is needed to translate FastCGI requests to plain old CGI. +.Pp +To compile +.Nm , +first copy +.Pa cgi.h.example +to +.Pa cgi.h +and edit it according to your needs. +It contains the following compile-time definitions: +.Bl -tag -width Ds +.It Ev COMPAT_OLDURI +Only useful for running on www.openbsd.org to deal with old URIs containing +.Qq "manpath=OpenBSD " +where the blank character has to be translated to a hyphen. +When compiling for other sites, this definition can be deleted. +.It Ev CSS_DIR +An optional path to the directory containing the CSS files, +to be specified relative to the server's document root, +and to be specified without a trailing slash. +When not specified, the CSS files +are assumed to be in the document root. +This is used in generated HTML code. +.It Ev CUSTOMIZE_BEGIN +A HTML string to be inserted right after opening the +.Aq BODY +element. +.It Ev CUSTOMIZE_TITLE +An ASCII string to be used for the HTML +.Aq TITLE +element. +.It Ev HTTP_HOST +The FQDN of the (possibly virtual) host the HTTP server is running on. +This is used for +.Ic Location: +headers in HTTP 303 responses. +.It Ev MAN_DIR +A path to the +.Nm +data directory to be used instead of +.Pa /var/www/man , +relative to the web server +.Xr chroot 2 +directory, to be specified without a trailing slash. +This is prepended to the manpath when opening +.Xr mandoc.db 5 +and manual page files. +.El +.Pp +After editing +.Pa cgi.h , +run +.Pp +.Dl make man.cgi +.Pp +and copy the files to the proper locations. +Reading the +.Cm installcgi +target in the +.Pa Makefile +can help with that, but do not run it without carefully checking it +because the directory layouts of web servers vary greatly. +.Ss URI interface +.Nm +uniform resource identifiers are not needed for interactive use, +but can be useful for deep linking. +They consist of: +.Bl -enum +.It +The +.Cm http:// +protocol specifier. +.It +The host name and a following slash. +.It +The path to the program, normally +.Pa cgi-bin/man.cgi/ . +.It +To show a single page, a slash, the manpath, another slash, +and the name of the requested file, for example +.Pa /OpenBSD-current/man1/mandoc.1 . +.It +For searches, a query string starting with a question mark +and consisting of +.Ar key Ns = Ns Ar value +pairs, separated by ampersands, for example +.Pa ?manpath=OpenBSD-current&query=mandoc . +Supported keys are +.Cm manpath , +.Cm query , +.Cm sec , +.Cm arch , +corresponding to +.Xr apropos 1 +.Fl M , +.Ar expression , +.Fl s , +.Fl S , +respectively, and +.Cm apropos , +which is a boolean parameter to select or deselect the +.Xr apropos 1 +query mode. +For backward compatibility with the traditional +.Nm , +.Cm sektion +is supported as an alias for +.Cm sec . +.El +.Ss Restricted character set +For security reasons, in particular to prevent cross site scripting +attacks, some strings used by +.Nm +can only contain the following characters: +.Pp +.Bl -dash -compact -offset indent +.It +lower case and upper case ASCII letters +.It +the ten decimal digits +.It +the dash +.Pq Sq - +.It +the dot +.Pq Sq \&. +.It +the slash +.Pq Sq / +.It +the underscore +.Pq Sq _ +.El +.Pp +In particular, this applies to the +.Ev SCRIPT_NAME , +to all manpaths, and to all architecture names. +.Sh ENVIRONMENT +The web server may pass the following CGI variables to +.Nm : +.Bl -tag -width Ds +.It Ev PATH_INFO +The final part of the URI path passed from the client to the server, +starting after the +.Ev SCRIPT_NAME +and ending before the +.Ev QUERY_STRING . +It is used by the +.Cm show +page to aquire the manpath and filename it needs. +.It Ev QUERY_STRING +The HTTP query string passed from the client to the server. +It is the final part of the URI, after the question mark. +It is used by the +.Cm search +page to acquire the named parameters it needs. +.It Ev SCRIPT_NAME +The path to the +.Nm +binary relative to the server root, usually +.Pa /cgi-bin/man.cgi . +This is used for generating URIs to be embedded +in generated HTML code and HTTP headers. +If this contains any character not contained in the +.Sx Restricted character set , +.Nm +reports an internal server error and exits without doing anything. +.El +.Sh FILES +.Bl -tag -width Ds +.It Pa /var/www +Default web server +.Xr chroot 2 +directory. +All the following paths are specified relative to this directory. +.It Pa /cgi-bin/man.cgi +The path to the +.Nm +program relative to the server root. +Can be overridden by +.Ev SCRIPT_NAME . +.It Pa /htdocs +The path to the server document root relative to the server root. +This is part of the web server configuration and not specific to +.Nm . +.It Pa /htdocs/man-cgi.css +A style sheet for general +.Nm +styling, referenced from each generated HTML page. +.It Pa /htdocs/man.css +A style sheet for +.Xr mandoc 1 +HTML styling, referenced from each generated HTML page after +.Pa man-cgi.css . +.It Pa /man +Default +.Nm +data directory containing all the manual trees. +Can be overridden by +.Ev MAN_DIR . +.It Pa /man/mandoc/man1/apropos.1 , /man/mandoc/man8/man.cgi.8 +Manual pages documenting +.Nm +itself, linked from the index page. +.It Pa /man/manpath.conf +The list of available manpaths, one per line. +If any of the lines in this file contains a slash +.Pq Sq / +or any character not contained in the +.Sx Restricted character set , +.Nm +reports an internal server error and exits without doing anything. +.It Pa /man/OpenBSD-current/man1/mandoc.1 +An example +.Xr mdoc 7 +source file located below the +.Dq OpenBSD-current +manpath. +.El +.Sh COMPATIBILITY +The +.Nm +CGI program is call-compatible with queries from the traditional +.Pa man.cgi +script by Wolfram Schneider. +However, the output may not be quite the same. +.Sh SEE ALSO +.Xr apropos 1 , +.Xr mandoc.db 5 , +.Xr makewhatis 8 , +.Xr slowcgi 8 +.Sh HISTORY +A version of +.Nm +based on +.Xr mandoc 1 +first appeared in mdocml-1.12.1 (March 2012). +The current SQLite3-based version first appeared in +.Ox 5.6 . +.Sh AUTHORS +.An -nosplit +The +.Nm +program was written by +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv +and ported to the SQLite3-based +.Xr mandoc.db 5 +backend by +.An Ingo Schwarze Aq Mt schwarze@openbsd.org . Property changes on: head/contrib/mdocml/man.cgi.8 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/mdocml/man.h =================================================================== --- head/contrib/mdocml/man.h (revision 274879) +++ head/contrib/mdocml/man.h (revision 274880) @@ -1,117 +1,121 @@ -/* $Id: man.h,v 1.62 2013/10/17 20:54:58 schwarze Exp $ */ +/* $Id: man.h,v 1.65 2014/06/20 23:02:31 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons + * Copyright (c) 2014 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef MAN_H #define MAN_H enum mant { MAN_br = 0, MAN_TH, MAN_SH, MAN_SS, MAN_TP, MAN_LP, MAN_PP, MAN_P, MAN_IP, MAN_HP, MAN_SM, MAN_SB, MAN_BI, MAN_IB, MAN_BR, MAN_RB, MAN_R, MAN_B, MAN_I, MAN_IR, MAN_RI, MAN_na, MAN_sp, MAN_nf, MAN_fi, MAN_RE, MAN_RS, MAN_DT, MAN_UC, MAN_PD, MAN_AT, MAN_in, MAN_ft, MAN_OP, MAN_EX, MAN_EE, MAN_UR, MAN_UE, + MAN_ll, MAN_MAX }; enum man_type { MAN_TEXT, MAN_ELEM, MAN_ROOT, MAN_BLOCK, MAN_HEAD, MAN_BODY, MAN_TAIL, MAN_TBL, MAN_EQN }; struct man_meta { char *msec; /* `TH' section (1, 3p, etc.) */ char *date; /* `TH' normalised date */ char *vol; /* `TH' volume */ char *title; /* `TH' title (e.g., FOO) */ char *source; /* `TH' source (e.g., GNU) */ + int hasbody; /* document is not empty */ }; struct man_node { struct man_node *parent; /* parent AST node */ struct man_node *child; /* first child AST node */ struct man_node *next; /* sibling AST node */ struct man_node *prev; /* prior sibling AST node */ int nchild; /* number children */ int line; int pos; enum mant tok; /* tok or MAN__MAX if none */ int flags; #define MAN_VALID (1 << 0) /* has been validated */ #define MAN_EOS (1 << 2) /* at sentence boundary */ #define MAN_LINE (1 << 3) /* first macro/text on line */ enum man_type type; /* AST node type */ char *string; /* TEXT node argument */ struct man_node *head; /* BLOCK node HEAD ptr */ struct man_node *tail; /* BLOCK node TAIL ptr */ struct man_node *body; /* BLOCK node BODY ptr */ const struct tbl_span *span; /* TBL */ const struct eqn *eqn; /* EQN */ }; /* Names of macros. Index is enum mant. */ extern const char *const *man_macronames; __BEGIN_DECLS struct man; const struct man_node *man_node(const struct man *); const struct man_meta *man_meta(const struct man *); const struct mparse *man_mparse(const struct man *); +void man_deroff(char **, const struct man_node *); __END_DECLS #endif /*!MAN_H*/ Index: head/contrib/mdocml/man_hash.c =================================================================== --- head/contrib/mdocml/man_hash.c (revision 274879) +++ head/contrib/mdocml/man_hash.c (revision 274880) @@ -1,107 +1,105 @@ -/* $Id: man_hash.c,v 1.25 2011/07/24 18:15:14 kristaps Exp $ */ +/* $Id: man_hash.c,v 1.27 2014/04/20 16:46:04 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include -#include #include #include "man.h" #include "mandoc.h" #include "libman.h" #define HASH_DEPTH 6 #define HASH_ROW(x) do { \ if (isupper((unsigned char)(x))) \ (x) -= 65; \ else \ (x) -= 97; \ (x) *= HASH_DEPTH; \ } while (/* CONSTCOND */ 0) /* * Lookup table is indexed first by lower-case first letter (plus one * for the period, which is stored in the last row), then by lower or * uppercase second letter. Buckets correspond to the index of the * macro (the integer value of the enum stored as a char to save a bit * of space). */ static unsigned char table[26 * HASH_DEPTH]; + /* * XXX - this hash has global scope, so if intended for use as a library * with multiple callers, it will need re-invocation protection. */ void man_hash_init(void) { int i, j, x; memset(table, UCHAR_MAX, sizeof(table)); - assert(/* LINTED */ - MAN_MAX < UCHAR_MAX); + assert(MAN_MAX < UCHAR_MAX); for (i = 0; i < (int)MAN_MAX; i++) { x = man_macronames[i][0]; assert(isalpha((unsigned char)x)); HASH_ROW(x); for (j = 0; j < HASH_DEPTH; j++) if (UCHAR_MAX == table[x + j]) { table[x + j] = (unsigned char)i; break; } assert(j < HASH_DEPTH); } } - enum mant man_hash_find(const char *tmp) { int x, y, i; enum mant tok; if ('\0' == (x = tmp[0])) return(MAN_MAX); if ( ! (isalpha((unsigned char)x))) return(MAN_MAX); HASH_ROW(x); for (i = 0; i < HASH_DEPTH; i++) { if (UCHAR_MAX == (y = table[x + i])) return(MAN_MAX); tok = (enum mant)y; if (0 == strcmp(tmp, man_macronames[tok])) return(tok); } return(MAN_MAX); } Index: head/contrib/mdocml/man_html.c =================================================================== --- head/contrib/mdocml/man_html.c (revision 274879) +++ head/contrib/mdocml/man_html.c (revision 274880) @@ -1,718 +1,698 @@ -/* $Id: man_html.c,v 1.90 2013/10/17 20:54:58 schwarze Exp $ */ +/* $Id: man_html.c,v 1.96 2014/08/01 19:25:52 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons - * Copyright (c) 2013 Ingo Schwarze + * Copyright (c) 2013, 2014 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include "mandoc.h" +#include "mandoc_aux.h" #include "out.h" #include "html.h" #include "man.h" #include "main.h" /* TODO: preserve ident widths. */ /* FIXME: have PD set the default vspace width. */ #define INDENT 5 #define MAN_ARGS const struct man_meta *man, \ const struct man_node *n, \ struct mhtml *mh, \ struct html *h struct mhtml { int fl; #define MANH_LITERAL (1 << 0) /* literal context */ }; struct htmlman { int (*pre)(MAN_ARGS); int (*post)(MAN_ARGS); }; -static void print_bvspace(struct html *, +static void print_bvspace(struct html *, const struct man_node *); static void print_man(MAN_ARGS); static void print_man_head(MAN_ARGS); static void print_man_nodelist(MAN_ARGS); static void print_man_node(MAN_ARGS); static int a2width(const struct man_node *, struct roffsu *); static int man_B_pre(MAN_ARGS); static int man_HP_pre(MAN_ARGS); static int man_IP_pre(MAN_ARGS); static int man_I_pre(MAN_ARGS); static int man_OP_pre(MAN_ARGS); static int man_PP_pre(MAN_ARGS); 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); static int man_in_pre(MAN_ARGS); static int man_literal_pre(MAN_ARGS); static void man_root_post(MAN_ARGS); static void man_root_pre(MAN_ARGS); static const struct htmlman mans[MAN_MAX] = { { man_br_pre, NULL }, /* br */ { NULL, NULL }, /* TH */ { man_SH_pre, NULL }, /* SH */ { man_SS_pre, NULL }, /* SS */ { man_IP_pre, NULL }, /* TP */ { man_PP_pre, NULL }, /* LP */ { man_PP_pre, NULL }, /* PP */ { man_PP_pre, NULL }, /* P */ { man_IP_pre, NULL }, /* IP */ - { man_HP_pre, NULL }, /* HP */ + { man_HP_pre, NULL }, /* HP */ { man_SM_pre, NULL }, /* SM */ { man_SM_pre, NULL }, /* SB */ { man_alt_pre, NULL }, /* BI */ { man_alt_pre, NULL }, /* IB */ { man_alt_pre, NULL }, /* BR */ { man_alt_pre, NULL }, /* RB */ { NULL, NULL }, /* R */ { man_B_pre, NULL }, /* B */ { man_I_pre, NULL }, /* I */ { man_alt_pre, NULL }, /* IR */ { man_alt_pre, NULL }, /* RI */ { man_ign_pre, NULL }, /* na */ { man_br_pre, NULL }, /* sp */ { man_literal_pre, NULL }, /* nf */ { man_literal_pre, NULL }, /* fi */ { NULL, NULL }, /* RE */ { man_RS_pre, NULL }, /* RS */ { man_ign_pre, NULL }, /* DT */ { man_ign_pre, NULL }, /* UC */ { man_ign_pre, NULL }, /* PD */ { man_ign_pre, NULL }, /* AT */ { 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 */ + { man_ign_pre, NULL }, /* ll */ }; + /* * Printing leading vertical space before a block. * This is used for the paragraph macros. * The rules are pretty simple, since there's very little nesting going * on here. Basically, if we're the first within another block (SS/SH), * then don't emit vertical space. If we are (RS), then do. If not the * first, print it. */ static void print_bvspace(struct html *h, const struct man_node *n) { if (n->body && n->body->child) if (MAN_TBL == n->body->child->type) return; if (MAN_ROOT == n->parent->type || MAN_RS != n->parent->tok) if (NULL == n->prev) return; print_otag(h, TAG_P, 0, NULL); } void html_man(void *arg, const struct man *man) { struct mhtml mh; memset(&mh, 0, sizeof(struct mhtml)); print_man(man_meta(man), man_node(man), &mh, (struct html *)arg); putchar('\n'); } static void -print_man(MAN_ARGS) +print_man(MAN_ARGS) { struct tag *t, *tt; struct htmlpair tag; PAIR_CLASS_INIT(&tag, "mandoc"); if ( ! (HTML_FRAGMENT & h->oflags)) { print_gen_decls(h); t = print_otag(h, TAG_HTML, 0, NULL); tt = print_otag(h, TAG_HEAD, 0, NULL); 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 + } else t = print_otag(h, TAG_DIV, 1, &tag); print_man_nodelist(man, n, mh, h); print_tagq(h, t); } - -/* ARGSUSED */ static void print_man_head(MAN_ARGS) { print_gen_head(h); 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); } - static void print_man_nodelist(MAN_ARGS) { print_man_node(man, n, mh, h); if (n->next) print_man_nodelist(man, n->next, mh, h); } - static void print_man_node(MAN_ARGS) { int child; struct tag *t; child = 1; t = h->tags.head; switch (n->type) { - case (MAN_ROOT): + case MAN_ROOT: man_root_pre(man, n, mh, h); break; - case (MAN_TEXT): + case MAN_TEXT: /* * If we have a blank line, output a vertical space. * If we have a space as the first character, break * before printing the line's data. */ if ('\0' == *n->string) { print_otag(h, TAG_P, 0, NULL); return; } if (' ' == *n->string && MAN_LINE & n->flags) print_otag(h, TAG_BR, 0, NULL); else if (MANH_LITERAL & mh->fl && n->prev) print_otag(h, TAG_BR, 0, NULL); print_text(h, n->string); return; - case (MAN_EQN): + case MAN_EQN: print_eqn(h, n->eqn); break; - case (MAN_TBL): + case MAN_TBL: /* * This will take care of initialising all of the table * state data for the first table, then tearing it down * for the last one. */ print_tbl(h, n->span); return; default: - /* + /* * Close out scope of font prior to opening a macro * scope. */ if (HTMLFONT_NONE != h->metac) { h->metal = h->metac; h->metac = HTMLFONT_NONE; } /* * Close out the current table, if it's open, and unset * the "meta" table state. This will be reopened on the * next table element. */ if (h->tblt) { print_tblclose(h); t = h->tags.head; } if (mans[n->tok].pre) child = (*mans[n->tok].pre)(man, n, mh, h); break; } if (child && n->child) 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): + case MAN_ROOT: man_root_post(man, n, mh, h); break; - case (MAN_EQN): + case MAN_EQN: break; default: if (mans[n->tok].post) (*mans[n->tok].post)(man, n, mh, h); break; } } - static int a2width(const struct man_node *n, struct roffsu *su) { if (MAN_TEXT != n->type) return(0); if (a2roffsu(n->string, su, SCALE_BU)) return(1); return(0); } - -/* ARGSUSED */ static void man_root_pre(MAN_ARGS) { struct htmlpair tag[3]; struct tag *t, *tt; - char b[BUFSIZ], title[BUFSIZ]; + char *title; - b[0] = 0; - if (man->vol) - (void)strlcat(b, man->vol, BUFSIZ); - assert(man->title); assert(man->msec); - snprintf(title, BUFSIZ - 1, "%s(%s)", man->title, man->msec); + mandoc_asprintf(&title, "%s(%s)", man->title, man->msec); PAIR_SUMMARY_INIT(&tag[0], "Document Header"); PAIR_CLASS_INIT(&tag[1], "head"); PAIR_INIT(&tag[2], ATTR_WIDTH, "100%"); t = print_otag(h, TAG_TABLE, 3, tag); PAIR_INIT(&tag[0], ATTR_WIDTH, "30%"); print_otag(h, TAG_COL, 1, tag); print_otag(h, TAG_COL, 1, tag); print_otag(h, TAG_COL, 1, tag); print_otag(h, TAG_TBODY, 0, NULL); tt = print_otag(h, TAG_TR, 0, NULL); PAIR_CLASS_INIT(&tag[0], "head-ltitle"); print_otag(h, TAG_TD, 1, tag); print_text(h, title); print_stagq(h, tt); PAIR_CLASS_INIT(&tag[0], "head-vol"); PAIR_INIT(&tag[1], ATTR_ALIGN, "center"); print_otag(h, TAG_TD, 2, tag); - print_text(h, b); + if (NULL != man->vol) + print_text(h, man->vol); print_stagq(h, tt); PAIR_CLASS_INIT(&tag[0], "head-rtitle"); PAIR_INIT(&tag[1], ATTR_ALIGN, "right"); print_otag(h, TAG_TD, 2, tag); print_text(h, title); print_tagq(h, t); + free(title); } - -/* ARGSUSED */ static void man_root_post(MAN_ARGS) { struct htmlpair tag[3]; struct tag *t, *tt; PAIR_SUMMARY_INIT(&tag[0], "Document Footer"); PAIR_CLASS_INIT(&tag[1], "foot"); PAIR_INIT(&tag[2], ATTR_WIDTH, "100%"); t = print_otag(h, TAG_TABLE, 3, tag); PAIR_INIT(&tag[0], ATTR_WIDTH, "50%"); print_otag(h, TAG_COL, 1, tag); print_otag(h, TAG_COL, 1, tag); tt = print_otag(h, TAG_TR, 0, NULL); PAIR_CLASS_INIT(&tag[0], "foot-date"); print_otag(h, TAG_TD, 1, tag); 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 (man->source) print_text(h, man->source); print_tagq(h, t); } -/* ARGSUSED */ static int man_br_pre(MAN_ARGS) { struct roffsu su; struct htmlpair tag; SCALE_VS_INIT(&su, 1); if (MAN_sp == n->tok) { if (NULL != (n = n->child)) if ( ! a2roffsu(n->string, &su, SCALE_VS)) SCALE_VS_INIT(&su, atoi(n->string)); } else - su.scale = 0; + su.scale = 0.0; bufinit(h); bufcat_su(h, "height", &su); PAIR_STYLE_INIT(&tag, h); print_otag(h, TAG_DIV, 1, &tag); /* So the div isn't empty: */ print_text(h, "\\~"); return(0); } -/* ARGSUSED */ static int man_SH_pre(MAN_ARGS) { struct htmlpair tag; if (MAN_BLOCK == n->type) { mh->fl &= ~MANH_LITERAL; PAIR_CLASS_INIT(&tag, "section"); print_otag(h, TAG_DIV, 1, &tag); return(1); } else if (MAN_BODY == n->type) return(1); print_otag(h, TAG_H1, 0, NULL); return(1); } -/* ARGSUSED */ static int man_alt_pre(MAN_ARGS) { const struct man_node *nn; int i, savelit; enum htmltag fp; struct tag *t; - if ((savelit = mh->fl & MANH_LITERAL)) + if ((savelit = mh->fl & MANH_LITERAL)) print_otag(h, TAG_BR, 0, NULL); mh->fl &= ~MANH_LITERAL; for (i = 0, nn = n->child; nn; nn = nn->next, i++) { t = NULL; switch (n->tok) { - case (MAN_BI): + case MAN_BI: fp = i % 2 ? TAG_I : TAG_B; break; - case (MAN_IB): + case MAN_IB: fp = i % 2 ? TAG_B : TAG_I; break; - case (MAN_RI): + case MAN_RI: fp = i % 2 ? TAG_I : TAG_MAX; break; - case (MAN_IR): + case MAN_IR: fp = i % 2 ? TAG_MAX : TAG_I; break; - case (MAN_BR): + case MAN_BR: fp = i % 2 ? TAG_MAX : TAG_B; break; - case (MAN_RB): + case MAN_RB: fp = i % 2 ? TAG_B : TAG_MAX; break; default: abort(); /* NOTREACHED */ } if (i) h->flags |= HTML_NOSPACE; if (TAG_MAX != fp) t = print_otag(h, fp, 0, NULL); print_man_node(man, nn, mh, h); if (t) print_tagq(h, t); } if (savelit) mh->fl |= MANH_LITERAL; return(0); } -/* ARGSUSED */ static int man_SM_pre(MAN_ARGS) { - + print_otag(h, TAG_SMALL, 0, NULL); if (MAN_SB == n->tok) print_otag(h, TAG_B, 0, NULL); return(1); } -/* ARGSUSED */ static int man_SS_pre(MAN_ARGS) { struct htmlpair tag; if (MAN_BLOCK == n->type) { mh->fl &= ~MANH_LITERAL; PAIR_CLASS_INIT(&tag, "subsection"); print_otag(h, TAG_DIV, 1, &tag); return(1); } else if (MAN_BODY == n->type) return(1); print_otag(h, TAG_H2, 0, NULL); return(1); } -/* ARGSUSED */ static int man_PP_pre(MAN_ARGS) { if (MAN_HEAD == n->type) return(0); else if (MAN_BLOCK == n->type) print_bvspace(h, n); return(1); } -/* ARGSUSED */ static int man_IP_pre(MAN_ARGS) { const struct man_node *nn; - if (MAN_BODY == n->type) { + if (MAN_BODY == n->type) { print_otag(h, TAG_DD, 0, NULL); return(1); } else if (MAN_HEAD != n->type) { print_otag(h, TAG_DL, 0, NULL); return(1); } /* FIXME: width specification. */ print_otag(h, TAG_DT, 0, NULL); /* For IP, only print the first header element. */ if (MAN_IP == n->tok && n->child) 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(man, nn, mh, h); + if (MAN_TP == n->tok) { + nn = n->child; + while (NULL != nn && 0 == (MAN_LINE & nn->flags)) + nn = nn->next; + while (NULL != nn) { + print_man_node(man, nn, mh, h); + nn = nn->next; + } + } return(0); } -/* ARGSUSED */ static int man_HP_pre(MAN_ARGS) { struct htmlpair tag; struct roffsu su; const struct man_node *np; if (MAN_HEAD == n->type) return(0); else if (MAN_BLOCK != n->type) return(1); np = n->head->child; if (NULL == np || ! a2width(np, &su)) SCALE_HS_INIT(&su, INDENT); bufinit(h); print_bvspace(h, n); bufcat_su(h, "margin-left", &su); su.scale = -su.scale; bufcat_su(h, "text-indent", &su); PAIR_STYLE_INIT(&tag, h); print_otag(h, TAG_P, 1, &tag); return(1); } -/* ARGSUSED */ static int man_OP_pre(MAN_ARGS) { struct tag *tt; struct htmlpair tag; print_text(h, "["); h->flags |= HTML_NOSPACE; PAIR_CLASS_INIT(&tag, "opt"); tt = print_otag(h, TAG_SPAN, 1, &tag); if (NULL != (n = n->child)) { print_otag(h, TAG_B, 0, NULL); print_text(h, n->string); } print_stagq(h, tt); if (NULL != n && NULL != n->next) { print_otag(h, TAG_I, 0, NULL); print_text(h, n->next->string); } print_stagq(h, tt); h->flags |= HTML_NOSPACE; print_text(h, "]"); return(0); } - -/* ARGSUSED */ static int man_B_pre(MAN_ARGS) { print_otag(h, TAG_B, 0, NULL); return(1); } -/* ARGSUSED */ static int man_I_pre(MAN_ARGS) { - + print_otag(h, TAG_I, 0, NULL); return(1); } -/* ARGSUSED */ static int man_literal_pre(MAN_ARGS) { if (MAN_fi == n->tok || MAN_EE == n->tok) { print_otag(h, TAG_BR, 0, NULL); mh->fl &= ~MANH_LITERAL; } else mh->fl |= MANH_LITERAL; return(0); } -/* ARGSUSED */ static int man_in_pre(MAN_ARGS) { print_otag(h, TAG_BR, 0, NULL); return(0); } -/* ARGSUSED */ static int man_ign_pre(MAN_ARGS) { return(0); } -/* ARGSUSED */ static int man_RS_pre(MAN_ARGS) { struct htmlpair tag; struct roffsu su; if (MAN_HEAD == n->type) return(0); else if (MAN_BODY == n->type) return(1); SCALE_HS_INIT(&su, INDENT); if (n->head->child) a2width(n->head->child, &su); bufinit(h); bufcat_su(h, "margin-left", &su); PAIR_STYLE_INIT(&tag, h); 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); } Index: head/contrib/mdocml/man_macro.c =================================================================== --- head/contrib/mdocml/man_macro.c (revision 274879) +++ head/contrib/mdocml/man_macro.c (revision 274880) @@ -1,515 +1,492 @@ -/* $Id: man_macro.c,v 1.79 2013/12/25 00:50:05 schwarze Exp $ */ +/* $Id: man_macro.c,v 1.87 2014/07/30 23:01:39 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2012, 2013 Ingo Schwarze * Copyright (c) 2013 Franco Fichtner * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include "man.h" #include "mandoc.h" #include "libmandoc.h" #include "libman.h" enum rew { REW_REWIND, REW_NOHALT, REW_HALT }; static int blk_close(MACRO_PROT_ARGS); static int blk_exp(MACRO_PROT_ARGS); static int blk_imp(MACRO_PROT_ARGS); static int in_line_eoln(MACRO_PROT_ARGS); -static int man_args(struct man *, int, +static int man_args(struct man *, int, int *, char *, char **); -static int rew_scope(enum man_type, +static int rew_scope(enum man_type, struct man *, enum mant); -static enum rew rew_dohalt(enum mant, enum man_type, +static enum rew rew_dohalt(enum mant, enum man_type, const struct man_node *); -static enum rew rew_block(enum mant, enum man_type, +static enum rew rew_block(enum mant, enum man_type, const struct man_node *); -static void rew_warn(struct man *, - struct man_node *, enum mandocerr); const struct man_macro __man_macros[MAN_MAX] = { { in_line_eoln, MAN_NSCOPED }, /* br */ { in_line_eoln, MAN_BSCOPE }, /* TH */ { blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SH */ { blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SS */ { blk_imp, MAN_BSCOPE | MAN_SCOPED | MAN_FSCOPED }, /* TP */ { blk_imp, MAN_BSCOPE }, /* LP */ { blk_imp, MAN_BSCOPE }, /* PP */ { blk_imp, MAN_BSCOPE }, /* P */ { blk_imp, MAN_BSCOPE }, /* IP */ { blk_imp, MAN_BSCOPE }, /* HP */ { in_line_eoln, MAN_SCOPED }, /* SM */ { in_line_eoln, MAN_SCOPED }, /* SB */ { in_line_eoln, 0 }, /* BI */ { in_line_eoln, 0 }, /* IB */ { in_line_eoln, 0 }, /* BR */ { in_line_eoln, 0 }, /* RB */ { in_line_eoln, MAN_SCOPED }, /* R */ { in_line_eoln, MAN_SCOPED }, /* B */ { in_line_eoln, MAN_SCOPED }, /* I */ { in_line_eoln, 0 }, /* IR */ { in_line_eoln, 0 }, /* RI */ { in_line_eoln, MAN_NSCOPED }, /* na */ { in_line_eoln, MAN_NSCOPED }, /* sp */ { in_line_eoln, MAN_BSCOPE }, /* nf */ { in_line_eoln, MAN_BSCOPE }, /* fi */ { blk_close, 0 }, /* RE */ { blk_exp, MAN_BSCOPE | MAN_EXPLICIT }, /* RS */ { in_line_eoln, 0 }, /* DT */ { in_line_eoln, 0 }, /* UC */ { in_line_eoln, 0 }, /* PD */ { in_line_eoln, 0 }, /* AT */ { 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 */ + { in_line_eoln, 0 }, /* ll */ }; const struct man_macro * const man_macros = __man_macros; -/* - * Warn when "n" is an explicit non-roff macro. - */ -static void -rew_warn(struct man *man, struct man_node *n, enum mandocerr er) -{ - - if (er == MANDOCERR_MAX || MAN_BLOCK != n->type) - return; - if (MAN_VALID & n->flags) - return; - if ( ! (MAN_EXPLICIT & man_macros[n->tok].flags)) - return; - - assert(er < MANDOCERR_FATAL); - man_nmsg(man, n, er); -} - - -/* - * Rewind scope. If a code "er" != MANDOCERR_MAX has been provided, it - * will be used if an explicit block scope is being closed out. - */ int -man_unscope(struct man *man, const struct man_node *to, - enum mandocerr er) +man_unscope(struct man *man, const struct man_node *to) { struct man_node *n; - assert(to); - man->next = MAN_NEXT_SIBLING; + to = to->parent; + n = man->last; + while (n != to) { - /* LINTED */ - while (man->last != to) { + /* Reached the end of the document? */ + + if (to == NULL && ! (n->flags & MAN_VALID)) { + if (man->flags & (MAN_BLINE | MAN_ELINE) && + man_macros[n->tok].flags & MAN_SCOPED) { + mandoc_vmsg(MANDOCERR_BLK_LINE, + man->parse, n->line, n->pos, + "EOF breaks %s", + man_macronames[n->tok]); + if (man->flags & MAN_ELINE) + man->flags &= ~MAN_ELINE; + else { + assert(n->type == MAN_HEAD); + n = n->parent; + man->flags &= ~MAN_BLINE; + } + man->last = n; + n = n->parent; + man_node_delete(man, man->last); + continue; + } + if (n->type == MAN_BLOCK && + man_macros[n->tok].flags & MAN_EXPLICIT) + mandoc_msg(MANDOCERR_BLK_NOEND, + man->parse, n->line, n->pos, + man_macronames[n->tok]); + } + /* - * Save the parent here, because we may delete the - * 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. + * We might delete the man->last node + * in the post-validation phase. + * Save a pointer to the parent such that + * we know where to continue the iteration. */ - n = man->last->parent; - rew_warn(man, man->last, er); + man->last = n; + n = n->parent; if ( ! man_valid_post(man)) return(0); - man->last = n; - assert(man->last); } - - rew_warn(man, man->last, er); - if ( ! man_valid_post(man)) - return(0); - return(1); } - static enum rew rew_block(enum mant ntok, enum man_type type, const struct man_node *n) { - if (MAN_BLOCK == type && ntok == n->parent->tok && - MAN_BODY == n->parent->type) + if (MAN_BLOCK == type && ntok == n->parent->tok && + MAN_BODY == n->parent->type) return(REW_REWIND); return(ntok == n->tok ? REW_HALT : REW_NOHALT); } - /* * There are three scope levels: scoped to the root (all), scoped to the * section (all less sections), and scoped to subsections (all less * sections and subsections). */ -static enum rew +static enum rew rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n) { enum rew c; /* We cannot progress beyond the root ever. */ if (MAN_ROOT == n->type) return(REW_HALT); assert(n->parent); /* Normal nodes shouldn't go to the level of the root. */ if (MAN_ROOT == n->parent->type) return(REW_REWIND); /* Already-validated nodes should be closed out. */ if (MAN_VALID & n->flags) return(REW_NOHALT); /* First: rewind to ourselves. */ 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: * section, sub-section, etc. */ switch (tok) { - case (MAN_SH): + case MAN_SH: break; - case (MAN_SS): + case MAN_SS: /* Rewind to a section, if a block. */ if (REW_NOHALT != (c = rew_block(MAN_SH, type, n))) return(c); break; - case (MAN_RS): + 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); /* Rewind to a section, if a block. */ if (REW_NOHALT != (c = rew_block(MAN_SH, type, n))) return(c); break; default: /* Rewind to an offsetter, if a block. */ if (REW_NOHALT != (c = rew_block(MAN_RS, type, n))) return(c); /* Rewind to a subsection, if a block. */ if (REW_NOHALT != (c = rew_block(MAN_SS, type, n))) return(c); /* Rewind to a section, if a block. */ if (REW_NOHALT != (c = rew_block(MAN_SH, type, n))) return(c); break; } return(REW_NOHALT); } - /* * Rewinding entails ascending the parse tree until a coherent point, * for example, the `SH' macro will close out any intervening `SS' * scopes. When a scope is closed, it must be validated and actioned. */ static int rew_scope(enum man_type type, struct man *man, enum mant tok) { struct man_node *n; enum rew c; - /* LINTED */ 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 * rewinding (REW_NOHALT). */ c = rew_dohalt(tok, type, n); if (REW_HALT == c) return(1); if (REW_REWIND == c) break; } - /* + /* * Rewind until the current point. Warn if we're a roff * instruction that's mowing over explicit scopes. */ assert(n); - return(man_unscope(man, n, MANDOCERR_MAX)); + return(man_unscope(man, n)); } /* * Close out a generic explicit macro. */ -/* ARGSUSED */ int blk_close(MACRO_PROT_ARGS) { - enum mant ntok; + enum mant ntok; const struct man_node *nn; switch (tok) { - case (MAN_RE): + case MAN_RE: ntok = MAN_RS; break; - case (MAN_UE): + case MAN_UE: ntok = MAN_UR; break; default: abort(); /* NOTREACHED */ } for (nn = man->last->parent; nn; nn = nn->parent) if (ntok == nn->tok && MAN_BLOCK == nn->type) break; if (NULL == nn) { - man_pmsg(man, line, ppos, MANDOCERR_NOSCOPE); + mandoc_msg(MANDOCERR_BLK_NOTOPEN, man->parse, + line, ppos, man_macronames[tok]); if ( ! rew_scope(MAN_BLOCK, man, MAN_PP)) return(0); - } else - man_unscope(man, nn, MANDOCERR_MAX); + } else + man_unscope(man, nn); return(1); } - -/* ARGSUSED */ int blk_exp(MACRO_PROT_ARGS) { struct man_node *n; int la; char *p; /* Close out prior implicit scopes. */ if ( ! rew_scope(MAN_BLOCK, man, tok)) return(0); 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(man, line, pos, buf, &p)) break; if ( ! man_word_alloc(man, line, la, p)) return(0); } assert(man); assert(tok != MAN_MAX); for (n = man->last; n; n = n->parent) { if (n->tok != tok) continue; assert(MAN_HEAD == n->type); - man_unscope(man, n, MANDOCERR_MAX); + man_unscope(man, n); break; } return(man_body_alloc(man, line, ppos, tok)); } - - /* * Parse an implicit-block macro. These contain a MAN_HEAD and a * MAN_BODY contained within a MAN_BLOCK. Rules for closing out other * scopes, such as `SH' closing out an `SS', are defined in the rew * routines. */ -/* ARGSUSED */ int blk_imp(MACRO_PROT_ARGS) { int la; char *p; struct man_node *n; /* Close out prior scopes. */ if ( ! rew_scope(MAN_BODY, man, tok)) return(0); if ( ! rew_scope(MAN_BLOCK, man, tok)) return(0); /* Allocate new block & head scope. */ if ( ! man_block_alloc(man, line, ppos, tok)) return(0); if ( ! man_head_alloc(man, line, ppos, tok)) return(0); n = man->last; /* Add line arguments. */ for (;;) { la = *pos; if ( ! man_args(man, line, pos, buf, &p)) break; if ( ! man_word_alloc(man, line, la, p)) return(0); } /* Close out head and open body (unless MAN_SCOPE). */ if (MAN_SCOPED & man_macros[tok].flags) { /* If we're forcing scope (`TP'), keep it open. */ if (MAN_FSCOPED & man_macros[tok].flags) { man->flags |= MAN_BLINE; return(1); } else if (n == man->last) { man->flags |= MAN_BLINE; return(1); } } if ( ! rew_scope(MAN_HEAD, man, tok)) return(0); return(man_body_alloc(man, line, ppos, tok)); } - -/* ARGSUSED */ int in_line_eoln(MACRO_PROT_ARGS) { int la; char *p; struct man_node *n; if ( ! man_elem_alloc(man, line, ppos, tok)) return(0); n = man->last; for (;;) { la = *pos; if ( ! man_args(man, line, pos, buf, &p)) break; 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)) + mandoc_eos(man->last->string, strlen(man->last->string))) 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 == man->last && MAN_SCOPED & man_macros[tok].flags) { assert( ! (MAN_NSCOPED & man_macros[tok].flags)); man->flags |= MAN_ELINE; return(1); - } - - /* Set ignorable context, if applicable. */ - - if (MAN_NSCOPED & man_macros[tok].flags) { - assert( ! (MAN_SCOPED & man_macros[tok].flags)); - man->flags |= MAN_ILINE; } assert(MAN_ROOT != man->last->type); man->next = MAN_NEXT_SIBLING; - + /* * Rewind our element scope. Note that when TH is pruned, we'll * be back at the root, so make sure that we don't clobber as * its sibling. */ for ( ; man->last; man->last = man->last->parent) { if (man->last == n) break; if (man->last->type == MAN_ROOT) break; if ( ! man_valid_post(man)) return(0); } assert(man->last); /* - * Same here regarding whether we're back at the root. + * Same here regarding whether we're back at the root. */ if (man->last->type != MAN_ROOT && ! man_valid_post(man)) return(0); return(1); } int man_macroend(struct man *man) { - return(man_unscope(man, man->first, MANDOCERR_SCOPEEXIT)); + return(man_unscope(man, man->first)); } static int man_args(struct man *man, int line, int *pos, char *buf, char **v) { char *start; assert(*pos); *v = start = buf + *pos; assert(' ' != *start); if ('\0' == *start) return(0); *v = mandoc_getarg(man->parse, v, line, pos); return(1); } Index: head/contrib/mdocml/man_term.c =================================================================== --- head/contrib/mdocml/man_term.c (revision 274879) +++ head/contrib/mdocml/man_term.c (revision 274880) @@ -1,1210 +1,1190 @@ -/* $Id: man_term.c,v 1.139 2013/12/22 23:34:13 schwarze Exp $ */ +/* $Id: man_term.c,v 1.149 2014/06/20 23:02:31 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons - * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze + * Copyright (c) 2010-2014 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include "mandoc.h" +#include "mandoc_aux.h" #include "out.h" #include "man.h" #include "term.h" #include "main.h" #define MAXMARGINS 64 /* maximum number of indented scopes */ struct mtermp { int fl; #define MANT_LITERAL (1 << 0) size_t lmargin[MAXMARGINS]; /* margins (incl. visible page) */ 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, \ +#define DECL_ARGS struct termp *p, \ struct mtermp *mt, \ const struct man_node *n, \ const struct man_meta *meta struct termact { int (*pre)(DECL_ARGS); void (*post)(DECL_ARGS); int flags; #define MAN_NOTEXT (1 << 0) /* Never has text children. */ }; static int a2width(const struct termp *, const char *); static size_t a2height(const struct termp *, const char *); static void print_man_nodelist(DECL_ARGS); 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 *, +static void print_bvspace(struct termp *, 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); static int pre_in(DECL_ARGS); static int pre_literal(DECL_ARGS); +static int pre_ll(DECL_ARGS); static int pre_sp(DECL_ARGS); static void post_IP(DECL_ARGS); static void post_HP(DECL_ARGS); 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 */ { NULL, NULL, 0 }, /* TH */ { pre_SH, post_SH, 0 }, /* SH */ { pre_SS, post_SS, 0 }, /* SS */ { pre_TP, post_TP, 0 }, /* TP */ { pre_PP, NULL, 0 }, /* LP */ { pre_PP, NULL, 0 }, /* PP */ { pre_PP, NULL, 0 }, /* P */ { pre_IP, post_IP, 0 }, /* IP */ - { pre_HP, post_HP, 0 }, /* HP */ + { pre_HP, post_HP, 0 }, /* HP */ { NULL, NULL, 0 }, /* SM */ { pre_B, NULL, 0 }, /* SB */ { pre_alternate, NULL, 0 }, /* BI */ { pre_alternate, NULL, 0 }, /* IB */ { pre_alternate, NULL, 0 }, /* BR */ { pre_alternate, NULL, 0 }, /* RB */ { NULL, NULL, 0 }, /* R */ { pre_B, NULL, 0 }, /* B */ { pre_I, NULL, 0 }, /* I */ { pre_alternate, NULL, 0 }, /* IR */ { pre_alternate, NULL, 0 }, /* RI */ { pre_ign, NULL, MAN_NOTEXT }, /* na */ { pre_sp, NULL, MAN_NOTEXT }, /* sp */ { pre_literal, NULL, 0 }, /* nf */ { pre_literal, NULL, 0 }, /* fi */ { NULL, NULL, 0 }, /* RE */ { pre_RS, post_RS, 0 }, /* RS */ { pre_ign, NULL, 0 }, /* DT */ { pre_ign, NULL, 0 }, /* UC */ { 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 */ + { pre_ll, NULL, MAN_NOTEXT }, /* ll */ }; - void terminal_man(void *arg, const struct man *man) { struct termp *p; const struct man_node *n; const struct man_meta *meta; struct mtermp mt; p = (struct termp *)arg; if (0 == p->defindent) p->defindent = 7; p->overstep = 0; p->maxrmargin = p->defrmargin; p->tabwidth = term_len(p, 5); if (NULL == p->symtab) p->symtab = mchars_alloc(); n = man_node(man); meta = man_meta(man); 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, meta); term_end(p); } static size_t a2height(const struct termp *p, const char *cp) { struct roffsu su; if ( ! a2roffsu(cp, &su, SCALE_VS)) SCALE_VS_INIT(&su, atoi(cp)); return(term_vspan(p, &su)); } - static int a2width(const struct termp *p, const char *cp) { struct roffsu su; if ( ! a2roffsu(cp, &su, SCALE_BU)) return(-1); return((int)term_hspan(p, &su)); } /* * Printing leading vertical space before a block. * This is used for the paragraph macros. * The rules are pretty simple, since there's very little nesting going * on here. Basically, if we're the first within another block (SS/SH), * then don't emit vertical space. If we are (RS), then do. If not the * first, print it. */ static void print_bvspace(struct termp *p, const struct man_node *n, int pardist) { int i; term_newln(p); if (n->body && n->body->child) if (MAN_TBL == n->body->child->type) return; if (MAN_ROOT == n->parent->type || MAN_RS != n->parent->tok) if (NULL == n->prev) return; for (i = 0; i < pardist; i++) term_vspace(p); } -/* ARGSUSED */ + static int pre_ign(DECL_ARGS) { return(0); } +static int +pre_ll(DECL_ARGS) +{ -/* ARGSUSED */ + term_setwidth(p, n->nchild ? n->child->string : NULL); + return(0); +} + static int pre_I(DECL_ARGS) { term_fontrepl(p, TERMFONT_UNDER); return(1); } - -/* ARGSUSED */ static int pre_literal(DECL_ARGS) { term_newln(p); if (MAN_nf == n->tok || MAN_EX == n->tok) mt->fl |= MANT_LITERAL; else mt->fl &= ~MANT_LITERAL; /* * Unlike .IP and .TP, .HP does not have a HEAD. * So in case a second call to term_flushln() is needed, * indentation has to be set up explicitly. */ if (MAN_HP == n->parent->tok && p->rmargin < p->maxrmargin) { p->offset = p->rmargin; p->rmargin = p->maxrmargin; p->trailspace = 0; - p->flags &= ~TERMP_NOBREAK; + p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); p->flags |= TERMP_NOSPACE; } return(0); } -/* 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]; const struct man_node *nn; int savelit, i; switch (n->tok) { - case (MAN_RB): + case MAN_RB: font[0] = TERMFONT_NONE; font[1] = TERMFONT_BOLD; break; - case (MAN_RI): + case MAN_RI: font[0] = TERMFONT_NONE; font[1] = TERMFONT_UNDER; break; - case (MAN_BR): + case MAN_BR: font[0] = TERMFONT_BOLD; font[1] = TERMFONT_NONE; break; - case (MAN_BI): + case MAN_BI: font[0] = TERMFONT_BOLD; font[1] = TERMFONT_UNDER; break; - case (MAN_IR): + case MAN_IR: font[0] = TERMFONT_UNDER; font[1] = TERMFONT_NONE; break; - case (MAN_IB): + case MAN_IB: font[0] = TERMFONT_UNDER; font[1] = TERMFONT_BOLD; break; default: abort(); } savelit = MANT_LITERAL & mt->fl; mt->fl &= ~MANT_LITERAL; for (i = 0, nn = n->child; nn; nn = nn->next, i = 1 - i) { term_fontrepl(p, font[i]); if (savelit && NULL == nn->next) mt->fl |= MANT_LITERAL; print_man_node(p, mt, nn, meta); if (nn->next) p->flags |= TERMP_NOSPACE; } return(0); } -/* ARGSUSED */ static int pre_B(DECL_ARGS) { term_fontrepl(p, TERMFONT_BOLD); return(1); } -/* ARGSUSED */ static int pre_OP(DECL_ARGS) { term_word(p, "["); p->flags |= TERMP_NOSPACE; if (NULL != (n = n->child)) { term_fontrepl(p, TERMFONT_BOLD); term_word(p, n->string); } if (NULL != n && NULL != n->next) { term_fontrepl(p, TERMFONT_UNDER); term_word(p, n->next->string); } term_fontrepl(p, TERMFONT_NONE); p->flags |= TERMP_NOSPACE; term_word(p, "]"); return(0); } -/* ARGSUSED */ static int pre_ft(DECL_ARGS) { const char *cp; if (NULL == n->child) { term_fontlast(p); return(0); } cp = n->child->string; switch (*cp) { - case ('4'): + case '4': /* FALLTHROUGH */ - case ('3'): + case '3': /* FALLTHROUGH */ - case ('B'): + case 'B': term_fontrepl(p, TERMFONT_BOLD); break; - case ('2'): + case '2': /* FALLTHROUGH */ - case ('I'): + case 'I': term_fontrepl(p, TERMFONT_UNDER); break; - case ('P'): + case 'P': term_fontlast(p); break; - case ('1'): + case '1': /* FALLTHROUGH */ - case ('C'): + case 'C': /* FALLTHROUGH */ - case ('R'): + case 'R': term_fontrepl(p, TERMFONT_NONE); break; default: break; } return(0); } -/* ARGSUSED */ static int pre_in(DECL_ARGS) { int len, less; size_t v; const char *cp; term_newln(p); if (NULL == n->child) { p->offset = mt->offset; return(0); } cp = n->child->string; less = 0; if ('-' == *cp) less = -1; else if ('+' == *cp) less = 1; else cp--; if ((len = a2width(p, ++cp)) < 0) return(0); v = (size_t)len; if (less < 0) p->offset -= p->offset > v ? v : p->offset; else if (less > 0) p->offset += v; - else + else p->offset = v; /* Don't let this creep beyond the right margin. */ if (p->offset > p->rmargin) p->offset = p->rmargin; return(0); } - -/* ARGSUSED */ static int pre_sp(DECL_ARGS) { char *s; size_t i, len; int neg; if ((NULL == n->prev && n->parent)) { switch (n->parent->tok) { - case (MAN_SH): + case MAN_SH: /* FALLTHROUGH */ - case (MAN_SS): + case MAN_SS: /* FALLTHROUGH */ - case (MAN_PP): + case MAN_PP: /* FALLTHROUGH */ - case (MAN_LP): + case MAN_LP: /* FALLTHROUGH */ - case (MAN_P): + case MAN_P: /* FALLTHROUGH */ return(0); default: break; } } neg = 0; switch (n->tok) { - case (MAN_br): + case MAN_br: len = 0; break; default: 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); else if (neg) p->skipvsp += len; else for (i = 0; i < len; i++) term_vspace(p); return(0); } - -/* ARGSUSED */ static int pre_HP(DECL_ARGS) { size_t len, one; int ival; const struct man_node *nn; switch (n->type) { - case (MAN_BLOCK): + case MAN_BLOCK: print_bvspace(p, n, mt->pardist); return(1); - case (MAN_BODY): + case MAN_BODY: break; default: return(0); } if ( ! (MANT_LITERAL & mt->fl)) { - p->flags |= TERMP_NOBREAK; + p->flags |= TERMP_NOBREAK | TERMP_BRIND; p->trailspace = 2; } len = mt->lmargin[mt->lmargincur]; ival = -1; /* Calculate offset. */ if (NULL != (nn = n->parent->head->child)) if ((ival = a2width(p, nn->string)) >= 0) len = (size_t)ival; one = term_len(p, 1); if (len < one) len = one; p->offset = mt->offset; p->rmargin = mt->offset + len; if (ival >= 0) mt->lmargin[mt->lmargincur] = (size_t)ival; return(1); } - -/* ARGSUSED */ static void post_HP(DECL_ARGS) { switch (n->type) { - case (MAN_BODY): + case MAN_BODY: term_newln(p); - p->flags &= ~TERMP_NOBREAK; + p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); p->trailspace = 0; p->offset = mt->offset; p->rmargin = p->maxrmargin; break; default: break; } } - -/* ARGSUSED */ static int pre_PP(DECL_ARGS) { switch (n->type) { - case (MAN_BLOCK): + case MAN_BLOCK: mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); print_bvspace(p, n, mt->pardist); break; default: p->offset = mt->offset; break; } return(MAN_HEAD != n->type); } - -/* ARGSUSED */ static int pre_IP(DECL_ARGS) { const struct man_node *nn; size_t len; int savelit, ival; switch (n->type) { - case (MAN_BODY): + case MAN_BODY: p->flags |= TERMP_NOSPACE; break; - case (MAN_HEAD): + case MAN_HEAD: p->flags |= TERMP_NOBREAK; p->trailspace = 1; break; - case (MAN_BLOCK): + case MAN_BLOCK: print_bvspace(p, n, mt->pardist); /* FALLTHROUGH */ default: return(1); } len = mt->lmargin[mt->lmargincur]; ival = -1; /* Calculate the offset from the optional second argument. */ if (NULL != (nn = n->parent->head->child)) if (NULL != (nn = nn->next)) if ((ival = a2width(p, nn->string)) >= 0) len = (size_t)ival; switch (n->type) { - case (MAN_HEAD): + case MAN_HEAD: /* Handle zero-width lengths. */ if (0 == len) len = term_len(p, 1); p->offset = mt->offset; p->rmargin = mt->offset + len; if (ival < 0) break; /* Set the saved left-margin. */ mt->lmargin[mt->lmargincur] = (size_t)ival; savelit = MANT_LITERAL & mt->fl; mt->fl &= ~MANT_LITERAL; if (n->child) print_man_node(p, mt, n->child, meta); if (savelit) mt->fl |= MANT_LITERAL; return(0); - case (MAN_BODY): + case MAN_BODY: p->offset = mt->offset + len; - p->rmargin = p->maxrmargin; + p->rmargin = p->maxrmargin > p->offset ? + p->maxrmargin : p->offset; break; default: break; } return(1); } - -/* ARGSUSED */ static void post_IP(DECL_ARGS) { switch (n->type) { - case (MAN_HEAD): + case MAN_HEAD: term_flushln(p); p->flags &= ~TERMP_NOBREAK; p->trailspace = 0; p->rmargin = p->maxrmargin; break; - case (MAN_BODY): + case MAN_BODY: term_newln(p); p->offset = mt->offset; break; default: break; } } - -/* ARGSUSED */ static int pre_TP(DECL_ARGS) { const struct man_node *nn; size_t len; int savelit, ival; switch (n->type) { - case (MAN_HEAD): + case MAN_HEAD: p->flags |= TERMP_NOBREAK; p->trailspace = 1; break; - case (MAN_BODY): + case MAN_BODY: p->flags |= TERMP_NOSPACE; break; - case (MAN_BLOCK): + case MAN_BLOCK: print_bvspace(p, n, mt->pardist); /* FALLTHROUGH */ default: return(1); } len = (size_t)mt->lmargin[mt->lmargincur]; ival = -1; /* Calculate offset. */ if (NULL != (nn = n->parent->head->child)) - if (nn->string && nn->parent->line == nn->line) + if (nn->string && 0 == (MAN_LINE & nn->flags)) if ((ival = a2width(p, nn->string)) >= 0) len = (size_t)ival; switch (n->type) { - case (MAN_HEAD): + case MAN_HEAD: /* Handle zero-length properly. */ if (0 == len) len = term_len(p, 1); p->offset = mt->offset; p->rmargin = mt->offset + len; savelit = MANT_LITERAL & mt->fl; mt->fl &= ~MANT_LITERAL; /* 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, meta); + nn = n->child; + while (NULL != nn && 0 == (MAN_LINE & nn->flags)) + nn = nn->next; + while (NULL != nn) { + print_man_node(p, mt, nn, meta); + nn = nn->next; + } + if (savelit) mt->fl |= MANT_LITERAL; if (ival >= 0) mt->lmargin[mt->lmargincur] = (size_t)ival; return(0); - case (MAN_BODY): + case MAN_BODY: p->offset = mt->offset + len; - p->rmargin = p->maxrmargin; + p->rmargin = p->maxrmargin > p->offset ? + p->maxrmargin : p->offset; p->trailspace = 0; p->flags &= ~TERMP_NOBREAK; break; default: break; } return(1); } - -/* ARGSUSED */ static void post_TP(DECL_ARGS) { switch (n->type) { - case (MAN_HEAD): + case MAN_HEAD: term_flushln(p); break; - case (MAN_BODY): + case MAN_BODY: term_newln(p); p->offset = mt->offset; break; default: break; } } - -/* ARGSUSED */ static int pre_SS(DECL_ARGS) { int i; switch (n->type) { - case (MAN_BLOCK): + case MAN_BLOCK: mt->fl &= ~MANT_LITERAL; mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); mt->offset = term_len(p, p->defindent); /* If following a prior empty `SS', no vspace. */ if (n->prev && MAN_SS == n->prev->tok) if (NULL == n->prev->body->child) break; if (NULL == n->prev) break; for (i = 0; i < mt->pardist; i++) term_vspace(p); break; - case (MAN_HEAD): + case MAN_HEAD: term_fontrepl(p, TERMFONT_BOLD); p->offset = term_len(p, 3); break; - case (MAN_BODY): + case MAN_BODY: p->offset = mt->offset; break; default: break; } return(1); } - -/* ARGSUSED */ static void post_SS(DECL_ARGS) { - + switch (n->type) { - case (MAN_HEAD): + case MAN_HEAD: term_newln(p); break; - case (MAN_BODY): + case MAN_BODY: term_newln(p); break; default: break; } } - -/* ARGSUSED */ static int pre_SH(DECL_ARGS) { int i; switch (n->type) { - case (MAN_BLOCK): + case MAN_BLOCK: mt->fl &= ~MANT_LITERAL; mt->lmargin[mt->lmargincur] = term_len(p, p->defindent); mt->offset = term_len(p, p->defindent); /* If following a prior empty `SH', no vspace. */ if (n->prev && MAN_SH == n->prev->tok) if (NULL == n->prev->body->child) break; /* If the first macro, no vspae. */ if (NULL == n->prev) break; for (i = 0; i < mt->pardist; i++) term_vspace(p); break; - case (MAN_HEAD): + case MAN_HEAD: term_fontrepl(p, TERMFONT_BOLD); p->offset = 0; break; - case (MAN_BODY): + case MAN_BODY: p->offset = mt->offset; break; default: break; } return(1); } - -/* ARGSUSED */ static void post_SH(DECL_ARGS) { - + switch (n->type) { - case (MAN_HEAD): + case MAN_HEAD: term_newln(p); break; - case (MAN_BODY): + case MAN_BODY: term_newln(p); break; default: break; } } -/* ARGSUSED */ static int pre_RS(DECL_ARGS) { int ival; size_t sz; switch (n->type) { - case (MAN_BLOCK): + case MAN_BLOCK: term_newln(p); return(1); - case (MAN_HEAD): + case MAN_HEAD: return(0); default: break; } sz = term_len(p, p->defindent); if (NULL != (n = n->parent->head->child)) - if ((ival = a2width(p, n->string)) >= 0) + if ((ival = a2width(p, n->string)) >= 0) sz = (size_t)ival; mt->offset += sz; - p->rmargin = p->maxrmargin; - p->offset = mt->offset < p->rmargin ? mt->offset : p->rmargin; + p->offset = mt->offset; + p->rmargin = p->maxrmargin > p->offset ? + p->maxrmargin : p->offset; if (++mt->lmarginsz < MAXMARGINS) mt->lmargincur = mt->lmarginsz; mt->lmargin[mt->lmargincur] = mt->lmargin[mt->lmargincur - 1]; return(1); } -/* ARGSUSED */ static void post_RS(DECL_ARGS) { int ival; size_t sz; switch (n->type) { - case (MAN_BLOCK): + case MAN_BLOCK: return; - case (MAN_HEAD): + case MAN_HEAD: return; default: term_newln(p); break; } sz = term_len(p, p->defindent); - if (NULL != (n = n->parent->head->child)) - if ((ival = a2width(p, n->string)) >= 0) + if (NULL != (n = n->parent->head->child)) + if ((ival = a2width(p, n->string)) >= 0) sz = (size_t)ival; mt->offset = mt->offset < sz ? 0 : mt->offset - sz; p->offset = mt->offset; if (--mt->lmarginsz < MAXMARGINS) 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) { size_t rm, rmax; int c; switch (n->type) { - case(MAN_TEXT): + case MAN_TEXT: /* * If we have a blank line, output a vertical space. * If we have a space as the first character, break * before printing the line's data. */ if ('\0' == *n->string) { term_vspace(p); return; } else if (' ' == *n->string && MAN_LINE & n->flags) term_newln(p); term_word(p, n->string); goto out; - case (MAN_EQN): + case MAN_EQN: term_eqn(p, n->eqn); return; - case (MAN_TBL): + case MAN_TBL: /* * Tables are preceded by a newline. Then process a * table line, which will cause line termination, */ - if (TBL_SPAN_FIRST & n->span->flags) + if (TBL_SPAN_FIRST & n->span->flags) term_newln(p); term_tbl(p, n->span); return; default: break; } if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) term_fontrepl(p, TERMFONT_NONE); c = 1; if (termacts[n->tok].pre) c = (*termacts[n->tok].pre)(p, mt, n, meta); if (c && n->child) print_man_nodelist(p, mt, n->child, meta); if (termacts[n->tok].post) (*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)) { + (NULL == n->next || MAN_LINE & n->next->flags)) { 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; } static void print_man_nodelist(DECL_ARGS) { print_man_node(p, mt, n, meta); if ( ! n->next) return; print_man_nodelist(p, mt, n->next, meta); } - static void print_man_foot(struct termp *p, const void *arg) { - char title[BUFSIZ]; - size_t datelen; - const struct man_meta *meta; + const struct man_meta *meta; + char *title; + size_t datelen; meta = (const struct man_meta *)arg; assert(meta->title); assert(meta->msec); assert(meta->date); term_fontrepl(p, TERMFONT_NONE); - term_vspace(p); + if (meta->hasbody) + term_vspace(p); /* * Temporary, undocumented option to imitate mdoc(7) output. * In the bottom right corner, use the source instead of * the title. */ if ( ! p->mdocstyle) { - term_vspace(p); - term_vspace(p); - snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec); + if (meta->hasbody) { + term_vspace(p); + term_vspace(p); + } + mandoc_asprintf(&title, "%s(%s)", + meta->title, meta->msec); } else if (meta->source) { - strlcpy(title, meta->source, BUFSIZ); + title = mandoc_strdup(meta->source); } else { - title[0] = '\0'; + title = mandoc_strdup(""); } datelen = term_strlen(p, meta->date); /* 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; if (meta->source) term_word(p, meta->source); term_flushln(p); /* At the bottom in the middle: manual date. */ p->flags |= TERMP_NOSPACE; p->offset = p->rmargin; p->rmargin = p->maxrmargin - term_strlen(p, title); if (p->offset + datelen >= p->rmargin) p->rmargin = p->offset + datelen; term_word(p, meta->date); term_flushln(p); /* Bottom right corner: manual title and section. */ p->flags &= ~TERMP_NOBREAK; p->flags |= TERMP_NOSPACE; p->trailspace = 0; p->offset = p->rmargin; p->rmargin = p->maxrmargin; term_word(p, title); term_flushln(p); + free(title); } - static void print_man_head(struct termp *p, const void *arg) { - char buf[BUFSIZ], title[BUFSIZ]; - size_t buflen, titlen; - const struct man_meta *meta; + const struct man_meta *meta; + const char *volume; + char *title; + size_t vollen, titlen; meta = (const struct man_meta *)arg; assert(meta->title); assert(meta->msec); - if (meta->vol) - strlcpy(buf, meta->vol, BUFSIZ); - else - buf[0] = '\0'; - buflen = term_strlen(p, buf); + volume = NULL == meta->vol ? "" : meta->vol; + vollen = term_strlen(p, volume); /* Top left corner: manual title and section. */ - snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec); + mandoc_asprintf(&title, "%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 - - term_strlen(p, buf) + term_len(p, 1)) / 2 : - p->maxrmargin - buflen; + p->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ? + (p->maxrmargin - vollen + term_len(p, 1)) / 2 : + p->maxrmargin - vollen; term_word(p, title); term_flushln(p); /* At the top in the middle: manual volume. */ p->flags |= TERMP_NOSPACE; p->offset = p->rmargin; - p->rmargin = p->offset + buflen + titlen < p->maxrmargin ? + p->rmargin = p->offset + vollen + titlen < p->maxrmargin ? p->maxrmargin - titlen : p->maxrmargin; - term_word(p, buf); + term_word(p, volume); term_flushln(p); /* 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; p->rmargin = p->maxrmargin; term_word(p, title); term_flushln(p); } p->flags &= ~TERMP_NOSPACE; p->offset = 0; p->rmargin = p->maxrmargin; - /* + /* * Groff prints three blank lines before the content. * Do the same, except in the temporary, undocumented * mode imitating mdoc(7) output. */ term_vspace(p); if ( ! p->mdocstyle) { term_vspace(p); term_vspace(p); } + free(title); } Index: head/contrib/mdocml/man_validate.c =================================================================== --- head/contrib/mdocml/man_validate.c (revision 274879) +++ head/contrib/mdocml/man_validate.c (revision 274880) @@ -1,592 +1,546 @@ -/* $Id: man_validate.c,v 1.86 2013/10/17 20:54:58 schwarze Exp $ */ +/* $Id: man_validate.c,v 1.105 2014/08/06 15:09:05 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2010, 2012, 2013 Ingo Schwarze + * Copyright (c) 2010, 2012, 2013, 2014 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include "man.h" #include "mandoc.h" +#include "mandoc_aux.h" #include "libman.h" #include "libmandoc.h" #define CHKARGS struct man *man, struct man_node *n typedef int (*v_check)(CHKARGS); -struct man_valid { - v_check *pres; - v_check *posts; -}; - static int check_eq0(CHKARGS); 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 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); static int post_nf(CHKARGS); -static int post_sec(CHKARGS); static int post_TH(CHKARGS); static int post_UC(CHKARGS); -static int pre_sec(CHKARGS); +static int post_UR(CHKARGS); -static v_check posts_at[] = { post_AT, NULL }; -static v_check posts_br[] = { post_vs, check_eq0, NULL }; -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 }; -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] = { - { NULL, posts_br }, /* br */ - { NULL, posts_th }, /* TH */ - { pres_sec, posts_sec }, /* SH */ - { pres_sec, posts_sec }, /* SS */ - { NULL, NULL }, /* TP */ - { NULL, posts_par }, /* LP */ - { NULL, posts_par }, /* PP */ - { NULL, posts_par }, /* P */ - { NULL, posts_ip }, /* IP */ - { NULL, NULL }, /* HP */ - { NULL, NULL }, /* SM */ - { NULL, NULL }, /* SB */ - { NULL, NULL }, /* BI */ - { NULL, NULL }, /* IB */ - { NULL, NULL }, /* BR */ - { NULL, NULL }, /* RB */ - { NULL, NULL }, /* R */ - { NULL, NULL }, /* B */ - { NULL, NULL }, /* I */ - { NULL, NULL }, /* IR */ - { NULL, NULL }, /* RI */ - { NULL, posts_eq0 }, /* na */ - { NULL, posts_sp }, /* sp */ - { NULL, posts_nf }, /* nf */ - { NULL, posts_fi }, /* fi */ - { NULL, NULL }, /* RE */ - { NULL, posts_part }, /* RS */ - { NULL, NULL }, /* DT */ - { NULL, posts_uc }, /* UC */ - { 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 */ +static v_check man_valids[MAN_MAX] = { + post_vs, /* br */ + post_TH, /* TH */ + NULL, /* SH */ + NULL, /* SS */ + NULL, /* TP */ + check_par, /* LP */ + check_par, /* PP */ + check_par, /* P */ + post_IP, /* IP */ + NULL, /* HP */ + NULL, /* SM */ + NULL, /* SB */ + NULL, /* BI */ + NULL, /* IB */ + NULL, /* BR */ + NULL, /* RB */ + NULL, /* R */ + NULL, /* B */ + NULL, /* I */ + NULL, /* IR */ + NULL, /* RI */ + check_eq0, /* na */ + post_vs, /* sp */ + post_nf, /* nf */ + post_fi, /* fi */ + NULL, /* RE */ + check_part, /* RS */ + NULL, /* DT */ + post_UC, /* UC */ + check_le1, /* PD */ + post_AT, /* AT */ + NULL, /* in */ + post_ft, /* ft */ + check_eq2, /* OP */ + post_nf, /* EX */ + post_fi, /* EE */ + post_UR, /* UR */ + NULL, /* UE */ + NULL, /* ll */ }; int -man_valid_pre(struct man *man, struct man_node *n) -{ - v_check *cp; - - switch (n->type) { - case (MAN_TEXT): - /* FALLTHROUGH */ - case (MAN_ROOT): - /* FALLTHROUGH */ - case (MAN_EQN): - /* FALLTHROUGH */ - case (MAN_TBL): - return(1); - default: - break; - } - - if (NULL == (cp = man_valids[n->tok].pres)) - return(1); - for ( ; *cp; cp++) - if ( ! (*cp)(man, n)) - return(0); - return(1); -} - - -int man_valid_post(struct man *man) { + struct man_node *n; v_check *cp; - if (MAN_VALID & man->last->flags) + n = man->last; + if (n->flags & MAN_VALID) return(1); - man->last->flags |= MAN_VALID; + n->flags |= MAN_VALID; - switch (man->last->type) { - case (MAN_TEXT): - check_text(man, man->last); - return(1); - case (MAN_ROOT): - return(check_root(man, man->last)); - case (MAN_EQN): + switch (n->type) { + case MAN_TEXT: + return(check_text(man, n)); + case MAN_ROOT: + return(check_root(man, n)); + case MAN_EQN: /* FALLTHROUGH */ - case (MAN_TBL): + case MAN_TBL: return(1); default: - break; + cp = man_valids + n->tok; + return(*cp ? (*cp)(man, n) : 1); } - - if (NULL == (cp = man_valids[man->last->tok].posts)) - return(1); - for ( ; *cp; cp++) - if ( ! (*cp)(man, man->last)) - return(0); - - return(1); } - static int -check_root(CHKARGS) +check_root(CHKARGS) { - if (MAN_BLINE & man->flags) - man_nmsg(man, n, MANDOCERR_SCOPEEXIT); - else if (MAN_ELINE & man->flags) - man_nmsg(man, n, MANDOCERR_SCOPEEXIT); + assert((man->flags & (MAN_BLINE | MAN_ELINE)) == 0); - man->flags &= ~MAN_BLINE; - man->flags &= ~MAN_ELINE; + if (NULL == man->first->child) + mandoc_msg(MANDOCERR_DOC_EMPTY, man->parse, + n->line, n->pos, NULL); + else + man->meta.hasbody = 1; - if (NULL == man->first->child) { - man_nmsg(man, n, MANDOCERR_NODOCBODY); - return(0); - } else if (NULL == man->meta.title) { - man_nmsg(man, n, MANDOCERR_NOTITLE); + if (NULL == man->meta.title) { + mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse, + n->line, n->pos, NULL); /* * If a title hasn't been set, do so now (by * implication, date and section also aren't set). */ - man->meta.title = mandoc_strdup("unknown"); - man->meta.msec = mandoc_strdup("1"); - man->meta.date = mandoc_normdate - (man->parse, NULL, n->line, n->pos); + man->meta.title = mandoc_strdup(""); + man->meta.msec = mandoc_strdup(""); + man->meta.date = man->quick ? mandoc_strdup("") : + mandoc_normdate(man->parse, NULL, n->line, n->pos); } return(1); } -static void +static int check_text(CHKARGS) { char *cp, *p; if (MAN_LITERAL & man->flags) - return; + return(1); cp = n->string; for (p = cp; NULL != (p = strchr(p, '\t')); p++) - man_pmsg(man, n->line, (int)(p - cp), MANDOCERR_BADTAB); + mandoc_msg(MANDOCERR_FI_TAB, man->parse, + n->line, n->pos + (p - cp), NULL); + return(1); } #define INEQ_DEFINE(x, ineq, name) \ static int \ check_##name(CHKARGS) \ { \ if (n->nchild ineq (x)) \ return(1); \ mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line, n->pos, \ - "line arguments %s %d (have %d)", \ - #ineq, (x), n->nchild); \ + "line arguments %s %d (have %d)", \ + #ineq, (x), n->nchild); \ return(1); \ } INEQ_DEFINE(0, ==, eq0) INEQ_DEFINE(2, ==, eq2) INEQ_DEFINE(1, <=, le1) -INEQ_DEFINE(2, >=, ge2) INEQ_DEFINE(5, <=, le5) static int -check_head1(CHKARGS) +post_UR(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); + return(check_part(man, n)); } static int post_ft(CHKARGS) { char *cp; int ok; if (0 == n->nchild) return(1); ok = 0; cp = n->child->string; switch (*cp) { - case ('1'): + case '1': /* FALLTHROUGH */ - case ('2'): + case '2': /* FALLTHROUGH */ - case ('3'): + case '3': /* FALLTHROUGH */ - case ('4'): + case '4': /* FALLTHROUGH */ - case ('I'): + case 'I': /* FALLTHROUGH */ - case ('P'): + case 'P': /* FALLTHROUGH */ - case ('R'): + case 'R': if ('\0' == cp[1]) ok = 1; break; - case ('B'): + case 'B': if ('\0' == cp[1] || ('I' == cp[1] && '\0' == cp[2])) ok = 1; break; - case ('C'): + case 'C': if ('W' == cp[1] && '\0' == cp[2]) ok = 1; break; default: break; } if (0 == ok) { - mandoc_vmsg - (MANDOCERR_BADFONT, man->parse, - n->line, n->pos, "%s", cp); + mandoc_vmsg(MANDOCERR_FT_BAD, man->parse, + n->line, n->pos, "ft %s", cp); *cp = '\0'; } if (1 < n->nchild) - mandoc_vmsg - (MANDOCERR_ARGCOUNT, man->parse, n->line, - n->pos, "want one child (have %d)", - n->nchild); + mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line, + n->pos, "want one child (have %d)", n->nchild); return(1); } static int -pre_sec(CHKARGS) -{ - - if (MAN_BLOCK == n->type) - man->flags &= ~MAN_LITERAL; - return(1); -} - -static int -post_sec(CHKARGS) -{ - - if ( ! (MAN_HEAD == n->type && 0 == n->nchild)) - return(1); - - man_nmsg(man, n, MANDOCERR_SYNTARGCOUNT); - return(0); -} - -static int check_part(CHKARGS) { if (MAN_BODY == n->type && 0 == n->nchild) - mandoc_msg(MANDOCERR_ARGCWARN, man->parse, n->line, - n->pos, "want children (have none)"); + mandoc_msg(MANDOCERR_ARGCWARN, man->parse, n->line, + n->pos, "want children (have none)"); return(1); } - static int check_par(CHKARGS) { switch (n->type) { - case (MAN_BLOCK): + case MAN_BLOCK: if (0 == n->body->nchild) man_node_delete(man, n); break; - case (MAN_BODY): + case MAN_BODY: if (0 == n->nchild) - man_nmsg(man, n, MANDOCERR_IGNPAR); + mandoc_vmsg(MANDOCERR_PAR_SKIP, + man->parse, n->line, n->pos, + "%s empty", man_macronames[n->tok]); break; - case (MAN_HEAD): + case MAN_HEAD: if (n->nchild) - man_nmsg(man, n, MANDOCERR_ARGSLOST); + mandoc_vmsg(MANDOCERR_ARG_SKIP, + man->parse, n->line, n->pos, + "%s %s%s", man_macronames[n->tok], + n->child->string, + n->nchild > 1 ? " ..." : ""); break; default: break; } return(1); } static int post_IP(CHKARGS) { switch (n->type) { - case (MAN_BLOCK): + case MAN_BLOCK: if (0 == n->head->nchild && 0 == n->body->nchild) man_node_delete(man, n); break; - case (MAN_BODY): + case MAN_BODY: if (0 == n->parent->head->nchild && 0 == n->nchild) - man_nmsg(man, n, MANDOCERR_IGNPAR); + mandoc_vmsg(MANDOCERR_PAR_SKIP, + man->parse, n->line, n->pos, + "%s empty", man_macronames[n->tok]); break; default: break; } return(1); } static int post_TH(CHKARGS) { + struct man_node *nb; const char *p; - int line, pos; + check_le5(man, n); + 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; man->meta.title = man->meta.vol = man->meta.date = - man->meta.msec = man->meta.source = NULL; + man->meta.msec = man->meta.source = NULL; + nb = n; + /* ->TITLE<- MSEC DATE SOURCE VOL */ n = n->child; if (n && n->string) { for (p = n->string; '\0' != *p; p++) { /* Only warn about this once... */ - if (isalpha((unsigned char)*p) && - ! isupper((unsigned char)*p)) { - man_nmsg(man, n, MANDOCERR_UPPERCASE); + if (isalpha((unsigned char)*p) && + ! isupper((unsigned char)*p)) { + mandoc_vmsg(MANDOCERR_TITLE_CASE, + man->parse, n->line, + n->pos + (p - n->string), + "TH %s", n->string); break; } } man->meta.title = mandoc_strdup(n->string); - } else + } else { man->meta.title = mandoc_strdup(""); + mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse, + nb->line, nb->pos, "TH"); + } /* TITLE ->MSEC<- DATE SOURCE VOL */ if (n) n = n->next; if (n && n->string) man->meta.msec = mandoc_strdup(n->string); - else + else { man->meta.msec = mandoc_strdup(""); + mandoc_vmsg(MANDOCERR_MSEC_MISSING, man->parse, + nb->line, nb->pos, "TH %s", man->meta.title); + } /* TITLE MSEC ->DATE<- SOURCE VOL */ if (n) n = n->next; if (n && n->string && '\0' != n->string[0]) { - pos = n->pos; - man->meta.date = mandoc_normdate - (man->parse, n->string, line, pos); - } else + man->meta.date = man->quick ? + mandoc_strdup(n->string) : + mandoc_normdate(man->parse, n->string, + n->line, n->pos); + } else { man->meta.date = mandoc_strdup(""); + mandoc_msg(MANDOCERR_DATE_MISSING, man->parse, + n ? n->line : nb->line, + n ? n->pos : nb->pos, "TH"); + } /* TITLE MSEC DATE ->SOURCE<- VOL */ if (n && (n = n->next)) 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)) 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(man, man->last); return(1); } static int post_nf(CHKARGS) { + check_eq0(man, n); + if (MAN_LITERAL & man->flags) - man_nmsg(man, n, MANDOCERR_SCOPEREP); + mandoc_msg(MANDOCERR_NF_SKIP, man->parse, + n->line, n->pos, "nf"); man->flags |= MAN_LITERAL; return(1); } static int post_fi(CHKARGS) { + check_eq0(man, n); + if ( ! (MAN_LITERAL & man->flags)) - man_nmsg(man, n, MANDOCERR_WNOSCOPE); + mandoc_msg(MANDOCERR_FI_SKIP, man->parse, + n->line, n->pos, "fi"); man->flags &= ~MAN_LITERAL; return(1); } static int post_UC(CHKARGS) { static const char * const bsd_versions[] = { "3rd Berkeley Distribution", "4th Berkeley Distribution", "4.2 Berkeley Distribution", "4.3 Berkeley Distribution", "4.4 Berkeley Distribution", }; const char *p, *s; n = n->child; if (NULL == n || MAN_TEXT != n->type) p = bsd_versions[0]; else { s = n->string; if (0 == strcmp(s, "3")) p = bsd_versions[0]; else if (0 == strcmp(s, "4")) p = bsd_versions[1]; else if (0 == strcmp(s, "5")) p = bsd_versions[2]; else if (0 == strcmp(s, "6")) p = bsd_versions[3]; else if (0 == strcmp(s, "7")) p = bsd_versions[4]; else p = bsd_versions[0]; } free(man->meta.source); man->meta.source = mandoc_strdup(p); return(1); } static int post_AT(CHKARGS) { static const char * const unix_versions[] = { "7th Edition", "System III", "System V", "System V Release 2", }; const char *p, *s; struct man_node *nn; n = n->child; if (NULL == n || MAN_TEXT != n->type) p = unix_versions[0]; else { s = n->string; if (0 == strcmp(s, "3")) p = unix_versions[0]; else if (0 == strcmp(s, "4")) p = unix_versions[1]; else if (0 == strcmp(s, "5")) { nn = n->next; if (nn && MAN_TEXT == nn->type && nn->string[0]) p = unix_versions[3]; else p = unix_versions[2]; } else p = unix_versions[0]; } free(man->meta.source); man->meta.source = mandoc_strdup(p); return(1); } static int post_vs(CHKARGS) { + if (n->tok == MAN_br) + check_eq0(man, n); + else + check_le1(man, n); + if (NULL != n->prev) return(1); switch (n->parent->tok) { - case (MAN_SH): + case MAN_SH: /* FALLTHROUGH */ - case (MAN_SS): - man_nmsg(man, n, MANDOCERR_IGNPAR); + case MAN_SS: + mandoc_vmsg(MANDOCERR_PAR_SKIP, man->parse, n->line, n->pos, + "%s after %s", man_macronames[n->tok], + man_macronames[n->parent->tok]); /* FALLTHROUGH */ - case (MAN_MAX): - /* + 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); } Index: head/contrib/mdocml/mandoc.1 =================================================================== --- head/contrib/mdocml/mandoc.1 (revision 274879) +++ head/contrib/mdocml/mandoc.1 (revision 274880) @@ -1,681 +1,1502 @@ -.\" $Id: mandoc.1,v 1.103 2013/07/13 19:41:16 schwarze Exp $ +.\" $Id: mandoc.1,v 1.106 2014/08/08 01:50:59 schwarze Exp $ .\" .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons -.\" Copyright (c) 2012 Ingo Schwarze +.\" Copyright (c) 2012, 2014 Ingo Schwarze .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: July 13 2013 $ +.Dd $Mdocdate: August 8 2014 $ .Dt MANDOC 1 .Os .Sh NAME .Nm mandoc .Nd format and display UNIX manuals .Sh SYNOPSIS .Nm mandoc .Op Fl V .Sm off .Op Fl I Cm os Li = Ar name .Sm on .Op Fl m Ns Ar format .Op Fl O Ns Ar option .Op Fl T Ns Ar output .Op Fl W Ns Ar level .Op Ar .Sh DESCRIPTION The .Nm utility formats .Ux manual pages for display. .Pp By default, .Nm reads .Xr mdoc 7 or .Xr man 7 text from stdin, implying .Fl m Ns Cm andoc , and produces .Fl T Ns Cm ascii output. .Pp The arguments are as follows: .Bl -tag -width Ds .Sm off .It Fl I Cm os Li = Ar name .Sm on Override the default operating system .Ar name for the .Xr mdoc 7 .Sq \&Os macro. .It Fl m Ns Ar format Input format. See .Sx Input Formats for available formats. Defaults to .Fl m Ns Cm andoc . .It Fl O Ns Ar option Comma-separated output options. .It Fl T Ns Ar output Output format. See .Sx Output Formats for available formats. Defaults to .Fl T Ns Cm ascii . .It Fl V Print version and exit. .It Fl W Ns Ar level Specify the minimum message .Ar level to be reported on the standard error output and to affect the exit status. The .Ar level can be .Cm warning , .Cm error , or .Cm fatal . The default is .Fl W Ns Cm fatal ; .Fl W Ns Cm all is an alias for .Fl W Ns Cm warning . See .Sx EXIT STATUS and .Sx DIAGNOSTICS for details. .Pp The special option .Fl W Ns Cm stop tells .Nm to exit after parsing a file that causes warnings or errors of at least the requested level. No formatted output will be produced from that file. If both a .Ar level and .Cm stop are requested, they can be joined with a comma, for example .Fl W Ns Cm error , Ns Cm stop . .It Ar file Read input from zero or more files. If unspecified, reads from stdin. If multiple files are specified, .Nm will halt with the first failed parse. .El .Ss Input Formats The .Nm utility accepts .Xr mdoc 7 and .Xr man 7 input with .Fl m Ns Cm doc and .Fl m Ns Cm an , respectively. The .Xr mdoc 7 format is .Em strongly recommended; .Xr man 7 should only be used for legacy manuals. .Pp A third option, .Fl m Ns Cm andoc , which is also the default, determines encoding on-the-fly: if the first non-comment macro is .Sq \&Dd or .Sq \&Dt , the .Xr mdoc 7 parser is used; otherwise, the .Xr man 7 parser is used. .Pp If multiple files are specified with .Fl m Ns Cm andoc , each has its file-type determined this way. If multiple files are specified and .Fl m Ns Cm doc or .Fl m Ns Cm an is specified, then this format is used exclusively. .Ss Output Formats The .Nm utility accepts the following .Fl T arguments, which correspond to output modes: .Bl -tag -width "-Tlocale" .It Fl T Ns Cm ascii Produce 7-bit ASCII output. This is the default. See .Sx ASCII Output . .It Fl T Ns Cm html Produce strict CSS1/HTML-4.01 output. See .Sx HTML Output . .It Fl T Ns Cm lint Parse only: produce no output. Implies .Fl W Ns Cm warning . .It Fl T Ns Cm locale Encode output using the current locale. See .Sx Locale Output . .It Fl T Ns Cm man Produce .Xr man 7 format output. See .Sx Man Output . .It Fl T Ns Cm pdf Produce PDF output. See .Sx PDF Output . .It Fl T Ns Cm ps Produce PostScript output. See .Sx PostScript Output . .It Fl T Ns Cm tree Produce an indented parse tree. .It Fl T Ns Cm utf8 Encode output in the UTF\-8 multi-byte format. See .Sx UTF\-8 Output . .It Fl T Ns Cm xhtml Produce strict CSS1/XHTML-1.0 output. See .Sx XHTML Output . .El .Pp If multiple input files are specified, these will be processed by the corresponding filter in-order. .Ss ASCII Output Output produced by .Fl T Ns Cm ascii , which is the default, is rendered in standard 7-bit ASCII documented in .Xr ascii 7 . .Pp Font styles are applied by using back-spaced encoding such that an underlined character .Sq c is rendered as .Sq _ Ns \e[bs] Ns c , where .Sq \e[bs] is the back-space character number 8. Emboldened characters are rendered as .Sq c Ns \e[bs] Ns c . .Pp The special characters documented in .Xr mandoc_char 7 are rendered best-effort in an ASCII equivalent. If no equivalent is found, .Sq \&? is used instead. .Pp Output width is limited to 78 visible columns unless literal input lines exceed this limit. .Pp The following .Fl O arguments are accepted: .Bl -tag -width Ds .It Cm indent Ns = Ns Ar indent The left margin for normal text is set to .Ar indent blank characters instead of the default of five for .Xr mdoc 7 and seven for .Xr man 7 . Increasing this is not recommended; it may result in degraded formatting, for example overfull lines or ugly line breaks. .It Cm width Ns = Ns Ar width The output width is set to .Ar width , which will normalise to \(>=60. .El .Ss HTML Output Output produced by .Fl T Ns Cm html conforms to HTML-4.01 strict. .Pp The .Pa example.style.css file documents style-sheet classes available for customising output. If a style-sheet is not specified with .Fl O Ns Ar style , .Fl T Ns Cm html defaults to simple output readable in any graphical or text-based web browser. .Pp Special characters are rendered in decimal-encoded UTF\-8. .Pp The following .Fl O arguments are accepted: .Bl -tag -width Ds .It Cm fragment Omit the .Aq !DOCTYPE declaration and the .Aq html , .Aq head , and .Aq body elements and only emit the subtree below the .Aq body element. The .Cm style argument will be ignored. This is useful when embedding manual content within existing documents. .It Cm includes Ns = Ns Ar fmt The string .Ar fmt , for example, .Ar ../src/%I.html , is used as a template for linked header files (usually via the .Sq \&In macro). Instances of .Sq \&%I are replaced with the include filename. The default is not to present a hyperlink. .It Cm man Ns = Ns Ar fmt The string .Ar fmt , for example, .Ar ../html%S/%N.%S.html , is used as a template for linked manuals (usually via the .Sq \&Xr macro). Instances of .Sq \&%N and .Sq %S are replaced with the linked manual's name and section, respectively. If no section is included, section 1 is assumed. The default is not to present a hyperlink. .It Cm style Ns = Ns Ar style.css The file .Ar style.css is used for an external style-sheet. This must be a valid absolute or relative URI. .El .Ss Locale Output Locale-depending output encoding is triggered with .Fl T Ns Cm locale . This option is not available on all systems: systems without locale support, or those whose internal representation is not natively UCS-4, will fall back to .Fl T Ns Cm ascii . See .Sx ASCII Output for font style specification and available command-line arguments. .Ss Man Output Translate input format into .Xr man 7 output format. This is useful for distributing manual sources to legacy systems lacking .Xr mdoc 7 formatters. .Pp If .Xr mdoc 7 is passed as input, it is translated into .Xr man 7 . If the input format is .Xr man 7 , the input is copied to the output, expanding any .Xr roff 7 .Sq so requests. The parser is also run, and as usual, the .Fl W level controls which .Sx DIAGNOSTICS are displayed before copying the input to the output. .Ss PDF Output PDF-1.1 output may be generated by .Fl T Ns Cm pdf . See .Sx PostScript Output for .Fl O arguments and defaults. .Ss PostScript Output PostScript .Qq Adobe-3.0 Level-2 pages may be generated by .Fl T Ns Cm ps . Output pages default to letter sized and are rendered in the Times font family, 11-point. Margins are calculated as 1/9 the page length and width. Line-height is 1.4m. .Pp Special characters are rendered as in .Sx ASCII Output . .Pp The following .Fl O arguments are accepted: .Bl -tag -width Ds .It Cm paper Ns = Ns Ar name The paper size .Ar name may be one of .Ar a3 , .Ar a4 , .Ar a5 , .Ar legal , or .Ar letter . You may also manually specify dimensions as .Ar NNxNN , width by height in millimetres. If an unknown value is encountered, .Ar letter is used. .El .Ss UTF\-8 Output Use .Fl T Ns Cm utf8 to force a UTF\-8 locale. See .Sx Locale Output for details and options. .Ss XHTML Output Output produced by .Fl T Ns Cm xhtml conforms to XHTML-1.0 strict. .Pp See .Sx HTML Output for details; beyond generating XHTML tags instead of HTML tags, these output modes are identical. .Sh EXIT STATUS The .Nm utility exits with one of the following values, controlled by the message .Ar level associated with the .Fl W option: .Pp .Bl -tag -width Ds -compact .It 0 No warnings or errors occurred, or those that did were ignored because they were lower than the requested .Ar level . .It 2 At least one warning occurred, but no error, and .Fl W Ns Cm warning was specified. .It 3 At least one parsing error occurred, but no fatal error, and .Fl W Ns Cm error or .Fl W Ns Cm warning was specified. .It 4 A fatal parsing error occurred. .It 5 Invalid command line arguments were specified. No input files have been read. .It 6 An operating system error occurred, for example memory exhaustion or an error accessing input files. Such errors cause .Nm to exit at once, possibly in the middle of parsing or formatting a file. .El .Pp Note that selecting .Fl T Ns Cm lint output mode implies .Fl W Ns Cm warning . .Sh EXAMPLES To page manuals to the terminal: .Pp .Dl $ mandoc \-Wall,stop mandoc.1 2\*(Gt&1 | less .Dl $ mandoc mandoc.1 mdoc.3 mdoc.7 | less .Pp To produce HTML manuals with .Ar style.css as the style-sheet: .Pp .Dl $ mandoc \-Thtml -Ostyle=style.css mdoc.7 \*(Gt mdoc.7.html .Pp To check over a large set of manuals: .Pp .Dl $ mandoc \-Tlint `find /usr/src -name \e*\e.[1-9]` .Pp To produce a series of PostScript manuals for A4 paper: .Pp .Dl $ mandoc \-Tps \-Opaper=a4 mdoc.7 man.7 \*(Gt manuals.ps .Pp Convert a modern .Xr mdoc 7 manual to the older .Xr man 7 format, for use on systems lacking an .Xr mdoc 7 parser: .Pp .Dl $ mandoc \-Tman foo.mdoc \*(Gt foo.man .Sh DIAGNOSTICS -Standard error messages reporting parsing errors are prefixed by +Messages displayed by +.Nm +follow this format: .Pp -.Sm off -.D1 Ar file : line : column : \ level : -.Sm on +.D1 Nm Ns : Ar file : Ns Ar line : Ns Ar column : level : message : macro args .Pp -where the fields have the following meanings: -.Bl -tag -width "column" -.It Ar file -The name of the input file causing the message. -.It Ar line -The line number in that input file. -Line numbering starts at 1. -.It Ar column -The column number in that input file. -Column numbering starts at 1. -If the issue is caused by a word, the column number usually -points to the first character of the word. -.It Ar level -The message level, printed in capital letters. -.El +Line and column numbers start at 1. +Both are omitted for messages referring to an input file as a whole. +Macro names and arguments are omitted where meaningless. +Fatal messages about invalid command line arguments +or operating system errors, for example when memory is exhausted, +may also omit the +.Ar file +and +.Ar level +fields. .Pp Message levels have the following meanings: .Bl -tag -width "warning" +.It Cm syserr +Opening or reading an input file failed, so the parser cannot +even be started and no output is produced from that input file. .It Cm fatal The parser is unable to parse a given input file at all. No formatted output is produced from that input file. .It Cm error An input file contains syntax that cannot be safely interpreted, either because it is invalid or because .Nm does not implement it yet. By discarding part of the input or inserting missing tokens, the parser is able to continue, and the error does not prevent generation of formatted output, but typically, preparing that output involves information loss, broken document structure or unintended formatting. .It Cm warning An input file uses obsolete, discouraged or non-portable syntax. All the same, the meaning of the input is unambiguous and a correct rendering can be produced. Documents causing warnings may render poorly when using other formatting tools instead of .Nm . .El .Pp Messages of the .Cm warning and .Cm error levels are hidden unless their level, or a lower level, is requested using a .Fl W option or .Fl T Ns Cm lint output mode. -.Pp +.Ss Warnings related to the document prologue +.Bl -ohang +.It Sy "missing manual title, using UNTITLED" +.Pq mdoc +A +.Ic \&Dt +macro has no arguments, or there is no +.Ic \&Dt +macro before the first non-prologue macro. +.It Sy "missing manual title, using \(dq\(dq" +.Pq man +There is no +.Ic \&TH +macro, or it has no arguments. +.It Sy "lower case character in document title" +.Pq mdoc , man +The title is still used as given in the +.Ic \&Dt +or +.Ic \&TH +macro. +.It Sy "missing manual section, using \(dq\(dq" +.Pq mdoc , man +A +.Ic \&Dt +or +.Ic \&TH +macro lacks the mandatory section argument. +.It Sy "unknown manual section" +.Pq mdoc +The section number in a +.Ic \&Dt +line is invalid, but still used. +.It Sy "unknown manual volume or arch" +.Pq mdoc +The volume name in a +.Ic \&Dt +line is invalid, but still used. +The manual is assumed to be architecture-independent. +.It Sy "missing date, using today's date" +.Pq mdoc, man +The document was parsed as +.Xr mdoc 7 +and it has no +.Ic \&Dd +macro, or the +.Ic \&Dd +macro has no arguments or only empty arguments; +or the document was parsed as +.Xr man 7 +and it has no +.Ic \&TH +macro, or the +.Ic \&TH +macro has less than three arguments or its third argument is empty. +.It Sy "cannot parse date, using it verbatim" +.Pq mdoc , man +The date given in a +.Ic \&Dd +or +.Ic \&TH +macro does not follow the conventional format. +.It Sy "missing Os macro, using \(dq\(dq" +.Pq mdoc +The default or current system is not shown in this case. +.It Sy "duplicate prologue macro" +.Pq mdoc +One of the prologue macros occurs more than once. +The last instance overrides all previous ones. +.It Sy "late prologue macro" +.Pq mdoc +A +.Ic \&Dd +or +.Ic \&Os +macro occurs after some non-prologue macro, but still takes effect. +.It Sy "skipping late title macro" +.Pq mdoc The +.Ic \&Dt +macro can only occur before the first non-prologue macro +because traditional formatters write the page header +before parsing the document body. +Even though this technical restriction does not apply to +.Nm , +traditional semantics is preserved. +The late macro is discarded including its arguments. +.It Sy "prologue macros out of order" +.Pq mdoc +The prologue macros are not given in the conventional order +.Ic \&Dd , +.Ic \&Dt , +.Ic \&Os . +All three macros are used even when given in another order. +.El +.Ss Warnings regarding document structure +.Bl -ohang +.It Sy ".so is fragile, better use ln(1)" +.Pq roff +Including files only works when the parser program runs with the correct +current working directory. +.It Sy "no document body" +.Pq mdoc , man +The document body contains neither text nor macros. +An empty document is shown, consisting only of a header and a footer line. +.It Sy "content before first section header" +.Pq mdoc , man +Some macros or text precede the first +.Ic \&Sh +or +.Ic \&SH +section header. +The offending macros and text are parsed and added to the top level +of the syntax tree, outside any section block. +.It Sy "first section is not NAME" +.Pq mdoc +The argument of the first +.Ic \&Sh +macro is not +.Sq NAME . +This may confuse +.Xr makewhatis 8 +and +.Xr apropos 1 . +.It Sy "bad NAME section contents" +.Pq mdoc +The last node in the NAME section is not an +.Ic \&Nd +macro, or any preceding macro is not +.Ic \&Nm , +or the NAME section is completely empty. +This may confuse +.Xr makewhatis 8 +and +.Xr apropos 1 . +.It Sy "sections out of conventional order" +.Pq mdoc +A standard section occurs after another section it usually precedes. +All section titles are used as given, +and the order of sections is not changed. +.It Sy "duplicate section title" +.Pq mdoc +The same standard section title occurs more than once. +.It Sy "unexpected section" +.Pq mdoc +A standard section header occurs in a section of the manual +where it normally isn't useful. +.El +.Ss "Warnings related to macros and nesting" +.Bl -ohang +.It Sy "obsolete macro" +.Pq mdoc +See the +.Xr mdoc 7 +manual for replacements. +.It Sy "skipping paragraph macro" +In +.Xr mdoc 7 +documents, this happens +.Bl -dash -compact +.It +at the beginning and end of sections and subsections +.It +right before non-compact lists and displays +.It +at the end of items in non-column, non-compact lists +.It +and for multiple consecutive paragraph macros. +.El +In +.Xr man 7 +documents, it happens +.Bl -dash -compact +.It +for empty +.Ic \&P , +.Ic \&PP , +and +.Ic \&LP +macros +.It +for +.Ic \&IP +macros having neither head nor body arguments +.It +for +.Ic \&br +or +.Ic \&sp +right after +.Ic \&SH +or +.Ic \&SS +.El +.It Sy "moving paragraph macro out of list" +.Pq mdoc +A list item in a +.Ic \&Bl +list contains a trailing paragraph macro. +The paragraph macro is moved after the end of the list. +.It Sy "skipping no-space macro" +.Pq mdoc +An input line begins with an +.Ic \&Ns +macro. +The macro is ignored. +.It Sy "blocks badly nested" +.Pq mdoc +If two blocks intersect, one should completely contain the other. +Otherwise, rendered output is likely to look strange in any output +format, and rendering in SGML-based output formats is likely to be +outright wrong because such languages do not support badly nested +blocks at all. +Typical examples of badly nested blocks are +.Qq Ic \&Ao \&Bo \&Ac \&Bc +and +.Qq Ic \&Ao \&Bq \&Ac . +In these examples, +.Ic \&Ac +breaks +.Ic \&Bo +and +.Ic \&Bq , +respectively. +.It Sy "nested displays are not portable" +.Pq mdoc +A +.Ic \&Bd , +.Ic \&D1 , +or +.Ic \&Dl +display occurs nested inside another +.Ic \&Bd +display. +This works with +.Nm , +but fails with most other implementations. +.It Sy "moving content out of list" +.Pq mdoc +A +.Ic \&Bl +list block contains text or macros before the first +.Ic \&It +macro. +The offending children are moved before the beginning of the list. +.It Sy ".Vt block has child macro" +.Pq mdoc +The +.Ic \&Vt +macro supports plain text arguments only. +Formatting may be ugly and semantic searching +for the affected content might not work. +.It Sy "fill mode already enabled, skipping" +.Pq man +A +.Ic \&fi +request occurs even though the document is still in fill mode, +or already switched back to fill mode. +It has no effect. +.It Sy "fill mode already disabled, skipping" +.Pq man +An +.Ic \&nf +request occurs even though the document already switched to no-fill mode +and did not switch back to fill mode yet. +It has no effect. +.It Sy "line scope broken" +.Pq man +While parsing the next-line scope of the previous macro, +another macro is found that prematurely terminates the previous one. +The previous, interrupted macro is deleted from the parse tree. +.El +.Ss "Warnings related to missing arguments" +.Bl -ohang +.It Sy "skipping empty request" +.Pq roff +The macro name is missing from a macro definition request. +.It Sy "conditional request controls empty scope" +.Pq roff +A conditional request is only useful if any of the following +follows it on the same logical input line: +.Bl -dash -compact +.It +The +.Sq \e{ +keyword to open a multi-line scope. +.It +A request or macro or some text, resulting in a single-line scope. +.It +The immediate end of the logical line without any intervening whitespace, +resulting in next-line scope. +.El +Here, a conditional request is followed by trailing whitespace only, +and there is no other content on its logical input line. +Note that it doesn't matter whether the logical input line is split +across multiple physical input lines using +.Sq \e +line continuation characters. +This is one of the rare cases +where trailing whitespace is syntactically significant. +The conditional request controls a scope containing whitespace only, +so it is unlikely to have a significant effect, +except that it may control a following +.Ic \&el +clause. +.It Sy "skipping empty macro" +.Pq mdoc +The indicated macro has no arguments and hence no effect. +.It Sy "empty argument, using 0n" +.Pq mdoc +The required width is missing after +.Ic \&Bd +or +.Ic \&Bl +.Fl offset +or +.Fl width. +.It Sy "argument count wrong" +.Pq mdoc , man +The indicated macro has too few or too many arguments. +The syntax tree will contain the wrong number of arguments as given. +Formatting behaviour depends on the specific macro in question. +Note that the same message may also occur as an ERROR, see below. +.It Sy "missing display type, using -ragged" +.Pq mdoc +The +.Ic \&Bd +macro is invoked without the required display type. +.It Sy "list type is not the first argument" +.Pq mdoc +In a +.Ic \&Bl +macro, at least one other argument precedes the type argument. +The .Nm -utility may also print messages related to invalid command line arguments -or operating system errors, for example when memory is exhausted or -input files cannot be read. -Such messages do not carry the prefix described above. +utility copes with any argument order, but some other +.Xr mdoc 7 +implementations do not. +.It Sy "missing -width in -tag list, using 8n" +.Pq mdoc +Every +.Ic \&Bl +macro having the +.Fl tag +argument requires +.Fl width , +too. +.It Sy "missing utility name, using \(dq\(dq" +.Pq mdoc +The +.Ic \&Ex Fl std +macro is called without an argument before +.Ic \&Nm +has first been called with an argument. +.It Sy "empty head in list item" +.Pq mdoc +In a +.Ic \&Bl +.Fl diag , +.Fl hang , +.Fl inset , +.Fl ohang , +or +.Fl tag +list, an +.Ic \&It +macro lacks the required argument. +The item head is left empty. +.It Sy "empty list item" +.Pq mdoc +In a +.Ic \&Bl +.Fl bullet , +.Fl dash , +.Fl enum , +or +.Fl hyphen +list, an +.Ic \&It +block is empty. +An empty list item is shown. +.It Sy "missing font type" +.Pq mdoc +A +.Ic \&Bf +macro has no argument. +It switches to the default font, +.Cm \efR . +.It Sy "unknown font type" +.Pq mdoc +The +.Ic \&Bf +argument is invalid. +The default font +.Cm \efR +is used instead. +.It Sy "missing -std argument, adding it" +.Pq mdoc +An +.Ic \&Ex +or +.Ic \&Rv +macro lacks the required +.Fl std +argument. +The +.Nm +utility assumes +.Fl std +even when it is not specified, but other implementations may not. +.El +.Ss "Warnings related to bad macro arguments" +.Bl -ohang +.It Sy "unterminated quoted argument" +.Pq roff +Macro arguments can be enclosed in double quote characters +such that space characters and macro names contained in the quoted +argument need not be escaped. +The closing quote of the last argument of a macro can be omitted. +However, omitting it is not recommended because it makes the code +harder to read. +.It Sy "duplicate argument" +.Pq mdoc +A +.Ic \&Bd +or +.Ic \&Bl +macro has more than one +.Fl compact , +more than one +.Fl offset , +or more than one +.Fl width +argument. +All but the last instances of these arguments are ignored. +.It Sy "skipping duplicate argument" +.Pq mdoc +An +.Ic \&An +macro has more than one +.Fl split +or +.Fl nosplit +argument. +All but the first of these arguments are ignored. +.It Sy "skipping duplicate display type" +.Pq mdoc +A +.Ic \&Bd +macro has more than one type argument; the first one is used. +.It Sy "skipping duplicate list type" +.Pq mdoc +A +.Ic \&Bl +macro has more than one type argument; the first one is used. +.It Sy "skipping -width argument" +.Pq mdoc +A +.Ic \&Bl +.Fl column , +.Fl diag , +.Fl ohang , +.Fl inset , +or +.Fl item +list has a +.Fl width +argument. +That has no effect. +.It Sy "unknown AT&T UNIX version" +.Pq mdoc +An +.Ic \&At +macro has an invalid argument. +It is used verbatim, with +.Qq "AT&T UNIX " +prefixed to it. +.It Sy "invalid content in Rs block" +.Pq mdoc +An +.Ic \&Rs +block contains plain text or non-% macros. +The bogus content is left in the syntax tree. +Formatting may be poor. +.It Sy "invalid Boolean argument" +.Pq mdoc +An +.Ic \&Sm +macro has an argument other than +.Cm on +or +.Cm off . +The invalid argument is moved out of the macro, which leaves the macro +empty, causing it to toggle the spacing mode. +.It Sy "unknown font, skipping request" +.Pq man +A +.Xr roff 7 +.Ic \&ft +request has an invalid argument. +.El +.Ss "Warnings related to plain text" +.Bl -ohang +.It Sy "blank line in fill mode, using .sp" +.Pq mdoc +The meaning of blank input lines is only well-defined in non-fill mode: +In fill mode, line breaks of text input lines are not supposed to be +significant. +However, for compatibility with groff, blank lines in fill mode +are replaced with +.Ic \&sp +requests. +.It Sy "tab in filled text" +.Pq mdoc , man +The meaning of tab characters is only well-defined in non-fill mode: +In fill mode, whitespace is not supposed to be significant +on text input lines. +As an implementation dependent choice, tab characters on text lines +are passed through to the formatters in any case. +Given that the text before the tab character will be filled, +it is hard to predict which tab stop position the tab will advance to. +.It Sy "whitespace at end of input line" +.Pq mdoc , man , roff +Whitespace at the end of input lines is almost never semantically +significant \(em but in the odd case where it might be, it is +extremely confusing when reviewing and maintaining documents. +.It Sy "bad comment style" +.Pq roff +Comment lines start with a dot, a backslash, and a double-quote character. +The +.Nm +utility treats the line as a comment line even without the backslash, +but leaving out the backslash might not be portable. +.It Sy "invalid escape sequence" +.Pq roff +An escape sequence has an invalid opening argument delimiter, lacks the +closing argument delimiter, or the argument has too few characters. +If the argument is incomplete, +.Ic \e* +and +.Ic \en +expand to an empty string, +.Ic \eB +to the digit +.Sq 0 , +and +.Ic \ew +to the length of the incomplete argument. +All other invalid escape sequences are ignored. +.It Sy "undefined string, using \(dq\(dq" +.Pq roff +If a string is used without being defined before, +its value is implicitly set to the empty string. +However, defining strings explicitly before use +keeps the code more readable. +.El +.Ss "Errors related to equations" +.Bl -inset -compact +.It "unexpected equation scope closure" +.It "equation scope open on exit" +.It "overlapping equation scopes" +.It "unexpected end of equation" +.It "equation syntax error" +.El +.Ss "Errors related to tables" +.Bl -inset -compact +.It "bad table syntax" +.It "bad table option" +.It "bad table layout" +.It "no table layout cells specified" +.It "no table data cells specified" +.It "ignore data in cell" +.It "data block still open" +.It "ignoring extra data cells" +.El +.Ss "Errors related to roff, mdoc, and man code" +.Bl -ohang +.It Sy "input stack limit exceeded, infinite loop?" +.Pq roff +Explicit recursion limits are implemented for the following features, +in order to prevent infinite loops: +.Bl -dash -compact +.It +expansion of nested escape sequences +including expansion of strings and number registers, +.It +expansion of nested user-defined macros, +.It +and +.Ic \&so +file inclusion. +.El +When a limit is hit, the output is incorrect, typically losing +some content, but the parser can continue. +.It Sy "skipping bad character" +.Pq mdoc , man , roff +The input file contains a byte that is not a printable +.Xr ascii 7 +character. +The message mentions the character number. +The offending byte is replaced with a question mark +.Pq Sq \&? . +Consider editing the input file to replace the byte with an ASCII +transliteration of the intended character. +.It Sy "skipping unknown macro" +.Pq mdoc , man , roff +The first identifier on a request or macro line is neither recognized as a +.Xr roff 7 +request, nor as a user-defined macro, nor, respectively, as an +.Xr mdoc 7 +or +.Xr man 7 +macro. +It may be mistyped or unsupported. +The request or macro is discarded including its arguments. +.It Sy "skipping item outside list" +.Pq mdoc +An +.Ic \&It +macro occurs outside any +.Ic \&Bl +list. +It is discarded including its arguments. +.It Sy "skipping column outside column list" +.Pq mdoc +A +.Ic \&Ta +macro occurs outside any +.Ic \&Bl Fl column +block. +It is discarded including its arguments. +.It Sy "skipping end of block that is not open" +.Pq mdoc , man , eqn , tbl , roff +Various syntax elements can only be used to explicitly close blocks +that have previously been opened. +An +.Xr mdoc 7 +block closing macro, a +.Xr man 7 +.Ic \&RE +or +.Ic \&UE +macro, or the end of an equation, table, or +.Xr roff 7 +conditional request is encountered but no matching block is open. +The offending request or macro is discarded. +.It Sy "inserting missing end of block" +.Pq mdoc , tbl +Various +.Xr mdoc 7 +macros as well as tables require explicit closing by dedicated macros. +A block that doesn't support bad nesting +ends before all of its children are properly closed. +The open child nodes are closed implicitly. +.It Sy "scope open on exit" +.Pq mdoc , man , eqn , tbl , roff +At the end of the document, an explicit +.Xr mdoc 7 +block, a +.Xr man 7 +next-line scope or +.Ic \&RS +or +.Ic \&UR +block, an equation, table, or +.Xr roff 7 +conditional or ignore block is still open. +The open block is closed implicitly. +.It Sy "escaped character not allowed in a name" +.Pq roff +Macro, string and register identifiers consist of printable, +non-whitespace ASCII characters. +Escape sequences and characters and strings expressed in terms of them +cannot form part of a name. +The first argument of an +.Ic \&am , +.Ic \&as , +.Ic \&de , +.Ic \&ds , +.Ic \&nr , +or +.Ic \&rr +request, or any argument of an +.Ic \&rm +request, or the name of a request or user defined macro being called, +is terminated by an escape sequence. +In the cases of +.Ic \&as , +.Ic \&ds , +and +.Ic \&nr , +the request has no effect at all. +In the cases of +.Ic \&am , +.Ic \&de , +.Ic \&rr , +and +.Ic \&rm , +what was parsed up to this point is used as the arguments to the request, +and the rest of the input line is discarded including the escape sequence. +When parsing for a request or a user-defined macro name to be called, +only the escape sequence is discarded. +The characters preceding it are used as the request or macro name, +the characters following it are used as the arguments to the request or macro. +.It Sy "argument count wrong" +.Pq mdoc , man , roff +The indicated request or macro has too few or too many arguments. +The syntax tree will contain the wrong number of arguments as given. +Formatting behaviour depends on the specific request or macro in question. +Note that the same message may also occur as a WARNING, see above. +.It Sy "missing list type, using -item" +.Pq mdoc +A +.Ic \&Bl +macro fails to specify the list type. +.It Sy "missing manual name, using \(dq\(dq" +.Pq mdoc +The first call to +.Ic \&Nm +lacks the required argument. +.It Sy "uname(3) system call failed, using UNKNOWN" +.Pq mdoc +The +.Ic \&Os +macro is called without arguments, and the +.Xr uname 3 +system call failed. +As a workaround, +.Nm +can be compiled with +.Sm off +.Fl D Cm OSNAME=\(dq\e\(dq Ar string Cm \e\(dq\(dq . +.Sm on +.It Sy "unknown standard specifier" +.Pq mdoc +An +.Ic \&St +macro has an unknown argument and is discarded. +.It Sy "skipping request without numeric argument" +.Pq roff +An +.Ic \&it +request has a non-numeric or negative argument or no argument at all. +The invalid request is ignored. +.It Sy "skipping all arguments" +.Pq mdoc , man , eqn , roff +An +.Xr mdoc 7 +.Ic \&Bt , +.Ic \&Ed , +.Ic \&Ef , +.Ic \&Ek , +.Ic \&El , +.Ic \&Re , +or +.Ic \&Ud +macro, an +.Ic \&It +macro in a list that don't support item heads, a +.Xr man 7 +.Ic \&LP , +.Ic \&P , +or +.Ic \&PP +macro, an +.Xr eqn 7 +.Ic \&EN +macro, or a +.Xr roff 7 +.Sq \&.. +block closing request is invoked with at least one argument. +All arguments are ignored. +.It Sy "skipping excess arguments" +.Pq mdoc , roff +The +.Ic \&Bf +macro is invoked with more than one argument, or a request of the +.Ic \&de +family is invoked with more than two arguments. +The excess arguments are ignored. +.El +.Ss FATAL errors +.Bl -ohang +.It Sy "input too large" +.Pq mdoc , man +Currently, +.Nm +cannot handle input files larger than its arbitrary size limit +of 2^31 bytes (2 Gigabytes). +Since useful manuals are always small, this is not a problem in practice. +Parsing is aborted as soon as the condition is detected. +.It Sy "NOT IMPLEMENTED: Bd -file" +.Pq mdoc +For security reasons, the +.Ic \&Bd +macro does not support the +.Fl file +argument. +By requesting the inclusion of a sensitive file, a malicious document +might otherwise trick a privileged user into inadvertently displaying +the file on the screen, revealing the file content to bystanders. +The parser exits immediately. +.It Sy "NOT IMPLEMENTED: .so with absolute path or \(dq..\(dq" +.Pq roff +For security reasons, +.Nm +allows +.Ic \&so +file inclusion requests only with relative paths +and only without ascending to any parent directory. +By requesting the inclusion of a sensitive file, a malicious document +might otherwise trick a privileged user into inadvertently displaying +the file on the screen, revealing the file content to bystanders. +The parser exits immediately. +.It Sy ".so request failed" +.Pq roff +Servicing a +.Ic \&so +request requires reading an external file. +While trying to do so, an +.Xr open 2 , +.Xr stat 2 , +or +.Xr read 2 +system call failed. +The parser exits immediately. +Before showing this message, +.Nm +always shows another message explaining why the system call failed. +.El .Sh COMPATIBILITY This section summarises .Nm compatibility with GNU troff. Each input and output format is separately noted. .Ss ASCII Compatibility .Bl -bullet -compact .It Unrenderable unicode codepoints specified with .Sq \e[uNNNN] escapes are printed as .Sq \&? in mandoc. In GNU troff, these raise an error. .It The .Sq \&Bd \-literal and .Sq \&Bd \-unfilled macros of .Xr mdoc 7 in .Fl T Ns Cm ascii are synonyms, as are \-filled and \-ragged. .It In historic GNU troff, the .Sq \&Pa .Xr mdoc 7 macro does not underline when scoped under an .Sq \&It in the FILES section. This behaves correctly in .Nm . .It A list or display following the .Sq \&Ss .Xr mdoc 7 macro in .Fl T Ns Cm ascii does not assert a prior vertical break, just as it doesn't with .Sq \&Sh . .It The .Sq \&na .Xr man 7 macro in .Fl T Ns Cm ascii has no effect. .It Words aren't hyphenated. .El .Ss HTML/XHTML Compatibility .Bl -bullet -compact .It The .Sq \efP escape will revert the font to the previous .Sq \ef escape, not to the last rendered decoration, which is now dictated by CSS instead of hard-coded. It also will not span past the current scope, for the same reason. Note that in .Sx ASCII Output mode, this will work fine. .It The .Xr mdoc 7 .Sq \&Bl \-hang and .Sq \&Bl \-tag list types render similarly (no break following overreached left-hand side) due to the expressive constraints of HTML. .It The .Xr man 7 .Sq IP and .Sq TP lists render similarly. .El .Sh SEE ALSO .Xr eqn 7 , .Xr man 7 , .Xr mandoc_char 7 , .Xr mdoc 7 , .Xr roff 7 , .Xr tbl 7 .Sh AUTHORS The .Nm utility was written by .An Kristaps Dzonsons Aq Mt kristaps@bsd.lv . .Sh CAVEATS In .Fl T Ns Cm html and .Fl T Ns Cm xhtml , the maximum size of an element attribute is determined by .Dv BUFSIZ , which is usually 1024 bytes. Be aware of this when setting long link formats such as .Fl O Ns Cm style Ns = Ns Ar really/long/link . .Pp Nesting elements within next-line element scopes of .Fl m Ns Cm an , such as .Sq br within an empty .Sq B , will confuse .Fl T Ns Cm html and .Fl T Ns Cm xhtml and cause them to forget the formatting of the prior next-line scope. .Pp The .Sq \(aq control character is an alias for the standard macro control character and does not emit a line-break as stipulated in GNU troff. Index: head/contrib/mdocml/mandoc.3 =================================================================== --- head/contrib/mdocml/mandoc.3 (revision 274879) +++ head/contrib/mdocml/mandoc.3 (revision 274880) @@ -1,682 +1,661 @@ -.\" $Id: mandoc.3,v 1.22 2013/10/06 17:01:52 schwarze Exp $ +.\" $Id: mandoc.3,v 1.25 2014/08/05 05:48:56 schwarze Exp $ .\" .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons .\" Copyright (c) 2010 Ingo Schwarze .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: October 6 2013 $ +.Dd $Mdocdate: August 5 2014 $ .Dt MANDOC 3 .Os .Sh NAME .Nm mandoc , -.Nm mandoc_escape , +.Nm man_deroff , .Nm man_meta , .Nm man_mparse , .Nm man_node , -.Nm mchars_alloc , -.Nm mchars_free , -.Nm mchars_num2char , -.Nm mchars_num2uc , -.Nm mchars_spec2cp , -.Nm mchars_spec2str , +.Nm mdoc_deroff , .Nm mdoc_meta , .Nm mdoc_node , .Nm mparse_alloc , .Nm mparse_free , .Nm mparse_getkeep , .Nm mparse_keep , .Nm mparse_readfd , .Nm mparse_reset , .Nm mparse_result , .Nm mparse_strerror , .Nm mparse_strlevel .Nd mandoc macro compiler library .Sh LIBRARY .Lb libmandoc .Sh SYNOPSIS -.In man.h -.In mdoc.h +.In sys/types.h .In mandoc.h -.Ft "enum mandoc_esc" -.Fo mandoc_escape -.Fa "const char const **end" -.Fa "const char const **start" -.Fa "int *sz" -.Fc -.Ft "const struct man_meta *" -.Fo man_meta -.Fa "const struct man *man" -.Fc -.Ft "const struct mparse *" -.Fo man_mparse -.Fa "const struct man *man" -.Fc -.Ft "const struct man_node *" -.Fo man_node -.Fa "const struct man *man" -.Fc -.Ft "struct mchars *" -.Fn mchars_alloc "void" -.Ft void -.Fn mchars_free "struct mchars *p" -.Ft char -.Fn mchars_num2char "const char *cp" "size_t sz" -.Ft int -.Fn mchars_num2uc "const char *cp" "size_t sz" -.Ft "const char *" -.Fo mchars_spec2str -.Fa "const struct mchars *p" -.Fa "const char *cp" -.Fa "size_t sz" -.Fa "size_t *rsz" -.Fc -.Ft int -.Fo mchars_spec2cp -.Fa "const struct mchars *p" -.Fa "const char *cp" -.Fa "size_t sz" -.Fc -.Ft "const struct mdoc_meta *" -.Fo mdoc_meta -.Fa "const struct mdoc *mdoc" -.Fc -.Ft "const struct mdoc_node *" -.Fo mdoc_node -.Fa "const struct mdoc *mdoc" -.Fc -.Ft void +.Fd "#define ASCII_NBRSP" +.Fd "#define ASCII_HYPH" +.Fd "#define ASCII_BREAK" +.Ft struct mparse * .Fo mparse_alloc -.Fa "enum mparset type" +.Fa "int options" .Fa "enum mandoclevel wlevel" -.Fa "mandocmsg msg" -.Fa "void *msgarg" +.Fa "mandocmsg mmsg" +.Fa "char *defos" .Fc .Ft void +.Fo (*mandocmsg) +.Fa "enum mandocerr errtype" +.Fa "enum mandoclevel level" +.Fa "const char *file" +.Fa "int line" +.Fa "int col" +.Fa "const char *msg" +.Fc +.Ft void .Fo mparse_free .Fa "struct mparse *parse" .Fc -.Ft void +.Ft const char * .Fo mparse_getkeep .Fa "const struct mparse *parse" .Fc .Ft void .Fo mparse_keep .Fa "struct mparse *parse" .Fc .Ft "enum mandoclevel" .Fo mparse_readfd .Fa "struct mparse *parse" .Fa "int fd" .Fa "const char *fname" .Fc .Ft void .Fo mparse_reset .Fa "struct mparse *parse" .Fc .Ft void .Fo mparse_result .Fa "struct mparse *parse" .Fa "struct mdoc **mdoc" .Fa "struct man **man" +.Fa "char **sodest" .Fc .Ft "const char *" .Fo mparse_strerror .Fa "enum mandocerr" .Fc .Ft "const char *" .Fo mparse_strlevel .Fa "enum mandoclevel" .Fc -.Vt extern const char * const * man_macronames; +.In sys/types.h +.In mandoc.h +.In mdoc.h +.Ft void +.Fo mdoc_deroff +.Fa "char **dest" +.Fa "const struct mdoc_node *node" +.Fc +.Ft "const struct mdoc_meta *" +.Fo mdoc_meta +.Fa "const struct mdoc *mdoc" +.Fc +.Ft "const struct mdoc_node *" +.Fo mdoc_node +.Fa "const struct mdoc *mdoc" +.Fc .Vt extern const char * const * mdoc_argnames; .Vt extern const char * const * mdoc_macronames; -.Fd "#define ASCII_NBRSP" -.Fd "#define ASCII_HYPH" +.In sys/types.h +.In mandoc.h +.In man.h +.Ft void +.Fo man_deroff +.Fa "char **dest" +.Fa "const struct man_node *node" +.Fc +.Ft "const struct man_meta *" +.Fo man_meta +.Fa "const struct man *man" +.Fc +.Ft "const struct mparse *" +.Fo man_mparse +.Fa "const struct man *man" +.Fc +.Ft "const struct man_node *" +.Fo man_node +.Fa "const struct man *man" +.Fc +.Vt extern const char * const * man_macronames; .Sh DESCRIPTION The .Nm mandoc library parses a .Ux manual into an abstract syntax tree (AST). .Ux manuals are composed of .Xr mdoc 7 or .Xr man 7 , and may be mixed with .Xr roff 7 , .Xr tbl 7 , and .Xr eqn 7 invocations. .Pp The following describes a general parse sequence: .Bl -enum .It initiate a parsing sequence with .Fn mparse_alloc ; .It parse files or file descriptors with .Fn mparse_readfd ; .It retrieve a parsed syntax tree, if the parse was successful, with .Fn mparse_result ; .It iterate over parse nodes with .Fn mdoc_node or .Fn man_node ; .It free all allocated memory with .Fn mparse_free , or invoke .Fn mparse_reset and parse new files. .El -.Pp -The -.Nm -library also contains routines for translating character strings into glyphs -.Pq see Fn mchars_alloc -and parsing escape sequences from strings -.Pq see Fn mandoc_escape . .Sh REFERENCE This section documents the functions, types, and variables available via -.In mandoc.h . +.In mandoc.h , +with the exception of those documented in +.Xr mandoc_escape 3 +and +.Xr mchars_alloc 3 . .Ss Types .Bl -ohang -.It Vt "enum mandoc_esc" -An escape sequence classification. .It Vt "enum mandocerr" A fatal error, error, or warning message during parsing. .It Vt "enum mandoclevel" A classification of an -.Vt "enum mandoclevel" +.Vt "enum mandocerr" as regards system operation. -.It Vt "struct mchars" -An opaque pointer to an object allowing for translation between -character strings and glyphs. -See -.Fn mchars_alloc . -.It Vt "enum mparset" -The type of parser when reading input. -This should usually be -.Dv MPARSE_AUTO -for auto-detection. .It Vt "struct mparse" An opaque pointer to a running parse sequence. Created with .Fn mparse_alloc and freed with .Fn mparse_free . This may be used across parsed input if .Fn mparse_reset is called between parses. .It Vt "mandocmsg" A prototype for a function to handle fatal error, error, and warning messages emitted by the parser. .El .Ss Functions .Bl -ohang -.It Fn mandoc_escape -Scan an escape sequence, i.e., a character string beginning with -.Sq \e . -Pass a pointer to the character after the -.Sq \e -as -.Va end ; -it will be set to the supremum of the parsed escape sequence unless -returning -.Dv ESCAPE_ERROR , -in which case the string is bogus and should be -thrown away. -If not -.Dv ESCAPE_ERROR -or -.Dv ESCAPE_IGNORE , -.Va start -is set to the first relevant character of the substring (font, glyph, -whatever) of length -.Va sz . -Both -.Va start -and -.Va sz -may be -.Dv NULL . -Declared in -.In mandoc.h , -implemented in -.Pa mandoc.c . +.It Fn man_deroff +Obtain a text-only representation of a +.Vt struct man_node , +including text contained in its child nodes. +To be used on children of the pointer returned from +.Fn man_node . +When it is no longer needed, the pointer returned from +.Fn man_deroff +can be passed to +.Xr free 3 . .It Fn man_meta -Obtain the meta-data of a successful parse. +Obtain the meta-data of a successful +.Xr man 7 +parse. This may only be used on a pointer returned by .Fn mparse_result . Declared in .In man.h , implemented in .Pa man.c . .It Fn man_mparse Get the parser used for the current output. Declared in .In man.h , implemented in .Pa man.c . .It Fn man_node -Obtain the root node of a successful parse. +Obtain the root node of a successful +.Xr man 7 +parse. This may only be used on a pointer returned by .Fn mparse_result . Declared in .In man.h , implemented in .Pa man.c . -.It Fn mchars_alloc -Allocate an -.Vt "struct mchars *" -object for translating special characters into glyphs. -See -.Xr mandoc_char 7 -for an overview of special characters. -The object must be freed with -.Fn mchars_free . -Declared in -.In mandoc.h , -implemented in -.Pa chars.c . -.It Fn mchars_free -Free an object created with -.Fn mchars_alloc . -Declared in -.In mandoc.h , -implemented in -.Pa chars.c . -.It Fn mchars_num2char -Convert a character index (e.g., the \eN\(aq\(aq escape) into a -printable ASCII character. -Returns \e0 (the nil character) if the input sequence is malformed. -Declared in -.In mandoc.h , -implemented in -.Pa chars.c . -.It Fn mchars_num2uc -Convert a hexadecimal character index (e.g., the \e[uNNNN] escape) into -a Unicode codepoint. -Returns \e0 (the nil character) if the input sequence is malformed. -Declared in -.In mandoc.h , -implemented in -.Pa chars.c . -.It Fn mchars_spec2cp -Convert a special character into a valid Unicode codepoint. -Returns \-1 on failure or a non-zero Unicode codepoint on success. -Declared in -.In mandoc.h , -implemented in -.Pa chars.c . -.It Fn mchars_spec2str -Convert a special character into an ASCII string. -Returns -.Dv NULL -on failure. -Declared in -.In mandoc.h , -implemented in -.Pa chars.c . +.It Fn mdoc_deroff +Obtain a text-only representation of a +.Vt struct mdoc_node , +including text contained in its child nodes. +To be used on children of the pointer returned from +.Fn mdoc_node . +When it is no longer needed, the pointer returned from +.Fn mdoc_deroff +can be passed to +.Xr free 3 . .It Fn mdoc_meta -Obtain the meta-data of a successful parse. +Obtain the meta-data of a successful +.Xr mdoc +parse. This may only be used on a pointer returned by .Fn mparse_result . Declared in .In mdoc.h , implemented in .Pa mdoc.c . .It Fn mdoc_node -Obtain the root node of a successful parse. +Obtain the root node of a successful +.Xr mdoc +parse. This may only be used on a pointer returned by .Fn mparse_result . Declared in .In mdoc.h , implemented in .Pa mdoc.c . .It Fn mparse_alloc Allocate a parser. +The arguments have the following effect: +.Bl -tag -offset 5n -width inttype +.It Ar options +When the +.Dv MPARSE_MDOC +or +.Dv MPARSE_MAN +bit is set, only that parser is used. +Otherwise, the document type is automatically detected. +.Pp +When the +.Dv MPARSE_SO +bit is set, +.Xr roff 7 +.Ic \&so +file inclusion requests are always honoured. +Otherwise, if the request is the only content in an input file, +only the file name is remembered, to be returned in the +.Fa sodest +argument of +.Fn mparse_result . +.Pp +When the +.Dv MPARSE_QUICK +bit is set, parsing is aborted after the NAME section. +This is for example useful in +.Xr makewhatis 8 +.Fl Q +to quickly build minimal databases. +.It Ar wlevel +Can be set to +.Dv MANDOCLEVEL_FATAL , +.Dv MANDOCLEVEL_ERROR , +or +.Dv MANDOCLEVEL_WARNING . +Messages below the selected level will be suppressed. +.It Ar mmsg +A callback function to handle errors and warnings. +See +.Pa main.c +for an example. +.It Ar defos +A default string for the +.Xr mdoc 7 +.Sq \&Os +macro, overriding the +.Dv OSNAME +preprocessor definition and the results of +.Xr uname 3 . +.El +.Pp The same parser may be used for multiple files so long as .Fn mparse_reset is called between parses. .Fn mparse_free must be called to free the memory allocated by this function. Declared in .In mandoc.h , implemented in .Pa read.c . .It Fn mparse_free Free all memory allocated by .Fn mparse_alloc . Declared in .In mandoc.h , implemented in .Pa read.c . .It Fn mparse_getkeep Acquire the keep buffer. Must follow a call of .Fn mparse_keep . Declared in .In mandoc.h , implemented in .Pa read.c . .It Fn mparse_keep Instruct the parser to retain a copy of its parsed input. This can be acquired with subsequent .Fn mparse_getkeep calls. Declared in .In mandoc.h , implemented in .Pa read.c . .It Fn mparse_readfd Parse a file or file descriptor. If .Va fd is -1, .Va fname is opened for reading. Otherwise, .Va fname is assumed to be the name associated with .Va fd . This may be called multiple times with different parameters; however, .Fn mparse_reset should be invoked between parses. Declared in .In mandoc.h , implemented in .Pa read.c . .It Fn mparse_reset Reset a parser so that .Fn mparse_readfd may be used again. Declared in .In mandoc.h , implemented in .Pa read.c . .It Fn mparse_result Obtain the result of a parse. Only successful parses .Po i.e., those where .Fn mparse_readfd returned less than MANDOCLEVEL_FATAL .Pc -should invoke this function, in which case one of the two pointers will +should invoke this function, in which case one of the three pointers will be filled in. Declared in .In mandoc.h , implemented in .Pa read.c . .It Fn mparse_strerror Return a statically-allocated string representation of an error code. Declared in .In mandoc.h , implemented in .Pa read.c . .It Fn mparse_strlevel Return a statically-allocated string representation of a level code. Declared in .In mandoc.h , implemented in .Pa read.c . .El .Ss Variables .Bl -ohang .It Va man_macronames The string representation of a man macro as indexed by .Vt "enum mant" . .It Va mdoc_argnames The string representation of a mdoc macro argument as indexed by .Vt "enum mdocargt" . .It Va mdoc_macronames The string representation of a mdoc macro as indexed by .Vt "enum mdoct" . .El .Sh IMPLEMENTATION NOTES This section consists of structural documentation for .Xr mdoc 7 and .Xr man 7 syntax trees and strings. .Ss Man and Mdoc Strings Strings may be extracted from mdoc and man meta-data, or from text nodes (MDOC_TEXT and MAN_TEXT, respectively). These strings have special non-printing formatting cues embedded in the text itself, as well as .Xr roff 7 escapes preserved from input. Implementing systems will need to handle both situations to produce human-readable text. In general, strings may be assumed to consist of 7-bit ASCII characters. .Pp The following non-printing characters may be embedded in text strings: .Bl -tag -width Ds .It Dv ASCII_NBRSP A non-breaking space character. .It Dv ASCII_HYPH A soft hyphen. +.It Dv ASCII_BREAK +A breakable zero-width space. .El .Pp Escape characters are also passed verbatim into text strings. An escape character is a sequence of characters beginning with the backslash .Pq Sq \e . To construct human-readable text, these should be intercepted with -.Fn mandoc_escape -and converted with one of -.Fn mchars_num2char , -.Fn mchars_spec2str , -and so on. +.Xr mandoc_escape 3 +and converted with one the functions described in +.Xr mchars_alloc 3 . .Ss Man Abstract Syntax Tree This AST is governed by the ontological rules dictated in .Xr man 7 and derives its terminology accordingly. .Pp The AST is composed of .Vt struct man_node nodes with element, root and text types as declared by the .Va type field. Each node also provides its parse point (the .Va line , .Va sec , and .Va pos fields), its position in the tree (the .Va parent , .Va child , .Va next and .Va prev fields) and some type-specific data. .Pp The tree itself is arranged according to the following normal form, where capitalised non-terminals represent nodes. .Pp .Bl -tag -width "ELEMENTXX" -compact .It ROOT \(<- mnode+ .It mnode \(<- ELEMENT | TEXT | BLOCK .It BLOCK \(<- HEAD BODY .It HEAD \(<- mnode* .It BODY \(<- mnode* .It ELEMENT \(<- ELEMENT | TEXT* .It TEXT \(<- [[:ascii:]]* .El .Pp The only elements capable of nesting other elements are those with -next-lint scope as documented in +next-line scope as documented in .Xr man 7 . .Ss Mdoc Abstract Syntax Tree This AST is governed by the ontological rules dictated in .Xr mdoc 7 and derives its terminology accordingly. .Qq In-line elements described in .Xr mdoc 7 are described simply as .Qq elements . .Pp The AST is composed of .Vt struct mdoc_node nodes with block, head, body, element, root and text types as declared by the .Va type field. Each node also provides its parse point (the .Va line , .Va sec , and .Va pos fields), its position in the tree (the .Va parent , .Va child , .Va nchild , .Va next and .Va prev fields) and some type-specific data, in particular, for nodes generated from macros, the generating macro in the .Va tok field. .Pp The tree itself is arranged according to the following normal form, where capitalised non-terminals represent nodes. .Pp .Bl -tag -width "ELEMENTXX" -compact .It ROOT \(<- mnode+ .It mnode \(<- BLOCK | ELEMENT | TEXT .It BLOCK \(<- HEAD [TEXT] (BODY [TEXT])+ [TAIL [TEXT]] .It ELEMENT \(<- TEXT* .It HEAD \(<- mnode* .It BODY \(<- mnode* [ENDBODY mnode*] .It TAIL \(<- mnode* .It TEXT \(<- [[:ascii:]]* .El .Pp Of note are the TEXT nodes following the HEAD, BODY and TAIL nodes of the BLOCK production: these refer to punctuation marks. Furthermore, although a TEXT node will generally have a non-zero-length string, in the specific case of .Sq \&.Bd \-literal , an empty line will produce a zero-length string. Multiple body parts are only found in invocations of .Sq \&Bl \-column , where a new body introduces a new phrase. .Pp The .Xr mdoc 7 syntax tree accommodates for broken block structures as well. The ENDBODY node is available to end the formatting associated with a given block before the physical end of that block. It has a non-null .Va end field, is of the BODY .Va type , has the same .Va tok as the BLOCK it is ending, and has a .Va pending field pointing to that BLOCK's BODY node. It is an indirect child of that BODY node and has no children of its own. .Pp An ENDBODY node is generated when a block ends while one of its child blocks is still open, like in the following example: .Bd -literal -offset indent \&.Ao ao \&.Bo bo ac \&.Ac bc \&.Bc end .Ed .Pp This example results in the following block structure: .Bd -literal -offset indent BLOCK Ao HEAD Ao BODY Ao TEXT ao BLOCK Bo, pending -> Ao HEAD Bo BODY Bo TEXT bo TEXT ac ENDBODY Ao, pending -> Ao TEXT bc TEXT end .Ed .Pp Here, the formatting of the .Sq \&Ao block extends from TEXT ao to TEXT ac, while the formatting of the .Sq \&Bo block extends from TEXT bo to TEXT bc. It renders as follows in .Fl T Ns Cm ascii mode: .Pp .Dl bc] end .Pp Support for badly-nested blocks is only provided for backward compatibility with some older .Xr mdoc 7 implementations. Using badly-nested blocks is .Em strongly discouraged ; for example, the .Fl T Ns Cm html and .Fl T Ns Cm xhtml front-ends to .Xr mandoc 1 are unable to render them in any meaningful way. Furthermore, behaviour when encountering badly-nested blocks is not -consistent across troff implementations, especially when using multiple +consistent across troff implementations, especially when using multiple levels of badly-nested blocks. .Sh SEE ALSO .Xr mandoc 1 , +.Xr mandoc_escape 3 , +.Xr mandoc_malloc 3 , +.Xr mchars_alloc 3 , .Xr eqn 7 , .Xr man 7 , .Xr mandoc_char 7 , .Xr mdoc 7 , .Xr roff 7 , .Xr tbl 7 .Sh AUTHORS The .Nm library was written by .An Kristaps Dzonsons Aq Mt kristaps@bsd.lv . Index: head/contrib/mdocml/mandoc.c =================================================================== --- head/contrib/mdocml/mandoc.c (revision 274879) +++ head/contrib/mdocml/mandoc.c (revision 274880) @@ -1,668 +1,600 @@ -/* $Id: mandoc.c,v 1.74 2013/12/30 18:30:32 schwarze Exp $ */ +/* $Id: mandoc.c,v 1.83 2014/07/06 19:09:00 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2011, 2012, 2013 Ingo Schwarze + * Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include "mandoc.h" +#include "mandoc_aux.h" #include "libmandoc.h" #define DATESIZE 32 static int a2time(time_t *, const char *, const char *); static char *time2a(time_t); 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; + enum mandoc_esc gly; /* * When the caller doesn't provide return storage, * use local storage. */ if (NULL == start) start = &local_start; if (NULL == sz) sz = &local_sz; /* * 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. */ gly = ESCAPE_ERROR; *start = ++*end; *sz = 0; term = '\0'; switch ((*start)[-1]) { /* * First the glyphs. There are several different forms of * these, but each eventually returns a substring of the glyph * name. */ - case ('('): + case '(': gly = ESCAPE_SPECIAL; *sz = 2; break; - case ('['): + case '[': gly = ESCAPE_SPECIAL; /* * Unicode escapes are defined in groff as \[uXXXX] to * \[u10FFFF], where the contained value must be a valid * Unicode codepoint. Here, however, only check whether * it's not a zero-width escape. */ if ('u' == (*start)[0] && ']' != (*start)[1]) gly = ESCAPE_UNICODE; term = ']'; break; - case ('C'): + case 'C': if ('\'' != **start) return(ESCAPE_ERROR); *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'): + case 'd': /* FALLTHROUGH */ - case ('u'): + case 'u': return(ESCAPE_IGNORE); /* * The \z escape is supposed to output the following - * character without advancing the cursor position. + * character without advancing the cursor position. * Since we are mostly dealing with terminal mode, * let us just skip the next character. */ - case ('z'): + 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. */ - case ('F'): + case 'F': /* FALLTHROUGH */ - case ('g'): + case 'g': /* FALLTHROUGH */ - case ('k'): + case 'k': /* FALLTHROUGH */ - case ('M'): + case 'M': /* FALLTHROUGH */ - case ('m'): + case 'm': /* FALLTHROUGH */ - case ('n'): + case 'n': /* FALLTHROUGH */ - case ('V'): + case 'V': /* FALLTHROUGH */ - case ('Y'): + case 'Y': gly = ESCAPE_IGNORE; /* FALLTHROUGH */ - case ('f'): + case 'f': if (ESCAPE_ERROR == gly) gly = ESCAPE_FONT; switch (**start) { - case ('('): + case '(': *start = ++*end; *sz = 2; break; - case ('['): + case '[': *start = ++*end; term = ']'; break; default: *sz = 1; break; } break; /* * These escapes are of the form \X'Y', where 'X' is the trigger * and 'Y' is any string. These have opaque sub-strings. + * The \B and \w escapes are handled in roff.c, roff_res(). */ - case ('A'): + case 'A': /* FALLTHROUGH */ - case ('b'): + case 'b': /* FALLTHROUGH */ - case ('B'): + case 'D': /* FALLTHROUGH */ - case ('D'): + case 'o': /* FALLTHROUGH */ - case ('o'): + case 'R': /* FALLTHROUGH */ - case ('R'): + case 'X': /* FALLTHROUGH */ - case ('w'): - /* FALLTHROUGH */ - case ('X'): - /* FALLTHROUGH */ - case ('Z'): - if ('\'' != **start) + case 'Z': + if ('\0' == **start) return(ESCAPE_ERROR); gly = ESCAPE_IGNORE; + term = **start; *start = ++*end; - term = '\''; break; /* * These escapes are of the form \X'N', where 'X' is the trigger * and 'N' resolves to a numerical expression. */ - case ('h'): + case 'h': /* FALLTHROUGH */ - case ('H'): + case 'H': /* FALLTHROUGH */ - case ('L'): + case 'L': /* FALLTHROUGH */ - case ('l'): + case 'l': /* FALLTHROUGH */ - case ('S'): + case 'S': /* FALLTHROUGH */ - case ('v'): + case 'v': /* FALLTHROUGH */ - case ('x'): - if ('\'' != **start) + case 'x': + if (strchr(" %&()*+-./0123456789:<=>", **start)) { + ++*end; return(ESCAPE_ERROR); + } gly = ESCAPE_IGNORE; + term = **start; *start = ++*end; - term = '\''; break; /* * Special handling for the numbered character escape. * XXX Do any other escapes need similar handling? */ - case ('N'): + case 'N': if ('\0' == **start) return(ESCAPE_ERROR); (*end)++; if (isdigit((unsigned char)**start)) { *sz = 1; return(ESCAPE_IGNORE); } (*start)++; while (isdigit((unsigned char)**end)) (*end)++; *sz = *end - *start; if ('\0' != **end) (*end)++; return(ESCAPE_NUMBERED); - /* + /* * Sizes get a special category of their own. */ - case ('s'): + case 's': gly = ESCAPE_IGNORE; /* See +/- counts as a sign. */ if ('+' == **end || '-' == **end || ASCII_HYPH == **end) (*end)++; switch (**end) { - case ('('): + case '(': *start = ++*end; *sz = 2; break; - case ('['): + case '[': *start = ++*end; term = ']'; break; - case ('\''): + case '\'': *start = ++*end; term = '\''; break; default: *sz = 1; break; } break; /* * Anything else is assumed to be a glyph. * In this case, pass back the character after the backslash. */ default: gly = ESCAPE_SPECIAL; *start = --*end; *sz = 1; break; } assert(ESCAPE_ERROR != gly); /* * Read up to the terminating character, * paying attention to nested escapes. */ if ('\0' != term) { while (**end != term) { switch (**end) { - case ('\0'): + case '\0': return(ESCAPE_ERROR); - case ('\\'): + 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); *end += *sz; } /* Run post-processors. */ switch (gly) { - case (ESCAPE_FONT): + case ESCAPE_FONT: 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 (**start) { - case ('3'): + case '3': /* FALLTHROUGH */ - case ('B'): + case 'B': gly = ESCAPE_FONTBOLD; break; - case ('2'): + case '2': /* FALLTHROUGH */ - case ('I'): + case 'I': gly = ESCAPE_FONTITALIC; break; - case ('P'): + case 'P': gly = ESCAPE_FONTPREV; break; - case ('1'): + case '1': /* FALLTHROUGH */ - case ('R'): + case 'R': gly = ESCAPE_FONTROMAN; break; } break; - case (ESCAPE_SPECIAL): + case ESCAPE_SPECIAL: if (1 == *sz && 'c' == **start) gly = ESCAPE_NOSPACE; break; default: break; } return(gly); } -void * -mandoc_calloc(size_t num, size_t size) -{ - void *ptr; - - ptr = calloc(num, size); - if (NULL == ptr) { - perror(NULL); - exit((int)MANDOCLEVEL_SYSERR); - } - - return(ptr); -} - - -void * -mandoc_malloc(size_t size) -{ - void *ptr; - - ptr = malloc(size); - if (NULL == ptr) { - perror(NULL); - exit((int)MANDOCLEVEL_SYSERR); - } - - return(ptr); -} - - -void * -mandoc_realloc(void *ptr, size_t size) -{ - - ptr = realloc(ptr, size); - if (NULL == ptr) { - perror(NULL); - exit((int)MANDOCLEVEL_SYSERR); - } - - return(ptr); -} - -char * -mandoc_strndup(const char *ptr, size_t sz) -{ - char *p; - - p = mandoc_malloc(sz + 1); - memcpy(p, ptr, sz); - p[(int)sz] = '\0'; - return(p); -} - -char * -mandoc_strdup(const char *ptr) -{ - char *p; - - p = strdup(ptr); - if (NULL == p) { - perror(NULL); - exit((int)MANDOCLEVEL_SYSERR); - } - - return(p); -} - /* * 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. * NUL-terminate the argument in place. * Collapse pairs of quotes inside quoted arguments. * Advance the argument pointer to the next argument, * or to the NUL byte terminating the argument line. */ char * mandoc_getarg(struct mparse *parse, char **cpp, int ln, int *pos) { char *start, *cp; int quoted, pairs, white; /* Quoting can only start with a new word. */ start = *cpp; quoted = 0; if ('"' == *start) { quoted = 1; start++; - } + } pairs = 0; white = 0; for (cp = start; '\0' != *cp; cp++) { /* * Move the following text left * after quoted quotes and after "\\" and "\t". */ if (pairs) cp[-pairs] = cp[0]; if ('\\' == cp[0]) { /* * In copy mode, translate double to single * backslashes and backslash-t to literal tabs. */ switch (cp[1]) { - case ('t'): + case 't': cp[0] = '\t'; /* FALLTHROUGH */ - case ('\\'): + case '\\': pairs++; cp++; break; - case (' '): + case ' ': /* Skip escaped blanks. */ if (0 == quoted) cp++; break; default: break; } } else if (0 == quoted) { if (' ' == cp[0]) { /* Unescaped blanks end unquoted args. */ white = 1; break; } } else if ('"' == cp[0]) { if ('"' == cp[1]) { /* Quoted quotes collapse. */ pairs++; cp++; } else { /* Unquoted quotes end quoted args. */ quoted = 2; break; } } } /* Quoted argument without a closing quote. */ if (1 == quoted) - mandoc_msg(MANDOCERR_BADQUOTE, parse, ln, *pos, NULL); + mandoc_msg(MANDOCERR_ARG_QUOTE, parse, ln, *pos, NULL); /* NUL-terminate this argument and move to the next one. */ if (pairs) cp[-pairs] = '\0'; if ('\0' != *cp) { *cp++ = '\0'; while (' ' == *cp) cp++; } *pos += (int)(cp - start) + (quoted ? 1 : 0); *cpp = cp; if ('\0' == *cp && (white || ' ' == cp[-1])) - mandoc_msg(MANDOCERR_EOLNSPACE, parse, ln, *pos, NULL); + mandoc_msg(MANDOCERR_SPACE_EOL, parse, ln, *pos, NULL); return(start); } static int a2time(time_t *t, const char *fmt, const char *p) { struct tm tm; char *pp; memset(&tm, 0, sizeof(struct tm)); pp = NULL; #ifdef HAVE_STRPTIME pp = strptime(p, fmt, &tm); #endif if (NULL != pp && '\0' == *pp) { *t = mktime(&tm); return(1); } return(0); } static char * time2a(time_t t) { struct tm *tm; char *buf, *p; size_t ssz; int isz; tm = localtime(&t); /* * Reserve space: * up to 9 characters for the month (September) + blank * up to 2 characters for the day + comma + blank * 4 characters for the year and a terminating '\0' */ p = buf = mandoc_malloc(10 + 4 + 4 + 1); if (0 == (ssz = strftime(p, 10 + 1, "%B ", tm))) goto fail; p += (int)ssz; if (-1 == (isz = snprintf(p, 4 + 1, "%d, ", tm->tm_mday))) goto fail; p += isz; if (0 == strftime(p, 4 + 1, "%Y", tm)) goto fail; return(buf); fail: free(buf); return(NULL); } char * mandoc_normdate(struct mparse *parse, char *in, int ln, int pos) { char *out; time_t t; if (NULL == in || '\0' == *in || 0 == strcmp(in, "$" "Mdocdate$")) { - mandoc_msg(MANDOCERR_NODATE, parse, ln, pos, NULL); + mandoc_msg(MANDOCERR_DATE_MISSING, parse, ln, pos, NULL); time(&t); } else if (a2time(&t, "%Y-%m-%d", in)) t = 0; else if (!a2time(&t, "$" "Mdocdate: %b %d %Y $", in) && !a2time(&t, "%b %d, %Y", in)) { - mandoc_msg(MANDOCERR_BADDATE, parse, ln, pos, NULL); + mandoc_msg(MANDOCERR_DATE_BAD, parse, ln, pos, in); t = 0; } out = t ? time2a(t) : NULL; return(out ? out : mandoc_strdup(in)); } int -mandoc_eos(const char *p, size_t sz, int enclosed) +mandoc_eos(const char *p, size_t sz) { - const char *q; - int found; + const char *q; + int enclosed, found; if (0 == sz) return(0); /* * End-of-sentence recognition must include situations where * some symbols, such as `)', allow prior EOS punctuation to * propagate outward. */ - found = 0; + enclosed = found = 0; for (q = p + (int)sz - 1; q >= p; q--) { switch (*q) { - case ('\"'): + case '\"': /* FALLTHROUGH */ - case ('\''): + case '\'': /* FALLTHROUGH */ - case (']'): + case ']': /* FALLTHROUGH */ - case (')'): + case ')': if (0 == found) enclosed = 1; break; - case ('.'): + case '.': /* FALLTHROUGH */ - case ('!'): + case '!': /* FALLTHROUGH */ - case ('?'): + case '?': found = 1; break; default: return(found && (!enclosed || isalnum((unsigned char)*q))); } } return(found && !enclosed); } /* * Convert a string to a long that may not be <0. * If the string is invalid, or is less than 0, return -1. */ int mandoc_strntoi(const char *p, size_t sz, int base) { char buf[32]; char *ep; long v; if (sz > 31) return(-1); memcpy(buf, p, sz); buf[(int)sz] = '\0'; errno = 0; v = strtol(buf, &ep, base); if (buf[0] == '\0' || *ep != '\0') return(-1); if (v > INT_MAX) v = INT_MAX; if (v < INT_MIN) v = INT_MIN; return((int)v); } Index: head/contrib/mdocml/mandoc.db.5 =================================================================== --- head/contrib/mdocml/mandoc.db.5 (nonexistent) +++ head/contrib/mdocml/mandoc.db.5 (revision 274880) @@ -0,0 +1,144 @@ +.\" $Id: mandoc.db.5,v 1.1 2014/04/15 20:18:26 schwarze Exp $ +.\" +.\" Copyright (c) 2014 Ingo Schwarze +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: April 15 2014 $ +.Dt MANDOC.DB 5 +.Os +.Sh NAME +.Nm mandoc.db +.Nd manual page database +.Sh DESCRIPTION +The +.Nm +SQLite3 file format is used to store information about installed manual +pages to facilitate semantic searching for manuals. +Each manual page tree contains its own +.Nm +file; see +.Sx FILES +for examples. +.Pp +Such database files are generated by +.Xr makewhatis 8 +and used by +.Xr apropos 1 +and +.Xr whatis 1 . +.Pp +One line in the following tables describes: +.Bl -tag -width Ds +.It Sy mpages +One physical manual page file, no matter how many times and under which +names it may appear in the file system. +.It Sy mlinks +One entry in the file system, no matter which content it points to. +.It Sy names +One manual page name, no matter whether it appears in a page header, +in a NAME or SYNOPSIS section, or as a file name. +.It Sy keys +One chunk of text from some macro invocation. +.El +.Pp +Each record in the latter three tables uses its +.Va pageid +column to point to a record in the +.Sy mpages +table. +.Pp +The other columns are as follows; unless stated otherwise, they are +of type +.Vt TEXT . +.Bl -tag -width mpages.desc +.It Sy mpages.desc +The description line +.Pq Sq \&Nd +of the page. +.It Sy mpages.form +The +.Vt INTEGER +1 if the page is unformatted, i.e. in +.Xr mdoc 7 +or +.Xr man 7 +format, and 2 if it is formatted, i.e. a +.Sq cat +page. +.It Sy mlinks.sec +The manual section as found in the subdirectory name. +.It Sy mlinks.arch +The manual architecture as found in the subdirectory name, or +.Qq any . +.It Sy mlinks.name +The manual name as found in the file name. +.It Sy names.bits +An +.Vt INTEGER +bit mask telling whether the name came from a header line, from the +NAME or SYNOPSIS section, or from a file name. +Bits are defined in +.In mansearch.h . +.It Sy names.name +The name itself. +.It Sy keys.bits +An +.Vt INTEGER +bit mask telling which semantic contexts the key was found in; +defined in +.In mansearch.h , +documented in +.Xr apropos 1 . +.It Sy keys.key +The string found in those contexts. +.El +.Sh FILES +.Bl -tag -width /usr/share/mandoc.db -compact +.It Pa /usr/share/mandoc.db +The manual page database for the base system. +.It Pa /usr/X11R6/mandoc.db +The same for the +.Xr X 7 +Window System. +.It Pa /usr/local/mandoc.db +The same for +.Xr packages 7 . +.El +.Sh SEE ALSO +.Xr apropos 1 , +.Xr man 1 , +.Xr sqlite3 1 , +.Xr whatis 1 , +.Xr mansearch 3 , +.Xr makewhatis 8 +.Sh HISTORY +A manual page database +.Pa /usr/lib/whatis +first appeared in +.Bx 2 . +The present format first appeared in +.Ox 5.6 . +.Sh AUTHORS +.An -nosplit +The original version of +.Xr makewhatis 8 +was written by +.An Bill Joy +in 1979. +An SQLite3 version was first implemented by +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv +in 2012. +The present database format was designed by +.An Ingo Schwarze Aq Mt schwarze@openbsd.org +in 2014. Property changes on: head/contrib/mdocml/mandoc.db.5 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/mdocml/mandoc.h =================================================================== --- head/contrib/mdocml/mandoc.h (revision 274879) +++ head/contrib/mdocml/mandoc.h (revision 274880) @@ -1,432 +1,438 @@ -/* $Id: mandoc.h,v 1.112 2013/12/30 18:30:32 schwarze Exp $ */ +/* $Id: mandoc.h,v 1.152 2014/08/06 15:09:05 schwarze Exp $ */ /* * Copyright (c) 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2012, 2013 Ingo Schwarze + * Copyright (c) 2010-2014 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef MANDOC_H #define MANDOC_H #define ASCII_NBRSP 31 /* non-breaking space */ #define ASCII_HYPH 30 /* breakable hyphen */ +#define ASCII_BREAK 29 /* breakable zero-width space */ /* * Status level. This refers to both internal status (i.e., whilst * running, when warnings/errors are reported) and an indicator of a * threshold of when to halt (when said internal state exceeds the * threshold). */ enum mandoclevel { MANDOCLEVEL_OK = 0, MANDOCLEVEL_RESERVED, MANDOCLEVEL_WARNING, /* warnings: syntax, whitespace, etc. */ MANDOCLEVEL_ERROR, /* input has been thrown away */ MANDOCLEVEL_FATAL, /* input is borked */ MANDOCLEVEL_BADARG, /* bad argument in invocation */ MANDOCLEVEL_SYSERR, /* system error */ MANDOCLEVEL_MAX }; /* * All possible things that can go wrong within a parse, be it libroff, * libmdoc, or libman. */ enum mandocerr { MANDOCERR_OK, MANDOCERR_WARNING, /* ===== start of warnings ===== */ /* related to the prologue */ - 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 */ - MANDOCERR_PROLOGREP, /* duplicate prologue macro */ - MANDOCERR_BADPROLOG, /* macro not allowed in prologue */ - MANDOCERR_BADBODY, /* macro not allowed in body */ + MANDOCERR_DT_NOTITLE, /* missing manual title, using UNTITLED: line */ + MANDOCERR_TH_NOTITLE, /* missing manual title, using "": [macro] */ + MANDOCERR_TITLE_CASE, /* lower case character in document title */ + MANDOCERR_MSEC_MISSING, /* missing manual section, using "": macro */ + MANDOCERR_MSEC_BAD, /* unknown manual section: Dt ... section */ + MANDOCERR_ARCH_BAD, /* unknown manual volume or arch: Dt ... volume */ + MANDOCERR_DATE_MISSING, /* missing date, using today's date */ + MANDOCERR_DATE_BAD, /* cannot parse date, using it verbatim: date */ + MANDOCERR_OS_MISSING, /* missing Os macro, using "" */ + MANDOCERR_PROLOG_REP, /* duplicate prologue macro: macro */ + MANDOCERR_PROLOG_LATE, /* late prologue macro: macro */ + MANDOCERR_DT_LATE, /* skipping late title macro: Dt args */ + MANDOCERR_PROLOG_ORDER, /* prologue macros out of order: macros */ /* related to document structure */ - MANDOCERR_SO, /* .so is fragile, better use ln(1) */ - MANDOCERR_NAMESECFIRST, /* NAME section must come first */ - MANDOCERR_BADNAMESEC, /* bad NAME section contents */ - MANDOCERR_SECOOO, /* sections out of conventional order */ - MANDOCERR_SECREP, /* duplicate section name */ - MANDOCERR_SECMSEC, /* section header suited to sections ... */ + MANDOCERR_SO, /* .so is fragile, better use ln(1): so path */ + MANDOCERR_DOC_EMPTY, /* no document body */ + MANDOCERR_SEC_BEFORE, /* content before first section header: macro */ + MANDOCERR_NAMESEC_FIRST, /* first section is not NAME: Sh title */ + MANDOCERR_NAMESEC_BAD, /* bad NAME section contents: macro */ + MANDOCERR_SEC_ORDER, /* sections out of conventional order: Sh title */ + MANDOCERR_SEC_REP, /* duplicate section title: Sh title */ + MANDOCERR_SEC_MSEC, /* unexpected section: Sh title for ... only */ /* 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 */ - MANDOCERR_NESTEDDISP, /* nested displays are not portable */ - MANDOCERR_SCOPEREP, /* already in literal mode */ - MANDOCERR_LINESCOPE, /* line scope broken */ + MANDOCERR_MACRO_OBS, /* obsolete macro: macro */ + MANDOCERR_PAR_SKIP, /* skipping paragraph macro: macro ... */ + MANDOCERR_PAR_MOVE, /* moving paragraph macro out of list: macro */ + MANDOCERR_NS_SKIP, /* skipping no-space macro */ + MANDOCERR_BLK_NEST, /* blocks badly nested: macro ... */ + MANDOCERR_BD_NEST, /* nested displays are not portable: macro ... */ + MANDOCERR_BL_MOVE, /* moving content out of list: macro */ + MANDOCERR_VT_CHILD, /* .Vt block has child macro: macro */ + MANDOCERR_FI_SKIP, /* fill mode already enabled, skipping: fi */ + MANDOCERR_NF_SKIP, /* fill mode already disabled, skipping: nf */ + MANDOCERR_BLK_LINE, /* line scope broken: macro breaks macro */ - /* related to missing macro arguments */ - MANDOCERR_MACROEMPTY, /* skipping empty macro */ + /* related to missing arguments */ + MANDOCERR_REQ_EMPTY, /* skipping empty request: request */ + MANDOCERR_COND_EMPTY, /* conditional request controls empty scope */ + MANDOCERR_MACRO_EMPTY, /* skipping empty macro: macro */ + MANDOCERR_ARG_EMPTY, /* empty argument, using 0n: macro arg */ MANDOCERR_ARGCWARN, /* argument count wrong */ - MANDOCERR_DISPTYPE, /* missing display type */ - MANDOCERR_LISTFIRST, /* list type must come first */ - MANDOCERR_NOWIDTHARG, /* tag lists require a width argument */ - MANDOCERR_FONTTYPE, /* missing font type */ - MANDOCERR_WNOSCOPE, /* skipping end of block that is not open */ + MANDOCERR_BD_NOTYPE, /* missing display type, using -ragged: Bd */ + MANDOCERR_BL_LATETYPE, /* list type is not the first argument: Bl arg */ + MANDOCERR_BL_NOWIDTH, /* missing -width in -tag list, using 8n */ + MANDOCERR_EX_NONAME, /* missing utility name, using "": Ex */ + MANDOCERR_IT_NOHEAD, /* empty head in list item: Bl -type It */ + MANDOCERR_IT_NOBODY, /* empty list item: Bl -type It */ + MANDOCERR_BF_NOFONT, /* missing font type, using \fR: Bf */ + MANDOCERR_BF_BADFONT, /* unknown font type, using \fR: Bf font */ + MANDOCERR_ARG_STD, /* missing -std argument, adding it: macro */ - /* related to bad macro arguments */ - MANDOCERR_IGNARGV, /* skipping argument */ - MANDOCERR_ARGVREP, /* duplicate argument */ - MANDOCERR_DISPREP, /* duplicate display type */ - MANDOCERR_LISTREP, /* duplicate list type */ - MANDOCERR_BADATT, /* unknown AT&T UNIX version */ - MANDOCERR_BADBOOL, /* bad Boolean value */ - MANDOCERR_BADFONT, /* unknown font */ - MANDOCERR_BADSTANDARD, /* unknown standard specifier */ - MANDOCERR_BADWIDTH, /* bad width argument */ + /* related to bad arguments */ + MANDOCERR_ARG_QUOTE, /* unterminated quoted argument */ + MANDOCERR_ARG_REP, /* duplicate argument: macro arg */ + MANDOCERR_AN_REP, /* skipping duplicate argument: An -arg */ + MANDOCERR_BD_REP, /* skipping duplicate display type: Bd -type */ + MANDOCERR_BL_REP, /* skipping duplicate list type: Bl -type */ + MANDOCERR_BL_SKIPW, /* skipping -width argument: Bl -type */ + MANDOCERR_AT_BAD, /* unknown AT&T UNIX version: At version */ + MANDOCERR_RS_BAD, /* invalid content in Rs block: macro */ + MANDOCERR_SM_BAD, /* invalid Boolean argument: macro arg */ + MANDOCERR_FT_BAD, /* unknown font, skipping request: ft font */ /* related to plain text */ - MANDOCERR_NOBLANKLN, /* blank line in non-literal context */ - MANDOCERR_BADTAB, /* tab in non-literal context */ - MANDOCERR_EOLNSPACE, /* end of line whitespace */ - MANDOCERR_BADCOMMENT, /* bad comment style */ - MANDOCERR_BADESCAPE, /* unknown escape sequence */ - MANDOCERR_BADQUOTE, /* unterminated quoted string */ + MANDOCERR_FI_BLANK, /* blank line in fill mode, using .sp */ + MANDOCERR_FI_TAB, /* tab in filled text */ + MANDOCERR_SPACE_EOL, /* whitespace at end of input line */ + MANDOCERR_COMMENT_BAD, /* bad comment style */ + MANDOCERR_ESC_BAD, /* invalid escape sequence: esc */ + MANDOCERR_STR_UNDEF, /* undefined string, using "": name */ - /* related to equations */ - MANDOCERR_EQNQUOTE, /* unexpected literal in equation */ - MANDOCERR_ERROR, /* ===== start of errors ===== */ /* related to equations */ MANDOCERR_EQNNSCOPE, /* unexpected equation scope closure*/ MANDOCERR_EQNSCOPE, /* equation scope open on exit */ MANDOCERR_EQNBADSCOPE, /* overlapping equation scopes */ MANDOCERR_EQNEOF, /* unexpected end of equation */ MANDOCERR_EQNSYNT, /* equation syntax error */ /* related to tables */ MANDOCERR_TBL, /* bad table syntax */ MANDOCERR_TBLOPT, /* bad table option */ MANDOCERR_TBLLAYOUT, /* bad table layout */ MANDOCERR_TBLNOLAYOUT, /* no table layout cells specified */ MANDOCERR_TBLNODATA, /* no table data cells specified */ MANDOCERR_TBLIGNDATA, /* ignore data in cell */ MANDOCERR_TBLBLOCK, /* data block still open */ MANDOCERR_TBLEXTRADAT, /* ignoring extra data cells */ + /* related to document structure and macros */ 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_BADCHAR, /* skipping bad character: number */ + MANDOCERR_MACRO, /* skipping unknown macro: macro */ + MANDOCERR_IT_STRAY, /* skipping item outside list: It ... */ + MANDOCERR_TA_STRAY, /* skipping column outside column list: Ta */ + MANDOCERR_BLK_NOTOPEN, /* skipping end of block that is not open */ + MANDOCERR_BLK_BROKEN, /* inserting missing end of block: macro ... */ + MANDOCERR_BLK_NOEND, /* appending missing end of block: macro */ + + /* related to request and macro arguments */ + MANDOCERR_NAMESC, /* escaped character not allowed in a name: name */ 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 */ - MANDOCERR_UNAME, /* uname(3) system call failed */ - /* FIXME: merge following with MANDOCERR_ARGCOUNT */ - 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 */ + MANDOCERR_BL_NOTYPE, /* missing list type, using -item: Bl */ + MANDOCERR_NM_NONAME, /* missing manual name, using "": Nm */ + MANDOCERR_OS_UNAME, /* uname(3) system call failed, using UNKNOWN */ + MANDOCERR_ST_BAD, /* unknown standard specifier: St standard */ + MANDOCERR_IT_NONUM, /* skipping request without numeric argument */ + MANDOCERR_ARG_SKIP, /* skipping all arguments: macro args */ + MANDOCERR_ARG_EXCESS, /* skipping excess arguments: macro ... args */ MANDOCERR_FATAL, /* ===== start of fatal errors ===== */ - MANDOCERR_NOTMANUAL, /* manual isn't really a manual */ - MANDOCERR_COLUMNS, /* column syntax is inconsistent */ - MANDOCERR_BADDISP, /* NOT IMPLEMENTED: .Bd -file */ - MANDOCERR_SYNTARGVCOUNT, /* argument count wrong, violates syntax */ - MANDOCERR_SYNTCHILD, /* child violates parent syntax */ - MANDOCERR_SYNTARGCOUNT, /* argument count wrong, violates syntax */ - MANDOCERR_SOPATH, /* NOT IMPLEMENTED: .so with absolute path or ".." */ - MANDOCERR_NODOCBODY, /* no document body */ - MANDOCERR_NODOCPROLOG, /* no document prologue */ - MANDOCERR_MEM, /* static buffer exhausted */ + MANDOCERR_TOOLARGE, /* input too large */ + MANDOCERR_BD_FILE, /* NOT IMPLEMENTED: Bd -file */ + MANDOCERR_SO_PATH, /* NOT IMPLEMENTED: .so with absolute path or ".." */ + MANDOCERR_SO_FAIL, /* .so request failed */ + + /* ===== system errors ===== */ + + MANDOCERR_SYSOPEN, /* cannot open file */ + MANDOCERR_SYSSTAT, /* cannot stat file */ + MANDOCERR_SYSREAD, /* cannot read file */ + MANDOCERR_MAX }; struct tbl_opts { char tab; /* cell-separator */ char decimal; /* decimal point */ int linesize; int opts; #define TBL_OPT_CENTRE (1 << 0) #define TBL_OPT_EXPAND (1 << 1) #define TBL_OPT_BOX (1 << 2) #define TBL_OPT_DBOX (1 << 3) #define TBL_OPT_ALLBOX (1 << 4) #define TBL_OPT_NOKEEP (1 << 5) #define TBL_OPT_NOSPACE (1 << 6) int cols; /* number of columns */ }; /* * 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 { int ident; /* 0 <= unique id < cols */ int vert; /* width of preceding vertical line */ struct tbl_head *next; struct tbl_head *prev; }; enum tbl_cellt { TBL_CELL_CENTRE, /* c, C */ TBL_CELL_RIGHT, /* r, R */ TBL_CELL_LEFT, /* l, L */ TBL_CELL_NUMBER, /* n, N */ TBL_CELL_SPAN, /* s, S */ TBL_CELL_LONG, /* a, A */ TBL_CELL_DOWN, /* ^ */ TBL_CELL_HORIZ, /* _, - */ TBL_CELL_DHORIZ, /* = */ TBL_CELL_MAX }; /* * A cell in a layout row. */ struct tbl_cell { struct tbl_cell *next; int vert; /* width of preceding vertical line */ enum tbl_cellt pos; size_t spacing; int flags; #define TBL_CELL_TALIGN (1 << 0) /* t, T */ #define TBL_CELL_BALIGN (1 << 1) /* d, D */ #define TBL_CELL_BOLD (1 << 2) /* fB, B, b */ #define TBL_CELL_ITALIC (1 << 3) /* fI, I, i */ #define TBL_CELL_EQUAL (1 << 4) /* e, E */ #define TBL_CELL_UP (1 << 5) /* u, U */ #define TBL_CELL_WIGN (1 << 6) /* z, Z */ struct tbl_head *head; }; /* * A layout row. */ struct tbl_row { struct tbl_row *next; struct tbl_cell *first; struct tbl_cell *last; + int vert; /* trailing vertical line */ }; enum tbl_datt { TBL_DATA_NONE, /* has no data */ TBL_DATA_DATA, /* consists of data/string */ TBL_DATA_HORIZ, /* horizontal line */ TBL_DATA_DHORIZ, /* double-horizontal line */ TBL_DATA_NHORIZ, /* squeezed horizontal line */ TBL_DATA_NDHORIZ /* squeezed double-horizontal line */ }; /* * A cell within a row of data. The "string" field contains the actual * string value that's in the cell. The rest is layout. */ struct tbl_dat { struct tbl_cell *layout; /* layout cell */ int spans; /* how many spans follow */ struct tbl_dat *next; char *string; /* data (NULL if not TBL_DATA_DATA) */ enum tbl_datt pos; }; enum tbl_spant { TBL_SPAN_DATA, /* span consists of data */ TBL_SPAN_HORIZ, /* span is horizontal line */ TBL_SPAN_DHORIZ /* span is double horizontal line */ }; /* * A row of data in a table. */ struct tbl_span { struct tbl_opts *opts; struct tbl_head *head; struct tbl_row *layout; /* layout row */ struct tbl_dat *first; struct tbl_dat *last; int line; /* parse line */ int flags; #define TBL_SPAN_FIRST (1 << 0) #define TBL_SPAN_LAST (1 << 1) enum tbl_spant pos; struct tbl_span *next; }; enum eqn_boxt { EQN_ROOT, /* root of parse tree */ EQN_TEXT, /* text (number, variable, whatever) */ EQN_SUBEXPR, /* nested `eqn' subexpression */ EQN_LIST, /* subexpressions list */ EQN_MATRIX /* matrix subexpression */ }; enum eqn_markt { EQNMARK_NONE = 0, EQNMARK_DOT, EQNMARK_DOTDOT, EQNMARK_HAT, EQNMARK_TILDE, EQNMARK_VEC, EQNMARK_DYAD, EQNMARK_BAR, EQNMARK_UNDER, EQNMARK__MAX }; enum eqn_fontt { EQNFONT_NONE = 0, EQNFONT_ROMAN, EQNFONT_BOLD, EQNFONT_FAT, EQNFONT_ITALIC, EQNFONT__MAX }; enum eqn_post { EQNPOS_NONE = 0, EQNPOS_OVER, EQNPOS_SUP, EQNPOS_SUB, EQNPOS_TO, EQNPOS_FROM, EQNPOS__MAX }; enum eqn_pilet { EQNPILE_NONE = 0, EQNPILE_PILE, EQNPILE_CPILE, EQNPILE_RPILE, EQNPILE_LPILE, EQNPILE_COL, EQNPILE_CCOL, EQNPILE_RCOL, EQNPILE_LCOL, EQNPILE__MAX }; /* * A "box" is a parsed mathematical expression as defined by the eqn.7 * grammar. */ struct eqn_box { int size; /* font size of expression */ #define EQN_DEFSIZE INT_MIN enum eqn_boxt type; /* type of node */ struct eqn_box *first; /* first child node */ struct eqn_box *last; /* last child node */ struct eqn_box *next; /* node sibling */ struct eqn_box *parent; /* node sibling */ char *text; /* text (or NULL) */ char *left; char *right; enum eqn_post pos; /* position of next box */ enum eqn_markt mark; /* a mark about the box */ enum eqn_fontt font; /* font of box */ enum eqn_pilet pile; /* equation piling */ }; /* * An equation consists of a tree of expressions starting at a given - * line and position. + * line and position. */ struct eqn { char *name; /* identifier (or NULL) */ struct eqn_box *root; /* root mathematical expression */ int ln; /* invocation line */ int pos; /* invocation position */ }; /* - * The type of parse sequence. This value is usually passed via the - * mandoc(1) command line of -man and -mdoc. It's almost exclusively - * -mandoc but the others have been retained for compatibility. + * Parse options. */ -enum mparset { - MPARSE_AUTO, /* magically determine the document type */ - MPARSE_MDOC, /* assume -mdoc */ - MPARSE_MAN /* assume -man */ -}; +#define MPARSE_MDOC 1 /* assume -mdoc */ +#define MPARSE_MAN 2 /* assume -man */ +#define MPARSE_SO 4 /* honour .so requests */ +#define MPARSE_QUICK 8 /* abort the parse early */ enum mandoc_esc { ESCAPE_ERROR = 0, /* bail! unparsable escape */ ESCAPE_IGNORE, /* escape to be ignored */ ESCAPE_SPECIAL, /* a regular special character */ 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_SKIPCHAR /* skip the next character */ }; typedef void (*mandocmsg)(enum mandocerr, enum mandoclevel, const char *, int, int, const char *); struct mparse; struct mchars; struct mdoc; struct man; __BEGIN_DECLS -void *mandoc_calloc(size_t, size_t); enum mandoc_esc mandoc_escape(const char **, const char **, int *); -void *mandoc_malloc(size_t); -void *mandoc_realloc(void *, size_t); -char *mandoc_strdup(const char *); -char *mandoc_strndup(const char *, size_t); struct mchars *mchars_alloc(void); void mchars_free(struct mchars *); -char mchars_num2char(const char *, size_t); +char mchars_num2char(const char *, size_t); int mchars_num2uc(const char *, size_t); -int mchars_spec2cp(const struct mchars *, +int mchars_spec2cp(const struct mchars *, const char *, size_t); -const char *mchars_spec2str(const struct mchars *, +const char *mchars_spec2str(const struct mchars *, const char *, size_t, size_t *); -struct mparse *mparse_alloc(enum mparset, enum mandoclevel, - mandocmsg, void *, char *); +struct mparse *mparse_alloc(int, enum mandoclevel, mandocmsg, + const char *); void mparse_free(struct mparse *); void mparse_keep(struct mparse *); enum mandoclevel mparse_readfd(struct mparse *, int, const char *); enum mandoclevel mparse_readmem(struct mparse *, const void *, size_t, const char *); void mparse_reset(struct mparse *); -void mparse_result(struct mparse *, - struct mdoc **, struct man **); +void mparse_result(struct mparse *, + struct mdoc **, struct man **, char **); const char *mparse_getkeep(const struct mparse *); const char *mparse_strerror(enum mandocerr); const char *mparse_strlevel(enum mandoclevel); __END_DECLS #endif /*!MANDOC_H*/ Index: head/contrib/mdocml/mandoc_aux.c =================================================================== --- head/contrib/mdocml/mandoc_aux.c (nonexistent) +++ head/contrib/mdocml/mandoc_aux.c (revision 274880) @@ -0,0 +1,121 @@ +/* $Id: mandoc_aux.c,v 1.3 2014/07/09 08:20:34 schwarze Exp $ */ +/* + * Copyright (c) 2009, 2011 Kristaps Dzonsons + * Copyright (c) 2014 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include +#include + +#include "mandoc.h" +#include "mandoc_aux.h" + +int +mandoc_asprintf(char **dest, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = vasprintf(dest, fmt, ap); + va_end(ap); + + if (-1 == ret) { + perror(NULL); + exit((int)MANDOCLEVEL_SYSERR); + } + return(ret); +} + +void * +mandoc_calloc(size_t num, size_t size) +{ + void *ptr; + + ptr = calloc(num, size); + if (NULL == ptr) { + perror(NULL); + exit((int)MANDOCLEVEL_SYSERR); + } + return(ptr); +} + +void * +mandoc_malloc(size_t size) +{ + void *ptr; + + ptr = malloc(size); + if (NULL == ptr) { + perror(NULL); + exit((int)MANDOCLEVEL_SYSERR); + } + return(ptr); +} + +void * +mandoc_realloc(void *ptr, size_t size) +{ + + ptr = realloc(ptr, size); + if (NULL == ptr) { + perror(NULL); + exit((int)MANDOCLEVEL_SYSERR); + } + return(ptr); +} + +void * +mandoc_reallocarray(void *ptr, size_t num, size_t size) +{ + + ptr = reallocarray(ptr, num, size); + if (NULL == ptr) { + perror(NULL); + exit((int)MANDOCLEVEL_SYSERR); + } + return(ptr); +} + +char * +mandoc_strdup(const char *ptr) +{ + char *p; + + p = strdup(ptr); + if (NULL == p) { + perror(NULL); + exit((int)MANDOCLEVEL_SYSERR); + } + return(p); +} + +char * +mandoc_strndup(const char *ptr, size_t sz) +{ + char *p; + + p = mandoc_malloc(sz + 1); + memcpy(p, ptr, sz); + p[(int)sz] = '\0'; + return(p); +} Property changes on: head/contrib/mdocml/mandoc_aux.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/mdocml/mandoc_aux.h =================================================================== --- head/contrib/mdocml/mandoc_aux.h (nonexistent) +++ head/contrib/mdocml/mandoc_aux.h (revision 274880) @@ -0,0 +1,33 @@ +/* $Id: mandoc_aux.h,v 1.2 2014/04/23 21:06:41 schwarze Exp $ */ +/* + * Copyright (c) 2009, 2011 Kristaps Dzonsons + * Copyright (c) 2014 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef MANDOC_AUX_H +#define MANDOC_AUX_H + +__BEGIN_DECLS + +int mandoc_asprintf(char **, const char *, ...); +void *mandoc_calloc(size_t, size_t); +void *mandoc_malloc(size_t); +void *mandoc_realloc(void *, size_t); +void *mandoc_reallocarray(void *, size_t, size_t); +char *mandoc_strdup(const char *); +char *mandoc_strndup(const char *, size_t); + +__END_DECLS + +#endif /*!MANDOC_AUX_H*/ Property changes on: head/contrib/mdocml/mandoc_aux.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/mdocml/mandoc_escape.3 =================================================================== --- head/contrib/mdocml/mandoc_escape.3 (nonexistent) +++ head/contrib/mdocml/mandoc_escape.3 (revision 274880) @@ -0,0 +1,362 @@ +.\" $Id: mandoc_escape.3,v 1.1 2014/08/05 05:48:56 schwarze Exp $ +.\" +.\" Copyright (c) 2014 Ingo Schwarze +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: August 5 2014 $ +.Dt MANDOC_ESCAPE 3 +.Os +.Sh NAME +.Nm mandoc_escape +.Nd parse roff escape sequences +.Sh LIBRARY +.Lb libmandoc +.Sh SYNOPSIS +.In sys/types.h +.In mandoc.h +.Ft "enum mandoc_esc" +.Fo mandoc_escape +.Fa "const char **end" +.Fa "const char **start" +.Fa "int *sz" +.Fc +.Sh DESCRIPTION +This function scans a +.Xr roff 7 +escape sequence. +.Pp +An escape sequence consists of +.Bl -dash -compact -width 2n +.It +an initial backslash character +.Pq Sq \e , +.It +a single ASCII character called the escape sequence identifier, +.It +and, with only a few exceptions, an argument. +.El +.Pp +Arguments can be given in the following forms; some escape sequence +identifiers only accept some of these forms as specified below. +The first three forms are called the standard forms. +.Bl -tag -width 2n +.It \&In brackets: Ic \&[ Ns Ar argument Ns Ic \&] +The argument starts after the initial +.Sq \&[ , +ends before the final +.Sq \&] , +and the escape sequence ends with the final +.Sq \&] . +.It Two-character argument short form: Ic \&( Ns Ar ar +This form can only be used for arguments +consisting of exactly two characters. +It has the same effect as +.Ic \&[ Ns Ar ar Ns Ic \&] . +.It One-character argument short form: Ar a +This form can only be used for arguments +consisting of exactly one character. +It has the same effect as +.Ic \&[ Ns Ar a Ns Ic \&] . +.It Delimited form: Ar C Ns Ar argument Ns Ar C +The argument starts after the initial delimiter character +.Ar C , +ends before the next occurrence of the delimiter character +.Ar C , +and the escape sequence ends with that second +.Ar C . +Some escape sequences allow arbitrary characters +.Ar C +as quoting characters, some restrict the range of characters +that can be used as quoting characters. +.El +.Pp +Upon function entry, +.Fa end +is expected to point to the escape sequence identifier. +The values passed in as +.Fa start +and +.Fa sz +are ignored and overwritten. +.Pp +By design, this function cannot handle those +.Xr roff 7 +escape sequences that require in-place expansion, in particular +user-defined strings +.Ic \e* , +number registers +.Ic \en , +width measurements +.Ic \ew , +and numerical expression control +.Ic \eB . +These are handled by +.Fn roff_res , +a private preprocessor function called from +.Fn roff_parseln , +see the file +.Pa roff.c . +.Pp +The function +.Fn mandoc_escape +is used +.Bl -dash -compact -width 2n +.It +recursively by itself, because some escape sequence arguments can +in turn contain other escape sequences, +.It +for error detection internally by the +.Xr roff 7 +parser part of the +.Lb libmandoc , +see the file +.Pa roff.c , +.It +above all externally by the +.Xr mandoc +formatting modules, in particular +.Fl Tascii +and +.Fl Thtml , +for formatting purposes, see the files +.Pa term.c +and +.Pa html.c , +.It +and rarely externally by high-level utilities using the mandoc library, +for example +.Xr makewhatis 8 , +to purge escape sequences from text. +.El +.Sh RETURN VALUES +Upon function return, the pointer +.Fa end +is set to the character after the end of the escape sequence, +such that the calling higher-level parser can easily continue. +.Pp +For escape sequences taking an argument, the pointer +.Fa start +is set to the beginning of the argument and +.Fa sz +is set to the length of the argument. +For escape sequences not taking an argument, +.Fa start +is set to the character after the end of the sequence and +.Fa sz +is set to 0. +Both +.Fa start +and +.Fa sz +may be +.Dv NULL ; +in that case, the argument and the length are not returned. +.Pp +For sequences taking an argument, the function +.Fn mandoc_escape +returns one of the following values: +.Bl -tag -width 2n +.It Dv ESCAPE_FONT +The escape sequence +.Ic \ef +taking an argument in standard form: +.Ic \ef[ , \ef( , \ef Ns Ar a . +Two-character arguments starting with the character +.Sq C +are reduced to one-character arguments by skipping the +.Sq C . +More specific values are returned for the most commonly used arguments: +.Bl -column "argument" "ESCAPE_FONTITALIC" +.It argument Ta return value +.It Cm R No or Cm 1 Ta Dv ESCAPE_FONTROMAN +.It Cm I No or Cm 2 Ta Dv ESCAPE_FONTITALIC +.It Cm B No or Cm 3 Ta Dv ESCAPE_FONTBOLD +.It Cm P Ta Dv ESCAPE_FONTPREV +.It Cm BI Ta Dv ESCAPE_FONTBI +.El +.It Dv ESCAPE_SPECIAL +The escape sequence +.Ic \eC +taking an argument delimited with the single quote character +and, as a special exception, the escape sequences +.Em not +having an identifier, that is, those where the argument, in standard +form, directly follows the initial backslash: +.Ic \eC' , \e[ , \e( , \e Ns Ar a . +Note that the one-character argument short form can only be used for +argument characters that do not clash with escape sequence identifiers. +.Pp +If the argument consists of more than one character +and starts with the character +.Sq u , +.Dv ESCAPE_UNICODE +is returned as described below. +If the argument is just the single character +.Sq u , +.Dv ESCAPE_ERROR +is returned. +.Pp +The +.Dv ESCAPE_SPECIAL +special character escape sequences can be rendered using the functions +.Fn mchars_spec2cp +and +.Fn mchars_spec2str +described in the +.Xr mchars_alloc 3 +manual. +.It Dv ESCAPE_UNICODE +Escape sequences of the same format as described above under +.Dv ESCAPE_SPECIAL , +but with an argument starting with the character +.Sq u : +.Ic \eC'u , \e[u . +As a special exception, +.Fa start +is set to the character after the +.Sq u , +and the +.Fa sz +return value does not include the +.Sq u +either. +.Pp +Such Unicode character escape sequences can be rendered using the function +.Fn mchars_num2uc +described in the +.Xr mchars_alloc 3 +manual. +.It Dv ESCAPE_NUMBERED +The escape sequence +.Ic \eN +followed by a delimited argument. +The delimiter character is arbitrary except that digits cannot be used. +If a digit is encountered instead of the opening delimiter, that +digit is considered to be the argument and the end of the sequence, and +.Dv ESCAPE_IGNORE +is returned. +.Pp +Such ASCII character escape sequences can be rendered using the function +.Fn mchars_num2char +described in the +.Xr mchars_alloc 3 +manual. +.It Dv ESCAPE_IGNORE +.Bl -bullet -width 2n +.It +The escape sequence +.Ic \es +followed by an argument in standard form or by an argument delimited +by the single quote character: +.Ic \es' , \es[ , \es( , \es Ns Ar a . +As a special exception, an optional +.Sq + +or +.Sq \- +character is allowed after the +.Sq s +for all forms. +.It +The escape sequences +.Ic \eF , +.Ic \eg , +.Ic \ek , +.Ic \eM , +.Ic \em , +.Ic \en , +.Ic \eV , +and +.Ic \eY +followed by an argument in standard form. +.It +The escape sequences +.Ic \eA , +.Ic \eb , +.Ic \eD , +.Ic \eo , +.Ic \eR , +.Ic \eX , +and +.Ic \eZ +followed by an argument delimited by an arbitrary character. +.It +The escape sequences +.Ic \eH , +.Ic \eh , +.Ic \eL , +.Ic \el , +.Ic \eS , +.Ic \ev , +and +.Ic \ex +followed by an argument delimited by a character that cannot occur +in numerical expressions. +However, if any character that can occur in numerical expressions +is found instead of a delimiter, the sequence is considered to end +with that character, and +.Dv ESCAPE_ERROR +is returned. +.El +.It Dv ESCAPE_ERROR +Escape sequences taking an argument but not matching any of the above patterns. +In particular, that happens if the end of the logical input line +is reached before the end of the argument. +.El +.Pp +For sequences that do not take an argument, the function +.Fn mandoc_escape +returns one of the following values: +.Bl -tag -width 2n +.It Dv ESCAPE_SKIPCHAR +The escape sequence +.Qq \ez . +.It Dv ESCAPE_NOSPACE +The escape sequence +.Qq \ec . +.It Dv ESCAPE_IGNORE +The escape sequences +.Qq \ed +and +.Qq \eu . +.El +.Sh FILES +This function is implemented in +.Pa mandoc.c . +.Sh SEE ALSO +.Xr mchars_alloc 3 , +.Xr mandoc_char 7 , +.Xr roff 7 +.Sh HISTORY +This function has been available since mandoc 1.11.2. +.Sh AUTHORS +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv +.An Ingo Schwarze Aq Mt schwarze@openbsd.org +.Sh BUGS +The function doesn't cleanly distinguish between sequences that are +valid and supported, valid and ignored, valid and unsupported, +syntactically invalid, or undefined. +For sequences that are ignored or unsupported, it doesn't tell +whether that deficiency is likely to cause major formatting problems +and/or loss of document content. +The function is already rather complicated and still parses some +sequences incorrectly. +. +.ig +For these sequences, the list given below specifies a starting string +and either the length of the argument or an ending character. +The argument starts after the starting string. +In the former case, the sequence ends with the end of the argument. +In the latter case, the argument ends before the ending character, +and the sequence ends with the ending character. +.. Property changes on: head/contrib/mdocml/mandoc_escape.3 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/mdocml/mandoc_html.3 =================================================================== --- head/contrib/mdocml/mandoc_html.3 (nonexistent) +++ head/contrib/mdocml/mandoc_html.3 (revision 274880) @@ -0,0 +1,249 @@ +.\" $Id: mandoc_html.3,v 1.1 2014/07/23 18:13:09 schwarze Exp $ +.\" +.\" Copyright (c) 2014 Ingo Schwarze +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: July 23 2014 $ +.Dt MANDOC_HTML 3 +.Os +.Sh NAME +.Nm mandoc_html +.Nd internals of the mandoc HTML formatter +.Sh SYNOPSIS +.In "html.h" +.Ft void +.Fn print_gen_decls "struct html *h" +.Ft void +.Fn print_gen_head "struct html *h" +.Ft struct tag * +.Fo print_otag +.Fa "struct html *h" +.Fa "enum htmltag tag" +.Fa "int sz" +.Fa "const struct htmlpair *p" +.Fc +.Ft void +.Fo print_tagq +.Fa "struct html *h" +.Fa "const struct tag *until" +.Fc +.Ft void +.Fo print_stagq +.Fa "struct html *h" +.Fa "const struct tag *suntil" +.Fc +.Ft void +.Fo print_text +.Fa "struct html *h" +.Fa "const char *word" +.Fc +.Sh DESCRIPTION +The mandoc HTML formatter is not a formal library. +However, as it is compiled into more than one program, in particular +.Xr mandoc 1 +and +.Xr man.cgi 8 , +and because it may be security-critical in some contexts, +some documentation is useful to help to use it correctly and +to prevent XSS vulnerabilities. +.Pp +The formatter produces HTML output on the standard output. +Since proper escaping is usually required and best taken care of +at one central place, the language-specific formatters +.Po +.Pa *_html.c , +see +.Sx FILES +.Pc +are not supposed to print directly to +.Dv stdout +using functions like +.Xr printf 3 , +.Xr putc 3 , +.Xr puts 3 , +or +.Xr write 2 . +Instead, they are expected to use the output functions declared in +.Pa html.h +and implemented as part of the main HTML formatting engine in +.Pa html.c . +.Ss Data structures +These structures are declared in +.Pa html.h . +.Bl -tag -width Ds +.It Vt struct html +Internal state of the HTML formatter. +.It Vt struct htmlpair +Holds one HTML attribute. +Members are +.Fa "enum htmlattr key" +and +.Fa "const char *val" . +Helper macros +.Fn PAIR_* +are provided to support initialization of such structures. +.It Vt struct tag +One entry for the LIFO stack of HTML elements. +Members are +.Fa "enum htmltag tag" +and +.Fa "struct tag *next" . +.El +.Ss Private interface functions +The function +.Fn print_gen_decls +prints the opening +.Ao Pf \&? Ic xml ? Ac +and +.Aq Pf \&! Ic DOCTYPE +declarations required for the current document type. +.Pp +The function +.Fn print_gen_head +prints the opening +.Aq Ic META +and +.Aq Ic LINK +elements for the document +.Aq Ic HEAD , +using the +.Fa style +member of +.Fa h +unless that is +.Dv NULL . +It uses +.Fn print_otag +which takes care of properly encoding attributes, +which is relevant for the +.Fa style +link in particular. +.Pp +The function +.Fn print_otag +prints the start tag of an HTML element with the name +.Fa tag , +including the +.Fa sz +attributes that can optionally be provided in the +.Fa p +array. +It uses the private function +.Fn print_attr +which in turn uses the private function +.Fn print_encode +to take care of HTML encoding. +If required by the element type, it remembers in +.Fa h +that the element is open. +The function +.Fn print_tagq +is used to close out all open elements up to and including +.Fa until ; +.Fn print_stagq +is a variant to close out all open elements up to but excluding +.Fa suntil . +.Pp +The function +.Fn print_text +prints HTML element content. +It uses the private function +.Fn print_encode +to take care of HTML encoding. +If the document has requested a non-standard font, for example using a +.Xr roff 7 +.Ic \ef +font escape sequence, +.Fn print_text +wraps +.Fa word +in an HTML font selection element using the +.Fn print_otag +and +.Fn print_tagq +functions. +.Pp +The functions +.Fn bufinit , +.Fn bufcat* , +and +.Fn buffmt* +do not directly produce output but buffer text in the +.Fa buf +member of +.Fa h . +They are not used internally by +.Pa html.c +but intended for use by the language-specific formatters +to ease preparation of strings for the +.Fa p +argument of +.Fn print_otag +and for the +.Fa word +argument of +.Fn print_text . +Consequently, these functions do not do any HTML encoding. +.Pp +The functions +.Fn html_strlen , +.Fn print_eqn , +.Fn print_tbl , +and +.Fn print_tblclose +are not yet documented. +.Sh FILES +.Bl -tag -width mandoc_aux.c -compact +.It Pa main.h +declarations of public functions for use by the main program, +not yet documented +.It Pa html.h +declarations of data types and private functions +for use by language-specific HTML formatters +.It Pa html.c +main HTML formatting engine and utility functions +.It Pa mdoc_html.c +.Xr mdoc 7 +HTML formatter +.It Pa man_html.c +.Xr man 7 +HTML formatter +.It Pa tbl_html.c +.Xr tbl 7 +HTML formatter +.It Pa eqn_html.c +.Xr eqn 7 +HTML formatter +.It Pa out.h +declarations of data types and private functions +for shared use by all mandoc formatters, +not yet documented +.It Pa out.c +private functions for shared use by all mandoc formatters +.It Pa mandoc_aux.h +declarations of common mandoc utility functions, see +.Xr mandoc 3 +.It Pa mandoc_aux.c +implementation of common mandoc utility functions +.El +.Sh SEE ALSO +.Xr mandoc 1 , +.Xr mandoc 3 , +.Xr man.cgi 8 +.Sh AUTHORS +.An -nosplit +The mandoc HTML formatter was written by +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv . +This manual was written by +.An Ingo Schwarze Aq Mt schwarze@openbsd.org . Property changes on: head/contrib/mdocml/mandoc_html.3 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/mdocml/mandoc_malloc.3 =================================================================== --- head/contrib/mdocml/mandoc_malloc.3 (nonexistent) +++ head/contrib/mdocml/mandoc_malloc.3 (revision 274880) @@ -0,0 +1,197 @@ +.\" $Id: mandoc_malloc.3,v 1.1 2014/08/05 05:48:56 schwarze Exp $ +.\" +.\" Copyright (c) 2014 Ingo Schwarze +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: August 5 2014 $ +.Dt MANDOC_MALLOC 3 +.Os +.Sh NAME +.Nm mandoc_malloc , +.Nm mandoc_realloc , +.Nm mandoc_reallocarray , +.Nm mandoc_calloc , +.Nm mandoc_strdup , +.Nm mandoc_strndup , +.Nm mandoc_asprintf +.Nd memory allocation function wrappers used in the mandoc library +.Sh LIBRARY +.Lb libmandoc +.Sh SYNOPSIS +.In sys/types.h +.In mandoc_aux.h +.Ft "void *" +.Fo mandoc_malloc +.Fa "size_t size" +.Fc +.Ft "void *" +.Fo mandoc_realloc +.Fa "void *ptr" +.Fa "size_t size" +.Fc +.Ft "void *" +.Fo mandoc_reallocarray +.Fa "void *ptr" +.Fa "size_t nmemb" +.Fa "size_t size" +.Fc +.Ft "void *" +.Fo mandoc_calloc +.Fa "size_t nmemb" +.Fa "size_t size" +.Fc +.Ft "char *" +.Fo mandoc_strdup +.Fa "const char *s" +.Fc +.Ft "char *" +.Fo mandoc_strndup +.Fa "const char *s" +.Fa "size_t maxlen" +.Fc +.Ft int +.Fo mandoc_asprintf +.Fa "char **ret" +.Fa "const char *format" +.Fa "..." +.Fc +.Sh DESCRIPTION +These functions call the +.Lb libc +functions of the same names, passing through their return values when +successful. +In case of failure, they do not return, but instead call +.Xr perror 3 +and +.Xr exit 3 . +They can be used both internally by any code in the +.Lb libmandoc +and externally by programs using that library, for example +.Xr mandoc 1 , +.Xr apropos 1 , +and +.Xr makewhatis 8 . +.Pp +The function +.Fn mandoc_malloc +allocates one new object, leaving the memory uninitialized. +The functions +.Fn mandoc_realloc +and +.Fn mandoc_reallocarray +change the size of an existing object or array, possibly moving it. +When shrinking the size, existing data is truncated; when growing, +the additional memory is not initialized. +The function +.Fn mandoc_calloc +allocates a new array, initializing it to zero. +.Pp +The argument +.Fa size +is the size of each object. +The argument +.Fa nmemb +is the new number of objects in the array. +The argument +.Fa ptr +is a pointer to the existing object or array to be resized; if it is +.Dv NULL , +a new object or array is allocated. +.Pp +The functions +.Fn mandoc_strdup +and +.Fn mandoc_strndup +copy a string into newly allocated memory. +For +.Fn mandoc_strdup , +the string pointed to by +.Fa s +needs to be NUL-terminated. +For +.Fn mandoc_strndup , +at most +.Fa maxlen +bytes are copied. +The function +.Fn mandoc_asprintf +writes output formatted according to +.Fa format +into newly allocated memory and returns a pointer to the result in +.Fa ret . +For all three string functions, the result is always NUL-terminated. +.Pp +When the objects and strings are no longer needed, +the pointers returned by these functions can be passed to +.Xr free 3 . +.Sh RETURN VALUES +The function +.Fn mandoc_asprintf +always returns the number of characters written, excluding the +final NUL byte. +It never returns -1. +.Pp +The other functions always return a valid pointer; they never return +.Dv NULL . +.Sh FILES +These functions are implemented in +.Pa mandoc_aux.c . +.Sh SEE ALSO +.Xr asprintf 3 , +.Xr exit 3 , +.Xr malloc 3 , +.Xr perror 3 , +.Xr strdup 3 +.Sh STANDARDS +The functions +.Fn malloc , +.Fn realloc , +and +.Fn calloc +are required by +.St -ansiC . +The functions +.Fn strdup +and +.Fn strndup +are required by +.St -p1003.1-2008 . +The function +.Fn asprintf +is a widespread extension that first appeared in the GNU C library. +.Pp +The function +.Fn reallocarray +is an extension that first appeared in +.Ox 5.6 . +If it is not provided by the operating system, the mandoc build system +uses a bundled portable implementation. +.Sh HISTORY +The functions +.Fn mandoc_malloc , +.Fn mandoc_realloc , +.Fn mandoc_calloc , +and +.Fn mandoc_strdup +have been available since mandoc 1.9.12, +.Fn mandoc_strndup +since 1.11.5, +and +.Fn mandoc_asprintf +and +.Fn mandoc_reallocarray +since 1.12.4 and 1.13.0. +.Sh AUTHORS +.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv +.An Ingo Schwarze Aq Mt schwarze@openbsd.org Property changes on: head/contrib/mdocml/mandoc_malloc.3 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/mdocml/mandocdb.c =================================================================== --- head/contrib/mdocml/mandocdb.c (nonexistent) +++ head/contrib/mdocml/mandocdb.c (revision 274880) @@ -0,0 +1,2491 @@ +/* $Id: mandocdb.c,v 1.155 2014/08/06 15:09:05 schwarze Exp $ */ +/* + * Copyright (c) 2011, 2012 Kristaps Dzonsons + * Copyright (c) 2011, 2012, 2013, 2014 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include