diff --git a/INSTALL b/INSTALL index 115d16006432..3f0d3bbc54ac 100644 --- a/INSTALL +++ b/INSTALL @@ -1,4 +1,4 @@ -$Id: INSTALL,v 1.17 2016/07/19 22:40:33 schwarze Exp $ +$Id: INSTALL,v 1.18 2017/02/08 12:24:10 schwarze Exp $ About mdocml, the portable mandoc distribution ---------------------------------------------- @@ -16,7 +16,7 @@ tech@ mailing list, too. Enjoy using the mandoc toolset! -Ingo Schwarze, Karlsruhe, July 2016 +Ingo Schwarze, Karlsruhe, February 2017 Installation @@ -31,15 +31,21 @@ Regarding how packages and ports are maintained for your operating system, please consult your operating system documentation. To install mandoc manually, the following steps are needed: -1. If you want to build the CGI program, man.cgi(8), too, run the -command "echo BUILD_CGI=1 > configure.local". Then run "cp -cgi.h.examples cgi.h" and edit cgi.h as desired. +1. If you want to build the CGI program, man.cgi(8), too, +run the command "echo BUILD_CGI=1 >> configure.local". +Then run "cp cgi.h.example cgi.h" and edit cgi.h as desired. -2. Define MANPATH_DEFAULT in configure.local +2. If you also want to build the new catman(8) utility, run the +command "echo BUILD_CATMAN=1 >> configure.local". Note that it +is unlikely to be a drop-in replacement providing the same +functionality as your system's "catman", if your operating +system contains one. + +3. Define MANPATH_DEFAULT in configure.local if /usr/share/man:/usr/X11R6/man:/usr/local/man is not appropriate for your operating system. -3. Run "./configure". +4. Run "./configure". This script attempts autoconfiguration of mandoc for your system. Read both its standard output and the file "Makefile.local" it generates. If anything looks wrong or different from what you @@ -49,27 +55,31 @@ result seems right to you. On Solaris 10 and earlier, you may have to run "ksh ./configure" because the native /bin/sh lacks some POSIX features. -4. Run "make". +5. Run "make". Any POSIX-compatible make, in particular both BSD make and GNU make, should work. If the build fails, look at "configure.local.example" and go back to step 2. -5. Run "make -n install" and check whether everything will be +6. Run "make -n install" and check whether everything will be installed to the intended places. Otherwise, put some *DIR or *NM* -variables into "configure.local" and go back to step 3. +variables into "configure.local" and go back to step 4. -6. Run "sudo make install". If you intend to build a binary +7. Optionally run the regression suite. +Basically, that amounts to "cd regress && ./regress.pl". +But you should probably look at "./mandoc -l regress/regress.pl.1" +first. + +8. Run "sudo make install". If you intend to build a binary package using some kind of fake root mechanism, you may need a command like "make DESTDIR=... install". Read the *-install targets in the "Makefile" to understand how DESTDIR is used. -7. Run the command "sudo -makewhatis" to build mandoc.db(5) databases in all the directory -trees configured in step 6. Whenever installing new manual pages, -re-run makewhatis(8) to update the databases, or apropos(1) will -not find the new pages. +9. Run the command "sudo makewhatis" to build mandoc.db(5) databases +in all the directory trees configured in step 6. Whenever installing +new manual pages, re-run makewhatis(8) to update the databases, or +apropos(1) will not find the new pages. -8. To set up a man.cgi(8) server, read its manual page. +10. To set up a man.cgi(8) server, read its manual page. Note that some man(7) pages may contain low-level roff(7) markup that mandoc does not yet understand. On some BSD systems using @@ -87,9 +97,10 @@ The following libraries are required: 2. The fts(3) directory traversion functions. If your system does not have them, the bundled compatibility version -will be used, so you need not worry in that case. But be careful: the -glibc version of fts(3) is known to be broken on 32bit platforms, -see . +will be used, so you need not worry in that case. But be careful: old +glibc versions of fts(3) were known to be broken on 32bit platforms, +see . +That was presumably fixed in glibc-2.23. If you run into that problem, set "HAVE_FTS=0" in configure.local. 3. Marc Espie's ohash(3) library. diff --git a/LICENSE b/LICENSE index 1dec04b9f4a6..b9efcbba8db3 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -$Id: LICENSE,v 1.13 2016/10/18 14:15:33 schwarze Exp $ +$Id: LICENSE,v 1.14 2017/02/08 12:24:10 schwarze Exp $ With the exceptions noted below, all code and documentation contained in the mdocml toolkit is protected by the Copyright @@ -10,6 +10,7 @@ Copyright (c) 2009, 2010, 2011, 2012 Joerg Sonnenberger Copyright (c) 2013 Franco Fichtner Copyright (c) 2014 Baptiste Daroussin Copyright (c) 2016 Ed Maste +Copyright (c) 2017 Michael Stapelberg Copyright (c) 1999, 2004 Marc Espie Copyright (c) 1998, 2004, 2010 Todd C. Miller Copyright (c) 2008 Otto Moerbeek diff --git a/Makefile b/Makefile index 5c2657c39a95..c11fe465940f 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ -# $Id: Makefile,v 1.493 2016/11/19 15:24:51 schwarze Exp $ +# $Id: Makefile,v 1.504 2017/02/18 15:29:39 schwarze Exp $ # # Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons -# Copyright (c) 2011, 2013-2016 Ingo Schwarze +# Copyright (c) 2011, 2013-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 @@ -15,11 +15,12 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -VERSION = 1.14.0 +VERSION = 1.14.1 # === LIST OF FILES ==================================================== TESTSRCS = test-be32toh.c \ + test-cmsg.c \ test-dirent-namlen.c \ test-EFTYPE.c \ test-err.c \ @@ -30,10 +31,12 @@ TESTSRCS = test-be32toh.c \ test-mkdtemp.c \ test-nanosleep.c \ test-ntohl.c \ + test-O_DIRECTORY.c \ test-ohash.c \ test-PATH_MAX.c \ test-pledge.c \ test-progname.c \ + test-recvmsg.c \ test-reallocarray.c \ test-rewb-bsd.c \ test-rewb-sysv.c \ @@ -49,6 +52,7 @@ TESTSRCS = test-be32toh.c \ test-wchar.c SRCS = att.c \ + catman.c \ cgi.c \ chars.c \ compat_err.c \ @@ -89,6 +93,7 @@ SRCS = att.c \ mandoc.c \ mandoc_aux.c \ mandoc_ohash.c \ + mandocd.c \ mandocdb.c \ manpage.c \ manpath.c \ @@ -128,6 +133,7 @@ DISTFILES = INSTALL \ NEWS \ TODO \ apropos.1 \ + catman.8 \ cgi.h.example \ compat_fts.h \ compat_ohash.h \ @@ -156,6 +162,7 @@ DISTFILES = INSTALL \ man.cgi.8 \ man.conf.5 \ man.h \ + man.options.1 \ manconf.h \ mandoc.1 \ mandoc.3 \ @@ -169,6 +176,7 @@ DISTFILES = INSTALL \ mandoc_html.3 \ mandoc_malloc.3 \ mandoc_ohash.h \ + mandocd.8 \ mansearch.3 \ mansearch.h \ mchars_alloc.3 \ @@ -280,6 +288,12 @@ CGI_OBJS = $(MANDOC_HTML_OBJS) \ cgi.o \ out.o +MANDOCD_OBJS = $(MANDOC_HTML_OBJS) \ + $(MANDOC_TERM_OBJS) \ + mandocd.o \ + out.o \ + tag.o + MANPAGE_OBJS = $(DBM_OBJS) \ manpage.o \ manpath.o @@ -298,6 +312,7 @@ WWW_MANS = apropos.1.html \ man.1.html \ mandoc.1.html \ soelim.1.html \ + man.cgi.3.html \ mandoc.3.html \ mandoc_escape.3.html \ mandoc_headers.3.html \ @@ -311,11 +326,12 @@ WWW_MANS = apropos.1.html \ eqn.7.html \ man.7.html \ mandoc_char.7.html \ + mandocd.8.html \ mdoc.7.html \ roff.7.html \ tbl.7.html \ + catman.8.html \ makewhatis.8.html \ - man.cgi.3.html \ man.cgi.8.html \ man.h.html \ manconf.h.html \ @@ -334,11 +350,7 @@ include Makefile.local # === DEPENDENCY HANDLING ============================================== -all: base-build $(BUILD_TARGETS) Makefile.local - -base-build: mandoc demandoc soelim - -cgi-build: man.cgi +all: mandoc demandoc soelim $(BUILD_TARGETS) Makefile.local install: base-install $(INSTALL_TARGETS) @@ -360,13 +372,14 @@ clean: rm -f libmandoc.a $(LIBMANDOC_OBJS) $(COMPAT_OBJS) rm -f mandoc $(MAIN_OBJS) rm -f man.cgi $(CGI_OBJS) + rm -f mandocd catman $(MANDOCD_OBJS) rm -f manpage $(MANPAGE_OBJS) rm -f demandoc $(DEMANDOC_OBJS) rm -f soelim $(SOELIM_OBJS) rm -f $(WWW_MANS) $(WWW_OBJS) rm -rf *.dSYM -base-install: base-build +base-install: mandoc demandoc soelim mkdir -p $(DESTDIR)$(BINDIR) mkdir -p $(DESTDIR)$(SBINDIR) mkdir -p $(DESTDIR)$(MANDIR)/man1 @@ -375,29 +388,29 @@ base-install: base-build mkdir -p $(DESTDIR)$(MANDIR)/man8 $(INSTALL_PROGRAM) mandoc demandoc $(DESTDIR)$(BINDIR) $(INSTALL_PROGRAM) soelim $(DESTDIR)$(BINDIR)/$(BINM_SOELIM) - ln -f $(DESTDIR)$(BINDIR)/mandoc $(DESTDIR)$(BINDIR)/$(BINM_MAN) - ln -f $(DESTDIR)$(BINDIR)/mandoc $(DESTDIR)$(BINDIR)/$(BINM_APROPOS) - ln -f $(DESTDIR)$(BINDIR)/mandoc $(DESTDIR)$(BINDIR)/$(BINM_WHATIS) - ln -f $(DESTDIR)$(BINDIR)/mandoc \ + $(LN) $(DESTDIR)$(BINDIR)/mandoc $(DESTDIR)$(BINDIR)/$(BINM_MAN) + $(LN) $(DESTDIR)$(BINDIR)/mandoc $(DESTDIR)$(BINDIR)/$(BINM_APROPOS) + $(LN) $(DESTDIR)$(BINDIR)/mandoc $(DESTDIR)$(BINDIR)/$(BINM_WHATIS) + $(LN) $(DESTDIR)$(BINDIR)/mandoc \ $(DESTDIR)$(SBINDIR)/$(BINM_MAKEWHATIS) $(INSTALL_MAN) mandoc.1 demandoc.1 $(DESTDIR)$(MANDIR)/man1 $(INSTALL_MAN) soelim.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_SOELIM).1 $(INSTALL_MAN) man.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_MAN).1 $(INSTALL_MAN) apropos.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_APROPOS).1 - ln -f $(DESTDIR)$(MANDIR)/man1/$(BINM_APROPOS).1 \ + $(LN) $(DESTDIR)$(MANDIR)/man1/$(BINM_APROPOS).1 \ $(DESTDIR)$(MANDIR)/man1/$(BINM_WHATIS).1 - $(INSTALL_MAN) man.conf.5 $(DESTDIR)$(MANDIR)/man5/${MANM_MANCONF}.5 + $(INSTALL_MAN) man.conf.5 $(DESTDIR)$(MANDIR)/man5/$(MANM_MANCONF).5 $(INSTALL_MAN) mandoc.db.5 $(DESTDIR)$(MANDIR)/man5 - $(INSTALL_MAN) man.7 $(DESTDIR)$(MANDIR)/man7/${MANM_MAN}.7 - $(INSTALL_MAN) mdoc.7 $(DESTDIR)$(MANDIR)/man7/${MANM_MDOC}.7 - $(INSTALL_MAN) roff.7 $(DESTDIR)$(MANDIR)/man7/${MANM_ROFF}.7 - $(INSTALL_MAN) eqn.7 $(DESTDIR)$(MANDIR)/man7/${MANM_EQN}.7 - $(INSTALL_MAN) tbl.7 $(DESTDIR)$(MANDIR)/man7/${MANM_TBL}.7 + $(INSTALL_MAN) man.7 $(DESTDIR)$(MANDIR)/man7/$(MANM_MAN).7 + $(INSTALL_MAN) mdoc.7 $(DESTDIR)$(MANDIR)/man7/$(MANM_MDOC).7 + $(INSTALL_MAN) roff.7 $(DESTDIR)$(MANDIR)/man7/$(MANM_ROFF).7 + $(INSTALL_MAN) eqn.7 $(DESTDIR)$(MANDIR)/man7/$(MANM_EQN).7 + $(INSTALL_MAN) tbl.7 $(DESTDIR)$(MANDIR)/man7/$(MANM_TBL).7 $(INSTALL_MAN) mandoc_char.7 $(DESTDIR)$(MANDIR)/man7 $(INSTALL_MAN) makewhatis.8 \ $(DESTDIR)$(MANDIR)/man8/$(BINM_MAKEWHATIS).8 -lib-install: base-build +lib-install: libmandoc.a mkdir -p $(DESTDIR)$(LIBDIR) mkdir -p $(DESTDIR)$(INCLUDEDIR) mkdir -p $(DESTDIR)$(MANDIR)/man3 @@ -407,13 +420,70 @@ lib-install: base-build $(INSTALL_MAN) mandoc.3 mandoc_escape.3 mandoc_malloc.3 \ mansearch.3 mchars_alloc.3 tbl.3 $(DESTDIR)$(MANDIR)/man3 -cgi-install: cgi-build +cgi-install: man.cgi mkdir -p $(DESTDIR)$(CGIBINDIR) mkdir -p $(DESTDIR)$(HTDOCDIR) $(INSTALL_PROGRAM) man.cgi $(DESTDIR)$(CGIBINDIR) $(INSTALL_DATA) mandoc.css $(DESTDIR)$(HTDOCDIR) -Makefile.local config.h: configure ${TESTSRCS} +catman-install: mandocd catman + mkdir -p $(DESTDIR)$(SBINDIR) + mkdir -p $(DESTDIR)$(MANDIR)/man8 + $(INSTALL_PROGRAM) mandocd $(DESTDIR)$(SBINDIR) + $(INSTALL_PROGRAM) catman $(DESTDIR)$(SBINDIR)/$(BINM_CATMAN) + $(INSTALL_MAN) mandocd.8 $(DESTDIR)$(MANDIR)/man8 + $(INSTALL_MAN) catman.8 $(DESTDIR)$(MANDIR)/man8/$(BINM_CATMAN).8 + +uninstall: + rm -f $(DESTDIR)$(BINDIR)/mandoc + rm -f $(DESTDIR)$(BINDIR)/demandoc + rm -f $(DESTDIR)$(BINDIR)/$(BINM_SOELIM) + rm -f $(DESTDIR)$(BINDIR)/$(BINM_MAN) + rm -f $(DESTDIR)$(BINDIR)/$(BINM_APROPOS) + rm -f $(DESTDIR)$(BINDIR)/$(BINM_WHATIS) + rm -f $(DESTDIR)$(SBINDIR)/$(BINM_MAKEWHATIS) + rm -f $(DESTDIR)$(MANDIR)/man1/mandoc.1 + rm -f $(DESTDIR)$(MANDIR)/man1/demandoc.1 + rm -f $(DESTDIR)$(MANDIR)/man1/$(BINM_SOELIM).1 + rm -f $(DESTDIR)$(MANDIR)/man1/$(BINM_MAN).1 + rm -f $(DESTDIR)$(MANDIR)/man1/$(BINM_APROPOS).1 + rm -f $(DESTDIR)$(MANDIR)/man1/$(BINM_WHATIS).1 + rm -f $(DESTDIR)$(MANDIR)/man5/$(MANM_MANCONF).5 + rm -f $(DESTDIR)$(MANDIR)/man5/mandoc.db.5 + rm -f $(DESTDIR)$(MANDIR)/man7/$(MANM_MAN).7 + rm -f $(DESTDIR)$(MANDIR)/man7/$(MANM_MDOC).7 + rm -f $(DESTDIR)$(MANDIR)/man7/$(MANM_ROFF).7 + rm -f $(DESTDIR)$(MANDIR)/man7/$(MANM_EQN).7 + rm -f $(DESTDIR)$(MANDIR)/man7/$(MANM_TBL).7 + rm -f $(DESTDIR)$(MANDIR)/man7/mandoc_char.7 + rm -f $(DESTDIR)$(MANDIR)/man8/$(BINM_MAKEWHATIS).8 + rm -f $(DESTDIR)$(CGIBINDIR)/man.cgi + rm -f $(DESTDIR)$(HTDOCDIR)/mandoc.css + rm -f $(DESTDIR)$(SBINDIR)/mandocd + rm -f $(DESTDIR)$(SBINDIR)/$(BINM_CATMAN) + rm -f $(DESTDIR)$(MANDIR)/man8/mandocd.8 + rm -f $(DESTDIR)$(MANDIR)/man8/$(BINM_CATMAN).8 + rm -f $(DESTDIR)$(LIBDIR)/libmandoc.a + rm -f $(DESTDIR)$(MANDIR)/man3/mandoc.3 + rm -f $(DESTDIR)$(MANDIR)/man3/mandoc_escape.3 + rm -f $(DESTDIR)$(MANDIR)/man3/mandoc_malloc.3 + rm -f $(DESTDIR)$(MANDIR)/man3/mansearch.3 + rm -f $(DESTDIR)$(MANDIR)/man3/mchars_alloc.3 + rm -f $(DESTDIR)$(MANDIR)/man3/tbl.3 + rm -f $(DESTDIR)$(INCLUDEDIR)/man.h + rm -f $(DESTDIR)$(INCLUDEDIR)/mandoc.h + rm -f $(DESTDIR)$(INCLUDEDIR)/mandoc_aux.h + rm -f $(DESTDIR)$(INCLUDEDIR)/mdoc.h + rm -f $(DESTDIR)$(INCLUDEDIR)/roff.h + rmdir $(DESTDIR)$(INCLUDEDIR) + +regress: all + cd regress && ./regress.pl + +regress-clean: + cd regress && ./regress.pl . clean + +Makefile.local config.h: configure $(TESTSRCS) @echo "$@ is out of date; please run ./configure" @exit 1 @@ -429,6 +499,12 @@ manpage: $(MANPAGE_OBJS) libmandoc.a man.cgi: $(CGI_OBJS) libmandoc.a $(CC) $(STATIC) -o $@ $(LDFLAGS) $(CGI_OBJS) libmandoc.a $(LDADD) +mandocd: $(MANDOCD_OBJS) libmandoc.a + $(CC) -o $@ $(LDFLAGS) $(MANDOCD_OBJS) libmandoc.a $(LDADD) + +catman: catman.o libmandoc.a + $(CC) -o $@ $(LDFLAGS) catman.o libmandoc.a $(LDADD) + demandoc: $(DEMANDOC_OBJS) libmandoc.a $(CC) -o $@ $(LDFLAGS) $(DEMANDOC_OBJS) libmandoc.a $(LDADD) @@ -453,14 +529,40 @@ depend: config.h Makefile.depend > Makefile.tmp mv Makefile.tmp Makefile.depend +regress-distclean: + @find regress \ + -name '.#*' -o \ + -name '*.orig' -o \ + -name '*.rej' -o \ + -name '*.core' \ + -exec rm -i {} \; + +regress-distcheck: + @find regress ! -type d ! -type f + @find regress -type f \ + ! -path '*/CVS/*' \ + ! -name Makefile \ + ! -name Makefile.inc \ + ! -name '*.in' \ + ! -name '*.out_ascii' \ + ! -name '*.out_utf8' \ + ! -name '*.out_html' \ + ! -name '*.out_lint' \ + ! -path regress/regress.pl \ + ! -path regress/regress.pl.1 + dist: mdocml.sha256 mdocml.sha256: mdocml.tar.gz sha256 mdocml.tar.gz > $@ mdocml.tar.gz: $(DISTFILES) + ls regress/*/*/*.mandoc_* && exit 1 || true mkdir -p .dist/mdocml-$(VERSION)/ $(INSTALL) -m 0644 $(DISTFILES) .dist/mdocml-$(VERSION) + cp -pR regress .dist/mdocml-$(VERSION) + find .dist/mdocml-$(VERSION)/regress \ + -type d -name CVS -print0 | xargs -0 rm -rf chmod 755 .dist/mdocml-$(VERSION)/configure ( cd .dist/ && tar zcf ../$@ mdocml-$(VERSION) ) rm -rf .dist/ diff --git a/Makefile.depend b/Makefile.depend index af1255defdf5..56bd4f986483 100644 --- a/Makefile.depend +++ b/Makefile.depend @@ -1,4 +1,5 @@ att.o: att.c config.h roff.h mdoc.h libmdoc.h +catman.o: catman.c config.h compat_fts.h cgi.o: cgi.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h main.h manconf.h mansearch.h cgi.h chars.o: chars.c config.h mandoc.h mandoc_aux.h mandoc_ohash.h compat_ohash.h libmandoc.h compat_err.o: compat_err.c config.h @@ -39,6 +40,7 @@ man_validate.o: man_validate.c config.h mandoc_aux.h mandoc.h roff.h man.h libma mandoc.o: mandoc.c config.h mandoc.h mandoc_aux.h libmandoc.h mandoc_aux.o: mandoc_aux.c config.h mandoc.h mandoc_aux.h mandoc_ohash.o: mandoc_ohash.c mandoc_aux.h mandoc_ohash.h compat_ohash.h +mandocd.o: mandocd.c config.h mandoc.h roff.h mdoc.h man.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 manconf.h mansearch.h dba_array.h dba.h manpage.o: manpage.c config.h manconf.h mansearch.h manpath.o: manpath.c config.h mandoc_aux.h manconf.h diff --git a/NEWS b/NEWS index 7f5625a7a157..2cea54fe6820 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,131 @@ -$Id: NEWS,v 1.12 2016/07/14 11:09:06 schwarze Exp $ +$Id: NEWS,v 1.20 2017/02/16 14:38:12 schwarze Exp $ This file lists the most important changes in the mdocml.bsd.lv distribution. +Changes in version 1.14.1, released on February XXX, 2017 + + --- MAJOR NEW FEATURES --- + * apropos(1): Reimplement complete semantic search functionality + without the dependency on SQLite3, using only POSIX APIs. + This comes with a completely new mandoc.db(5) file format. + * man(1): Support more than one tag entry for the same search term, + plus some minor improvements to the less(1) :t support. + * -Thtml: Use real macro names for CSS classes. + Systematic cleanup of and many improvements to mandoc.css. + * -Thtml: Produce human readable HTML code by using indentation + and better line breaks. Improve various HTML elements, + and trim several useless ones. + * New catman(8) utility, still somewhat experimental. + * Now includes a portable version of the OpenBSD mandoc regression + suite, see regress/regress.pl.1 for details. + --- REMOVED FUNCTIONALITY --- + * Operating systems that don't provide mmap(3) are no longer supported. + * Drop support for manpath(1). Even if your system has manpath(1), + it is simpler to use MANPATH_DEFAULT in configure.local for + operating system defaults, man.conf(5) for machine-specific + modifications, and ${MANPATH}, -m, and -M for user preferences + than to bother with the complexity of manpath(1). + * makewhatis(8) -p: No longer warn about missing MLINKS since these + are no longer needed for anything. + --- MINOR NEW FEATURES --- + * mdoc(7): Warn about invalid punctuation and content below NAME. + * mdoc(7): Warn about .Xr lacking the second argument (section). + * mdoc(7): Warn about violations of the rule "new sentence, new line". + * roff(7): Warn about trailing whitespace at the end of comments. + * mdoc(7): Improve rendering of double quotes. + * mdoc(7): Always do text production in the validator, never in the + formatters. Cleaner, simpler, shorter, helps NetBSD apropos(1) + and also makes -Ttree output more useful. + * -Ttree: Show metadata and some additional node flags. + New -Onoval output option to show the unvalidated tree. + --- RELIABILITY BUGFIXES --- + * man(1): Make "man -l" work with standard input from a pipe or file, + as long as standard output is a terminal. + * man(7): Fix out of bounds read access if a text node immediately + preceded the first .SH header. + * mdoc(7): Fix out of bounds read access for .Bl without a type + but with a width. + * mdoc(7): Fix out of bounds read access for .Bl -column starting + with a tab character instead of a child .It macro. + * mdoc(7): Fix syntax tree corruption leading to segfaults caused + by stray block end macros in nested blocks of mismatching type. + * man(1): Fix NULL dereference when the first of multiple pages + shown was preformatted. + * mdoc(7): Fix syntax tree corruption leading to NULL dereference + caused by partial implicit macros inside .Bl -column table cells. + * mdoc(7): Fix syntax tree corruption leading to NULL dereference + for macro sequences like .Bl .Bl .It Bo .El .It. + * mdoc(7): Fix syntax tree corruption leading to NULL dereference + caused by .Ta following a nested .Bl -column breaking another block. + * mdoc(7): Fix syntax tree corruption sometimes leading to NULL + dereference caused by indirectly broken .Nd or .Nm blocks. + * mdoc(7) -Thtml: Fix a NULL dereference for .Bl -column with 0 columns. + * mdoc(7): Fix NULL dereference in some specific cases of a + block-end macro calling another block-end macro. + * mdoc(7): Fix NULL dereference if the only child of the head + of the first .Sh was an empty in-line macro. + * eqn(7): Fix NULL dereference in the terminal formatter + for empty matrices and empty square roots. + * mdoc(7): Fix an assertion failure for a .Bd without a type that + breaks another block. + * mdoc(7): Fix an assertion failure that happened for some .Bl -column + lists containing a column width of "-4n", "-3n", or "-2n". + * mdoc(7): Fix an assertion failure caused by .Bl -column without .It + but containing eqn(7) or tbl(7) code. + * roff(7): Fix an assertion failure caused by \z\[u00FF] with -Tps/-Tpdf. + * roff(7): Fix an assertion failures caused by whitespace inside \o'' + (overstrike) sequences. + * -Thtml: Fix an assertion failure caused by -Oman or -Oincludes of + excessive length. + --- PORTABILITY IMPROVEMENTS --- + * man(1): Do not mix stdio narrow and wide stream orientation + on stdout, which could cause output corruption on glibc. + * mandoc(1): Autodetect a suitable locale for -Tutf8 mode. + * ./configure: Autodetect whether PATH_MAX and O_DIRECTORY are defined. + * ./configure: Autodetect if nanosleep(3) needs -lrt. + * ./configure: Provide an ${LN} configuration variable. + * ./configure: Put compiler arguments that may contain -l at the end. + --- MINOR BUGFIXES --- + * mdoc(7): Fix SYNOPSIS output if the first child of .Nm is a macro. + * mdoc(7) -Thtml: Improve formatting of .Bl -tag with short tags. + * man(7) -Thtml: Preserve whitespace in .nf (nofill) mode. + * mandoc(1): Error out on invalid output options on the command line. + --- STRUCTURAL CHANGES, no functional change --- + * Redesign part of the mandoc_html(3) interfaces, making them much + easier to use and reducing the amount of code by a few hundred lines. + --- THANKS TO --- + * Michael Stapelberg (Debian) for designing the new mandocd(8) + and parts of the new catman(8), and for a number of patches + and bug reports. + * Baptiste Daroussin (FreeBSD) for profiling the new makewhatis(8) + implementation and suggesting an algorithmic improvement which + more than doubled performance, and for a few bug reports. + * Ed Maste (FreeBSD) for an important patch improving reproducibility + of builds in makewhatis(8), and for a few bug reports. + * Theo Buehler (OpenBSD) for more than ten important bug reports, + most of them found by systematic afl(1) fuzzing. + * Benny Lofgren, David Dahlberg, and in particular Vadim Zhukov + for crucial help in getting .Bl -tag CSS formatting fixed. + * Svyatoslav Mishyn (Crux Linux) for an initial version of the + patch to autodetect a suitable locale for -Tutf8 mode. + * Jason McIntyre (OpenBSD) for multiple useful discussions + and a number of bug reports. + * Alexander Bluhm, Andrew Fresh, Antoine Jacoutot, Antony Bentley, + Christian Weisgerber, Jonathan Gray, Marc Espie, Martijn van Duren, + Stuart Henderson, Ted Unangst, Theo de Raadt (OpenBSD), Abhinav + Upadhyay, Christos Zoulas, Kamil Rytarowski, Sevan Janiyan, + Thomas Klausner (NetBSD), Aaron M. Ucko, Bdale Garbee, Reiner + Herrmann, Shane Kerr (Debian), Leah Neukirchen (Void Linux), + Daniel Sabogal (Alpine Linux), Yuri Pankov (illumos), + Carsten Kunze (Heirloom roff), Kristaps Dzonsons (bsd.lv), + Anton Lindqvist, Jan Stary, Jeremy A. Mates, Mark Patruck, + Pavan Maddamsetti, Sean Levy , and + Tiago Silva for bug reports. + * Brent Cook, Marc Espie, Philip Guenther, Todd Miller (OpenBSD) + and Markus Waldeck for useful discussions. + * And as usual, OpenCSW for providing me with a Solaris 9/10/11 + testing environment. + Changes in version 1.13.4, released on July 14, 2016 --- MAJOR NEW FEATURES --- @@ -109,7 +233,7 @@ Changes in version 1.13.4, released on July 14, 2016 again resulting in more than half a dozen important bug reports. * Svyatoslav Mishyn (Crux Linux) for some patches, several bug reports, and extensive release testing. - * Christian Neukirchen (void Linux) for a number of compatibility + * Leah Neukirchen (Void Linux) for a number of compatibility patches and suggestions and several bug reports. * Christos Zoulas (NetBSD) for a bug fix patch and some useful suggestions for cleanup. diff --git a/TODO b/TODO index 181c43100ab2..13a57f2b600f 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,6 @@ ************************************************************************ * Official mandoc TODO. -* $Id: TODO,v 1.223 2017/01/17 15:32:43 schwarze Exp $ +* $Id: TODO,v 1.234 2017/02/18 11:53:33 schwarze Exp $ ************************************************************************ Many issues are annotated for difficulty as follows: @@ -193,10 +193,6 @@ are mere guesses, and some may be wrong. uqs@ Thu, 2 Jun 2011 11:33:35 +0200 loc * exist ** algo *** size * imp ** ---- missing man features ----------------------------------------------- - -- -T[x]html doesn't stipulate non-collapsing spaces in literal mode - --- missing tbl features ----------------------------------------------- - horizontal lines in the layout still consume data cells @@ -223,13 +219,16 @@ are mere guesses, and some may be wrong. - support mdoc(7) and man(7) macros inside tbl(7) code; probably requires the parser reorg and letting tbl(7) use roff_node such that macro sets can mix; - informed by bapt@ that FreeBSD needs this. + informed by bapt@ that FreeBSD needs this: 3 Jan 2015 23:32:23 +0100 loc *** exist ** algo *** size ** imp *** - look at the POSIX manuals in the books/man-pages-posix port, they use some unsupported tbl(7) features. loc * exist ** algo ** size ** imp *** +- look what Joerg Schilling manual pages use + Thu, 19 Mar 2015 18:31:48 +0100 + - use Unicode U+2500 to U+256C for table borders in tbl(7) -Tutf-8 output suggested by bentley@ Tue, 14 Oct 2014 04:10:55 -0600 @@ -263,15 +262,6 @@ are mere guesses, and some may be wrong. even for apropos title line output; req by bapt@ loc * exist * algo * size * imp *** -- makewhatis(8) for preformatted pages: - parse the section number from the header line - and compare to the section number from the directory name - loc * exist * algo * size * imp ** - -- Does makewhatis(8) detect missing NAME sections, missing names, - and missing descriptions in all the file formats? - loc * exist * algo * size * imp *** - - clean up escape sequence handling, creating three classes: (1) fully implemented, or parsed and ignored without loss of content (2) unimplemented, potentially causing loss of content @@ -300,6 +290,8 @@ are mere guesses, and some may be wrong. - look at AT&T DWB http://www2.research.att.com/sw/download Carsten Kunze has patches Mon, 4 Aug 2014 17:01:28 +0200 + ported version: https://github.com/n-t-roff/DWB3.3 + Carsten Kunze Wed, 22 Apr 2015 11:21:43 +0200 - look at pages generated from reStructeredText, e.g. devel/mercurial hg(1) These are a weird mixture of man(7) and custom autogenerated low-level @@ -334,6 +326,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 features of the Slackware man.conf(5) format + Carsten Kunze Wed, 11 Mar 2015 17:57:24 +0100 + ************************************************************************ * formatting issues: ugly output ************************************************************************ @@ -394,7 +389,7 @@ are mere guesses, and some may be wrong. reveals lots of bugs both in groff and mandoc... reported by bentley@ Wed, 22 May 2013 23:49:30 -0600 ---- PDF issues --------------------------------------------------------- +--- PostScript and PDF issues ------------------------------------------ - PDF output doesn't use a monospaced font for .Bd -literal Example: "mandoc -Tpdf afterboot.8 > output.pdf && pdfviewer output.pdf". @@ -404,21 +399,11 @@ are mere guesses, and some may be wrong. instructions from juanfra@ Wed, 11 Jun 2014 02:21:01 +0200 add a new <> block to the PDF files with /BaseFont /Courier and change the /Name from /F0 to the new font (/F5 (?)). + re-reported by tb@ Mon, 16 Mar 2015 16:47:21 +0100 loc * exist ** algo ** size * imp ** --- HTML issues -------------------------------------------------------- --
formatting is ugly - hints are easy to find on the web, e.g. - http://stackoverflow.com/questions/1713048/ - see also matthew@ Fri, 18 Jul 2014 19:25:12 -0700 - loc * exist * algo ** size * imp *** - -- In -man -Thtml, .nf does not preserve indentation. - It should either convert blanks to   - or use
 rather than 
