diff --git a/Makefile.depend b/Makefile.depend index a0898095ae7a..3540aeda822c 100644 --- a/Makefile.depend +++ b/Makefile.depend @@ -29,7 +29,7 @@ dbm.o: dbm.c config.h mansearch.h dbm_map.h dbm.h dbm_map.o: dbm_map.c config.h mansearch.h dbm_map.h dbm.h demandoc.o: demandoc.c config.h mandoc.h roff.h man.h mdoc.h mandoc_parse.h eqn.o: eqn.c config.h mandoc_aux.h mandoc.h roff.h eqn.h libmandoc.h eqn_parse.h -eqn_html.o: eqn_html.c config.h mandoc.h eqn.h out.h html.h +eqn_html.o: eqn_html.c config.h mandoc.h roff.h eqn.h out.h html.h eqn_term.o: eqn_term.c config.h eqn.h out.h term.h html.o: html.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h out.h html.h manconf.h main.h lib.o: lib.c config.h roff.h libmdoc.h lib.in @@ -37,16 +37,16 @@ main.o: main.c config.h mandoc_aux.h mandoc.h mandoc_xr.h roff.h mdoc.h man.h ma man.o: man.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h man_html.o: man_html.c config.h mandoc_aux.h mandoc.h roff.h man.h out.h html.h main.h man_macro.o: man_macro.c config.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h -man_term.o: man_term.c config.h mandoc_aux.h roff.h man.h out.h term.h main.h +man_term.o: man_term.c config.h mandoc_aux.h mandoc.h roff.h man.h out.h term.h tag.h main.h man_validate.o: man_validate.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h mandoc.o: mandoc.c config.h mandoc_aux.h mandoc.h roff.h libmandoc.h roff_int.h mandoc_aux.o: mandoc_aux.c config.h mandoc.h mandoc_aux.h -mandoc_msg.o: mandoc_msg.c mandoc.h +mandoc_msg.o: mandoc_msg.c config.h mandoc.h mandoc_ohash.o: mandoc_ohash.c mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc_xr.o: mandoc_xr.c mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc_xr.h mandocd.o: mandocd.c config.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h main.h manconf.h mandocdb.o: mandocdb.c config.h compat_fts.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h manconf.h mansearch.h dba_array.h dba.h -manpath.o: manpath.c config.h mandoc_aux.h manconf.h +manpath.o: manpath.c config.h mandoc_aux.h mandoc.h manconf.h mansearch.o: mansearch.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h manconf.h mansearch.h dbm.h mdoc.o: mdoc.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h mdoc_argv.o: mdoc_argv.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h @@ -67,10 +67,10 @@ roff_term.o: roff_term.c mandoc.h roff.h out.h term.h roff_validate.o: roff_validate.c mandoc.h roff.h libmandoc.h roff_int.h soelim.o: soelim.c config.h compat_stringlist.h st.o: st.c config.h mandoc.h roff.h libmdoc.h -tag.o: tag.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h tag.h +tag.o: tag.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h tag.h tbl.o: tbl.c config.h mandoc_aux.h mandoc.h tbl.h libmandoc.h tbl_parse.h tbl_int.h tbl_data.o: tbl_data.c config.h mandoc_aux.h mandoc.h tbl.h libmandoc.h tbl_int.h -tbl_html.o: tbl_html.c config.h mandoc.h tbl.h out.h html.h +tbl_html.o: tbl_html.c config.h mandoc.h roff.h tbl.h out.h html.h tbl_layout.o: tbl_layout.c config.h mandoc_aux.h mandoc.h tbl.h libmandoc.h tbl_int.h tbl_opts.o: tbl_opts.c config.h mandoc.h tbl.h libmandoc.h tbl_int.h tbl_term.o: tbl_term.c config.h mandoc.h tbl.h out.h term.h diff --git a/TODO b/TODO index 063e2789d2c5..049e6a4f2beb 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,6 @@ ************************************************************************ * Official mandoc TODO. -* $Id: TODO,v 1.289 2019/03/04 13:01:57 schwarze Exp $ +* $Id: TODO,v 1.295 2019/06/11 16:04:36 schwarze Exp $ ************************************************************************ Many issues are annotated for difficulty as follows: @@ -62,6 +62,27 @@ are mere guesses, and some may be wrong. needed for Tcl_NewStringObj(3) via wiz@ Wed, 5 Mar 2014 22:27:43 +0100 loc ** exist *** algo *** size * imp *** +- .als only works for macros in mandoc, not for user-defined strings. + Also, the "val" field in struct roffkv would have to be replaced + with a pointer to a reference-counted wrapper, and an alias + would have to point to the same wrapper as the original. + .als to undefined does nothing; the alias is not created. + .rm'ing the original leaves the alias to point to the old value. + .de .als .de changes both, but + .de .als .rm .de only changes the new value, not the alias. + Found in groffer(1) version 1.19 + Jan Stary 20 Apr 2019 20:16:54 +0200 + loc * exist ** algo ** size ** imp * + +- roff string condition comparisons fail when vars contain quotes: + .ds s ' + .if '\*s'' \&... + hard to fix because of the basic architecture (string replacement + happens before roff(7) syntax parsing) + Found in groffer(1) version 1.19 + Jan Stary 20 Apr 2019 20:16:54 +0200 + loc * exist *** algo *** size ** imp * + --- missing mdoc features ---------------------------------------------- - .Bl -column .Xo support is missing @@ -264,6 +285,9 @@ are mere guesses, and some may be wrong. https://github.com/schmonz/ikiwiki/compare/mandoc Amitai Schlair Mon, 19 May 2014 14:05:53 -0400 +- check compatibility with + https://git.sr.ht/~sircmpwn/scdoc + - check features of the Slackware man.conf(5) format Carsten Kunze Wed, 11 Mar 2015 17:57:24 +0100 diff --git a/arch.c b/arch.c index 56b937ec8412..551c86796a21 100644 --- a/arch.c +++ b/arch.c @@ -1,4 +1,4 @@ -/* $Id: arch.c,v 1.14 2019/03/04 13:01:57 schwarze Exp $ */ +/* $Id: arch.c,v 1.15 2019/05/21 07:52:00 schwarze Exp $ */ /* * Copyright (c) 2017, 2019 Ingo Schwarze * @@ -26,7 +26,7 @@ arch_valid(const char *arch, enum mandoc_os os) const char *openbsd_arch[] = { "alpha", "amd64", "arm64", "armv7", "hppa", "i386", "landisk", "loongson", "luna88k", "macppc", "mips64", - "octeon", "sgi", "socppc", "sparc64", NULL + "octeon", "sgi", "sparc64", NULL }; const char *netbsd_arch[] = { "acorn26", "acorn32", "algor", "alpha", "amiga", diff --git a/cgi.c b/cgi.c index 0af0f1255d40..4762f819d57d 100644 --- a/cgi.c +++ b/cgi.c @@ -1,4 +1,4 @@ -/* $Id: cgi.c,v 1.166 2019/03/06 12:32:41 schwarze Exp $ */ +/* $Id: cgi.c,v 1.167 2019/07/10 12:49:20 schwarze Exp $ */ /* * Copyright (c) 2011, 2012 Kristaps Dzonsons * Copyright (c) 2014, 2015, 2016, 2017, 2018 Ingo Schwarze @@ -869,7 +869,6 @@ resp_format(const struct req *req, const char *file) memset(&conf, 0, sizeof(conf)); conf.fragment = 1; conf.style = mandoc_strdup(CSS_DIR "/mandoc.css"); - conf.toc = 1; usepath = strcmp(req->q.manpath, req->p[0]); mandoc_asprintf(&conf.man, "/%s%s%s%s%%N.%%S", scriptname, *scriptname == '\0' ? "" : "/", diff --git a/configure b/configure index 5507de7021b8..2df028da0510 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #!/bin/sh # -# $Id: configure,v 1.70 2019/03/06 16:04:31 schwarze Exp $ +# $Id: configure,v 1.71 2019/07/01 22:56:24 schwarze Exp $ # # Copyright (c) 2014-2019 Ingo Schwarze # @@ -529,7 +529,7 @@ fi echo "extern char *mkdtemp(char *);" if [ ${HAVE_PROGNAME} -eq 0 ]; then - echo "extern const char *getprogname(void);" + echo "extern const char *getprogname(void);" echo "extern void setprogname(const char *);" fi diff --git a/dbm.c b/dbm.c index f6b1259ef5ad..7dc07d0674ad 100644 --- a/dbm.c +++ b/dbm.c @@ -1,4 +1,4 @@ -/* $Id: dbm.c,v 1.6 2018/11/19 19:22:07 schwarze Exp $ */ +/* $Id: dbm.c,v 1.7 2019/07/01 22:56:24 schwarze Exp $ */ /* * Copyright (c) 2016 Ingo Schwarze * @@ -233,7 +233,7 @@ static struct dbm_res page_bytitle(enum iter arg_iter, const struct dbm_match *arg_match) { static const struct dbm_match *match; - static const char *cp; + static const char *cp; static int32_t ip; struct dbm_res res = {-1, 0}; @@ -315,7 +315,7 @@ page_byarch(const struct dbm_match *arg_match) static const struct dbm_match *match; struct dbm_res res = {-1, 0}; static int32_t ip; - const char *cp; + const char *cp; /* Initialize for a new iteration. */ diff --git a/dbm_map.h b/dbm_map.h index 9768fc5f2dcc..dc072aef5463 100644 --- a/dbm_map.h +++ b/dbm_map.h @@ -1,4 +1,4 @@ -/* $Id: dbm_map.h,v 1.1 2016/07/19 21:31:55 schwarze Exp $ */ +/* $Id: dbm_map.h,v 1.2 2019/07/01 22:56:24 schwarze Exp $ */ /* * Copyright (c) 2016 Ingo Schwarze * @@ -14,7 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * Private interface for low-level routines for the map-based version + * Private interface for low-level routines for the map-based version * of the mandoc database, for read-only access. * To be used by dbm*.c only. */ diff --git a/eqn.7 b/eqn.7 index 244903c56fe9..c9fe483b1719 100644 --- a/eqn.7 +++ b/eqn.7 @@ -1,4 +1,4 @@ -.\" $Id: eqn.7,v 1.37 2017/09/04 10:35:27 schwarze Exp $ +.\" $Id: eqn.7,v 1.38 2019/04/23 17:57:49 schwarze Exp $ .\" .\" Copyright (c) 2011 Kristaps Dzonsons .\" Copyright (c) 2014 Ingo Schwarze @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: September 4 2017 $ +.Dd $Mdocdate: April 23 2019 $ .Dt EQN 7 .Os .Sh NAME @@ -470,7 +470,7 @@ commands are also ignored. .%T System for Typesetting Mathematics .%J Communications of the ACM .%V 18 -.%P 151\(en157 +.%P pp. 151\(en157 .%D March, 1975 .Re .Rs diff --git a/eqn_html.c b/eqn_html.c index 1fe41ecbfac5..64d06649997f 100644 --- a/eqn_html.c +++ b/eqn_html.c @@ -1,4 +1,4 @@ -/* $Id: eqn_html.c,v 1.18 2018/12/13 05:23:38 schwarze Exp $ */ +/* $Id: eqn_html.c,v 1.19 2019/03/17 18:21:45 schwarze Exp $ */ /* * Copyright (c) 2011, 2014 Kristaps Dzonsons * Copyright (c) 2017 Ingo Schwarze @@ -26,6 +26,7 @@ #include #include "mandoc.h" +#include "roff.h" #include "eqn.h" #include "out.h" #include "html.h" diff --git a/html.c b/html.c index 1302972a4e13..9c45d3162eaf 100644 --- a/html.c +++ b/html.c @@ -1,4 +1,4 @@ -/* $Id: html.c,v 1.254 2019/03/03 13:02:11 schwarze Exp $ */ +/* $Id: html.c,v 1.255 2019/04/30 15:53:00 schwarze Exp $ */ /* * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons * Copyright (c) 2011-2015, 2017-2019 Ingo Schwarze @@ -120,6 +120,7 @@ static void print_ctag(struct html *, struct tag *); static int print_escape(struct html *, char); static int print_encode(struct html *, const char *, const char *, int); static void print_href(struct html *, const char *, const char *, int); +static void print_metaf(struct html *); void * @@ -222,55 +223,49 @@ print_gen_head(struct html *h) print_tagq(h, t); } -void -print_metaf(struct html *h, enum mandoc_esc deco) +int +html_setfont(struct html *h, enum mandoc_esc font) { - enum htmlfont font; - - switch (deco) { + switch (font) { case ESCAPE_FONTPREV: font = h->metal; break; case ESCAPE_FONTITALIC: - font = HTMLFONT_ITALIC; - break; case ESCAPE_FONTBOLD: - font = HTMLFONT_BOLD; - break; case ESCAPE_FONTBI: - font = HTMLFONT_BI; - break; case ESCAPE_FONTCW: - font = HTMLFONT_CW; + case ESCAPE_FONTROMAN: break; case ESCAPE_FONT: - case ESCAPE_FONTROMAN: - font = HTMLFONT_NONE; + font = ESCAPE_FONTROMAN; break; default: - return; + return 0; } + h->metal = h->metac; + h->metac = font; + return 1; +} +static void +print_metaf(struct html *h) +{ if (h->metaf) { print_tagq(h, h->metaf); h->metaf = NULL; } - - h->metal = h->metac; - h->metac = font; - - switch (font) { - case HTMLFONT_ITALIC: + switch (h->metac) { + case ESCAPE_FONTITALIC: h->metaf = print_otag(h, TAG_I, ""); break; - case HTMLFONT_BOLD: + case ESCAPE_FONTBOLD: h->metaf = print_otag(h, TAG_B, ""); break; - case HTMLFONT_BI: + case ESCAPE_FONTBI: h->metaf = print_otag(h, TAG_B, ""); print_otag(h, TAG_I, ""); break; - case HTMLFONT_CW: + case ESCAPE_FONTCW: h->metaf = print_otag(h, TAG_SPAN, "c", "Li"); break; default: @@ -479,7 +474,8 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse) case ESCAPE_FONTROMAN: if (0 == norecurse) { h->flags |= HTML_NOSPACE; - print_metaf(h, esc); + if (html_setfont(h, esc)) + print_metaf(h); h->flags &= ~HTML_NOSPACE; } continue; @@ -806,27 +802,9 @@ print_text(struct html *h, const char *word) print_word(h, " "); } - assert(NULL == h->metaf); - switch (h->metac) { - case HTMLFONT_ITALIC: - h->metaf = print_otag(h, TAG_I, ""); - break; - case HTMLFONT_BOLD: - h->metaf = print_otag(h, TAG_B, ""); - break; - case HTMLFONT_BI: - h->metaf = print_otag(h, TAG_B, ""); - print_otag(h, TAG_I, ""); - break; - case HTMLFONT_CW: - h->metaf = print_otag(h, TAG_SPAN, "c", "Li"); - break; - default: - print_indent(h); - break; - } - - assert(word); + assert(h->metaf == NULL); + print_metaf(h); + print_indent(h); if ( ! print_encode(h, word, NULL, 0)) { if ( ! (h->flags & HTML_NONOSPACE)) h->flags &= ~HTML_NOSPACE; @@ -834,7 +812,7 @@ print_text(struct html *h, const char *word) } else h->flags |= HTML_NOSPACE | HTML_NONEWLINE; - if (h->metaf) { + if (h->metaf != NULL) { print_tagq(h, h->metaf); h->metaf = NULL; } diff --git a/html.h b/html.h index a6bf89119057..242a63a8d624 100644 --- a/html.h +++ b/html.h @@ -1,4 +1,4 @@ -/* $Id: html.h,v 1.102 2019/03/01 10:57:18 schwarze Exp $ */ +/* $Id: html.h,v 1.103 2019/04/30 15:53:00 schwarze Exp $ */ /* * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons * Copyright (c) 2017, 2018, 2019 Ingo Schwarze @@ -69,15 +69,6 @@ enum htmltag { TAG_MAX }; -enum htmlfont { - HTMLFONT_NONE = 0, - HTMLFONT_BOLD, - HTMLFONT_ITALIC, - HTMLFONT_BI, - HTMLFONT_CW, - HTMLFONT_MAX -}; - struct tag { struct tag *next; int refcnt; @@ -111,8 +102,8 @@ struct html { char *base_includes; /* base for include href */ char *style; /* style-sheet URI */ struct tag *metaf; /* current open font scope */ - enum htmlfont metal; /* last used font */ - enum htmlfont metac; /* current font mode */ + enum mandoc_esc metal; /* last used font */ + enum mandoc_esc metac; /* current font mode */ int oflags; /* output options */ #define HTML_FRAGMENT (1 << 0) /* don't emit HTML/HEAD/BODY */ #define HTML_TOC (1 << 1) /* emit a table of contents */ @@ -128,7 +119,6 @@ void roff_html_pre(struct html *, const struct roff_node *); void print_gen_comment(struct html *, struct roff_node *); void print_gen_decls(struct html *); void print_gen_head(struct html *); -void print_metaf(struct html *, enum mandoc_esc); struct tag *print_otag(struct html *, enum htmltag, const char *, ...); void print_tagq(struct html *, const struct tag *); void print_stagq(struct html *, const struct tag *); @@ -141,3 +131,4 @@ void print_endline(struct html *); void html_close_paragraph(struct html *); enum roff_tok html_fillmode(struct html *, enum roff_tok); char *html_make_id(const struct roff_node *, int); +int html_setfont(struct html *, enum mandoc_esc); diff --git a/lib.in b/lib.in index b8dd87eb99f8..a01f79e1ac48 100644 --- a/lib.in +++ b/lib.in @@ -1,4 +1,4 @@ -/* $Id: lib.in,v 1.21 2019/03/04 17:35:21 schwarze Exp $ */ +/* $Id: lib.in,v 1.22 2019/07/01 22:56:24 schwarze Exp $ */ /* * Copyright (c) 2009 Kristaps Dzonsons * Copyright (c) 2009, 2012 Joerg Sonnenberger @@ -43,7 +43,7 @@ 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("libcuse", "Userland Character Device Library (libcuse, \\-lcuse)") +LINE("libcuse", "Userland Character Device Library (libcuse, \\-lcuse)") LINE("libdevattr", "Device attribute and event library (libdevattr, \\-ldevattr)") LINE("libdevctl", "Device Control Library (libdevctl, \\-ldevctl)") LINE("libdevinfo", "Device and Resource Information Utility Library (libdevinfo, \\-ldevinfo)") diff --git a/libroff.h b/libroff.h deleted file mode 100644 index b6a026d820b3..000000000000 --- a/libroff.h +++ /dev/null @@ -1,80 +0,0 @@ -/* $Id: libroff.h,v 1.42 2017/07/08 17:52:49 schwarze Exp $ */ -/* - * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2014, 2015, 2017 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. - */ - -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_node *next; -}; - -struct eqn_node { - struct mparse *parse; /* main parser, for error reporting */ - struct roff_node *node; /* syntax tree of this equation */ - struct eqn_def *defs; /* array of definitions */ - char *data; /* source code of this equation */ - char *start; /* first byte of the current token */ - char *end; /* first byte of the next token */ - size_t defsz; /* number of definitions */ - size_t sz; /* length of the source code */ - size_t toksz; /* length of the current token */ - int gsize; /* default point size */ - int delim; /* in-line delimiters enabled */ - char odelim; /* in-line opening delimiter */ - char cdelim; /* in-line closing delimiter */ -}; - -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 *); -void tbl_read(struct tbl_node *, int, const char *, int); -void tbl_option(struct tbl_node *, int, const char *, int *); -void tbl_layout(struct tbl_node *, int, const char *, int); -void tbl_data(struct tbl_node *, int, const char *, int); -void tbl_cdata(struct tbl_node *, int, const char *, int); -const struct tbl_span *tbl_span(struct tbl_node *); -int tbl_end(struct tbl_node *); -struct eqn_node *eqn_alloc(struct mparse *); -void eqn_box_free(struct eqn_box *); -void eqn_free(struct eqn_node *); -void eqn_parse(struct eqn_node *); -void eqn_read(struct eqn_node *, const char *); -void eqn_reset(struct eqn_node *); diff --git a/main.c b/main.c index b91c15860ab1..b11f7b51c164 100644 --- a/main.c +++ b/main.c @@ -1,4 +1,4 @@ -/* $Id: main.c,v 1.322 2019/03/06 10:18:58 schwarze Exp $ */ +/* $Id: main.c,v 1.332 2019/07/19 20:27:25 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons * Copyright (c) 2010-2012, 2014-2019 Ingo Schwarze @@ -21,6 +21,7 @@ #include #include #include /* MACHINE */ +#include #include #include @@ -97,13 +98,10 @@ static int fs_lookup(const struct manpaths *, static int fs_search(const struct mansearch *, const struct manpaths *, int, char**, struct manpage **, size_t *); -static int koptions(int *, char *); -static void moptions(int *, char *); static void outdata_alloc(struct curparse *); static void parse(struct curparse *, int, const char *); -static void passthrough(const char *, int, int); +static void passthrough(int, int); static pid_t spawn_pager(struct tag_files *); -static int toptions(struct curparse *, char *); static void usage(enum argmode) __attribute__((__noreturn__)); static int woptions(struct curparse *, char *); @@ -125,7 +123,7 @@ main(int argc, char *argv[]) char *conf_file, *defpaths, *auxpaths; char *oarg, *tagarg; unsigned char *uc; - size_t i, sz; + size_t i, sz, ssz; int prio, best_prio; enum outmode outmode; int fd, startdir; @@ -154,10 +152,11 @@ main(int argc, char *argv[]) return mandocdb(argc, argv); #if HAVE_PLEDGE - if (pledge("stdio rpath tmppath tty proc exec", NULL) == -1) - err((int)MANDOCLEVEL_SYSERR, "pledge"); + if (pledge("stdio rpath tmppath tty proc exec", NULL) == -1) { + mandoc_msg(MANDOCERR_PLEDGE, 0, 0, "%s", strerror(errno)); + return mandoc_msg_getrc(); + } #endif - #if HAVE_SANDBOX_INIT if (sandbox_init(kSBXProfileNoInternet, SANDBOX_NAMED, NULL) == -1) errx((int)MANDOCLEVEL_SYSERR, "sandbox_init"); @@ -221,19 +220,29 @@ main(int argc, char *argv[]) outmode = OUTMODE_ALL; break; case 'I': - if (strncmp(optarg, "os=", 3)) { - warnx("-I %s: Bad argument", optarg); - return (int)MANDOCLEVEL_BADARG; + if (strncmp(optarg, "os=", 3) != 0) { + mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0, + "-I %s", optarg); + return mandoc_msg_getrc(); } if (curp.os_s != NULL) { - warnx("-I %s: Duplicate argument", optarg); - return (int)MANDOCLEVEL_BADARG; + mandoc_msg(MANDOCERR_BADARG_DUPE, 0, 0, + "-I %s", optarg); + return mandoc_msg_getrc(); } curp.os_s = mandoc_strdup(optarg + 3); break; case 'K': - if ( ! koptions(&options, optarg)) - return (int)MANDOCLEVEL_BADARG; + options &= ~(MPARSE_UTF8 | MPARSE_LATIN1); + if (strcmp(optarg, "utf-8") == 0) + options |= MPARSE_UTF8; + else if (strcmp(optarg, "iso-8859-1") == 0) + options |= MPARSE_LATIN1; + else if (strcmp(optarg, "us-ascii") != 0) { + mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0, + "-K %s", optarg); + return mandoc_msg_getrc(); + } break; case 'k': search.argmode = ARG_EXPR; @@ -258,12 +267,37 @@ main(int argc, char *argv[]) search.sec = optarg; break; case 'T': - if ( ! toptions(&curp, optarg)) - return (int)MANDOCLEVEL_BADARG; + if (strcmp(optarg, "ascii") == 0) + curp.outtype = OUTT_ASCII; + else if (strcmp(optarg, "lint") == 0) { + curp.outtype = OUTT_LINT; + mandoc_msg_setoutfile(stdout); + mandoc_msg_setmin(MANDOCERR_BASE); + } else if (strcmp(optarg, "tree") == 0) + curp.outtype = OUTT_TREE; + else if (strcmp(optarg, "man") == 0) + curp.outtype = OUTT_MAN; + else if (strcmp(optarg, "html") == 0) + curp.outtype = OUTT_HTML; + else if (strcmp(optarg, "markdown") == 0) + curp.outtype = OUTT_MARKDOWN; + else if (strcmp(optarg, "utf8") == 0) + curp.outtype = OUTT_UTF8; + else if (strcmp(optarg, "locale") == 0) + curp.outtype = OUTT_LOCALE; + else if (strcmp(optarg, "ps") == 0) + curp.outtype = OUTT_PS; + else if (strcmp(optarg, "pdf") == 0) + curp.outtype = OUTT_PDF; + else { + mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0, + "-T %s", optarg); + return mandoc_msg_getrc(); + } break; case 'W': - if ( ! woptions(&curp, optarg)) - return (int)MANDOCLEVEL_BADARG; + if (woptions(&curp, optarg) == -1) + return mandoc_msg_getrc(); break; case 'w': outmode = OUTMODE_FLN; @@ -299,12 +333,9 @@ main(int argc, char *argv[]) search.outkey = oarg; else { while (oarg != NULL) { - thisarg = oarg; if (manconf_output(&conf.output, - strsep(&oarg, ","), 0) == 0) - continue; - warnx("-O %s: Bad argument", thisarg); - return (int)MANDOCLEVEL_BADARG; + strsep(&oarg, ","), 0) == -1) + return mandoc_msg_getrc(); } } } @@ -328,9 +359,13 @@ main(int argc, char *argv[]) } #if HAVE_PLEDGE - if (!use_pager) - if (pledge("stdio rpath", NULL) == -1) - err((int)MANDOCLEVEL_SYSERR, "pledge"); + if (use_pager == 0) { + if (pledge("stdio rpath", NULL) == -1) { + mandoc_msg(MANDOCERR_PLEDGE, 0, 0, + "%s", strerror(errno)); + return mandoc_msg_getrc(); + } + } #endif /* Parse arguments. */ @@ -355,7 +390,7 @@ main(int argc, char *argv[]) } else if (argc > 1 && ((uc = (unsigned char *)argv[0]) != NULL) && ((isdigit(uc[0]) && (uc[1] == '\0' || - (isalpha(uc[1]) && uc[2] == '\0'))) || + isalpha(uc[1]))) || (uc[0] == 'n' && uc[1] == '\0'))) { search.sec = (char *)uc; argv++; @@ -395,7 +430,7 @@ main(int argc, char *argv[]) usage(search.argmode); if (sz == 0 && search.argmode == ARG_NAME) - fs_search(&search, &conf.manpath, + (void)fs_search(&search, &conf.manpath, argc, argv, &res, &sz); if (search.argmode == ARG_NAME) { @@ -403,7 +438,10 @@ main(int argc, char *argv[]) if (strchr(argv[c], '/') == NULL) continue; if (access(argv[c], R_OK) == -1) { - warn("%s", argv[c]); + mandoc_msg_setinfilename(argv[c]); + mandoc_msg(MANDOCERR_BADARG_BAD, + 0, 0, "%s", strerror(errno)); + mandoc_msg_setinfilename(NULL); continue; } res = mandoc_reallocarray(res, @@ -411,6 +449,7 @@ main(int argc, char *argv[]) res[sz].file = mandoc_strdup(argv[c]); res[sz].names = NULL; res[sz].output = NULL; + res[sz].bits = 0; res[sz].ipath = SIZE_MAX; res[sz].sec = 10; res[sz].form = FORM_SRC; @@ -433,7 +472,7 @@ main(int argc, char *argv[]) if (outmode == OUTMODE_ONE) { argc = 1; - best_prio = 20; + best_prio = 40; } else if (outmode == OUTMODE_ALL) argc = (int)sz; @@ -452,10 +491,21 @@ main(int argc, char *argv[]) sec = res[i].file; sec += strcspn(sec, "123456789"); if (sec[0] == '\0') - continue; + continue; /* No section at all. */ prio = sec_prios[sec[0] - '1']; - if (sec[1] != '/') - prio += 10; + if (search.sec != NULL) { + ssz = strlen(search.sec); + if (strncmp(sec, search.sec, ssz) == 0) + sec += ssz; + } else + sec++; /* Prefer without suffix. */ + if (*sec != '/') + prio += 10; /* Wrong dir name. */ + if (search.sec != NULL && + (strlen(sec) <= ssz + 3 || + strcmp(sec + strlen(sec) - ssz, + search.sec) != 0)) + prio += 20; /* Wrong file ext. */ if (prio >= best_prio) continue; best_prio = prio; @@ -477,16 +527,26 @@ main(int argc, char *argv[]) #if HAVE_PLEDGE if (use_pager) { - if (pledge("stdio rpath tmppath tty proc exec", NULL) == -1) - err((int)MANDOCLEVEL_SYSERR, "pledge"); + if (pledge("stdio rpath tmppath tty proc exec", NULL) == -1) { + mandoc_msg(MANDOCERR_PLEDGE, 0, 0, + "%s", strerror(errno)); + return mandoc_msg_getrc(); + } } else { - if (pledge("stdio rpath", NULL) == -1) - err((int)MANDOCLEVEL_SYSERR, "pledge"); + if (pledge("stdio rpath", NULL) == -1) { + mandoc_msg(MANDOCERR_PLEDGE, 0, 0, + "%s", strerror(errno)); + return mandoc_msg_getrc(); + } } #endif - if (search.argmode == ARG_FILE) - moptions(&options, auxpaths); + if (search.argmode == ARG_FILE && auxpaths != NULL) { + if (strcmp(auxpaths, "doc") == 0) + options |= MPARSE_MDOC; + else if (strcmp(auxpaths, "an") == 0) + options |= MPARSE_MAN; + } mchars_alloc(); curp.mp = mparse_alloc(options, curp.os_e, curp.os_s); @@ -494,7 +554,8 @@ main(int argc, char *argv[]) if (argc < 1) { if (use_pager) { tag_files = tag_init(); - tag_files->tagname = conf.output.tag; + if (tag_files != NULL) + tag_files->tagname = conf.output.tag; } thisarg = ""; mandoc_msg_setinfilename(thisarg); @@ -527,30 +588,31 @@ main(int argc, char *argv[]) } else thisarg = *argv; + mandoc_msg_setinfilename(thisarg); fd = mparse_open(curp.mp, thisarg); if (fd != -1) { if (use_pager) { use_pager = 0; tag_files = tag_init(); - tag_files->tagname = conf.output.tag; + if (tag_files != NULL) + tag_files->tagname = conf.output.tag; } - mandoc_msg_setinfilename(thisarg); if (resp == NULL || resp->form == FORM_SRC) parse(&curp, fd, thisarg); else - passthrough(resp->file, fd, - conf.output.synopsisonly); - mandoc_msg_setinfilename(NULL); + passthrough(fd, conf.output.synopsisonly); if (ferror(stdout)) { if (tag_files != NULL) { - warn("%s", tag_files->ofn); + mandoc_msg(MANDOCERR_WRITE, 0, 0, + "%s: %s", tag_files->ofn, + strerror(errno)); tag_unlink(); tag_files = NULL; } else - warn("stdout"); - mandoc_msg_setrc(MANDOCLEVEL_SYSERR); + mandoc_msg(MANDOCERR_WRITE, 0, 0, + "%s", strerror(errno)); break; } @@ -560,8 +622,10 @@ main(int argc, char *argv[]) terminal_sepline(curp.outdata); } } else - mandoc_msg(MANDOCERR_FILE, 0, 0, - "%s: %s", thisarg, strerror(errno)); + mandoc_msg(resp == NULL ? MANDOCERR_BADARG_BAD : + MANDOCERR_OPEN, 0, 0, "%s", strerror(errno)); + + mandoc_msg_setinfilename(NULL); if (curp.wstop && mandoc_msg_getrc() != MANDOCLEVEL_OK) break; @@ -653,8 +717,8 @@ out: continue; if (pid == -1) { - warn("wait"); - mandoc_msg_setrc(MANDOCLEVEL_SYSERR); + mandoc_msg(MANDOCERR_WAIT, 0, 0, + "%s", strerror(errno)); break; } if (!WIFSTOPPED(status)) @@ -663,14 +727,16 @@ out: signum = WSTOPSIG(status); } tag_unlink(); - } + } else if (curp.outtype != OUTT_LINT && + (search.argmode == ARG_FILE || sz > 0)) + mandoc_msg_summary(); + return (int)mandoc_msg_getrc(); } static void usage(enum argmode argmode) { - switch (argmode) { case ARG_FILE: fputs("usage: mandoc [-ac] [-I os=name] " @@ -701,6 +767,7 @@ fs_lookup(const struct manpaths *paths, size_t ipath, const char *sec, const char *arch, const char *name, struct manpage **res, size_t *ressz) { + struct stat sb; glob_t globinfo; struct manpage *page; char *file; @@ -710,13 +777,13 @@ fs_lookup(const struct manpaths *paths, size_t ipath, form = FORM_SRC; mandoc_asprintf(&file, "%s/man%s/%s.%s", paths->paths[ipath], sec, name, sec); - if (access(file, R_OK) != -1) + if (stat(file, &sb) != -1) goto found; free(file); mandoc_asprintf(&file, "%s/cat%s/%s.0", paths->paths[ipath], sec, name); - if (access(file, R_OK) != -1) { + if (stat(file, &sb) != -1) { form = FORM_CAT; goto found; } @@ -725,7 +792,7 @@ fs_lookup(const struct manpaths *paths, size_t ipath, if (arch != NULL) { mandoc_asprintf(&file, "%s/man%s/%s/%s.%s", paths->paths[ipath], sec, arch, name, sec); - if (access(file, R_OK) != -1) + if (stat(file, &sb) != -1) goto found; free(file); } @@ -734,37 +801,42 @@ fs_lookup(const struct manpaths *paths, size_t ipath, paths->paths[ipath], sec, name); globres = glob(file, 0, NULL, &globinfo); if (globres != 0 && globres != GLOB_NOMATCH) - warn("%s: glob", file); + mandoc_msg(MANDOCERR_GLOB, 0, 0, + "%s: %s", file, strerror(errno)); free(file); if (globres == 0) file = mandoc_strdup(*globinfo.gl_pathv); globfree(&globinfo); - if (globres == 0) - goto found; + if (globres == 0) { + if (stat(file, &sb) != -1) + goto found; + free(file); + } if (res != NULL || ipath + 1 != paths->sz) - return 0; + return -1; mandoc_asprintf(&file, "%s.%s", name, sec); - globres = access(file, R_OK); + globres = stat(file, &sb); free(file); - return globres != -1; + return globres; found: warnx("outdated mandoc.db lacks %s(%s) entry, run %s %s", name, sec, BINM_MAKEWHATIS, paths->paths[ipath]); if (res == NULL) { free(file); - return 1; + return 0; } - *res = mandoc_reallocarray(*res, ++*ressz, sizeof(struct manpage)); + *res = mandoc_reallocarray(*res, ++*ressz, sizeof(**res)); page = *res + (*ressz - 1); page->file = file; page->names = NULL; page->output = NULL; + page->bits = NAME_FILE & NAME_MASK; page->ipath = ipath; page->sec = (*sec >= '1' && *sec <= '9') ? *sec - '1' + 1 : 10; page->form = form; - return 1; + return 0; } static int @@ -786,14 +858,14 @@ fs_search(const struct mansearch *cfg, const struct manpaths *paths, for (ipath = 0; ipath < paths->sz; ipath++) { if (cfg->sec != NULL) { if (fs_lookup(paths, ipath, cfg->sec, - cfg->arch, *argv, res, ressz) && + cfg->arch, *argv, res, ressz) != -1 && cfg->firstmatch) - return 1; + return 0; } else for (isec = 0; isec < nsec; isec++) if (fs_lookup(paths, ipath, sections[isec], - cfg->arch, *argv, res, ressz) && + cfg->arch, *argv, res, ressz) != -1 && cfg->firstmatch) - return 1; + return 0; } if (res != NULL && *ressz == lastsz && strchr(*argv, '/') == NULL) { @@ -812,7 +884,7 @@ fs_search(const struct mansearch *cfg, const struct manpaths *paths, argv++; argc--; } - return 0; + return -1; } static void @@ -919,7 +991,7 @@ check_xr(void) search.firstmatch = 1; if (mansearch(&search, &paths, 1, &xr->name, NULL, &sz)) continue; - if (fs_search(&search, &paths, 1, &xr->name, NULL, &sz)) + if (fs_search(&search, &paths, 1, &xr->name, NULL, &sz) != -1) continue; if (xr->count == 1) mandoc_msg(MANDOCERR_XR_BAD, xr->line, @@ -959,34 +1031,34 @@ outdata_alloc(struct curparse *curp) } static void -passthrough(const char *file, int fd, int synopsis_only) +passthrough(int fd, int synopsis_only) { const char synb[] = "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS"; const char synr[] = "SYNOPSIS"; FILE *stream; - const char *syscall; char *line, *cp; size_t linesz; ssize_t len, written; - int print; + int lno, print; + stream = NULL; line = NULL; linesz = 0; if (fflush(stdout) == EOF) { - syscall = "fflush"; - goto fail; + mandoc_msg(MANDOCERR_FFLUSH, 0, 0, "%s", strerror(errno)); + goto done; } - if ((stream = fdopen(fd, "r")) == NULL) { close(fd); - syscall = "fdopen"; - goto fail; + mandoc_msg(MANDOCERR_FDOPEN, 0, 0, "%s", strerror(errno)); + goto done; } - print = 0; + lno = print = 0; while ((len = getline(&line, &linesz, stream)) != -1) { + lno++; cp = line; if (synopsis_only) { if (print) { @@ -1004,94 +1076,20 @@ passthrough(const char *file, int fd, int synopsis_only) } } for (; len > 0; len -= written) { - if ((written = write(STDOUT_FILENO, cp, len)) != -1) - continue; - fclose(stream); - syscall = "write"; - goto fail; + if ((written = write(STDOUT_FILENO, cp, len)) == -1) { + mandoc_msg(MANDOCERR_WRITE, 0, 0, + "%s", strerror(errno)); + goto done; + } } } - - if (ferror(stream)) { - fclose(stream); - syscall = "getline"; - goto fail; - } + if (ferror(stream)) + mandoc_msg(MANDOCERR_GETLINE, lno, 0, "%s", strerror(errno)); done: free(line); - fclose(stream); - return; - -fail: - free(line); - warn("%s: SYSERR: %s", file, syscall); - mandoc_msg_setrc(MANDOCLEVEL_SYSERR); -} - -static int -koptions(int *options, char *arg) -{ - - if ( ! strcmp(arg, "utf-8")) { - *options |= MPARSE_UTF8; - *options &= ~MPARSE_LATIN1; - } else if ( ! strcmp(arg, "iso-8859-1")) { - *options |= MPARSE_LATIN1; - *options &= ~MPARSE_UTF8; - } else if ( ! strcmp(arg, "us-ascii")) { - *options &= ~(MPARSE_UTF8 | MPARSE_LATIN1); - } else { - warnx("-K %s: Bad argument", arg); - return 0; - } - return 1; -} - -static void -moptions(int *options, char *arg) -{ - - if (arg == NULL) - return; - if (strcmp(arg, "doc") == 0) - *options |= MPARSE_MDOC; - else if (strcmp(arg, "an") == 0) - *options |= MPARSE_MAN; -} - -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; - mandoc_msg_setoutfile(stdout); - mandoc_msg_setmin(MANDOCERR_BASE); - } 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, "markdown")) - curp->outtype = OUTT_MARKDOWN; - 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, "ps")) - curp->outtype = OUTT_PS; - else if (0 == strcmp(arg, "pdf")) - curp->outtype = OUTT_PDF; - else { - warnx("-T %s: Bad argument", arg); - return 0; - } - - return 1; + if (stream != NULL) + fclose(stream); } static int @@ -1135,7 +1133,7 @@ woptions(struct curparse *curp, char *arg) mandoc_msg_setmin(MANDOCERR_UNSUPP); break; case 7: - mandoc_msg_setmin(MANDOCERR_MAX); + mandoc_msg_setmin(MANDOCERR_BADARG); break; case 8: mandoc_msg_setmin(MANDOCERR_BASE); @@ -1146,11 +1144,11 @@ woptions(struct curparse *curp, char *arg) curp->os_e = MANDOC_OS_NETBSD; break; default: - warnx("-W %s: Bad argument", o); - return 0; + mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0, "-W %s", o); + return -1; } } - return 1; + return 0; } static pid_t @@ -1196,7 +1194,7 @@ spawn_pager(struct tag_files *tag_files) use_ofn = 1; #if HAVE_LESS_T - if ((cmdlen = strlen(argv[0])) >= 4) { + if (*tag_files->tfn != '\0' && (cmdlen = strlen(argv[0])) >= 4) { cp = argv[0] + cmdlen - 4; if (strcmp(cp, "less") == 0) { argv[argc++] = mandoc_strdup("-T"); @@ -1215,15 +1213,19 @@ spawn_pager(struct tag_files *tag_files) switch (pager_pid = fork()) { case -1: - err((int)MANDOCLEVEL_SYSERR, "fork"); + mandoc_msg(MANDOCERR_FORK, 0, 0, "%s", strerror(errno)); + exit(mandoc_msg_getrc()); case 0: break; default: (void)setpgid(pager_pid, 0); (void)tcsetpgrp(tag_files->ofd, pager_pid); #if HAVE_PLEDGE - if (pledge("stdio rpath tmppath tty proc", NULL) == -1) - err((int)MANDOCLEVEL_SYSERR, "pledge"); + if (pledge("stdio rpath tmppath tty proc", NULL) == -1) { + mandoc_msg(MANDOCERR_PLEDGE, 0, 0, + "%s", strerror(errno)); + exit(mandoc_msg_getrc()); + } #endif tag_files->pager_pid = pager_pid; return pager_pid; @@ -1231,8 +1233,10 @@ spawn_pager(struct tag_files *tag_files) /* The child process becomes the pager. */ - if (dup2(tag_files->ofd, STDOUT_FILENO) == -1) - err((int)MANDOCLEVEL_SYSERR, "pager stdout"); + if (dup2(tag_files->ofd, STDOUT_FILENO) == -1) { + mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno)); + _exit(mandoc_msg_getrc()); + } close(tag_files->ofd); assert(tag_files->tfd == -1); @@ -1242,5 +1246,6 @@ spawn_pager(struct tag_files *tag_files) nanosleep(&timeout, NULL); execvp(argv[0], argv); - err((int)MANDOCLEVEL_SYSERR, "exec %s", argv[0]); + mandoc_msg(MANDOCERR_EXEC, 0, 0, "%s: %s", argv[0], strerror(errno)); + _exit(mandoc_msg_getrc()); } diff --git a/man.7 b/man.7 index 7706b5ca23df..6b4bece71433 100644 --- a/man.7 +++ b/man.7 @@ -1,4 +1,4 @@ -.\" $Id: man.7,v 1.143 2019/03/02 22:04:40 schwarze Exp $ +.\" $Id: man.7,v 1.144 2019/07/09 03:46:59 schwarze Exp $ .\" .\" Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons .\" Copyright (c) 2011-2015,2017,2018,2019 Ingo Schwarze @@ -17,7 +17,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: March 2 2019 $ +.Dd $Mdocdate: July 9 2019 $ .Dt MAN 7 .Os .Sh NAME @@ -160,7 +160,9 @@ This has no effect unless the tabulator positions were changed with the .Ic ta request. .It Ic EE -This is a non-standard GNU extension. +This is a non-standard Version 9 +.At +extension later adopted by GNU. In .Xr mandoc 1 , it does the same as the @@ -168,7 +170,9 @@ it does the same as the .Ic fi request (switch to fill mode). .It Ic EX -This is a non-standard GNU extension. +This is a non-standard Version 9 +.At +extension later adopted by GNU. In .Xr mandoc 1 , it does the same as the @@ -496,8 +500,8 @@ The syntax is as follows: .It Ic BI Ta n Ta current Ta \& .It Ic BR Ta n Ta current Ta \& .It Ic DT Ta 0 Ta current Ta \& -.It Ic EE Ta 0 Ta current Ta GNU -.It Ic EX Ta 0 Ta current Ta GNU +.It Ic EE Ta 0 Ta current Ta Version 9 At +.It Ic EX Ta 0 Ta current Ta Version 9 At .It Ic I Ta n Ta next-line Ta \& .It Ic IB Ta n Ta current Ta \& .It Ic IR Ta n Ta current Ta \& diff --git a/man_html.c b/man_html.c index 994a208aa0ee..c0a429c5d6c9 100644 --- a/man_html.c +++ b/man_html.c @@ -1,4 +1,4 @@ -/* $Id: man_html.c,v 1.173 2019/03/02 16:30:53 schwarze Exp $ */ +/* $Id: man_html.c,v 1.174 2019/04/30 15:53:00 schwarze Exp $ */ /* * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons * Copyright (c) 2013-2015, 2017-2019 Ingo Schwarze @@ -203,9 +203,9 @@ print_man_node(MAN_ARGS) * Close out scope of font prior to opening a macro * scope. */ - if (HTMLFONT_NONE != h->metac) { + if (h->metac != ESCAPE_FONTROMAN) { h->metal = h->metac; - h->metac = HTMLFONT_NONE; + h->metac = ESCAPE_FONTROMAN; } /* diff --git a/man_term.c b/man_term.c index d867762dcace..d9ee14ad22ba 100644 --- a/man_term.c +++ b/man_term.c @@ -1,4 +1,4 @@ -/* $Id: man_term.c,v 1.228 2019/01/05 21:18:26 schwarze Exp $ */ +/* $Id: man_term.c,v 1.232 2019/07/23 17:53:35 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons * Copyright (c) 2010-2015, 2017-2019 Ingo Schwarze @@ -27,10 +27,12 @@ #include #include "mandoc_aux.h" +#include "mandoc.h" #include "roff.h" #include "man.h" #include "out.h" #include "term.h" +#include "tag.h" #include "main.h" #define MAXMARGINS 64 /* maximum number of indented scopes */ @@ -92,6 +94,8 @@ static void post_SY(DECL_ARGS); static void post_TP(DECL_ARGS); static void post_UR(DECL_ARGS); +static void tag_man(struct termp *, struct roff_node *); + static const struct man_term_act man_term_acts[MAN_MAX - MAN_TH] = { { NULL, NULL, 0 }, /* TH */ { pre_SH, post_SH, 0 }, /* SH */ @@ -146,7 +150,7 @@ terminal_man(void *arg, const struct roff_meta *man) { struct mtermp mt; struct termp *p; - struct roff_node *n; + struct roff_node *n, *nc, *nn; size_t save_defindent; p = (struct termp *)arg; @@ -165,18 +169,23 @@ terminal_man(void *arg, const struct roff_meta *man) n = man->first->child; if (p->synopsisonly) { - while (n != NULL) { - if (n->tok == MAN_SH && - n->child->child->type == ROFFT_TEXT && - !strcmp(n->child->child->string, "SYNOPSIS")) { - if (n->child->next->child != NULL) - print_man_nodelist(p, &mt, - n->child->next->child, man); - term_newln(p); + for (nn = NULL; n != NULL; n = n->next) { + if (n->tok != MAN_SH) + continue; + nc = n->child->child; + if (nc->type != ROFFT_TEXT) + continue; + if (strcmp(nc->string, "SYNOPSIS") == 0) break; - } - n = n->next; + if (nn == NULL && strcmp(nc->string, "NAME") == 0) + nn = n; } + if (n == NULL) + n = nn; + p->flags |= TERMP_NOSPACE; + if (n != NULL && (n = n->child->next->child) != NULL) + print_man_nodelist(p, &mt, n, man); + term_newln(p); } else { term_begin(p, print_man_head, print_man_foot, man); p->flags |= TERMP_NOSPACE; @@ -310,7 +319,7 @@ pre_alternate(DECL_ARGS) assert(nn->type == ROFFT_TEXT); term_word(p, nn->string); if (nn->flags & NODE_EOS) - p->flags |= TERMP_SENTENCE; + p->flags |= TERMP_SENTENCE; if (nn->next != NULL) p->flags |= TERMP_NOSPACE; } @@ -529,8 +538,10 @@ pre_IP(DECL_ARGS) case ROFFT_HEAD: p->tcol->offset = mt->offset; p->tcol->rmargin = mt->offset + len; - if (n->child != NULL) + if (n->child != NULL) { print_man_node(p, mt, n->child, meta); + tag_man(p, n->child); + } return 0; case ROFFT_BODY: p->tcol->offset = mt->offset + len; @@ -610,6 +621,18 @@ pre_TP(DECL_ARGS) while (nn != NULL && (nn->flags & NODE_LINE) == 0) nn = nn->next; + if (nn == NULL) + return 0; + + if (nn->type == ROFFT_TEXT) + tag_man(p, nn); + else if (nn->child != NULL && + nn->child->type == ROFFT_TEXT && + (nn->tok == MAN_B || nn->tok == MAN_BI || + nn->tok == MAN_BR || nn->tok == MAN_I || + nn->tok == MAN_IB || nn->tok == MAN_IR)) + tag_man(p, nn->child); + while (nn != NULL) { print_man_node(p, mt, nn, meta); nn = nn->next; @@ -1143,3 +1166,60 @@ print_man_head(struct termp *p, const struct roff_meta *meta) } free(title); } + +/* + * Skip leading whitespace, dashes, backslashes, and font escapes, + * then create a tag if the first following byte is a letter. + * Priority is high unless whitespace is present. + */ +static void +tag_man(struct termp *p, struct roff_node *n) +{ + const char *cp, *arg; + int prio, sz; + + assert(n->type == ROFFT_TEXT); + cp = n->string; + prio = 1; + for (;;) { + switch (*cp) { + case ' ': + case '\t': + prio = INT_MAX; + /* FALLTHROUGH */ + case '-': + cp++; + break; + case '\\': + cp++; + switch (mandoc_escape(&cp, &arg, &sz)) { + case ESCAPE_FONT: + case ESCAPE_FONTROMAN: + case ESCAPE_FONTITALIC: + case ESCAPE_FONTBOLD: + case ESCAPE_FONTPREV: + case ESCAPE_FONTBI: + break; + case ESCAPE_SPECIAL: + if (sz != 1) + return; + switch (*arg) { + case '&': + case '-': + case 'e': + break; + default: + return; + } + break; + default: + return; + } + break; + default: + if (isalpha((unsigned char)*cp)) + tag_put(cp, prio, p->line); + return; + } + } +} diff --git a/man_validate.c b/man_validate.c index 4bfaf764e6c8..0aa550bd08d9 100644 --- a/man_validate.c +++ b/man_validate.c @@ -1,4 +1,4 @@ -/* $Id: man_validate.c,v 1.146 2018/12/31 10:04:39 schwarze Exp $ */ +/* $Id: man_validate.c,v 1.149 2019/06/27 15:07:30 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2010, 2012-2018 Ingo Schwarze @@ -41,7 +41,7 @@ typedef void (*v_check)(CHKARGS); -static void check_abort(CHKARGS); +static void check_abort(CHKARGS) __attribute__((__noreturn__)); static void check_par(CHKARGS); static void check_part(CHKARGS); static void check_root(CHKARGS); @@ -185,8 +185,7 @@ check_root(CHKARGS) man->meta.title = mandoc_strdup(""); man->meta.msec = mandoc_strdup(""); - man->meta.date = man->quick ? mandoc_strdup("") : - mandoc_normdate(man, NULL, n->line, n->pos); + man->meta.date = mandoc_normdate(man, NULL, n->line, n->pos); } if (man->meta.os_e && @@ -369,8 +368,8 @@ post_TH(CHKARGS) /* ->TITLE<- MSEC DATE OS VOL */ n = n->child; - if (n && n->string) { - for (p = n->string; '\0' != *p; p++) { + if (n != NULL && n->string != NULL) { + for (p = n->string; *p != '\0'; p++) { /* Only warn about this once... */ if (isalpha((unsigned char)*p) && ! isupper((unsigned char)*p)) { @@ -388,9 +387,9 @@ post_TH(CHKARGS) /* TITLE ->MSEC<- DATE OS VOL */ - if (n) + if (n != NULL) n = n->next; - if (n && n->string) + if (n != NULL && n->string != NULL) man->meta.msec = mandoc_strdup(n->string); else { man->meta.msec = mandoc_strdup(""); @@ -400,17 +399,16 @@ post_TH(CHKARGS) /* TITLE MSEC ->DATE<- OS VOL */ - if (n) + if (n != NULL) n = n->next; - if (n && n->string && '\0' != n->string[0]) { - man->meta.date = man->quick ? - mandoc_strdup(n->string) : - mandoc_normdate(man, n->string, n->line, n->pos); - } else { + if (n != NULL && n->string != NULL && n->string[0] != '\0') + man->meta.date = mandoc_normdate(man, + n->string, n->line, n->pos); + else { man->meta.date = mandoc_strdup(""); mandoc_msg(MANDOCERR_DATE_MISSING, - n ? n->line : nb->line, - n ? n->pos : nb->pos, "TH"); + n == NULL ? nb->line : n->line, + n == NULL ? nb->pos : n->pos, "TH"); } /* TITLE MSEC DATE ->OS<- VOL */ diff --git a/mandoc.1 b/mandoc.1 index 79f6e8500d5c..298d5dc70610 100644 --- a/mandoc.1 +++ b/mandoc.1 @@ -1,7 +1,7 @@ -.\" $Id: mandoc.1,v 1.237 2019/02/23 18:53:54 schwarze Exp $ +.\" $Id: mandoc.1,v 1.240 2019/07/10 19:39:01 schwarze Exp $ .\" .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons -.\" Copyright (c) 2012, 2014-2018 Ingo Schwarze +.\" Copyright (c) 2012, 2014-2019 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 @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: February 23 2019 $ +.Dd $Mdocdate: July 10 2019 $ .Dt MANDOC 1 .Os .Sh NAME @@ -222,7 +222,8 @@ reads from standard input. .Pp The options .Fl fhklw -are also supported and are documented in man(1). +are also supported and are documented in +.Xr man 1 . In .Fl f and @@ -697,7 +698,7 @@ No input files have been read. .It 6 An operating system error occurred, for example exhaustion of memory, file descriptors, or process table entries. -Such errors cause +Such errors may cause .Nm to exit at once, possibly in the middle of parsing or formatting a file. .El @@ -777,6 +778,13 @@ fields. .Pp Message levels have the following meanings: .Bl -tag -width "warning" +.It Cm syserr +An operating system error occurred. +There isn't necessarily anything wrong with the input files. +Output may all the same be missing or incomplete. +.It Cm badarg +Invalid command line arguments were specified. +No input files have been read and no output is produced. .It Cm unsupp An input file uses unsupported low-level .Xr roff 7 @@ -825,8 +833,7 @@ Messages of the .Cm error , and .Cm unsupp -levels except those about non-existent or unreadable input files -are hidden unless their level, or a lower level, is requested using a +levels are hidden unless their level, or a lower level, is requested using a .Fl W option or .Fl T Cm lint @@ -1699,9 +1706,12 @@ 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 +are formatted like .Ic \&sp requests. +To request a paragraph break, use +.Ic \&Pp +instead of a blank line. .It Sy "tab in filled text" .Pq mdoc , man The meaning of tab characters is only well-defined in non-fill mode: @@ -2238,6 +2248,43 @@ macro or of an undefined macro. The macro is ignored, and its arguments are handled as if they were a text line. .El +.Ss Bad command line arguments +.Bl -ohang +.It Sy "bad command line argument" +The argument following one of the +.Fl IKMmOTW +command line options is invalid, or a +.Ar file +given as a command line argument cannot be opened. +.It Sy "duplicate command line argument" +The +.Fl I +command line option was specified twice. +.It Sy "option has a superfluous value" +An argument to the +.Fl O +option has a value but does not accept one. +.It Sy "missing option value" +An argument to the +.Fl O +option has no argument but requires one. +.It Sy "bad option value" +An argument to the +.Fl O +.Cm indent +or +.Cm width +option has an invalid value. +.It Sy "duplicate option value" +The same +.Fl O +option is specified more than once. +.It Sy "no such tag" +The +.Fl O Cm tag +option was specified but the tag was not found in any of the displayed +manual pages. +.El .Sh SEE ALSO .Xr apropos 1 , .Xr man 1 , diff --git a/mandoc.c b/mandoc.c index fb9395a585db..5a2be88e40df 100644 --- a/mandoc.c +++ b/mandoc.c @@ -1,4 +1,4 @@ -/* $Id: mandoc.c,v 1.114 2018/12/30 00:49:55 schwarze Exp $ */ +/* $Id: mandoc.c,v 1.116 2019/06/27 15:07:30 schwarze Exp $ */ /* * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons * Copyright (c) 2011-2015, 2017, 2018 Ingo Schwarze @@ -494,9 +494,10 @@ time2a(time_t t) size_t ssz; int isz; + buf = NULL; tm = localtime(&t); if (tm == NULL) - return NULL; + goto fail; /* * Reserve space: @@ -520,7 +521,8 @@ time2a(time_t t) * of looking at LC_TIME. */ - if ((isz = snprintf(p, 4 + 1, "%d, ", tm->tm_mday)) == -1) + isz = snprintf(p, 4 + 1, "%d, ", tm->tm_mday); + if (isz < 0 || isz > 4) goto fail; p += isz; @@ -530,7 +532,7 @@ time2a(time_t t) fail: free(buf); - return NULL; + return mandoc_strdup(""); } char * @@ -539,12 +541,15 @@ mandoc_normdate(struct roff_man *man, char *in, int ln, int pos) char *cp; time_t t; + if (man->quick) + return mandoc_strdup(in == NULL ? "" : in); + /* No date specified: use today's date. */ - if (in == NULL || *in == '\0' || strcmp(in, "$" "Mdocdate$") == 0) { + if (in == NULL || *in == '\0') mandoc_msg(MANDOCERR_DATE_MISSING, ln, pos, NULL); + if (in == NULL || *in == '\0' || strcmp(in, "$" "Mdocdate$") == 0) return time2a(time(NULL)); - } /* Valid mdoc(7) date format. */ diff --git a/mandoc.css b/mandoc.css index 085f5c08b26d..d75700a28ba7 100644 --- a/mandoc.css +++ b/mandoc.css @@ -1,4 +1,4 @@ -/* $Id: mandoc.css,v 1.45 2019/03/01 10:57:18 schwarze Exp $ */ +/* $Id: mandoc.css,v 1.46 2019/06/02 16:57:13 schwarze Exp $ */ /* * Standard style sheet for mandoc(1) -Thtml and man.cgi(8). * @@ -10,8 +10,13 @@ /* Global defaults. */ -html { max-width: 65em; } -body { font-family: Helvetica,Arial,sans-serif; } +html { max-width: 65em; + --bg: #FFFFFF; + --fg: #000000; } +body { background: var(--bg); + color: var(--fg); + font-family: Helvetica,Arial,sans-serif; } +h1 { font-size: 110%; } table { margin-top: 0em; margin-bottom: 0em; border-collapse: collapse; } @@ -69,8 +74,7 @@ td.foot-os { text-align: right; } section.Sh { } h1.Sh { margin-top: 1.2em; margin-bottom: 0.6em; - margin-left: -3.2em; - font-size: 110%; } + margin-left: -3.2em; } section.Ss { } h2.Ss { margin-top: 1.2em; margin-bottom: 0.6em; @@ -310,14 +314,14 @@ h1.Sh::before, h2.Ss::before, .St::before, .Sx::before, .Sy::before, pointer-events: none; position: absolute; bottom: 100%; - box-shadow: 0 0 .35em #000; + box-shadow: 0 0 .35em var(--fg); padding: .15em .25em; white-space: nowrap; font-family: Helvetica,Arial,sans-serif; font-style: normal; font-weight: bold; - color: black; - background: #fff; } + background: var(--bg); + color: var(--fg); } .An:hover::before, .Ar:hover::before, .Cd:hover::before, .Cm:hover::before, .Dv:hover::before, .Em:hover::before, .Er:hover::before, .Ev:hover::before, .Fa:hover::before, .Fd:hover::before, .Fl:hover::before, .Fn:hover::before, @@ -345,3 +349,12 @@ h1.Sh, h2.Ss { margin-left: 0em; } .HP { margin-left: 2em; text-indent: -2em; } } + +/* Overrides for a dark color scheme for accessibility. */ + +@media (prefers-color-scheme: dark) { +html { --bg: #1E1F21; + --fg: #EEEFF1; } +:link { color: #BAD7FF; } +:visited { color: #F6BAFF; } +} diff --git a/mandoc.h b/mandoc.h index a44b192e0f4f..4a7e7aa749ad 100644 --- a/mandoc.h +++ b/mandoc.h @@ -1,7 +1,7 @@ -/* $Id: mandoc.h,v 1.262 2018/12/16 00:17:02 schwarze Exp $ */ +/* $Id: mandoc.h,v 1.264 2019/07/14 18:16:13 schwarze Exp $ */ /* * Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons - * Copyright (c) 2012-2018 Ingo Schwarze + * Copyright (c) 2012-2019 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 @@ -193,7 +193,6 @@ enum mandocerr { MANDOCERR_TBLDATA_BLK, /* data block open at end of tbl: macro */ /* related to document structure and macros */ - MANDOCERR_FILE, /* cannot open file */ MANDOCERR_PROLOG_REP, /* duplicate prologue macro: macro */ MANDOCERR_DT_LATE, /* skipping late title macro: Dt args */ MANDOCERR_ROFFLOOP, /* input stack limit exceeded, infinite loop? */ @@ -242,6 +241,35 @@ enum mandocerr { MANDOCERR_TBLLAYOUT_MOD, /* unsupported tbl layout modifier: m */ MANDOCERR_TBLMACRO, /* ignoring macro in table: macro */ + MANDOCERR_BADARG, /* ===== start of bad invocations ===== */ + + MANDOCERR_BADARG_BAD, /* bad argument */ + MANDOCERR_BADARG_DUPE, /* duplicate argument */ + MANDOCERR_BADVAL, /* does not take a value */ + MANDOCERR_BADVAL_MISS, /* missing argument value */ + MANDOCERR_BADVAL_BAD, /* bad argument value */ + MANDOCERR_BADVAL_DUPE, /* duplicate argument value */ + MANDOCERR_TAG, /* no such tag */ + + MANDOCERR_SYSERR, /* ===== start of system errors ===== */ + + MANDOCERR_DUP, + MANDOCERR_EXEC, + MANDOCERR_FDOPEN, + MANDOCERR_FFLUSH, + MANDOCERR_FORK, + MANDOCERR_FSTAT, + MANDOCERR_GETLINE, + MANDOCERR_GLOB, + MANDOCERR_GZCLOSE, + MANDOCERR_GZDOPEN, + MANDOCERR_MKSTEMP, + MANDOCERR_OPEN, + MANDOCERR_PLEDGE, + MANDOCERR_READ, + MANDOCERR_WAIT, + MANDOCERR_WRITE, + MANDOCERR_MAX }; @@ -281,6 +309,7 @@ enum mandoclevel mandoc_msg_getrc(void); void mandoc_msg_setrc(enum mandoclevel); void mandoc_msg(enum mandocerr, int, int, const char *, ...) __attribute__((__format__ (__printf__, 4, 5))); +void mandoc_msg_summary(void); void mchars_alloc(void); void mchars_free(void); int mchars_num2char(const char *, size_t); diff --git a/mandoc_char.7 b/mandoc_char.7 index 578f37f180c0..b46575d4d250 100644 --- a/mandoc_char.7 +++ b/mandoc_char.7 @@ -1,4 +1,4 @@ -.\" $Id: mandoc_char.7,v 1.75 2018/12/15 19:30:26 schwarze Exp $ +.\" $Id: mandoc_char.7,v 1.76 2019/03/31 19:17:26 schwarze Exp $ .\" .\" Copyright (c) 2003 Jason McIntyre .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons @@ -16,7 +16,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: December 15 2018 $ +.Dd $Mdocdate: March 31 2019 $ .Dt MANDOC_CHAR 7 .Os .Sh NAME @@ -107,8 +107,8 @@ supporting it, for example in .Fl T Cm utf8 and .Fl T Cm html . -But currently, no practically relevant manual page formatter actually -requires that subtlety, so in manual pages just write plain +But currently, no practically relevant manual page formatter requires +that subtlety, so in manual pages, it is sufficient to write plain .Sq - to represent hyphen, minus, and hyphen-minus. .Pp diff --git a/mandoc_headers.3 b/mandoc_headers.3 index 321384739116..2cda75cba8b3 100644 --- a/mandoc_headers.3 +++ b/mandoc_headers.3 @@ -1,4 +1,20 @@ -.Dd $Mdocdate: December 30 2018 $ +.\" $Id: mandoc_headers.3,v 1.31 2019/03/17 18:21:45 schwarze Exp $ +.\" +.\" Copyright (c) 2014-2019 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: March 17 2019 $ .Dt MANDOC_HEADERS 3 .Os .Sh NAME @@ -129,19 +145,19 @@ and the function Uses pointers to the types .Vt struct ohash from -.Pa mandoc_ohash.h , +.Qq Pa mandoc_ohash.h , .Vt struct mdoc_arg and .Vt union mdoc_data from -.Pa mdoc.h , +.Qq Pa mdoc.h , .Vt struct tbl_span from -.Pa tbl.h , +.Qq Pa tbl.h , and .Vt struct eqn_box from -.Pa eqn.h +.Qq Pa eqn.h as opaque struct members. .It Qq Pa tbl.h Data structures for the @@ -184,13 +200,13 @@ Top level parser interface, for use in the main program and in the main parser, but not in formatters. .Pp Requires -.Pa mandoc.h +.Qq Pa mandoc.h for .Vt enum mandocerr and .Vt enum mandoclevel and -.Pa roff.h +.Qq Pa roff.h for .Vt enum mandoc_os . .Pp @@ -202,7 +218,7 @@ for function prototypes. Uses .Vt struct roff_meta from -.Pa roff.h +.Qq Pa roff.h as an opaque type for function prototypes. .It Qq Pa mandoc_xr.h Cross reference validation; intended for use in the main program @@ -251,11 +267,11 @@ described in Uses the types .Vt struct roff_node from -.Pa roff.h +.Qq Pa roff.h and .Vt struct roff_man from -.Pa roff_int.h +.Qq Pa roff_int.h as opaque types for function prototypes. .Pp When this header is included, the same file should not include @@ -269,7 +285,7 @@ described in Uses the type .Vt struct roff_man from -.Pa roff.h +.Qq Pa roff.h as an opaque type for function prototypes. .Pp When this header is included, the same file should not include @@ -305,7 +321,7 @@ for function prototypes. Uses the type .Vt struct roff_man from -.Pa roff.h +.Qq Pa roff.h as an opaque type for function prototypes. .It Qq Pa roff_int.h Parser internals shared by multiple parsers. @@ -334,24 +350,24 @@ and the two special functions and .Fn mdoc_argv_free because the latter two are needed by -.Qq Pa roff.c . +.Pa roff.c . .Pp Uses the types .Vt struct ohash from -.Pa mandoc_ohash.h , +.Qq Pa mandoc_ohash.h , .Vt struct roff_node and .Vt struct roff_meta from -.Pa roff.h , +.Qq Pa roff.h , .Vt struct roff from .Pa roff.c , and .Vt struct mdoc_arg from -.Pa mdoc.h +.Qq Pa mdoc.h as opaque types for function prototypes. .It Qq Pa libmdoc.h Requires @@ -372,14 +388,14 @@ parser. Uses the types .Vt struct roff_node from -.Pa roff.h , +.Qq Pa roff.h , .Vt struct roff_man from -.Pa roff_int.h , +.Qq Pa roff_int.h , and .Vt struct mdoc_arg from -.Pa mdoc.h +.Qq Pa mdoc.h as opaque types for function prototypes. .Pp When this header is included, the same file should not include @@ -399,11 +415,11 @@ parser. Uses the types .Vt struct roff_node from -.Pa roff.h +.Qq Pa roff.h and .Vt struct roff_man from -.Pa roff_int.h +.Qq Pa roff_int.h as opaque types for function prototypes. .Pp When this header is included, the same file should not include @@ -437,12 +453,12 @@ and Uses the type .Vt struct eqn_box from -.Pa mandoc.h +.Qq Pa mandoc.h as an opaque type for function prototypes. Uses the types .Vt struct roff_node from -.Pa roff.h +.Qq Pa roff.h and .Vt struct eqn_def from @@ -466,11 +482,11 @@ Provides the functions documented in Uses the types .Vt struct tbl_span from -.Pa tbl.h +.Qq Pa tbl.h and .Vt struct tbl_node from -.Pa tbl_int.h +.Qq Pa tbl_int.h as opaque types for function prototypes. .Pp When this header is included, the same file should not include @@ -523,11 +539,11 @@ and Uses .Vt struct tbl_span from -.Pa mandoc.h +.Qq Pa mandoc.h as an opaque type for function prototypes. .Pp When this header is included, the same file should not include -.Pa mansearch.h . +.Qq Pa mansearch.h . .It Qq Pa term.h Requires .In sys/types.h @@ -558,27 +574,30 @@ Uses and .Vt struct eqn_box from -.Pa mandoc.h +.Qq Pa mandoc.h and .Vt struct roff_meta and .Vt struct roff_node from -.Pa roff.h +.Qq Pa roff.h as opaque types for function prototypes. .Pp When this header is included, the same file should not include -.Pa html.h +.Qq Pa html.h or -.Pa mansearch.h . +.Qq Pa mansearch.h . .It Qq Pa html.h Requires .In sys/types.h for .Vt size_t , -.Pa mandoc.h +.Qq Pa mandoc.h for .Vt enum mandoc_esc , +.Qq Pa roff.h +for +.Vt enum roff_tok , and .Qq Pa out.h for @@ -602,17 +621,17 @@ Uses and .Vt struct eqn_box from -.Pa mandoc.h +.Qq Pa mandoc.h and .Vt struct roff_node from -.Pa roff.h +.Qq Pa roff.h as opaque types for function prototypes. .Pp When this header is included, the same file should not include -.Pa term.h +.Qq Pa term.h or -.Pa mansearch.h . +.Qq Pa mansearch.h . .It Qq Pa tag.h Requires .In sys/types.h @@ -631,7 +650,7 @@ Provides the top level steering functions for all formatters. Uses the type .Vt struct roff_meta from -.Pa roff.h +.Qq Pa roff.h as an opaque type for function prototypes. .It Qq Pa manconf.h Requires @@ -671,12 +690,12 @@ and Uses .Vt struct manpaths from -.Pa manconf.h +.Qq Pa manconf.h as an opaque type for function prototypes. .Pp When this header is included, the same file should not include -.Pa out.h , -.Pa term.h , +.Qq Pa out.h , +.Qq Pa term.h , or -.Pa html.h . +.Qq Pa html.h . .El diff --git a/mandoc_msg.c b/mandoc_msg.c index ff4d80313c2c..e73dcfd830ff 100644 --- a/mandoc_msg.c +++ b/mandoc_msg.c @@ -1,7 +1,7 @@ -/* $Id: mandoc_msg.c,v 1.6 2019/03/06 15:55:38 schwarze Exp $ */ +/* $Id: mandoc_msg.c,v 1.8 2019/07/14 18:16:13 schwarze Exp $ */ /* * Copyright (c) 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2014,2015,2016,2017,2018 Ingo Schwarze + * Copyright (c) 2014-2019 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -29,8 +29,8 @@ static const enum mandocerr lowest_type[MANDOCLEVEL_MAX] = { MANDOCERR_WARNING, MANDOCERR_ERROR, MANDOCERR_UNSUPP, - MANDOCERR_MAX, - MANDOCERR_MAX + MANDOCERR_BADARG, + MANDOCERR_SYSERR }; static const char *const level_name[MANDOCLEVEL_MAX] = { @@ -193,7 +193,6 @@ static const char *const type_message[MANDOCERR_MAX] = { "data block open at end of tbl", /* related to document structure and macros */ - NULL, "duplicate prologue macro", "skipping late title macro", "input stack limit exceeded, infinite loop?", @@ -240,11 +239,40 @@ static const char *const type_message[MANDOCERR_MAX] = { "eqn delim option in tbl", "unsupported tbl layout modifier", "ignoring macro in table", + + /* bad command line arguments */ + NULL, + "bad command line argument", + "duplicate command line argument", + "option has a superfluous value", + "missing option value", + "bad option value", + "duplicate option value", + "no such tag", + + /* system errors */ + NULL, + "dup", + "exec", + "fdopen", + "fflush", + "fork", + "fstat", + "getline", + "glob", + "gzclose", + "gzdopen", + "mkstemp", + "open", + "pledge", + "read", + "wait", + "write", }; static FILE *fileptr = NULL; static const char *filename = NULL; -static enum mandocerr min_type = MANDOCERR_MAX; +static enum mandocerr min_type = MANDOCERR_BADARG; static enum mandoclevel rc = MANDOCLEVEL_OK; @@ -297,10 +325,10 @@ mandoc_msg(enum mandocerr t, int line, int col, const char *fmt, ...) va_list ap; enum mandoclevel level; - if (t < min_type && t != MANDOCERR_FILE) + if (t < min_type) return; - level = MANDOCLEVEL_UNSUPP; + level = MANDOCLEVEL_SYSERR; while (t < lowest_type[level]) level--; mandoc_msg_setrc(level); @@ -327,3 +355,12 @@ mandoc_msg(enum mandocerr t, int line, int col, const char *fmt, ...) } fputc('\n', fileptr); } + +void +mandoc_msg_summary(void) +{ + if (fileptr != NULL && rc != MANDOCLEVEL_OK) + fprintf(fileptr, + "%s: see above the output for %s messages\n", + getprogname(), level_name[rc]); +} diff --git a/mandocdb.c b/mandocdb.c index 222350c987b6..64ac10115877 100644 --- a/mandocdb.c +++ b/mandocdb.c @@ -1,7 +1,7 @@ -/* $Id: mandocdb.c,v 1.262 2018/12/30 00:49:55 schwarze Exp $ */ +/* $Id: mandocdb.c,v 1.263 2019/05/03 18:17:12 schwarze Exp $ */ /* * Copyright (c) 2011, 2012 Kristaps Dzonsons - * Copyright (c) 2011-2018 Ingo Schwarze + * Copyright (c) 2011-2019 Ingo Schwarze * Copyright (c) 2016 Ed Maste * * Permission to use, copy, modify, and distribute this software for any @@ -1186,9 +1186,11 @@ mpages_merge(struct dba *dba, struct mparse *mp) mlink->next = mlink_dest->next; mlink_dest->next = mpage->mlinks; mpage->mlinks = NULL; + goto nextpage; } - goto nextpage; - } else if (meta != NULL && meta->macroset == MACROSET_MDOC) { + meta->macroset = MACROSET_NONE; + } + if (meta != NULL && meta->macroset == MACROSET_MDOC) { mpage->form = FORM_SRC; mpage->sec = meta->msec; mpage->sec = mandoc_strdup( @@ -1208,12 +1210,15 @@ mpages_merge(struct dba *dba, struct mparse *mp) } assert(mpage->desc == NULL); - if (meta == NULL) { - mpage->form = FORM_CAT; + if (meta == NULL || meta->sodest != NULL) { mpage->sec = mandoc_strdup(mlink->dsec); mpage->arch = mandoc_strdup(mlink->arch); mpage->title = mandoc_strdup(mlink->name); - parse_cat(mpage, fd); + if (meta == NULL) { + mpage->form = FORM_CAT; + parse_cat(mpage, fd); + } else + mpage->form = FORM_SRC; } else if (meta->macroset == MACROSET_MDOC) parse_mdoc(mpage, meta, meta->first); else diff --git a/manpath.c b/manpath.c index 74f38a95db9e..e4578ccec364 100644 --- a/manpath.c +++ b/manpath.c @@ -1,6 +1,6 @@ -/* $Id: manpath.c,v 1.37 2018/11/22 11:30:23 schwarze Exp $ */ +/* $Id: manpath.c,v 1.40 2019/07/10 19:39:01 schwarze Exp $ */ /* - * Copyright (c) 2011,2014,2015,2017,2018 Ingo Schwarze + * Copyright (c) 2011,2014,2015,2017-2019 Ingo Schwarze * Copyright (c) 2011 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any @@ -21,20 +21,19 @@ #include #include -#if HAVE_ERR -#include -#endif +#include #include #include #include #include #include "mandoc_aux.h" +#include "mandoc.h" #include "manconf.h" static void manconf_file(struct manconf *, const char *); -static void manpath_add(struct manpaths *, const char *, int); -static void manpath_parseline(struct manpaths *, char *, int); +static void manpath_add(struct manpaths *, const char *, char); +static void manpath_parseline(struct manpaths *, char *, char); void @@ -44,11 +43,11 @@ manconf_parse(struct manconf *conf, const char *file, char *insert; /* Always prepend -m. */ - manpath_parseline(&conf->manpath, auxp, 1); + manpath_parseline(&conf->manpath, auxp, 'm'); /* If -M is given, it overrides everything else. */ if (NULL != defp) { - manpath_parseline(&conf->manpath, defp, 1); + manpath_parseline(&conf->manpath, defp, 'M'); return; } @@ -66,13 +65,13 @@ manconf_parse(struct manconf *conf, const char *file, /* Prepend man.conf(5) to MANPATH. */ if (':' == defp[0]) { manconf_file(conf, file); - manpath_parseline(&conf->manpath, defp, 0); + manpath_parseline(&conf->manpath, defp, '\0'); return; } /* Append man.conf(5) to MANPATH. */ if (':' == defp[strlen(defp) - 1]) { - manpath_parseline(&conf->manpath, defp, 0); + manpath_parseline(&conf->manpath, defp, '\0'); manconf_file(conf, file); return; } @@ -81,28 +80,28 @@ manconf_parse(struct manconf *conf, const char *file, insert = strstr(defp, "::"); if (NULL != insert) { *insert++ = '\0'; - manpath_parseline(&conf->manpath, defp, 0); + manpath_parseline(&conf->manpath, defp, '\0'); manconf_file(conf, file); - manpath_parseline(&conf->manpath, insert + 1, 0); + manpath_parseline(&conf->manpath, insert + 1, '\0'); return; } /* MANPATH overrides man.conf(5) completely. */ - manpath_parseline(&conf->manpath, defp, 0); + manpath_parseline(&conf->manpath, defp, '\0'); } void manpath_base(struct manpaths *dirs) { char path_base[] = MANPATH_BASE; - manpath_parseline(dirs, path_base, 0); + manpath_parseline(dirs, path_base, '\0'); } /* * Parse a FULL pathname from a colon-separated list of arrays. */ static void -manpath_parseline(struct manpaths *dirs, char *path, int complain) +manpath_parseline(struct manpaths *dirs, char *path, char option) { char *dir; @@ -110,7 +109,7 @@ manpath_parseline(struct manpaths *dirs, char *path, int complain) return; for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":")) - manpath_add(dirs, dir, complain); + manpath_add(dirs, dir, option); } /* @@ -118,33 +117,32 @@ manpath_parseline(struct manpaths *dirs, char *path, int complain) * Grow the array one-by-one for simplicity's sake. */ static void -manpath_add(struct manpaths *dirs, const char *dir, int complain) +manpath_add(struct manpaths *dirs, const char *dir, char option) { char buf[PATH_MAX]; struct stat sb; char *cp; size_t i; - if (NULL == (cp = realpath(dir, buf))) { - if (complain) - warn("manpath: %s", dir); - return; - } + if ((cp = realpath(dir, buf)) == NULL) + goto fail; for (i = 0; i < dirs->sz; i++) - if (0 == strcmp(dirs->paths[i], dir)) + if (strcmp(dirs->paths[i], dir) == 0) return; - if (stat(cp, &sb) == -1) { - if (complain) - warn("manpath: %s", dir); - return; - } + if (stat(cp, &sb) == -1) + goto fail; dirs->paths = mandoc_reallocarray(dirs->paths, - dirs->sz + 1, sizeof(char *)); - + dirs->sz + 1, sizeof(*dirs->paths)); dirs->paths[dirs->sz++] = mandoc_strdup(cp); + return; + +fail: + if (option != '\0') + mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0, + "-%c %s: %s", option, dir, strerror(errno)); } void @@ -210,7 +208,7 @@ manconf_file(struct manconf *conf, const char *file) *ep = '\0'; /* FALLTHROUGH */ case 0: /* manpath */ - manpath_add(&conf->manpath, cp, 0); + manpath_add(&conf->manpath, cp, '\0'); *manpath_default = '\0'; break; case 1: /* output */ @@ -225,7 +223,7 @@ manconf_file(struct manconf *conf, const char *file) out: if (*manpath_default != '\0') - manpath_parseline(&conf->manpath, manpath_default, 0); + manpath_parseline(&conf->manpath, manpath_default, '\0'); } int @@ -235,14 +233,15 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile) "includes", "man", "paper", "style", "indent", "width", "tag", "fragment", "mdoc", "noval", "toc" }; + const size_t ntoks = sizeof(toks) / sizeof(toks[0]); const char *errstr; char *oldval; size_t len, tok; - for (tok = 0; tok < sizeof(toks)/sizeof(toks[0]); tok++) { + for (tok = 0; tok < ntoks; tok++) { len = strlen(toks[tok]); - if ( ! strncmp(cp, toks[tok], len) && + if (strncmp(cp, toks[tok], len) == 0 && strchr(" = ", cp[len]) != NULL) { cp += len; if (*cp == '=') @@ -254,11 +253,11 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile) } if (tok < 6 && *cp == '\0') { - warnx("-O %s=?: Missing argument value", toks[tok]); + mandoc_msg(MANDOCERR_BADVAL_MISS, 0, 0, "-O %s=?", toks[tok]); return -1; } - if (tok > 6 && *cp != '\0') { - warnx("-O %s: Does not take a value: %s", toks[tok], cp); + if (tok > 6 && tok < ntoks && *cp != '\0') { + mandoc_msg(MANDOCERR_BADVAL, 0, 0, "-O %s=%s", toks[tok], cp); return -1; } @@ -299,7 +298,8 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile) conf->indent = strtonum(cp, 0, 1000, &errstr); if (errstr == NULL) return 0; - warnx("-O indent=%s is %s", cp, errstr); + mandoc_msg(MANDOCERR_BADVAL_BAD, 0, 0, + "-O indent=%s is %s", cp, errstr); return -1; case 5: if (conf->width) { @@ -309,7 +309,8 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile) conf->width = strtonum(cp, 1, 1000, &errstr); if (errstr == NULL) return 0; - warnx("-O width=%s is %s", cp, errstr); + mandoc_msg(MANDOCERR_BADVAL_BAD, 0, 0, + "-O width=%s is %s", cp, errstr); return -1; case 6: if (conf->tag != NULL) { @@ -331,13 +332,16 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile) conf->toc = 1; return 0; default: - if (fromfile) - warnx("-O %s: Bad argument", cp); + mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0, "-O %s", cp); + return -1; + } + if (fromfile) { + free(oldval); + return 0; + } else { + mandoc_msg(MANDOCERR_BADVAL_DUPE, 0, 0, + "-O %s=%s: already set to %s", toks[tok], cp, oldval); + free(oldval); return -1; } - if (fromfile == 0) - warnx("-O %s=%s: Option already set to %s", - toks[tok], cp, oldval); - free(oldval); - return -1; } diff --git a/mansearch.c b/mansearch.c index 0c457f95d109..59a35771970c 100644 --- a/mansearch.c +++ b/mansearch.c @@ -1,4 +1,4 @@ -/* $Id: mansearch.c,v 1.80 2018/12/13 11:55:46 schwarze Exp $ */ +/* $Id: mansearch.c,v 1.82 2019/07/01 22:56:24 schwarze Exp $ */ /* * Copyright (c) 2012 Kristaps Dzonsons * Copyright (c) 2013-2018 Ingo Schwarze @@ -191,7 +191,7 @@ mansearch(const struct mansearch *search, mpage->file, R_OK) == -1) { warn("%s", mpage->file); warnx("outdated mandoc.db contains " - "bogus %s entry, run makewhatis %s", + "bogus %s entry, run makewhatis %s", page->file + 1, paths->paths[i]); free(mpage->file); free(rp); @@ -199,6 +199,7 @@ mansearch(const struct mansearch *search, } mpage->names = buildnames(page); mpage->output = buildoutput(outkey, page); + mpage->bits = search->firstmatch ? rp->bits : 0; mpage->ipath = i; mpage->sec = *page->sect - '0'; if (mpage->sec < 0 || mpage->sec > 9) @@ -294,8 +295,10 @@ manmerge_term(struct expr *e, struct ohash *htab) break; slot = ohash_lookup_memory(htab, (char *)&res, sizeof(res.page), res.page); - if ((rp = ohash_find(htab, slot)) != NULL) + if ((rp = ohash_find(htab, slot)) != NULL) { + rp->bits |= res.bits; continue; + } rp = mandoc_malloc(sizeof(*rp)); *rp = res; ohash_insert(htab, slot, rp); @@ -408,7 +411,8 @@ manpage_compare(const void *vp1, const void *vp2) mp1 = vp1; mp2 = vp2; - if ((diff = mp1->sec - mp2->sec)) + if ((diff = mp2->bits - mp1->bits) || + (diff = mp1->sec - mp2->sec)) return diff; /* Fall back to alphabetic ordering of names. */ diff --git a/mansearch.h b/mansearch.h index 355873f83e09..8a0aa121d0c6 100644 --- a/mansearch.h +++ b/mansearch.h @@ -1,4 +1,4 @@ -/* $Id: mansearch.h,v 1.29 2018/11/22 12:01:46 schwarze Exp $ */ +/* $Id: mansearch.h,v 1.30 2019/04/30 18:51:57 schwarze Exp $ */ /* * Copyright (c) 2012 Kristaps Dzonsons * Copyright (c) 2013, 2014, 2016, 2017 Ingo Schwarze @@ -92,6 +92,7 @@ struct manpage { char *file; /* to be prefixed by manpath */ char *names; /* a list of names with sections */ char *output; /* user-defined additional output */ + uint64_t bits; /* name type mask */ size_t ipath; /* number of the manpath */ int sec; /* section number, 10 means invalid */ enum form form; diff --git a/mdoc.7 b/mdoc.7 index 0624ce788cd2..deca4ba88c05 100644 --- a/mdoc.7 +++ b/mdoc.7 @@ -1,4 +1,4 @@ -.\" $Id: mdoc.7,v 1.276 2019/02/07 15:45:53 schwarze Exp $ +.\" $Id: mdoc.7,v 1.279 2019/07/15 19:20:30 schwarze Exp $ .\" .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons .\" Copyright (c) 2010, 2011, 2013-2018 Ingo Schwarze @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: February 7 2019 $ +.Dd $Mdocdate: July 15 2019 $ .Dt MDOC 7 .Os .Sh NAME @@ -596,6 +596,13 @@ block. Book or journal page number of an .Ic \&Rs block. +Conventionally, the argument starts with +.Ql p.\& +for a single page or +.Ql pp.\& +for a range of pages, for example: +.Pp +.Dl .%P pp. 42\e(en47 .It Ic \&%Q Ar name Institutional author (school, government, etc.) of an .Ic \&Rs @@ -1156,17 +1163,19 @@ declarations. This practise is discouraged. .It Ic \&Cm Ar keyword ... Command modifiers. -Typically used for fixed strings passed as arguments, unless +Typically used for fixed strings passed as arguments to interactive +commands, to commands in interpreted scripts, or to configuration +file directives, unless .Ic \&Fl is more appropriate. -Also useful when specifying configuration options or keys. .Pp Examples: .Dl ".Nm mt Fl f Ar device Cm rewind" .Dl ".Nm ps Fl o Cm pid , Ns Cm command" .Dl ".Nm dd Cm if= Ns Ar file1 Cm of= Ns Ar file2" -.Dl ".Cm IdentityFile Pa ~/.ssh/id_rsa" -.Dl ".Cm LogLevel Dv DEBUG" +.Dl ".Ic set Fl o Cm vi" +.Dl ".Ic lookup Cm file bind" +.Dl ".Ic permit Ar identity Op Cm as Ar target" .It Ic \&D1 Ar line One-line indented display. This is formatted by the default rules and is useful for simple indented @@ -1677,10 +1686,10 @@ This macro is not implemented in .Xr mandoc 1 . It was used to include the contents of a (header) file literally. .It Ic \&Ic Ar keyword ... -Designate an internal or interactive command. -This is similar to -.Ic \&Cm -but used for instructions rather than values. +Internal or interactive command, or configuration instruction +in a configuration file. +See also +.Ic \&Cm . .Pp Examples: .Dl \&.Ic :wq @@ -2969,7 +2978,7 @@ exclamation mark Note that even a period preceded by a backslash .Pq Sq \e.\& gets this special handling; use -.Sq \e&. +.Sq \e&.\& to prevent that. .Pp Many in-line macros interrupt their scope when they encounter @@ -2996,6 +3005,13 @@ in the same way as a plain .Sq \&| character. Using this predefined string is not recommended in new manuals. +.Pp +Appending a zero-width space +.Pq Sq \e& +to the end of an input line is also useful to prevent the interpretation +of a trailing period, exclamation or question mark as the end of a +sentence, for example when an abbreviation happens to occur +at the end of a text or macro input line. .Ss Font handling In .Nm diff --git a/mdoc_argv.c b/mdoc_argv.c index f4ce4a8730f3..1bfd336b7a97 100644 --- a/mdoc_argv.c +++ b/mdoc_argv.c @@ -1,7 +1,7 @@ -/* $Id: mdoc_argv.c,v 1.119 2018/12/21 17:15:19 schwarze Exp $ */ +/* $Id: mdoc_argv.c,v 1.120 2019/07/11 17:06:17 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2012, 2014-2018 Ingo Schwarze + * Copyright (c) 2012, 2014-2019 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 @@ -454,6 +454,7 @@ args(struct roff_man *mdoc, int line, int *pos, mandoc_msg(MANDOCERR_ARG_QUOTE, line, *pos, NULL); mdoc->flags &= ~MDOC_PHRASELIT; } + mdoc->flags &= ~MDOC_PHRASEQL; return ARGS_EOLN; } diff --git a/mdoc_markdown.c b/mdoc_markdown.c index e9a931218cc4..88e37c0b188b 100644 --- a/mdoc_markdown.c +++ b/mdoc_markdown.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_markdown.c,v 1.30 2018/12/30 00:49:55 schwarze Exp $ */ +/* $Id: mdoc_markdown.c,v 1.31 2019/07/01 22:56:24 schwarze Exp $ */ /* * Copyright (c) 2017, 2018 Ingo Schwarze * @@ -1290,7 +1290,7 @@ md_post_It(struct roff_node *n) while ((n = n->prev) != NULL && n->type != ROFFT_HEAD) i++; - /* + /* * If a width was specified for this column, * subtract what printed, and * add the same spacing as in mdoc_term.c. diff --git a/mdoc_term.c b/mdoc_term.c index 52ff27e17f11..18f0ff09e2c7 100644 --- a/mdoc_term.c +++ b/mdoc_term.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_term.c,v 1.372 2019/01/04 03:39:01 schwarze Exp $ */ +/* $Id: mdoc_term.c,v 1.374 2019/06/27 12:20:18 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2010, 2012-2019 Ingo Schwarze @@ -253,7 +253,7 @@ static int fn_prio; void terminal_mdoc(void *arg, const struct roff_meta *mdoc) { - struct roff_node *n; + struct roff_node *n, *nn; struct termp *p; size_t save_defindent; @@ -265,16 +265,20 @@ terminal_mdoc(void *arg, const struct roff_meta *mdoc) n = mdoc->first->child; if (p->synopsisonly) { - while (n != NULL) { - if (n->tok == MDOC_Sh && n->sec == SEC_SYNOPSIS) { - if (n->child->next->child != NULL) - print_mdoc_nodelist(p, NULL, - mdoc, n->child->next->child); - term_newln(p); + for (nn = NULL; n != NULL; n = n->next) { + if (n->tok != MDOC_Sh) + continue; + if (n->sec == SEC_SYNOPSIS) break; - } - n = n->next; + if (nn == NULL && n->sec == SEC_NAME) + nn = n; } + if (n == NULL) + n = nn; + p->flags |= TERMP_NOSPACE; + if (n != NULL && (n = n->child->next->child) != NULL) + print_mdoc_nodelist(p, NULL, mdoc, n); + term_newln(p); } else { save_defindent = p->defindent; if (p->defindent == 0) @@ -352,6 +356,7 @@ print_mdoc_node(DECL_ARGS) * produce output. Note that some pre-handlers do so. */ + act = NULL; switch (n->type) { case ROFFT_TEXT: if (n->flags & NODE_LINE) { diff --git a/mdoc_validate.c b/mdoc_validate.c index 7d1575f2f0f1..11cdf00b56cb 100644 --- a/mdoc_validate.c +++ b/mdoc_validate.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_validate.c,v 1.371 2019/03/04 13:01:57 schwarze Exp $ */ +/* $Id: mdoc_validate.c,v 1.374 2019/06/27 15:07:30 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons * Copyright (c) 2010-2019 Ingo Schwarze @@ -64,7 +64,7 @@ static size_t macro2len(enum roff_tok); static void rewrite_macro2len(struct roff_man *, char **); static int similar(const char *, const char *); -static void post_abort(POST_ARGS); +static void post_abort(POST_ARGS) __attribute__((__noreturn__)); static void post_an(POST_ARGS); static void post_an_norm(POST_ARGS); static void post_at(POST_ARGS); @@ -1903,8 +1903,7 @@ post_root(POST_ARGS) /* Add missing prologue data. */ if (mdoc->meta.date == NULL) - mdoc->meta.date = mdoc->quick ? mandoc_strdup("") : - mandoc_normdate(mdoc, NULL, 0, 0); + mdoc->meta.date = mandoc_normdate(mdoc, NULL, 0, 0); if (mdoc->meta.title == NULL) { mandoc_msg(MANDOCERR_DT_NOTITLE, 0, 0, "EOF"); @@ -2519,21 +2518,10 @@ post_dd(POST_ARGS) mandoc_msg(MANDOCERR_PROLOG_ORDER, n->line, n->pos, "Dd after Os"); - if (n->child == NULL || n->child->string[0] == '\0') { - mdoc->meta.date = mdoc->quick ? mandoc_strdup("") : - mandoc_normdate(mdoc, NULL, n->line, n->pos); - return; - } - datestr = NULL; deroff(&datestr, n); - if (mdoc->quick) - mdoc->meta.date = datestr; - else { - mdoc->meta.date = mandoc_normdate(mdoc, - datestr, n->line, n->pos); - free(datestr); - } + mdoc->meta.date = mandoc_normdate(mdoc, datestr, n->line, n->pos); + free(datestr); } static void diff --git a/out.c b/out.c index 363d04cf979d..d0b0d0a2ace3 100644 --- a/out.c +++ b/out.c @@ -1,4 +1,4 @@ -/* $Id: out.c,v 1.77 2018/12/13 11:55:47 schwarze Exp $ */ +/* $Id: out.c,v 1.78 2019/03/29 21:27:06 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2011,2014,2015,2017,2018 Ingo Schwarze @@ -149,7 +149,7 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp_first, gp = &first_group; for (dp = sp->first; dp != NULL; dp = dp->next) { icol = dp->layout->col; - while (icol > maxcol) + while (maxcol < icol + dp->hspans) tbl->cols[++maxcol].spacing = SIZE_MAX; col = tbl->cols + icol; col->flags |= dp->layout->flags; diff --git a/read.c b/read.c index a3a1f982c01c..b3858061e710 100644 --- a/read.c +++ b/read.c @@ -1,4 +1,4 @@ -/* $Id: read.c,v 1.211 2019/01/11 17:04:44 schwarze Exp $ */ +/* $Id: read.c,v 1.214 2019/07/10 19:39:01 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2010-2019 Ingo Schwarze @@ -157,7 +157,7 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start) ln.sz = 256; ln.buf = mandoc_malloc(ln.sz); ln.next = NULL; - firstln = loop = NULL; + firstln = lastln = loop = NULL; lnn = curp->line; pos = 0; inloop = 0; @@ -255,6 +255,8 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start) /* XXX Ugly hack to mark the end of the input. */ if (i == blk.sz || blk.buf[i] == '\0') { + if (pos + 2 > ln.sz) + resize_buf(&ln, 256); ln.buf[pos++] = '\n'; ln.buf[pos] = '\0'; } @@ -429,9 +431,8 @@ read_whole_file(struct mparse *curp, int fd, struct buf *fb, int *with_mmap) int gzerrnum, retval; if (fstat(fd, &st) == -1) { - mandoc_msg(MANDOCERR_FILE, 0, 0, - "fstat: %s", strerror(errno)); - return 0; + mandoc_msg(MANDOCERR_FSTAT, 0, 0, "%s", strerror(errno)); + return -1; } /* @@ -444,13 +445,13 @@ read_whole_file(struct mparse *curp, int fd, struct buf *fb, int *with_mmap) if (curp->gzip == 0 && S_ISREG(st.st_mode)) { if (st.st_size > 0x7fffffff) { mandoc_msg(MANDOCERR_TOOLARGE, 0, 0, NULL); - return 0; + return -1; } *with_mmap = 1; fb->sz = (size_t)st.st_size; fb->buf = mmap(NULL, fb->sz, PROT_READ, MAP_SHARED, fd, 0); if (fb->buf != MAP_FAILED) - return 1; + return 0; } if (curp->gzip) { @@ -462,15 +463,15 @@ read_whole_file(struct mparse *curp, int fd, struct buf *fb, int *with_mmap) * which this function must not do. */ if ((fd = dup(fd)) == -1) { - mandoc_msg(MANDOCERR_FILE, 0, 0, - "dup: %s", strerror(errno)); - return 0; + mandoc_msg(MANDOCERR_DUP, 0, 0, + "%s", strerror(errno)); + return -1; } if ((gz = gzdopen(fd, "rb")) == NULL) { - mandoc_msg(MANDOCERR_FILE, 0, 0, - "gzdopen: %s", strerror(errno)); + mandoc_msg(MANDOCERR_GZDOPEN, 0, 0, + "%s", strerror(errno)); close(fd); - return 0; + return -1; } } else gz = NULL; @@ -482,7 +483,7 @@ read_whole_file(struct mparse *curp, int fd, struct buf *fb, int *with_mmap) *with_mmap = 0; off = 0; - retval = 0; + retval = -1; fb->sz = 0; fb->buf = NULL; for (;;) { @@ -498,13 +499,13 @@ read_whole_file(struct mparse *curp, int fd, struct buf *fb, int *with_mmap) read(fd, fb->buf + (int)off, fb->sz - off); if (ssz == 0) { fb->sz = off; - retval = 1; + retval = 0; break; } if (ssz == -1) { if (curp->gzip) (void)gzerror(gz, &gzerrnum); - mandoc_msg(MANDOCERR_FILE, 0, 0, "read: %s", + mandoc_msg(MANDOCERR_READ, 0, 0, "%s", curp->gzip && gzerrnum != Z_ERRNO ? zError(gzerrnum) : strerror(errno)); break; @@ -513,10 +514,10 @@ read_whole_file(struct mparse *curp, int fd, struct buf *fb, int *with_mmap) } if (curp->gzip && (gzerrnum = gzclose(gz)) != Z_OK) - mandoc_msg(MANDOCERR_FILE, 0, 0, "gzclose: %s", + mandoc_msg(MANDOCERR_GZCLOSE, 0, 0, "%s", gzerrnum == Z_ERRNO ? strerror(errno) : zError(gzerrnum)); - if (retval == 0) { + if (retval == -1) { free(fb->buf); fb->buf = NULL; } @@ -555,7 +556,7 @@ mparse_readfd(struct mparse *curp, int fd, const char *filename) mandoc_msg(MANDOCERR_ROFFLOOP, curp->line, 0, NULL); return; } - if (read_whole_file(curp, fd, &blk, &with_mmap) == 0) + if (read_whole_file(curp, fd, &blk, &with_mmap) == -1) return; /* diff --git a/roff.7 b/roff.7 index de76a3c4d246..f129750b1b0e 100644 --- a/roff.7 +++ b/roff.7 @@ -1,4 +1,4 @@ -.\" $Id: roff.7,v 1.111 2019/01/01 03:45:29 schwarze Exp $ +.\" $Id: roff.7,v 1.114 2019/07/15 19:20:30 schwarze Exp $ .\" .\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons .\" Copyright (c) 2010-2019 Ingo Schwarze @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: January 1 2019 $ +.Dd $Mdocdate: July 15 2019 $ .Dt ROFF 7 .Os .Sh NAME @@ -315,12 +315,18 @@ delimiters The proper spacing is also intelligently preserved if a sentence ends at the boundary of a macro line. .Pp +If an input line happens to end with a period, exclamation or question +mark that isn't the end of a sentence, append a zero-width space +.Pq Sq \e& . +.Pp Examples: .Bd -literal -offset indent -compact Do not end sentences mid-line like this. Instead, end a sentence like this. A macro would end like this: \&.Xr mandoc 1 \&. +An abbreviation at the end of an input line needs escaping, e.g.\e& +like this. .Ed .Sh REQUEST SYNTAX A request or macro line consists of: @@ -503,10 +509,9 @@ This is a Heirloom extension and currently unsupported. .It Ic \&br Break the output line. .It Ic \&break -Break out of a +Break out of the innermost .Ic \&while loop. -Currently unsupported. .It Ic \&breakchar Ar char ... Optional line break characters. This is a Heirloom extension and currently ignored. @@ -2279,7 +2284,7 @@ code. .Pp The special semantics of the .Cm nS -number register is an idiosyncracy of +number register is an idiosyncrasy of .Ox manuals and not supported by other .Xr mdoc 7 diff --git a/roff.c b/roff.c index 2b07352b90a3..f26d9f01f226 100644 --- a/roff.c +++ b/roff.c @@ -1,4 +1,4 @@ -/* $Id: roff.c,v 1.363 2019/02/06 21:11:43 schwarze Exp $ */ +/* $Id: roff.c,v 1.366 2019/07/01 22:56:24 schwarze Exp $ */ /* * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons * Copyright (c) 2010-2015, 2017-2019 Ingo Schwarze @@ -133,15 +133,18 @@ struct roff { char escape; /* escape character */ }; +/* + * A macro definition, condition, or ignored block. + */ struct roffnode { enum roff_tok tok; /* type of node */ struct roffnode *parent; /* up one in stack */ int line; /* parse line */ int col; /* parse col */ char *name; /* node name, e.g. macro name */ - char *end; /* end-rules: custom token */ - int endspan; /* end-rules: next-line or infty */ - int rule; /* current evaluation rule */ + char *end; /* custom end macro of the block */ + int endspan; /* scope to: 1=eol 2=next line -1=\} */ + int rule; /* content is: 1=evaluated 0=skipped */ }; #define ROFF_ARGS struct roff *r, /* parse ctx */ \ @@ -181,6 +184,7 @@ static int roff_als(ROFF_ARGS); static int roff_block(ROFF_ARGS); static int roff_block_text(ROFF_ARGS); static int roff_block_sub(ROFF_ARGS); +static int roff_break(ROFF_ARGS); static int roff_cblock(ROFF_ARGS); static int roff_cc(ROFF_ARGS); static int roff_ccond(struct roff *, int, int); @@ -400,7 +404,7 @@ static struct roffmac roffs[TOKEN_NONE] = { { roff_unsupp, NULL, NULL, 0 }, /* boxa */ { roff_line_ignore, NULL, NULL, 0 }, /* bp */ { roff_unsupp, NULL, NULL, 0 }, /* BP */ - { roff_unsupp, NULL, NULL, 0 }, /* break */ + { roff_break, NULL, NULL, 0 }, /* break */ { roff_line_ignore, NULL, NULL, 0 }, /* breakchar */ { roff_line_ignore, NULL, NULL, 0 }, /* brnl */ { roff_noarg, NULL, NULL, 0 }, /* brp */ @@ -685,7 +689,7 @@ roffhash_find(struct ohash *htab, const char *name, size_t sz) /* * Pop the current node off of the stack of roff instructions currently - * pending. + * pending. Return 1 if it is a loop or 0 otherwise. */ static int roffnode_pop(struct roff *r) @@ -779,7 +783,7 @@ roff_reset(struct roff *r) void roff_free(struct roff *r) { - int i; + int i; roff_free1(r); for (i = 0; i < r->mstacksz; i++) @@ -1586,7 +1590,7 @@ char * roff_getarg(struct roff *r, char **cpp, int ln, int *pos) { struct buf buf; - char *cp, *start; + char *cp, *start; int newesc, pairs, quoted, white; /* Quoting can only start with a new word. */ @@ -2002,6 +2006,10 @@ roff_cblock(ROFF_ARGS) } +/* + * Pop all nodes ending at the end of the current input line. + * Return the number of loops ended. + */ static int roffnode_cleanscope(struct roff *r) { @@ -2016,6 +2024,11 @@ roffnode_cleanscope(struct roff *r) return inloop; } +/* + * Handle the closing \} of a conditional block. + * Apart from generating warnings, this only pops nodes. + * Return the number of loops ended. + */ static int roff_ccond(struct roff *r, int ln, int ppos) { @@ -2235,6 +2248,7 @@ roff_block_text(ROFF_ARGS) static int roff_cond_sub(ROFF_ARGS) { + struct roffnode *bl; char *ep; int endloop, irc, rr; enum roff_tok t; @@ -2282,9 +2296,21 @@ roff_cond_sub(ROFF_ARGS) */ t = roff_parse(r, buf->buf, &pos, ln, ppos); - irc |= t != TOKEN_NONE && (rr || roffs[t].flags & ROFFMAC_STRUCT) ? - (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs) : - rr ? ROFF_CONT : ROFF_IGN; + if (t == ROFF_break) { + if (irc & ROFF_LOOPMASK) + irc = ROFF_IGN | ROFF_LOOPEXIT; + else if (rr) { + for (bl = r->last; bl != NULL; bl = bl->parent) { + bl->rule = 0; + if (bl->tok == ROFF_while) + break; + } + } + } else if (t != TOKEN_NONE && + (rr || roffs[t].flags & ROFFMAC_STRUCT)) + irc |= (*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs); + else + irc |= rr ? ROFF_CONT : ROFF_IGN; return irc; } @@ -3482,6 +3508,17 @@ roff_als(ROFF_ARGS) return ROFF_IGN; } +/* + * The .break request only makes sense inside conditionals, + * and that case is already handled in roff_cond_sub(). + */ +static int +roff_break(ROFF_ARGS) +{ + mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, pos, "break"); + return ROFF_IGN; +} + static int roff_cc(ROFF_ARGS) { @@ -3804,6 +3841,11 @@ roff_userdef(ROFF_ARGS) char *arg, *ap, *dst, *src; size_t sz; + /* If the macro is empty, ignore it altogether. */ + + if (*r->current_string == '\0') + return ROFF_IGN; + /* Initialize a new macro stack context. */ if (++r->mstackpos == r->mstacksz) { @@ -3851,7 +3893,7 @@ roff_userdef(ROFF_ARGS) buf->sz = strlen(buf->buf) + 1; *offs = 0; - return buf->sz > 1 && buf->buf[buf->sz - 2] == '\n' ? + return buf->buf[buf->sz - 2] == '\n' ? ROFF_REPARSE | ROFF_USERCALL : ROFF_IGN | ROFF_APPEND; } diff --git a/roff_html.c b/roff_html.c index 02b8beea3bdc..e525aa2ede68 100644 --- a/roff_html.c +++ b/roff_html.c @@ -1,4 +1,4 @@ -/* $Id: roff_html.c,v 1.19 2019/01/07 07:26:29 schwarze Exp $ */ +/* $Id: roff_html.c,v 1.20 2019/04/30 15:53:01 schwarze Exp $ */ /* * Copyright (c) 2010 Kristaps Dzonsons * Copyright (c) 2014, 2017, 2018, 2019 Ingo Schwarze @@ -94,7 +94,7 @@ roff_html_pre_ft(ROFF_HTML_ARGS) const char *cp; cp = n->child->string; - print_metaf(h, mandoc_font(cp, (int)strlen(cp))); + html_setfont(h, mandoc_font(cp, (int)strlen(cp))); } static void diff --git a/tag.c b/tag.c index 473ea7b6f491..d5e7f89c1a50 100644 --- a/tag.c +++ b/tag.c @@ -1,6 +1,6 @@ -/* $Id: tag.c,v 1.21 2018/11/22 11:30:23 schwarze Exp $ */ +/* $Id: tag.c,v 1.24 2019/07/22 03:21:50 schwarze Exp $ */ /* - * Copyright (c) 2015, 2016, 2018 Ingo Schwarze + * Copyright (c) 2015, 2016, 2018, 2019 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 @@ -18,9 +18,7 @@ #include -#if HAVE_ERR -#include -#endif +#include #include #include #include @@ -32,6 +30,7 @@ #include "mandoc_aux.h" #include "mandoc_ohash.h" +#include "mandoc.h" #include "tag.h" struct tag_entry { @@ -83,8 +82,10 @@ tag_init(void) /* Save the original standard output for use by the pager. */ - if ((tag_files.ofd = dup(STDOUT_FILENO)) == -1) + if ((tag_files.ofd = dup(STDOUT_FILENO)) == -1) { + mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno)); goto fail; + } /* Create both temporary output files. */ @@ -92,12 +93,20 @@ tag_init(void) sizeof(tag_files.ofn)); (void)strlcpy(tag_files.tfn, "/tmp/man.XXXXXXXXXX", sizeof(tag_files.tfn)); - if ((ofd = mkstemp(tag_files.ofn)) == -1) + if ((ofd = mkstemp(tag_files.ofn)) == -1) { + mandoc_msg(MANDOCERR_MKSTEMP, 0, 0, + "%s: %s", tag_files.ofn, strerror(errno)); goto fail; - if ((tag_files.tfd = mkstemp(tag_files.tfn)) == -1) + } + if ((tag_files.tfd = mkstemp(tag_files.tfn)) == -1) { + mandoc_msg(MANDOCERR_MKSTEMP, 0, 0, + "%s: %s", tag_files.tfn, strerror(errno)); goto fail; - if (dup2(ofd, STDOUT_FILENO) == -1) + } + if (dup2(ofd, STDOUT_FILENO) == -1) { + mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno)); goto fail; + } close(ofd); /* @@ -142,11 +151,11 @@ tag_put(const char *s, int prio, size_t line) s += 2; /* - * Skip whitespace and whatever follows it, + * Skip whitespace and escapes and whatever follows, * and if there is any, downgrade the priority. */ - len = strcspn(s, " \t"); + len = strcspn(s, " \t\\"); if (len == 0) return; @@ -216,21 +225,27 @@ tag_write(void) struct tag_entry *entry; size_t i; unsigned int slot; + int empty; if (tag_files.tfd <= 0) return; if (tag_files.tagname != NULL && ohash_find(&tag_data, ohash_qlookup(&tag_data, tag_files.tagname)) == NULL) { - warnx("%s: no such tag", tag_files.tagname); + mandoc_msg(MANDOCERR_TAG, 0, 0, "%s", tag_files.tagname); tag_files.tagname = NULL; } - stream = fdopen(tag_files.tfd, "w"); + if ((stream = fdopen(tag_files.tfd, "w")) == NULL) + mandoc_msg(MANDOCERR_FDOPEN, 0, 0, "%s", strerror(errno)); + empty = 1; entry = ohash_first(&tag_data, &slot); while (entry != NULL) { - if (stream != NULL && entry->prio >= 0) - for (i = 0; i < entry->nlines; i++) + if (stream != NULL && entry->prio >= 0) { + for (i = 0; i < entry->nlines; i++) { fprintf(stream, "%s %s %zu\n", entry->s, tag_files.ofn, entry->lines[i]); + empty = 0; + } + } free(entry->lines); free(entry); entry = ohash_next(&tag_data, &slot); @@ -241,6 +256,10 @@ tag_write(void) else close(tag_files.tfd); tag_files.tfd = -1; + if (empty) { + unlink(tag_files.tfn); + *tag_files.tfn = '\0'; + } } void diff --git a/tbl_html.c b/tbl_html.c index 4ab6bed10bd0..e137757dc16c 100644 --- a/tbl_html.c +++ b/tbl_html.c @@ -1,4 +1,4 @@ -/* $Id: tbl_html.c,v 1.32 2019/01/06 04:55:09 schwarze Exp $ */ +/* $Id: tbl_html.c,v 1.33 2019/03/17 18:21:45 schwarze Exp $ */ /* * Copyright (c) 2011 Kristaps Dzonsons * Copyright (c) 2014, 2015, 2017, 2018 Ingo Schwarze @@ -25,6 +25,7 @@ #include #include "mandoc.h" +#include "roff.h" #include "tbl.h" #include "out.h" #include "html.h" diff --git a/tbl_term.c b/tbl_term.c index a197f8ef743a..de88d61c15e1 100644 --- a/tbl_term.c +++ b/tbl_term.c @@ -1,4 +1,4 @@ -/* $Id: tbl_term.c,v 1.68 2019/02/09 21:02:47 schwarze Exp $ */ +/* $Id: tbl_term.c,v 1.72 2019/07/01 22:56:24 schwarze Exp $ */ /* * Copyright (c) 2009, 2011 Kristaps Dzonsons * Copyright (c) 2011-2019 Ingo Schwarze @@ -46,7 +46,8 @@ static void tbl_fill_border(struct termp *, int, size_t); static void tbl_fill_char(struct termp *, char, size_t); static void tbl_fill_string(struct termp *, const char *, size_t); static void tbl_hrule(struct termp *, const struct tbl_span *, - const struct tbl_span *, int); + const struct tbl_span *, const struct tbl_span *, + int); static void tbl_literal(struct termp *, const struct tbl_dat *, const struct roffcol *); static void tbl_number(struct termp *, const struct tbl_opts *, @@ -163,7 +164,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) const struct tbl_cell *cp, *cpn, *cpp, *cps; const struct tbl_dat *dp; static size_t offset; - size_t save_offset; + size_t save_offset; size_t coloff, tsz; int hspans, ic, more; int dvert, fc, horiz, lhori, rhori, uvert; @@ -222,9 +223,9 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) if (tp->enc == TERMENC_ASCII && sp->opts->opts & TBL_OPT_DBOX) - tbl_hrule(tp, NULL, sp, TBL_OPT_DBOX); + tbl_hrule(tp, NULL, sp, sp, TBL_OPT_DBOX); if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) - tbl_hrule(tp, NULL, sp, TBL_OPT_BOX); + tbl_hrule(tp, NULL, sp, sp, TBL_OPT_BOX); } /* Set up the columns. */ @@ -342,7 +343,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) more = 0; if (horiz) - tbl_hrule(tp, sp->prev, sp, 0); + tbl_hrule(tp, sp->prev, sp, sp->next, 0); else { cp = sp->layout->first; cpn = sp->next == NULL ? NULL : @@ -557,12 +558,12 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) tp->tcol->rmargin = tp->maxrmargin; if (sp->next == NULL) { if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) { - tbl_hrule(tp, sp, NULL, TBL_OPT_BOX); + tbl_hrule(tp, sp, sp, NULL, TBL_OPT_BOX); tp->skipvsp = 1; } if (tp->enc == TERMENC_ASCII && sp->opts->opts & TBL_OPT_DBOX) { - tbl_hrule(tp, sp, NULL, TBL_OPT_DBOX); + tbl_hrule(tp, sp, sp, NULL, TBL_OPT_DBOX); tp->skipvsp = 2; } assert(tp->tbl.cols); @@ -571,7 +572,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) } else if (horiz == 0 && sp->opts->opts & TBL_OPT_ALLBOX && (sp->next == NULL || sp->next->pos == TBL_SPAN_DATA || sp->next->next != NULL)) - tbl_hrule(tp, sp, sp->next, TBL_OPT_ALLBOX); + tbl_hrule(tp, sp, sp, sp->next, TBL_OPT_ALLBOX); tp->tcol->offset = save_offset; tp->flags &= ~TERMP_NONOSPACE; @@ -579,9 +580,10 @@ term_tbl(struct termp *tp, const struct tbl_span *sp) static void tbl_hrule(struct termp *tp, const struct tbl_span *spp, - const struct tbl_span *spn, int flags) + const struct tbl_span *sp, const struct tbl_span *spn, int flags) { const struct tbl_cell *cpp; /* Layout cell above this line. */ + const struct tbl_cell *cp; /* Layout cell in this line. */ const struct tbl_cell *cpn; /* Layout cell below this line. */ const struct tbl_dat *dpn; /* Data cell below this line. */ const struct roffcol *col; /* Contains width and spacing. */ @@ -592,6 +594,7 @@ tbl_hrule(struct termp *tp, const struct tbl_span *spp, int uw, dw; /* Vertical line widths. */ cpp = spp == NULL ? NULL : spp->layout->first; + cp = sp == NULL ? NULL : sp->layout->first; cpn = spn == NULL ? NULL : spn->layout->first; dpn = NULL; if (spn != NULL) { @@ -600,11 +603,11 @@ tbl_hrule(struct termp *tp, const struct tbl_span *spp, else if (spn->next != NULL) dpn = spn->next->first; } - opts = spn == NULL ? spp->opts->opts : spn->opts->opts; + opts = sp->opts->opts; bw = opts & TBL_OPT_DBOX ? (tp->enc == TERMENC_UTF8 ? 2 : 1) : opts & (TBL_OPT_BOX | TBL_OPT_ALLBOX) ? 1 : 0; hw = flags == TBL_OPT_DBOX || flags == TBL_OPT_BOX ? bw : - spn->pos == TBL_SPAN_DHORIZ ? 2 : 1; + sp->pos == TBL_SPAN_DHORIZ ? 2 : 1; /* Print the left end of the line. */ @@ -619,14 +622,19 @@ tbl_hrule(struct termp *tp, const struct tbl_span *spp, (spp == NULL || cpn == NULL || cpn->pos != TBL_CELL_DOWN ? BRIGHT * hw : 0), 1); + col = tp->tbl.cols; for (;;) { - col = tp->tbl.cols + (cpn == NULL ? cpp->col : cpn->col); + if (cp == NULL) + col++; + else + col = tp->tbl.cols + cp->col; /* Print the horizontal line inside this column. */ lw = cpp == NULL || cpn == NULL || (cpn->pos != TBL_CELL_DOWN && - (dpn == NULL || strcmp(dpn->string, "\\^") != 0)) + (dpn == NULL || dpn->string == NULL || + strcmp(dpn->string, "\\^") != 0)) ? hw : 0; tbl_direct_border(tp, BHORIZ * lw, col->width + col->spacing / 2); @@ -645,7 +653,10 @@ tbl_hrule(struct termp *tp, const struct tbl_span *spp, uw = 1; } cpp = cpp->next; - } + } else if (spp != NULL && opts & TBL_OPT_ALLBOX) + uw = 1; + if (cp != NULL) + cp = cp->next; if (cpn != NULL) { if (flags != TBL_OPT_DBOX) { dw = cpn->vert; @@ -655,8 +666,9 @@ tbl_hrule(struct termp *tp, const struct tbl_span *spp, cpn = cpn->next; while (dpn != NULL && dpn->layout != cpn) dpn = dpn->next; - } - if (cpp == NULL && cpn == NULL) + } else if (spn != NULL && opts & TBL_OPT_ALLBOX) + dw = 1; + if (col + 1 == tp->tbl.cols + sp->opts->cols) break; /* Vertical lines do not cross spanned cells. */ @@ -670,7 +682,8 @@ tbl_hrule(struct termp *tp, const struct tbl_span *spp, rw = cpp == NULL || cpn == NULL || (cpn->pos != TBL_CELL_DOWN && - (dpn == NULL || strcmp(dpn->string, "\\^") != 0)) + (dpn == NULL || dpn->string == NULL || + strcmp(dpn->string, "\\^") != 0)) ? hw : 0; /* The line crossing at the end of this column. */ diff --git a/term.c b/term.c index 8e9762282582..3b9277aaabbc 100644 --- a/term.c +++ b/term.c @@ -1,4 +1,4 @@ -/* $Id: term.c,v 1.280 2019/01/15 12:16:18 schwarze Exp $ */ +/* $Id: term.c,v 1.281 2019/06/03 20:23:41 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2010-2019 Ingo Schwarze @@ -281,6 +281,8 @@ term_fill(struct termp *p, size_t *nbr, size_t *vbr, size_t vtarget) case ASCII_BREAK: vn = vis; break; + default: + abort(); } /* Can break at the end of a word. */ if (breakline || vn > vtarget)