(like .Bd -literal does). - Reported by afresh1@ 12 Apr 2016 14:35:45 -0700 - - .Bf at the beginning of a paragraph inserts a bogus 1ex horizontal space, see for example random(3). Introduced in http://mdocml.bsd.lv/cgi-bin/cvsweb/mdoc_html.c.diff?r1=1.91&r2=1.92 @@ -427,6 +412,9 @@ are mere guesses, and some may be wrong. - jsg on icb, Nov 3, 2014: try to guess Xr in man(7) for hyperlinking + and render them with + https://github.com/Debian/debiman/issues/15 + loc * exist * algo ** size ** imp ** - The tables used to render the three-part page headers actually force the width of the to the max-width given for . @@ -435,9 +423,6 @@ are mere guesses, and some may be wrong. http://undeadly.org/cgi?action=article&sid=20140925064244&pid=1 loc * exist * algo ** size * imp *** -- consider whether can be used for Ar Dv Er Ev Fa Va. - from bentley@ Wed, 13 Aug 2014 09:17:55 -0600 - - generate tags in HTML idea from florian@ Tue, 7 Apr 2015 00:26:28 +0000 may be possible to implement with .Lk img://something.png alt_text @@ -454,6 +439,9 @@ are mere guesses, and some may be wrong. Steffen Nurpmeso Sat, 08 Nov 2014 13:34:59 +0100 loc * exist ** algo ** size * imp ** +- .Lk formatting for long links with line breaks + Franco Fichtner 8 Oct 2013 00:33:42 +0200 + - In .Bl -enum -width 0n, groff continues one the same line after the number, mandoc breaks the line. mail to kristaps@ Mon, 20 Jul 2009 02:21:39 +0200 @@ -498,6 +486,7 @@ are mere guesses, and some may be wrong. The same applies to .Bl -column column widths; reported again by Nicolas Joly Thu, 1 Mar 2012 13:41:26 +0100 via wiz@ 5 Mar reported again by Franco Fichtner Fri, 27 Sep 2013 21:02:28 +0200 + reported again by Bruce Evans Fri, 17 Feb 2017 21:22:44 +0100 via bapt@ loc *** exist *** algo *** size ** imp *** An easy partial fix would be to just skip the first word if it starts with a dot, including any following white space, when measuring. @@ -508,12 +497,6 @@ are mere guesses, and some may be wrong. we want three blank lines, not two as in mandoc. loc ** exist ** algo ** size * imp ** -- Header lines of excessive length: - Port OpenBSD man_term.c rev. 1.25 to mdoc_term.c - and document it in mdoc(7) and man(7) COMPATIBILITY - found while talking to Chris Bennett - loc * exist * algo * size * imp * - - Sequences of multiple man(7) paragraphs (.PP, .IP) interspersed with .ps and .nf/.fi produce execessive blank lines, see libJudy and graphics/dcmtk. The parser reorg may help with this. @@ -535,21 +518,10 @@ are mere guesses, and some may be wrong. to access the manpath and mandoc.db(3) after parsing. asked for by jmc@ Fri, 4 Dec 2015 22:39:40 +0000 -- Report errors in -O suboption parsing. - loc * exist * algo * size * imp ** - - warn when .Sh or .Ss contain other macros Steffen Nurpmeso, savannah.gnu.org/bugs/index.php?45034 loc * exist * algo * size * imp ** -- check that MANDOCERR_BADTAB is thrown in the right cases, - i.e. when finding a literal tab character in fill mode, - and possibly change the wording of the warning message - to refer to fill mode, not literal mode - See the mail from Werner LEMBERG on the groff list, - Fri, 14 Feb 2014 18:54:42 +0100 (CET) - loc * exist ** algo ** size * imp ** - - warn about attempts to call non-callable macros Steffen Nurpmeso Tue, 11 Nov 2014 22:55:16 +0100 Note that formatting is inconsistent in groff. @@ -558,9 +530,6 @@ are mere guesses, and some may be wrong. all over mdoc_macro.c and all subtly different. loc ** exist ** algo ** size ** imp ** -- warn about "new sentence, new line" - loc ** exist ** algo *** size * imp ** - - mandoc_special does not really check the escape sequence, but just the overall format loc ** exist ** algo *** size ** imp ** @@ -580,13 +549,6 @@ are mere guesses, and some may be wrong. * documentation issues ************************************************************************ -- mention hyphenation rules: - breaking at letter-letter in text mode (not macro args) - proper hyphenation is unimplemented - -- talk about spacing around delimiters - to jmc@, kristaps@ Sat, 23 Apr 2011 17:41:27 +0200 - - mark macros as: page structure domain, manual domain, general text domain is this useful? @@ -606,14 +568,8 @@ Several areas can be cleaned up to make mandoc even faster. These are - improve hashing mechanism for macros (quite important: performance) -- improve hashing mechanism for characters (not as important) - - the PDF file is HUGE: this can be reduced by using relative offsets -- instead of re-initialising the roff predefined-strings set before each - parse, create a read-only version the first time and copy it - loc * exist ** algo ** size * imp ** - ************************************************************************ * structural issues ************************************************************************ @@ -648,9 +604,6 @@ Several areas can be cleaned up to make mandoc even faster. These are output through libz. - Sandbox (see OpenSSH). - Enable caching support via HTTP 304 and If-Modified-Since. - - Allow for cgi.h to be overridden by CGI environment variables. - Otherwise, binary distributions will inherit the compile-time - behaviour, which is not optimal. - Have Mac OSX systems automatically disable -static compilation of the CGI: -static isn't supported. diff --git a/apropos.1 b/apropos.1 index 10ba3c6a454d..8f51030ec0c8 100644 --- a/apropos.1 +++ b/apropos.1 @@ -1,4 +1,4 @@ -.\" $Id: apropos.1,v 1.39 2015/04/03 08:46:17 schwarze Exp $ +.\" $Id: apropos.1,v 1.40 2017/01/31 19:44:04 schwarze Exp $ .\" .\" Copyright (c) 2011, 2012 Kristaps Dzonsons .\" Copyright (c) 2011, 2012, 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: April 3 2015 $ +.Dd $Mdocdate: January 31 2017 $ .Dt APROPOS 1 .Os .Sh NAME @@ -468,6 +468,10 @@ and in .Ox 5.6 for .Nm whatis . +The options +.Fl acfhIKklOTWw +appeared in +.Ox 5.7 . .Sh AUTHORS .An -nosplit .An Bill Joy diff --git a/catman.8 b/catman.8 new file mode 100644 index 000000000000..1de1096a3e4a --- /dev/null +++ b/catman.8 @@ -0,0 +1,186 @@ +.\" $Id: catman.8,v 1.7 2017/02/06 19:04:21 schwarze Exp $ +.\" +.\" Copyright (c) 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. +.\" +.Dd $Mdocdate: February 6 2017 $ +.Dt CATMAN 8 +.Os +.Sh NAME +.Nm catman +.Nd format all manual pages below a directory +.Sh SYNOPSIS +.Nm catman +.Op Fl I Cm os Ns = Ns Ar name +.Op Fl T Ar output +.Ar srcdir dstdir +.Sh DESCRIPTION +The +.Nm +utility assumes that all files below +.Ar srcdir +are manual pages in +.Xr mdoc 7 +and +.Xr man 7 +format and formats all of them, storing the formatted versions in +the same relative paths below +.Ar dstdir . +Subdirectories of +.Ar dstdir +are created as needed. +Existing files are not explicitly deleted, but possibly overwritten. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl I Cm os Ns = Ns Ar name +Override the default operating system +.Ar name +for the +.Xr mdoc 7 +.Ic Os +and for the +.Xr man 7 +.Ic TH +macro. +.It Fl T Ar output +Output format. +The +.Ar output +argument can be +.Cm ascii , +.Cm utf8 , +or +.Cm html ; +see +.Xr mandoc 1 . +In +.Cm html +output mode, the +.Cm fragment +output option is implied. +Other output options are not supported. +.El +.Sh IMPLEMENTATION NOTES +Since this version avoids +.Xr fork 2 +and +.Xr exec 3 +overhead and uses the much faster +.Sy mandoc +parsers and formatters rather than +.Sy groff , +it may be about one order of magnitude faster than other +.Nm +implementations. +.Sh EXIT STATUS +.Ex -std +.Pp +Possible errors include: +.Bl -bullet +.It +missing, invalid, or excessive command line arguments +.It +failure to change the current working directory to +.Ar srcdir +.It +failure to open +.Ar dstdir +.It +communication failure with +.Xr mandocd 8 +.It +resource exhaustion, for example file descriptor, process table, +or memory exhaustion +.El +.Pp +Except for memory exhaustion and similar system-level failures, +failures while trying to open, read, parse, or format individual +manual pages, to save individual formatted files to the file system, +or even to create directories do not cause +.Nm +to return an error exit status. +In such cases, +.Nm +will simply continue with the next file or subdirectory. +.Sh SEE ALSO +.Xr mandoc 1 , +.Xr mandocd 8 +.Sh HISTORY +A +.Nm +utility first appeared in +.Fx 1.0 . +Other, incompatible implementations appeared in +.Nx 1.0 +and in +.Sy man-db No 2.2 . +.Pp +This version appeared in version 1.14.1 of the +.Sy mandoc +toolkit. +.Sh AUTHORS +.An -nosplit +The first +.Nm +implementation was a short shell script by +.An Christoph Robitschko +in July 1993. +.Pp +The +.Nx +implementations were written by +.An J. T. Conklin Aq Mt jtc@netbsd.org +in 1993, +.An Christian E. Hopps Aq Mt chopps@netbsd.org +in 1994, +and +.An Dante Profeta Aq Mt dante@netbsd.org +in 1999; the +.Sy man-db +implementation by +.An Graeme W. Wilford +in 1994; and the +.Fx +implementations by +.An Wolfram Schneider Aq Mt wosch@freebsd.org +in 1995 and +.An John Rochester Aq Mt john@jrochester.org +in 2002. +.Pp +The concept of the present version was designed and implemented by +.An Michael Stapelberg Aq Mt stapelberg@debian.org +in 2017. +Option and argument handling and directory iteration was added by +.An Ingo Schwarze Aq Mt schwarze@openbsd.org . +.Sh CAVEATS +All versions of +.Nm +are incompatible with each other because each caters to the needs +of a specific operating system, for example regarding directory +structures and file naming conventions. +.Pp +This version is more flexible than the others in so far as it does +not assume any particular directory structure or naming convention. +That flexibility comes at the price of not being able to change the +names and relative paths of the source files when reusing them to +store the formatted files, of not supporting any configuration file +formats or environment variables, and of being unable to scan for +and remove junk files in +.Ar dstdir . +.Pp +Currently, +.Nm +always reformats each page, even if the formatted version is newer +than the source version. diff --git a/catman.c b/catman.c new file mode 100644 index 000000000000..7d62c0e74add --- /dev/null +++ b/catman.c @@ -0,0 +1,260 @@ +/* $Id: catman.c,v 1.21 2017/02/18 12:24:24 schwarze Exp $ */ +/* + * Copyright (c) 2017 Michael Stapelberg + * Copyright (c) 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 AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#if HAVE_CMSG_XPG42 +#define _XPG4_2 +#endif + +#include +#include +#include + +#if HAVE_ERR +#include +#endif +#include +#include +#if HAVE_FTS +#include +#else +#include "compat_fts.h" +#endif +#include +#include +#include +#include +#include + +int process_manpage(int, int, const char *); +int process_tree(int, int); +void run_mandocd(int, const char *, const char *) + __attribute__((__noreturn__)); +ssize_t sock_fd_write(int, int, int, int); +void usage(void) __attribute__((__noreturn__)); + + +void +run_mandocd(int sockfd, const char *outtype, const char* defos) +{ + char sockfdstr[10]; + + if (snprintf(sockfdstr, sizeof(sockfdstr), "%d", sockfd) == -1) + err(1, "snprintf"); + if (defos == NULL) + execlp("mandocd", "mandocd", "-T", outtype, + sockfdstr, (char *)NULL); + else + execlp("mandocd", "mandocd", "-T", outtype, + "-I", defos, sockfdstr, (char *)NULL); + err(1, "exec"); +} + +ssize_t +sock_fd_write(int fd, int fd0, int fd1, int fd2) +{ + const struct timespec timeout = { 0, 10000000 }; /* 0.01 s */ + struct msghdr msg; + struct iovec iov; + union { + struct cmsghdr cmsghdr; + char control[CMSG_SPACE(3 * sizeof(int))]; + } cmsgu; + struct cmsghdr *cmsg; + int *walk; + ssize_t sz; + unsigned char dummy[1] = {'\0'}; + + iov.iov_base = dummy; + iov.iov_len = sizeof(dummy); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + msg.msg_control = cmsgu.control; + msg.msg_controllen = sizeof(cmsgu.control); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(3 * sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + + walk = (int *)CMSG_DATA(cmsg); + *(walk++) = fd0; + *(walk++) = fd1; + *(walk++) = fd2; + + /* + * It appears that on some systems, sendmsg(3) + * may return EAGAIN even in blocking mode. + * Seen for example on Oracle Solaris 11.2. + * The sleeping time was chosen by experimentation, + * to neither cause more than a handful of retries + * in normal operation nor unnecessary delays. + */ + for (;;) { + if ((sz = sendmsg(fd, &msg, 0)) != -1 || + errno != EAGAIN) + break; + nanosleep(&timeout, NULL); + } + return sz; +} + +int +process_manpage(int srv_fd, int dstdir_fd, const char *path) +{ + int in_fd, out_fd; + int irc; + + if ((in_fd = open(path, O_RDONLY)) == -1) { + warn("open(%s)", path); + return 0; + } + + if ((out_fd = openat(dstdir_fd, path, + O_WRONLY | O_NOFOLLOW | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) { + warn("openat(%s)", path); + close(in_fd); + return 0; + } + + irc = sock_fd_write(srv_fd, in_fd, out_fd, STDERR_FILENO); + + close(in_fd); + close(out_fd); + + if (irc < 0) { + warn("sendmsg"); + return -1; + } + return 0; +} + +int +process_tree(int srv_fd, int dstdir_fd) +{ + FTS *ftsp; + FTSENT *entry; + const char *argv[2]; + const char *path; + + argv[0] = "."; + argv[1] = (char *)NULL; + + if ((ftsp = fts_open((char * const *)argv, + FTS_PHYSICAL | FTS_NOCHDIR, NULL)) == NULL) { + warn("fts_open"); + return -1; + } + + while ((entry = fts_read(ftsp)) != NULL) { + path = entry->fts_path + 2; + switch (entry->fts_info) { + case FTS_F: + if (process_manpage(srv_fd, dstdir_fd, path) == -1) { + fts_close(ftsp); + return -1; + } + break; + case FTS_D: + if (*path != '\0' && + mkdirat(dstdir_fd, path, S_IRWXU | S_IRGRP | + S_IXGRP | S_IROTH | S_IXOTH) == -1 && + errno != EEXIST) { + warn("mkdirat(%s)", path); + (void)fts_set(ftsp, entry, FTS_SKIP); + } + break; + case FTS_DP: + break; + default: + warnx("%s: not a regular file", path); + break; + } + } + + fts_close(ftsp); + return 0; +} + +int +main(int argc, char **argv) +{ + const char *defos, *outtype; + int srv_fds[2]; + int dstdir_fd; + int opt; + pid_t pid; + + defos = NULL; + outtype = "ascii"; + while ((opt = getopt(argc, argv, "I:T:")) != -1) { + switch (opt) { + case 'I': + defos = optarg; + break; + case 'T': + outtype = optarg; + break; + default: + usage(); + } + } + + if (argc > 0) { + argc -= optind; + argv += optind; + } + if (argc != 2) + usage(); + + if (socketpair(AF_LOCAL, SOCK_STREAM, AF_UNSPEC, srv_fds) == -1) + err(1, "socketpair"); + + pid = fork(); + switch (pid) { + case -1: + err(1, "fork"); + case 0: + close(srv_fds[0]); + run_mandocd(srv_fds[1], outtype, defos); + default: + break; + } + close(srv_fds[1]); + + if ((dstdir_fd = open(argv[1], O_RDONLY | O_DIRECTORY)) == -1) + err(1, "open(%s)", argv[1]); + + if (chdir(argv[0]) == -1) + err(1, "chdir(%s)", argv[0]); + + return process_tree(srv_fds[0], dstdir_fd) == -1 ? 1 : 0; +} + +void +usage(void) +{ + fprintf(stderr, "usage: %s [-I os=name] [-T output] " + "srcdir dstdir\n", BINM_CATMAN); + exit(1); +} diff --git a/cgi.c b/cgi.c index 06beca3fce5a..3303d00100b9 100644 --- a/cgi.c +++ b/cgi.c @@ -1,4 +1,4 @@ -/* $Id: cgi.c,v 1.144 2017/01/21 01:20:31 schwarze Exp $ */ +/* $Id: cgi.c,v 1.147 2017/02/08 13:34:27 schwarze Exp $ */ /* * Copyright (c) 2011, 2012 Kristaps Dzonsons * Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze @@ -21,7 +21,9 @@ #include #include +#if HAVE_ERR #include +#endif #include #include #include @@ -113,7 +115,7 @@ static const char *const sec_names[] = { static const int sec_MAX = sizeof(sec_names) / sizeof(char *); static const char *const arch_names[] = { - "amd64", "alpha", "armv7", + "amd64", "alpha", "armv7", "arm64", "hppa", "i386", "landisk", "loongson", "luna88k", "macppc", "mips64", "octeon", "sgi", "socppc", "sparc64", @@ -799,6 +801,7 @@ 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"); usepath = strcmp(req->q.manpath, req->p[0]); mandoc_asprintf(&conf.man, "/%s%s%%N.%%S", usepath ? req->q.manpath : "", usepath ? "/" : ""); @@ -826,6 +829,7 @@ resp_format(const struct req *req, const char *file) mparse_free(mp); mchars_free(); free(conf.man); + free(conf.style); } static void diff --git a/chars.c b/chars.c index c2cfaf818444..f1f5d5d78ca8 100644 --- a/chars.c +++ b/chars.c @@ -1,4 +1,4 @@ -/* $Id: chars.c,v 1.68 2015/10/13 22:59:54 schwarze Exp $ */ +/* $Id: chars.c,v 1.69 2017/02/17 18:28:06 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2011, 2014, 2015 Ingo Schwarze @@ -101,8 +101,8 @@ static struct ln lines[] = { { "bq", ",", 0x201a }, { "lq", "\"", 0x201c }, { "rq", "\"", 0x201d }, - { "Lq", "``", 0x201c }, - { "Rq", "''", 0x201d }, + { "Lq", "\"", 0x201c }, + { "Rq", "\"", 0x201d }, { "oq", "`", 0x2018 }, { "cq", "\'", 0x2019 }, { "aq", "\'", 0x0027 }, diff --git a/compat_fts.c b/compat_fts.c index c2cc9570c545..3859111a52f8 100644 --- a/compat_fts.c +++ b/compat_fts.c @@ -6,7 +6,7 @@ int dummy; #else -/* $Id: compat_fts.c,v 1.12 2016/10/18 23:58:12 schwarze Exp $ */ +/* $Id: compat_fts.c,v 1.14 2017/02/18 12:24:24 schwarze Exp $ */ /* $OpenBSD: fts.c,v 1.56 2016/09/21 04:38:56 guenther Exp $ */ /*- @@ -63,15 +63,9 @@ static FTSENT *fts_sort(FTS *, FTSENT *, int); static unsigned short fts_stat(FTS *, FTSENT *); #define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) -#ifndef O_DIRECTORY -#define O_DIRECTORY 0 -#endif #ifndef O_CLOEXEC #define O_CLOEXEC 0 #endif -#ifndef PATH_MAX -#define PATH_MAX 4096 -#endif #define CLR(opt) (sp->fts_options &= ~(opt)) #define ISSET(opt) (sp->fts_options & (opt)) @@ -84,7 +78,7 @@ fts_open(char * const *argv, int options, FTS *sp; FTSENT *p, *root; int nitems; - FTSENT *parent, *tmp; + FTSENT *parent, *prev; /* Options check. */ if (options & ~FTS_OPTIONMASK) { @@ -117,7 +111,7 @@ fts_open(char * const *argv, int options, parent->fts_level = FTS_ROOTPARENTLEVEL; /* Allocate/initialize root(s). */ - for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) { + for (root = prev = NULL, nitems = 0; *argv; ++argv, ++nitems) { if ((p = fts_alloc(sp, *argv, strlen(*argv))) == NULL) goto mem3; p->fts_level = FTS_ROOTLEVEL; @@ -139,11 +133,10 @@ fts_open(char * const *argv, int options, } else { p->fts_link = NULL; if (root == NULL) - tmp = root = p; - else { - tmp->fts_link = p; - tmp = p; - } + root = p; + else + prev->fts_link = p; + prev = p; } } if (compar && nitems > 1) diff --git a/configure b/configure index 1b8101582822..588cab12bac2 100755 --- a/configure +++ b/configure @@ -1,8 +1,8 @@ #!/bin/sh # -# $Id: configure,v 1.55 2017/01/12 15:45:05 schwarze Exp $ +# $Id: configure,v 1.61 2017/02/18 12:24:24 schwarze Exp $ # -# Copyright (c) 2014, 2015, 2016 Ingo Schwarze +# Copyright (c) 2014, 2015, 2016, 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 @@ -33,6 +33,8 @@ echo "config.log: writing..." # Initialize all variables here, # such that nothing can leak in from the environment. +SOURCEDIR=`dirname "$0"` + MANPATH_DEFAULT="/usr/share/man:/usr/X11R6/man:/usr/local/man" OSNAME= UTF8_LOCALE= @@ -44,11 +46,15 @@ LDADD= LDFLAGS= LD_NANOSLEEP= LD_OHASH= +LD_RECVMSG= STATIC="-static" BUILD_CGI=0 +BUILD_CATMAN=0 INSTALL_LIBMANDOC=0 +HAVE_CMSG= +HAVE_CMSG_XPG42=0 HAVE_DIRENT_NAMLEN= HAVE_EFTYPE= HAVE_ENDIAN= @@ -61,11 +67,13 @@ HAVE_ISBLANK= HAVE_MKDTEMP= HAVE_NANOSLEEP= HAVE_NTOHL= +HAVE_O_DIRECTORY= HAVE_OHASH= HAVE_PATH_MAX= HAVE_PLEDGE= HAVE_PROGNAME= HAVE_REALLOCARRAY= +HAVE_RECVMSG= HAVE_REWB_BSD= HAVE_REWB_SYSV= HAVE_SANDBOX_INIT= @@ -93,6 +101,7 @@ HTDOCDIR= CGIBINDIR= BINM_APROPOS="apropos" +BINM_CATMAN="catman" BINM_MAKEWHATIS="makewhatis" BINM_MAN="man" BINM_SOELIM="soelim" @@ -109,6 +118,7 @@ INSTALL_PROGRAM= INSTALL_LIB= INSTALL_MAN= INSTALL_DATA= +LN="ln -f" # --- manual settings from configure.local ----------------------------- @@ -148,7 +158,8 @@ ${1}${3}: testing... ${COMP} -o test-${1} test-${1}.c ${3} __HEREDOC__ - if ${COMP} -o "test-${1}" "test-${1}.c" ${3} 1>&3 2>&3; then + if ${COMP} -o "test-${1}" "${SOURCEDIR}/test-${1}.c" ${3} 1>&3 2>&3 + then echo "${1}${3}: ${CC} succeeded" 1>&3 else echo "${1}${3}: ${CC} failed with $?" 1>&3 @@ -211,6 +222,7 @@ runtest getsubopt GETSUBOPT || true runtest isblank ISBLANK || true runtest mkdtemp MKDTEMP || true runtest ntohl NTOHL || true +runtest O_DIRECTORY O_DIRECTORY || true runtest PATH_MAX PATH_MAX || true runtest pledge PLEDGE || true runtest sandbox_init SANDBOX_INIT || true @@ -266,6 +278,36 @@ if [ "${HAVE_NANOSLEEP}" -eq 0 ]; then exit 1 fi +if [ ${BUILD_CATMAN} -gt 0 ]; then + # --- recvmsg --- + if [ -n "${LD_RECVMSG}" ]; then + runtest recvmsg RECVMSG "${LD_RECVMSG}" || true + elif singletest recvmsg RECVMSG; then + : + elif runtest recvmsg RECVMSG "-lsocket"; then + LD_RECVMSG="-lsocket" + fi + if [ "${HAVE_RECVMSG}" -eq 0 ]; then + echo "FATAL: recvmsg: no" 1>&2 + echo "FATAL: recvmsg: no" 1>&3 + echo "Without recvmsg(2), you cannot BUILD_CATMAN." 1>&2 + exit 1 + fi + + # --- cmsg --- + if singletest cmsg CMSG; then + : + elif runtest cmsg CMSG "-D_XPG4_2"; then + HAVE_CMSG_XPG42=1 + fi + if [ "${HAVE_CMSG}" -eq 0 ]; then + echo "FATAL: cmsg: no" 1>&2 + echo "FATAL: cmsg: no" 1>&3 + echo "Without CMSG_FIRSTHDR(3), you cannot BUILD_CATMAN." 1>&2 + exit 1 + fi +fi + # --- ohash --- if ismanual ohash OHASH "${HAVE_OHASH}"; then : @@ -281,7 +323,7 @@ if [ "${HAVE_OHASH}" -eq 0 ]; then fi # --- LDADD --- -LDADD="${LDADD} ${LD_NANOSLEEP} ${LD_OHASH} -lz" +LDADD="${LDADD} ${LD_NANOSLEEP} ${LD_RECVMSG} ${LD_OHASH} -lz" echo "LDADD=\"${LDADD}\"" 1>&2 echo "LDADD=\"${LDADD}\"" 1>&3 echo 1>&3 @@ -318,6 +360,7 @@ echo "#define MANPATH_DEFAULT \"${MANPATH_DEFAULT}\"" [ -n "${UTF8_LOCALE}" ] && echo "#define UTF8_LOCALE \"${UTF8_LOCALE}\"" [ -n "${HOMEBREWDIR}" ] && echo "#define HOMEBREWDIR \"${HOMEBREWDIR}\"" [ ${HAVE_EFTYPE} -eq 0 ] && echo "#define EFTYPE EINVAL" +[ ${HAVE_O_DIRECTORY} -eq 0 ] && echo "#define O_DIRECTORY 0" [ ${HAVE_PATH_MAX} -eq 0 ] && echo "#define PATH_MAX 4096" if [ ${HAVE_ENDIAN} -eq 0 -a ${HAVE_SYS_ENDIAN} -eq 0 ]; then echo "#define be32toh ntohl" @@ -325,6 +368,7 @@ if [ ${HAVE_ENDIAN} -eq 0 -a ${HAVE_SYS_ENDIAN} -eq 0 ]; then fi cat << __HEREDOC__ +#define HAVE_CMSG_XPG42 ${HAVE_CMSG_XPG42} #define HAVE_DIRENT_NAMLEN ${HAVE_DIRENT_NAMLEN} #define HAVE_ENDIAN ${HAVE_ENDIAN} #define HAVE_ERR ${HAVE_ERR} @@ -354,6 +398,7 @@ cat << __HEREDOC__ #define HAVE_OHASH ${HAVE_OHASH} #define BINM_APROPOS "${BINM_APROPOS}" +#define BINM_CATMAN "${BINM_CATMAN}" #define BINM_MAKEWHATIS "${BINM_MAKEWHATIS}" #define BINM_MAN "${BINM_MAN}" #define BINM_SOELIM "${BINM_SOELIM}" @@ -428,10 +473,14 @@ exec > Makefile.local [ -z "${INSTALL_DATA}" ] && INSTALL_DATA="${INSTALL} -m 0444" BUILD_TARGETS= -[ ${BUILD_CGI} -gt 0 ] && BUILD_TARGETS="cgi-build" +[ ${BUILD_CGI} -gt 0 ] && BUILD_TARGETS="man.cgi" +[ ${BUILD_CATMAN} -gt 0 ] && \ + BUILD_TARGETS="${BUILD_TARGETS} mandocd catman" INSTALL_TARGETS= [ ${INSTALL_LIBMANDOC} -gt 0 ] && INSTALL_TARGETS="lib-install" [ ${BUILD_CGI} -gt 0 ] && INSTALL_TARGETS="${INSTALL_TARGETS} cgi-install" +[ ${BUILD_CATMAN} -gt 0 ] && \ + INSTALL_TARGETS="${INSTALL_TARGETS} catman-install" cat << __HEREDOC__ BUILD_TARGETS = ${BUILD_TARGETS} @@ -451,6 +500,7 @@ WWWPREFIX = ${WWWPREFIX} HTDOCDIR = ${HTDOCDIR} CGIBINDIR = ${CGIBINDIR} BINM_APROPOS = ${BINM_APROPOS} +BINM_CATMAN = ${BINM_CATMAN} BINM_MAKEWHATIS = ${BINM_MAKEWHATIS} BINM_MAN = ${BINM_MAN} BINM_SOELIM = ${BINM_SOELIM} @@ -466,6 +516,7 @@ INSTALL_PROGRAM = ${INSTALL_PROGRAM} INSTALL_LIB = ${INSTALL_LIB} INSTALL_MAN = ${INSTALL_MAN} INSTALL_DATA = ${INSTALL_DATA} +LN = ${LN} __HEREDOC__ echo "Makefile.local: written" 1>&2 diff --git a/configure.local.example b/configure.local.example index d5799a5a9e5c..365c700cafa2 100644 --- a/configure.local.example +++ b/configure.local.example @@ -1,6 +1,6 @@ -# $Id: configure.local.example,v 1.22 2016/11/19 15:24:51 schwarze Exp $ +# $Id: configure.local.example,v 1.29 2017/02/18 12:24:24 schwarze Exp $ # -# Copyright (c) 2014, 2015, 2016 Ingo Schwarze +# Copyright (c) 2014, 2015, 2016, 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 @@ -119,6 +119,15 @@ BINM_WHATIS=mwhatis # default is "whatis" BINM_MAKEWHATIS=mandocdb # default is "makewhatis" BINM_SOELIM=msoelim # default is "soelim" +# Some distributions do not want hardlinks +# between installed binary programs. +# Set the following variable to use symbolic links instead. +# It is also used for links between manual pages. +# It is only used by the install* targets. +# When using this, DESTDIR must be empty or an absolute path. + +LN="ln -sf" # default is "ln -f" + # Before falling back to the bundled version of the ohash(3) hashing # library, autoconfiguration tries the following linker flag to # link against your system version. If you do have ohash(3) on @@ -140,6 +149,12 @@ CFLAGS="${CFLAGS} -I/usr/local/include" LD_NANOSLEEP="-lrt" +# Some platforms may need an additional linker flag for recvmsg(2). +# If none is needed or it is -lsocket, it is autodetected. +# Otherwise, set the following variable. + +LD_RECVMSG="-lsocket" + # Some platforms might need additional linker flags to link against # libmandoc that are not autodetected, though no such cases are # currently known. @@ -212,6 +227,20 @@ WWWPREFIX="/var/www" HTDOCDIR="${WWWPREFIX}/htdocs" CGIBINDIR="${WWWPREFIX}/cgi-bin" +# --- user settings related to catman ---------------------------------- + +# By default, building mandocd(8) and catman(8) is disabled. +# To enable it, use the following line. +# It does not work on SunOS 5.10 because there is no mkdirat(2) +# nor on SunOS 5.9 which also lacks CMSG_LEN(3) and CMSG_SPACE(3). + +BUILD_CATMAN=1 + +# Install catman(8) with a different name. +# See BINM_MAN above for details of how this works. + +BINM_CATMAN=mcatman # default is "catman" + # --- settings that rarely need to be touched -------------------------- # Do not set these variables unless you really need to. @@ -250,6 +279,7 @@ HAVE_GETSUBOPT=0 HAVE_ISBLANK=0 HAVE_MKDTEMP=0 HAVE_NTOHL=0 +HAVE_O_DIRECTORY=0 HAVE_OHASH=0 HAVE_PATH_MAX=0 HAVE_PLEDGE=0 diff --git a/dba.c b/dba.c index bb1539b741e9..ee43933de3bf 100644 --- a/dba.c +++ b/dba.c @@ -1,4 +1,4 @@ -/* $Id: dba.c,v 1.9 2017/01/15 15:28:55 schwarze Exp $ */ +/* $Id: dba.c,v 1.10 2017/02/17 14:43:54 schwarze Exp $ */ /* * Copyright (c) 2016, 2017 Ingo Schwarze * @@ -315,8 +315,8 @@ compare_names(const void *vp1, const void *vp2) const char *cp1, *cp2; int diff; - cp1 = *(char **)vp1; - cp2 = *(char **)vp2; + cp1 = *(const char * const *)vp1; + cp2 = *(const char * const *)vp2; return (diff = *cp2 - *cp1) ? diff : strcasecmp(cp1 + 1, cp2 + 1); } @@ -326,8 +326,8 @@ compare_strings(const void *vp1, const void *vp2) { const char *cp1, *cp2; - cp1 = *(char **)vp1; - cp2 = *(char **)vp2; + cp1 = *(const char * const *)vp1; + cp2 = *(const char * const *)vp2; return strcmp(cp1, cp2); } @@ -502,7 +502,7 @@ compare_entries(const void *vp1, const void *vp2) { const struct macro_entry *ep1, *ep2; - ep1 = *(struct macro_entry **)vp1; - ep2 = *(struct macro_entry **)vp2; + ep1 = *(const struct macro_entry * const *)vp1; + ep2 = *(const struct macro_entry * const *)vp2; return strcmp(ep1->value, ep2->value); } diff --git a/dbm_map.c b/dbm_map.c index d158302bad66..87c085d22ec1 100644 --- a/dbm_map.c +++ b/dbm_map.c @@ -1,4 +1,4 @@ -/* $Id: dbm_map.c,v 1.7 2016/10/22 10:09:27 schwarze Exp $ */ +/* $Id: dbm_map.c,v 1.8 2017/02/17 14:43:54 schwarze Exp $ */ /* * Copyright (c) 2016 Ingo Schwarze * @@ -175,7 +175,7 @@ dbm_getint(int32_t offset) int32_t dbm_addr(const void *p) { - return htobe32((char *)p - dbm_base); + return htobe32((const char *)p - dbm_base); } int diff --git a/eqn_term.c b/eqn_term.c index 5f2818b4052b..435801527450 100644 --- a/eqn_term.c +++ b/eqn_term.c @@ -1,7 +1,7 @@ -/* $Id: eqn_term.c,v 1.8 2015/01/01 15:36:08 schwarze Exp $ */ +/* $Id: eqn_term.c,v 1.9 2017/02/12 14:19:01 schwarze Exp $ */ /* * Copyright (c) 2011 Kristaps Dzonsons - * Copyright (c) 2014, 2015 Ingo Schwarze + * 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 @@ -68,8 +68,10 @@ eqn_box(struct termp *p, const struct eqn_box *bp) if (bp->pos == EQNPOS_SQRT) { term_word(p, "sqrt"); - p->flags |= TERMP_NOSPACE; - eqn_box(p, bp->first); + if (bp->first != NULL) { + p->flags |= TERMP_NOSPACE; + eqn_box(p, bp->first); + } } else if (bp->type == EQN_SUBEXPR) { child = bp->first; eqn_box(p, child); @@ -93,7 +95,8 @@ eqn_box(struct termp *p, const struct eqn_box *bp) } } else { child = bp->first; - if (bp->type == EQN_MATRIX && child->type == EQN_LIST) + if (bp->type == EQN_MATRIX && + child != NULL && child->type == EQN_LIST) child = child->first; while (child != NULL) { eqn_box(p, diff --git a/gmdiff b/gmdiff index 8d24fa76cad9..278ce7491f87 100644 --- a/gmdiff +++ b/gmdiff @@ -19,7 +19,7 @@ if [ `id -u` -eq 0 ]; then fi if [ $# -eq 0 ]; then - echo "usage: $0 -h manual_source_file ..." + echo "usage: $0 [-h] manual_source_file ..." exit 1 fi @@ -33,7 +33,7 @@ else EQN="eqn -Tascii" ROFF="groff -ww -Tascii -P -c" fi -MOPT="-Werror $MOPT" +MOPT="-Werror -Tascii $MOPT" while [ -n "$1" ]; do file=$1 diff --git a/html.c b/html.c index 24fd6f471f6e..40f2cc076bf9 100644 --- a/html.c +++ b/html.c @@ -1,4 +1,4 @@ -/* $Id: html.c,v 1.200 2017/01/21 02:29:57 schwarze Exp $ */ +/* $Id: html.c,v 1.207 2017/02/05 20:22:04 schwarze Exp $ */ /* * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons * Copyright (c) 2011-2015, 2017 Ingo Schwarze @@ -65,7 +65,7 @@ static const struct htmldata htmltags[TAG_MAX] = { {"br", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL}, {"a", 0}, {"table", HTML_NLALL | HTML_INDENT}, - {"tbody", HTML_NLALL | HTML_INDENT}, + {"colgroup", HTML_NLALL | HTML_INDENT}, {"col", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL}, {"tr", HTML_NLALL | HTML_INDENT}, {"td", HTML_NLAROUND}, @@ -76,6 +76,8 @@ static const struct htmldata htmltags[TAG_MAX] = { {"dt", HTML_NLAROUND}, {"dd", HTML_NLAROUND | HTML_INDENT}, {"pre", HTML_NLALL | HTML_NOINDENT}, + {"var", 0}, + {"cite", 0}, {"b", 0}, {"i", 0}, {"code", 0}, @@ -114,7 +116,6 @@ static const char *const roffscales[SCALE_MAX] = { static void a2width(const char *, struct roffsu *); static void print_byte(struct html *, char); -static void print_endline(struct html *); static void print_endword(struct html *); static void print_indent(struct html *); static void print_word(struct html *, const char *); @@ -133,7 +134,7 @@ html_alloc(const struct manoutput *outopts) h = mandoc_calloc(1, sizeof(struct html)); - h->tags.head = NULL; + h->tag = NULL; h->style = outopts->style; h->base_man = outopts->man; h->base_includes = outopts->includes; @@ -151,8 +152,8 @@ html_free(void *p) h = (struct html *)p; - while ((tag = h->tags.head) != NULL) { - h->tags.head = tag->next; + while ((tag = h->tag) != NULL) { + h->tag = tag->next; free(tag); } @@ -450,19 +451,19 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) char numbuf[16]; struct tag *t; const char *attr; - char *s; + char *arg1, *arg2; double v; int i, have_style, tflags; tflags = htmltags[tag].flags; - /* Push this tags onto the stack of open scopes. */ + /* Push this tag onto the stack of open scopes. */ if ((tflags & HTML_NOSTACK) == 0) { t = mandoc_malloc(sizeof(struct tag)); t->tag = tag; - t->next = h->tags.head; - h->tags.head = t; + t->next = h->tag; + h->tag = t; } else t = NULL; @@ -495,12 +496,14 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) have_style = 0; while (*fmt != '\0') { if (*fmt == 's') { - print_word(h, " style=\""); have_style = 1; fmt++; break; } - s = va_arg(ap, char *); + + /* Parse a non-style attribute and its arguments. */ + + arg1 = va_arg(ap, char *); switch (*fmt++) { case 'c': attr = "class"; @@ -512,23 +515,31 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) attr = "id"; break; case '?': - attr = s; - s = va_arg(ap, char *); + attr = arg1; + arg1 = va_arg(ap, char *); break; default: abort(); } + arg2 = NULL; + if (*fmt == 'M') + arg2 = va_arg(ap, char *); + if (arg1 == NULL) + continue; + + /* Print the non-style attributes. */ + print_byte(h, ' '); print_word(h, attr); print_byte(h, '='); print_byte(h, '"'); switch (*fmt) { case 'M': - print_href(h, s, va_arg(ap, char *), 1); + print_href(h, arg1, arg2, 1); fmt++; break; case 'I': - print_href(h, s, NULL, 0); + print_href(h, arg1, NULL, 0); fmt++; break; case 'R': @@ -536,7 +547,7 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) fmt++; /* FALLTHROUGH */ default: - print_encode(h, s, NULL, 1); + print_encode(h, arg1, NULL, 1); break; } print_byte(h, '"'); @@ -544,30 +555,37 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) /* Print out styles. */ - s = NULL; - su = &mysu; while (*fmt != '\0') { + arg1 = NULL; + su = NULL; /* First letter: input argument type. */ switch (*fmt++) { case 'h': i = va_arg(ap, int); + su = &mysu; SCALE_HS_INIT(su, i); break; case 's': - s = va_arg(ap, char *); + arg1 = va_arg(ap, char *); break; case 'u': su = va_arg(ap, struct roffsu *); break; case 'v': i = va_arg(ap, int); + su = &mysu; SCALE_VS_INIT(su, i); break; case 'w': - s = va_arg(ap, char *); - a2width(s, su); + case 'W': + if ((arg2 = va_arg(ap, char *)) == NULL) + break; + su = &mysu; + a2width(arg2, su); + if (fmt[-1] == 'W') + su->scale *= -1.0; break; default: abort(); @@ -598,33 +616,37 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) attr = "min-width"; break; case '?': - print_word(h, s); - print_byte(h, ':'); - print_byte(h, ' '); - print_word(h, va_arg(ap, char *)); - print_byte(h, ';'); - if (*fmt != '\0') - print_byte(h, ' '); - continue; + attr = arg1; + arg1 = va_arg(ap, char *); + break; default: abort(); } - v = su->scale; - if (su->unit == SCALE_MM && (v /= 100.0) == 0.0) - v = 1.0; - else if (su->unit == SCALE_BU) - v /= 24.0; + if (su == NULL && arg1 == NULL) + continue; + + if (have_style == 1) + print_word(h, " style=\""); + else + print_byte(h, ' '); print_word(h, attr); print_byte(h, ':'); print_byte(h, ' '); - (void)snprintf(numbuf, sizeof(numbuf), "%.2f", v); - print_word(h, numbuf); - print_word(h, roffscales[su->unit]); + if (su != NULL) { + v = su->scale; + if (su->unit == SCALE_MM && (v /= 100.0) == 0.0) + v = 1.0; + else if (su->unit == SCALE_BU) + v /= 24.0; + (void)snprintf(numbuf, sizeof(numbuf), "%.2f", v); + print_word(h, numbuf); + print_word(h, roffscales[su->unit]); + } else + print_word(h, arg1); print_byte(h, ';'); - if (*fmt != '\0') - print_byte(h, ' '); + have_style = 2; } - if (have_style) + if (have_style == 2) print_byte(h, '"'); va_end(ap); @@ -679,7 +701,7 @@ print_ctag(struct html *h, struct tag *tag) if (tflags & HTML_NLAFTER) print_endline(h); - h->tags.head = tag->next; + h->tag = tag->next; free(tag); } @@ -740,7 +762,7 @@ print_tagq(struct html *h, const struct tag *until) { struct tag *tag; - while ((tag = h->tags.head) != NULL) { + while ((tag = h->tag) != NULL) { print_ctag(h, tag); if (until && tag == until) return; @@ -752,7 +774,7 @@ print_stagq(struct html *h, const struct tag *suntil) { struct tag *tag; - while ((tag = h->tags.head) != NULL) { + while ((tag = h->tag) != NULL) { if (suntil && tag == suntil) return; print_ctag(h, tag); @@ -809,7 +831,7 @@ print_byte(struct html *h, char c) * If something was printed on the current output line, end it. * Not to be called right after print_indent(). */ -static void +void print_endline(struct html *h) { if (h->col == 0) diff --git a/html.h b/html.h index 19532c49d93e..5be2f82db64f 100644 --- a/html.h +++ b/html.h @@ -1,4 +1,4 @@ -/* $Id: html.h,v 1.78 2017/01/19 16:59:30 schwarze Exp $ */ +/* $Id: html.h,v 1.83 2017/02/05 20:22:04 schwarze Exp $ */ /* * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons * Copyright (c) 2017 Ingo Schwarze @@ -30,7 +30,7 @@ enum htmltag { TAG_BR, TAG_A, TAG_TABLE, - TAG_TBODY, + TAG_COLGROUP, TAG_COL, TAG_TR, TAG_TD, @@ -41,6 +41,8 @@ enum htmltag { TAG_DT, TAG_DD, TAG_PRE, + TAG_VAR, + TAG_CITE, TAG_B, TAG_I, TAG_CODE, @@ -78,10 +80,6 @@ struct tag { enum htmltag tag; }; -struct tagq { - struct tag *head; -}; - struct html { int flags; #define HTML_NOSPACE (1 << 0) /* suppress next space */ @@ -100,7 +98,7 @@ struct html { size_t col; /* current output byte position */ size_t bufcol; /* current buf byte position */ char buf[80]; /* output buffer */ - struct tagq tags; /* stack of open tags */ + struct tag *tag; /* last open tag */ struct rofftbl tbl; /* current table */ struct tag *tblt; /* current open table scope */ char *base_man; /* base for manpage href */ @@ -127,5 +125,6 @@ void print_tblclose(struct html *); void print_tbl(struct html *, const struct tbl_span *); void print_eqn(struct html *, const struct eqn *); void print_paragraph(struct html *); +void print_endline(struct html *); int html_strlen(const char *); diff --git a/libmandoc.h b/libmandoc.h index 96e726cbce74..04b3a44565f3 100644 --- a/libmandoc.h +++ b/libmandoc.h @@ -1,4 +1,4 @@ -/* $Id: libmandoc.h,v 1.64 2016/07/19 13:36:13 schwarze Exp $ */ +/* $Id: libmandoc.h,v 1.66 2017/02/18 13:43:52 schwarze Exp $ */ /* * Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons * Copyright (c) 2013, 2014, 2015 Ingo Schwarze @@ -43,7 +43,7 @@ void mandoc_msg(enum mandocerr, struct mparse *, int, int, const char *); void mandoc_vmsg(enum mandocerr, struct mparse *, int, int, const char *, ...) - __attribute__((__format__ (printf, 5, 6))); + __attribute__((__format__ (__printf__, 5, 6))); char *mandoc_getarg(struct mparse *, char **, int, int *); char *mandoc_normdate(struct mparse *, char *, int, int); int mandoc_eos(const char *, size_t); @@ -59,7 +59,7 @@ int man_parseln(struct roff_man *, int, char *, int); void man_endparse(struct roff_man *); int preconv_cue(const struct buf *, size_t); -int preconv_encode(struct buf *, size_t *, +int preconv_encode(const struct buf *, size_t *, struct buf *, size_t *, int *); void roff_free(struct roff *); diff --git a/libmdoc.h b/libmdoc.h index 5a6cc3ed9ba8..ac1521410b55 100644 --- a/libmdoc.h +++ b/libmdoc.h @@ -1,4 +1,4 @@ -/* $Id: libmdoc.h,v 1.108 2015/11/07 14:01:16 schwarze Exp $ */ +/* $Id: libmdoc.h,v 1.109 2017/02/16 03:00:23 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2013, 2014, 2015 Ingo Schwarze @@ -70,7 +70,7 @@ struct roff_node *mdoc_block_alloc(struct roff_man *, int, int, int, struct mdoc_arg *); void mdoc_tail_alloc(struct roff_man *, int, int, int); struct roff_node *mdoc_endbody_alloc(struct roff_man *, int, int, int, - struct roff_node *, enum mdoc_endbody); + struct roff_node *); void mdoc_node_relink(struct roff_man *, struct roff_node *); void mdoc_node_validate(struct roff_man *); void mdoc_state(struct roff_man *, struct roff_node *); diff --git a/main.c b/main.c index b64b3be11501..02abaaf79100 100644 --- a/main.c +++ b/main.c @@ -1,4 +1,4 @@ -/* $Id: main.c,v 1.279 2017/01/09 17:49:57 schwarze Exp $ */ +/* $Id: main.c,v 1.283 2017/02/17 14:31:52 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons * Copyright (c) 2010-2012, 2014-2017 Ingo Schwarze @@ -100,7 +100,7 @@ static void parse(struct curparse *, int, const char *); static void passthrough(const char *, int, int); static pid_t spawn_pager(struct tag_files *); static int toptions(struct curparse *, char *); -static void usage(enum argmode) __attribute__((noreturn)); +static void usage(enum argmode) __attribute__((__noreturn__)); static int woptions(struct curparse *, char *); static const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9}; @@ -113,16 +113,14 @@ int main(int argc, char *argv[]) { struct manconf conf; - struct curparse curp; struct mansearch search; + struct curparse curp; struct tag_files *tag_files; - const char *progname; - char *auxpaths; - char *defos; - unsigned char *uc; struct manpage *res, *resp; - char *conf_file, *defpaths; - const char *sec; + const char *progname, *sec, *thisarg; + char *conf_file, *defpaths, *auxpaths; + char *defos, *oarg; + unsigned char *uc; size_t i, sz; int prio, best_prio; enum outmode outmode; @@ -168,6 +166,7 @@ main(int argc, char *argv[]) memset(&search, 0, sizeof(struct mansearch)); search.outkey = "Nd"; + oarg = NULL; if (strcmp(progname, BINM_MAN) == 0) search.argmode = ARG_NAME; @@ -246,10 +245,7 @@ main(int argc, char *argv[]) auxpaths = optarg; break; case 'O': - search.outkey = optarg; - while (optarg != NULL) - manconf_output(&conf.output, - strsep(&optarg, ",")); + oarg = optarg; break; case 'S': search.arch = optarg; @@ -294,6 +290,21 @@ main(int argc, char *argv[]) } } + if (oarg != NULL) { + if (outmode == OUTMODE_LST) + 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; + } + } + } + if (outmode == OUTMODE_FLN || outmode == OUTMODE_LST || !isatty(STDOUT_FILENO)) @@ -736,7 +747,8 @@ parse(struct curparse *curp, int fd, const char *file) if (man == NULL) return; if (man->macroset == MACROSET_MDOC) { - mdoc_validate(man); + if (curp->outtype != OUTT_TREE || !curp->outopts->noval) + mdoc_validate(man); switch (curp->outtype) { case OUTT_HTML: html_mdoc(curp->outdata, man); @@ -759,7 +771,8 @@ parse(struct curparse *curp, int fd, const char *file) } } if (man->macroset == MACROSET_MAN) { - man_validate(man); + if (curp->outtype != OUTT_TREE || !curp->outopts->noval) + man_validate(man); switch (curp->outtype) { case OUTT_HTML: html_man(curp->outdata, man); diff --git a/man.1 b/man.1 index 191bc9594cc1..67b53d70ed43 100644 --- a/man.1 +++ b/man.1 @@ -1,4 +1,4 @@ -.\" $Id: man.1,v 1.20 2017/01/06 01:34:57 schwarze Exp $ +.\" $Id: man.1,v 1.21 2017/01/31 19:44:04 schwarze Exp $ .\" .\" Copyright (c) 1989, 1990, 1993 .\" The Regents of the University of California. All rights reserved. @@ -31,7 +31,7 @@ .\" .\" @(#)man.1 8.2 (Berkeley) 1/2/94 .\" -.Dd $Mdocdate: January 6 2017 $ +.Dd $Mdocdate: January 31 2017 $ .Dt MAN 1 .Os .Sh NAME @@ -427,9 +427,23 @@ in .Fl C in .Nx 1.0 ; -and .Fl s and .Fl S in -.Ox 2.3 . +.Ox 2.3 ; +and +.Fl I , +.Fl K , +.Fl l , +.Fl O , +and +.Fl W +in +.Ox 5.7 . +The +.Fl T +option first appeared in +.At III +and was also added in +.Ox 5.7 . diff --git a/man.options.1 b/man.options.1 new file mode 100644 index 000000000000..9ad608f5e551 --- /dev/null +++ b/man.options.1 @@ -0,0 +1,1326 @@ +.\" $Id: man.options.1,v 1.6 2017/02/02 20:10:51 schwarze Exp $ +.\" +.\" Copyright (c) 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. +.\" +.Dd $Mdocdate: February 2 2017 $ +.Dt MAN.OPTIONS 1 +.Os +.Sh NAME +.Nm man.options +.Nd assignment of option letters in manual page utilities +.\" +.\" Sources that occur repeatedly. +.\" Only use if the precise implementation time is unknown. +.\" +.de PWB +.No PWB/UNIX 1.0 Pq July 1, 1977 \\$1 +.. +.de At7 +.At v7 Pq January 1979 \\$1 +.. +.de At3 +.At III Pq June 1980 \\$1 +.. +.de Bx4 +.Bx 4 Pq November 16, 1980 \\$1 +.. +.de At5 +.At V Pq January 1983 \\$1 +.. +.de Bx43 +.Bx 4.3 Pq June 1986 \\$1 +.. +.\" option was present in groff-1.01 as contained in 4.3BSD-Net/2 +.\" and no mention of it could be found in the ChangeLog, +.\" so it's probably older than groff-0.4, where the log started +.de g04 +.No probably before groff-0.4 Pq before July 14, 1990 \\$1 +.. +.de Eaton +.No Eaton Pq before July 7, 1993; 1990/91? \\$1 +.. +.\" man-1.5e was released on July 11, 1998. +.de man15e +.No man-1.5e Pq not before 1993, not after 1998 \\$1 +.. +.\" man-1.5g was released on April 7, 1999. +.de man15g +.No man-1.5g Pq not before 1993, not after 1999 \\$1 +.. +.\" code first seen in the initial import of man-db into CVS , +.\" which was more or less debian man-db-2.3.17 +.\" Colin Watson's first release was 2.3.18 on May 14, 2001 +.\" no clue about it found in ChangeLog-2013, +.\" so it was probably already present before man-db-2.2a4 +.de dbI +.No man-db probably before 2.2a4 Pq before Nov 8, 1994 \\$1 +.. +.\" +.\" -------------------------------------------------------------------- +.\" +.Sh DESCRIPTION +This manual page lists option letters used in many different versions +of the +.Nm man , +.Nm apropos , +.Nm whatis , +.Nm mandoc , +.Nm makewhatis , +.Nm mandb , +.Nm makemandb , +.Nm catman , +and +.Nm manpath +utilities. +Option letters used by +.Nm groff , +.Nm nroff , +.Nm troff , +and +.Nm roff +are also included because beginning with +.At v7 , +many versions of +.Xr man 1 +pass on unrecognized options to these programs. +.Pp +For each option letter, information is first grouped into paragraphs, +each paragraph describing similar functionality and starting with +one line briefly summarizing that functionality. +.Pp +For each program using the letter for that functionality, one line +is provided, giving the name of the program, a colon, the system +where this letter first appeared for this functionality in this +program, optionally a comma and a list of other system versions +introducing the same, a semicolon, and a list of current systems +supporting it. +If a system appears before the semicolon, it is not repeated +afterwards. +.Pp +Entries are sorted by historical precedence, except that obsolete +options are moved to the end. +Dates are commit dates where known, and release dates otherwise. +.Bl -tag -width 3n +.It Fl a +display all matching manual pages +.br +.Nm man : +.Bx 4.3 Tahoe Pq June 1988 , +.Eaton ; +.Ox , Fx , Nx , No man-db , man-1.6 , illumos , Solaris 9-11 +.br +.Nm apropos , whatis , mandoc : +.Ox 5.7 Pq August 27, 2014 +.Pp +only display items that match all keywords +.br +.Nm apropos : +.No man-db Pq Aug 29, 2007 +.Pp +use all directories and files for +.Xr mandoc.db 5 +.br +.Nm makewhatis : +.Ox 5.6 Pq April 18, 2014 +.Pp +.Bq superseded by Fl T Cm ascii +ASCII output mode +.br +.Nm troff : +.At7 +.br +.Nm groff : +.g04 +.It Fl B +use specified browser +.br +.Nm man : +.No man-1.6 Pq June 24, 2005 +.It Fl b +print a backtrace with each warning or error message +.br +.Nm groff : +.g04 +.Pp +.Bq obsolete hardware +report whether the phototypesetter is busy +.br +.Nm troff : +.At7 +.It Fl C +alternate configuration file +.br +.Nm apropos , whatis : +.Bx 4.4 Lite1 Pq April 22, 1994 , +.No man-db Pq Feb 22, 2003 ; +.Ox , Nx +.br +.Nm man : +.Nx 1.0 Pq Oct 26, 1994 , +.man15e ; +.Ox +.br +.Nm mandb , catman , manpath : +.No man-db Pq Feb 22, 2003 +.br +.Nm makemandb : +.Nx Pq Feb 7, 2012 +.br +.Nm makewhatis : +.Ox 5.6 Pq April 18, 2014 +.br +.Nm mandoc : +.Ox 5.7 Pq August 27, 2014 +.Pp +.Bq obsolete +enable compatibility mode +.br +.Nm groff : +.No before groff-0.5 Pq before August 3, 1990 +.It Fl c +do not use a pager +.br +.Nm man : +.Bx 4.3 Reno Pq June 1990 ; +.Ox , Nx +.br +.Nm apropos , whatis , mandoc : +.Ox 5.7 Pq August 27, 2014 +.Pp +process given catpath +.br +.Nm makewhatis : +.Pq not before 1992, not after 1995 +.Pp +recreate databases from scratch +.br +.Nm mandb : +.dbI +.Pp +produce a catpath as opposed to a manpath +.br +.Nm manpath : +.dbI +.Pp +internal option for use by +.Xr catman 1 +.br +.Nm man : +.dbI +.Pp +reformat source page even if cat page exists +.br +.Nm man : +.man15e +.Pp +disable terminal color output in +.Xr grotty 1 +.br +.Nm groff : +.No groff-1.18.0 Pq Oct 4, 2001 +.Pp +recreate nroff versions from SGML sources +.br +.Nm catman : +.No Solaris 9-11 +.Pp +.Bq obsolete +postprocess with +.Xr col 1 +.br +.Nm man : +.At3 , +.At5 +.It Fl D +reset whatever was set with +.Ev MANOPT +.br +.Nm man : +.dbI +.Pp +print debugging info in addition to manual page +.br +.Nm man : +.man15e +.Pp +set default input encoding for +.Xr preconv 1 +.br +.Nm groff : +.No groff-1.20 Pq August 20, 2008 +.Pp +display all files added to +.Xr mandoc.db 5 +.br +.Nm makewhatis : +.Ox 5.6 Pq April 18, 2014 +.It Fl d +define a user-defined string +.br +.Nm groff : +.g04 +.Pp +print debugging information +.br +.Nm man : +.Eaton ; +.Fx , No man-db , man-1.6 , illumos , Solaris 9-11 +.br +.Nm manpath : +.Eaton ; +.Fx , No man-db +.br +.Nm apropos , whatis : +.dbI ; +.Fx +.br +.Nm mandb , catman : +.dbI +.Pp +remove and re-add a file to +.Xr mandoc.db 5 +.br +.Nm makewhatis : +.Ox 2.7 Pq Feb 3, 2000 +.Pp +.Bq superseded by Fl l +interpret arguments as file names +.br +.Nm man : +.At3 , +.At5 +.It Fl E +inhibit all error messages +.br +.Nm groff : +.g04 +.Pp +select output encoding +.br +.Nm man : +.No man-db Pq Dec 23, 2001 +.It Fl e +preprocess with +.Xr eqn 7 +.br +.Nm man : +.At7 +.br +.Nm groff : +.g04 +.Pp +adjust text to left and right margins +.br +.Nm nroff : +.At7 +.Pp +use exact matching +.br +.Nm apropos , whatis : +.dbI +.Pp +restrict search by section extension +.br +.Nm man : +.No man-db-2.3.5 Pq April 21, 1995 +.It Fl F +use alternate font directory +.br +.Nm troff : +.Bx 4.2 Pq September 1983 +.br +.Nm groff : +.g04 +.Pp +preformat only, do not display +.br +.Nm man : +.No man-1.5g Pq April 7, 1999 +.Pp +force searching dirs, do not use index (default) +.br +.Nm man : +.No illumos , Solaris 9-11 +.It Fl f +.Xr whatis 1 +mode +.br +.Nm man : +.Bx4 , +.Eaton ; +.Ox , Fx , No man-db , man-1.6 +.br +.Nm apropos , whatis : +.No man-db Pq Dec 2, 2010 , +.Ox 5.7 Pq August 27, 2014 +.br +.Nm mandoc : +.Ox 5.7 Pq August 27, 2014 +.Pp +set the default font family +.br +.Nm groff : +.g04 +.Pp +force formatting even if cat page is newer +.br +.Nm catman : +.Fx Pq March 15, 1995 +.Pp +update only the entries for the given file +.br +.Nm mandb : +.No man-db Pq Feb 21, 2003 +.Pp +force rebuilding the database from scratch +.br +.Nm makemandb : +.Nx Pq Feb 7, 2012 +.Pp +locate manual page related to given file name +.br +.Nm man : +.No illumos , Solaris 9-11 +.Pp +.Bq obsolete hardware +do not feed out paper nor stop phototypesetter +.br +.Nm troff : +.At7 +.It Fl G +preprocess with +.Xr grap 1 +.br +.Nm groff : +.No groff-1.16 Pq May 1, 2000 +.It Fl g +produce a global manpath +.br +.Nm manpath : +.No man-db-2.2a7 Pq Nov 16, 1994 +.Pp +preprocess with +.Xr grn 1 +.br +.Nm groff : +.No groff-1.16 Pq Feb 20, 2000 +.Pp +.Bq obsolete hardware +output to a GCOS phototypesetter +.br +.Nm troff : +.At7 +.Pp +.Bq obsolete hardware +output to a DASI 300 terminal in 12-pitch mode +.br +.Nm man : +.PWB +.It Fl H +read hyphenation patterns from the given file +.br +.Nm groff : +.g04 +.Pp +produce HTML output +.br +.Nm man : +.No man-db-1.3.12 to 1.3.17 Pq not before 1996, not after 2001 +.Pp +use program to render HTML files as text +.br +.Nm man : +.No man-1.6 Pq June 24, 2005 +.It Fl h +print a help message and exit +.br +.Nm groff : +.g04 +.br +.Nm man : +.Eaton ; +.Fx , No man-db , man-1.6 +.br +.Nm manpath : +.Eaton ; +.Fx , No man-db +.br +.Nm apropos , whatis , mandb , catman : +.dbI +.Pp +display the SYNOPSIS lines only +.br +.Nm man : +.Bx 4.3 Net/2 Pq August 20, 1991 ; +.Ox , Nx +.br +.Nm apropos , whatis , mandoc : +.Ox 5.7 Pq Sep 3, 2014 +.Pp +turn on HTML formatting +.br +.Nm apropos : +.Nx Pq Apr 2, 2013 +.Pp +.Bq obsolete +replace spaces by tabs in the output +.br +.Nm roff , nroff : +.At7 +.It Fl I +input file search path for +.Xr soelim 1 +.br +.Nm groff : +.No groff-1.12 Pq Sep 11, 1999 +.Pp +respect case when matching manual page names +.br +.Nm man , catman : +.No man-db Pq Apr 21, 2002 +.Pp +input options, in particular default operating system name +.br +.Nm mandoc : +.Ox 5.2 Pq May 24, 2012 +.br +.Nm man , apropos , whatis : +.Ox 5.7 Pq August 27, 2014 +.It Fl i +read standard input after the input files are exhausted +.br +.Nm nroff , troff : +.At7 +.br +.Nm groff : +.g04 +.Pp +ignore case when matching manual page names +.br +.Nm man , catman : +.No man-db Pq Apr 21, 2002 +.Pp +turn on terminal escape code formatting +.br +.Nm apropos : +.Nx Pq March 29, 2013 +.It Fl J +preprocess with +.Xr gideal 1 +.br +.Nm groff : +.No groff-1.22.3 Pq June 17, 2014 +.It Fl j +preprocess with +.Xr chem 1 +.br +.Nm groff : +.No groff-1.22 Pq Jan 22, 2011 +.It Fl K +source code full text search +.br +.Nm man : +.man15e , +.No man-db Pq June 28, 2009 ; +.No Solaris 11 +.Pp +input encoding +.br +.Nm groff : +.No groff-1.20 Pq Dec 31, 2005 +.br +.Nm man , apropos , whatis , mandoc : +.Ox 5.7 Pq Oct 30, 2014 +.It Fl k +.Xr apropos 1 +mode +.br +.Nm man : +.Bx4 , +.Eaton ; +.No POSIX , Ox , Fx , Nx , No man-db , man-1.6 , illumos , Solaris 9-11 +.br +.Nm apropos , whatis , mandoc : +.Ox 5.7 Pq August 27, 2014 +.Pp +ignore formatting errors +.br +.Nm catman : +.Nx Pq April 26, 1994 +.Pp +preprocess with +.Xr preconv 1 +.br +.Nm groff : +.No groff-1.20 Pq Dec 31, 2005 +.Pp +.Bq obsolete hardware +display on a Tektronix 4014 terminal +.br +.Nm man : +.At7 +.It Fl L +pass argument to the spooler +.br +.Nm groff : +.No groff-0.6 Pq Sep 14, 1990 +.Pp +use alternate +.Xr locale 1 +.br +.Nm man , apropos , whatis : +.No before man-db-2.2a13 Pq before Dec 15, 1994 +.Pp +print list of locales +.br +.Nm manpath : +.Fx Pq Nov 23, 1999 +.Pp +use +.Xr locale 1 +specified in the environment +.br +.Nm catman : +.Fx Pq May 18, 2002 +.It Fl l +spool the output +.br +.Nm groff : +.g04 +.Pp +interpret arguments as file names +.br +.Nm man : +.No before man-2.2a7 Pq before Nov 16, 1994 , +.Ox 5.7 Pq Aug 30, 2014 +.br +.Nm apropos , whatis , mandoc : +.Ox 5.7 Pq Aug 30, 2014 +.Pp +do not trim output to the terminal width +.br +.Nm apropos , whatis : +.No man-db Pq Aug 19, 2007 +.Pp +only parse NAME sections +.br +.Nm makemandb : +.Nx Pq Feb 7, 2012 +.Pp +legacy mode: search Nm,Nd, no context or formatting +.br +.Nm apropos : +.Nx Pq March 29, 2013 +.Pp +list all manual pages matching name within the search path +.br +.Nm man : +.No illumos , Solaris 9-11 +.It Fl M +override manual page search path +.br +.Nm man : +.Bx43 , +.Eaton ; +.Ox , Fx , Nx , No man-db , man-1.6 , illumos , Solaris 9-11 +.br +.Nm apropos , whatis : +.Bx43 , +.No before man-db-2.2a14 Pq before Dec 16, 1994 ; +.Ox , No illumos +.br +.Nm catman : +.dbI ; +.Nx Pq July 27, 1993 , +.No Solaris 9-11 +.br +.Nm mandoc : +.Ox 5.7 Pq August 27, 2014 +.Pp +prepend to macro file search path +.br +.Nm groff : +.g04 +.Pp +do not show the context of the match +.br +.Nm apropos : +.Nx Pq May 22, 2016 +.It Fl m +specify input macro language +.br +.Nm nroff , troff : +.At7 +.br +.Nm groff : +.g04 +.br +.Nm mandoc : +.Ox 4.8 Pq April 6, 2009 +.Pp +augment manual page search path +.br +.Nm man , apropos , whatis : +.Bx 4.3 Reno Pq June 1990 ; +.Ox , Nx +.br +.Nm catman : +.Nx Pq Apr 4, 1999 +.br +.Nm mandoc : +.Ox 5.7 Pq August 27, 2014 +.Pp +override operating system +.br +.Nm man : +.Eaton ; +.No man-db , man-1.6 +.br +.Nm apropos , whatis , manpath : +.dbI +.Pp +override architecture +.br +.Nm man : +.Fx Pq Jan 11, 2002 +.Pp +show the context of the match +.br +.Nm apropos : +.Nx Pq May 22, 2016 +.It Fl N +do not allow newlines between +.Xr eqn 7 +delimiters +.br +.Nm groff : +.No groff-1.01 Pq Feb 21, 1991 +.It Fl n +specify a page number for the first page +.br +.Nm troff : +.At7 +.br +.Nm groff : +.g04 +.Pp +.Xr nroff 1 +output mode +.br +.Nm man : +.At7 +.Pp +do not create the +.Xr whatis 1 +database +.br +.Nm catman : +.Nx Pq July 27, 1993 +.Pp +print commands instead of executing them +.br +.Nm catman : +.Fx Pq May 18, 2002 , +.No Solaris 9-11 +.Pp +limit the number of results +.br +.Nm apropos : +.Nx Pq Feb 7, 2012 +.Pp +dry run simulating +.Xr mandoc.db 5 +creation +.br +.Nm makewhatis : +.Ox 5.6 Pq April 18, 2014 +.It Fl O +output options +.br +.Nm mandoc : +.Ox 4.8 Pq Oct 27, 2009 +.br +.Nm man , apropos , whatis : +.Ox 5.7 Pq August 27, 2014 +.It Fl o +select pages by numbers +.br +.Nm nroff , troff : +.At7 +.br +.Nm groff : +.g04 +.Pp +force use of non-localized manual pages +.br +.Nm man : +.Fx Pq June 7, 1999 +.Pp +optimize index for speed and disk space +.br +.Nm makemandb : +.Nx Pq Feb 7, 2012 +.It Fl P +pass argument to postprocessor +.br +.Nm groff : +.No groff-0.6 Pq Sep 14, 1990 +.Pp +use specified pager +.br +.Nm man : +.Eaton ; +.Fx , No man-db , man-1.6 +.Pp +turn on pager formatting +.br +.Nm apropos : +.Nx Pq Apr 2, 2013 +.It Fl p +preprocess with +.Xr pic 1 +.br +.Nm groff : +.g04 +.Pp +use the given list of preprocessors +.br +.Nm man : +.Eaton ; +.Fx , No man-db , man-1.6 +.Pp +dry run, display commands instead of executing them +.br +.Nm catman : +.Nx Pq July 27, 1993 , +.Fx Pq March 15, 1995 to May 18, 2002 , +.No Solaris 9-11 +.Pp +print warnings when building +.Xr mandoc.db 5 +.br +.Nm makewhatis : +.Ox 2.7 Pq April 23, 2000 +.Pp +do not look for deleted manual pages +.br +.Nm mandb : +.No man-db Pq June 28, 2001 +.Pp +print the search path for manual pages +.br +.Nm man : +.Nx Pq June 14 , 2011 +.Pp +turn on pager formatting and pipe through pager +.br +.Nm apropos : +.Nx Pq Feb 7, 2012 +.Pp +.Bq obsolete hardware +set phototypesetter point size +.br +.Nm troff : +.At7 +.It Fl Q +print only fatal error messages +.br +.Nm makemandb : +.Nx Pq Aug 29, 2012 +.Pp +quick mode of +.Xr mandoc.db 5 +creation +.br +.Nm makewhatis : +.Ox 5.6 Pq April 18, 2014 +.It Fl q +invoke the simultaneous input-output mode of the .rd request +.br +.Nm nroff , troff : +.At7 +.Pp +issue no warnings +.br +.Nm manpath : +.Eaton ; +.Fx , No man-db +.br +.Nm mandb : +.dbI +.Pp +print only warnings and errors, no status updates +.br +.Nm makemandb : +.Nx Pq Aug 29, 2012 +.It Fl R +postprocess with +.Xr refer 1 +.br +.Nm groff : +.No groff-1.02 Pq June 2, 1991 +.Pp +recode to the specified encoding +.br +.Nm man : +.No man-db Pq Dec 31, 2007 +.It Fl r +set number register +.br +.Nm nroff , troff : +.At7 +.br +.Nm groff : +.g04 +.Pp +scan for and remove junk files +.br +.Nm catman : +.Fx Pq March 31, 1995 +.Pp +set +.Xr less 1 +prompt +.br +.Nm man : +.No man-db-2.3.5 Pq April 21, 1995 +.Pp +use regular expression matching +.br +.Nm apropos , whatis : +.No man-db-2.3.5 Pq April 21, 1995 +.Pp +turn off formatting +.br +.Nm apropos : +.Nx Pq Feb 10, 2013 +.Pp +check for formatting errors, do not display +.br +.Nm man : +.No illumos , Solaris 9-11 +.It Fl S +manual section search list +.br +.Nm man : +.Eaton ; +.Fx , No man-db , man-1.6 +.Pp +safer mode +.br +.Nm groff : +.No groff-1.10 Pq May 17, 1994 +.Pp +restrict architecture +.br +.Nm man : +.Ox 2.3 Pq March 9, 1998 , +.Nx Pq May 27, 2000 +.br +.Nm apropos : +.Ox 4.5 Pq Dec 24, 2008 , +.Nx Pq May 8, 2009 +.br +.Nm whatis : +.Ox 5.6 Pq April 18, 2014 +.br +.Nm mandoc : +.Ox 5.7 Pq August 27, 2014 +.It Fl s +preprocess with +.Xr soelim 1 +.br +.Nm groff : +.g04 +.Pp +silent mode, do not echo commands +.br +.Nm catman : +.Nx Pq April 26, 1994 +.Pp +restrict section +.br +.Nm makewhatis : +.man15g +.br +.Nm man : +.Ox 2.3 Pq March 9, 1998 , +.Nx Pq June 12, 2000 ; +.No illumos , Solaris 9-11 +.br +.Nm apropos : +.No man-db Pq Nov 16, 2003 , +.Ox 4.5 Pq Dec 24, 2008 , +.Nx Pq May 8, 2009 ; +.No illumos +.br +.Nm whatis : +.No man-db Pq Nov 16, 2003 , +.Ox 5.6 Pq April 18, 2014 ; +.No illumos +.br +.Nm mandoc : +.Ox 5.7 Pq August 27, 2014 +.Pp +do not look for stray cats +.br +.Nm mandb : +.dbI +.Pp +.Bq SysV compat, recommends Fl S +manual section search list +.br +.Nm man : +.No man-db Pq Jan 1, 2008 +.Pp +.Bq superseded by Fl h +display the SYNOPSIS lines only +.br +.Nm man : +.PWB +.Pp +.Bq obsolete hardware +pause before each page for paper manipulation +.br +.Nm roff : +.At7 +.Pp +.Bq obsolete hardware +.Xr troff 1 +output mode, small format +.br +.Nm man : +.At3 , +.At5 +.It Fl T +select terminal output format +.br +.Nm nroff : +.At7 +.br +.Nm man : +.At3 , +.At5 , +.dbI , +.Ox 5.7 Pq August 27, 2014 +.br +.Nm groff : +.g04 +.br +.Nm mandoc : +.Ox 4.8 Pq April 6, 2009 +.br +.Nm apropos , whatis : +.Ox 5.7 Pq August 27, 2014 +.Pp +use UTF-8 for +.Xr mandoc.db 5 +.br +.Nm makewhatis : +.Ox 5.6 Pq April 18, 2014 +.Pp +.Bq superseded by Fl m +use other macro package +.br +.Nm man , catman : +.No Solaris 9-11 +.It Fl t +.Xr troff 1 +output mode +.br +.Nm man : +.PWB , +.At7 , +.Bx 2 Pq May 10, 1979 , +.At3 , +.At5 , +.Eaton ; +.Fx , No man-db , man-1.6 , illumos , Solaris 9-11 +.br +.Nm catman : +.No Solaris 9-11 +.Pp +preprocess with +.Xr tbl 7 +.br +.Nm groff : +.g04 +.Pp +check manual pages in the hierarchy +.br +.Nm mandb : +.No man-db-1.3.12 to 1.3.17 Pq not before 1996, not after 2001 +.Pp +check files for problems related to +.Xr mandoc.db 5 +.br +.Nm makewhatis : +.Ox 2.7 Pq April 23, 2000 +.It Fl U +unsafe mode +.br +.Nm groff : +.No groff-1.12 Pq Dec 13, 1999 +.It Fl u +update database +.br +.Nm makewhatis : +.Pq not before 1992, not after 1995 +.Pp +create user databases only +.br +.Nm mandb : +.dbI +.Pp +update database cache (requires suid) +.br +.Nm man : +.No before man-db-2.2a10 Pq before Dec 6, 1994 +.Pp +remove files from +.Xr mandoc.db 5 +.br +.Nm makewhatis : +.Ox 3.4 Pq July 9, 2003 +.It Fl V +print the pipeline on stdout instead of executing it +.br +.Nm groff : +.No groff-0.6 Pq Sep 2, 1990 +.Pp +print version information +.br +.Nm man , apropos , whatis , mandb , catman , manpath : +.dbI +.It Fl v +print version number +.br +.Nm groff : +.g04 +.Pp +verbose mode +.br +.Nm catman : +.Fx Pq March 15, 1995 +.br +.Nm makewhatis : +.man15g +.br +.Nm apropos , whatis : +.No man-db Pq Dec 29, 2002 +.Pp +print the name of every parsed file +.br +.Nm makemandb : +.Nx Pq Feb 7, 2012 +.Pp +.Bq obsolete hardware +produce output on the Versatec printer +.br +.Nm man : +.PWB +.It Fl W +disable the named warning +.br +.Nm groff : +.No groff-0.5 Pq August 14, 1990 +.Pp +list pathnames without additional information +.br +.Nm man : +.man15e +.Pp +list pathnames of cat files +.br +.Nm man : +.No man-db Pq Aug 13, 2002 +.Pp +minimum message level to display +.br +.Nm mandoc : +.Ox 4.8 Pq April 6, 2009 +.br +.Nm man , apropos , whatis : +.Ox 5.7 Pq August 27, 2014 +.It Fl w +list pathnames +.br +.Nm man : +.At7 , +.At3 , +.At5 , +.Eaton ; +.Ox , Fx , Nx , No man-db , man-1.6 +.br +.Nm apropos , whatis , mandoc : +.Ox 5.7 Pq August 27, 2014 +.Pp +enable the named warning +.br +.Nm groff : +.No groff-0.5 Pq August 14, 1990 +.Pp +only create the +.Xr whatis 1 +database +.br +.Nm catman : +.Nx Pq July 27, 1993 , +.No Solaris 9-11 +.Pp +use wildcard matching +.br +.Nm apropos , whatis : +.No man-db-2.3.5 Pq April 21, 1995 +.Pp +use manpath obtained from man --path +.br +.Nm makewhatis : +.man15g +.Pp +update the +.Xr whatis 1 +database +.br +.Nm man : +.No illumos +.Pp +.Bq obsolete hardware +wait until the phototypesetter is available +.br +.Nm troff : +.At7 +.It Fl X +display with +.Xr gxditview 1 +.br +.Nm groff : +.No groff-1.06 Pq Sep 1, 1992 +.br +.Nm man : +.dbI +.It Fl y +use the non-compacted version of the macros +.br +.Nm man : +.At3 , +.At5 +.It Fl Z +do not run preprocessors +.br +.Nm groff : +.g04 +.br +.Nm man : +.No man-db-2.2a5 Pq Nov 10, 1994 +.It Fl z +suppress formatted output from +.Xr troff 1 , +print only error messages +.br +.Nm groff : +.g04 +.It Fl 7 +ASCII output mode +.br +.Nm man : +.No man-db-2.3.5 Pq April 21, 1995 +.It Fl \&? +print a help message and exit +.br +.Nm groff : +.g04 +.br +.Nm man , manpath : +.Eaton ; +.Fx , No man-db +.br +.Nm apropos , whatis , mandb , catman : +.dbI +.El +.Pp +Multi-letter options: +.Bl -tag -width Ds +.It Fl hp +.Bq obsolete hardware +output to a Hewlett Packard terminal +.br +.Nm man : +.PWB +.It Fl 12 +.Bq obsolete hardware +use 12-pitch for certain terminals +.br +.Nm man : +.At3 , +.At5 +.It Fl 450 +.Bq obsolete hardware +output to a DASI 450 terminal +.br +.Nm man : +.PWB +.El +.Pp +In +.At v3 , +.Xr man 1 +had no options. +.br +The syntax was: +.Sy man Ar name Op Ar section +.Pp +In +.At v4 , +.br +the syntax changed to: +.Sy man Oo Ar section Oc Op Ar name ... +.Sh AUTHORS +This information was assembled by +.An Ingo Schwarze Aq Mt schwarze@openbsd.org +using +.Bl -bullet -compact +.It +the Unix Archive of the Unix Heritage Society +.It +the CSRG Archive CD-ROMs +.It +the FreeBSD SVN repository +.It +the OpenBSD CVS repository +.It +the NetBSD CVS repository +.It +the GNU roff (groff) git repository +.It +the 4.3BSD-Net/2 groff CHANGES file (Oct 1990 to March 1991) +.It +the 4.3BSD-Net/2 groff ChangeLog file (July 1990 to March 1991) +.It +the man-db CVS and git repositories (since April 2001) +.It +the man-db NEWS file (April 1995 to Dec 2016) +.It +the man-db ChangeLog-2013 file (Nov 1994 to Dec 2013) +.It +release tarballs man-1.5g (July 1998) to man-1.5p (Jan 2005), +man-1.6 (June 2005), and man-1.6a to man-1.6g (Dec 2010) +.It +a makewhatis release tarball without version number from 1995 +.It +the illumos manual pages on the WWW +.It +and Solaris 11, SunOS 5.10, and SunOS 5.9 machines at opencsw.org. +.El diff --git a/man_html.c b/man_html.c index 641e0e336eaf..9151e4c7505e 100644 --- a/man_html.c +++ b/man_html.c @@ -1,4 +1,4 @@ -/* $Id: man_html.c,v 1.129 2017/01/21 01:20:32 schwarze Exp $ */ +/* $Id: man_html.c,v 1.133 2017/02/05 18:15:39 schwarze Exp $ */ /* * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze @@ -32,21 +32,14 @@ #include "html.h" #include "main.h" -/* TODO: preserve ident widths. */ /* FIXME: have PD set the default vspace width. */ #define INDENT 5 #define MAN_ARGS const struct roff_meta *man, \ const struct roff_node *n, \ - struct mhtml *mh, \ struct html *h -struct mhtml { - int fl; -#define MANH_LITERAL (1 << 0) /* literal context */ -}; - struct htmlman { int (*pre)(MAN_ARGS); int (*post)(MAN_ARGS); @@ -57,6 +50,7 @@ static void print_bvspace(struct html *, static void print_man_head(MAN_ARGS); static void print_man_nodelist(MAN_ARGS); static void print_man_node(MAN_ARGS); +static int fillmode(struct html *, int); static int a2width(const struct roff_node *, struct roffsu *); static int man_B_pre(MAN_ARGS); @@ -74,7 +68,6 @@ static int man_alt_pre(MAN_ARGS); static int man_br_pre(MAN_ARGS); static int man_ign_pre(MAN_ARGS); static int man_in_pre(MAN_ARGS); -static int man_literal_pre(MAN_ARGS); static void man_root_post(MAN_ARGS); static void man_root_pre(MAN_ARGS); @@ -101,8 +94,8 @@ static const struct htmlman mans[MAN_MAX] = { { man_alt_pre, NULL }, /* IR */ { man_alt_pre, NULL }, /* RI */ { man_br_pre, NULL }, /* sp */ - { man_literal_pre, NULL }, /* nf */ - { man_literal_pre, NULL }, /* fi */ + { NULL, NULL }, /* nf */ + { NULL, NULL }, /* fi */ { NULL, NULL }, /* RE */ { man_RS_pre, NULL }, /* RS */ { man_ign_pre, NULL }, /* DT */ @@ -112,8 +105,8 @@ static const struct htmlman mans[MAN_MAX] = { { man_in_pre, NULL }, /* in */ { man_ign_pre, NULL }, /* ft */ { man_OP_pre, NULL }, /* OP */ - { man_literal_pre, NULL }, /* EX */ - { man_literal_pre, NULL }, /* EE */ + { NULL, NULL }, /* EX */ + { NULL, NULL }, /* EE */ { man_UR_pre, NULL }, /* UR */ { NULL, NULL }, /* UE */ { man_ign_pre, NULL }, /* ll */ @@ -146,27 +139,25 @@ print_bvspace(struct html *h, const struct roff_node *n) void html_man(void *arg, const struct roff_man *man) { - struct mhtml mh; struct html *h; struct tag *t; - memset(&mh, 0, sizeof(mh)); h = (struct html *)arg; if ((h->oflags & HTML_FRAGMENT) == 0) { print_gen_decls(h); print_otag(h, TAG_HTML, ""); t = print_otag(h, TAG_HEAD, ""); - print_man_head(&man->meta, man->first, &mh, h); + print_man_head(&man->meta, man->first, h); print_tagq(h, t); print_otag(h, TAG_BODY, ""); } - man_root_pre(&man->meta, man->first, &mh, h); + man_root_pre(&man->meta, man->first, h); t = print_otag(h, TAG_DIV, "c", "manual-text"); - print_man_nodelist(&man->meta, man->first->child, &mh, h); + print_man_nodelist(&man->meta, man->first->child, h); print_tagq(h, t); - man_root_post(&man->meta, man->first, &mh, h); + man_root_post(&man->meta, man->first, h); print_tagq(h, NULL); } @@ -187,7 +178,7 @@ print_man_nodelist(MAN_ARGS) { while (n != NULL) { - print_man_node(man, n, mh, h); + print_man_node(man, n, h); n = n->next; } } @@ -195,25 +186,95 @@ print_man_nodelist(MAN_ARGS) static void print_man_node(MAN_ARGS) { - int child; - struct tag *t; + static int want_fillmode = MAN_fi; + static int save_fillmode; - child = 1; - t = h->tags.head; + struct tag *t; + int child; + + /* + * Handle fill mode switch requests up front, + * they would just cause trouble in the subsequent code. + */ + + switch (n->tok) { + case MAN_nf: + case MAN_EX: + want_fillmode = MAN_nf; + return; + case MAN_fi: + case MAN_EE: + want_fillmode = MAN_fi; + if (fillmode(h, 0) == MAN_fi) + print_otag(h, TAG_BR, ""); + return; + default: + break; + } + + /* Set up fill mode for the upcoming node. */ switch (n->type) { - case ROFFT_TEXT: - if ('\0' == *n->string) { - print_paragraph(h); - return; + case ROFFT_BLOCK: + save_fillmode = 0; + /* Some block macros suspend or cancel .nf. */ + switch (n->tok) { + case MAN_TP: /* Tagged paragraphs */ + case MAN_IP: /* temporarily disable .nf */ + case MAN_HP: /* for the head. */ + save_fillmode = want_fillmode; + /* FALLTHROUGH */ + case MAN_SH: /* Section headers */ + case MAN_SS: /* permanently cancel .nf. */ + want_fillmode = MAN_fi; + /* FALLTHROUGH */ + case MAN_PP: /* These have no head. */ + case MAN_LP: /* They will simply */ + case MAN_P: /* reopen .nf in the body. */ + case MAN_RS: + case MAN_UR: + fillmode(h, MAN_fi); + break; + default: + break; } - if (n->flags & NODE_LINE && (*n->string == ' ' || - (n->prev != NULL && mh->fl & MANH_LITERAL && - ! (h->flags & HTML_NONEWLINE)))) + break; + case ROFFT_TBL: + fillmode(h, MAN_fi); + break; + case ROFFT_ELEM: + /* + * Some in-line macros produce tags and/or text + * in the handler, so they require fill mode to be + * configured up front just like for text nodes. + * For the others, keep the traditional approach + * of doing the same, for now. + */ + fillmode(h, want_fillmode); + break; + case ROFFT_TEXT: + if (fillmode(h, want_fillmode) == MAN_fi && + want_fillmode == MAN_fi && + n->flags & NODE_LINE && *n->string == ' ') print_otag(h, TAG_BR, ""); - print_text(h, n->string); + if (*n->string != '\0') + break; + print_paragraph(h); return; + default: + break; + } + + /* Produce output for this node. */ + + child = 1; + switch (n->type) { + case ROFFT_TEXT: + t = h->tag; + print_text(h, n->string); + break; case ROFFT_EQN: + t = h->tag; print_eqn(h, n->eqn); break; case ROFFT_TBL: @@ -239,29 +300,55 @@ print_man_node(MAN_ARGS) * the "meta" table state. This will be reopened on the * next table element. */ - if (h->tblt) { + if (h->tblt) print_tblclose(h); - t = h->tags.head; - } + + t = h->tag; if (mans[n->tok].pre) - child = (*mans[n->tok].pre)(man, n, mh, h); + child = (*mans[n->tok].pre)(man, n, h); + + /* Some block macros resume .nf in the body. */ + if (save_fillmode && n->type == ROFFT_BODY) + want_fillmode = save_fillmode; + break; } if (child && n->child) - print_man_nodelist(man, n->child, mh, h); + print_man_nodelist(man, n->child, h); /* This will automatically close out any font scope. */ print_stagq(h, t); - switch (n->type) { - case ROFFT_EQN: - break; - default: - if (mans[n->tok].post) - (*mans[n->tok].post)(man, n, mh, h); - break; + if (fillmode(h, 0) == MAN_nf && + n->next != NULL && n->next->flags & NODE_LINE) + print_endline(h); +} + +/* + * MAN_nf switches to no-fill mode, MAN_fi to fill mode. + * Other arguments do not switch. + * The old mode is returned. + */ +static int +fillmode(struct html *h, int want) +{ + struct tag *pre; + int had; + + for (pre = h->tag; pre != NULL; pre = pre->next) + if (pre->tag == TAG_PRE) + break; + + had = pre == NULL ? MAN_fi : MAN_nf; + + if (want && want != had) { + if (want == MAN_nf) + print_otag(h, TAG_PRE, ""); + else + print_tagq(h, pre); } + return had; } static int @@ -287,7 +374,6 @@ man_root_pre(MAN_ARGS) mandoc_asprintf(&title, "%s(%s)", man->title, man->msec); t = print_otag(h, TAG_TABLE, "c", "head"); - print_otag(h, TAG_TBODY, ""); tt = print_otag(h, TAG_TR, ""); print_otag(h, TAG_TD, "c", "head-ltitle"); @@ -349,13 +435,8 @@ man_br_pre(MAN_ARGS) static int man_SH_pre(MAN_ARGS) { - if (n->type == ROFFT_BLOCK) { - mh->fl &= ~MANH_LITERAL; - return 1; - } else if (n->type == ROFFT_BODY) - return 1; - - print_otag(h, TAG_H1, "c", "Sh"); + if (n->type == ROFFT_HEAD) + print_otag(h, TAG_H1, "c", "Sh"); return 1; } @@ -363,17 +444,11 @@ static int man_alt_pre(MAN_ARGS) { const struct roff_node *nn; - int i, savelit; + int i; enum htmltag fp; struct tag *t; - if ((savelit = mh->fl & MANH_LITERAL)) - print_otag(h, TAG_BR, ""); - - mh->fl &= ~MANH_LITERAL; - for (i = 0, nn = n->child; nn; nn = nn->next, i++) { - t = NULL; switch (n->tok) { case MAN_BI: fp = i % 2 ? TAG_I : TAG_B; @@ -400,18 +475,14 @@ man_alt_pre(MAN_ARGS) if (i) h->flags |= HTML_NOSPACE; - if (TAG_MAX != fp) + if (fp != TAG_MAX) t = print_otag(h, fp, ""); - print_man_node(man, nn, mh, h); + print_text(h, nn->string); - if (t) + if (fp != TAG_MAX) print_tagq(h, t); } - - if (savelit) - mh->fl |= MANH_LITERAL; - return 0; } @@ -427,13 +498,8 @@ man_SM_pre(MAN_ARGS) static int man_SS_pre(MAN_ARGS) { - if (n->type == ROFFT_BLOCK) { - mh->fl &= ~MANH_LITERAL; - return 1; - } else if (n->type == ROFFT_BODY) - return 1; - - print_otag(h, TAG_H2, "c", "Ss"); + if (n->type == ROFFT_HEAD) + print_otag(h, TAG_H2, "c", "Ss"); return 1; } @@ -469,7 +535,7 @@ man_IP_pre(MAN_ARGS) /* For IP, only print the first header element. */ if (MAN_IP == n->tok && n->child) - print_man_node(man, n->child, mh, h); + print_man_node(man, n->child, h); /* For TP, only print next-line header elements. */ @@ -478,7 +544,7 @@ man_IP_pre(MAN_ARGS) while (NULL != nn && 0 == (NODE_LINE & nn->flags)) nn = nn->next; while (NULL != nn) { - print_man_node(man, nn, mh, h); + print_man_node(man, nn, h); nn = nn->next; } } @@ -551,19 +617,6 @@ man_I_pre(MAN_ARGS) return 1; } -static int -man_literal_pre(MAN_ARGS) -{ - - if (MAN_fi == n->tok || MAN_EE == n->tok) { - print_otag(h, TAG_BR, ""); - mh->fl &= ~MANH_LITERAL; - } else - mh->fl |= MANH_LITERAL; - - return 0; -} - static int man_in_pre(MAN_ARGS) { @@ -610,7 +663,7 @@ man_UR_pre(MAN_ARGS) if (n->next->child != NULL) n = n->next; - print_man_nodelist(man, n->child, mh, h); + print_man_nodelist(man, n->child, h); return 0; } diff --git a/man_term.c b/man_term.c index 672ab4163228..b2732d455891 100644 --- a/man_term.c +++ b/man_term.c @@ -1,7 +1,7 @@ -/* $Id: man_term.c,v 1.188 2017/01/10 13:47:00 schwarze Exp $ */ +/* $Id: man_term.c,v 1.191 2017/02/15 14:10:08 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons - * Copyright (c) 2010-2015 Ingo Schwarze + * Copyright (c) 2010-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 @@ -143,6 +143,7 @@ terminal_man(void *arg, const struct roff_man *man) struct termp *p; struct roff_node *n; struct mtermp mt; + size_t save_defindent; p = (struct termp *)arg; p->overstep = 0; @@ -170,6 +171,7 @@ terminal_man(void *arg, const struct roff_man *man) n = n->next; } } else { + save_defindent = p->defindent; if (p->defindent == 0) p->defindent = 7; term_begin(p, print_man_head, print_man_foot, &man->meta); @@ -177,6 +179,7 @@ terminal_man(void *arg, const struct roff_man *man) if (n != NULL) print_man_nodelist(p, &mt, n, &man->meta); term_end(p); + p->defindent = save_defindent; } } @@ -819,7 +822,8 @@ pre_SH(DECL_ARGS) do { n = n->prev; - } while (n != NULL && termacts[n->tok].flags & MAN_NOTEXT); + } while (n != NULL && n->tok != TOKEN_NONE && + termacts[n->tok].flags & MAN_NOTEXT); if (n == NULL || (n->tok == MAN_SH && n->body->child == NULL)) break; diff --git a/manconf.h b/manconf.h index 782269e7b33d..f5c678e8903f 100644 --- a/manconf.h +++ b/manconf.h @@ -35,6 +35,7 @@ struct manoutput { int fragment; int mdoc; int synopsisonly; + int noval; }; struct manconf { @@ -44,5 +45,5 @@ struct manconf { void manconf_parse(struct manconf *, const char *, char *, char *); -void manconf_output(struct manoutput *, const char *); +int manconf_output(struct manoutput *, const char *, int); void manconf_free(struct manconf *); diff --git a/mandoc.1 b/mandoc.1 index 946955a64c54..45615d5d02ba 100644 --- a/mandoc.1 +++ b/mandoc.1 @@ -1,4 +1,4 @@ -.\" $Id: mandoc.1,v 1.171 2017/01/21 02:32:39 schwarze Exp $ +.\" $Id: mandoc.1,v 1.174 2017/02/10 15:45:28 schwarze Exp $ .\" .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons .\" Copyright (c) 2012, 2014-2017 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 21 2017 $ +.Dd $Mdocdate: February 10 2017 $ .Dt MANDOC 1 .Os .Sh NAME @@ -538,6 +538,8 @@ A closing parenthesis if the node is a closing delimiter. .It A full stop if the node ends a sentence. .It +BROKEN if the node is a block broken by another block. +.It NOSRC if the node is not in the input file, but automatically generated from macros. .It @@ -545,6 +547,17 @@ NOPRT if the node is not supposed to generate output for any output format. .El .El +.Pp +The following +.Fl O +argument is accepted: +.Bl -tag -width Ds +.It Cm noval +Skip validation and show the unvalidated syntax tree. +This can help to find out whether a given behaviour is caused by +the parser or by the validator. +Meta data is not available in this case. +.El .Sh ENVIRONMENT .Bl -tag -width MANPAGER .It Ev MANPAGER @@ -1357,6 +1370,10 @@ it is hard to predict which tab stop position the tab will advance to. Whitespace at the end of input lines is almost never semantically significant \(em but in the odd case where it might be, it is extremely confusing when reviewing and maintaining documents. +.It Sy "new sentence, new line" +.Pq mdoc +A new sentence starts in the middle of a text line. +Start it on a new input line to help formatters produce correct spacing. .It Sy "bad comment style" .Pq roff Comment lines start with a dot, a backslash, and a double-quote character. @@ -1832,6 +1849,19 @@ as if they were a text line. .Xr mdoc 7 , .Xr roff 7 , .Xr tbl 7 +.Sh HISTORY +The +.Nm +utility first appeared in +.Ox 4.8 . +The option +.Fl I +appeared in +.Ox 5.2 , +and +.Fl aCcfhKklMSsw +in +.Ox 5.7 . .Sh AUTHORS .An -nosplit The diff --git a/mandoc.css b/mandoc.css index 162b730749ed..bc4d98281a8d 100644 --- a/mandoc.css +++ b/mandoc.css @@ -1,4 +1,4 @@ -/* $Id: mandoc.css,v 1.13 2017/01/21 02:29:57 schwarze Exp $ */ +/* $Id: mandoc.css,v 1.17 2017/02/05 21:00:43 schwarze Exp $ */ /* * Standard style sheet for mandoc(1) -Thtml and man.cgi(8). */ @@ -91,15 +91,25 @@ dd.It-inset { } dl.Bl-ohang { } dt.It-ohang { } dd.It-ohang { margin-left: 0ex; } -dl.Bl-tag { } -dt.It-tag { } -dd.It-tag { } +dl.Bl-tag { margin-left: 8ex; } +dt.It-tag { float: left; + clear: both; + margin-top: 0ex; + margin-left: -8ex; + padding-right: 2ex; + vertical-align: top; } +dd.It-tag { width: 100%; + margin-top: 0ex; + margin-left: 0ex; + vertical-align: top; + overflow: auto; } table.Bl-column { } tr.It-column { } td.It-column { margin-top: 1em; } -span.Rs { } +cite.Rs { font-style: normal; + font-weight: normal; } span.RsA { } i.RsB { font-weight: normal; } span.RsC { } @@ -124,7 +134,8 @@ table.Nm { } b.Nm { font-style: normal; } b.Fl { font-style: normal; } b.Cm { font-style: normal; } -i.Ar { font-weight: normal; } +var.Ar { font-style: italic; + font-weight: normal; } span.Op { } b.Ic { font-style: normal; } code.Ev { font-style: normal; @@ -138,11 +149,15 @@ span.Lb { } b.In { font-style: normal; } a.In { } b.Fd { font-style: normal; } -i.Ft { font-weight: normal; } +var.Ft { font-style: italic; + font-weight: normal; } b.Fn { font-style: normal; } -i.Fa { font-weight: normal; } -i.Vt { font-weight: normal; } -i.Va { font-weight: normal; } +var.Fa { font-style: italic; + font-weight: normal; } +var.Vt { font-style: italic; + font-weight: normal; } +var.Va { font-style: italic; + font-weight: normal; } code.Dv { font-style: normal; font-weight: normal; font-family: monospace; } @@ -158,6 +173,7 @@ a.Mt { } b.Cd { font-style: normal; } i.Ad { font-weight: normal; } b.Ms { font-style: normal; } +span.St { } a.Ux { } /* Physical markup. */ diff --git a/mandoc.h b/mandoc.h index 2ea64ea0aea0..a80d6ae7b82d 100644 --- a/mandoc.h +++ b/mandoc.h @@ -1,4 +1,4 @@ -/* $Id: mandoc.h,v 1.213 2017/01/09 01:37:03 schwarze Exp $ */ +/* $Id: mandoc.h,v 1.214 2017/01/28 23:30:08 schwarze Exp $ */ /* * Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons * Copyright (c) 2010-2017 Ingo Schwarze @@ -134,6 +134,7 @@ enum mandocerr { MANDOCERR_FI_BLANK, /* blank line in fill mode, using .sp */ MANDOCERR_FI_TAB, /* tab in filled text */ MANDOCERR_SPACE_EOL, /* whitespace at end of input line */ + MANDOCERR_EOS, /* new sentence, new line */ MANDOCERR_COMMENT_BAD, /* bad comment style */ MANDOCERR_ESC_BAD, /* invalid escape sequence: esc */ MANDOCERR_STR_UNDEF, /* undefined string, using "": name */ diff --git a/mandoc_aux.h b/mandoc_aux.h index 603cc5a7257c..a2425066c14e 100644 --- a/mandoc_aux.h +++ b/mandoc_aux.h @@ -1,4 +1,4 @@ -/* $Id: mandoc_aux.h,v 1.5 2016/07/19 13:36:13 schwarze Exp $ */ +/* $Id: mandoc_aux.h,v 1.6 2017/02/17 14:31:52 schwarze Exp $ */ /* * Copyright (c) 2009, 2011 Kristaps Dzonsons * Copyright (c) 2014 Ingo Schwarze @@ -17,7 +17,7 @@ */ int mandoc_asprintf(char **, const char *, ...) - __attribute__((__format__ (printf, 2, 3))); + __attribute__((__format__ (__printf__, 2, 3))); void *mandoc_calloc(size_t, size_t); void *mandoc_malloc(size_t); void *mandoc_realloc(void *, size_t); diff --git a/mandoc_char.7 b/mandoc_char.7 index d272080fc1d9..4212ec58bd77 100644 --- a/mandoc_char.7 +++ b/mandoc_char.7 @@ -1,4 +1,4 @@ -.\" $Id: mandoc_char.7,v 1.63 2015/09/02 15:38:35 schwarze Exp $ +.\" $Id: mandoc_char.7,v 1.64 2017/02/05 21:41:21 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: September 2 2015 $ +.Dd $Mdocdate: February 5 2017 $ .Dt MANDOC_CHAR 7 .Os .Sh NAME @@ -62,6 +62,30 @@ blue-eyed lorry-driver .Ed .Pp +If a word on a text input line contains a hyphen, a formatter may decide +to insert an output line break after the hyphen if that helps filling +the current output line, but the whole word would overflow the line. +If it is important that the word is not broken across lines in this +way, a zero-width space +.Pq Sq \e& +can be inserted before or after the hyphen. +While +.Xr mandoc 1 +never breaks the output line after hyphens adjacent to a zero-width +space, after any of the other dash- or hyphen-like characters +represented by escape sequences, or after hyphens inside words in +macro arguments, other software may not respect these rules and may +break the line even in such cases. +.Pp +Some +.Xr roff 7 +implementations contains dictionaries allowing to break the line +at syllable boundaries even inside words that contain no hyphens. +Such automatic hyphenation is not supported by +.Xr mandoc 1 , +which only breaks the line at whitespace, and inside words only +after existing hyphens. +.Pp The mathematical minus sign is used for negative numbers or subtraction. It should be written as .Sq \e(mi : diff --git a/mandoc_html.3 b/mandoc_html.3 index 80b1fe69f7cf..3b48eb00426e 100644 --- a/mandoc_html.3 +++ b/mandoc_html.3 @@ -1,4 +1,4 @@ -.\" $Id: mandoc_html.3,v 1.3 2017/01/17 15:32:44 schwarze Exp $ +.\" $Id: mandoc_html.3,v 1.5 2017/01/28 22:36:38 schwarze Exp $ .\" .\" Copyright (c) 2014, 2017 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. .\" -.Dd $Mdocdate: January 17 2017 $ +.Dd $Mdocdate: January 28 2017 $ .Dt MANDOC_HTML 3 .Os .Sh NAME @@ -137,6 +137,9 @@ Most attributes require one .Va char * argument which becomes the value of the attribute. The arguments have to be given in the same order as the attribute letters. +If an argument is +.Dv NULL , +the respective attribute is not written. .Bl -tag -width 1n -offset indent .It Cm c Print a @@ -175,13 +178,15 @@ Print an arbitrary attribute. This format letter requires two .Vt char * arguments, the attribute name and the value. +The name must not be +.Dv NULL . .It Cm s Print a .Cm style attribute. If present, it must be the last format letter. In contrast to the other format letters, this one does not yet -print the value and does not require an argument. +print the value and does not take an argument. Instead, the rest of the format string consists of pairs of argument type letters and style name letters. .El @@ -212,6 +217,13 @@ Requires one argument, interpreted as an .Xr mdoc 7 Ns -style width specifier. +If the argument is +.Dv NULL , +nothing is printed for this pair. +.It Cm W +Similar to +.Cm w , +but makes the width negative by multiplying it with \(mi1. .El .Pp Style name letters decide what to do with the preceding argument: @@ -251,6 +263,8 @@ requires two .Vt char * arguments. The first is the style name, the second its value. +The style name must not be +.Dv NULL . .El .Pp .Fn print_otag @@ -336,5 +350,6 @@ implementation of common mandoc utility functions .An -nosplit The mandoc HTML formatter was written by .An Kristaps Dzonsons Aq Mt kristaps@bsd.lv . -This manual was written by -.An Ingo Schwarze Aq Mt schwarze@openbsd.org . +It is maintained by +.An Ingo Schwarze Aq Mt schwarze@openbsd.org , +who also wrote this manual. diff --git a/mandocd.8 b/mandocd.8 new file mode 100644 index 000000000000..678c7dc34ce3 --- /dev/null +++ b/mandocd.8 @@ -0,0 +1,198 @@ +.\" $Id: mandocd.8,v 1.1 2017/02/06 19:04:21 schwarze Exp $ +.\" +.\" Copyright (c) 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. +.\" +.Dd $Mdocdate: February 6 2017 $ +.Dt MANDOCD 8 +.Os +.Sh NAME +.Nm mandocd +.Nd server process to format manual pages in batch mode +.Sh SYNOPSIS +.Nm mandocd +.Op Fl I Cm os Ns = Ns Ar name +.Op Fl T Ar output +.Ar socket_fd +.Sh DESCRIPTION +The +.Nm +utility formats many manual pages without requiring +.Xr fork 2 +and +.Xr exec 3 +overhead in between. +It does not require listing all the manuals to be formatted on the +command line, and it supports writing each formatted manual to its +own file descriptor. +.Pp +This server requires that a connected UNIX domain +.Xr socket 2 +is already present at +.Xr exec 3 +time. +Consequently, it cannot be started from the +.Xr sh 1 +command line because the shell cannot supply such a socket. +Typically, the socket is created by the parent process using +.Xr socketpair 2 +before calling +.Xr fork 2 +and +.Xr exec 3 +on +.Nm . +The parent process will pass the file descriptor number as an argument to +.Xr exec 3 , +formatted as a decimal ASCII-encoded integer. +See +.Xr catman 8 +for a typical implementation of a parent process. +.Pp +.Nm +loops reading one-byte messages with +.Xr recvmsg 2 +from the file descriptor number +.Ar socket_fd . +It ignores the byte read and only uses the out-of-band auxiliary +.Vt struct cmsghdr +control data, typically supplied by the calling process using +.Xr CMSG_FIRSTHDR 3 . +The parent process is expected to pass three file descriptors +with each dummy byte. +The first one is used for +.Xr mdoc 7 +or +.Xr man 7 +input, the second one for formatted output, and the third one +for error output. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl I Cm os Ns = Ns Ar name +Override the default operating system +.Ar name +for the +.Xr mdoc 7 +.Ic Os +and for the +.Xr man 7 +.Ic TH +macro. +.It Fl T Ar output +Output format. +The +.Ar output +argument can be +.Cm ascii , +.Cm utf8 , +or +.Cm html ; +see +.Xr mandoc 1 . +In +.Cm html +output mode, the +.Cm fragment +output option is implied. +Other output options are not supported. +.El +.Pp +After exhausting one input file descriptor, all three file descriptors +are closed before reading the next dummy byte and control message. +.Pp +When a zero-byte message is read, when the +.Ar socket_fd +is closed by the parent process, +or when an error occurs, +.Nm +exits. +.Sh EXIT STATUS +.Ex -std +.Pp +A zero-byte message or a closed +.Ar socket_fd +is considered success. +Possible errors include: +.Bl -bullet +.It +missing, invalid, or excessive +.Xr exec 3 +arguments +.It +.Xr recvmsg 2 +failure, for example due to +.Er EMSGSIZE +.It +missing or unexpected control data, in particular a +.Fa cmsg_level +in the +.Vt struct cmsghdr +that differs from +.Dv SOL_SOCKET , +a +.Fa cmsg_type +that differs from +.Dv SCM_RIGHTS , +or a +.Fa cmsg_len +that is not three times the size of an +.Vt int +.It +invalid file descriptors passed in the +.Xr CMSG_DATA 3 +.It +resource exhaustion, in particular +.Xr dup 2 +or +.Xr malloc 3 +failure +.El +.Pp +Except for memory exhaustion and similar system-level failures, +parsing and formatting errors do not cause +.Nm +to return an error exit status. +Even after severe parsing errors, +.Nm +will simply accept and process the next input file descriptor. +.Sh SEE ALSO +.Xr mandoc 1 , +.Xr mandoc 3 , +.Xr catman 8 +.Sh HISTORY +The +.Nm +utility appeared in version 1.14.1 or the +.Sy mandoc +toolkit. +.Sh AUTHORS +.An -nosplit +The concept was designed and implemented by +.An Michael Stapelberg Aq Mt stapelberg@debian.org . +The +.Xr mandoc 3 +glue needed to make it a stand-alone process was added by +.An Ingo Schwarze Aq Mt schwarze@openbsd.org . +.Sh CAVEATS +If the parsed manual pages contain +.Xr roff 7 +.Pf . Ic so +requests, +.Nm +needs to be started with the current working directory set to the +root of the manual page tree. +Avoid starting it in directories that contain secret files in any +subdirectories, in particular in the user starting it has read +access to these secret files. diff --git a/mandocd.c b/mandocd.c new file mode 100644 index 000000000000..2f6046b730a0 --- /dev/null +++ b/mandocd.c @@ -0,0 +1,285 @@ +/* $Id: mandocd.c,v 1.5 2017/02/17 14:31:52 schwarze Exp $ */ +/* + * Copyright (c) 2017 Michael Stapelberg + * Copyright (c) 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 AUTHORS DISCLAIM ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#if HAVE_CMSG_XPG42 +#define _XPG4_2 +#endif + +#include +#include + +#if HAVE_ERR +#include +#endif +#include +#include +#include +#include +#include +#include + +#include "mandoc.h" +#include "roff.h" +#include "mdoc.h" +#include "man.h" +#include "main.h" +#include "manconf.h" + +enum outt { + OUTT_ASCII = 0, + OUTT_UTF8, + OUTT_HTML +}; + +static void process(struct mparse *, enum outt, void *); +static int read_fds(int, int *); +static void usage(void) __attribute__((__noreturn__)); + + +#define NUM_FDS 3 +static int +read_fds(int clientfd, int *fds) +{ + struct msghdr msg; + struct iovec iov[1]; + unsigned char dummy[1]; + struct cmsghdr *cmsg; + int *walk; + int cnt; + + /* Union used for alignment. */ + union { + uint8_t controlbuf[CMSG_SPACE(NUM_FDS * sizeof(int))]; + struct cmsghdr align; + } u; + + memset(&msg, '\0', sizeof(msg)); + msg.msg_control = u.controlbuf; + msg.msg_controllen = sizeof(u.controlbuf); + + /* + * Read a dummy byte - sendmsg cannot send an empty message, + * even if we are only interested in the OOB data. + */ + + iov[0].iov_base = dummy; + iov[0].iov_len = sizeof(dummy); + msg.msg_iov = iov; + msg.msg_iovlen = 1; + + switch (recvmsg(clientfd, &msg, 0)) { + case -1: + warn("recvmsg"); + return -1; + case 0: + return 0; + default: + break; + } + + if ((cmsg = CMSG_FIRSTHDR(&msg)) == NULL) { + warnx("CMSG_FIRSTHDR: missing control message"); + return -1; + } + + if (cmsg->cmsg_level != SOL_SOCKET || + cmsg->cmsg_type != SCM_RIGHTS || + cmsg->cmsg_len != CMSG_LEN(NUM_FDS * sizeof(int))) { + warnx("CMSG_FIRSTHDR: invalid control message"); + return -1; + } + + walk = (int *)CMSG_DATA(cmsg); + for (cnt = 0; cnt < NUM_FDS; cnt++) + fds[cnt] = *walk++; + + return 1; +} + +int +main(int argc, char *argv[]) +{ + struct manoutput options; + struct mparse *parser; + void *formatter; + const char *defos; + const char *errstr; + int clientfd; + int old_stdin; + int old_stdout; + int old_stderr; + int fds[3]; + int state, opt; + enum outt outtype; + + defos = NULL; + outtype = OUTT_ASCII; + while ((opt = getopt(argc, argv, "I:T:")) != -1) { + switch (opt) { + case 'I': + if (strncmp(optarg, "os=", 3) == 0) + defos = optarg + 3; + else { + warnx("-I %s: Bad argument", optarg); + usage(); + } + break; + case 'T': + if (strcmp(optarg, "ascii") == 0) + outtype = OUTT_ASCII; + else if (strcmp(optarg, "utf8") == 0) + outtype = OUTT_UTF8; + else if (strcmp(optarg, "html") == 0) + outtype = OUTT_HTML; + else { + warnx("-T %s: Bad argument", optarg); + usage(); + } + break; + default: + usage(); + } + } + + if (argc > 0) { + argc -= optind; + argv += optind; + } + if (argc != 1) + usage(); + + errstr = NULL; + clientfd = strtonum(argv[0], 3, INT_MAX, &errstr); + if (errstr) + errx(1, "file descriptor %s %s", argv[1], errstr); + + mchars_alloc(); + parser = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1, + MANDOCLEVEL_BADARG, NULL, defos); + + memset(&options, 0, sizeof(options)); + switch (outtype) { + case OUTT_ASCII: + formatter = ascii_alloc(&options); + break; + case OUTT_UTF8: + formatter = utf8_alloc(&options); + break; + case OUTT_HTML: + options.fragment = 1; + formatter = html_alloc(&options); + break; + } + + state = 1; /* work to do */ + fflush(stdout); + fflush(stderr); + if ((old_stdin = dup(STDIN_FILENO)) == -1 || + (old_stdout = dup(STDOUT_FILENO)) == -1 || + (old_stderr = dup(STDERR_FILENO)) == -1) { + warn("dup"); + state = -1; /* error */ + } + + while (state == 1 && (state = read_fds(clientfd, fds)) == 1) { + if (dup2(fds[0], STDIN_FILENO) == -1 || + dup2(fds[1], STDOUT_FILENO) == -1 || + dup2(fds[2], STDERR_FILENO) == -1) { + warn("dup2"); + state = -1; + break; + } + + close(fds[0]); + close(fds[1]); + close(fds[2]); + + process(parser, outtype, formatter); + mparse_reset(parser); + + fflush(stdout); + fflush(stderr); + /* Close file descriptors by restoring the old ones. */ + if (dup2(old_stderr, STDERR_FILENO) == -1 || + dup2(old_stdout, STDOUT_FILENO) == -1 || + dup2(old_stdin, STDIN_FILENO) == -1) { + warn("dup2"); + state = -1; + break; + } + } + + close(clientfd); + switch (outtype) { + case OUTT_ASCII: + case OUTT_UTF8: + ascii_free(formatter); + break; + case OUTT_HTML: + html_free(formatter); + break; + } + mparse_free(parser); + mchars_free(); + return state == -1 ? 1 : 0; +} + +static void +process(struct mparse *parser, enum outt outtype, void *formatter) +{ + struct roff_man *man; + + mparse_readfd(parser, STDIN_FILENO, ""); + mparse_result(parser, &man, NULL); + + if (man == NULL) + return; + + if (man->macroset == MACROSET_MDOC) { + mdoc_validate(man); + switch (outtype) { + case OUTT_ASCII: + case OUTT_UTF8: + terminal_mdoc(formatter, man); + break; + case OUTT_HTML: + html_mdoc(formatter, man); + break; + } + } + if (man->macroset == MACROSET_MAN) { + man_validate(man); + switch (outtype) { + case OUTT_ASCII: + case OUTT_UTF8: + terminal_man(formatter, man); + break; + case OUTT_HTML: + html_man(formatter, man); + break; + } + } +} + +void +usage(void) +{ + fprintf(stderr, "usage: mandocd [-I os=name] [-T output] socket_fd\n"); + exit(1); +} diff --git a/mandocdb.c b/mandocdb.c index 133e73670c10..3b26ca964964 100644 --- a/mandocdb.c +++ b/mandocdb.c @@ -1,4 +1,4 @@ -/* $Id: mandocdb.c,v 1.237 2017/01/11 17:39:53 schwarze Exp $ */ +/* $Id: mandocdb.c,v 1.244 2017/02/17 14:45:55 schwarze Exp $ */ /* * Copyright (c) 2011, 2012 Kristaps Dzonsons * Copyright (c) 2011-2017 Ingo Schwarze @@ -162,7 +162,7 @@ static void putmdockey(const struct mpage *, const struct roff_node *, uint64_t, int); static int render_string(char **, size_t *); static void say(const char *, const char *, ...) - __attribute__((__format__ (printf, 2, 3))); + __attribute__((__format__ (__printf__, 2, 3))); static int set_basedir(const char *, int); static int treescan(void); static size_t utf8(unsigned int, char [7]); @@ -589,7 +589,7 @@ treescan(void) const char *argv[2]; argv[0] = "."; - argv[1] = (char *)NULL; + argv[1] = NULL; f = fts_open((char * const *)argv, FTS_PHYSICAL | FTS_NOCHDIR, fts_compare); @@ -871,6 +871,20 @@ filescan(const char *file) return; } + /* + * In test mode or when the original name is absolute + * but outside our tree, guess the base directory. + */ + + if (op == OP_TEST || (start == buf && *start == '/')) { + if (strncmp(buf, "man/", 4) == 0) + start = buf + 4; + else if ((start = strstr(buf, "/man/")) != NULL) + start += 5; + else + start = buf; + } + /* * First try to guess our directory structure. * If we find a separator, try to look for man* or cat*. @@ -1139,6 +1153,7 @@ mpages_merge(struct dba *dba, struct mparse *mp) if (mlink->dform != FORM_CAT || mlink->fform != FORM_CAT) { mparse_readfd(mp, fd, mlink->file); close(fd); + fd = -1; mparse_result(mp, &man, &sodest); } @@ -1195,34 +1210,43 @@ mpages_merge(struct dba *dba, struct mparse *mp) mpage->title = mandoc_strdup(man->meta.title); } else if (man != NULL && man->macroset == MACROSET_MAN) { man_validate(man); - mpage->form = FORM_SRC; - mpage->sec = mandoc_strdup(man->meta.msec); - mpage->arch = mandoc_strdup(mlink->arch); - mpage->title = mandoc_strdup(man->meta.title); - } else { + if (*man->meta.msec != '\0' || + *man->meta.msec != '\0') { + mpage->form = FORM_SRC; + mpage->sec = mandoc_strdup(man->meta.msec); + mpage->arch = mandoc_strdup(mlink->arch); + mpage->title = mandoc_strdup(man->meta.title); + } else + man = NULL; + } + + assert(mpage->desc == NULL); + if (man == NULL) { mpage->form = FORM_CAT; mpage->sec = mandoc_strdup(mlink->dsec); mpage->arch = mandoc_strdup(mlink->arch); mpage->title = mandoc_strdup(mlink->name); + parse_cat(mpage, fd); + } else if (man->macroset == MACROSET_MDOC) + parse_mdoc(mpage, &man->meta, man->first); + else + parse_man(mpage, &man->meta, man->first); + if (mpage->desc == NULL) { + mpage->desc = mandoc_strdup(mlink->name); + if (warnings) + say(mlink->file, "No one-line description, " + "using filename \"%s\"", mlink->name); } - assert(mpage->desc == NULL); - if (man != NULL && man->macroset == MACROSET_MDOC) - parse_mdoc(mpage, &man->meta, man->first); - else if (man != NULL) - parse_man(mpage, &man->meta, man->first); - else - parse_cat(mpage, fd); - if (mpage->desc == NULL) - mpage->desc = mandoc_strdup(mpage->mlinks->name); - - if (warnings && !use_all) - for (mlink = mpage->mlinks; mlink; - mlink = mlink->next) + for (mlink = mpage->mlinks; + mlink != NULL; + mlink = mlink->next) { + putkey(mpage, mlink->name, NAME_FILE); + if (warnings && !use_all) mlink_check(mpage, mlink); + } dbadd(dba, mpage); - mlink = mpage->mlinks; nextpage: ohash_delete(&strings); @@ -1234,29 +1258,48 @@ static void parse_cat(struct mpage *mpage, int fd) { FILE *stream; - char *line, *p, *title; + struct mlink *mlink; + char *line, *p, *title, *sec; size_t linesz, plen, titlesz; ssize_t len; int offs; - stream = (-1 == fd) ? - fopen(mpage->mlinks->file, "r") : - fdopen(fd, "r"); - if (NULL == stream) { - if (-1 != fd) + mlink = mpage->mlinks; + stream = fd == -1 ? fopen(mlink->file, "r") : fdopen(fd, "r"); + if (stream == NULL) { + if (fd != -1) close(fd); if (warnings) - say(mpage->mlinks->file, "&fopen"); + say(mlink->file, "&fopen"); return; } line = NULL; linesz = 0; + /* Parse the section number from the header line. */ + + while (getline(&line, &linesz, stream) != -1) { + if (*line == '\n') + continue; + if ((sec = strchr(line, '(')) == NULL) + break; + if ((p = strchr(++sec, ')')) == NULL) + break; + free(mpage->sec); + mpage->sec = mandoc_strndup(sec, p - sec); + if (warnings && *mlink->dsec != '\0' && + strcasecmp(mpage->sec, mlink->dsec)) + say(mlink->file, + "Section \"%s\" manual in %s directory", + mpage->sec, mlink->dsec); + break; + } + /* Skip to first blank line. */ - while (getline(&line, &linesz, stream) != -1) - if (*line == '\n') + while (line == NULL || *line != '\n') + if (getline(&line, &linesz, stream) == -1) break; /* @@ -1302,8 +1345,7 @@ parse_cat(struct mpage *mpage, int fd) if (NULL == title || '\0' == *title) { if (warnings) - say(mpage->mlinks->file, - "Cannot find NAME section"); + say(mlink->file, "Cannot find NAME section"); fclose(stream); free(title); return; @@ -1322,8 +1364,8 @@ parse_cat(struct mpage *mpage, int fd) /* Skip to next word. */ ; } else { if (warnings) - say(mpage->mlinks->file, - "No dash in title line"); + say(mlink->file, "No dash in title line, " + "reusing \"%s\" as one-line description", title); p = title; } diff --git a/manpath.c b/manpath.c index 008c59392379..f43ace60694e 100644 --- a/manpath.c +++ b/manpath.c @@ -1,6 +1,6 @@ -/* $Id: manpath.c,v 1.31 2016/07/19 22:40:33 schwarze Exp $ */ +/* $Id: manpath.c,v 1.33 2017/02/10 15:45:28 schwarze Exp $ */ /* - * Copyright (c) 2011, 2014, 2015 Ingo Schwarze + * Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze * Copyright (c) 2011 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any @@ -207,7 +207,7 @@ manconf_file(struct manconf *conf, const char *file) *manpath_default = '\0'; break; case 1: /* output */ - manconf_output(&conf->output, cp); + manconf_output(&conf->output, cp, 1); break; default: break; @@ -221,15 +221,17 @@ manconf_file(struct manconf *conf, const char *file) manpath_parseline(&conf->manpath, manpath_default, 0); } -void -manconf_output(struct manoutput *conf, const char *cp) +int +manconf_output(struct manoutput *conf, const char *cp, int fromfile) { const char *const toks[] = { "includes", "man", "paper", "style", - "indent", "width", "fragment", "mdoc" + "indent", "width", "fragment", "mdoc", "noval" }; - size_t len, tok; + const char *errstr; + char *oldval; + size_t len, tok; for (tok = 0; tok < sizeof(toks)/sizeof(toks[0]); tok++) { len = strlen(toks[tok]); @@ -244,41 +246,81 @@ manconf_output(struct manoutput *conf, const char *cp) } } - if (tok < 6 && *cp == '\0') - return; + if (tok < 6 && *cp == '\0') { + warnx("-O %s=?: Missing argument value", toks[tok]); + return -1; + } + if ((tok == 6 || tok == 7) && *cp != '\0') { + warnx("-O %s: Does not take a value: %s", toks[tok], cp); + return -1; + } switch (tok) { case 0: - if (conf->includes == NULL) - conf->includes = mandoc_strdup(cp); - break; + if (conf->includes != NULL) { + oldval = mandoc_strdup(conf->includes); + break; + } + conf->includes = mandoc_strdup(cp); + return 0; case 1: - if (conf->man == NULL) - conf->man = mandoc_strdup(cp); - break; + if (conf->man != NULL) { + oldval = mandoc_strdup(conf->man); + break; + } + conf->man = mandoc_strdup(cp); + return 0; case 2: - if (conf->paper == NULL) - conf->paper = mandoc_strdup(cp); - break; + if (conf->paper != NULL) { + oldval = mandoc_strdup(conf->paper); + break; + } + conf->paper = mandoc_strdup(cp); + return 0; case 3: - if (conf->style == NULL) - conf->style = mandoc_strdup(cp); - break; + if (conf->style != NULL) { + oldval = mandoc_strdup(conf->style); + break; + } + conf->style = mandoc_strdup(cp); + return 0; case 4: - if (conf->indent == 0) - conf->indent = strtonum(cp, 0, 1000, NULL); - break; + if (conf->indent) { + mandoc_asprintf(&oldval, "%zu", conf->indent); + break; + } + conf->indent = strtonum(cp, 0, 1000, &errstr); + if (errstr == NULL) + return 0; + warnx("-O indent=%s is %s", cp, errstr); + return -1; case 5: - if (conf->width == 0) - conf->width = strtonum(cp, 58, 1000, NULL); - break; + if (conf->width) { + mandoc_asprintf(&oldval, "%zu", conf->width); + break; + } + conf->width = strtonum(cp, 58, 1000, &errstr); + if (errstr == NULL) + return 0; + warnx("-O width=%s is %s", cp, errstr); + return -1; case 6: conf->fragment = 1; - break; + return 0; case 7: conf->mdoc = 1; - break; + return 0; + case 8: + conf->noval = 1; + return 0; default: - break; + if (fromfile) + warnx("-O %s: Bad argument", cp); + 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/mdoc.7 b/mdoc.7 index e28db482db0f..6d95887736a1 100644 --- a/mdoc.7 +++ b/mdoc.7 @@ -1,4 +1,4 @@ -.\" $Id: mdoc.7,v 1.260 2017/01/09 14:10:53 schwarze Exp $ +.\" $Id: mdoc.7,v 1.262 2017/02/16 14:38:12 schwarze Exp $ .\" .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons .\" Copyright (c) 2010, 2011, 2013-2017 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 9 2017 $ +.Dd $Mdocdate: February 16 2017 $ .Dt MDOC 7 .Os .Sh NAME @@ -974,10 +974,8 @@ argument. A columnated list. The .Fl width -argument has no effect; instead, each argument specifies the width -of one column, using either the scaling width syntax described in -.Xr roff 7 -or the string length of the argument. +argument has no effect; instead, the string length of each argument +specifies the width of one column. If the first line of the body of a .Fl column list is not an @@ -3064,6 +3062,8 @@ For many macros, when the leading arguments are opening delimiters, these delimiters are put before the macro scope, and when the trailing arguments are closing delimiters, these delimiters are put after the macro scope. +Spacing is suppressed after opening delimiters +and before closing delimiters. For example, .Pp .D1 Pf \. \&Aq "( [ word ] ) ." @@ -3120,7 +3120,7 @@ renders as: .D1 Fl a ( b | c \*(Ba d ) e .Pp This applies to both opening and closing delimiters, -and also to the middle delimiter: +and also to the middle delimiter, which does not suppress spacing: .Pp .Bl -tag -width Ds -offset indent -compact .It \&| diff --git a/mdoc.c b/mdoc.c index 009496184ab4..5be1e7810d55 100644 --- a/mdoc.c +++ b/mdoc.c @@ -1,7 +1,7 @@ -/* $Id: mdoc.c,v 1.258 2017/01/10 13:47:00 schwarze Exp $ */ +/* $Id: mdoc.c,v 1.260 2017/02/16 03:00:23 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons - * Copyright (c) 2010, 2012-2016 Ingo Schwarze + * Copyright (c) 2010, 2012-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 @@ -136,7 +136,7 @@ mdoc_tail_alloc(struct roff_man *mdoc, int line, int pos, int tok) struct roff_node * mdoc_endbody_alloc(struct roff_man *mdoc, int line, int pos, int tok, - struct roff_node *body, enum mdoc_endbody end) + struct roff_node *body) { struct roff_node *p; @@ -145,7 +145,7 @@ mdoc_endbody_alloc(struct roff_man *mdoc, int line, int pos, int tok, p = roff_node_alloc(mdoc, line, pos, ROFFT_BODY, tok); p->body = body; p->norm = body->norm; - p->end = end; + p->end = ENDBODY_SPACE; roff_node_append(mdoc, p); mdoc->next = ROFF_NEXT_SIBLING; return p; @@ -312,6 +312,22 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs) if (mandoc_eos(buf+offs, (size_t)(end-buf-offs))) mdoc->last->flags |= NODE_EOS; + + for (c = buf + offs; c != NULL; c = strchr(c + 1, '.')) { + if (c - buf < offs + 2) + continue; + if (end - c < 4) + break; + if (isalpha((unsigned char)c[-2]) && + isalpha((unsigned char)c[-1]) && + c[1] == ' ' && + isupper((unsigned char)(c[2] == ' ' ? c[3] : c[2])) && + (c[-2] != 'n' || c[-1] != 'c') && + (c[-2] != 'v' || c[-1] != 's')) + mandoc_msg(MANDOCERR_EOS, mdoc->parse, + line, (int)(c - buf), NULL); + } + return 1; } diff --git a/mdoc_html.c b/mdoc_html.c index 3f757d20eb3d..e82451416699 100644 --- a/mdoc_html.c +++ b/mdoc_html.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_html.c,v 1.260 2017/01/21 02:09:51 schwarze Exp $ */ +/* $Id: mdoc_html.c,v 1.271 2017/02/16 03:00:23 schwarze Exp $ */ /* * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons * Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze @@ -110,6 +110,7 @@ static int mdoc_skip_pre(MDOC_ARGS); static int mdoc_sm_pre(MDOC_ARGS); static int mdoc_sp_pre(MDOC_ARGS); static int mdoc_ss_pre(MDOC_ARGS); +static int mdoc_st_pre(MDOC_ARGS); static int mdoc_sx_pre(MDOC_ARGS); static int mdoc_sy_pre(MDOC_ARGS); static int mdoc_va_pre(MDOC_ARGS); @@ -155,7 +156,7 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = { {mdoc_ft_pre, NULL}, /* Ot */ {mdoc_pa_pre, NULL}, /* Pa */ {mdoc_ex_pre, NULL}, /* Rv */ - {NULL, NULL}, /* St */ + {mdoc_st_pre, NULL}, /* St */ {mdoc_va_pre, NULL}, /* Va */ {mdoc_vt_pre, NULL}, /* Vt */ {mdoc_xr_pre, NULL}, /* Xr */ @@ -173,7 +174,7 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = { {NULL, NULL}, /* Ac */ {mdoc_quote_pre, mdoc_quote_post}, /* Ao */ {mdoc_quote_pre, mdoc_quote_post}, /* Aq */ - {NULL, NULL}, /* At */ + {mdoc_xx_pre, NULL}, /* At */ {NULL, NULL}, /* Bc */ {mdoc_bf_pre, NULL}, /* Bf */ {mdoc_quote_pre, mdoc_quote_post}, /* Bo */ @@ -349,7 +350,7 @@ print_mdoc_node(MDOC_ARGS) return; child = 1; - t = h->tags.head; + t = h->tag; n->flags &= ~NODE_ENDED; switch (n->type) { @@ -389,7 +390,7 @@ print_mdoc_node(MDOC_ARGS) */ if (h->tblt != NULL) { print_tblclose(h); - t = h->tags.head; + t = h->tag; } assert(h->tblt == NULL); if (mdocs[n->tok].pre && (n->end == ENDBODY_NOT || n->child)) @@ -416,8 +417,6 @@ print_mdoc_node(MDOC_ARGS) (*mdocs[n->tok].post)(meta, n, h); if (n->end != ENDBODY_NOT) n->body->flags |= NODE_ENDED; - if (n->end == ENDBODY_NOSPACE) - h->flags |= HTML_NOSPACE; break; } } @@ -428,7 +427,6 @@ mdoc_root_post(MDOC_ARGS) struct tag *t, *tt; t = print_otag(h, TAG_TABLE, "c", "foot"); - print_otag(h, TAG_TBODY, ""); tt = print_otag(h, TAG_TR, ""); print_otag(h, TAG_TD, "c", "foot-date"); @@ -459,7 +457,6 @@ mdoc_root_pre(MDOC_ARGS) meta->title, meta->msec); t = print_otag(h, TAG_TABLE, "c", "head"); - print_otag(h, TAG_TBODY, ""); tt = print_otag(h, TAG_TR, ""); print_otag(h, TAG_TD, "c", "head-ltitle"); @@ -507,22 +504,18 @@ mdoc_sh_pre(MDOC_ARGS) char *id; switch (n->type) { - case ROFFT_BLOCK: - return 1; + case ROFFT_HEAD: + id = make_id(n); + print_otag(h, TAG_H1, "ci", "Sh", id); + free(id); + break; case ROFFT_BODY: if (n->sec == SEC_AUTHORS) h->flags &= ~(HTML_SPLIT|HTML_NOSPLIT); - return 1; + break; default: break; } - - if ((id = make_id(n)) != NULL) { - print_otag(h, TAG_H1, "ci", "Sh", id); - free(id); - } else - print_otag(h, TAG_H1, "c", "Sh"); - return 1; } @@ -534,12 +527,9 @@ mdoc_ss_pre(MDOC_ARGS) if (n->type != ROFFT_HEAD) return 1; - if ((id = make_id(n)) != NULL) { - print_otag(h, TAG_H2, "ci", "Ss", id); - free(id); - } else - print_otag(h, TAG_H2, "c", "Ss"); - + id = make_id(n); + print_otag(h, TAG_H2, "ci", "Ss", id); + free(id); return 1; } @@ -581,6 +571,7 @@ mdoc_nd_pre(MDOC_ARGS) static int mdoc_nm_pre(MDOC_ARGS) { + struct tag *t; int len; switch (n->type) { @@ -589,8 +580,6 @@ mdoc_nm_pre(MDOC_ARGS) /* FALLTHROUGH */ case ROFFT_ELEM: print_otag(h, TAG_B, "c", "Nm"); - if (n->child == NULL && meta->name != NULL) - print_text(h, meta->name); return 1; case ROFFT_BODY: print_otag(h, TAG_TD, ""); @@ -609,9 +598,10 @@ mdoc_nm_pre(MDOC_ARGS) if (len == 0 && meta->name != NULL) len = html_strlen(meta->name); + t = print_otag(h, TAG_COLGROUP, ""); print_otag(h, TAG_COL, "shw", len); print_otag(h, TAG_COL, ""); - print_otag(h, TAG_TBODY, ""); + print_tagq(h, t); print_otag(h, TAG_TR, ""); return 1; } @@ -656,7 +646,7 @@ mdoc_ns_pre(MDOC_ARGS) static int mdoc_ar_pre(MDOC_ARGS) { - print_otag(h, TAG_I, "c", "Ar"); + print_otag(h, TAG_VAR, "c", "Ar"); return 1; } @@ -671,6 +661,7 @@ static int mdoc_it_pre(MDOC_ARGS) { const struct roff_node *bl; + struct tag *t; const char *cattr; enum mdoc_list type; @@ -738,7 +729,6 @@ mdoc_it_pre(MDOC_ARGS) case LIST_hang: case LIST_inset: case LIST_ohang: - case LIST_tag: switch (n->type) { case ROFFT_HEAD: if (bl->norm->Bl.comp) @@ -749,11 +739,37 @@ mdoc_it_pre(MDOC_ARGS) print_otag(h, TAG_B, "c", cattr); break; case ROFFT_BODY: - if (bl->norm->Bl.width == NULL) + print_otag(h, TAG_DD, "cswl", cattr, + bl->norm->Bl.width); + break; + default: + break; + } + break; + case LIST_tag: + switch (n->type) { + case ROFFT_HEAD: + if (h->style != NULL && !bl->norm->Bl.comp && + (n->parent->prev == NULL || + n->parent->prev->body->child != NULL)) { + t = print_otag(h, TAG_DT, "csWl", + cattr, bl->norm->Bl.width); + print_text(h, "\\ "); + print_tagq(h, t); + t = print_otag(h, TAG_DD, "c", cattr); + print_text(h, "\\ "); + print_tagq(h, t); + } + print_otag(h, TAG_DT, "csWl", cattr, + bl->norm->Bl.width); + break; + case ROFFT_BODY: + if (n->child == NULL) { + print_otag(h, TAG_DD, "css?", cattr, + "width", "auto"); + print_text(h, "\\ "); + } else print_otag(h, TAG_DD, "c", cattr); - else - print_otag(h, TAG_DD, "cswl", cattr, - bl->norm->Bl.width); break; default: break; @@ -782,18 +798,20 @@ mdoc_it_pre(MDOC_ARGS) static int mdoc_bl_pre(MDOC_ARGS) { + struct tag *t; + struct mdoc_bl *bl; const char *cattr; - int i; + size_t i; enum htmltag elemtype; - if (n->type == ROFFT_BODY) { - if (LIST_column == n->norm->Bl.type) - print_otag(h, TAG_TBODY, ""); - return 1; - } + bl = &n->norm->Bl; - if (n->type == ROFFT_HEAD) { - if (LIST_column != n->norm->Bl.type) + switch (n->type) { + case ROFFT_BODY: + return 1; + + case ROFFT_HEAD: + if (bl->type != LIST_column || bl->ncols == 0) return 0; /* @@ -803,14 +821,18 @@ mdoc_bl_pre(MDOC_ARGS) * screen and we want to preserve that behaviour. */ - for (i = 0; i < (int)n->norm->Bl.ncols - 1; i++) - print_otag(h, TAG_COL, "sww", n->norm->Bl.cols[i]); - print_otag(h, TAG_COL, "swW", n->norm->Bl.cols[i]); - + t = print_otag(h, TAG_COLGROUP, ""); + for (i = 0; i < bl->ncols - 1; i++) + print_otag(h, TAG_COL, "sww", bl->cols[i]); + print_otag(h, TAG_COL, "swW", bl->cols[i]); + print_tagq(h, t); return 0; + + default: + break; } - switch (n->norm->Bl.type) { + switch (bl->type) { case LIST_bullet: elemtype = TAG_UL; cattr = "Bl-bullet"; @@ -845,9 +867,11 @@ mdoc_bl_pre(MDOC_ARGS) cattr = "Bl-ohang"; break; case LIST_tag: - elemtype = TAG_DL; cattr = "Bl-tag"; - break; + if (bl->offs) + print_otag(h, TAG_DIV, "cswl", cattr, bl->offs); + print_otag(h, TAG_DL, "cswl", cattr, bl->width); + return 1; case LIST_column: elemtype = TAG_TABLE; cattr = "Bl-column"; @@ -855,12 +879,7 @@ mdoc_bl_pre(MDOC_ARGS) default: abort(); } - - if (n->norm->Bl.offs) - print_otag(h, elemtype, "cswl", cattr, n->norm->Bl.offs); - else - print_otag(h, elemtype, "c", cattr); - + print_otag(h, elemtype, "cswl", cattr, bl->offs); return 1; } @@ -872,6 +891,13 @@ mdoc_ex_pre(MDOC_ARGS) return 1; } +static int +mdoc_st_pre(MDOC_ARGS) +{ + print_otag(h, TAG_SPAN, "c", "St"); + return 1; +} + static int mdoc_em_pre(MDOC_ARGS) { @@ -898,12 +924,9 @@ mdoc_sx_pre(MDOC_ARGS) { char *id; - if ((id = make_id(n)) != NULL) { - print_otag(h, TAG_A, "chR", "Sx", id); - free(id); - } else - print_otag(h, TAG_A, "c", "Sx"); - + id = make_id(n); + print_otag(h, TAG_A, "chR", "Sx", id); + free(id); return 1; } @@ -1069,12 +1092,12 @@ mdoc_fa_pre(MDOC_ARGS) struct tag *t; if (n->parent->tok != MDOC_Fo) { - print_otag(h, TAG_I, "c", "Fa"); + print_otag(h, TAG_VAR, "c", "Fa"); return 1; } for (nn = n->child; nn; nn = nn->next) { - t = print_otag(h, TAG_I, "c", "Fa"); + t = print_otag(h, TAG_VAR, "c", "Fa"); print_text(h, nn->string); print_tagq(h, t); if (nn->next) { @@ -1153,7 +1176,7 @@ mdoc_vt_pre(MDOC_ARGS) } else if (n->type == ROFFT_HEAD) return 0; - print_otag(h, TAG_I, "c", "Vt"); + print_otag(h, TAG_VAR, "c", "Vt"); return 1; } @@ -1161,7 +1184,7 @@ static int mdoc_ft_pre(MDOC_ARGS) { synopsis_pre(h, n); - print_otag(h, TAG_I, "c", "Ft"); + print_otag(h, TAG_VAR, "c", "Ft"); return 1; } @@ -1182,7 +1205,7 @@ mdoc_fn_pre(MDOC_ARGS) ep = strchr(sp, ' '); if (NULL != ep) { - t = print_otag(h, TAG_I, "c", "Ft"); + t = print_otag(h, TAG_VAR, "c", "Ft"); while (ep) { sz = MIN((int)(ep - sp), BUFSIZ - 1); @@ -1208,10 +1231,10 @@ mdoc_fn_pre(MDOC_ARGS) for (n = n->child->next; n; n = n->next) { if (NODE_SYNPRETTY & n->flags) - t = print_otag(h, TAG_I, "css?", "Fa", + t = print_otag(h, TAG_VAR, "css?", "Fa", "white-space", "nowrap"); else - t = print_otag(h, TAG_I, "c", "Fa"); + t = print_otag(h, TAG_VAR, "c", "Fa"); print_text(h, n->string); print_tagq(h, t); if (n->next) { @@ -1419,7 +1442,7 @@ mdoc_ic_pre(MDOC_ARGS) static int mdoc_va_pre(MDOC_ARGS) { - print_otag(h, TAG_I, "c", "Va"); + print_otag(h, TAG_VAR, "c", "Va"); return 1; } @@ -1450,7 +1473,7 @@ mdoc_bf_pre(MDOC_ARGS) else if (FONT_Li == n->norm->Bf.font) cattr = "Li"; else - cattr = "none"; + cattr = "No"; /* * We want this to be inline-formatted, but needs to be div to @@ -1493,7 +1516,7 @@ mdoc_rs_pre(MDOC_ARGS) if (n->prev && SEC_SEE_ALSO == n->sec) print_paragraph(h); - print_otag(h, TAG_SPAN, "c", "Rs"); + print_otag(h, TAG_CITE, "c", "Rs"); return 1; } diff --git a/mdoc_macro.c b/mdoc_macro.c index d4edcea14162..5ab9c412587b 100644 --- a/mdoc_macro.c +++ b/mdoc_macro.c @@ -1,7 +1,7 @@ -/* $Id: mdoc_macro.c,v 1.210 2017/01/10 13:47:00 schwarze Exp $ */ +/* $Id: mdoc_macro.c,v 1.217 2017/02/16 09:47:31 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons - * Copyright (c) 2010, 2012-2016 Ingo Schwarze + * Copyright (c) 2010, 2012-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 @@ -50,6 +50,8 @@ static int find_pending(struct roff_man *, int, int, int, struct roff_node *); static int lookup(struct roff_man *, int, int, int, const char *); static int macro_or_word(MACRO_PROT_ARGS, int); +static void break_intermediate(struct roff_node *, + struct roff_node *); static int parse_rest(struct roff_man *, int, int, int *, char *); static int rew_alt(int); static void rew_elem(struct roff_man *, int); @@ -376,6 +378,20 @@ rew_elem(struct roff_man *mdoc, int tok) rew_last(mdoc, n); } +static void +break_intermediate(struct roff_node *n, struct roff_node *breaker) +{ + if (n != breaker && + n->type != ROFFT_BLOCK && n->type != ROFFT_HEAD && + (n->type != ROFFT_BODY || n->end != ENDBODY_NOT)) + n = n->parent; + while (n != breaker) { + if ( ! (n->flags & NODE_VALID)) + n->flags |= NODE_BROKEN; + n = n->parent; + } +} + /* * If there is an open sub-block of the target requiring * explicit close-out, postpone closing out the target until @@ -388,26 +404,26 @@ find_pending(struct roff_man *mdoc, int tok, int line, int ppos, struct roff_node *n; int irc; + if (target->flags & NODE_VALID) + return 0; + irc = 0; for (n = mdoc->last; n != NULL && n != target; n = n->parent) { - if (n->flags & NODE_ENDED) { - if ( ! (n->flags & NODE_VALID)) - n->flags |= NODE_BROKEN; + if (n->flags & NODE_ENDED) continue; - } if (n->type == ROFFT_BLOCK && mdoc_macros[n->tok].flags & MDOC_EXPLICIT) { irc = 1; - n->flags = NODE_BROKEN; + break_intermediate(mdoc->last, target); if (target->type == ROFFT_HEAD) - target->flags = NODE_ENDED; + target->flags |= NODE_ENDED; else if ( ! (target->flags & NODE_ENDED)) { mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse, line, ppos, "%s breaks %s", mdoc_macronames[tok], mdoc_macronames[n->tok]); mdoc_endbody_alloc(mdoc, line, ppos, - tok, target, ENDBODY_NOSPACE); + tok, target); } } } @@ -568,30 +584,34 @@ blk_exp_close(MACRO_PROT_ARGS) endbody = itblk = later = NULL; for (n = mdoc->last; n; n = n->parent) { - if (n->flags & NODE_ENDED) { - if ( ! (n->flags & NODE_VALID)) - n->flags |= NODE_BROKEN; + if (n->flags & NODE_ENDED) continue; - } /* - * Mismatching end macros can never break anything, - * SYNOPSIS name blocks can never be broken, + * Mismatching end macros can never break anything * and we only care about the breaking of BLOCKs. */ - if (body == NULL || - n->tok == MDOC_Nm || - n->type != ROFFT_BLOCK) + if (body == NULL || n->type != ROFFT_BLOCK) continue; + /* + * SYNOPSIS name blocks can not be broken themselves, + * but they do get broken together with a broken child. + */ + + if (n->tok == MDOC_Nm) { + if (later != NULL) + n->flags |= NODE_BROKEN | NODE_ENDED; + continue; + } + if (n->tok == MDOC_It) { itblk = n; continue; } if (atok == n->tok) { - assert(body); /* * Found the start of our own block. @@ -617,7 +637,7 @@ blk_exp_close(MACRO_PROT_ARGS) mdoc_macronames[later->tok]); endbody = mdoc_endbody_alloc(mdoc, line, ppos, - atok, body, ENDBODY_SPACE); + atok, body); if (tok == MDOC_El) itblk->flags |= NODE_ENDED | NODE_BROKEN; @@ -633,15 +653,22 @@ blk_exp_close(MACRO_PROT_ARGS) break; } - /* Explicit blocks close out description lines. */ + /* + * Explicit blocks close out description lines, but + * even those can get broken together with a child. + */ if (n->tok == MDOC_Nd) { - rew_last(mdoc, n); + if (later != NULL) + n->flags |= NODE_BROKEN | NODE_ENDED; + else + rew_last(mdoc, n); continue; } /* Breaking an open sub block. */ + break_intermediate(mdoc->last, body); n->flags |= NODE_BROKEN; if (later == NULL) later = n; @@ -706,15 +733,14 @@ blk_exp_close(MACRO_PROT_ARGS) } if (n != NULL) { + pending = 0; if (ntok != TOKEN_NONE && n->flags & NODE_BROKEN) { target = n; do target = target->parent; while ( ! (target->flags & NODE_ENDED)); - pending = find_pending(mdoc, ntok, line, ppos, - target); - } else - pending = 0; + pending = find_pending(mdoc, ntok, line, ppos, target); + } if ( ! pending) rew_pending(mdoc, n); } @@ -987,7 +1013,7 @@ blk_full(MACRO_PROT_ARGS) /* Close out prior implicit scopes. */ - rew_last(mdoc, n); + rew_pending(mdoc, n); } /* Skip items outside lists. */ diff --git a/mdoc_man.c b/mdoc_man.c index 2c19e15fb8ba..88d39370e8c2 100644 --- a/mdoc_man.c +++ b/mdoc_man.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_man.c,v 1.101 2017/01/11 17:39:53 schwarze Exp $ */ +/* $Id: mdoc_man.c,v 1.104 2017/02/17 19:15:41 schwarze Exp $ */ /* * Copyright (c) 2011-2017 Ingo Schwarze * @@ -639,9 +639,6 @@ print_node(DECL_ARGS) if (ENDBODY_NOT != n->end) n->body->flags |= NODE_ENDED; - - if (ENDBODY_NOSPACE == n->end) - outflags &= ~(MMAN_spc | MMAN_nl); } static int @@ -720,8 +717,7 @@ pre__t(DECL_ARGS) if (n->parent && MDOC_Rs == n->parent->tok && n->parent->norm->Rs.quote_T) { - print_word(""); - putchar('\"'); + print_word("\\(lq"); outflags &= ~MMAN_spc; } else font_push('I'); @@ -735,8 +731,7 @@ post__t(DECL_ARGS) if (n->parent && MDOC_Rs == n->parent->tok && n->parent->norm->Rs.quote_T) { outflags &= ~MMAN_spc; - print_word(""); - putchar('\"'); + print_word("\\(rq"); } else font_pop(); post_percent(meta, n); @@ -1518,7 +1513,7 @@ pre_nm(DECL_ARGS) } if (n->type != ROFFT_ELEM && n->type != ROFFT_HEAD) return 1; - name = n->child ? n->child->string : meta->name; + name = n->child == NULL ? NULL : n->child->string; if (NULL == name) return 0; if (n->type == ROFFT_HEAD) { @@ -1529,8 +1524,6 @@ pre_nm(DECL_ARGS) outflags |= MMAN_nl; } font_push('B'); - if (NULL == n->child) - print_word(meta->name); return 1; } @@ -1544,7 +1537,7 @@ post_nm(DECL_ARGS) break; case ROFFT_HEAD: case ROFFT_ELEM: - if (n->child != NULL || meta->name != NULL) + if (n->child != NULL && n->child->string != NULL) font_pop(); break; default: diff --git a/mdoc_term.c b/mdoc_term.c index dad54c8c44f9..e9ea455a48e8 100644 --- a/mdoc_term.c +++ b/mdoc_term.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_term.c,v 1.341 2017/01/11 17:39:53 schwarze Exp $ */ +/* $Id: mdoc_term.c,v 1.346 2017/02/17 19:15:41 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2010, 2012-2017 Ingo Schwarze @@ -258,6 +258,7 @@ terminal_mdoc(void *arg, const struct roff_man *mdoc) { struct roff_node *n; struct termp *p; + size_t save_defindent; p = (struct termp *)arg; p->overstep = 0; @@ -278,6 +279,7 @@ terminal_mdoc(void *arg, const struct roff_man *mdoc) n = n->next; } } else { + save_defindent = p->defindent; if (p->defindent == 0) p->defindent = 5; term_begin(p, print_mdoc_head, print_mdoc_foot, @@ -290,6 +292,7 @@ terminal_mdoc(void *arg, const struct roff_man *mdoc) print_mdoc_nodelist(p, NULL, &mdoc->meta, n); } term_end(p); + p->defindent = save_defindent; } } @@ -392,14 +395,6 @@ print_mdoc_node(DECL_ARGS) */ if (ENDBODY_NOT != n->end) n->body->flags |= NODE_ENDED; - - /* - * End of line terminating an implicit block - * while an explicit block is still open. - * Continue the explicit block without spacing. - */ - if (ENDBODY_NOSPACE == n->end) - p->flags |= TERMP_NOSPACE; break; } @@ -611,6 +606,7 @@ termp_ll_pre(DECL_ARGS) static int termp_it_pre(DECL_ARGS) { + struct roffsu su; char buf[24]; const struct roff_node *bl, *nn; size_t ncols, dcol; @@ -688,9 +684,12 @@ termp_it_pre(DECL_ARGS) for (i = 0, nn = n->prev; nn->prev && i < (int)ncols; - nn = nn->prev, i++) - offset += dcol + a2width(p, - bl->norm->Bl.cols[i]); + nn = nn->prev, i++) { + SCALE_HS_INIT(&su, + term_strlen(p, bl->norm->Bl.cols[i])); + su.scale /= term_strlen(p, "0"); + offset += term_hspan(p, &su) / 24 + dcol; + } /* * When exceeding the declared number of columns, leave @@ -705,7 +704,9 @@ termp_it_pre(DECL_ARGS) * Use the declared column widths, extended as explained * in the preceding paragraph. */ - width = a2width(p, bl->norm->Bl.cols[i]) + dcol; + SCALE_HS_INIT(&su, term_strlen(p, bl->norm->Bl.cols[i])); + su.scale /= term_strlen(p, "0"); + width = term_hspan(p, &su) / 24 + dcol; break; default: if (NULL == bl->norm->Bl.width) @@ -993,7 +994,7 @@ termp_nm_pre(DECL_ARGS) return 1; } - if (NULL == n->child && NULL == meta->name) + if (n->child == NULL) return 0; if (n->type == ROFFT_HEAD) @@ -1017,8 +1018,6 @@ termp_nm_pre(DECL_ARGS) } term_fontpush(p, TERMFONT_BOLD); - if (NULL == n->child) - term_word(p, meta->name); return 1; } @@ -1715,6 +1714,8 @@ termp_quote_pre(DECL_ARGS) case MDOC_Bq: term_word(p, "["); break; + case MDOC__T: + /* FALLTHROUGH */ case MDOC_Do: case MDOC_Dq: term_word(p, "\\(Lq"); @@ -1729,7 +1730,6 @@ termp_quote_pre(DECL_ARGS) case MDOC_Pq: term_word(p, "("); break; - case MDOC__T: case MDOC_Qo: case MDOC_Qq: term_word(p, "\""); @@ -1772,6 +1772,8 @@ termp_quote_post(DECL_ARGS) case MDOC_Bq: term_word(p, "]"); break; + case MDOC__T: + /* FALLTHROUGH */ case MDOC_Do: case MDOC_Dq: term_word(p, "\\(Rq"); @@ -1788,7 +1790,6 @@ termp_quote_post(DECL_ARGS) case MDOC_Pq: term_word(p, ")"); break; - case MDOC__T: case MDOC_Qo: case MDOC_Qq: term_word(p, "\""); diff --git a/mdoc_validate.c b/mdoc_validate.c index 043145ae1ccc..e58e7a4721a9 100644 --- a/mdoc_validate.c +++ b/mdoc_validate.c @@ -1,4 +1,4 @@ -/* $Id: mdoc_validate.c,v 1.317 2017/01/11 17:39:53 schwarze Exp $ */ +/* $Id: mdoc_validate.c,v 1.318 2017/02/06 03:44:58 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons * Copyright (c) 2010-2017 Ingo Schwarze @@ -1013,6 +1013,16 @@ post_nm(POST_ARGS) (mdoc->lastsec == SEC_NAME && n->child == NULL)) mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse, n->line, n->pos, "Nm"); + + if ((n->type != ROFFT_ELEM && n->type != ROFFT_HEAD) || + (n->child != NULL && n->child->type == ROFFT_TEXT) || + mdoc->meta.name == NULL) + return; + + mdoc->next = ROFF_NEXT_CHILD; + roff_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name); + mdoc->last->flags |= NODE_NOSRC; + mdoc->last = n; } static void diff --git a/preconv.c b/preconv.c index 1fc137a9640d..08f8df86a61b 100644 --- a/preconv.c +++ b/preconv.c @@ -1,4 +1,4 @@ -/* $Id: preconv.c,v 1.15 2015/10/06 18:32:19 schwarze Exp $ */ +/* $Id: preconv.c,v 1.16 2017/02/18 13:43:52 schwarze Exp $ */ /* * Copyright (c) 2011 Kristaps Dzonsons * Copyright (c) 2014 Ingo Schwarze @@ -26,14 +26,14 @@ #include "libmandoc.h" int -preconv_encode(struct buf *ib, size_t *ii, struct buf *ob, size_t *oi, +preconv_encode(const struct buf *ib, size_t *ii, struct buf *ob, size_t *oi, int *filenc) { - unsigned char *cu; - int nby; - unsigned int accum; + const unsigned char *cu; + int nby; + unsigned int accum; - cu = (unsigned char *)ib->buf + *ii; + cu = (const unsigned char *)ib->buf + *ii; assert(*cu & 0x80); if ( ! (*filenc & MPARSE_UTF8)) @@ -90,7 +90,7 @@ preconv_encode(struct buf *ib, size_t *ii, struct buf *ob, size_t *oi, assert(accum < 0xd800 || accum > 0xdfff); *oi += snprintf(ob->buf + *oi, 11, "\\[u%.4X]", accum); - *ii = (char *)cu - ib->buf; + *ii = (const char *)cu - ib->buf; *filenc &= ~MPARSE_LATIN1; return 1; diff --git a/read.c b/read.c index d20a6098e9e4..3e5d41161a0c 100644 --- a/read.c +++ b/read.c @@ -1,4 +1,4 @@ -/* $Id: read.c,v 1.157 2017/01/09 01:37:03 schwarze Exp $ */ +/* $Id: read.c,v 1.161 2017/02/18 17:29:28 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2010-2017 Ingo Schwarze @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -48,8 +47,8 @@ #define REPARSE_LIMIT 1000 struct mparse { - struct roff_man *man; /* man parser */ struct roff *roff; /* roff parser (!NULL) */ + struct roff_man *man; /* man parser */ char *sodest; /* filename pointed to by .so */ const char *file; /* filename of current input file */ struct buf *primary; /* buffer currently being parsed */ @@ -177,6 +176,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = { "blank line in fill mode, using .sp", "tab in filled text", "whitespace at end of input line", + "new sentence, new line", "bad comment style", "invalid escape sequence", "undefined string, using \"\"", @@ -602,12 +602,11 @@ static int read_whole_file(struct mparse *curp, const char *file, int fd, struct buf *fb, int *with_mmap) { + struct stat st; gzFile gz; size_t off; ssize_t ssz; - struct stat st; - if (fstat(fd, &st) == -1) err((int)MANDOCLEVEL_SYSERR, "%s", file); @@ -829,13 +828,15 @@ mparse_reset(struct mparse *curp) { roff_reset(curp->roff); roff_man_reset(curp->man); + + free(curp->sodest); + curp->sodest = NULL; + if (curp->secondary) curp->secondary->sz = 0; curp->file_status = MANDOCLEVEL_OK; - - free(curp->sodest); - curp->sodest = NULL; + curp->gzip = 0; } void @@ -843,8 +844,7 @@ mparse_free(struct mparse *curp) { roff_man_free(curp->man); - if (curp->roff) - roff_free(curp->roff); + roff_free(curp->roff); if (curp->secondary) free(curp->secondary->buf); diff --git a/roff.c b/roff.c index 966ed9d53dd9..ad55d320e4d5 100644 --- a/roff.c +++ b/roff.c @@ -1,4 +1,4 @@ -/* $Id: roff.c,v 1.288 2017/01/12 18:02:20 schwarze Exp $ */ +/* $Id: roff.c,v 1.289 2017/02/17 03:03:03 schwarze Exp $ */ /* * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons * Copyright (c) 2010-2015, 2017 Ingo Schwarze @@ -1226,15 +1226,22 @@ deroff(char **dest, const struct roff_node *n) /* Skip leading whitespace. */ for (cp = n->string; *cp != '\0'; cp++) { - if (cp[0] == '\\' && strchr(" %&0^|~", cp[1]) != NULL) + if (cp[0] == '\\' && cp[1] != '\0' && + strchr(" %&0^|~", cp[1]) != NULL) cp++; else if ( ! isspace((unsigned char)*cp)) break; } + /* Skip trailing backslash. */ + + sz = strlen(cp); + if (cp[sz - 1] == '\\') + sz--; + /* Skip trailing whitespace. */ - for (sz = strlen(cp); sz; sz--) + for (; sz; sz--) if ( ! isspace((unsigned char)cp[sz-1])) break; @@ -3358,7 +3365,8 @@ roff_strdup(const struct roff *r, const char *p) ssz = 0; while ('\0' != *p) { - if ('\\' != *p && r->xtab && r->xtab[(int)*p].p) { + assert((unsigned int)*p < 128); + if ('\\' != *p && r->xtab && r->xtab[(unsigned int)*p].p) { sz = r->xtab[(int)*p].sz; res = mandoc_realloc(res, ssz + sz + 1); memcpy(res + ssz, r->xtab[(int)*p].p, sz); diff --git a/roff.h b/roff.h index 3039d4e9f536..b87cf132b726 100644 --- a/roff.h +++ b/roff.h @@ -1,4 +1,4 @@ -/* $Id: roff.h,v 1.39 2017/01/10 13:47:00 schwarze Exp $ */ +/* $Id: roff.h,v 1.40 2017/02/16 03:00:23 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze @@ -75,8 +75,7 @@ enum roff_next { */ enum mdoc_endbody { ENDBODY_NOT = 0, - ENDBODY_SPACE, /* Is broken: append a space. */ - ENDBODY_NOSPACE /* Is broken: don't append a space. */ + ENDBODY_SPACE /* Is broken: append a space. */ }; struct roff_node { diff --git a/tag.c b/tag.c index 0fbd2e105978..21ac6b32e4d3 100644 --- a/tag.c +++ b/tag.c @@ -1,4 +1,4 @@ -/* $Id: tag.c,v 1.17 2017/01/09 17:49:58 schwarze Exp $ */ +/* $Id: tag.c,v 1.18 2017/02/17 14:31:52 schwarze Exp $ */ /* * Copyright (c) 2015, 2016 Ingo Schwarze * @@ -38,7 +38,7 @@ struct tag_entry { char s[]; }; -static void tag_signal(int) __attribute__((noreturn)); +static void tag_signal(int) __attribute__((__noreturn__)); static struct ohash tag_data; static struct tag_files tag_files; diff --git a/tbl_html.c b/tbl_html.c index 962d900e3682..4dff29370a51 100644 --- a/tbl_html.c +++ b/tbl_html.c @@ -1,4 +1,4 @@ -/* $Id: tbl_html.c,v 1.19 2017/01/17 01:47:51 schwarze Exp $ */ +/* $Id: tbl_html.c,v 1.20 2017/02/05 18:15:39 schwarze Exp $ */ /* * Copyright (c) 2011 Kristaps Dzonsons * Copyright (c) 2014, 2015, 2017 Ingo Schwarze @@ -50,6 +50,7 @@ html_tbl_strlen(const char *p, void *arg) static void html_tblopen(struct html *h, const struct tbl_span *sp) { + struct tag *t; int ic; if (h->tbl.cols == NULL) { @@ -61,10 +62,10 @@ html_tblopen(struct html *h, const struct tbl_span *sp) assert(NULL == h->tblt); h->tblt = print_otag(h, TAG_TABLE, "c", "tbl"); + t = print_otag(h, TAG_COLGROUP, ""); for (ic = 0; ic < sp->opts->cols; ic++) print_otag(h, TAG_COL, "shw", h->tbl.cols[ic].width); - - print_otag(h, TAG_TBODY, ""); + print_tagq(h, t); } void diff --git a/term_ps.c b/term_ps.c index 286a89f91a61..696ff2243592 100644 --- a/term_ps.c +++ b/term_ps.c @@ -1,4 +1,4 @@ -/* $Id: term_ps.c,v 1.82 2016/08/10 11:03:43 schwarze Exp $ */ +/* $Id: term_ps.c,v 1.83 2017/02/17 14:31:52 schwarze Exp $ */ /* * Copyright (c) 2010, 2011 Kristaps Dzonsons * Copyright (c) 2014, 2015, 2016 Ingo Schwarze @@ -104,7 +104,7 @@ static void ps_pclose(struct termp *); static void ps_plast(struct termp *); static void ps_pletter(struct termp *, int); static void ps_printf(struct termp *, const char *, ...) - __attribute__((__format__ (printf, 2, 3))); + __attribute__((__format__ (__printf__, 2, 3))); static void ps_putchar(struct termp *, char); static void ps_setfont(struct termp *, enum termfont); static void ps_setwidth(struct termp *, int, int); diff --git a/test-O_DIRECTORY.c b/test-O_DIRECTORY.c new file mode 100644 index 000000000000..e44d51ca4ff7 --- /dev/null +++ b/test-O_DIRECTORY.c @@ -0,0 +1,7 @@ +#include + +int +main(void) +{ + return open(".", O_RDONLY | O_DIRECTORY) == -1; +} diff --git a/test-cmsg.c b/test-cmsg.c new file mode 100644 index 000000000000..b5441f9c82fe --- /dev/null +++ b/test-cmsg.c @@ -0,0 +1,13 @@ +#include +#include + +int +main(void) +{ + struct msghdr msg; + + msg.msg_control = NULL; + msg.msg_controllen = 0; + + return CMSG_FIRSTHDR(&msg) != NULL; +} diff --git a/test-recvmsg.c b/test-recvmsg.c new file mode 100644 index 000000000000..d026c70fb8c7 --- /dev/null +++ b/test-recvmsg.c @@ -0,0 +1,8 @@ +#include +#include + +int +main(void) +{ + return recvmsg(-1, NULL, 0) != -1; +} diff --git a/tree.c b/tree.c index 9e68b69e5fb0..dd36ff594e53 100644 --- a/tree.c +++ b/tree.c @@ -1,4 +1,4 @@ -/* $Id: tree.c,v 1.72 2017/01/12 17:29:33 schwarze Exp $ */ +/* $Id: tree.c,v 1.73 2017/02/10 15:45:28 schwarze Exp $ */ /* * Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze @@ -192,6 +192,8 @@ print_mdoc(const struct roff_node *n, int indent) putchar(')'); if (NODE_EOS & n->flags) putchar('.'); + if (NODE_BROKEN & n->flags) + printf(" BROKEN"); if (NODE_NOSRC & n->flags) printf(" NOSRC"); if (NODE_NOPRT & n->flags)