aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBaptiste Daroussin <bapt@FreeBSD.org>2021-11-15 15:35:39 +0000
committerBaptiste Daroussin <bapt@FreeBSD.org>2021-11-15 15:35:39 +0000
commite9bf778aefc154b6bdefd2772f7fd85819f465b1 (patch)
treee47699afedf03da33f8556a140426379495987dd
parenta5efdeedef481aea3632844ca94a80567a75b5ad (diff)
downloadsrc-vendor/mandoc.tar.gz
src-vendor/mandoc.zip
mandoc: import v1.14.6vendor/mandoc/1.14.6vendor/mandoc
-rw-r--r--INSTALL17
-rw-r--r--LICENSE6
-rw-r--r--Makefile64
-rw-r--r--Makefile.depend38
-rw-r--r--NEWS201
-rw-r--r--TODO142
-rw-r--r--apropos.115
-rw-r--r--arch.c4
-rw-r--r--att.c4
-rw-r--r--catman.c4
-rw-r--r--cgi.c72
-rw-r--r--chars.c7
-rw-r--r--compat_err.c13
-rw-r--r--compat_fts.c29
-rw-r--r--compat_fts.h3
-rw-r--r--compat_getline.c13
-rw-r--r--compat_getsubopt.c13
-rw-r--r--compat_isblank.c14
-rw-r--r--compat_mkdtemp.c23
-rw-r--r--compat_mkstemps.c63
-rw-r--r--compat_ohash.c13
-rw-r--r--compat_progname.c15
-rw-r--r--compat_reallocarray.c15
-rw-r--r--compat_recallocarray.c25
-rw-r--r--compat_strcasestr.c13
-rw-r--r--compat_stringlist.c82
-rw-r--r--compat_stringlist.h43
-rw-r--r--compat_strlcat.c62
-rw-r--r--compat_strlcpy.c49
-rw-r--r--compat_strndup.c16
-rw-r--r--compat_strsep.c15
-rw-r--r--compat_strtonum.c15
-rw-r--r--compat_vasprintf.c13
-rwxr-xr-xconfigure313
-rw-r--r--configure.local.example71
-rw-r--r--dba_array.c4
-rw-r--r--dba_read.c4
-rw-r--r--eqn.755
-rw-r--r--eqn.c14
-rw-r--r--html.c337
-rw-r--r--html.h36
-rw-r--r--libmandoc.h14
-rw-r--r--main.c956
-rw-r--r--man.198
-rw-r--r--man.755
-rw-r--r--man.conf.514
-rw-r--r--man_html.c43
-rw-r--r--man_macro.c12
-rw-r--r--man_term.c132
-rw-r--r--man_validate.c157
-rw-r--r--manconf.h10
-rw-r--r--mandoc.1141
-rw-r--r--mandoc.c85
-rw-r--r--mandoc.css7
-rw-r--r--mandoc.h22
-rw-r--r--mandoc_char.721
-rw-r--r--mandoc_headers.379
-rw-r--r--mandoc_html.3270
-rw-r--r--mandoc_malloc.341
-rw-r--r--mandoc_msg.c17
-rw-r--r--mandoc_ohash.c4
-rw-r--r--mandoc_parse.h3
-rw-r--r--mandoc_xr.c4
-rw-r--r--mandocd.c4
-rw-r--r--mandocdb.c247
-rw-r--r--manpath.c48
-rw-r--r--mdoc.7183
-rw-r--r--mdoc.c13
-rw-r--r--mdoc_html.c385
-rw-r--r--mdoc_macro.c7
-rw-r--r--mdoc_man.c124
-rw-r--r--mdoc_markdown.c55
-rw-r--r--mdoc_state.c5
-rw-r--r--mdoc_term.c440
-rw-r--r--mdoc_validate.c527
-rw-r--r--out.c75
-rw-r--r--out.h6
-rw-r--r--read.c31
-rw-r--r--roff.78
-rw-r--r--roff.c233
-rw-r--r--roff.h17
-rw-r--r--roff_html.c4
-rw-r--r--roff_int.h5
-rw-r--r--roff_term.c56
-rw-r--r--roff_validate.c10
-rw-r--r--soelim.c8
-rw-r--r--tag.c415
-rw-r--r--tag.h35
-rw-r--r--tbl.713
-rw-r--r--tbl.h7
-rw-r--r--tbl_data.c53
-rw-r--r--tbl_html.c42
-rw-r--r--tbl_layout.c63
-rw-r--r--tbl_term.c60
-rw-r--r--term.c25
-rw-r--r--term_ascii.c32
-rw-r--r--term_ps.c9
-rw-r--r--term_tab.c4
-rw-r--r--term_tag.c227
-rw-r--r--term_tag.h34
-rw-r--r--test-attribute.c48
-rw-r--r--test-mkstemps.c12
-rw-r--r--tree.c201
103 files changed, 5023 insertions, 2888 deletions
diff --git a/INSTALL b/INSTALL
index 3c09f3f214cb..e79674a16aa4 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,4 +1,4 @@
-$Id: INSTALL,v 1.23 2019/03/06 15:58:10 schwarze Exp $
+$Id: INSTALL,v 1.24 2021/09/20 13:25:42 schwarze Exp $
About the portable mandoc distribution
--------------------------------------
@@ -18,7 +18,7 @@ tech@ mailing list, too.
Enjoy using the mandoc toolset!
-Ingo Schwarze, Karlsruhe, March 2019
+Ingo Schwarze, Karlsruhe, September 2021
Installation
@@ -65,10 +65,15 @@ installed to the intended places. Otherwise, put some *DIR or *NM*
variables into "configure.local" and go back to step 4.
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. In particular, regarding Solaris systems, look at the BUGS
-section of that manual page.
+Basically, that amounts to "make regress" to do a standard regression
+run, running all tests. For more fine-grained control,
+read "./mandoc -l regress/regress.pl.1",
+then run "cd regress && ./regress.pl" with optional arguments.
+The regression suite requires a reasonably modern Perl interpreter.
+Examples of systems that are too old to run the regression suite
+include Solaris 9, Solaris 10, and Mac OS X 10.4 Tiger.
+On Solaris 11, the suite does run, but some tests fail;
+look at the BUGS section of that manual page.
8. Run "sudo make install". If you intend to build a binary
package using some kind of fake root mechanism, you may need a
diff --git a/LICENSE b/LICENSE
index 81eada0b3657..0a0fc1acd2ac 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,11 +1,11 @@
-$Id: LICENSE,v 1.21 2018/11/26 17:11:11 schwarze Exp $
+$Id: LICENSE,v 1.22 2021/09/19 11:02:09 schwarze Exp $
With the exceptions noted below, all non-trivial files contained
in the mandoc toolkit are protected by the Copyright of the following
developers:
Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
-Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org>
+Copyright (c) 2010-2021 Ingo Schwarze <schwarze@openbsd.org>
Copyright (c) 1999, 2004, 2017 Marc Espie <espie@openbsd.org>
Copyright (c) 2009, 2010, 2011, 2012 Joerg Sonnenberger <joerg@netbsd.org>
Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
@@ -13,7 +13,7 @@ Copyright (c) 2014 Baptiste Daroussin <bapt@freebsd.org>
Copyright (c) 2016 Ed Maste <emaste@freebsd.org>
Copyright (c) 2017 Michael Stapelberg <stapelberg@debian.org>
Copyright (c) 2017 Anthony Bentley <bentley@openbsd.org>
-Copyright (c) 1998, 2004, 2010 Todd C. Miller <Todd.Miller@courtesan.com>
+Copyright (c) 1998, 2004, 2010, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net>
Copyright (c) 2004 Ted Unangst <tedu@openbsd.org>
Copyright (c) 1994 Christos Zoulas <christos@netbsd.org>
diff --git a/Makefile b/Makefile
index f4e29540df00..48c4741812b6 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
-# $Id: Makefile,v 1.530 2019/03/06 16:08:41 schwarze Exp $
+# $Id: Makefile,v 1.540 2021/09/21 11:04:40 schwarze Exp $
#
+# Copyright (c) 2011, 2013-2021 Ingo Schwarze <schwarze@openbsd.org>
# Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
-# Copyright (c) 2011, 2013-2019 Ingo Schwarze <schwarze@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
@@ -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.5
+VERSION = 1.14.6
# === LIST OF FILES ====================================================
-TESTSRCS = test-be32toh.c \
+TESTSRCS = test-attribute.c \
+ test-be32toh.c \
test-cmsg.c \
test-dirent-namlen.c \
test-EFTYPE.c \
@@ -29,6 +30,7 @@ TESTSRCS = test-be32toh.c \
test-getsubopt.c \
test-isblank.c \
test-mkdtemp.c \
+ test-mkstemps.c \
test-nanosleep.c \
test-noop.c \
test-ntohl.c \
@@ -65,6 +67,7 @@ SRCS = arch.c \
compat_getsubopt.c \
compat_isblank.c \
compat_mkdtemp.c \
+ compat_mkstemps.c \
compat_ohash.c \
compat_progname.c \
compat_reallocarray.c \
@@ -134,6 +137,7 @@ SRCS = arch.c \
term_ascii.c \
term_ps.c \
term_tab.c \
+ term_tag.c \
tree.c
DISTFILES = INSTALL \
@@ -209,6 +213,7 @@ DISTFILES = INSTALL \
tbl_int.h \
tbl_parse.h \
term.h \
+ term_tag.h \
$(SRCS) \
$(TESTSRCS)
@@ -245,19 +250,22 @@ LIBMANDOC_OBJS = $(LIBMAN_OBJS) \
mandoc_xr.o \
msec.o \
preconv.o \
- read.o
+ read.o \
+ tag.o
-COMPAT_OBJS = compat_err.o \
+ALL_COBJS = compat_err.o \
compat_fts.o \
compat_getline.o \
compat_getsubopt.o \
compat_isblank.o \
compat_mkdtemp.o \
+ compat_mkstemps.o \
compat_ohash.o \
compat_progname.o \
compat_reallocarray.o \
compat_recallocarray.o \
compat_strcasestr.o \
+ compat_stringlist.o \
compat_strlcat.o \
compat_strlcpy.o \
compat_strndup.o \
@@ -280,6 +288,7 @@ MANDOC_TERM_OBJS = eqn_term.o \
term_ascii.o \
term_ps.o \
term_tab.o \
+ term_tag.o \
tbl_term.o
DBM_OBJS = dbm.o \
@@ -302,7 +311,6 @@ MAIN_OBJS = $(MANDOC_HTML_OBJS) \
mdoc_man.o \
mdoc_markdown.o \
out.o \
- tag.o \
tree.o
CGI_OBJS = $(MANDOC_HTML_OBJS) \
@@ -313,18 +321,10 @@ CGI_OBJS = $(MANDOC_HTML_OBJS) \
MANDOCD_OBJS = $(MANDOC_HTML_OBJS) \
$(MANDOC_TERM_OBJS) \
mandocd.o \
- out.o \
- tag.o
+ out.o
DEMANDOC_OBJS = demandoc.o
-SOELIM_OBJS = soelim.o \
- compat_err.o \
- compat_getline.o \
- compat_progname.o \
- compat_reallocarray.o \
- compat_stringlist.o
-
WWW_MANS = apropos.1.html \
demandoc.1.html \
man.1.html \
@@ -373,7 +373,7 @@ include Makefile.local
# === DEPENDENCY HANDLING ==============================================
-all: mandoc demandoc soelim $(BUILD_TARGETS) Makefile.local
+all: mandoc man demandoc soelim $(BUILD_TARGETS) Makefile.local
install: base-install $(INSTALL_TARGETS)
@@ -392,13 +392,14 @@ distclean: clean
rm -f Makefile.local config.h config.h.old config.log config.log.old
clean:
- rm -f libmandoc.a $(LIBMANDOC_OBJS) $(COMPAT_OBJS)
- rm -f mandoc $(MAIN_OBJS)
+ rm -f libmandoc.a $(LIBMANDOC_OBJS) $(ALL_COBJS)
+ rm -f mandoc man $(MAIN_OBJS)
rm -f man.cgi $(CGI_OBJS)
rm -f mandocd catman catman.o $(MANDOCD_OBJS)
rm -f demandoc $(DEMANDOC_OBJS)
- rm -f soelim $(SOELIM_OBJS)
+ rm -f soelim soelim.o
rm -f $(WWW_MANS) $(WWW_INCS) mandoc*.tar.gz mandoc*.sha256
+ rm -f Makefile.tmp1 Makefile.tmp2
rm -rf *.dSYM
base-install: mandoc demandoc soelim
@@ -511,12 +512,15 @@ Makefile.local config.h: configure $(TESTSRCS)
@echo "$@ is out of date; please run ./configure"
@exit 1
-libmandoc.a: $(COMPAT_OBJS) $(LIBMANDOC_OBJS)
- ar rs $@ $(COMPAT_OBJS) $(LIBMANDOC_OBJS)
+libmandoc.a: $(MANDOC_COBJS) $(LIBMANDOC_OBJS)
+ $(AR) rs $@ $(MANDOC_COBJS) $(LIBMANDOC_OBJS)
mandoc: $(MAIN_OBJS) libmandoc.a
$(CC) -o $@ $(LDFLAGS) $(MAIN_OBJS) libmandoc.a $(LDADD)
+man: mandoc
+ $(LN) mandoc man
+
man.cgi: $(CGI_OBJS) libmandoc.a
$(CC) $(STATIC) -o $@ $(LDFLAGS) $(CGI_OBJS) libmandoc.a $(LDADD)
@@ -529,8 +533,8 @@ catman: catman.o libmandoc.a
demandoc: $(DEMANDOC_OBJS) libmandoc.a
$(CC) -o $@ $(LDFLAGS) $(DEMANDOC_OBJS) libmandoc.a $(LDADD)
-soelim: $(SOELIM_OBJS)
- $(CC) -o $@ $(LDFLAGS) $(SOELIM_OBJS)
+soelim: $(SOELIM_COBJS) soelim.o
+ $(CC) -o $@ $(LDFLAGS) $(SOELIM_COBJS) soelim.o
# --- maintainer targets ---
@@ -540,11 +544,13 @@ www-install: www
$(INSTALL_DATA) $(WWW_INCS) $(HTDOCDIR)/includes
depend: config.h
- mkdep -f Makefile.depend $(CFLAGS) $(SRCS)
+ ./configure -depend
+ mkdep -f Makefile.tmp1 $(CFLAGS) $(SRCS)
perl -e 'undef $$/; $$_ = <>; s|/usr/include/\S+||g; \
s|\\\n||g; s| +| |g; s| $$||mg; print;' \
- Makefile.depend > Makefile.tmp
- mv Makefile.tmp Makefile.depend
+ Makefile.tmp1 > Makefile.tmp2
+ rm Makefile.tmp1
+ mv Makefile.tmp2 Makefile.depend
regress-distclean:
@find regress \
@@ -597,7 +603,7 @@ dist-install: dist
.h.h.html:
highlight -I $< > $@
-.1.1.html .3.3.html .5.5.html .7.7.html .8.8.html: mandoc
- mandoc -Thtml -Wwarning,stop \
+.1.1.html .3.3.html .5.5.html .7.7.html .8.8.html:
+ ./mandoc -Thtml -Wwarning,stop \
-O 'style=/mandoc.css,man=/man/%N.%S.html;https://man.openbsd.org/%N.%S,includes=/includes/%I.html' \
$< > $@
diff --git a/Makefile.depend b/Makefile.depend
index 3540aeda822c..d5f6556c3e7e 100644
--- a/Makefile.depend
+++ b/Makefile.depend
@@ -9,6 +9,7 @@ compat_getline.o: compat_getline.c config.h
compat_getsubopt.o: compat_getsubopt.c config.h
compat_isblank.o: compat_isblank.c config.h
compat_mkdtemp.o: compat_mkdtemp.c config.h
+compat_mkstemps.o: compat_mkstemps.c config.h
compat_ohash.o: compat_ohash.c config.h compat_ohash.h
compat_progname.o: compat_progname.c config.h
compat_reallocarray.o: compat_reallocarray.c config.h
@@ -22,8 +23,8 @@ compat_strsep.o: compat_strsep.c config.h
compat_strtonum.o: compat_strtonum.c config.h
compat_vasprintf.o: compat_vasprintf.c config.h
dba.o: dba.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mansearch.h dba_write.h dba_array.h dba.h
-dba_array.o: dba_array.c mandoc_aux.h dba_write.h dba_array.h
-dba_read.o: dba_read.c mandoc_aux.h mansearch.h dba_array.h dba.h dbm.h
+dba_array.o: dba_array.c config.h mandoc_aux.h dba_write.h dba_array.h
+dba_read.o: dba_read.c config.h mandoc_aux.h mansearch.h dba_array.h dba.h dbm.h
dba_write.o: dba_write.c config.h dba_write.h
dbm.o: dbm.c config.h mansearch.h dbm_map.h dbm.h
dbm_map.o: dbm_map.c config.h mansearch.h dbm_map.h dbm.h
@@ -33,17 +34,17 @@ eqn_html.o: eqn_html.c config.h mandoc.h roff.h eqn.h out.h html.h
eqn_term.o: eqn_term.c config.h eqn.h out.h term.h
html.o: html.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h out.h html.h manconf.h main.h
lib.o: lib.c config.h roff.h libmdoc.h lib.in
-main.o: main.c config.h mandoc_aux.h mandoc.h mandoc_xr.h roff.h mdoc.h man.h mandoc_parse.h tag.h main.h manconf.h mansearch.h
+main.o: main.c config.h mandoc_aux.h mandoc.h mandoc_xr.h roff.h mdoc.h man.h mandoc_parse.h tag.h term_tag.h main.h manconf.h mansearch.h
man.o: man.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h
man_html.o: man_html.c config.h mandoc_aux.h mandoc.h roff.h man.h out.h html.h main.h
man_macro.o: man_macro.c config.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h
-man_term.o: man_term.c config.h mandoc_aux.h mandoc.h roff.h man.h out.h term.h tag.h main.h
-man_validate.o: man_validate.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h
+man_term.o: man_term.c config.h mandoc_aux.h mandoc.h roff.h man.h out.h term.h term_tag.h main.h
+man_validate.o: man_validate.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h tag.h
mandoc.o: mandoc.c config.h mandoc_aux.h mandoc.h roff.h libmandoc.h roff_int.h
mandoc_aux.o: mandoc_aux.c config.h mandoc.h mandoc_aux.h
mandoc_msg.o: mandoc_msg.c config.h mandoc.h
-mandoc_ohash.o: mandoc_ohash.c mandoc_aux.h mandoc_ohash.h compat_ohash.h
-mandoc_xr.o: mandoc_xr.c mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc_xr.h
+mandoc_ohash.o: mandoc_ohash.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h
+mandoc_xr.o: mandoc_xr.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc_xr.h
mandocd.o: mandocd.c config.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h main.h manconf.h
mandocdb.o: mandocdb.c config.h compat_fts.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h manconf.h mansearch.h dba_array.h dba.h
manpath.o: manpath.c config.h mandoc_aux.h mandoc.h manconf.h
@@ -53,21 +54,21 @@ mdoc_argv.o: mdoc_argv.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.
mdoc_html.o: mdoc_html.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h out.h html.h main.h
mdoc_macro.o: mdoc_macro.c config.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h
mdoc_man.o: mdoc_man.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h out.h main.h
-mdoc_markdown.o: mdoc_markdown.c mandoc_aux.h mandoc.h roff.h mdoc.h main.h
-mdoc_state.o: mdoc_state.c mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h
-mdoc_term.o: mdoc_term.c config.h mandoc_aux.h roff.h mdoc.h out.h term.h tag.h main.h
-mdoc_validate.o: mdoc_validate.c config.h mandoc_aux.h mandoc.h mandoc_xr.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h
+mdoc_markdown.o: mdoc_markdown.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h main.h
+mdoc_state.o: mdoc_state.c config.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h
+mdoc_term.o: mdoc_term.c config.h mandoc_aux.h roff.h mdoc.h out.h term.h term_tag.h main.h
+mdoc_validate.o: mdoc_validate.c config.h mandoc_aux.h mandoc.h mandoc_xr.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h tag.h
msec.o: msec.c config.h mandoc.h libmandoc.h msec.in
-out.o: out.c config.h mandoc_aux.h tbl.h out.h
+out.o: out.c config.h mandoc_aux.h mandoc.h tbl.h out.h
preconv.o: preconv.c config.h mandoc.h roff.h mandoc_parse.h libmandoc.h
-read.o: read.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h libmandoc.h roff_int.h
+read.o: read.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h libmandoc.h roff_int.h tag.h
roff.o: roff.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h mandoc_parse.h libmandoc.h roff_int.h tbl_parse.h eqn_parse.h predefs.in
-roff_html.o: roff_html.c mandoc.h roff.h out.h html.h
-roff_term.o: roff_term.c mandoc.h roff.h out.h term.h
-roff_validate.o: roff_validate.c mandoc.h roff.h libmandoc.h roff_int.h
+roff_html.o: roff_html.c config.h mandoc.h roff.h out.h html.h
+roff_term.o: roff_term.c config.h mandoc.h roff.h out.h term.h
+roff_validate.o: roff_validate.c config.h mandoc.h roff.h libmandoc.h roff_int.h
soelim.o: soelim.c config.h compat_stringlist.h
st.o: st.c config.h mandoc.h roff.h libmdoc.h
-tag.o: tag.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h tag.h
+tag.o: tag.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h roff.h mdoc.h roff_int.h tag.h
tbl.o: tbl.c config.h mandoc_aux.h mandoc.h tbl.h libmandoc.h tbl_parse.h tbl_int.h
tbl_data.o: tbl_data.c config.h mandoc_aux.h mandoc.h tbl.h libmandoc.h tbl_int.h
tbl_html.o: tbl_html.c config.h mandoc.h roff.h tbl.h out.h html.h
@@ -77,5 +78,6 @@ tbl_term.o: tbl_term.c config.h mandoc.h tbl.h out.h term.h
term.o: term.c config.h mandoc.h mandoc_aux.h out.h term.h main.h
term_ascii.o: term_ascii.c config.h mandoc.h mandoc_aux.h out.h term.h manconf.h main.h
term_ps.o: term_ps.c config.h mandoc_aux.h out.h term.h manconf.h main.h
-term_tab.o: term_tab.c mandoc_aux.h out.h term.h
+term_tab.o: term_tab.c config.h mandoc_aux.h out.h term.h
+term_tag.o: term_tag.c config.h mandoc.h roff.h roff_int.h tag.h term_tag.h
tree.o: tree.c config.h mandoc.h roff.h mdoc.h man.h tbl.h eqn.h main.h
diff --git a/NEWS b/NEWS
index 89eb3f6fb629..634ffaf6ccfa 100644
--- a/NEWS
+++ b/NEWS
@@ -1,7 +1,206 @@
-$Id: NEWS,v 1.34 2019/03/10 09:32:00 schwarze Exp $
+$Id: NEWS,v 1.40 2021/09/23 18:03:00 schwarze Exp $
This file lists the most important changes in the mandoc.bsd.lv distribution.
+Changes in version 1.14.6, released on September 23, 2021
+
+ --- MAJOR NEW FEATURES ---
+ * mdoc(7): automatic tagging improved in many respects
+ * mdoc(7): new .Tg (tag) macro to explicitly mark a place as defining a term
+ * man(7): implement some automatic tagging support
+ * man(1): let -w without argument show the manpath, like in man-db and man-1.6
+ * -T html: wrap text and phrasing elements in paragraphs unless already
+ contained in flow containers; never put them directly into sections.
+ This helps to format paragraphs with the CSS class selector .Pp.
+ * man.conf(5): remove support for the "_whatdb" configuration directive
+ that was deprecated in 2015; please use "manpath" instead
+ --- MINOR NEW FEATURES ---
+ * man(1): switch the default pager from "more -s" to "less"
+ * man(1): in the fallback code to look for manual pages without using
+ mandoc.db(5), accept files "man<one-digit-section>/<name>.<full-section>"
+ in addition to the already supported "man<full-section>/name.[01-9]*"
+ * if messages are shown and output is printed without a pager, display
+ a heads-up on stderr at the end because otherwise, users may easily
+ miss the messages
+ * man.cgi(8): add a Content-Security-Policy HTTP header
+ * man.cgi(8): switch off autocomplete and autocapitalize
+ * mandoc.css: support prefers-color-scheme: dark
+ * -T html: add meta viewport element to help mobile devices
+ * -T html -O tag: let this pass a file:// URI to the pager
+ * tbl(7): implement the "nospaces" option
+ * tbl(7) -T html: implement the "a" (em indent) layout specification
+ * tbl(7) -T html: implement the "b" (bold) and "i" (italic) layout modifiers
+ * tbl(7): support two-character font names in the layout font modifier
+ * tbl(7) -T html: support horinzontal rulers in individual cells
+ * tbl(7) -T tree: print more details about columns, options, rows, and cells
+ * roff(7): implement the .break request (break out of a .while loop)
+ * roff(7): support the CB and CI fonts in \f and .ft
+ * -T lint: new STYLE message if a file name extension contradicts .Dt/.TH
+ * -T lint: new STYLE message about overlong text lines
+ * -W style: check .Xr links along the full manpath
+ --- RELIABILITY BUGFIXES ---
+ * man(1): do not segfault if /tmp/ is not writeable
+ * man(1): do not access a NULL pointer when both -l and -w are given
+ * makewhatis(8): do not crash when a manpath directory contains
+ a symbolic link that points to a directory
+ * man(7): fix an assertion failure caused by doubly nested next-line scopes
+ * tbl(7): fix a crash when the last column is only reached by spans
+ * tbl(7): fix a NULL pointer access in some cases of two spans on one row
+ * tbl(7) -T ascii: fix a NULL pointer access on empty data cells
+ * tbl(7) -T ascii: fix a NULL pointer access on a line next to a short row
+ * tbl(7): fix an assertion failure caused by excessive spacing modifiers
+ * tbl(7): fix an infinite loop for some overlapping horizontal spans
+ * roff(7): fix a rare case of writing one byte past the end of the input buffer
+ * roff(7): do not call abort(3) when \*[.T] is encountered
+ * roff(7): fix an assertion failure caused by a macro inside .ce .if
+ * roff(7): fix assertion failures for .ti and .po with excessive arguments
+ * roff(7): avoid near-infinte output for .ce inside explicit no-fill mode
+ * -T ascii/utf8: fix assertion failures caused by excessive spacing
+ * -T html: fix an assertion failure caused by .ft in rare situations
+ * -T man: fix an assertion failure caused by tbl(7) and eqn(7) input
+ --- PORTABILITY IMPROVEMENTS ---
+ * rename HOMEBREWDIR to READ_ALLOWED_PATH, allow it to contain more than
+ one directory, and explain how to use that for NixOS and GNU Guix Linux
+ * configure: stop trying to ask make(1) what the default compiler is
+ because that test was too fragile; just use "cc" by default
+ * configure: various simplifications and improved robustness
+ * configure: only compile compat_*.c implementations that are needed
+ * configure: provide feature tests for __attribute__(()) and mkstemps(3)
+ * compat_*: sync with upstreams for security, functionality, and style
+ * in regress.pl, avoid the non-portable options sed(1) -i and echo(1) -n
+ * in the regression suite, avoid file names that differ only by case
+ --- MINOR FUNCTIONAL IMPROVEMENTS ---
+ * man(1) -h: for pages lacking a SYNOPSIS, show the NAME section
+ * man(1): when the first argument starts with a digit, optionally
+ followed by a letter, and at least one more argument follows,
+ interpret the first argument as a section name even when additional
+ characters follow after the digit and letter
+ * man(1): with a specific section requested, try harder to find
+ the best match; use this order of preference:
+ 1. The section in both the directory name and the file name matches exactly.
+ 2. The section in the file name matches exactly.
+ 3. The section in the directory name matches exactly.
+ 4. Neither of them matches exactly.
+ * man(1): if no tags were generated at all, unlink(2) the empty tags file
+ as soon as the condition can be detected and do not pass it to less(1)
+ * makewhatis(8): handle both dangling symlinks and .so links
+ in manual page directories more gracefully
+ * man.cgi(8): for invalid queries and for valid queries returning
+ no result, return the appropriate 40x status code rather than 200
+ * mdoc(7): let .Dd concatenate all arguments and default to the empty string
+ * mdoc(7): convert ".Fl Fl" to ".Fl \-" during validation, improving -T html
+ * mdoc(7): improve output of .At 32v
+ * man(7): no longer print multiple blank lines before NAME and page footer
+ * tbl(7) -T utf8: improved rendering of horizontal lines
+ * tbl(7) -T html: in "n" cells, align by padding numbers on the right
+ * tbl(7): no longer leak tabulator settings to subsequent roff(7) code
+ * mdoc(7) -T html: for .Bl -tag, use "column-count: 1" rather
+ than "overflow: auto" to avoid the ugly side effects
+ * mdoc(7) -T html: render .Bd -unfilled in proportionally-spaced font
+ * mdoc(7) -T html: format .Nd with <span> rather than <div>
+ * mdoc(7) -T lint: do not warn about Mdocdate without an actual date
+ * mdoc(7) -T lint: do not complain about function types of the
+ form "ret_type (fname)(args)", but otherwise check names more strictly
+ * -T html: append .html suffix to temporary files to please browsers
+ * -T markdown: print a BAGARG message if called on man(7) input
+ --- MINOR BUGFIXES ---
+ * man(1): do the search for each name independently, and
+ show the results in the order of the command line argument
+ * man(1): escape shell wildcard characters in name arguments before glob(3)
+ * man(1): when asking for a single manual page by name, prefer file name
+ matches over .Dt/.TH matches over first NAME matches over later NAME
+ matches, but do not change the ordering for apropos(1) nor for man -a
+ * man(1): correctly extract the section name from the file name extension
+ of gzipped manual page files
+ * makewhatis(8): fix file type tests putting wrong data into mandoc.db(5)
+ * man.cgi(8): fix section number in the <title> element for preformatted pages
+ * tbl(7): correct handling of T& after horizontal rulers in the layout
+ * tbl(7): correct column widths if rows have different numbers of cells
+ * tbl(7): empty columns are 1n wide rather than 0n
+ * tbl(7): correctly calculate required column widths for tables containing
+ cells that horizontally span columns which contains "n" (number) formatted
+ cells on other rows
+ * tbl(7): skip escape sequences when looking for column separators
+ * eqn(7): skip whitespace before tokens
+ * roff(7): when calling an empty macro, do not clobber existing arguments
+ * roff(7): recognize \} on lines closing a macro definition request
+ * roff(7): do not throw a bogus warning for "'br\}" and similar lines
+ * roff(7): stop generating comment nodes when encountering the first content
+ * mandoc_char(7): make \0 (digit-width space) non-breaking
+ * mdoc(7) .Bl -column: parse Macro in .It "word<tab>word" Ta word Macro<eol>
+ * mdoc(7) -T html: display straight quotes, not curly quotes, for .Qq/.Qo
+ * -T html: remove some spurious line breaks, in particular inside <pre>
+ * -T html: use <br/> for a space character at the beginning of an input line
+ * -T html: use ~%d for ordinal fragment suffixes, reserve '~' for that purpose
+ --- STRUCTURAL IMPROVEMENTS ---
+ * introduce the concept of semantically transparent syntax tree nodes,
+ allowing improved decisions in various validators and formatters
+ * move some code out of the giant main() into separate functions
+ doing one well-defined task each
+ * clearly separate parser state (struct curparse) and formatter state
+ (struct outstate), don't mix them in the same struct
+ * in the HTML formatter, assert(3) that no HTML nesting violation occurs
+ * let html_close_paragraph() close any phrasing context
+ --- THANKS TO ---
+ * Anthony Bentley and Klemens Nanni (OpenBSD) for many patches and bug
+ reports, for useful discussions, and for checking patches
+ * Anton Lindqvist (OpenBSD) for two patches and a bug report
+ * Marc Espie (OpenBSD) for a patch, many bug reports, and useful discussions
+ * Lukas Epple (NixOS) for a patch, bug reports, suggesting a minor
+ portability feature, checking patches, and extensive release testing
+ * Abel Romero Perez for a patch, a bug report, and suggesting a new feature
+ * nabijaczleweli for a patch and for suggesting feature improvements
+ * Jonathan Gray (OpenBSD) for a patch and for bug reports
+ * Otto Moerbeek (OpenBSD) and Alexander Gromnitsky for a patch
+ * Armin Besirovic for a contribution to mandoc.css
+ * Jason McIntyre (OpenBSD) for manual page patches, suggesting a new feature,
+ checking many patches, and useful discussions
+ * Martin Vahlensieck for a manual page patch and reporting a code style issue
+ * Frederic Cambus and Ian Sutton (OpenBSD) for a manual page patch
+ * Jan Schreiber for many bug reports found with afl(1)
+ * G. Branden Robinson (GNU troff) for several bug reports, feature
+ suggestions, and for checking many groff patches
+ * Michael Stapelberg (Debian) for several bug reports and feature
+ suggestions, and for extensive release testing
+ * Ian Ropers, Lorenzo Beretta, and Oliver Corff for several bug reports
+ and feature suggestions
+ * Stephen Gregoratto for several bug reports
+ * Theo de Raadt (OpenBSD) for two bug reports, checking a patch,
+ and a useful discussion
+ * Thomas Klausner (NetBSD) for two bug reports and for release testing
+ * Andreas Kahari and Jason A. Donenfeld for two bug reports
+ * Soeren Tempel (Alpine Linux) for a bug report, suggesting a feature
+ improvement, and checking two patches
+ * Aman Verma, Jan Stary, and John Gardner for a bug report
+ and for suggesting a feature impovement
+ * Todd Miller (OpenBSD) for a bug report, checking a patch,
+ and a useful discussion
+ * Andrew Fresh, Brian Callahan, Christian Weisgerber, Paul de Weerd (OpenBSD),
+ Havard Eidnes, Jason Thorpe (NetBSD), Yuri Pankov (FreeBSD),
+ Bjarni Ingi Gislason, Chris Bennett, Edgar Pettijohn, Eldred Habert,
+ Jamie Landeg-Jones, Kazuo KUROI, and Wynn Wolf Arbor for a bug report
+ * Theo Buehler (OpenBSD) for suggesting two feature impovements
+ and for checking a patch
+ * Leah Neukirchen (Void Linux) for suggesting a feature impovement
+ and for release testing
+ * Colin Watson (Debian) for suggesting a feature impovement
+ and for checking groff patches
+ * Matej Cepl (SUSE Linux), Matthew Martin, Steffen Nurpmeso,
+ and Tim Baumgard for suggesting a feature impovement
+ * Christos Zoulas (NetBSD) for a report regarding portability
+ * Daniel Dickman (OpenBSD) for suggesting a portability improvement
+ * Werner Lemberg (GNU troff) and Douglas McIlroy
+ for reporting bugs in manual pages
+ * Baptiste Daroussin and Eygene Ryabinkin (FreeBSD)
+ for an additional regression test
+ * Michal Nowak for reporting several code style issues
+ * TJ Townsend (OpenBSD) for help with CSS
+ * Sevan Janiyan (NetBSD) and Robert Mustacchi (Illumos)
+ for extensive release testing
+ * Job Snijders, Kinichiro INOGUCHI, and Martijn van Duren (OpenBSD)
+ for checking patches
+ * Bertrand Garrigues and Ralph Corderoy (GNU troff) for checking groff patches
+
Changes in version 1.14.5, released on March 10, 2019
--- MAJOR NEW FEATURES ---
diff --git a/TODO b/TODO
index 049e6a4f2beb..fe2059c9e5d5 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,6 @@
************************************************************************
* Official mandoc TODO.
-* $Id: TODO,v 1.295 2019/06/11 16:04:36 schwarze Exp $
+* $Id: TODO,v 1.319 2021/09/21 17:58:13 schwarze Exp $
************************************************************************
Many issues are annotated for difficulty as follows:
@@ -33,6 +33,43 @@ Obviously, as the issues have not been solved yet, these annotations
are mere guesses, and some may be wrong.
************************************************************************
+* assertion failures
+************************************************************************
+
+- .if n .ce in the middle of .TS data
+ afl case f1/id:000103,sig:06,src:009024+009105,op:splice,rep:2 (jes@)
+ While roff_parseln() prevents .ce and similar requests in the middle
+ of a tbl, the guard is no longer effective when the .ce is wrapped
+ in a roff block, for example a conditional. The resulting assertion
+ has never been seen in any real-world manual page.
+ This is too dangerous to fix before release because it requires
+ reorganizing the very delicate internals of roff_parseln(),
+ which risks causing more severe bugs.
+ loc * exist *** algo *** size * imp *
+
+
+************************************************************************
+* bugs: invalid output
+************************************************************************
+
+- wrong number of layout columns in tbl(7) code generated by -T man
+ https://savannah.gnu.org/bugs/?57720
+ The reason likely is that tbl(7) does not support the -Bl -column
+ feature of not explicitly specifying the last table column.
+ loc ** exist * algo ** size * imp ***
+
+- eqn(7) delimiters cause conditional lines to misbehave
+ nabijaczleweli 8 Sep 2021 15:24:48 +0200
+ loc * exist *** algo *** size * imp *
+
+- roff.c, roff_expand() should not remove blanks before comments
+ to Oliver Corff, Sep 7, 2021
+ loc * exist * algo * size * imp *
+ but watch out for regressions in the high-level parsers
+ maybe it should not even remove comments? - consider T{\"
+
+
+************************************************************************
* missing features
************************************************************************
@@ -83,8 +120,39 @@ are mere guesses, and some may be wrong.
Jan Stary 20 Apr 2019 20:16:54 +0200
loc * exist *** algo *** size ** imp *
+- mandoc replaces all ASCII control characters except tab and line feed
+ with '?' during input. It would be better to replace them with
+ Unicode escapes in preconv_encode() or somewhere in the vicinity,
+ such that the already existing better replacement strings show
+ up in the output. Emulating groff is not desirable: groff replaces
+ 0x00, 0x0b, and 0x0d to 0x1f with the empty string (bad because
+ that's easy to overlook for the document author), 0x01 with '.'
+ (very confusing), and passes through 0x02 to 0x08, 0x0c, and 0x7f
+ raw (bad because that is insecure output). Remember that 0x07 may
+ need special handling because it is sometimes used for certain
+ delimiters, so it may need handling *after* roff.c rather than before.
+ reminded by John Gardner 16 Jun 2020 14:26:28 +1000
+ Actually, more ASCII control characters than just 0x07 may need
+ later handling because they can for example be used in macro names.
+ So they may need handling after roff(7) processing.
+ pointed out by John Gardner 23 Jun 2020 18:28:08 +1000
+ more info from John Gardner 29 Jun 2020 19:54:04 +1000
+ loc ** exist ** algo ** size ** imp *
+
+- many missing features used in old groff_char(7),
+ some can possibly be supported
+ kamil at netbsd 12 Nov 2020 17:27:09 +0100 + reply
+
+- \s with arbitrary arg delimiters as already supported for other escapes
+ found following jmc@'s mail 28 Apr 2021 18:31:41 +0100
+ loc * exist * algo * size * imp *
+
--- missing mdoc features ----------------------------------------------
+- .Sh and .Ss should be parsed and partially callable, see groff_mdoc(7)
+ reed at reedmedia dot net Sat, 21 Dec 2019 17:13:07 -0600
+ loc ** exist ** algo ** size ** imp *
+
- .Bl -column .Xo support is missing
ultimate goal:
restore .Xr and .Dv to
@@ -153,6 +221,13 @@ are mere guesses, and some may be wrong.
--- missing man features -----------------------------------------------
+- MANWIDTH
+ Markus Waldeck <waldeck at gmx dot de> 9 Jun 2015 05:49:56 +0200
+ Laura Morales <lauretas at mail dot com> 26 Apr 2018 08:15:55 +0200
+ Kamil Rytarowski <kamil at netbsd> 13 Nov 2020 00:19:36 +0100
+ patch from Kamil 13 Nov 2020 22:37:07 +0100
+ loc * exist * algo * size * imp *
+
- groff_www(7) .MTO and .URL
These macros were used by the GNU grep(1) man page.
The groff_www(7) manual page itself uses them, too.
@@ -217,6 +292,21 @@ are mere guesses, and some may be wrong.
--- missing misc features ----------------------------------------------
+- conisder whether man(1) fallback code in main.c/fs_*() can find files
+ like man3c/fopen.3c (illumos, Solaris) and man3p/fopen.3p (POSIX)
+ discussed with Robert Mustacchi 21 Sep 2021 10:39:40 -0700
+ loc * exist * algo ** size * imp **
+
+- let makewhatis(8) follow symbolic links to dirs below READ_ALLOWED_PATH
+ this may be feasible using fts_set(FTS_FOLLOW)
+ mail to sternenseemann 19 Aug 2021 19:11:50 +0200
+ loc * exist ** algo ** size * imp **
+
+- -T man does not handle eqn(7) and tbl(7)
+ Stephen Gregoratto 16 Feb 2020 01:28:07 +1100
+ also https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=901636
+ loc ** exist ** algo ** size *** imp **
+
- man -ks 1,8 route; kn@ Jul 13, 2018 orally
- italic correction (\/) in PostScript mode
@@ -291,6 +381,10 @@ are mere guesses, and some may be wrong.
- check features of the Slackware man.conf(5) format
Carsten Kunze Wed, 11 Mar 2015 17:57:24 +0100
+- look at http://www.snake.net/software/troffcvt/ (troff to HTML)
+ mentioned by Oliver Corff 22 Jan 2021 01:36:49 +0100
+
+
************************************************************************
* formatting issues: ugly output
************************************************************************
@@ -370,10 +464,29 @@ are mere guesses, and some may be wrong.
add a new <</Type /Font>> 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 **
+ loc ** exist ** algo ** size * imp **
--- HTML issues --------------------------------------------------------
+- make the HTML scaffolding customozable with -O skip=...
+ mail to Oliver Corff 3 Jun 2021 17:28:02 +0200
+ more feedback from Oliver 3 Jun 2021 18:27:56 +0200
+ more feedback from Oliver 3 Jun 2021 23:37:18 +0200
+
+- .Bd -unfilled should not use monospaced font
+ anton@ 4 Mar 2021 08:19:35 +0100
+ loc ** exist * algo * size * imp **
+
+- HTML formatting of .nf should avoid <br/>
+ and not close and re-open <pre> on .P
+ my mail to ports@ 27 Jun 2021 16:09:20 +0200
+ loc ** exist ** algo * size * imp **
+
+- get rid of the last handful of style= attributes such that
+ Content-Security-Policy: can be enabled without unsafe-inline
+ suggested by bentley@ Nov 10, 2019 at 06:02:49AM -0700
+ loc * exist * algo * size * imp **
+
- .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
@@ -386,6 +499,11 @@ are mere guesses, and some may be wrong.
https://github.com/Debian/debiman/issues/15
loc * exist * algo ** size ** imp **
+- space characters can end up in href= attributes, for example coming
+ from the first .Xr argument (where they make no sense, but still);
+ does this affect other characters, other source macros...?
+ Jackson Pauls 29 Aug 2017 16:56:27 +0100
+
- The tables used to render the three-part page headers actually force
the width of the <body> to the max-width given for <html>.
Not yet sure how to fix that...
@@ -470,6 +588,10 @@ are mere guesses, and some may be wrong.
* warning issues
************************************************************************
+- shorten/simplify error messages for usage errors
+ To: deraadt@ 25 Oct 2020 23:37:01 +0100
+ loc ** exist * algo * size ** imp ***
+
- warn about duplicate .Sh/.Ss heads
gre(4): Rename duplicate sections 20 Apr 2018 15:27:33 +0200
loc * exist * algo * size * imp **
@@ -505,6 +627,10 @@ are mere guesses, and some may be wrong.
output without intervening whitespace, in particular after a
macro line (from the mdoclint TODO)
+- report double .TH in man(7) as an ERROR and let the first win
+ kristaps@ 28 Mar 2021 13:30:41 +0200
+ loc * exist * algo * size * imp *
+
- makewhatis -p complains about language subdirectories:
/usr/local/man//ru: Unknown directory part
@@ -553,6 +679,9 @@ are mere guesses, and some may be wrong.
* CGI issues
************************************************************************
+ - Inspect httpd(8) logs on man.openbsd.org and consider
+ whether logging can be improved, where bad syntax comes from,
+ and what needs to be done to get rid of COMPAT_OLDURI.
- Enable HTTP compression by detecting gzip encoding and filtering
output through libz.
- Privilege separation (see OpenSSH).
@@ -562,6 +691,15 @@ are mere guesses, and some may be wrong.
* to improve in the groff_mdoc(7) macros
************************************************************************
+- delete OS release verification from .Dx, .Fx, .Nx, .Ox etc.
+ https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=629161
+ also Branden Robinson 18 Dec 2019 00:59:52 +1100
+
+- Can the distinction between .Vt and .Va be made stricter,
+ recommending .Vt extern char * Ns Va optarg ; ?
+ What about the block macro properties of .Vt in the SYNOPSIS?
+ zeurkous 25 Dec 2019 08:48:36 +0100
+
- .Cd # arch1, arch2 in section 4 pages:
find better way to indicate multiple architectures, maybe:
allow .Dt vgafb 4 "macppc sparc64"
diff --git a/apropos.1 b/apropos.1
index 01d2a6bfa4f4..9129ae31f126 100644
--- a/apropos.1
+++ b/apropos.1
@@ -1,4 +1,4 @@
-.\" $Id: apropos.1,v 1.49 2018/11/22 12:33:52 schwarze Exp $
+.\" $Id: apropos.1,v 1.51 2020/10/01 22:50:00 schwarze Exp $
.\"
.\" Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2011,2012,2014,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
@@ -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: November 22 2018 $
+.Dd $Mdocdate: October 1 2020 $
.Dt APROPOS 1
.Os
.Sh NAME
@@ -73,7 +73,7 @@ would.
If the standard output is a terminal device and
.Fl c
is not specified, use
-.Xr more 1
+.Xr less 1
to paginate them.
In
.Fl a
@@ -340,7 +340,7 @@ types appearing in function arguments in the SYNOPSIS
Any non-empty value of the environment variable
.Ev MANPAGER
is used instead of the standard pagination program,
-.Xr more 1 ;
+.Xr less 1 ;
see
.Xr man 1
for details.
@@ -363,8 +363,7 @@ Specifies the pagination program to use when
.Ev MANPAGER
is not defined.
If neither PAGER nor MANPAGER is defined,
-.Xr more 1
-.Fl s
+.Xr less 1
is used.
Only used if
.Fl a
@@ -404,6 +403,10 @@ Search in names and descriptions using a case-sensitive regular expression:
.Pp
.Dl $ apropos \(aq\(tiset.?[ug]id\(aq
.Pp
+Search for all manual pages in a given section:
+.Pp
+.Dl $ apropos \-s 9 \&.
+.Pp
Search for manuals in the library section mentioning both the
.Qq optind
and the
diff --git a/arch.c b/arch.c
index 551c86796a21..41a23cbbc32b 100644
--- a/arch.c
+++ b/arch.c
@@ -1,4 +1,4 @@
-/* $Id: arch.c,v 1.15 2019/05/21 07:52:00 schwarze Exp $ */
+/* $Id: arch.c,v 1.17 2021/05/13 13:33:11 schwarze Exp $ */
/*
* Copyright (c) 2017, 2019 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -26,7 +26,7 @@ arch_valid(const char *arch, enum mandoc_os os)
const char *openbsd_arch[] = {
"alpha", "amd64", "arm64", "armv7", "hppa", "i386",
"landisk", "loongson", "luna88k", "macppc", "mips64",
- "octeon", "sgi", "sparc64", NULL
+ "octeon", "powerpc64", "riscv64", "sparc64", NULL
};
const char *netbsd_arch[] = {
"acorn26", "acorn32", "algor", "alpha", "amiga",
diff --git a/att.c b/att.c
index 5575bed54a4f..abde95d7397b 100644
--- a/att.c
+++ b/att.c
@@ -1,4 +1,4 @@
-/* $Id: att.c,v 1.18 2018/12/13 11:55:46 schwarze Exp $ */
+/* $Id: att.c,v 1.19 2021/09/04 20:26:43 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -37,7 +37,7 @@ mdoc_a2att(const char *p)
LINE("v5", "Version\\~5 AT&T UNIX");
LINE("v6", "Version\\~6 AT&T UNIX");
LINE("v7", "Version\\~7 AT&T UNIX");
- LINE("32v", "Version\\~32V AT&T UNIX");
+ LINE("32v", "Version\\~7 AT&T UNIX/32V");
LINE("III", "AT&T System\\~III UNIX");
LINE("V", "AT&T System\\~V UNIX");
LINE("V.1", "AT&T System\\~V Release\\~1 UNIX");
diff --git a/catman.c b/catman.c
index 7d62c0e74add..b1bab0f68c4b 100644
--- a/catman.c
+++ b/catman.c
@@ -1,4 +1,4 @@
-/* $Id: catman.c,v 1.21 2017/02/18 12:24:24 schwarze Exp $ */
+/* $Id: catman.c,v 1.22 2020/06/14 23:40:31 schwarze Exp $ */
/*
* Copyright (c) 2017 Michael Stapelberg <stapelberg@debian.org>
* Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -17,7 +17,7 @@
*/
#include "config.h"
-#if HAVE_CMSG_XPG42
+#if NEED_XPG4_2
#define _XPG4_2
#endif
diff --git a/cgi.c b/cgi.c
index 4762f819d57d..91310ce404b4 100644
--- a/cgi.c
+++ b/cgi.c
@@ -1,7 +1,7 @@
-/* $Id: cgi.c,v 1.167 2019/07/10 12:49:20 schwarze Exp $ */
+/* $Id: cgi.c,v 1.175 2021/08/19 15:23:36 schwarze Exp $ */
/*
+ * Copyright (c) 2014-2019, 2021 Ingo Schwarze <schwarze@usta.de>
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2015, 2016, 2017, 2018 Ingo Schwarze <schwarze@usta.de>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,6 +14,8 @@
* 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.
+ *
+ * Implementation of the man.cgi(8) program.
*/
#include "config.h"
@@ -70,14 +72,15 @@ enum focus {
static void html_print(const char *);
static void html_putchar(char);
static int http_decode(char *);
-static void http_encode(const char *p);
+static void http_encode(const char *);
static void parse_manpath_conf(struct req *);
-static void parse_path_info(struct req *req, const char *path);
+static void parse_path_info(struct req *, const char *);
static void parse_query_string(struct req *, const char *);
static void pg_error_badrequest(const char *);
static void pg_error_internal(void);
static void pg_index(const struct req *);
-static void pg_noresult(const struct req *, const char *);
+static void pg_noresult(const struct req *, int, const char *,
+ const char *);
static void pg_redirect(const struct req *, const char *);
static void pg_search(const struct req *);
static void pg_searchres(const struct req *,
@@ -119,16 +122,18 @@ 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", "arm64",
- "hppa", "i386", "landisk",
- "loongson", "luna88k", "macppc", "mips64",
- "octeon", "sgi", "socppc", "sparc64",
+ "amd64", "alpha", "armv7", "arm64",
+ "hppa", "i386", "landisk", "loongson",
+ "luna88k", "macppc", "mips64", "octeon",
+ "powerpc64", "riscv64", "sparc64",
+
"amiga", "arc", "armish", "arm32",
"atari", "aviion", "beagle", "cats",
"hppa64", "hp300",
"ia64", "mac68k", "mvme68k", "mvme88k",
"mvmeppc", "palm", "pc532", "pegasos",
- "pmax", "powerpc", "solbourne", "sparc",
+ "pmax", "powerpc", "sgi", "socppc",
+ "solbourne", "sparc",
"sun3", "vax", "wgrisc", "x68k",
"zaurus"
};
@@ -339,6 +344,8 @@ resp_begin_http(int code, const char *msg)
printf("Content-Type: text/html; charset=utf-8\r\n"
"Cache-Control: no-cache\r\n"
+ "Content-Security-Policy: default-src 'none'; "
+ "style-src 'self' 'unsafe-inline'\r\n"
"Pragma: no-cache\r\n"
"\r\n");
@@ -363,7 +370,8 @@ resp_copy(const char *filename)
static void
resp_begin_html(int code, const char *msg, const char *file)
{
- char *cp;
+ const char *name, *sec, *cp;
+ int namesz, secsz;
resp_begin_http(code, msg);
@@ -378,12 +386,27 @@ resp_begin_html(int code, const char *msg, const char *file)
" <title>",
CSS_DIR);
if (file != NULL) {
- if ((cp = strrchr(file, '/')) != NULL)
- file = cp + 1;
- if ((cp = strrchr(file, '.')) != NULL) {
- printf("%.*s(%s) - ", (int)(cp - file), file, cp + 1);
- } else
- printf("%s - ", file);
+ cp = strrchr(file, '/');
+ name = cp == NULL ? file : cp + 1;
+ cp = strrchr(name, '.');
+ namesz = cp == NULL ? strlen(name) : cp - name;
+ sec = NULL;
+ if (cp != NULL && cp[1] != '0') {
+ sec = cp + 1;
+ secsz = strlen(sec);
+ } else if (name - file > 1) {
+ for (cp = name - 2; cp >= file; cp--) {
+ if (*cp < '1' || *cp > '9')
+ continue;
+ sec = cp;
+ secsz = name - cp - 1;
+ break;
+ }
+ }
+ printf("%.*s", namesz, name);
+ if (sec != NULL)
+ printf("(%.*s)", secsz, sec);
+ fputs(" - ", stdout);
}
printf("%s</title>\n"
"</head>\n"
@@ -408,7 +431,8 @@ resp_searchform(const struct req *req, enum focus focus)
{
int i;
- printf("<form action=\"/%s\" method=\"get\">\n"
+ printf("<form action=\"/%s\" method=\"get\" "
+ "autocomplete=\"off\" autocapitalize=\"none\">\n"
" <fieldset>\n"
" <legend>Manual Page Search Parameters</legend>\n",
scriptname);
@@ -546,12 +570,13 @@ pg_index(const struct req *req)
}
static void
-pg_noresult(const struct req *req, const char *msg)
+pg_noresult(const struct req *req, int code, const char *http_msg,
+ const char *user_msg)
{
- resp_begin_html(200, NULL, NULL);
+ resp_begin_html(code, http_msg, NULL);
resp_searchform(req, FOCUS_QUERY);
puts("<p>");
- puts(msg);
+ puts(user_msg);
puts("</p>");
resp_end_html();
}
@@ -1016,9 +1041,10 @@ pg_search(const struct req *req)
if (req->isquery && req->q.equal && argc == 1)
pg_redirect(req, argv[0]);
else if (mansearch(&search, &paths, argc, argv, &res, &ressz) == 0)
- pg_noresult(req, "You entered an invalid query.");
+ pg_noresult(req, 400, "Bad Request",
+ "You entered an invalid query.");
else if (ressz == 0)
- pg_noresult(req, "No results found.");
+ pg_noresult(req, 404, "Not Found", "No results found.");
else
pg_searchres(req, res, ressz);
diff --git a/chars.c b/chars.c
index 24166dbd9f8f..d54fc458aea2 100644
--- a/chars.c
+++ b/chars.c
@@ -1,7 +1,8 @@
-/* $Id: chars.c,v 1.78 2018/12/15 19:30:26 schwarze Exp $ */
+/* $Id: chars.c,v 1.79 2020/02/13 16:18:29 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011,2014,2015,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 2014, 2015, 2017, 2018, 2020
+ * Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -47,7 +48,7 @@ static struct ln lines[] = {
/* Spacing. */
{ " ", ascii_nbrsp, 0x00a0 },
{ "~", ascii_nbrsp, 0x00a0 },
- { "0", " ", 0x2002 },
+ { "0", ascii_nbrsp, 0x00a0 },
{ ":", ascii_break, 0 },
/* Lines. */
diff --git a/compat_err.c b/compat_err.c
index d8b09cb2a307..31994cbfaee7 100644
--- a/compat_err.c
+++ b/compat_err.c
@@ -1,12 +1,4 @@
-#include "config.h"
-
-#if HAVE_ERR
-
-int dummy;
-
-#else
-
-/* $Id: compat_err.c,v 1.4 2015/11/26 07:42:11 schwarze Exp $ */
+/* $Id: compat_err.c,v 1.5 2020/06/15 01:37:14 schwarze Exp $ */
/*
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
@@ -35,6 +27,7 @@ int dummy;
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+#include "config.h"
#include <errno.h>
#include <stdarg.h>
@@ -108,5 +101,3 @@ warnx(const char *fmt, ...)
va_end(ap);
fputc('\n', stderr);
}
-
-#endif
diff --git a/compat_fts.c b/compat_fts.c
index 3859111a52f8..e44298df02b8 100644
--- a/compat_fts.c
+++ b/compat_fts.c
@@ -1,13 +1,5 @@
-#include "config.h"
-
-#if HAVE_FTS
-
-int dummy;
-
-#else
-
-/* $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 $ */
+/* $Id: compat_fts.c,v 1.17 2020/06/15 01:37:14 schwarze Exp $ */
+/* $OpenBSD: fts.c,v 1.59 2019/06/28 13:32:41 deraadt Exp $ */
/*-
* Copyright (c) 1990, 1993, 1994
@@ -37,6 +29,7 @@ int dummy;
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+#include "config.h"
#include <sys/stat.h>
#include <sys/types.h>
@@ -62,6 +55,8 @@ static int fts_palloc(FTS *, size_t);
static FTSENT *fts_sort(FTS *, FTSENT *, int);
static unsigned short fts_stat(FTS *, FTSENT *);
+typedef int (*qsort_compar_proto)(const void *, const void *);
+
#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
@@ -573,19 +568,20 @@ fts_sort(FTS *sp, FTSENT *head, int nitems)
if (nitems > sp->fts_nitems) {
struct _ftsent **a;
- sp->fts_nitems = nitems + 40;
if ((a = reallocarray(sp->fts_array,
- sp->fts_nitems, sizeof(FTSENT *))) == NULL) {
+ nitems + 40, sizeof(FTSENT *))) == NULL) {
free(sp->fts_array);
sp->fts_array = NULL;
sp->fts_nitems = 0;
return (head);
}
+ sp->fts_nitems = nitems + 40;
sp->fts_array = a;
}
for (ap = sp->fts_array, p = head; p; p = p->fts_link)
*ap++ = p;
- qsort(sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar);
+ qsort(sp->fts_array, nitems, sizeof(FTSENT *),
+ (qsort_compar_proto)sp->fts_compar);
for (head = *(ap = sp->fts_array); --nitems; ++ap)
ap[0]->fts_link = ap[1];
ap[0]->fts_link = NULL;
@@ -648,13 +644,14 @@ fts_palloc(FTS *sp, size_t more)
errno = ENAMETOOLONG;
return (1);
}
- sp->fts_pathlen += more;
- p = realloc(sp->fts_path, sp->fts_pathlen);
+ p = recallocarray(sp->fts_path, sp->fts_pathlen,
+ sp->fts_pathlen + more, 1);
if (p == NULL) {
free(sp->fts_path);
sp->fts_path = NULL;
return (1);
}
+ sp->fts_pathlen += more;
sp->fts_path = p;
return (0);
}
@@ -697,5 +694,3 @@ fts_maxarglen(char * const *argv)
max = len;
return (max + 1);
}
-
-#endif
diff --git a/compat_fts.h b/compat_fts.h
index f4a97a4c3a56..ca3f3a7ed804 100644
--- a/compat_fts.h
+++ b/compat_fts.h
@@ -43,7 +43,8 @@ typedef struct {
char *fts_path; /* path for this descent */
size_t fts_pathlen; /* sizeof(path) */
int fts_nitems; /* elements in the sort array */
- int (*fts_compar)(); /* compare function */
+ int (*fts_compar)(const struct _ftsent **, const struct _ftsent **);
+ /* compare function */
#define FTS_NOCHDIR 0x0004 /* don't change directories */
#define FTS_PHYSICAL 0x0010 /* physical walk */
diff --git a/compat_getline.c b/compat_getline.c
index aed4754ffdae..843a94a6bb93 100644
--- a/compat_getline.c
+++ b/compat_getline.c
@@ -1,12 +1,4 @@
-#include "config.h"
-
-#if HAVE_GETLINE
-
-int dummy;
-
-#else
-
-/* $Id: compat_getline.c,v 1.1 2015/11/07 20:52:52 schwarze Exp $ */
+/* $Id: compat_getline.c,v 1.2 2020/06/15 01:37:14 schwarze Exp $ */
/*
* Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -22,6 +14,7 @@ int dummy;
* 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"
#include <sys/types.h>
#include <errno.h>
@@ -64,5 +57,3 @@ getline(char **buf, size_t *bufsz, FILE *fp)
return pos;
}
}
-
-#endif
diff --git a/compat_getsubopt.c b/compat_getsubopt.c
index 880f2f789d4a..c442f87ecab7 100644
--- a/compat_getsubopt.c
+++ b/compat_getsubopt.c
@@ -1,12 +1,4 @@
-#include "config.h"
-
-#if HAVE_GETSUBOPT
-
-int dummy;
-
-#else
-
-/* $Id: compat_getsubopt.c,v 1.5 2014/08/17 20:53:50 schwarze Exp $ */
+/* $Id: compat_getsubopt.c,v 1.6 2020/06/15 01:37:15 schwarze Exp $ */
/* $OpenBSD: getsubopt.c,v 1.4 2005/08/08 08:05:36 espie Exp $ */
/*-
@@ -37,6 +29,7 @@ int dummy;
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+#include "config.h"
#include <unistd.h>
#include <stdlib.h>
@@ -92,5 +85,3 @@ getsubopt(char **optionp, char * const *tokens, char **valuep)
return(cnt);
return(-1);
}
-
-#endif
diff --git a/compat_isblank.c b/compat_isblank.c
index 9e3c74706c3d..38d1d2839eb8 100644
--- a/compat_isblank.c
+++ b/compat_isblank.c
@@ -1,12 +1,4 @@
-#include "config.h"
-
-#if HAVE_ISBLANK
-
-int dummy;
-
-#else
-
-/* $Id: compat_isblank.c,v 1.2 2015/10/06 18:32:19 schwarze Exp $ */
+/* $Id: compat_isblank.c,v 1.3 2020/06/15 01:37:15 schwarze Exp $ */
/*
* Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -22,12 +14,10 @@ int dummy;
* 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"
int
isblank(int c)
{
-
return c == ' ' || c == '\t';
}
-
-#endif
diff --git a/compat_mkdtemp.c b/compat_mkdtemp.c
index 1fcb325f4f9a..c2edfcb1927b 100644
--- a/compat_mkdtemp.c
+++ b/compat_mkdtemp.c
@@ -1,14 +1,6 @@
-#include "config.h"
-
-#if HAVE_MKDTEMP
-
-int dummy;
-
-#else
-
-/* $Id: compat_mkdtemp.c,v 1.2 2015/10/06 18:32:19 schwarze Exp $ */
+/* $Id: compat_mkdtemp.c,v 1.4 2021/09/19 15:02:55 schwarze Exp $ */
/*
- * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2015, 2021 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -25,6 +17,7 @@ int dummy;
* The algorithm of this function is inspired by OpenBSD mkdtemp(3)
* by Theo de Raadt and Todd Miller, but the code differs.
*/
+#include "config.h"
#include <sys/stat.h>
#include <errno.h>
@@ -43,19 +36,15 @@ mkdtemp(char *path)
start--;
for (tries = INT_MAX; tries; tries--) {
- if (mktemp(path) == NULL) {
- errno = EEXIST;
+ if (mktemp(path) == NULL)
return NULL;
- }
if (mkdir(path, S_IRUSR | S_IWUSR | S_IXUSR) == 0)
return path;
- if (errno != EEXIST)
- return NULL;
for (cp = start; *cp != '\0'; cp++)
*cp = 'X';
+ if (errno != EEXIST)
+ return NULL;
}
errno = EEXIST;
return NULL;
}
-
-#endif
diff --git a/compat_mkstemps.c b/compat_mkstemps.c
new file mode 100644
index 000000000000..32394ffa682e
--- /dev/null
+++ b/compat_mkstemps.c
@@ -0,0 +1,63 @@
+/* $Id: compat_mkstemps.c,v 1.1 2021/09/19 15:05:39 schwarze Exp $ */
+/*
+ * Copyright (c) 2015, 2021 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * 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.
+ *
+ * Parts of the algorithm of this function are inspired by OpenBSD
+ * mkdtemp(3) by Theo de Raadt and Todd Miller, but the code differs.
+ */
+#include "config.h"
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+mkstemps(char *path, int suffixlen)
+{
+ char *start, *end, *cp;
+ int fd, tries;
+ char backup;
+
+ end = strchr(path, '\0');
+ if (suffixlen < 0 || suffixlen > end - path - 6) {
+ errno = EINVAL;
+ return -1;
+ }
+ end -= suffixlen;
+ for (start = end; start > path; start--)
+ if (start[-1] != 'X')
+ break;
+
+ backup = *end;
+ for (tries = INT_MAX; tries; tries--) {
+ *end = '\0';
+ cp = mktemp(path);
+ *end = backup;
+ if (cp == NULL)
+ return -1;
+ fd = open(path, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
+ if (fd != -1)
+ return fd;
+ for (cp = start; cp < end; cp++)
+ *cp = 'X';
+ if (errno != EEXIST)
+ return -1;
+ }
+ errno = EEXIST;
+ return -1;
+}
diff --git a/compat_ohash.c b/compat_ohash.c
index cbd6052182f2..f29c086c6d7d 100644
--- a/compat_ohash.c
+++ b/compat_ohash.c
@@ -1,11 +1,4 @@
-#include "config.h"
-
-#if HAVE_OHASH
-
-int dummy;
-
-#else
-
+/* $Id: compat_ohash.c,v 1.7 2020/06/15 01:37:15 schwarze Exp $ */
/* $OpenBSD: ohash.c,v 1.1 2014/06/02 18:52:03 deraadt Exp $ */
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
@@ -22,9 +15,9 @@ int dummy;
* 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"
#include <sys/types.h>
-
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
@@ -335,5 +328,3 @@ ohash_qlookupi(struct ohash *h, const char *s, const char **e)
hv = ohash_interval(s, e);
return ohash_lookup_interval(h, s, *e, hv);
}
-
-#endif /*!HAVE_OHASH*/
diff --git a/compat_progname.c b/compat_progname.c
index 9840cc7c6c61..e067e489c6b7 100644
--- a/compat_progname.c
+++ b/compat_progname.c
@@ -1,12 +1,4 @@
-#include "config.h"
-
-#if HAVE_PROGNAME
-
-int dummy;
-
-#else
-
-/* $Id: compat_progname.c,v 1.1 2015/11/06 16:30:33 schwarze Exp $ */
+/* $Id: compat_progname.c,v 1.2 2020/06/15 01:37:15 schwarze Exp $ */
/*
* Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -22,21 +14,18 @@ int dummy;
* 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"
static const char *progname;
void
setprogname(const char *name)
{
-
progname = name;
}
const char *
getprogname(void)
{
-
return progname;
}
-
-#endif
diff --git a/compat_reallocarray.c b/compat_reallocarray.c
index 66151904257d..a12cec1344cb 100644
--- a/compat_reallocarray.c
+++ b/compat_reallocarray.c
@@ -1,13 +1,5 @@
-#include "config.h"
-
-#if HAVE_REALLOCARRAY
-
-int dummy;
-
-#else
-
-/* $Id: compat_reallocarray.c,v 1.4 2014/12/11 09:05:01 schwarze Exp $ */
-/* $OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $ */
+/* $Id: compat_reallocarray.c,v 1.5 2020/06/15 01:37:15 schwarze Exp $ */
+/* $OpenBSD: reallocarray.c,v 1.3 2015/09/13 08:31:47 guenther Exp $ */
/*
* Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
*
@@ -23,6 +15,7 @@ int dummy;
* 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"
#include <sys/types.h>
#include <errno.h>
@@ -45,5 +38,3 @@ reallocarray(void *optr, size_t nmemb, size_t size)
}
return realloc(optr, size * nmemb);
}
-
-#endif /*!HAVE_REALLOCARRAY*/
diff --git a/compat_recallocarray.c b/compat_recallocarray.c
index d86dc5091a0a..723e145c0446 100644
--- a/compat_recallocarray.c
+++ b/compat_recallocarray.c
@@ -1,15 +1,7 @@
-#include "config.h"
-
-#if HAVE_RECALLOCARRAY
-
-int dummy;
-
-#else
-
-/* $Id: compat_recallocarray.c,v 1.1 2017/06/12 19:05:47 schwarze Exp $ */
-/* $OpenBSD: malloc.c,v 1.225 2017/05/13 07:11:29 otto Exp $ */
+/* $Id: compat_recallocarray.c,v 1.2 2020/06/15 01:37:15 schwarze Exp $ */
+/* $OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $ */
/*
- * Copyright (c) 2017 Otto Moerbeek <otto@drijf.net>
+ * Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -23,18 +15,19 @@ int dummy;
* 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"
#include <sys/types.h>
#include <errno.h>
-#include <stdint.h>
#include <stdlib.h>
+#include <stdint.h>
#include <string.h>
/*
* This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
* if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
*/
-#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
+#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
/*
* Even though specified in POSIX, the PAGESIZE and PAGE_SIZE
@@ -42,7 +35,7 @@ int dummy;
* to avoid free() overhead for small shrinking, simply pick
* an arbitrary number.
*/
-#define MALLOC_PAGESIZE (1UL << 12)
+#define getpagesize() (1UL << 12)
void *
@@ -75,7 +68,7 @@ recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size)
if (newsize <= oldsize) {
size_t d = oldsize - newsize;
- if (d < oldsize / 2 && d < MALLOC_PAGESIZE) {
+ if (d < oldsize / 2 && d < getpagesize()) {
memset((char *)ptr + newsize, 0, d);
return ptr;
}
@@ -104,5 +97,3 @@ recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size)
return newptr;
}
-
-#endif /* !HAVE_RECALLOCARRAY */
diff --git a/compat_strcasestr.c b/compat_strcasestr.c
index 62c0ff740c81..5eba8257fdb0 100644
--- a/compat_strcasestr.c
+++ b/compat_strcasestr.c
@@ -1,12 +1,4 @@
-#include "config.h"
-
-#if HAVE_STRCASESTR
-
-int dummy;
-
-#else
-
-/* $Id: compat_strcasestr.c,v 1.4 2014/12/11 09:19:32 schwarze Exp $ */
+/* $Id: compat_strcasestr.c,v 1.5 2020/06/15 01:37:15 schwarze Exp $ */
/* $NetBSD: strcasestr.c,v 1.3 2005/11/29 03:12:00 christos Exp $ */
/*-
@@ -40,6 +32,7 @@ int dummy;
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+#include "config.h"
#include <sys/types.h>
#include <ctype.h>
@@ -69,5 +62,3 @@ strcasestr(const char *s, const char *find)
}
return __UNCONST(s);
}
-
-#endif
diff --git a/compat_stringlist.c b/compat_stringlist.c
index 17eba7724af5..fb8e56aebaa4 100644
--- a/compat_stringlist.c
+++ b/compat_stringlist.c
@@ -1,16 +1,13 @@
-#include "config.h"
-
-#if HAVE_STRINGLIST
-
-int dummy;
-
-#else
+/* $Id: compat_stringlist.c,v 1.8 2020/06/15 21:48:09 schwarze Exp $ */
+/* $NetBSD: stringlist.c,v 1.14 2015/05/21 01:29:13 christos Exp $ */
-/* $Id: compat_stringlist.c,v 1.6 2015/11/07 14:22:29 schwarze Exp $ */
-/*
- * Copyright (c) 1994 Christos Zoulas <christos@netbsd.org>
+/*-
+ * Copyright (c) 1994, 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -20,22 +17,20 @@ int dummy;
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
*/
+#include "config.h"
-#if HAVE_ERR
-#include <err.h>
-#endif
#include <stdlib.h>
#include <string.h>
#include "compat_stringlist.h"
@@ -52,13 +47,15 @@ sl_init(void)
sl = malloc(sizeof(StringList));
if (sl == NULL)
- err(1, "stringlist");
+ return NULL;
sl->sl_cur = 0;
sl->sl_max = _SL_CHUNKSIZE;
sl->sl_str = reallocarray(NULL, sl->sl_max, sizeof(char *));
- if (sl->sl_str == NULL)
- err(1, "stringlist");
+ if (sl->sl_str == NULL) {
+ free(sl);
+ sl = NULL;
+ }
return sl;
}
@@ -70,14 +67,17 @@ int
sl_add(StringList *sl, char *name)
{
if (sl->sl_cur == sl->sl_max - 1) {
+ char **new;
+
+ new = reallocarray(sl->sl_str, (sl->sl_max + _SL_CHUNKSIZE),
+ sizeof(char *));
+ if (new == NULL)
+ return -1;
sl->sl_max += _SL_CHUNKSIZE;
- sl->sl_str = reallocarray(sl->sl_str,
- sl->sl_max, sizeof(char *));
- if (sl->sl_str == NULL)
- return (-1);
+ sl->sl_str = new;
}
sl->sl_str[sl->sl_cur++] = name;
- return (0);
+ return 0;
}
@@ -116,4 +116,20 @@ sl_find(StringList *sl, const char *name)
return NULL;
}
-#endif
+int
+sl_delete(StringList *sl, const char *name, int all)
+{
+ size_t i, j;
+
+ for (i = 0; i < sl->sl_cur; i++)
+ if (strcmp(sl->sl_str[i], name) == 0) {
+ if (all)
+ free(sl->sl_str[i]);
+ for (j = i + 1; j < sl->sl_cur; j++)
+ sl->sl_str[j - 1] = sl->sl_str[j];
+ sl->sl_str[--sl->sl_cur] = NULL;
+ return 0;
+ }
+ return -1;
+}
+
diff --git a/compat_stringlist.h b/compat_stringlist.h
index f04e8435047d..5777b1cb2871 100644
--- a/compat_stringlist.h
+++ b/compat_stringlist.h
@@ -1,10 +1,13 @@
-/* $Id: compat_stringlist.h,v 1.4 2015/11/07 14:01:16 schwarze Exp $ */
-/* $NetBSD: stringlist.h,v 1.2 1997/01/17 06:11:36 lukem Exp $ */
+/* $Id: compat_stringlist.h,v 1.5 2020/06/15 21:48:09 schwarze Exp $ */
+/* $NetBSD: stringlist.h,v 1.7 2008/04/28 20:22:54 martin Exp $ */
-/*
- * Copyright (c) 1994 Christos Zoulas <christos@netbsd.org>
+/*-
+ * Copyright (c) 1994 The NetBSD Foundation, Inc.
* All rights reserved.
*
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -14,17 +17,17 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
@@ -38,8 +41,8 @@ typedef struct _stringlist {
size_t sl_cur;
} StringList;
-
-StringList *sl_init(void);
-int sl_add(StringList *, char *);
-void sl_free(StringList *, int);
-char *sl_find(StringList *, const char *);
+StringList *sl_init(void);
+int sl_add(StringList *, char *);
+void sl_free(StringList *, int);
+char *sl_find(StringList *, const char *);
+int sl_delete(StringList *, const char *, int);
diff --git a/compat_strlcat.c b/compat_strlcat.c
index acaae4fb1506..dc0ec5e79064 100644
--- a/compat_strlcat.c
+++ b/compat_strlcat.c
@@ -1,15 +1,8 @@
-#include "config.h"
-
-#if HAVE_STRLCAT
-
-int dummy;
-
-#else
-
-/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
+/* $Id: compat_strlcat.c,v 1.6 2020/06/15 20:49:57 schwarze Exp $ */
+/* $OpenBSD: strlcat.c,v 1.19 2019/01/25 00:19:25 millert Exp $ */
/*
- * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1998, 2015 Todd C. Miller <millert@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -23,43 +16,42 @@ int dummy;
* 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"
#include <sys/types.h>
#include <string.h>
/*
- * Appends src to string dst of size siz (unlike strncat, siz is the
- * full size of dst, not space left). At most siz-1 characters
- * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
- * Returns strlen(src) + MIN(siz, strlen(initial dst)).
- * If retval >= siz, truncation occurred.
+ * Appends src to string dst of size dsize (unlike strncat, dsize is the
+ * full size of dst, not space left). At most dsize-1 characters
+ * will be copied. Always NUL terminates (unless dsize <= strlen(dst)).
+ * Returns strlen(src) + MIN(dsize, strlen(initial dst)).
+ * If retval >= dsize, truncation occurred.
*/
size_t
-strlcat(char *dst, const char *src, size_t siz)
+strlcat(char *dst, const char *src, size_t dsize)
{
- char *d = dst;
- const char *s = src;
- size_t n = siz;
+ const char *odst = dst;
+ const char *osrc = src;
+ size_t n = dsize;
size_t dlen;
- /* Find the end of dst and adjust bytes left but don't go past end */
- while (n-- != 0 && *d != '\0')
- d++;
- dlen = d - dst;
- n = siz - dlen;
-
- if (n == 0)
- return(dlen + strlen(s));
- while (*s != '\0') {
- if (n != 1) {
- *d++ = *s;
+ /* Find the end of dst and adjust bytes left but don't go past end. */
+ while (n-- != 0 && *dst != '\0')
+ dst++;
+ dlen = dst - odst;
+ n = dsize - dlen;
+
+ if (n-- == 0)
+ return(dlen + strlen(src));
+ while (*src != '\0') {
+ if (n != 0) {
+ *dst++ = *src;
n--;
}
- s++;
+ src++;
}
- *d = '\0';
+ *dst = '\0';
- return(dlen + (s - src)); /* count does not include NUL */
+ return(dlen + (src - osrc)); /* count does not include NUL */
}
-
-#endif
diff --git a/compat_strlcpy.c b/compat_strlcpy.c
index a00d511817a3..2e7201a64953 100644
--- a/compat_strlcpy.c
+++ b/compat_strlcpy.c
@@ -1,15 +1,8 @@
-#include "config.h"
-
-#if HAVE_STRLCPY
-
-int dummy;
-
-#else
-
-/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
+/* $Id: compat_strlcpy.c,v 1.6 2020/06/15 20:49:57 schwarze Exp $ */
+/* $OpenBSD: strlcpy.c,v 1.16 2019/01/25 00:19:25 millert Exp $ */
/*
- * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1998, 2015 Todd C. Miller <millert@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -23,39 +16,37 @@ int dummy;
* 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"
#include <sys/types.h>
#include <string.h>
/*
- * Copy src to string dst of size siz. At most siz-1 characters
- * will be copied. Always NUL terminates (unless siz == 0).
- * Returns strlen(src); if retval >= siz, truncation occurred.
+ * Copy string src to buffer dst of size dsize. At most dsize-1
+ * chars will be copied. Always NUL terminates (unless dsize == 0).
+ * Returns strlen(src); if retval >= dsize, truncation occurred.
*/
size_t
-strlcpy(char *dst, const char *src, size_t siz)
+strlcpy(char *dst, const char *src, size_t dsize)
{
- char *d = dst;
- const char *s = src;
- size_t n = siz;
+ const char *osrc = src;
+ size_t nleft = dsize;
- /* Copy as many bytes as will fit */
- if (n != 0) {
- while (--n != 0) {
- if ((*d++ = *s++) == '\0')
+ /* Copy as many bytes as will fit. */
+ if (nleft != 0) {
+ while (--nleft != 0) {
+ if ((*dst++ = *src++) == '\0')
break;
}
}
- /* Not enough room in dst, add NUL and traverse rest of src */
- if (n == 0) {
- if (siz != 0)
- *d = '\0'; /* NUL-terminate dst */
- while (*s++)
+ /* Not enough room in dst, add NUL and traverse rest of src. */
+ if (nleft == 0) {
+ if (dsize != 0)
+ *dst = '\0'; /* NUL-terminate dst */
+ while (*src++)
;
}
- return(s - src - 1); /* count does not include NUL */
+ return(src - osrc - 1); /* count does not include NUL */
}
-
-#endif
diff --git a/compat_strndup.c b/compat_strndup.c
index 5e127364f5c8..89693e795ce9 100644
--- a/compat_strndup.c
+++ b/compat_strndup.c
@@ -1,15 +1,8 @@
-#include "config.h"
-
-#if HAVE_STRNDUP
-
-int dummy;
+/* $Id: compat_strndup.c,v 1.3 2020/06/15 20:19:39 schwarze Exp $ */
+/* $OpenBSD: strndup.c,v 1.3 2019/01/25 00:19:25 millert Exp $ */
-#else
-
-/* $Id: compat_strndup.c,v 1.1 2018/02/27 11:16:23 schwarze Exp $ */
-/* OpenBSD: strndup.c,v 1.2 2015/08/31 02:53:57 guenther Exp */
/*
- * Copyright (c) 2010 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2010 Todd C. Miller <millert@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -23,6 +16,7 @@ int dummy;
* 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"
#include <sys/types.h>
@@ -46,5 +40,3 @@ strndup(const char *str, size_t maxlen)
return copy;
}
-
-#endif
diff --git a/compat_strsep.c b/compat_strsep.c
index 1df57582802b..9765ac823eeb 100644
--- a/compat_strsep.c
+++ b/compat_strsep.c
@@ -1,13 +1,5 @@
-#include "config.h"
-
-#if HAVE_STRSEP
-
-int dummy;
-
-#else
-
-/* $Id: compat_strsep.c,v 1.4 2014/12/11 09:05:01 schwarze Exp $ */
-/* $OpenBSD: strsep.c,v 1.7 2014/02/05 20:42:32 stsp Exp $ */
+/* $Id: compat_strsep.c,v 1.5 2020/06/15 01:37:15 schwarze Exp $ */
+/* $OpenBSD: strsep.c,v 1.8 2015/08/31 02:53:57 guenther Exp $ */
/*-
* Copyright (c) 1990, 1993
@@ -37,6 +29,7 @@ int dummy;
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+#include "config.h"
/*
* Get next token from string *stringp, where tokens are possibly-empty
@@ -75,5 +68,3 @@ strsep(char **stringp, const char *delim)
}
/* NOTREACHED */
}
-
-#endif
diff --git a/compat_strtonum.c b/compat_strtonum.c
index 628e5d51b86b..ce0459fa8825 100644
--- a/compat_strtonum.c
+++ b/compat_strtonum.c
@@ -1,13 +1,5 @@
-#include "config.h"
-
-#if HAVE_STRTONUM
-
-int dummy;
-
-#else
-
-/* $Id: compat_strtonum.c,v 1.1 2015/02/16 14:56:22 schwarze Exp $ */
-/* $OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $ */
+/* $Id: compat_strtonum.c,v 1.2 2020/06/15 01:37:15 schwarze Exp $ */
+/* $OpenBSD: strtonum.c,v 1.8 2015/09/13 08:31:48 guenther Exp $ */
/*
* Copyright (c) 2004 Ted Unangst and Todd Miller
@@ -25,6 +17,7 @@ int dummy;
* 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"
#include <errno.h>
#include <limits.h>
@@ -72,5 +65,3 @@ strtonum(const char *numstr, long long minval, long long maxval,
return (ll);
}
-
-#endif /* !HAVE_STRTONUM */
diff --git a/compat_vasprintf.c b/compat_vasprintf.c
index 9040822b0097..11556c0155b8 100644
--- a/compat_vasprintf.c
+++ b/compat_vasprintf.c
@@ -1,12 +1,4 @@
-#include "config.h"
-
-#if HAVE_VASPRINTF
-
-int dummy;
-
-#else
-
-/* $Id: compat_vasprintf.c,v 1.3 2015/10/06 18:32:19 schwarze Exp $ */
+/* $Id: compat_vasprintf.c,v 1.4 2020/06/15 01:37:15 schwarze Exp $ */
/*
* Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -28,6 +20,7 @@ int dummy;
* printf(3) or completely reimplementing printf(3), i can't think
* of another portable solution.
*/
+#include "config.h"
#include <stdarg.h>
#include <stdio.h>
@@ -52,5 +45,3 @@ vasprintf(char **ret, const char *format, va_list ap)
*ret = NULL;
return -1;
}
-
-#endif
diff --git a/configure b/configure
index 2df028da0510..5cf4e081c2cb 100755
--- a/configure
+++ b/configure
@@ -1,8 +1,8 @@
#!/bin/sh
#
-# $Id: configure,v 1.71 2019/07/01 22:56:24 schwarze Exp $
+# $Id: configure,v 1.81 2021/09/20 10:19:51 schwarze Exp $
#
-# Copyright (c) 2014-2019 Ingo Schwarze <schwarze@openbsd.org>
+# Copyright (c) 2014-2021 Ingo Schwarze <schwarze@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
@@ -33,7 +33,7 @@ echo "file config.log: writing..."
# Initialize all variables here,
# such that nothing can leak in from the environment.
-SOURCEDIR=`dirname "$0"`
+SOURCEDIR=`dirname "${0}"`
MANPATH_BASE="/usr/share/man:/usr/X11R6/man"
MANPATH_DEFAULT="/usr/share/man:/usr/X11R6/man:/usr/local/man"
@@ -41,8 +41,10 @@ OSENUM=
OSNAME=
UTF8_LOCALE=
-CC=`printf "all:\\n\\t@echo \\\$(CC)\\n" | env -i make -sf -`
+AR=ar
+CC=cc
CFLAGS=
+FATAL=0
LDADD=
LDFLAGS=
LD_NANOSLEEP=
@@ -54,8 +56,8 @@ BUILD_CGI=0
BUILD_CATMAN=0
INSTALL_LIBMANDOC=0
+HAVE_ATTRIBUTE=
HAVE_CMSG=
-HAVE_CMSG_XPG42=0
HAVE_DIRENT_NAMLEN=
HAVE_EFTYPE=
HAVE_ENDIAN=
@@ -67,6 +69,7 @@ HAVE_GETSUBOPT=
HAVE_ISBLANK=
HAVE_LESS_T=
HAVE_MKDTEMP=
+HAVE_MKSTEMPS=
HAVE_NANOSLEEP=
HAVE_NTOHL=
HAVE_O_DIRECTORY=
@@ -94,6 +97,10 @@ HAVE_WCHAR=
NEED_GNU_SOURCE=0
NEED_OPENBSD_SOURCE=0
+NEED_XPG4_2=0
+
+MANDOC_COBJS=
+SOELIM_COBJS=
PREFIX="/usr/local"
BINDIR=
@@ -102,7 +109,7 @@ BIN_FROM_SBIN=
INCLUDEDIR=
LIBDIR=
MANDIR=
-HOMEBREWDIR=
+READ_ALLOWED_PATH=
WWWPREFIX="/var/www"
HTDOCDIR=
@@ -114,6 +121,7 @@ BINM_MAKEWHATIS="makewhatis"
BINM_MAN="man"
BINM_SOELIM="soelim"
BINM_WHATIS="whatis"
+BINM_PAGER=
MANM_MAN="man"
MANM_MANCONF="man.conf"
MANM_MDOC="mdoc"
@@ -159,16 +167,17 @@ ismanual() {
# In case of failure, do not decide anything yet.
# Arguments: test file name, test var name, additional CFLAGS
singletest() {
- n=${1}${3}${4}
+ n=${1}${3}
cat 1>&3 << __HEREDOC__
testing ${n} ...
-${COMP} -o test-${1} test-${1}.c ${3} ${4}
+${COMP} -o test-${1} test-${1}.c ${3}
__HEREDOC__
- if ${COMP} -o "test-${1}" "${SOURCEDIR}/test-${1}.c" ${3} ${4} 1>&3 2>&3
+ if ${COMP} -o "test-${1}" "${SOURCEDIR}/test-${1}.c" ${3} 1>&3 2>&3
then
echo "partial result of ${n}: ${CC} succeeded" 1>&3
else
+ echo "tested ${n}: no (compilation failed)" 1>&2
echo "result of ${n}: ${CC} failed with exit status $?" 1>&3
echo "result of compiling ${n}: no" 1>&3
echo 1>&3
@@ -180,11 +189,16 @@ __HEREDOC__
echo "result of running ${n}: yes" 1>&3
echo 1>&3
eval HAVE_${2}=1
- [ "X$3" = "X-D_GNU_SOURCE" ] && NEED_GNU_SOURCE=1
- [ "X$3" = "X-D_OPENBSD_SOURCE" ] && NEED_OPENBSD_SOURCE=1
+ [ "${3}" = "-D_GNU_SOURCE" ] && NEED_GNU_SOURCE=1
+ [ "${3}" = "-D_OPENBSD_SOURCE" ] && NEED_OPENBSD_SOURCE=1
+ [ "${3}" = "-D_XPG4_2" ] && NEED_XPG4_2=1
+ [ "${3}" = "-lrt" ] && LD_NANOSLEEP="-lrt"
+ [ "${3}" = "-lsocket" ] && LD_RECVMSG="-lsocket"
+ [ "${3}" = "-lutil" ] && LD_OHASH="-lutil"
rm "test-${1}"
return 0
else
+ echo "tested ${n}: no (execution failed)" 1>&2
echo "result of ${n}: execution failed with exit status $?" 1>&3
echo "result of running ${n}: no" 1>&3
echo 1>&3
@@ -196,11 +210,12 @@ __HEREDOC__
# Run a complete autoconfiguration test, including the check for
# a manual override and disabling the feature on failure.
# Arguments: test file name, test var name, additional CFLAGS
+# The final argument can optionally be repeated a second time.
runtest() {
eval _manual=\${HAVE_${2}}
ismanual "${1}" "${2}" "${_manual}" && return 0
- singletest "${1}" "${2}" "${3}" "${4}" && return 0
- echo "tested ${1}${3}${4}: no" 1>&2
+ singletest "${1}" "${2}" "${3}" && return 0
+ [ -n "${4}" ] && singletest "${1}" "${2}" "${4}" && return 0
eval HAVE_${2}=0
return 1
}
@@ -208,7 +223,7 @@ runtest() {
# Select a UTF-8 locale.
get_locale() {
[ -n "${HAVE_WCHAR}" ] && [ "${HAVE_WCHAR}" -eq 0 ] && return 0
- ismanual UTF8_LOCALE UTF8_LOCALE "$UTF8_LOCALE" && return 0
+ ismanual UTF8_LOCALE UTF8_LOCALE "${UTF8_LOCALE}" && return 0
echo "testing UTF8_LOCALE ..." 1>&3
UTF8_LOCALE=`locale -a | grep -i '^en_US\.UTF-*8$' | head -n 1`
if [ -z "${UTF8_LOCALE}" ]; then
@@ -228,9 +243,9 @@ if [ -n "${OSENUM}" ]; then
echo "OSENUM specified manually: ${OSENUM}" 1>&3
else
OSDETECT=`uname`
- if [ "X${OSDETECT}" = "XNetBSD" ]; then
+ if [ "${OSDETECT}" = "NetBSD" ]; then
OSENUM=MANDOC_OS_NETBSD
- elif [ "X${OSDETECT}" = "XOpenBSD" ]; then
+ elif [ "${OSDETECT}" = "OpenBSD" ]; then
OSENUM=MANDOC_OS_OPENBSD
else
OSENUM=MANDOC_OS_OTHER
@@ -250,8 +265,8 @@ if [ -n "${CFLAGS}" ]; then
else
COMP="${CC} ${DEFCFLAGS} -Wno-unused -Werror"
fi
-echo -n "tested ${CC} -W: " 1>&2
-echo -n "testing ${CC} -W: " 1>&3
+printf "%s" "tested ${CC} -W: " 1>&2
+printf "%s" "testing ${CC} -W: " 1>&3
runtest noop WFLAG || true
if [ -n "${CFLAGS}" ]; then
@@ -283,51 +298,48 @@ fi
# --- tests for config.h ----------------------------------------------
# --- library functions ---
+runtest attribute ATTRIBUTE || true
+runtest cmsg CMSG "" "-D_XPG4_2" || true
runtest dirent-namlen DIRENT_NAMLEN || true
runtest be32toh ENDIAN || true
runtest be32toh SYS_ENDIAN -DSYS_ENDIAN || true
runtest EFTYPE EFTYPE || true
runtest err ERR || true
runtest getline GETLINE || true
-singletest getsubopt GETSUBOPT || \
- runtest getsubopt GETSUBOPT -D_GNU_SOURCE || true
+runtest getsubopt GETSUBOPT "" -D_GNU_SOURCE || true
runtest isblank ISBLANK || true
runtest mkdtemp MKDTEMP || true
+runtest mkstemps MKSTEMPS || true
+runtest nanosleep NANOSLEEP "${LD_NANOSLEEP}" "-lrt" || 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
runtest progname PROGNAME || true
-singletest reallocarray REALLOCARRAY || \
- runtest reallocarray REALLOCARRAY -D_OPENBSD_SOURCE || true
-singletest recallocarray RECALLOCARRAY || \
- runtest recallocarray RECALLOCARRAY -D_OPENBSD_SOURCE || true
+runtest reallocarray REALLOCARRAY "" -D_OPENBSD_SOURCE || true
+runtest recallocarray RECALLOCARRAY "" -D_OPENBSD_SOURCE || true
+runtest recvmsg RECVMSG "${LD_RECVMSG}" "-lsocket" || true
runtest rewb-bsd REWB_BSD || true
runtest rewb-sysv REWB_SYSV || true
-singletest strcasestr STRCASESTR || \
- runtest strcasestr STRCASESTR -D_GNU_SOURCE || true
+runtest strcasestr STRCASESTR "" -D_GNU_SOURCE || true
runtest stringlist STRINGLIST || true
runtest strlcat STRLCAT || true
runtest strlcpy STRLCPY || true
runtest strndup STRNDUP || true
-singletest strptime STRPTIME || \
- runtest strptime STRPTIME -D_GNU_SOURCE || true
+runtest strptime STRPTIME "" -D_GNU_SOURCE || true
runtest strsep STRSEP || true
-singletest strtonum STRTONUM || \
- runtest strtonum STRTONUM -D_OPENBSD_SOURCE || true
-singletest vasprintf VASPRINTF || \
- runtest vasprintf VASPRINTF -D_GNU_SOURCE || true
-
-if [ ${HAVE_ENDIAN} -eq 0 -a \
- ${HAVE_SYS_ENDIAN} -eq 0 -a \
- ${HAVE_NTOHL} -eq 0 ]; then
- echo "FATAL: no endian conversion functions found" 1>&2
- echo "FATAL: no endian conversion functions found" 1>&3
- exit 1
-fi
+runtest strtonum STRTONUM "" -D_OPENBSD_SOURCE || true
+runtest vasprintf VASPRINTF "" -D_GNU_SOURCE || true
-if ismanual fts FTS ${HAVE_FTS}; then
+# --- fts ---
+if [ "${1}" = "-depend" ]; then
+ HAVE_FTS=0
+ HAVE_FTS_COMPARE_CONST=0
+ echo "tested fts: HAVE_FTS=0 (for make depend)" 1>&2
+ echo "tested fts: HAVE_FTS=0 (for make depend)" 1>&3
+ echo 1>&3
+elif ismanual fts FTS ${HAVE_FTS}; then
HAVE_FTS_COMPARE_CONST=0
elif runtest fts FTS_COMPARE_CONST -DFTS_COMPARE_CONST; then
HAVE_FTS=1
@@ -335,25 +347,41 @@ else
runtest fts FTS || true
fi
-if ismanual "less -T" LESS_T ${HAVE_LESS_T}; then
+# --- pager ---
+manual=
+if [ -n "${BINM_PAGER}" ]; then
+ manual=" (manual)"
+elif less test-noop.c 1>/dev/null 2>&3; then
+ BINM_PAGER=less
+ echo "tested less: yes" 1>&2
+ echo "tested less: yes" 1>&3
+else
+ BINM_PAGER=more
+ echo "tested less: no" 1>&2
+ echo "tested less: no" 1>&3
+fi
+echo "selected BINM_PAGER=${BINM_PAGER}${manual}" 1>&2
+echo "selected BINM_PAGER=${BINM_PAGER}${manual}" 1>&3
+
+# --- tagging support in the pager ---
+if ismanual "${BINM_PAGER} -T" LESS_T ${HAVE_LESS_T}; then
:
-elif less -ET /dev/null test-noop.c 1>/dev/null 2>&3; then
+elif ${BINM_PAGER} -T /dev/null test-noop.c 1>/dev/null 2>&3; then
HAVE_LESS_T=1
- echo "tested less -T: yes" 1>&2
- echo "tested less -T: yes" 1>&3
+ echo "tested ${BINM_PAGER} -T: yes" 1>&2
+ echo "tested ${BINM_PAGER} -T: yes" 1>&3
echo 1>&3
else
HAVE_LESS_T=0
- echo "tested less -T: no" 1>&2
- echo "tested less -T: no" 1>&3
+ echo "tested ${BINM_PAGER} -T: no" 1>&2
+ echo "tested ${BINM_PAGER} -T: no" 1>&3
echo 1>&3
fi
# --- wide character and locale support ---
if get_locale; then
- singletest wchar WCHAR -DUTF8_LOCALE=\"${UTF8_LOCALE}\" || \
- runtest wchar WCHAR -D_GNU_SOURCE \
- -DUTF8_LOCALE=\"${UTF8_LOCALE}\" || true
+ runtest wchar WCHAR "-DUTF8_LOCALE=\"${UTF8_LOCALE}\"" \
+ "-D_GNU_SOURCE -DUTF8_LOCALE=\"${UTF8_LOCALE}\"" || true
else
HAVE_WCHAR=0
echo "tested wchar: no (no UTF8_LOCALE)" 1>&2
@@ -361,63 +389,45 @@ else
echo 1>&3
fi
-# --- nanosleep ---
-if [ -n "${LD_NANOSLEEP}" ]; then
- runtest nanosleep NANOSLEEP "${LD_NANOSLEEP}" || true
-elif singletest nanosleep NANOSLEEP; then
- :
-elif runtest nanosleep NANOSLEEP "-lrt"; then
- LD_NANOSLEEP="-lrt"
+# --- ohash ---
+if [ "${1}" = "-depend" ]; then
+ HAVE_OHASH=0
+ echo "tested ohash: HAVE_OHASH=0 (for make depend)" 1>&2
+ echo "tested ohash: HAVE_OHASH=0 (for make depend)" 1>&3
+ echo 1>&3
+else
+ runtest ohash OHASH "${LD_OHASH}" "-lutil" || true
+fi
+if [ "${HAVE_OHASH}" -eq 0 ]; then
+ LD_OHASH=
+fi
+
+# --- required functions ---
+if [ ${HAVE_ENDIAN} -eq 0 -a \
+ ${HAVE_SYS_ENDIAN} -eq 0 -a \
+ ${HAVE_NTOHL} -eq 0 ]; then
+ echo "FATAL: no endian conversion functions found" 1>&2
+ echo "FATAL: no endian conversion functions found" 1>&3
+ FATAL=1
fi
if [ "${HAVE_NANOSLEEP}" -eq 0 ]; then
echo "FATAL: nanosleep: no" 1>&2
echo "FATAL: nanosleep: no" 1>&3
- exit 1
+ FATAL=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
- :
-elif [ -n "${LD_OHASH}" ]; then
- runtest ohash OHASH "${LD_OHASH}" || true
-elif singletest ohash OHASH; then
- :
-elif runtest ohash OHASH "-lutil"; then
- LD_OHASH="-lutil"
+if [ ${BUILD_CATMAN} -gt 0 -a "${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
+ FATAL=1
fi
-if [ "${HAVE_OHASH}" -eq 0 ]; then
- LD_OHASH=
+if [ ${BUILD_CATMAN} -gt 0 -a "${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
+ FATAL=1
fi
+[ "${FATAL}" -eq 0 ] || exit 1
# --- LDADD ---
LDADD="${LDADD} ${LD_NANOSLEEP} ${LD_RECVMSG} ${LD_OHASH} -lz"
@@ -434,10 +444,6 @@ cat << __HEREDOC__
#error "Do not use C++. See the INSTALL file."
#endif
-#if !defined(__GNUC__) || (__GNUC__ < 4)
-#define __attribute__(x)
-#endif
-
__HEREDOC__
[ ${NEED_GNU_SOURCE} -eq 0 ] || echo "#define _GNU_SOURCE"
@@ -458,7 +464,9 @@ echo "#define MANPATH_DEFAULT \"${MANPATH_DEFAULT}\""
echo "#define OSENUM ${OSENUM}"
[ -n "${OSNAME}" ] && echo "#define OSNAME \"${OSNAME}\""
[ -n "${UTF8_LOCALE}" ] && echo "#define UTF8_LOCALE \"${UTF8_LOCALE}\""
-[ -n "${HOMEBREWDIR}" ] && echo "#define HOMEBREWDIR \"${HOMEBREWDIR}\""
+[ -n "${READ_ALLOWED_PATH}" ] \
+ && echo "#define READ_ALLOWED_PATH \"${READ_ALLOWED_PATH}\""
+[ ${HAVE_ATTRIBUTE} -eq 0 ] && echo "#define __attribute__(x)"
[ ${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"
@@ -466,9 +474,8 @@ if [ ${HAVE_ENDIAN} -eq 0 -a ${HAVE_SYS_ENDIAN} -eq 0 ]; then
echo "#define be32toh ntohl"
echo "#define htobe32 htonl"
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}
@@ -479,6 +486,7 @@ cat << __HEREDOC__
#define HAVE_ISBLANK ${HAVE_ISBLANK}
#define HAVE_LESS_T ${HAVE_LESS_T}
#define HAVE_MKDTEMP ${HAVE_MKDTEMP}
+#define HAVE_MKSTEMPS ${HAVE_MKSTEMPS}
#define HAVE_NTOHL ${HAVE_NTOHL}
#define HAVE_PLEDGE ${HAVE_PLEDGE}
#define HAVE_PROGNAME ${HAVE_PROGNAME}
@@ -499,6 +507,7 @@ cat << __HEREDOC__
#define HAVE_VASPRINTF ${HAVE_VASPRINTF}
#define HAVE_WCHAR ${HAVE_WCHAR}
#define HAVE_OHASH ${HAVE_OHASH}
+#define NEED_XPG4_2 ${NEED_XPG4_2}
#define BINM_APROPOS "${BINM_APROPOS}"
#define BINM_CATMAN "${BINM_CATMAN}"
@@ -506,6 +515,7 @@ cat << __HEREDOC__
#define BINM_MAN "${BINM_MAN}"
#define BINM_SOELIM "${BINM_SOELIM}"
#define BINM_WHATIS "${BINM_WHATIS}"
+#define BINM_PAGER "${BINM_PAGER}"
__HEREDOC__
@@ -514,52 +524,82 @@ if [ ${HAVE_ERR} -eq 0 ]; then
echo "extern void errx(int, const char *, ...);"
echo "extern void warn(const char *, ...);"
echo "extern void warnx(const char *, ...);"
+ MANDOC_COBJS="${MANDOC_COBJS} compat_err.o"
+ SOELIM_COBJS="${SOELIM_COBJS} compat_err.o"
fi
-
-[ ${HAVE_GETLINE} -eq 0 ] && \
+if [ ${HAVE_FTS} -eq 0 ]; then
+ MANDOC_COBJS="${MANDOC_COBJS} compat_fts.o"
+fi
+if [ ${HAVE_GETLINE} -eq 0 ]; then
echo "extern ssize_t getline(char **, size_t *, FILE *);"
-
-[ ${HAVE_GETSUBOPT} -eq 0 ] && \
+ MANDOC_COBJS="${MANDOC_COBJS} compat_getline.o"
+ SOELIM_COBJS="${SOELIM_COBJS} compat_getline.o"
+fi
+if [ ${HAVE_GETSUBOPT} -eq 0 ]; then
echo "extern int getsubopt(char **, char * const *, char **);"
-
-[ ${HAVE_ISBLANK} -eq 0 ] && \
+ MANDOC_COBJS="${MANDOC_COBJS} compat_getsubopt.o"
+fi
+if [ ${HAVE_ISBLANK} -eq 0 ]; then
echo "extern int isblank(int);"
-
-[ ${HAVE_MKDTEMP} -eq 0 ] && \
+ MANDOC_COBJS="${MANDOC_COBJS} compat_isblank.o"
+fi
+if [ ${HAVE_MKDTEMP} -eq 0 ]; then
echo "extern char *mkdtemp(char *);"
-
+ MANDOC_COBJS="${MANDOC_COBJS} compat_mkdtemp.o"
+fi
+if [ ${HAVE_MKSTEMPS} -eq 0 ]; then
+ echo "extern int mkstemps(char *, int);"
+ MANDOC_COBJS="${MANDOC_COBJS} compat_mkstemps.o"
+fi
+if [ ${HAVE_OHASH} -eq 0 ]; then
+ MANDOC_COBJS="${MANDOC_COBJS} compat_ohash.o"
+fi
if [ ${HAVE_PROGNAME} -eq 0 ]; then
echo "extern const char *getprogname(void);"
echo "extern void setprogname(const char *);"
+ MANDOC_COBJS="${MANDOC_COBJS} compat_progname.o"
+ SOELIM_COBJS="${SOELIM_COBJS} compat_progname.o"
fi
-
-[ ${HAVE_REALLOCARRAY} -eq 0 ] && \
+if [ ${HAVE_REALLOCARRAY} -eq 0 ]; then
echo "extern void *reallocarray(void *, size_t, size_t);"
-
-[ ${HAVE_RECALLOCARRAY} -eq 0 ] && \
+ MANDOC_COBJS="${MANDOC_COBJS} compat_reallocarray.o"
+ SOELIM_COBJS="${SOELIM_COBJS} compat_reallocarray.o"
+fi
+if [ ${HAVE_RECALLOCARRAY} -eq 0 ]; then
echo "extern void *recallocarray(void *, size_t, size_t, size_t);"
-
-[ ${HAVE_STRCASESTR} -eq 0 ] && \
+ MANDOC_COBJS="${MANDOC_COBJS} compat_recallocarray.o"
+fi
+if [ ${HAVE_STRCASESTR} -eq 0 ]; then
echo "extern char *strcasestr(const char *, const char *);"
-
-[ ${HAVE_STRLCAT} -eq 0 ] && \
+ MANDOC_COBJS="${MANDOC_COBJS} compat_strcasestr.o"
+fi
+if [ ${HAVE_STRINGLIST} -eq 0 ]; then
+ SOELIM_COBJS="${SOELIM_COBJS} compat_stringlist.o"
+fi
+if [ ${HAVE_STRLCAT} -eq 0 ]; then
echo "extern size_t strlcat(char *, const char *, size_t);"
-
-[ ${HAVE_STRLCPY} -eq 0 ] && \
+ MANDOC_COBJS="${MANDOC_COBJS} compat_strlcat.o"
+fi
+if [ ${HAVE_STRLCPY} -eq 0 ]; then
echo "extern size_t strlcpy(char *, const char *, size_t);"
-
-[ ${HAVE_STRNDUP} -eq 0 ] && \
+ MANDOC_COBJS="${MANDOC_COBJS} compat_strlcpy.o"
+fi
+if [ ${HAVE_STRNDUP} -eq 0 ]; then
echo "extern char *strndup(const char *, size_t);"
-
-[ ${HAVE_STRSEP} -eq 0 ] && \
+ MANDOC_COBJS="${MANDOC_COBJS} compat_strndup.o"
+fi
+if [ ${HAVE_STRSEP} -eq 0 ]; then
echo "extern char *strsep(char **, const char *);"
-
-[ ${HAVE_STRTONUM} -eq 0 ] && \
+ MANDOC_COBJS="${MANDOC_COBJS} compat_strsep.o"
+fi
+if [ ${HAVE_STRTONUM} -eq 0 ]; then
echo "extern long long strtonum(const char *, long long, long long, const char **);"
-
-[ ${HAVE_VASPRINTF} -eq 0 ] && \
+ MANDOC_COBJS="${MANDOC_COBJS} compat_strtonum.o"
+fi
+if [ ${HAVE_VASPRINTF} -eq 0 ]; then
echo "extern int vasprintf(char **, const char *, va_list);"
-
+ MANDOC_COBJS="${MANDOC_COBJS} compat_vasprintf.o"
+fi
echo "file config.h: written" 1>&2
echo "file config.h: written" 1>&3
@@ -595,10 +635,13 @@ INSTALL_TARGETS=
cat << __HEREDOC__
BUILD_TARGETS = ${BUILD_TARGETS}
INSTALL_TARGETS = ${INSTALL_TARGETS}
+AR = ${AR}
CC = ${CC}
CFLAGS = ${CFLAGS}
LDADD = ${LDADD}
LDFLAGS = ${LDFLAGS}
+MANDOC_COBJS = ${MANDOC_COBJS}
+SOELIM_COBJS = ${SOELIM_COBJS}
STATIC = ${STATIC}
PREFIX = ${PREFIX}
BINDIR = ${BINDIR}
diff --git a/configure.local.example b/configure.local.example
index 4a456aade7c3..1050f4a1d9ab 100644
--- a/configure.local.example
+++ b/configure.local.example
@@ -1,6 +1,6 @@
-# $Id: configure.local.example,v 1.36 2019/03/06 10:18:58 schwarze Exp $
+# $Id: configure.local.example,v 1.43 2021/09/20 13:25:42 schwarze Exp $
#
-# Copyright (c) 2014-2019 Ingo Schwarze <schwarze@openbsd.org>
+# Copyright (c) 2014-2021 Ingo Schwarze <schwarze@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
@@ -28,6 +28,19 @@
# --- user settings relevant for all builds ----------------------------
+# By default, "cc" is used as the C compiler, but it can be overridden.
+# For example, the system compiler in SunOS 5.9 may not provide <stdint.h>,
+# which may require this line:
+CC=gcc
+
+# IBM AIX may need:
+CC=xlc
+
+# By default, "ar" is used as the library archive builder, but it
+# can be overridden. For example, NixOS may not have ar(1) in the
+# PATH, but may want to specify an absolute path instead.
+AR=ar
+
# For -Tutf8 and -Tlocale operation, mandoc(1) requires <locale.h>
# providing setlocale(3) and <wchar.h> providing wcwidth(3) and
# putwchar(3) with a wchar_t storing UCS-4 values. Theoretically,
@@ -88,7 +101,7 @@ OSENUM=MANDOC_OS_OTHER
# If you do not want uname(3) to be called but instead want a fixed
# string to be used, use the following line:
-OSNAME="OpenBSD 6.5"
+OSNAME="OpenBSD 7.0"
# The following installation directories are used.
# It is possible to set only one or a few of these variables,
@@ -143,6 +156,14 @@ BINM_WHATIS=mwhatis # default is "whatis"
BINM_MAKEWHATIS=mandocdb # default is "makewhatis"
BINM_SOELIM=msoelim # default is "soelim"
+# If less(1) is available, it is used as the default manual pager.
+# Otherwise, more(1) is used: its existence is required by POSIX.
+# It is possible to force using a different default pager, either
+# by giving the name of a program found in the PATH, or by giving
+# an absolute path.
+
+BINM_PAGER=pg # default is "less" or "more"
+
# Some distributions do not want hardlinks
# between installed binary programs.
# Set the following variable to use symbolic links instead.
@@ -193,14 +214,28 @@ INSTALL_LIB="${INSTALL} -m 0444"
INSTALL_MAN="${INSTALL} -m 0444"
INSTALL_DATA="${INSTALL} -m 0444"
-# When using the "homebrew" package manager on Mac OS X, the actual
-# manuals are located in a so-called "cellar" and only symlinked
-# into the manual trees. To allow mandoc to follow such symlinks,
-# you have to specify the physical location of the cellar as returned
-# by realpath(3), for example:
+# By default, makewhatis(8) can only read from the paths passed on the
+# command line or configured in man.conf(5).
+# But some package managers on some operating systems store manual pages
+# in separate "cellar" or "store" directories and only symlink them
+# into the manual trees.
+# To support one or more such package managers, give makewhatis(8)
+# read access to the cellars and stores on your system, in the form
+# of a colon-separated path:
+# Homebrow package manager on Mac OS X:
PREFIX="/usr/local"
-HOMEBREWDIR="${PREFIX}/Cellar"
+READ_ALLOWED_PATH="${PREFIX}/Cellar"
+
+# Nix package manager and/or NixOS Linux distribution:
+READ_ALLOWED_PATH="/nix/store"
+
+# GNU Guix package manager and/or GNU Guix Linux distribution:
+READ_ALLOWED_PATH="/gnu/store"
+
+# If multiple package managers are used concurrently:
+PREFIX="/usr/local"
+READ_ALLOWED_PATH="/nix/store:${PREFIX}/Cellar"
# --- user settings for the mandoc(3) library --------------------------
@@ -256,6 +291,8 @@ CGIBINDIR="${WWWPREFIX}/cgi-bin"
# 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).
+# It may not work on old releases of Mac OS X either. For example,
+# Mac OS X 10.4 Tiger provides neither mkdirat(2) nor openat(2).
BUILD_CATMAN=1
@@ -268,21 +305,6 @@ BINM_CATMAN=mcatman # default is "catman"
# Do not set these variables unless you really need to.
-# You can manually override the compiler to be used.
-# But that's rarely useful because ./configure asks your make(1)
-# which compiler to use, and that answer will hardly be wrong.
-
-CC=cc
-
-# Because the system compiler may not provide <stdint.h>,
-# SunOS 5.9 may need:
-
-CC=gcc
-
-# IBM AIX may need:
-
-CC=xlc
-
# Normally, leave CFLAGS unset. In that case, -g will automatically
# be used, and various -W options will be added if the compiler
# supports them. If you define CFLAGS manually, it will be used
@@ -295,6 +317,7 @@ CFLAGS="-g"
# and will be regarded as failed) or 1 (test will not be run and will
# be regarded as successful).
+HAVE_ATTRIBUTE=0
HAVE_DIRENT_NAMLEN=0
HAVE_ENDIAN=0
HAVE_EFTYPE=0
diff --git a/dba_array.c b/dba_array.c
index 18c9f09f1a21..aaf02baa7c39 100644
--- a/dba_array.c
+++ b/dba_array.c
@@ -1,4 +1,4 @@
-/* $Id: dba_array.c,v 1.1 2016/07/19 21:31:55 schwarze Exp $ */
+/* $Id: dba_array.c,v 1.2 2020/06/22 19:20:40 schwarze Exp $ */
/*
* Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -17,6 +17,8 @@
* Allocation-based arrays for the mandoc database, for read-write access.
* The interface is defined in "dba_array.h".
*/
+#include "config.h"
+
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
diff --git a/dba_read.c b/dba_read.c
index e976057064ab..4fc3ee5eddcb 100644
--- a/dba_read.c
+++ b/dba_read.c
@@ -1,4 +1,4 @@
-/* $Id: dba_read.c,v 1.4 2016/08/17 20:46:56 schwarze Exp $ */
+/* $Id: dba_read.c,v 1.5 2020/06/22 19:20:40 schwarze Exp $ */
/*
* Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -19,6 +19,8 @@
* The interface is defined in "dba.h".
* This file is seperate from dba.c because this also uses "dbm.h".
*/
+#include "config.h"
+
#include <regex.h>
#include <stdint.h>
#include <stdlib.h>
diff --git a/eqn.7 b/eqn.7
index c9fe483b1719..e164e8fb651c 100644
--- a/eqn.7
+++ b/eqn.7
@@ -1,4 +1,4 @@
-.\" $Id: eqn.7,v 1.38 2019/04/23 17:57:49 schwarze Exp $
+.\" $Id: eqn.7,v 1.39 2020/01/10 11:55:04 schwarze Exp $
.\"
.\" Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
@@ -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 23 2019 $
+.Dd $Mdocdate: January 10 2020 $
.Dt EQN 7
.Os
.Sh NAME
@@ -44,28 +44,16 @@ specification (see
.Sx SEE ALSO
for references).
.Pp
-Equations within
-.Xr mdoc 7
-or
-.Xr man 7
-documents are enclosed by the standalone
-.Sq \&.EQ
-and
-.Sq \&.EN
-tags.
-Equations are multi-line blocks consisting of formulas and control
-statements.
-.Sh EQUATION STRUCTURE
-Each equation is bracketed by
-.Sq \&.EQ
-and
-.Sq \&.EN
-strings.
-.Em Note :
-these are not the same as
-.Xr roff 7
-macros, and may only be invoked as
-.Sq \&.EQ .
+An equation starts with an input line containing exactly the characters
+.Sq \&.EQ ,
+may contain multiple input lines, and ends with an input line
+containing exactly the characters
+.Sq \&.EN .
+Equivalently, an equation can be given in the middle of a single
+text input line by surrounding it with the equation delimiters
+defined with the
+.Cm delim
+statement.
.Pp
The equation grammar is as follows, where quoted strings are
case-sensitive literals in the input:
@@ -178,6 +166,25 @@ statement is a synonym for
while
.Cm tdefine
is discarded.
+.It Cm delim
+This statement takes a string argument consisting of two bytes,
+to be used as the opening and closing delimiters for equations
+in the middle of text input lines.
+Conventionally, the dollar sign is used for both delimiters,
+as follows:
+.Bd -literal -offset indent
+\&.EQ
+delim $$
+\&.EN
+An equation like $sin pi = 0$ can now be entered
+in the middle of a text input line.
+.Ed
+.Pp
+The special statement
+.Cm delim off
+temporarily disables previously declared delimiters and
+.Cm delim on
+reenables them.
.It Cm gfont
Set the default font of subsequent output.
Its syntax is as follows:
diff --git a/eqn.c b/eqn.c
index 3d63382ab31b..27f5cac396cb 100644
--- a/eqn.c
+++ b/eqn.c
@@ -1,7 +1,7 @@
-/* $Id: eqn.c,v 1.83 2018/12/14 06:33:14 schwarze Exp $ */
+/* $Id: eqn.c,v 1.84 2020/01/08 12:16:24 schwarze Exp $ */
/*
* Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014,2015,2017,2018,2020 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -399,6 +399,14 @@ eqn_next(struct eqn_node *ep, enum parse_mode mode)
case '"':
quoted = 1;
break;
+ case ' ':
+ case '\t':
+ case '~':
+ case '^':
+ if (quoted)
+ break;
+ ep->start++;
+ continue;
default:
break;
}
@@ -669,7 +677,7 @@ eqn_parse(struct eqn_node *ep)
if (ep->data == NULL)
return;
- ep->start = ep->end = ep->data + strspn(ep->data, " ^~");
+ ep->start = ep->end = ep->data;
next_tok:
tok = eqn_next(ep, MODE_TOK);
diff --git a/html.c b/html.c
index 9c45d3162eaf..71c9c711e825 100644
--- a/html.c
+++ b/html.c
@@ -1,7 +1,7 @@
-/* $Id: html.c,v 1.255 2019/04/30 15:53:00 schwarze Exp $ */
+/* $Id: html.c,v 1.275 2021/09/09 14:47:24 schwarze Exp $ */
/*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011-2015, 2017-2021 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,6 +14,9 @@
* 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.
+ *
+ * Common functions for mandoc(1) HTML formatters.
+ * For use by individual formatters and by the main program.
*/
#include "config.h"
@@ -42,34 +45,30 @@
struct htmldata {
const char *name;
int flags;
-#define HTML_NOSTACK (1 << 0)
-#define HTML_AUTOCLOSE (1 << 1)
-#define HTML_NLBEFORE (1 << 2)
-#define HTML_NLBEGIN (1 << 3)
-#define HTML_NLEND (1 << 4)
-#define HTML_NLAFTER (1 << 5)
+#define HTML_INPHRASE (1 << 0) /* Can appear in phrasing context. */
+#define HTML_TOPHRASE (1 << 1) /* Establishes phrasing context. */
+#define HTML_NOSTACK (1 << 2) /* Does not have an end tag. */
+#define HTML_NLBEFORE (1 << 3) /* Output line break before opening. */
+#define HTML_NLBEGIN (1 << 4) /* Output line break after opening. */
+#define HTML_NLEND (1 << 5) /* Output line break before closing. */
+#define HTML_NLAFTER (1 << 6) /* Output line break after closing. */
#define HTML_NLAROUND (HTML_NLBEFORE | HTML_NLAFTER)
#define HTML_NLINSIDE (HTML_NLBEGIN | HTML_NLEND)
#define HTML_NLALL (HTML_NLAROUND | HTML_NLINSIDE)
-#define HTML_INDENT (1 << 6)
-#define HTML_NOINDENT (1 << 7)
+#define HTML_INDENT (1 << 7) /* Indent content by two spaces. */
+#define HTML_NOINDENT (1 << 8) /* Exception: never indent content. */
};
static const struct htmldata htmltags[TAG_MAX] = {
{"html", HTML_NLALL},
{"head", HTML_NLALL | HTML_INDENT},
- {"body", HTML_NLALL},
- {"meta", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL},
+ {"meta", HTML_NOSTACK | HTML_NLALL},
+ {"link", HTML_NOSTACK | HTML_NLALL},
+ {"style", HTML_NLALL | HTML_INDENT},
{"title", HTML_NLAROUND},
+ {"body", HTML_NLALL},
{"div", HTML_NLAROUND},
- {"div", 0},
{"section", HTML_NLALL},
- {"h1", HTML_NLAROUND},
- {"h2", HTML_NLAROUND},
- {"span", 0},
- {"link", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL},
- {"br", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL},
- {"a", 0},
{"table", HTML_NLALL | HTML_INDENT},
{"tr", HTML_NLALL | HTML_INDENT},
{"td", HTML_NLAROUND},
@@ -79,16 +78,22 @@ static const struct htmldata htmltags[TAG_MAX] = {
{"dl", HTML_NLALL | HTML_INDENT},
{"dt", HTML_NLAROUND},
{"dd", HTML_NLAROUND | HTML_INDENT},
- {"p", HTML_NLAROUND | HTML_INDENT},
- {"pre", HTML_NLALL | HTML_NOINDENT},
- {"var", 0},
- {"cite", 0},
- {"b", 0},
- {"i", 0},
- {"code", 0},
- {"small", 0},
- {"style", HTML_NLALL | HTML_INDENT},
- {"math", HTML_NLALL | HTML_INDENT},
+ {"h1", HTML_TOPHRASE | HTML_NLAROUND},
+ {"h2", HTML_TOPHRASE | HTML_NLAROUND},
+ {"p", HTML_TOPHRASE | HTML_NLAROUND | HTML_INDENT},
+ {"pre", HTML_TOPHRASE | HTML_NLAROUND | HTML_NOINDENT},
+ {"a", HTML_INPHRASE | HTML_TOPHRASE},
+ {"b", HTML_INPHRASE | HTML_TOPHRASE},
+ {"cite", HTML_INPHRASE | HTML_TOPHRASE},
+ {"code", HTML_INPHRASE | HTML_TOPHRASE},
+ {"i", HTML_INPHRASE | HTML_TOPHRASE},
+ {"small", HTML_INPHRASE | HTML_TOPHRASE},
+ {"span", HTML_INPHRASE | HTML_TOPHRASE},
+ {"var", HTML_INPHRASE | HTML_TOPHRASE},
+ {"br", HTML_INPHRASE | HTML_NOSTACK | HTML_NLALL},
+ {"hr", HTML_INPHRASE | HTML_NOSTACK},
+ {"mark", HTML_INPHRASE },
+ {"math", HTML_INPHRASE | HTML_NLALL | HTML_INDENT},
{"mrow", 0},
{"mi", 0},
{"mn", 0},
@@ -108,6 +113,11 @@ static const struct htmldata htmltags[TAG_MAX] = {
};
/* Avoid duplicate HTML id= attributes. */
+
+struct id_entry {
+ int ord; /* Ordinal number of the latest occurrence. */
+ char id[]; /* The id= attribute without any ordinal suffix. */
+};
static struct ohash id_unique;
static void html_reset_internal(struct html *);
@@ -131,6 +141,7 @@ html_alloc(const struct manoutput *outopts)
h = mandoc_calloc(1, sizeof(struct html));
h->tag = NULL;
+ h->metac = h->metal = ESCAPE_FONTROMAN;
h->style = outopts->style;
if ((h->base_man1 = outopts->man) == NULL)
h->base_man2 = NULL;
@@ -142,7 +153,7 @@ html_alloc(const struct manoutput *outopts)
if (outopts->toc)
h->oflags |= HTML_TOC;
- mandoc_ohash_init(&id_unique, 4, 0);
+ mandoc_ohash_init(&id_unique, 4, offsetof(struct id_entry, id));
return h;
}
@@ -151,17 +162,17 @@ static void
html_reset_internal(struct html *h)
{
struct tag *tag;
- char *cp;
+ struct id_entry *entry;
unsigned int slot;
while ((tag = h->tag) != NULL) {
h->tag = tag->next;
free(tag);
}
- cp = ohash_first(&id_unique, &slot);
- while (cp != NULL) {
- free(cp);
- cp = ohash_next(&id_unique, &slot);
+ entry = ohash_first(&id_unique, &slot);
+ while (entry != NULL) {
+ free(entry);
+ entry = ohash_next(&id_unique, &slot);
}
ohash_delete(&id_unique);
}
@@ -170,7 +181,7 @@ void
html_reset(void *p)
{
html_reset_internal(p);
- mandoc_ohash_init(&id_unique, 4, 0);
+ mandoc_ohash_init(&id_unique, 4, offsetof(struct id_entry, id));
}
void
@@ -186,6 +197,8 @@ print_gen_head(struct html *h)
struct tag *t;
print_otag(h, TAG_META, "?", "charset", "utf-8");
+ print_otag(h, TAG_META, "??", "name", "viewport",
+ "content", "width=device-width, initial-scale=1.0");
if (h->style != NULL) {
print_otag(h, TAG_LINK, "?h??", "rel", "stylesheet",
h->style, "type", "text/css", "media", "all");
@@ -203,23 +216,18 @@ print_gen_head(struct html *h)
print_endline(h);
print_text(h, "td.head-vol { text-align: center; }");
print_endline(h);
- print_text(h, "div.Pp { margin: 1ex 0ex; }");
+ print_text(h, ".Nd, .Bf, .Op { display: inline; }");
print_endline(h);
- print_text(h, "div.Nd, div.Bf, div.Op { display: inline; }");
+ print_text(h, ".Pa, .Ad { font-style: italic; }");
print_endline(h);
- print_text(h, "span.Pa, span.Ad { font-style: italic; }");
+ print_text(h, ".Ms { font-weight: bold; }");
print_endline(h);
- print_text(h, "span.Ms { font-weight: bold; }");
- print_endline(h);
- print_text(h, "dl.Bl-diag ");
+ print_text(h, ".Bl-diag ");
print_byte(h, '>');
print_text(h, " dt { font-weight: bold; }");
print_endline(h);
- print_text(h, "code.Nm, code.Fl, code.Cm, code.Ic, "
- "code.In, code.Fd, code.Fn,");
- print_endline(h);
- print_text(h, "code.Cd { font-weight: bold; "
- "font-family: inherit; }");
+ print_text(h, "code.Nm, .Fl, .Cm, .Ic, code.In, .Fd, .Fn, .Cd "
+ "{ font-weight: bold; font-family: inherit; }");
print_tagq(h, t);
}
@@ -233,8 +241,10 @@ html_setfont(struct html *h, enum mandoc_esc font)
case ESCAPE_FONTITALIC:
case ESCAPE_FONTBOLD:
case ESCAPE_FONTBI:
- case ESCAPE_FONTCW:
case ESCAPE_FONTROMAN:
+ case ESCAPE_FONTCR:
+ case ESCAPE_FONTCB:
+ case ESCAPE_FONTCI:
break;
case ESCAPE_FONT:
font = ESCAPE_FONTROMAN;
@@ -265,9 +275,17 @@ print_metaf(struct html *h)
h->metaf = print_otag(h, TAG_B, "");
print_otag(h, TAG_I, "");
break;
- case ESCAPE_FONTCW:
+ case ESCAPE_FONTCR:
h->metaf = print_otag(h, TAG_SPAN, "c", "Li");
break;
+ case ESCAPE_FONTCB:
+ h->metaf = print_otag(h, TAG_SPAN, "c", "Li");
+ print_otag(h, TAG_B, "");
+ break;
+ case ESCAPE_FONTCI:
+ h->metaf = print_otag(h, TAG_SPAN, "c", "Li");
+ print_otag(h, TAG_I, "");
+ break;
default:
break;
}
@@ -276,21 +294,18 @@ print_metaf(struct html *h)
void
html_close_paragraph(struct html *h)
{
- struct tag *t;
+ struct tag *this, *next;
+ int flags;
- for (t = h->tag; t != NULL && t->closed == 0; t = t->next) {
- switch(t->tag) {
- case TAG_P:
- case TAG_PRE:
- print_tagq(h, t);
+ this = h->tag;
+ for (;;) {
+ next = this->next;
+ flags = htmltags[this->tag].flags;
+ if (flags & (HTML_INPHRASE | HTML_TOPHRASE))
+ print_ctag(h, this);
+ if ((flags & HTML_INPHRASE) == 0)
break;
- case TAG_A:
- print_tagq(h, t);
- continue;
- default:
- continue;
- }
- break;
+ this = next;
}
}
@@ -328,33 +343,66 @@ html_fillmode(struct html *h, enum roff_tok want)
return had;
}
+/*
+ * Allocate a string to be used for the "id=" attribute of an HTML
+ * element and/or as a segment identifier for a URI in an <a> element.
+ * The function may fail and return NULL if the node lacks text data
+ * to create the attribute from.
+ * The caller is responsible for free(3)ing the returned string.
+ *
+ * If the "unique" argument is non-zero, the "id_unique" ohash table
+ * is used for de-duplication. If the "unique" argument is 1,
+ * it is the first time the function is called for this tag and
+ * location, so if an ordinal suffix is needed, it is incremented.
+ * If the "unique" argument is 2, it is the second time the function
+ * is called for this tag and location, so the ordinal suffix
+ * remains unchanged.
+ */
char *
html_make_id(const struct roff_node *n, int unique)
{
const struct roff_node *nch;
- char *buf, *bufs, *cp;
+ struct id_entry *entry;
+ char *buf, *cp;
+ size_t len;
unsigned int slot;
- int suffix;
- for (nch = n->child; nch != NULL; nch = nch->next)
- if (nch->type != ROFFT_TEXT)
- return NULL;
-
- buf = NULL;
- deroff(&buf, n);
- if (buf == NULL)
- return NULL;
+ if (n->tag != NULL)
+ buf = mandoc_strdup(n->tag);
+ else {
+ switch (n->tok) {
+ case MDOC_Sh:
+ case MDOC_Ss:
+ case MDOC_Sx:
+ case MAN_SH:
+ case MAN_SS:
+ for (nch = n->child; nch != NULL; nch = nch->next)
+ if (nch->type != ROFFT_TEXT)
+ return NULL;
+ buf = NULL;
+ deroff(&buf, n);
+ if (buf == NULL)
+ return NULL;
+ break;
+ default:
+ if (n->child == NULL || n->child->type != ROFFT_TEXT)
+ return NULL;
+ buf = mandoc_strdup(n->child->string);
+ break;
+ }
+ }
/*
* In ID attributes, only use ASCII characters that are
* permitted in URL-fragment strings according to the
* explicit list at:
* https://url.spec.whatwg.org/#url-fragment-string
+ * In addition, reserve '~' for ordinal suffixes.
*/
for (cp = buf; *cp != '\0'; cp++)
if (isalnum((unsigned char)*cp) == 0 &&
- strchr("!$&'()*+,-./:;=?@_~", *cp) == NULL)
+ strchr("!$&'()*+,-./:;=?@_", *cp) == NULL)
*cp = '_';
if (unique == 0)
@@ -362,25 +410,21 @@ html_make_id(const struct roff_node *n, int unique)
/* Avoid duplicate HTML id= attributes. */
- bufs = NULL;
- suffix = 1;
slot = ohash_qlookup(&id_unique, buf);
- cp = ohash_find(&id_unique, slot);
- if (cp != NULL) {
- while (cp != NULL) {
- free(bufs);
- if (++suffix > 127) {
- free(buf);
- return NULL;
- }
- mandoc_asprintf(&bufs, "%s_%d", buf, suffix);
- slot = ohash_qlookup(&id_unique, bufs);
- cp = ohash_find(&id_unique, slot);
- }
- free(buf);
- buf = bufs;
+ if ((entry = ohash_find(&id_unique, slot)) == NULL) {
+ len = strlen(buf) + 1;
+ entry = mandoc_malloc(sizeof(*entry) + len);
+ entry->ord = 1;
+ memcpy(entry->id, buf, len);
+ ohash_insert(&id_unique, slot, entry);
+ } else if (unique == 1)
+ entry->ord++;
+
+ if (entry->ord > 1) {
+ cp = buf;
+ mandoc_asprintf(&buf, "%s~%d", cp, entry->ord);
+ free(cp);
}
- ohash_insert(&id_unique, slot, buf);
return buf;
}
@@ -470,8 +514,10 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse)
case ESCAPE_FONTBOLD:
case ESCAPE_FONTITALIC:
case ESCAPE_FONTBI:
- case ESCAPE_FONTCW:
case ESCAPE_FONTROMAN:
+ case ESCAPE_FONTCR:
+ case ESCAPE_FONTCB:
+ case ESCAPE_FONTCI:
if (0 == norecurse) {
h->flags |= HTML_NOSPACE;
if (html_setfont(h, esc))
@@ -589,6 +635,25 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
tflags = htmltags[tag].flags;
+ /* Flow content is not allowed in phrasing context. */
+
+ if ((tflags & HTML_INPHRASE) == 0) {
+ for (t = h->tag; t != NULL; t = t->next) {
+ if (t->closed)
+ continue;
+ assert((htmltags[t->tag].flags & HTML_TOPHRASE) == 0);
+ break;
+ }
+
+ /*
+ * Always wrap phrasing elements in a paragraph
+ * unless already contained in some flow container;
+ * never put them directly into a section.
+ */
+
+ } else if (tflags & HTML_TOPHRASE && h->tag->tag == TAG_SECTION)
+ print_otag(h, TAG_P, "c", "Pp");
+
/* Push this tag onto the stack of open scopes. */
if ((tflags & HTML_NOSTACK) == 0) {
@@ -706,7 +771,7 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
/* Accommodate for "well-formed" singleton escaping. */
- if (HTML_AUTOCLOSE & htmltags[tag].flags)
+ if (htmltags[tag].flags & HTML_NOSTACK)
print_byte(h, '/');
print_byte(h, '>');
@@ -724,6 +789,49 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
return t;
}
+/*
+ * Print an element with an optional "id=" attribute.
+ * If the element has phrasing content and an "id=" attribute,
+ * also add a permalink: outside if it can be in phrasing context,
+ * inside otherwise.
+ */
+struct tag *
+print_otag_id(struct html *h, enum htmltag elemtype, const char *cattr,
+ struct roff_node *n)
+{
+ struct roff_node *nch;
+ struct tag *ret, *t;
+ char *id, *href;
+
+ ret = NULL;
+ id = href = NULL;
+ if (n->flags & NODE_ID)
+ id = html_make_id(n, 1);
+ if (n->flags & NODE_HREF)
+ href = id == NULL ? html_make_id(n, 2) : id;
+ if (href != NULL && htmltags[elemtype].flags & HTML_INPHRASE)
+ ret = print_otag(h, TAG_A, "chR", "permalink", href);
+ t = print_otag(h, elemtype, "ci", cattr, id);
+ if (ret == NULL) {
+ ret = t;
+ if (href != NULL && (nch = n->child) != NULL) {
+ /* man(7) is safe, it tags phrasing content only. */
+ if (n->tok > MDOC_MAX ||
+ htmltags[elemtype].flags & HTML_TOPHRASE)
+ nch = NULL;
+ else /* For mdoc(7), beware of nested blocks. */
+ while (nch != NULL && nch->type == ROFFT_TEXT)
+ nch = nch->next;
+ if (nch == NULL)
+ print_otag(h, TAG_A, "chR", "permalink", href);
+ }
+ }
+ free(id);
+ if (id == NULL)
+ free(href);
+ return ret;
+}
+
static void
print_ctag(struct html *h, struct tag *tag)
{
@@ -793,6 +901,25 @@ print_gen_comment(struct html *h, struct roff_node *n)
void
print_text(struct html *h, const char *word)
{
+ print_tagged_text(h, word, NULL);
+}
+
+void
+print_tagged_text(struct html *h, const char *word, struct roff_node *n)
+{
+ struct tag *t;
+ char *href;
+
+ /*
+ * Always wrap text in a paragraph unless already contained in
+ * some flow container; never put it directly into a section.
+ */
+
+ if (h->tag->tag == TAG_SECTION)
+ print_otag(h, TAG_P, "c", "Pp");
+
+ /* Output whitespace before this text? */
+
if (h->col && (h->flags & HTML_NOSPACE) == 0) {
if ( ! (HTML_KEEP & h->flags)) {
if (HTML_PREKEEP & h->flags)
@@ -802,9 +929,21 @@ print_text(struct html *h, const char *word)
print_word(h, "&#x00A0;");
}
+ /*
+ * Optionally switch fonts, optionally write a permalink, then
+ * print the text, optionally surrounded by HTML whitespace.
+ */
+
assert(h->metaf == NULL);
print_metaf(h);
print_indent(h);
+
+ if (n != NULL && (href = html_make_id(n, 2)) != NULL) {
+ t = print_otag(h, TAG_A, "chR", "permalink", href);
+ free(href);
+ } else
+ t = NULL;
+
if ( ! print_encode(h, word, NULL, 0)) {
if ( ! (h->flags & HTML_NONOSPACE))
h->flags &= ~HTML_NOSPACE;
@@ -815,7 +954,8 @@ print_text(struct html *h, const char *word)
if (h->metaf != NULL) {
print_tagq(h, h->metaf);
h->metaf = NULL;
- }
+ } else if (t != NULL)
+ print_tagq(h, t);
h->flags &= ~HTML_IGNDELIM;
}
@@ -942,15 +1082,12 @@ print_indent(struct html *h)
{
size_t i;
- if (h->col)
+ if (h->col || h->noindent)
return;
- if (h->noindent == 0) {
- h->col = h->indent * 2;
- for (i = 0; i < h->col; i++)
- putchar(' ');
- }
- h->flags &= ~HTML_NOSPACE;
+ h->col = h->indent * 2;
+ for (i = 0; i < h->col; i++)
+ putchar(' ');
}
/*
diff --git a/html.h b/html.h
index 242a63a8d624..3d201403342d 100644
--- a/html.h
+++ b/html.h
@@ -1,7 +1,7 @@
-/* $Id: html.h,v 1.103 2019/04/30 15:53:00 schwarze Exp $ */
+/* $Id: html.h,v 1.109 2021/09/09 14:47:24 schwarze Exp $ */
/*
+ * Copyright (c) 2017, 2018, 2019, 2020 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2017, 2018, 2019 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,23 +14,21 @@
* 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.
+ *
+ * Internal interfaces for mandoc(1) HTML formatters.
+ * For use by the individual HTML formatters only.
*/
enum htmltag {
TAG_HTML,
TAG_HEAD,
- TAG_BODY,
TAG_META,
+ TAG_LINK,
+ TAG_STYLE,
TAG_TITLE,
+ TAG_BODY,
TAG_DIV,
- TAG_IDIV,
TAG_SECTION,
- TAG_H1,
- TAG_H2,
- TAG_SPAN,
- TAG_LINK,
- TAG_BR,
- TAG_A,
TAG_TABLE,
TAG_TR,
TAG_TD,
@@ -40,15 +38,21 @@ enum htmltag {
TAG_DL,
TAG_DT,
TAG_DD,
+ TAG_H1,
+ TAG_H2,
TAG_P,
TAG_PRE,
- TAG_VAR,
- TAG_CITE,
+ TAG_A,
TAG_B,
- TAG_I,
+ TAG_CITE,
TAG_CODE,
+ TAG_I,
TAG_SMALL,
- TAG_STYLE,
+ TAG_SPAN,
+ TAG_VAR,
+ TAG_BR,
+ TAG_HR,
+ TAG_MARK,
TAG_MATH,
TAG_MROW,
TAG_MI,
@@ -120,8 +124,12 @@ void print_gen_comment(struct html *, struct roff_node *);
void print_gen_decls(struct html *);
void print_gen_head(struct html *);
struct tag *print_otag(struct html *, enum htmltag, const char *, ...);
+struct tag *print_otag_id(struct html *, enum htmltag, const char *,
+ struct roff_node *);
void print_tagq(struct html *, const struct tag *);
void print_stagq(struct html *, const struct tag *);
+void print_tagged_text(struct html *, const char *,
+ struct roff_node *);
void print_text(struct html *, const char *);
void print_tblclose(struct html *);
void print_tbl(struct html *, const struct tbl_span *);
diff --git a/libmandoc.h b/libmandoc.h
index ff6f4692f062..ab7c29be510f 100644
--- a/libmandoc.h
+++ b/libmandoc.h
@@ -1,7 +1,7 @@
-/* $Id: libmandoc.h,v 1.77 2018/12/21 17:15:18 schwarze Exp $ */
+/* $Id: libmandoc.h,v 1.80 2021/06/27 17:57:54 schwarze Exp $ */
/*
+ * Copyright (c) 2013-2015,2017,2018,2020 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013,2014,2015,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,6 +14,9 @@
* 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.
+ *
+ * Internal interfaces for parser utilities needed by multiple parsers
+ * and the top-level functions to call the mdoc, man, and roff parsers.
*/
/*
@@ -47,8 +50,9 @@ struct buf {
struct roff;
struct roff_man;
+struct roff_node;
-char *mandoc_normdate(struct roff_man *, char *, int, int);
+char *mandoc_normdate(struct roff_node *, struct roff_node *);
int mandoc_eos(const char *, size_t);
int mandoc_strntoi(const char *, size_t, int);
const char *mandoc_a2msec(const char*);
@@ -69,10 +73,10 @@ void roff_reset(struct roff *);
void roff_man_free(struct roff_man *);
struct roff_man *roff_man_alloc(struct roff *, const char *, int);
void roff_man_reset(struct roff_man *);
-int roff_parseln(struct roff *, int, struct buf *, int *);
+int roff_parseln(struct roff *, int, struct buf *, int *, size_t);
void roff_userret(struct roff *);
void roff_endparse(struct roff *);
-void roff_setreg(struct roff *, const char *, int, char sign);
+void roff_setreg(struct roff *, const char *, int, char);
int roff_getreg(struct roff *, const char *);
char *roff_strdup(const struct roff *, const char *);
char *roff_getarg(struct roff *, char **, int, int *);
diff --git a/main.c b/main.c
index b11f7b51c164..c5a7cff918ab 100644
--- a/main.c
+++ b/main.c
@@ -1,7 +1,7 @@
-/* $Id: main.c,v 1.332 2019/07/19 20:27:25 schwarze Exp $ */
+/* $Id: main.c,v 1.358 2021/09/04 22:38:46 schwarze Exp $ */
/*
+ * Copyright (c) 2010-2012, 2014-2021 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2012, 2014-2019 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -15,6 +15,8 @@
* 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.
+ *
+ * Main program for mandoc(1), man(1), apropos(1), whatis(1), and help(1).
*/
#include "config.h"
@@ -32,6 +34,7 @@
#include <errno.h>
#include <fcntl.h>
#include <glob.h>
+#include <limits.h>
#if HAVE_SANDBOX_INIT
#include <sandbox.h>
#endif
@@ -52,6 +55,7 @@
#include "man.h"
#include "mandoc_parse.h"
#include "tag.h"
+#include "term_tag.h"
#include "main.h"
#include "manconf.h"
#include "mansearch.h"
@@ -77,33 +81,39 @@ enum outt {
OUTT_PDF /* -Tpdf */
};
-struct curparse {
- struct mparse *mp;
- struct manoutput *outopts; /* output options */
+struct outstate {
+ struct tag_files *tag_files; /* Tagging state variables. */
void *outdata; /* data for output */
- char *os_s; /* operating system for display */
+ int use_pager;
int wstop; /* stop after a file with a warning */
- enum mandoc_os os_e; /* check base system conventions */
+ int had_output; /* Some output was generated. */
enum outt outtype; /* which output to use */
};
int mandocdb(int, char *[]);
-static void check_xr(void);
-static int fs_lookup(const struct manpaths *,
- size_t ipath, const char *,
- const char *, const char *,
+static void check_xr(struct manpaths *);
+static void fs_append(char **, size_t, int,
+ size_t, const char *, enum form,
+ struct manpage **, size_t *);
+static int fs_lookup(const struct manpaths *, size_t,
+ const char *, const char *, const char *,
struct manpage **, size_t *);
static int fs_search(const struct mansearch *,
- const struct manpaths *, int, char**,
+ const struct manpaths *, const char *,
struct manpage **, size_t *);
-static void outdata_alloc(struct curparse *);
-static void parse(struct curparse *, int, const char *);
+static void glob_esc(char **, const char *, const char *);
+static void outdata_alloc(struct outstate *, struct manoutput *);
+static void parse(struct mparse *, int, const char *,
+ struct outstate *, struct manconf *);
static void passthrough(int, int);
-static pid_t spawn_pager(struct tag_files *);
+static void process_onefile(struct mparse *, struct manpage *,
+ int, struct outstate *, struct manconf *);
+static void run_pager(struct outstate *, char *);
+static pid_t spawn_pager(struct outstate *, char *);
static void usage(enum argmode) __attribute__((__noreturn__));
-static int woptions(struct curparse *, char *);
+static int woptions(char *, enum mandoc_os *, int *);
static const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9};
static char help_arg[] = "help";
@@ -113,26 +123,31 @@ static char *help_argv[] = {help_arg, NULL};
int
main(int argc, char *argv[])
{
- struct manconf conf;
- struct mansearch search;
- struct curparse curp;
- struct winsize ws;
- struct tag_files *tag_files;
- struct manpage *res, *resp;
- const char *progname, *sec, *thisarg;
- char *conf_file, *defpaths, *auxpaths;
- char *oarg, *tagarg;
+ struct manconf conf; /* Manpaths and output options. */
+ struct outstate outst; /* Output state. */
+ struct winsize ws; /* Result of ioctl(TIOCGWINSZ). */
+ struct mansearch search; /* Search options. */
+ struct manpage *res; /* Complete list of search results. */
+ struct manpage *resn; /* Search results for one name. */
+ struct mparse *mp; /* Opaque parser object. */
+ const char *conf_file; /* -C: alternate config file. */
+ const char *os_s; /* -I: Operating system for display. */
+ const char *progname, *sec, *ep;
+ char *defpaths; /* -M: override manpaths. */
+ char *auxpaths; /* -m: additional manpaths. */
+ char *oarg; /* -O: output option string. */
+ char *tagarg; /* -O tag: default value. */
unsigned char *uc;
- size_t i, sz, ssz;
+ size_t ressz; /* Number of elements in res[]. */
+ size_t resnsz; /* Number of elements in resn[]. */
+ size_t i, ib, ssz;
+ int options; /* Parser options. */
+ int show_usage; /* Invalid argument: give up. */
int prio, best_prio;
- enum outmode outmode;
- int fd, startdir;
- int show_usage;
- int options;
- int use_pager;
- int status, signum;
+ int startdir;
int c;
- pid_t pager_pid, tc_pgid, man_pgid, pid;
+ enum mandoc_os os_e; /* Check base system conventions. */
+ enum outmode outmode; /* According to command line. */
#if HAVE_PROGNAME
progname = getprogname();
@@ -152,7 +167,7 @@ main(int argc, char *argv[])
return mandocdb(argc, argv);
#if HAVE_PLEDGE
- if (pledge("stdio rpath tmppath tty proc exec", NULL) == -1) {
+ if (pledge("stdio rpath wpath cpath tmppath tty proc exec", NULL) == -1) {
mandoc_msg(MANDOCERR_PLEDGE, 0, 0, "%s", strerror(errno));
return mandoc_msg_getrc();
}
@@ -165,8 +180,8 @@ main(int argc, char *argv[])
/* Search options. */
memset(&conf, 0, sizeof(conf));
- conf_file = defpaths = NULL;
- auxpaths = NULL;
+ conf_file = NULL;
+ defpaths = auxpaths = NULL;
memset(&search, 0, sizeof(struct mansearch));
search.outkey = "Nd";
@@ -183,15 +198,19 @@ main(int argc, char *argv[])
else
search.argmode = ARG_FILE;
- /* Parser and formatter options. */
+ /* Parser options. */
- memset(&curp, 0, sizeof(struct curparse));
- curp.outtype = OUTT_LOCALE;
- curp.outopts = &conf.output;
options = MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1;
+ os_e = MANDOC_OS_OTHER;
+ os_s = NULL;
+
+ /* Formatter options. */
+
+ memset(&outst, 0, sizeof(outst));
+ outst.tag_files = NULL;
+ outst.outtype = OUTT_LOCALE;
+ outst.use_pager = 1;
- use_pager = 1;
- tag_files = NULL;
show_usage = 0;
outmode = OUTMODE_DEF;
@@ -209,14 +228,14 @@ main(int argc, char *argv[])
conf_file = optarg;
break;
case 'c':
- use_pager = 0;
+ outst.use_pager = 0;
break;
case 'f':
search.argmode = ARG_WORD;
break;
case 'h':
conf.output.synopsisonly = 1;
- use_pager = 0;
+ outst.use_pager = 0;
outmode = OUTMODE_ALL;
break;
case 'I':
@@ -225,12 +244,12 @@ main(int argc, char *argv[])
"-I %s", optarg);
return mandoc_msg_getrc();
}
- if (curp.os_s != NULL) {
+ if (os_s != NULL) {
mandoc_msg(MANDOCERR_BADARG_DUPE, 0, 0,
"-I %s", optarg);
return mandoc_msg_getrc();
}
- curp.os_s = mandoc_strdup(optarg + 3);
+ os_s = optarg + 3;
break;
case 'K':
options &= ~(MPARSE_UTF8 | MPARSE_LATIN1);
@@ -268,27 +287,27 @@ main(int argc, char *argv[])
break;
case 'T':
if (strcmp(optarg, "ascii") == 0)
- curp.outtype = OUTT_ASCII;
+ outst.outtype = OUTT_ASCII;
else if (strcmp(optarg, "lint") == 0) {
- curp.outtype = OUTT_LINT;
+ outst.outtype = OUTT_LINT;
mandoc_msg_setoutfile(stdout);
mandoc_msg_setmin(MANDOCERR_BASE);
} else if (strcmp(optarg, "tree") == 0)
- curp.outtype = OUTT_TREE;
+ outst.outtype = OUTT_TREE;
else if (strcmp(optarg, "man") == 0)
- curp.outtype = OUTT_MAN;
+ outst.outtype = OUTT_MAN;
else if (strcmp(optarg, "html") == 0)
- curp.outtype = OUTT_HTML;
+ outst.outtype = OUTT_HTML;
else if (strcmp(optarg, "markdown") == 0)
- curp.outtype = OUTT_MARKDOWN;
+ outst.outtype = OUTT_MARKDOWN;
else if (strcmp(optarg, "utf8") == 0)
- curp.outtype = OUTT_UTF8;
+ outst.outtype = OUTT_UTF8;
else if (strcmp(optarg, "locale") == 0)
- curp.outtype = OUTT_LOCALE;
+ outst.outtype = OUTT_LOCALE;
else if (strcmp(optarg, "ps") == 0)
- curp.outtype = OUTT_PS;
+ outst.outtype = OUTT_PS;
else if (strcmp(optarg, "pdf") == 0)
- curp.outtype = OUTT_PDF;
+ outst.outtype = OUTT_PDF;
else {
mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0,
"-T %s", optarg);
@@ -296,7 +315,7 @@ main(int argc, char *argv[])
}
break;
case 'W':
- if (woptions(&curp, optarg) == -1)
+ if (woptions(optarg, &os_e, &outst.wstop) == -1)
return mandoc_msg_getrc();
break;
case 'w':
@@ -313,11 +332,12 @@ main(int argc, char *argv[])
/* Postprocess options. */
- if (outmode == OUTMODE_DEF) {
+ switch (outmode) {
+ case OUTMODE_DEF:
switch (search.argmode) {
case ARG_FILE:
outmode = OUTMODE_ALL;
- use_pager = 0;
+ outst.use_pager = 0;
break;
case ARG_NAME:
outmode = OUTMODE_ONE;
@@ -326,6 +346,16 @@ main(int argc, char *argv[])
outmode = OUTMODE_LST;
break;
}
+ break;
+ case OUTMODE_FLN:
+ if (search.argmode == ARG_FILE)
+ outmode = OUTMODE_ALL;
+ break;
+ case OUTMODE_ALL:
+ break;
+ case OUTMODE_LST:
+ case OUTMODE_ONE:
+ abort();
}
if (oarg != NULL) {
@@ -340,15 +370,17 @@ main(int argc, char *argv[])
}
}
- if (curp.outtype != OUTT_TREE || !curp.outopts->noval)
+ if (outst.outtype != OUTT_TREE || conf.output.noval == 0)
options |= MPARSE_VALIDATE;
if (outmode == OUTMODE_FLN ||
outmode == OUTMODE_LST ||
- !isatty(STDOUT_FILENO))
- use_pager = 0;
+ (conf.output.outfilename == NULL &&
+ conf.output.tagfilename == NULL &&
+ isatty(STDOUT_FILENO) == 0))
+ outst.use_pager = 0;
- if (use_pager &&
+ if (outst.use_pager &&
(conf.output.width == 0 || conf.output.indent == 0) &&
ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1 &&
ws.ws_col > 1) {
@@ -359,12 +391,16 @@ main(int argc, char *argv[])
}
#if HAVE_PLEDGE
- if (use_pager == 0) {
- if (pledge("stdio rpath", NULL) == -1) {
- mandoc_msg(MANDOCERR_PLEDGE, 0, 0,
- "%s", strerror(errno));
- return mandoc_msg_getrc();
- }
+ if (outst.use_pager == 0)
+ c = pledge("stdio rpath", NULL);
+ else if (conf.output.outfilename != NULL ||
+ conf.output.tagfilename != NULL)
+ c = pledge("stdio rpath wpath cpath", NULL);
+ else
+ c = pledge("stdio rpath tmppath tty proc exec", NULL);
+ if (c == -1) {
+ mandoc_msg(MANDOCERR_PLEDGE, 0, 0, "%s", strerror(errno));
+ return mandoc_msg_getrc();
}
#endif
@@ -374,11 +410,10 @@ main(int argc, char *argv[])
argc -= optind;
argv += optind;
}
- resp = NULL;
/*
- * Quirks for help(1)
- * and for a man(1) section argument without -s.
+ * Quirks for help(1) and man(1),
+ * in particular for a section argument without -s.
*/
if (search.argmode == ARG_NAME) {
@@ -402,6 +437,8 @@ main(int argc, char *argv[])
if (search.arch == NULL)
search.arch = MACHINE;
#endif
+ if (outmode == OUTMODE_ONE)
+ search.firstmatch = 1;
}
/*
@@ -415,80 +452,78 @@ main(int argc, char *argv[])
conf.output.tag = tagarg == NULL ? *argv : tagarg + 1;
}
- /* man(1), whatis(1), apropos(1) */
-
- if (search.argmode != ARG_FILE) {
- if (search.argmode == ARG_NAME &&
- outmode == OUTMODE_ONE)
- search.firstmatch = 1;
-
- /* Access the mandoc database. */
+ /* Read the configuration file. */
+ if (search.argmode != ARG_FILE ||
+ mandoc_msg_getmin() == MANDOCERR_STYLE)
manconf_parse(&conf, conf_file, defpaths, auxpaths);
- if ( ! mansearch(&search, &conf.manpath,
- argc, argv, &res, &sz))
- usage(search.argmode);
- if (sz == 0 && search.argmode == ARG_NAME)
- (void)fs_search(&search, &conf.manpath,
- argc, argv, &res, &sz);
+ /* man(1): Resolve each name individually. */
- if (search.argmode == ARG_NAME) {
- for (c = 0; c < argc; c++) {
- if (strchr(argv[c], '/') == NULL)
- continue;
- if (access(argv[c], R_OK) == -1) {
- mandoc_msg_setinfilename(argv[c]);
+ if (search.argmode == ARG_NAME) {
+ if (argc < 1) {
+ if (outmode != OUTMODE_FLN)
+ usage(ARG_NAME);
+ if (conf.manpath.sz == 0) {
+ warnx("The manpath is empty.");
+ mandoc_msg_setrc(MANDOCLEVEL_BADARG);
+ } else {
+ for (i = 0; i + 1 < conf.manpath.sz; i++)
+ printf("%s:", conf.manpath.paths[i]);
+ printf("%s\n", conf.manpath.paths[i]);
+ }
+ manconf_free(&conf);
+ return (int)mandoc_msg_getrc();
+ }
+ for (res = NULL, ressz = 0; argc > 0; argc--, argv++) {
+ (void)mansearch(&search, &conf.manpath,
+ 1, argv, &resn, &resnsz);
+ if (resnsz == 0)
+ (void)fs_search(&search, &conf.manpath,
+ *argv, &resn, &resnsz);
+ if (resnsz == 0 && strchr(*argv, '/') == NULL) {
+ if (search.arch != NULL &&
+ arch_valid(search.arch, OSENUM) == 0)
+ warnx("Unknown architecture \"%s\".",
+ search.arch);
+ else if (search.sec != NULL)
+ warnx("No entry for %s in "
+ "section %s of the manual.",
+ *argv, search.sec);
+ else
+ warnx("No entry for %s in "
+ "the manual.", *argv);
+ mandoc_msg_setrc(MANDOCLEVEL_BADARG);
+ continue;
+ }
+ if (resnsz == 0) {
+ if (access(*argv, R_OK) == -1) {
+ mandoc_msg_setinfilename(*argv);
mandoc_msg(MANDOCERR_BADARG_BAD,
0, 0, "%s", strerror(errno));
mandoc_msg_setinfilename(NULL);
continue;
}
+ resnsz = 1;
+ resn = mandoc_calloc(resnsz, sizeof(*res));
+ resn->file = mandoc_strdup(*argv);
+ resn->ipath = SIZE_MAX;
+ resn->form = FORM_SRC;
+ }
+ if (outmode != OUTMODE_ONE || resnsz == 1) {
res = mandoc_reallocarray(res,
- sz + 1, sizeof(*res));
- res[sz].file = mandoc_strdup(argv[c]);
- res[sz].names = NULL;
- res[sz].output = NULL;
- res[sz].bits = 0;
- res[sz].ipath = SIZE_MAX;
- res[sz].sec = 10;
- res[sz].form = FORM_SRC;
- sz++;
+ ressz + resnsz, sizeof(*res));
+ memcpy(res + ressz, resn,
+ sizeof(*resn) * resnsz);
+ ressz += resnsz;
+ continue;
}
- }
- if (sz == 0) {
- if (search.argmode != ARG_NAME)
- warnx("nothing appropriate");
- mandoc_msg_setrc(MANDOCLEVEL_BADARG);
- goto out;
- }
+ /* Search for the best section. */
- /*
- * For standard man(1) and -a output mode,
- * prepare for copying filename pointers
- * into the program parameter array.
- */
-
- if (outmode == OUTMODE_ONE) {
- argc = 1;
best_prio = 40;
- } else if (outmode == OUTMODE_ALL)
- argc = (int)sz;
-
- /* Iterate all matching manuals. */
-
- resp = res;
- for (i = 0; i < sz; i++) {
- if (outmode == OUTMODE_FLN)
- puts(res[i].file);
- else if (outmode == OUTMODE_LST)
- printf("%s - %s\n", res[i].names,
- res[i].output == NULL ? "" :
- res[i].output);
- else if (outmode == OUTMODE_ONE) {
- /* Search for the best section. */
- sec = res[i].file;
+ for (ib = i = 0; i < resnsz; i++) {
+ sec = resn[i].file;
sec += strcspn(sec, "123456789");
if (sec[0] == '\0')
continue; /* No section at all. */
@@ -501,45 +536,66 @@ main(int argc, char *argv[])
sec++; /* Prefer without suffix. */
if (*sec != '/')
prio += 10; /* Wrong dir name. */
- if (search.sec != NULL &&
- (strlen(sec) <= ssz + 3 ||
- strcmp(sec + strlen(sec) - ssz,
- search.sec) != 0))
- prio += 20; /* Wrong file ext. */
+ if (search.sec != NULL) {
+ ep = strchr(sec, '\0');
+ if (ep - sec > 3 &&
+ strncmp(ep - 3, ".gz", 3) == 0)
+ ep -= 3;
+ if ((size_t)(ep - sec) < ssz + 3 ||
+ strncmp(ep - ssz, search.sec,
+ ssz) != 0) /* Wrong file */
+ prio += 20; /* extension. */
+ }
if (prio >= best_prio)
continue;
best_prio = prio;
- resp = res + i;
+ ib = i;
}
+ res = mandoc_reallocarray(res, ressz + 1,
+ sizeof(*res));
+ memcpy(res + ressz++, resn + ib, sizeof(*resn));
}
- /*
- * For man(1), -a and -i output mode, fall through
- * to the main mandoc(1) code iterating files
- * and running the parsers on each of them.
- */
+ /* apropos(1), whatis(1): Process the full search expression. */
+
+ } else if (search.argmode != ARG_FILE) {
+ if (mansearch(&search, &conf.manpath,
+ argc, argv, &res, &ressz) == 0)
+ usage(search.argmode);
- if (outmode == OUTMODE_FLN || outmode == OUTMODE_LST)
+ if (ressz == 0) {
+ warnx("nothing appropriate");
+ mandoc_msg_setrc(MANDOCLEVEL_BADARG);
goto out;
- }
+ }
- /* mandoc(1) */
+ /* mandoc(1): Take command line arguments as file names. */
-#if HAVE_PLEDGE
- if (use_pager) {
- if (pledge("stdio rpath tmppath tty proc exec", NULL) == -1) {
- mandoc_msg(MANDOCERR_PLEDGE, 0, 0,
- "%s", strerror(errno));
- return mandoc_msg_getrc();
- }
} else {
- if (pledge("stdio rpath", NULL) == -1) {
- mandoc_msg(MANDOCERR_PLEDGE, 0, 0,
- "%s", strerror(errno));
- return mandoc_msg_getrc();
+ ressz = argc > 0 ? argc : 1;
+ res = mandoc_calloc(ressz, sizeof(*res));
+ for (i = 0; i < ressz; i++) {
+ if (argc > 0)
+ res[i].file = mandoc_strdup(argv[i]);
+ res[i].ipath = SIZE_MAX;
+ res[i].form = FORM_SRC;
}
}
-#endif
+
+ switch (outmode) {
+ case OUTMODE_FLN:
+ for (i = 0; i < ressz; i++)
+ puts(res[i].file);
+ goto out;
+ case OUTMODE_LST:
+ for (i = 0; i < ressz; i++)
+ printf("%s - %s\n", res[i].names,
+ res[i].output == NULL ? "" :
+ res[i].output);
+ goto out;
+ default:
+ break;
+ }
if (search.argmode == ARG_FILE && auxpaths != NULL) {
if (strcmp(auxpaths, "doc") == 0)
@@ -549,19 +605,7 @@ main(int argc, char *argv[])
}
mchars_alloc();
- curp.mp = mparse_alloc(options, curp.os_e, curp.os_s);
-
- if (argc < 1) {
- if (use_pager) {
- tag_files = tag_init();
- if (tag_files != NULL)
- tag_files->tagname = conf.output.tag;
- }
- thisarg = "<stdin>";
- mandoc_msg_setinfilename(thisarg);
- parse(&curp, STDIN_FILENO, thisarg);
- mandoc_msg_setinfilename(NULL);
- }
+ mp = mparse_alloc(options, os_e, os_s);
/*
* Remember the original working directory, if possible.
@@ -571,164 +615,53 @@ main(int argc, char *argv[])
* readable: Maybe it won't be needed after all.
*/
startdir = open(".", O_RDONLY | O_DIRECTORY);
-
- while (argc > 0) {
-
- /*
- * Changing directories is not needed in ARG_FILE mode.
- * Do it on a best-effort basis. Even in case of
- * failure, some functionality may still work.
- */
- if (resp != NULL) {
- if (resp->ipath != SIZE_MAX)
- (void)chdir(conf.manpath.paths[resp->ipath]);
- else if (startdir != -1)
- (void)fchdir(startdir);
- thisarg = resp->file;
- } else
- thisarg = *argv;
-
- mandoc_msg_setinfilename(thisarg);
- fd = mparse_open(curp.mp, thisarg);
- if (fd != -1) {
- if (use_pager) {
- use_pager = 0;
- tag_files = tag_init();
- if (tag_files != NULL)
- tag_files->tagname = conf.output.tag;
- }
-
- if (resp == NULL || resp->form == FORM_SRC)
- parse(&curp, fd, thisarg);
- else
- passthrough(fd, conf.output.synopsisonly);
-
- if (ferror(stdout)) {
- if (tag_files != NULL) {
- mandoc_msg(MANDOCERR_WRITE, 0, 0,
- "%s: %s", tag_files->ofn,
- strerror(errno));
- tag_unlink();
- tag_files = NULL;
- } else
- mandoc_msg(MANDOCERR_WRITE, 0, 0,
- "%s", strerror(errno));
- break;
- }
-
- if (argc > 1 && curp.outtype <= OUTT_UTF8) {
- if (curp.outdata == NULL)
- outdata_alloc(&curp);
- terminal_sepline(curp.outdata);
- }
- } else
- mandoc_msg(resp == NULL ? MANDOCERR_BADARG_BAD :
- MANDOCERR_OPEN, 0, 0, "%s", strerror(errno));
-
- mandoc_msg_setinfilename(NULL);
-
- if (curp.wstop && mandoc_msg_getrc() != MANDOCLEVEL_OK)
+ for (i = 0; i < ressz; i++) {
+ process_onefile(mp, res + i, startdir, &outst, &conf);
+ if (outst.wstop && mandoc_msg_getrc() != MANDOCLEVEL_OK)
break;
-
- if (resp != NULL)
- resp++;
- else
- argv++;
- if (--argc)
- mparse_reset(curp.mp);
}
if (startdir != -1) {
(void)fchdir(startdir);
close(startdir);
}
-
- if (curp.outdata != NULL) {
- switch (curp.outtype) {
+ if (conf.output.tag != NULL && conf.output.tag_found == 0) {
+ mandoc_msg(MANDOCERR_TAG, 0, 0, "%s", conf.output.tag);
+ conf.output.tag = NULL;
+ }
+ if (outst.outdata != NULL) {
+ switch (outst.outtype) {
case OUTT_HTML:
- html_free(curp.outdata);
+ html_free(outst.outdata);
break;
case OUTT_UTF8:
case OUTT_LOCALE:
case OUTT_ASCII:
- ascii_free(curp.outdata);
+ ascii_free(outst.outdata);
break;
case OUTT_PDF:
case OUTT_PS:
- pspdf_free(curp.outdata);
+ pspdf_free(outst.outdata);
break;
default:
break;
}
}
mandoc_xr_free();
- mparse_free(curp.mp);
+ mparse_free(mp);
mchars_free();
out:
- if (search.argmode != ARG_FILE) {
+ mansearch_free(res, ressz);
+ if (search.argmode != ARG_FILE)
manconf_free(&conf);
- mansearch_free(res, sz);
- }
-
- free(curp.os_s);
-
- /*
- * When using a pager, finish writing both temporary files,
- * fork it, wait for the user to close it, and clean up.
- */
-
- if (tag_files != NULL) {
- fclose(stdout);
- tag_write();
- man_pgid = getpgid(0);
- tag_files->tcpgid = man_pgid == getpid() ?
- getpgid(getppid()) : man_pgid;
- pager_pid = 0;
- signum = SIGSTOP;
- for (;;) {
-
- /* Stop here until moved to the foreground. */
-
- tc_pgid = tcgetpgrp(tag_files->ofd);
- if (tc_pgid != man_pgid) {
- if (tc_pgid == pager_pid) {
- (void)tcsetpgrp(tag_files->ofd,
- man_pgid);
- if (signum == SIGTTIN)
- continue;
- } else
- tag_files->tcpgid = tc_pgid;
- kill(0, signum);
- continue;
- }
-
- /* Once in the foreground, activate the pager. */
-
- if (pager_pid) {
- (void)tcsetpgrp(tag_files->ofd, pager_pid);
- kill(pager_pid, SIGCONT);
- } else
- pager_pid = spawn_pager(tag_files);
-
- /* Wait for the pager to stop or exit. */
- while ((pid = waitpid(pager_pid, &status,
- WUNTRACED)) == -1 && errno == EINTR)
- continue;
-
- if (pid == -1) {
- mandoc_msg(MANDOCERR_WAIT, 0, 0,
- "%s", strerror(errno));
- break;
- }
- if (!WIFSTOPPED(status))
- break;
-
- signum = WSTOPSIG(status);
- }
- tag_unlink();
- } else if (curp.outtype != OUTT_LINT &&
- (search.argmode == ARG_FILE || sz > 0))
+ if (outst.tag_files != NULL) {
+ if (term_tag_close() != -1 &&
+ conf.output.outfilename == NULL &&
+ conf.output.tagfilename == NULL)
+ run_pager(&outst, conf.output.tag);
+ term_tag_unlink();
+ } else if (outst.had_output && outst.outtype != OUTT_LINT)
mandoc_msg_summary();
return (int)mandoc_msg_getrc();
@@ -762,6 +695,42 @@ usage(enum argmode argmode)
exit((int)MANDOCLEVEL_BADARG);
}
+static void
+glob_esc(char **dst, const char *src, const char *suffix)
+{
+ while (*src != '\0') {
+ if (strchr("*?[", *src) != NULL)
+ *(*dst)++ = '\\';
+ *(*dst)++ = *src++;
+ }
+ while (*suffix != '\0')
+ *(*dst)++ = *suffix++;
+}
+
+static void
+fs_append(char **file, size_t filesz, int copy, size_t ipath,
+ const char *sec, enum form form, struct manpage **res, size_t *ressz)
+{
+ struct manpage *page;
+
+ *res = mandoc_reallocarray(*res, *ressz + filesz, sizeof(**res));
+ page = *res + *ressz;
+ *ressz += filesz;
+ for (;;) {
+ page->file = copy ? mandoc_strdup(*file) : *file;
+ page->names = NULL;
+ page->output = NULL;
+ page->bits = NAME_FILE & NAME_MASK;
+ page->ipath = ipath;
+ page->sec = (*sec >= '1' && *sec <= '9') ? *sec - '1' + 1 : 10;
+ page->form = form;
+ if (--filesz == 0)
+ break;
+ file++;
+ page++;
+ }
+}
+
static int
fs_lookup(const struct manpaths *paths, size_t ipath,
const char *sec, const char *arch, const char *name,
@@ -769,12 +738,19 @@ fs_lookup(const struct manpaths *paths, size_t ipath,
{
struct stat sb;
glob_t globinfo;
- struct manpage *page;
- char *file;
+ char *file, *cp, secnum[2];
int globres;
enum form form;
+ const char *const slman = "/man";
+ const char *const slash = "/";
+ const char *const sglob = ".[01-9]*";
+ const char *const dot = ".";
+ const char *const aster = "*";
+
+ memset(&globinfo, 0, sizeof(globinfo));
form = FORM_SRC;
+
mandoc_asprintf(&file, "%s/man%s/%s.%s",
paths->paths[ipath], sec, name, sec);
if (stat(file, &sb) != -1)
@@ -797,21 +773,46 @@ fs_lookup(const struct manpaths *paths, size_t ipath,
free(file);
}
- mandoc_asprintf(&file, "%s/man%s/%s.[01-9]*",
- paths->paths[ipath], sec, name);
+ cp = file = mandoc_malloc(strlen(paths->paths[ipath]) * 2 +
+ strlen(slman) + strlen(sec) * 2 + strlen(slash) +
+ strlen(name) * 2 + strlen(sglob) + 1);
+ glob_esc(&cp, paths->paths[ipath], slman);
+ glob_esc(&cp, sec, slash);
+ glob_esc(&cp, name, sglob);
+ *cp = '\0';
globres = glob(file, 0, NULL, &globinfo);
if (globres != 0 && globres != GLOB_NOMATCH)
mandoc_msg(MANDOCERR_GLOB, 0, 0,
"%s: %s", file, strerror(errno));
free(file);
+ file = NULL;
if (globres == 0)
- file = mandoc_strdup(*globinfo.gl_pathv);
+ goto found;
globfree(&globinfo);
- if (globres == 0) {
- if (stat(file, &sb) != -1)
- goto found;
+
+ if (sec[1] != '\0' && *ressz == 0) {
+ secnum[0] = sec[0];
+ secnum[1] = '\0';
+ cp = file = mandoc_malloc(strlen(paths->paths[ipath]) * 2 +
+ strlen(slman) + strlen(secnum) * 2 + strlen(slash) +
+ strlen(name) * 2 + strlen(dot) +
+ strlen(sec) * 2 + strlen(aster) + 1);
+ glob_esc(&cp, paths->paths[ipath], slman);
+ glob_esc(&cp, secnum, slash);
+ glob_esc(&cp, name, dot);
+ glob_esc(&cp, sec, aster);
+ *cp = '\0';
+ globres = glob(file, 0, NULL, &globinfo);
+ if (globres != 0 && globres != GLOB_NOMATCH)
+ mandoc_msg(MANDOCERR_GLOB, 0, 0,
+ "%s: %s", file, strerror(errno));
free(file);
+ file = NULL;
+ if (globres == 0)
+ goto found;
+ globfree(&globinfo);
}
+
if (res != NULL || ipath + 1 != paths->sz)
return -1;
@@ -823,81 +824,134 @@ fs_lookup(const struct manpaths *paths, size_t ipath,
found:
warnx("outdated mandoc.db lacks %s(%s) entry, run %s %s",
name, sec, BINM_MAKEWHATIS, paths->paths[ipath]);
- if (res == NULL) {
+ if (res == NULL)
free(file);
- return 0;
- }
- *res = mandoc_reallocarray(*res, ++*ressz, sizeof(**res));
- page = *res + (*ressz - 1);
- page->file = file;
- page->names = NULL;
- page->output = NULL;
- page->bits = NAME_FILE & NAME_MASK;
- page->ipath = ipath;
- page->sec = (*sec >= '1' && *sec <= '9') ? *sec - '1' + 1 : 10;
- page->form = form;
+ else if (file == NULL)
+ fs_append(globinfo.gl_pathv, globinfo.gl_pathc, 1,
+ ipath, sec, form, res, ressz);
+ else
+ fs_append(&file, 1, 0, ipath, sec, form, res, ressz);
+ globfree(&globinfo);
return 0;
}
static int
fs_search(const struct mansearch *cfg, const struct manpaths *paths,
- int argc, char **argv, struct manpage **res, size_t *ressz)
+ const char *name, struct manpage **res, size_t *ressz)
{
const char *const sections[] =
{"1", "8", "6", "2", "3", "5", "7", "4", "9", "3p"};
const size_t nsec = sizeof(sections)/sizeof(sections[0]);
- size_t ipath, isec, lastsz;
+ size_t ipath, isec;
assert(cfg->argmode == ARG_NAME);
-
if (res != NULL)
*res = NULL;
- *ressz = lastsz = 0;
- while (argc) {
- for (ipath = 0; ipath < paths->sz; ipath++) {
- if (cfg->sec != NULL) {
- if (fs_lookup(paths, ipath, cfg->sec,
- cfg->arch, *argv, res, ressz) != -1 &&
- cfg->firstmatch)
- return 0;
- } else for (isec = 0; isec < nsec; isec++)
+ *ressz = 0;
+ for (ipath = 0; ipath < paths->sz; ipath++) {
+ if (cfg->sec != NULL) {
+ if (fs_lookup(paths, ipath, cfg->sec, cfg->arch,
+ name, res, ressz) != -1 && cfg->firstmatch)
+ return 0;
+ } else {
+ for (isec = 0; isec < nsec; isec++)
if (fs_lookup(paths, ipath, sections[isec],
- cfg->arch, *argv, res, ressz) != -1 &&
+ cfg->arch, name, res, ressz) != -1 &&
cfg->firstmatch)
return 0;
}
- if (res != NULL && *ressz == lastsz &&
- strchr(*argv, '/') == NULL) {
- if (cfg->arch != NULL &&
- arch_valid(cfg->arch, OSENUM) == 0)
- warnx("Unknown architecture \"%s\".",
- cfg->arch);
- else if (cfg->sec == NULL)
- warnx("No entry for %s in the manual.",
- *argv);
- else
- warnx("No entry for %s in section %s "
- "of the manual.", *argv, cfg->sec);
- }
- lastsz = *ressz;
- argv++;
- argc--;
}
return -1;
}
static void
-parse(struct curparse *curp, int fd, const char *file)
+process_onefile(struct mparse *mp, struct manpage *resp, int startdir,
+ struct outstate *outst, struct manconf *conf)
{
- struct roff_meta *meta;
+ int fd;
+
+ /*
+ * Changing directories is not needed in ARG_FILE mode.
+ * Do it on a best-effort basis. Even in case of
+ * failure, some functionality may still work.
+ */
+ if (resp->ipath != SIZE_MAX)
+ (void)chdir(conf->manpath.paths[resp->ipath]);
+ else if (startdir != -1)
+ (void)fchdir(startdir);
+
+ mandoc_msg_setinfilename(resp->file);
+ if (resp->file != NULL) {
+ if ((fd = mparse_open(mp, resp->file)) == -1) {
+ mandoc_msg(resp->ipath == SIZE_MAX ?
+ MANDOCERR_BADARG_BAD : MANDOCERR_OPEN,
+ 0, 0, "%s", strerror(errno));
+ mandoc_msg_setinfilename(NULL);
+ return;
+ }
+ } else
+ fd = STDIN_FILENO;
+
+ if (outst->use_pager) {
+ outst->use_pager = 0;
+ outst->tag_files = term_tag_init(conf->output.outfilename,
+ outst->outtype == OUTT_HTML ? ".html" : "",
+ conf->output.tagfilename);
+#if HAVE_PLEDGE
+ if ((conf->output.outfilename != NULL ||
+ conf->output.tagfilename != NULL) &&
+ pledge("stdio rpath cpath", NULL) == -1) {
+ mandoc_msg(MANDOCERR_PLEDGE, 0, 0,
+ "%s", strerror(errno));
+ exit(mandoc_msg_getrc());
+ }
+#endif
+ }
+ if (outst->had_output && outst->outtype <= OUTT_UTF8) {
+ if (outst->outdata == NULL)
+ outdata_alloc(outst, &conf->output);
+ terminal_sepline(outst->outdata);
+ }
- /* Begin by parsing the file itself. */
+ if (resp->form == FORM_SRC)
+ parse(mp, fd, resp->file, outst, conf);
+ else {
+ passthrough(fd, conf->output.synopsisonly);
+ outst->had_output = 1;
+ }
+
+ if (ferror(stdout)) {
+ if (outst->tag_files != NULL) {
+ mandoc_msg(MANDOCERR_WRITE, 0, 0, "%s: %s",
+ outst->tag_files->ofn, strerror(errno));
+ term_tag_unlink();
+ outst->tag_files = NULL;
+ } else
+ mandoc_msg(MANDOCERR_WRITE, 0, 0, "%s",
+ strerror(errno));
+ }
+ mandoc_msg_setinfilename(NULL);
+}
+
+static void
+parse(struct mparse *mp, int fd, const char *file,
+ struct outstate *outst, struct manconf *conf)
+{
+ static struct manpaths basepaths;
+ static int previous;
+ struct roff_meta *meta;
- assert(file);
assert(fd >= 0);
+ if (file == NULL)
+ file = "<stdin>";
- mparse_readfd(curp->mp, fd, file);
+ if (previous)
+ mparse_reset(mp);
+ else
+ previous = 1;
+
+ mparse_readfd(mp, fd, file);
if (fd != STDIN_FILENO)
close(fd);
@@ -906,81 +960,89 @@ parse(struct curparse *curp, int fd, const char *file)
* level, do not produce output.
*/
- if (curp->wstop && mandoc_msg_getrc() != MANDOCLEVEL_OK)
+ if (outst->wstop && mandoc_msg_getrc() != MANDOCLEVEL_OK)
return;
- if (curp->outdata == NULL)
- outdata_alloc(curp);
- else if (curp->outtype == OUTT_HTML)
- html_reset(curp);
+ if (outst->outdata == NULL)
+ outdata_alloc(outst, &conf->output);
+ else if (outst->outtype == OUTT_HTML)
+ html_reset(outst->outdata);
mandoc_xr_reset();
- meta = mparse_result(curp->mp);
+ meta = mparse_result(mp);
/* Execute the out device, if it exists. */
+ outst->had_output = 1;
if (meta->macroset == MACROSET_MDOC) {
- switch (curp->outtype) {
+ switch (outst->outtype) {
case OUTT_HTML:
- html_mdoc(curp->outdata, meta);
+ html_mdoc(outst->outdata, meta);
break;
case OUTT_TREE:
- tree_mdoc(curp->outdata, meta);
+ tree_mdoc(outst->outdata, meta);
break;
case OUTT_MAN:
- man_mdoc(curp->outdata, meta);
+ man_mdoc(outst->outdata, meta);
break;
case OUTT_PDF:
case OUTT_ASCII:
case OUTT_UTF8:
case OUTT_LOCALE:
case OUTT_PS:
- terminal_mdoc(curp->outdata, meta);
+ terminal_mdoc(outst->outdata, meta);
break;
case OUTT_MARKDOWN:
- markdown_mdoc(curp->outdata, meta);
+ markdown_mdoc(outst->outdata, meta);
break;
default:
break;
}
}
if (meta->macroset == MACROSET_MAN) {
- switch (curp->outtype) {
+ switch (outst->outtype) {
case OUTT_HTML:
- html_man(curp->outdata, meta);
+ html_man(outst->outdata, meta);
break;
case OUTT_TREE:
- tree_man(curp->outdata, meta);
+ tree_man(outst->outdata, meta);
break;
case OUTT_MAN:
- mparse_copy(curp->mp);
+ mparse_copy(mp);
break;
case OUTT_PDF:
case OUTT_ASCII:
case OUTT_UTF8:
case OUTT_LOCALE:
case OUTT_PS:
- terminal_man(curp->outdata, meta);
+ terminal_man(outst->outdata, meta);
+ break;
+ case OUTT_MARKDOWN:
+ mandoc_msg(MANDOCERR_MAN_TMARKDOWN, 0, 0, NULL);
break;
default:
break;
}
}
- if (mandoc_msg_getmin() < MANDOCERR_STYLE)
- check_xr();
+ if (conf->output.tag != NULL && conf->output.tag_found == 0 &&
+ tag_exists(conf->output.tag))
+ conf->output.tag_found = 1;
+
+ if (mandoc_msg_getmin() < MANDOCERR_STYLE) {
+ if (basepaths.sz == 0)
+ manpath_base(&basepaths);
+ check_xr(&basepaths);
+ } else if (mandoc_msg_getmin() < MANDOCERR_WARNING)
+ check_xr(&conf->manpath);
}
static void
-check_xr(void)
+check_xr(struct manpaths *paths)
{
- static struct manpaths paths;
struct mansearch search;
struct mandoc_xr *xr;
size_t sz;
- if (paths.sz == 0)
- manpath_base(&paths);
-
for (xr = mandoc_xr_get(); xr != NULL; xr = xr->next) {
if (xr->line == -1)
continue;
@@ -989,9 +1051,9 @@ check_xr(void)
search.outkey = NULL;
search.argmode = ARG_NAME;
search.firstmatch = 1;
- if (mansearch(&search, &paths, 1, &xr->name, NULL, &sz))
+ if (mansearch(&search, paths, 1, &xr->name, NULL, &sz))
continue;
- if (fs_search(&search, &paths, 1, &xr->name, NULL, &sz) != -1)
+ if (fs_search(&search, paths, xr->name, NULL, &sz) != -1)
continue;
if (xr->count == 1)
mandoc_msg(MANDOCERR_XR_BAD, xr->line,
@@ -1004,26 +1066,26 @@ check_xr(void)
}
static void
-outdata_alloc(struct curparse *curp)
+outdata_alloc(struct outstate *outst, struct manoutput *outconf)
{
- switch (curp->outtype) {
+ switch (outst->outtype) {
case OUTT_HTML:
- curp->outdata = html_alloc(curp->outopts);
+ outst->outdata = html_alloc(outconf);
break;
case OUTT_UTF8:
- curp->outdata = utf8_alloc(curp->outopts);
+ outst->outdata = utf8_alloc(outconf);
break;
case OUTT_LOCALE:
- curp->outdata = locale_alloc(curp->outopts);
+ outst->outdata = locale_alloc(outconf);
break;
case OUTT_ASCII:
- curp->outdata = ascii_alloc(curp->outopts);
+ outst->outdata = ascii_alloc(outconf);
break;
case OUTT_PDF:
- curp->outdata = pdf_alloc(curp->outopts);
+ outst->outdata = pdf_alloc(outconf);
break;
case OUTT_PS:
- curp->outdata = ps_alloc(curp->outopts);
+ outst->outdata = ps_alloc(outconf);
break;
default:
break;
@@ -1093,7 +1155,7 @@ done:
}
static int
-woptions(struct curparse *curp, char *arg)
+woptions(char *arg, enum mandoc_os *os_e, int *wstop)
{
char *v, *o;
const char *toks[11];
@@ -1114,7 +1176,7 @@ woptions(struct curparse *curp, char *arg)
o = arg;
switch (getsubopt(&arg, (char * const *)toks, &v)) {
case 0:
- curp->wstop = 1;
+ *wstop = 1;
break;
case 1:
case 2:
@@ -1137,11 +1199,11 @@ woptions(struct curparse *curp, char *arg)
break;
case 8:
mandoc_msg_setmin(MANDOCERR_BASE);
- curp->os_e = MANDOC_OS_OPENBSD;
+ *os_e = MANDOC_OS_OPENBSD;
break;
case 9:
mandoc_msg_setmin(MANDOCERR_BASE);
- curp->os_e = MANDOC_OS_NETBSD;
+ *os_e = MANDOC_OS_NETBSD;
break;
default:
mandoc_msg(MANDOCERR_BADARG_BAD, 0, 0, "-W %s", o);
@@ -1151,8 +1213,66 @@ woptions(struct curparse *curp, char *arg)
return 0;
}
+/*
+ * Wait until moved to the foreground,
+ * then fork the pager and wait for the user to close it.
+ */
+static void
+run_pager(struct outstate *outst, char *tag_target)
+{
+ int signum, status;
+ pid_t man_pgid, tc_pgid;
+ pid_t pager_pid, wait_pid;
+
+ man_pgid = getpgid(0);
+ outst->tag_files->tcpgid =
+ man_pgid == getpid() ? getpgid(getppid()) : man_pgid;
+ pager_pid = 0;
+ signum = SIGSTOP;
+
+ for (;;) {
+ /* Stop here until moved to the foreground. */
+
+ tc_pgid = tcgetpgrp(STDOUT_FILENO);
+ if (tc_pgid != man_pgid) {
+ if (tc_pgid == pager_pid) {
+ (void)tcsetpgrp(STDOUT_FILENO, man_pgid);
+ if (signum == SIGTTIN)
+ continue;
+ } else
+ outst->tag_files->tcpgid = tc_pgid;
+ kill(0, signum);
+ continue;
+ }
+
+ /* Once in the foreground, activate the pager. */
+
+ if (pager_pid) {
+ (void)tcsetpgrp(STDOUT_FILENO, pager_pid);
+ kill(pager_pid, SIGCONT);
+ } else
+ pager_pid = spawn_pager(outst, tag_target);
+
+ /* Wait for the pager to stop or exit. */
+
+ while ((wait_pid = waitpid(pager_pid, &status,
+ WUNTRACED)) == -1 && errno == EINTR)
+ continue;
+
+ if (wait_pid == -1) {
+ mandoc_msg(MANDOCERR_WAIT, 0, 0,
+ "%s", strerror(errno));
+ break;
+ }
+ if (!WIFSTOPPED(status))
+ break;
+
+ signum = WSTOPSIG(status);
+ }
+}
+
static pid_t
-spawn_pager(struct tag_files *tag_files)
+spawn_pager(struct outstate *outst, char *tag_target)
{
const struct timespec timeout = { 0, 100000000 }; /* 0.1s */
#define MAX_PAGER_ARGS 16
@@ -1165,11 +1285,14 @@ spawn_pager(struct tag_files *tag_files)
int argc, use_ofn;
pid_t pager_pid;
+ assert(outst->tag_files->ofd == -1);
+ assert(outst->tag_files->tfs == NULL);
+
pager = getenv("MANPAGER");
if (pager == NULL || *pager == '\0')
pager = getenv("PAGER");
if (pager == NULL || *pager == '\0')
- pager = "more -s";
+ pager = BINM_PAGER;
cp = mandoc_strdup(pager);
/*
@@ -1194,21 +1317,28 @@ spawn_pager(struct tag_files *tag_files)
use_ofn = 1;
#if HAVE_LESS_T
- if (*tag_files->tfn != '\0' && (cmdlen = strlen(argv[0])) >= 4) {
+ if (*outst->tag_files->tfn != '\0' &&
+ (cmdlen = strlen(argv[0])) >= 4) {
cp = argv[0] + cmdlen - 4;
if (strcmp(cp, "less") == 0) {
argv[argc++] = mandoc_strdup("-T");
- argv[argc++] = tag_files->tfn;
- if (tag_files->tagname != NULL) {
+ argv[argc++] = outst->tag_files->tfn;
+ if (tag_target != NULL) {
argv[argc++] = mandoc_strdup("-t");
- argv[argc++] = tag_files->tagname;
+ argv[argc++] = tag_target;
use_ofn = 0;
}
}
}
#endif
- if (use_ofn)
- argv[argc++] = tag_files->ofn;
+ if (use_ofn) {
+ if (outst->outtype == OUTT_HTML && tag_target != NULL)
+ mandoc_asprintf(&argv[argc], "file://%s#%s",
+ outst->tag_files->ofn, tag_target);
+ else
+ argv[argc] = outst->tag_files->ofn;
+ argc++;
+ }
argv[argc] = NULL;
switch (pager_pid = fork()) {
@@ -1219,7 +1349,7 @@ spawn_pager(struct tag_files *tag_files)
break;
default:
(void)setpgid(pager_pid, 0);
- (void)tcsetpgrp(tag_files->ofd, pager_pid);
+ (void)tcsetpgrp(STDOUT_FILENO, pager_pid);
#if HAVE_PLEDGE
if (pledge("stdio rpath tmppath tty proc", NULL) == -1) {
mandoc_msg(MANDOCERR_PLEDGE, 0, 0,
@@ -1227,20 +1357,14 @@ spawn_pager(struct tag_files *tag_files)
exit(mandoc_msg_getrc());
}
#endif
- tag_files->pager_pid = pager_pid;
+ outst->tag_files->pager_pid = pager_pid;
return pager_pid;
}
- /* The child process becomes the pager. */
-
- if (dup2(tag_files->ofd, STDOUT_FILENO) == -1) {
- mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno));
- _exit(mandoc_msg_getrc());
- }
- close(tag_files->ofd);
- assert(tag_files->tfd == -1);
-
- /* Do not start the pager before controlling the terminal. */
+ /*
+ * The child process becomes the pager.
+ * Do not start it before controlling the terminal.
+ */
while (tcgetpgrp(STDOUT_FILENO) != getpid())
nanosleep(&timeout, NULL);
diff --git a/man.1 b/man.1
index 0d2976bab795..d3a54c6a235c 100644
--- a/man.1
+++ b/man.1
@@ -1,9 +1,9 @@
-.\" $Id: man.1,v 1.35 2019/03/09 15:55:01 schwarze Exp $
+.\" $Id: man.1,v 1.40 2020/07/20 16:57:30 schwarze Exp $
.\"
.\" Copyright (c) 1989, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\" Copyright (c) 2003, 2007, 2008, 2014 Jason McIntyre <jmc@openbsd.org>
-.\" Copyright (c) 2010, 2011, 2014-2018 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2010, 2011, 2014-2020 Ingo Schwarze <schwarze@openbsd.org>
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@@ -31,7 +31,7 @@
.\"
.\" @(#)man.1 8.2 (Berkeley) 1/2/94
.\"
-.Dd $Mdocdate: March 9 2019 $
+.Dd $Mdocdate: July 20 2020 $
.Dt MAN 1
.Os
.Sh NAME
@@ -51,7 +51,7 @@ The
.Nm
utility
displays the
-manual pages entitled
+manual page entitled
.Ar name .
Pages may be selected according to
a specific category
@@ -64,7 +64,6 @@ The options are as follows:
.Bl -tag -width Ds
.It Fl a
Display all matching manual pages.
-Normally, only the first page found is displayed.
.It Fl C Ar file
Use the specified
.Ar file
@@ -75,7 +74,7 @@ See
for a description of the contents of this file.
.It Fl c
Copy the manual page to the standard output instead of using
-.Xr more 1
+.Xr less 1
to paginate it.
This is done by default if the standard output is not a terminal device.
.Pp
@@ -129,31 +128,31 @@ are ignored.
This option implies
.Fl a .
.It Fl M Ar path
-Override the list of standard directories which
-.Nm
-searches for manual pages.
+Override the list of directories to search for manual pages.
The supplied
.Ar path
must be a colon
.Pq Ql \&:
separated list of directories.
-This search path may also be set using the environment variable
-.Ev MANPATH .
+This option also overrides the environment variable
+.Ev MANPATH
+and any directories specified in the
+.Xr man.conf 5
+file.
.It Fl m Ar path
-Augment the list of standard directories which
-.Nm
-searches for manual pages.
+Augment the list of directories to search for manual pages.
The supplied
.Ar path
must be a colon
.Pq Ql \&:
separated list of directories.
-These directories will be searched before the standard directories or
-the directories specified using the
+These directories will be searched before those specified using the
.Fl M
-option or the
+option, the
.Ev MANPATH
-environment variable.
+environment variable, the
+.Xr man.conf 5
+file, or the default directories.
.It Fl S Ar subsection
Only show pages for the specified
.Xr machine 1
@@ -168,6 +167,7 @@ architecture whilst using another.
This option overrides the
.Ev MACHINE
environment variable.
+.Tg s
.It Oo Fl s Oc Ar section
Only select manuals from the specified
.Ar section .
@@ -197,13 +197,12 @@ System maintenance and operation commands.
.It 9
Kernel internals.
.El
-.Pp
-If not specified and a match is found in more than one section,
-the first match is selected from the following list:
-1, 8, 6, 2, 3, 5, 7, 4, 9, 3p.
.It Fl w
List the pathnames of all matching manual pages instead of displaying
any of them.
+If no
+.Ar name
+is given, list the directories that would be searched.
.El
.Pp
The options
@@ -214,9 +213,23 @@ The options
.Fl fkl
are mutually exclusive and override each other.
.Pp
-Guidelines for writing
-man pages can be found in
-.Xr mdoc 7 .
+The search starts with the
+.Fl m
+argument if provided, then continues with the
+.Fl M
+argument, the
+.Ev MANPATH
+variable, the
+.Ic manpath
+entries in the
+.Xr man.conf 5
+file, or with
+.Pa /usr/share/man : Ns Pa /usr/X11R6/man : Ns Pa /usr/local/man
+by default.
+Within each of these, directories are searched in the order provided.
+Within each directory, the search proceeds according to the following
+list of sections: 1, 8, 6, 2, 3, 5, 7, 4, 9, 3p.
+The first match found is shown.
.Pp
The
.Xr mandoc.db 5
@@ -236,6 +249,10 @@ The database is kept up to date with
which is run by the
.Xr weekly 8
maintenance script.
+.Pp
+Guidelines for writing
+man pages can be found in
+.Xr mdoc 7 .
.Sh ENVIRONMENT
.Bl -tag -width MANPATHX
.It Ev MACHINE
@@ -258,7 +275,7 @@ is case insensitive.
Any non-empty value of the environment variable
.Ev MANPAGER
is used instead of the standard pagination program,
-.Xr more 1 .
+.Xr less 1 .
If
.Xr less 1
is used, the interactive
@@ -286,15 +303,15 @@ manual opens a manual page at the definition of a specific
.Ar term
rather than at the beginning.
.It Ev MANPATH
-The standard search path used by
-.Nm
-may be changed by specifying a path in the
+Override the standard search path which is either specified in
+.Xr man.conf 5
+or the default path.
+The format of
.Ev MANPATH
-environment variable.
-The format of the path is a colon
+is a colon
.Pq Ql \&:
separated list of directories.
-Invalid paths are ignored.
+Invalid directories are ignored.
Overridden by
.Fl M ,
ignored if
@@ -303,25 +320,24 @@ is specified.
.Pp
If
.Ev MANPATH
-begins with a colon, it is appended to the default list;
-if it ends with a colon, it is prepended to the default list;
+begins with a colon, it is appended to the standard path;
+if it ends with a colon, it is prepended to the standard path;
or if it contains two adjacent colons,
-the standard search path is inserted between the colons.
-If none of these conditions are met, it overrides the
-standard search path.
+the standard path is inserted between the colons.
.It Ev PAGER
Specifies the pagination program to use when
.Ev MANPAGER
is not defined.
If neither PAGER nor MANPAGER is defined,
-.Xr more 1
-.Fl s
+.Xr less 1
is used.
.El
.Sh FILES
.Bl -tag -width /etc/man.conf -compact
.It Pa /etc/man.conf
-default man configuration file
+default
+.Nm
+configuration file
.El
.Sh EXIT STATUS
.Ex -std man
@@ -365,7 +381,7 @@ are extensions to that specification.
A
.Nm
command first appeared in
-.At v3 .
+.At v2 .
.Pp
The
.Fl w
diff --git a/man.7 b/man.7
index 6b4bece71433..cca9c1fe3520 100644
--- a/man.7
+++ b/man.7
@@ -1,7 +1,7 @@
-.\" $Id: man.7,v 1.144 2019/07/09 03:46:59 schwarze Exp $
+.\" $Id: man.7,v 1.148 2021/08/05 14:31:14 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright (c) 2011-2015,2017,2018,2019 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2011-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org>
.\" Copyright (c) 2017 Anthony Bentley <bentley@openbsd.org>
.\" Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
.\"
@@ -17,7 +17,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: July 9 2019 $
+.Dd $Mdocdate: August 5 2021 $
.Dt MAN 7
.Os
.Sh NAME
@@ -127,6 +127,8 @@ Sets the volume for the footer for compatibility with man pages from
.At
releases.
The optional arguments specify which release it is from.
+This macro is an extension that first appeared in
+.Bx 4.3 .
.It Ic B
Text is rendered in bold face.
.It Ic BI
@@ -244,7 +246,7 @@ link description to be shown
.Ed
.It Ic OP
Optional command-line argument.
-This is a non-standard GNU extension.
+This is a non-standard DWB extension.
It has the following syntax:
.Pp
.D1 Pf . Ic OP Ar key Op Ar value
@@ -255,8 +257,12 @@ is usually a command-line flag and
.Ar value
its argument.
.It Ic P
-A synonym for
-.Ic PP .
+This synonym for
+.Ic PP
+is an
+.At III
+extension later adopted by
+.Bx 4.3 .
.It Ic PD
Specify the vertical space to be inserted before each new paragraph.
.br
@@ -343,6 +349,9 @@ See also
.It Ic SB
Text is rendered in small size (one point smaller than the default font)
bold face.
+This macro is an extension that probably first appeared in SunOS 4.0
+and was later adopted by GNU and by
+.Bx 4.4 .
.It Ic SH
Begin a section.
The scope of a section is only closed by another section or the end of
@@ -435,6 +444,8 @@ Sets the volume for the footer for compatibility with man pages from
.Bx
releases.
The optional first argument specifies which release it is from.
+This macro is an extension that first appeared in
+.Bx 3 .
.It Ic UE
End a uniform resource identifier block started with
.Ic UR .
@@ -505,7 +516,7 @@ The syntax is as follows:
.It Ic I Ta n Ta next-line Ta \&
.It Ic IB Ta n Ta current Ta \&
.It Ic IR Ta n Ta current Ta \&
-.It Ic OP Ta >=1 Ta current Ta GNU
+.It Ic OP Ta >=1 Ta current Ta DWB
.It Ic PD Ta 1 Ta current Ta \&
.It Ic RB Ta n Ta current Ta \&
.It Ic RI Ta n Ta current Ta \&
@@ -601,16 +612,32 @@ The
language first appeared as a macro package for the roff typesetting
system in
.At v7 .
-It was later rewritten by James Clark as a macro package for groff.
-Eric S. Raymond wrote the extended
-.Nm
-macros for groff in 2007.
+.Pp
The stand-alone implementation that is part of the
.Xr mandoc 1
-utility written by Kristaps Dzonsons appeared in
+utility first appeared in
.Ox 4.6 .
.Sh AUTHORS
-This
+.An -nosplit
+.An Douglas McIlroy Aq Mt m.douglas.mcilroy@dartmouth.edu
+designed and implemented the original version of these macros,
+wrote the original version of this manual page,
+and was the first to use them when he edited volume 1 of the
+.At v7
+manual pages.
+.Pp
+.An James Clark
+later rewrote the macros for groff.
+.An Eric S. Raymond Aq Mt esr@thyrsus.com
+and
+.An Werner Lemberg Aq Mt wl@gnu.org
+added the extended
+.Nm
+macros to groff in 2007.
+.Pp
+The
+.Xr mandoc 1
+program and this
.Nm
-reference was written by
+reference were written by
.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
diff --git a/man.conf.5 b/man.conf.5
index 0ffe868ad764..ffe9fcc07058 100644
--- a/man.conf.5
+++ b/man.conf.5
@@ -1,4 +1,4 @@
-.\" $Id: man.conf.5,v 1.6 2018/10/02 14:56:47 schwarze Exp $
+.\" $Id: man.conf.5,v 1.8 2020/02/10 14:42:10 schwarze Exp $
.\"
.\" Copyright (c) 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
.\"
@@ -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: October 2 2018 $
+.Dd $Mdocdate: February 10 2020 $
.Dt MAN.CONF 5
.Os
.Sh NAME
@@ -101,15 +101,11 @@ manual.
.It Ic toc Ta none Ta Cm html Ta print table of contents
.It Ic width Ta integer Ta Cm ascii , utf8 Ta right margin
.El
-.It Ic _whatdb Ar path Ns Cm /whatis.db
-This directive provides the same functionality as
-.Ic manpath ,
-but using a historic and misleading syntax.
-It is kept for backward compatibility for now,
-but will eventually be removed.
.El
.Sh FILES
-.Pa /etc/man.conf
+.Bl -tag -width /etc/examples/man.conf -compact
+.It Pa /etc/man.conf
+.El
.Sh EXAMPLES
The following configuration file reproduces the defaults:
installing it is equivalent to not having a
diff --git a/man_html.c b/man_html.c
index c0a429c5d6c9..147c20e46443 100644
--- a/man_html.c
+++ b/man_html.c
@@ -1,7 +1,7 @@
-/* $Id: man_html.c,v 1.174 2019/04/30 15:53:00 schwarze Exp $ */
+/* $Id: man_html.c,v 1.179 2020/10/16 17:22:43 schwarze Exp $ */
/*
+ * Copyright (c) 2013-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,6 +14,8 @@
* 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.
+ *
+ * HTML formatter for man(7) used by mandoc(1).
*/
#include "config.h"
@@ -34,7 +36,7 @@
#include "main.h"
#define MAN_ARGS const struct roff_meta *man, \
- const struct roff_node *n, \
+ struct roff_node *n, \
struct html *h
struct man_html_act {
@@ -167,7 +169,12 @@ print_man_node(MAN_ARGS)
if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
return;
- html_fillmode(h, n->flags & NODE_NOFILL ? ROFF_nf : ROFF_fi);
+ if ((n->flags & NODE_NOFILL) == 0)
+ html_fillmode(h, ROFF_fi);
+ else if (html_fillmode(h, ROFF_nf) == ROFF_nf &&
+ n->tok != ROFF_fi && n->flags & NODE_LINE &&
+ (n->prev == NULL || n->prev->tok != MAN_YS))
+ print_endline(h);
child = 1;
switch (n->type) {
@@ -178,7 +185,7 @@ print_man_node(MAN_ARGS)
}
if (*n->string == ' ' && n->flags & NODE_LINE &&
(h->flags & HTML_NONEWLINE) == 0)
- print_endline(h);
+ print_otag(h, TAG_BR, "");
else if (n->flags & NODE_DELIMC)
h->flags |= HTML_NOSPACE;
t = h->tag;
@@ -244,20 +251,13 @@ print_man_node(MAN_ARGS)
* Close the list if no further item of the same type
* follows; otherwise, close the item only.
*/
- if (list_continues(n, n->next) == '\0') {
+ if (list_continues(n, roff_node_next(n)) == '\0') {
print_tagq(h, t);
t = NULL;
}
}
if (t != NULL)
print_stagq(h, t);
-
- if (n->flags & NODE_NOFILL && n->tok != MAN_YS &&
- (n->next != NULL && n->next->flags & NODE_LINE)) {
- /* In .nf = <pre>, print even empty lines. */
- h->col++;
- print_endline(h);
- }
}
static void
@@ -310,7 +310,6 @@ static int
man_SH_pre(MAN_ARGS)
{
const char *class;
- char *id;
enum htmltag tag;
if (n->tok == MAN_SH) {
@@ -326,10 +325,7 @@ man_SH_pre(MAN_ARGS)
print_otag(h, TAG_SECTION, "c", class);
break;
case ROFFT_HEAD:
- id = html_make_id(n, 1);
- print_otag(h, tag, "ci", class, id);
- if (id != NULL)
- print_otag(h, TAG_A, "chR", "permalink", id);
+ print_otag_id(h, tag, class, n);
break;
case ROFFT_BODY:
break;
@@ -445,15 +441,17 @@ list_continues(const struct roff_node *n1, const struct roff_node *n2)
static int
man_IP_pre(MAN_ARGS)
{
- const struct roff_node *nn;
+ struct roff_node *nn;
const char *list_class;
enum htmltag list_elem, body_elem;
char list_type;
nn = n->type == ROFFT_BLOCK ? n : n->parent;
- if ((list_type = list_continues(nn->prev, nn)) == '\0') {
+ list_type = list_continues(roff_node_prev(nn), nn);
+ if (list_type == '\0') {
/* Start a new list. */
- if ((list_type = list_continues(nn, nn->next)) == '\0')
+ list_type = list_continues(nn, roff_node_next(nn));
+ if (list_type == '\0')
list_type = ' ';
switch (list_type) {
case ' ':
@@ -487,7 +485,7 @@ man_IP_pre(MAN_ARGS)
case ROFFT_HEAD:
if (body_elem == TAG_LI)
return 0;
- print_otag(h, TAG_DT, "");
+ print_otag_id(h, TAG_DT, NULL, n);
break;
case ROFFT_BODY:
print_otag(h, body_elem, "");
@@ -495,7 +493,6 @@ man_IP_pre(MAN_ARGS)
default:
abort();
}
-
switch(n->tok) {
case MAN_IP: /* Only print the first header element. */
if (n->child != NULL)
diff --git a/man_macro.c b/man_macro.c
index d195576dee28..b3c3a3cb488b 100644
--- a/man_macro.c
+++ b/man_macro.c
@@ -1,7 +1,7 @@
-/* $Id: man_macro.c,v 1.144 2019/01/05 18:59:46 schwarze Exp $ */
+/* $Id: man_macro.c,v 1.145 2020/09/09 17:01:10 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2012-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2012-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -107,9 +107,11 @@ man_unscope(struct roff_man *man, const struct roff_node *to)
mandoc_msg(MANDOCERR_BLK_LINE,
n->line, n->pos,
"EOF breaks %s", roff_name[n->tok]);
- if (man->flags & MAN_ELINE)
- man->flags &= ~MAN_ELINE;
- else {
+ if (man->flags & MAN_ELINE) {
+ if ((man_macro(n->parent->tok)->flags &
+ MAN_ESCOPED) == 0)
+ man->flags &= ~MAN_ELINE;
+ } else {
assert(n->type == ROFFT_HEAD);
n = n->parent;
man->flags &= ~MAN_BLINE;
diff --git a/man_term.c b/man_term.c
index d9ee14ad22ba..d289f2d12bfb 100644
--- a/man_term.c
+++ b/man_term.c
@@ -1,7 +1,7 @@
-/* $Id: man_term.c,v 1.232 2019/07/23 17:53:35 schwarze Exp $ */
+/* $Id: man_term.c,v 1.236 2021/06/28 19:50:15 schwarze Exp $ */
/*
+ * Copyright (c) 2010-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,6 +14,9 @@
* 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.
+ *
+ * Plain text formatter for man(7), used by mandoc(1)
+ * for ASCII, UTF-8, PostScript, and PDF output.
*/
#include "config.h"
@@ -32,7 +35,7 @@
#include "man.h"
#include "out.h"
#include "term.h"
-#include "tag.h"
+#include "term_tag.h"
#include "main.h"
#define MAXMARGINS 64 /* maximum number of indented scopes */
@@ -64,7 +67,7 @@ static void print_man_head(struct termp *,
static void print_man_foot(struct termp *,
const struct roff_meta *);
static void print_bvspace(struct termp *,
- const struct roff_node *, int);
+ struct roff_node *, int);
static int pre_B(DECL_ARGS);
static int pre_DT(DECL_ARGS);
@@ -94,8 +97,6 @@ static void post_SY(DECL_ARGS);
static void post_TP(DECL_ARGS);
static void post_UR(DECL_ARGS);
-static void tag_man(struct termp *, struct roff_node *);
-
static const struct man_term_act man_term_acts[MAN_MAX - MAN_TH] = {
{ NULL, NULL, 0 }, /* TH */
{ pre_SH, post_SH, 0 }, /* SH */
@@ -205,19 +206,20 @@ terminal_man(void *arg, const struct roff_meta *man)
* first, print it.
*/
static void
-print_bvspace(struct termp *p, const struct roff_node *n, int pardist)
+print_bvspace(struct termp *p, struct roff_node *n, int pardist)
{
- int i;
+ struct roff_node *nch;
+ int i;
term_newln(p);
- if (n->body != NULL && n->body->child != NULL)
- if (n->body->child->type == ROFFT_TBL)
- return;
+ if (n->body != NULL &&
+ (nch = roff_node_child(n->body)) != NULL &&
+ nch->type == ROFFT_TBL)
+ return;
- if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS)
- if (n->prev == NULL)
- return;
+ if (n->parent->tok != MAN_RS && roff_node_prev(n) == NULL)
+ return;
for (i = 0; i < pardist; i++)
term_vspace(p);
@@ -538,10 +540,8 @@ pre_IP(DECL_ARGS)
case ROFFT_HEAD:
p->tcol->offset = mt->offset;
p->tcol->rmargin = mt->offset + len;
- if (n->child != NULL) {
+ if (n->child != NULL)
print_man_node(p, mt, n->child, meta);
- tag_man(p, n->child);
- }
return 0;
case ROFFT_BODY:
p->tcol->offset = mt->offset + len;
@@ -621,18 +621,6 @@ pre_TP(DECL_ARGS)
while (nn != NULL && (nn->flags & NODE_LINE) == 0)
nn = nn->next;
- if (nn == NULL)
- return 0;
-
- if (nn->type == ROFFT_TEXT)
- tag_man(p, nn);
- else if (nn->child != NULL &&
- nn->child->type == ROFFT_TEXT &&
- (nn->tok == MAN_B || nn->tok == MAN_BI ||
- nn->tok == MAN_BR || nn->tok == MAN_I ||
- nn->tok == MAN_IB || nn->tok == MAN_IR))
- tag_man(p, nn->child);
-
while (nn != NULL) {
print_man_node(p, mt, nn, meta);
nn = nn->next;
@@ -683,12 +671,8 @@ pre_SS(DECL_ARGS)
* and after an empty subsection.
*/
- do {
- n = n->prev;
- } while (n != NULL && n->tok >= MAN_TH &&
- man_term_act(n->tok)->flags & MAN_NOTEXT);
- if (n == NULL || n->type == ROFFT_COMMENT ||
- (n->tok == MAN_SS && n->body->child == NULL))
+ if ((n = roff_node_prev(n)) == NULL ||
+ (n->tok == MAN_SS && roff_node_child(n->body) == NULL))
break;
for (i = 0; i < mt->pardist; i++)
@@ -728,12 +712,8 @@ pre_SH(DECL_ARGS)
* and after an empty section.
*/
- do {
- n = n->prev;
- } while (n != NULL && n->tok >= MAN_TH &&
- man_term_act(n->tok)->flags & MAN_NOTEXT);
- if (n == NULL || n->type == ROFFT_COMMENT ||
- (n->tok == MAN_SH && n->body->child == NULL))
+ if ((n = roff_node_prev(n)) == NULL ||
+ (n->tok == MAN_SH && roff_node_child(n->body) == NULL))
break;
for (i = 0; i < mt->pardist; i++)
@@ -839,7 +819,7 @@ pre_SY(DECL_ARGS)
switch (n->type) {
case ROFFT_BLOCK:
- if (n->prev == NULL || n->prev->tok != MAN_SY)
+ if ((nn = roff_node_prev(n)) == NULL || nn->tok != MAN_SY)
print_bvspace(p, n, mt->pardist);
return 1;
case ROFFT_HEAD:
@@ -920,6 +900,9 @@ print_man_node(DECL_ARGS)
const struct man_term_act *act;
int c;
+ if (n->flags & NODE_ID)
+ term_tag_write(n, p->line);
+
switch (n->type) {
case ROFFT_TEXT:
/*
@@ -1038,10 +1021,6 @@ print_man_foot(struct termp *p, const struct roff_meta *meta)
*/
if ( ! p->mdocstyle) {
- if (meta->hasbody) {
- term_vspace(p);
- term_vspace(p);
- }
mandoc_asprintf(&title, "%s(%s)",
meta->title, meta->msec);
} else if (meta->os != NULL) {
@@ -1160,66 +1139,5 @@ print_man_head(struct termp *p, const struct roff_meta *meta)
*/
term_vspace(p);
- if ( ! p->mdocstyle) {
- term_vspace(p);
- term_vspace(p);
- }
free(title);
}
-
-/*
- * Skip leading whitespace, dashes, backslashes, and font escapes,
- * then create a tag if the first following byte is a letter.
- * Priority is high unless whitespace is present.
- */
-static void
-tag_man(struct termp *p, struct roff_node *n)
-{
- const char *cp, *arg;
- int prio, sz;
-
- assert(n->type == ROFFT_TEXT);
- cp = n->string;
- prio = 1;
- for (;;) {
- switch (*cp) {
- case ' ':
- case '\t':
- prio = INT_MAX;
- /* FALLTHROUGH */
- case '-':
- cp++;
- break;
- case '\\':
- cp++;
- switch (mandoc_escape(&cp, &arg, &sz)) {
- case ESCAPE_FONT:
- case ESCAPE_FONTROMAN:
- case ESCAPE_FONTITALIC:
- case ESCAPE_FONTBOLD:
- case ESCAPE_FONTPREV:
- case ESCAPE_FONTBI:
- break;
- case ESCAPE_SPECIAL:
- if (sz != 1)
- return;
- switch (*arg) {
- case '&':
- case '-':
- case 'e':
- break;
- default:
- return;
- }
- break;
- default:
- return;
- }
- break;
- default:
- if (isalpha((unsigned char)*cp))
- tag_put(cp, prio, p->line);
- return;
- }
- }
-}
diff --git a/man_validate.c b/man_validate.c
index 0aa550bd08d9..404b223f2b54 100644
--- a/man_validate.c
+++ b/man_validate.c
@@ -1,7 +1,7 @@
-/* $Id: man_validate.c,v 1.149 2019/06/27 15:07:30 schwarze Exp $ */
+/* $Id: man_validate.c,v 1.156 2021/08/10 12:55:03 schwarze Exp $ */
/*
+ * Copyright (c) 2010, 2012-2020 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012-2018 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,6 +14,8 @@
* 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.
+ *
+ * Validation module for man(7) syntax trees used by mandoc(1).
*/
#include "config.h"
@@ -36,6 +38,7 @@
#include "libmandoc.h"
#include "roff_int.h"
#include "libman.h"
+#include "tag.h"
#define CHKARGS struct roff_man *man, struct roff_node *n
@@ -45,6 +48,7 @@ static void check_abort(CHKARGS) __attribute__((__noreturn__));
static void check_par(CHKARGS);
static void check_part(CHKARGS);
static void check_root(CHKARGS);
+static void check_tag(struct roff_node *, struct roff_node *);
static void check_text(CHKARGS);
static void post_AT(CHKARGS);
@@ -54,6 +58,7 @@ static void post_IP(CHKARGS);
static void post_OP(CHKARGS);
static void post_SH(CHKARGS);
static void post_TH(CHKARGS);
+static void post_TP(CHKARGS);
static void post_UC(CHKARGS);
static void post_UR(CHKARGS);
static void post_in(CHKARGS);
@@ -62,8 +67,8 @@ static const v_check man_valids[MAN_MAX - MAN_TH] = {
post_TH, /* TH */
post_SH, /* SH */
post_SH, /* SS */
- NULL, /* TP */
- NULL, /* TQ */
+ post_TP, /* TP */
+ post_TP, /* TQ */
check_abort,/* LP */
check_par, /* PP */
check_abort,/* P */
@@ -185,7 +190,7 @@ check_root(CHKARGS)
man->meta.title = mandoc_strdup("");
man->meta.msec = mandoc_strdup("");
- man->meta.date = mandoc_normdate(man, NULL, n->line, n->pos);
+ man->meta.date = mandoc_normdate(NULL, NULL);
}
if (man->meta.os_e &&
@@ -201,6 +206,68 @@ check_abort(CHKARGS)
abort();
}
+/*
+ * Skip leading whitespace, dashes, backslashes, and font escapes,
+ * then create a tag if the first following byte is a letter.
+ * Priority is high unless whitespace is present.
+ */
+static void
+check_tag(struct roff_node *n, struct roff_node *nt)
+{
+ const char *cp, *arg;
+ int prio, sz;
+
+ if (nt == NULL || nt->type != ROFFT_TEXT)
+ return;
+
+ cp = nt->string;
+ prio = TAG_STRONG;
+ for (;;) {
+ switch (*cp) {
+ case ' ':
+ case '\t':
+ prio = TAG_WEAK;
+ /* FALLTHROUGH */
+ case '-':
+ cp++;
+ break;
+ case '\\':
+ cp++;
+ switch (mandoc_escape(&cp, &arg, &sz)) {
+ case ESCAPE_FONT:
+ case ESCAPE_FONTBOLD:
+ case ESCAPE_FONTITALIC:
+ case ESCAPE_FONTBI:
+ case ESCAPE_FONTROMAN:
+ case ESCAPE_FONTCR:
+ case ESCAPE_FONTCB:
+ case ESCAPE_FONTCI:
+ case ESCAPE_FONTPREV:
+ case ESCAPE_IGNORE:
+ break;
+ case ESCAPE_SPECIAL:
+ if (sz != 1)
+ return;
+ switch (*arg) {
+ case '-':
+ case 'e':
+ break;
+ default:
+ return;
+ }
+ break;
+ default:
+ return;
+ }
+ break;
+ default:
+ if (isalpha((unsigned char)*cp))
+ tag_put(cp, prio, n);
+ return;
+ }
+ }
+}
+
static void
check_text(CHKARGS)
{
@@ -246,9 +313,32 @@ static void
post_SH(CHKARGS)
{
struct roff_node *nc;
+ char *cp, *tag;
- if (n->type != ROFFT_BODY || (nc = n->child) == NULL)
+ nc = n->child;
+ switch (n->type) {
+ case ROFFT_HEAD:
+ tag = NULL;
+ deroff(&tag, n);
+ if (tag != NULL) {
+ for (cp = tag; *cp != '\0'; cp++)
+ if (*cp == ' ')
+ *cp = '_';
+ if (nc != NULL && nc->type == ROFFT_TEXT &&
+ strcmp(nc->string, tag) == 0)
+ tag_put(NULL, TAG_STRONG, n);
+ else
+ tag_put(tag, TAG_FALLBACK, n);
+ free(tag);
+ }
+ return;
+ case ROFFT_BODY:
+ if (nc != NULL)
+ break;
return;
+ default:
+ return;
+ }
if (nc->tok == MAN_PP && nc->body->child != NULL) {
while (nc->body->last != NULL) {
@@ -332,12 +422,14 @@ check_par(CHKARGS)
static void
post_IP(CHKARGS)
{
-
switch (n->type) {
case ROFFT_BLOCK:
if (n->head->child == NULL && n->body->child == NULL)
roff_node_delete(man, n);
break;
+ case ROFFT_HEAD:
+ check_tag(n, n->child);
+ break;
case ROFFT_BODY:
if (n->parent->head->child == NULL && n->child == NULL)
mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos,
@@ -348,6 +440,37 @@ post_IP(CHKARGS)
}
}
+/*
+ * The first next-line element in the head is the tag.
+ * If that's a font macro, use its first child instead.
+ */
+static void
+post_TP(CHKARGS)
+{
+ struct roff_node *nt;
+
+ if (n->type != ROFFT_HEAD || (nt = n->child) == NULL)
+ return;
+
+ while ((nt->flags & NODE_LINE) == 0)
+ if ((nt = nt->next) == NULL)
+ return;
+
+ switch (nt->tok) {
+ case MAN_B:
+ case MAN_BI:
+ case MAN_BR:
+ case MAN_I:
+ case MAN_IB:
+ case MAN_IR:
+ nt = nt->child;
+ break;
+ default:
+ break;
+ }
+ check_tag(n, nt);
+}
+
static void
post_TH(CHKARGS)
{
@@ -389,9 +512,14 @@ post_TH(CHKARGS)
if (n != NULL)
n = n->next;
- if (n != NULL && n->string != NULL)
+ if (n != NULL && n->string != NULL) {
man->meta.msec = mandoc_strdup(n->string);
- else {
+ if (man->filesec != '\0' &&
+ man->filesec != *n->string &&
+ *n->string >= '1' && *n->string <= '9')
+ mandoc_msg(MANDOCERR_MSEC_FILE, n->line, n->pos,
+ "*.%c vs TH ... %c", man->filesec, *n->string);
+ } else {
man->meta.msec = mandoc_strdup("");
mandoc_msg(MANDOCERR_MSEC_MISSING,
nb->line, nb->pos, "TH %s", man->meta.title);
@@ -401,15 +529,10 @@ post_TH(CHKARGS)
if (n != NULL)
n = n->next;
- if (n != NULL && n->string != NULL && n->string[0] != '\0')
- man->meta.date = mandoc_normdate(man,
- n->string, n->line, n->pos);
- else {
+ if (man->quick && n != NULL)
man->meta.date = mandoc_strdup("");
- mandoc_msg(MANDOCERR_DATE_MISSING,
- n == NULL ? nb->line : n->line,
- n == NULL ? nb->pos : n->pos, "TH");
- }
+ else
+ man->meta.date = mandoc_normdate(n, nb);
/* TITLE MSEC DATE ->OS<- VOL */
diff --git a/manconf.h b/manconf.h
index bb3761998c88..c84409d7b570 100644
--- a/manconf.h
+++ b/manconf.h
@@ -1,6 +1,6 @@
-/* $Id: manconf.h,v 1.7 2018/11/22 11:30:23 schwarze Exp $ */
+/* $OpenBSD: manconf.h,v 1.7 2018/11/22 11:30:15 schwarze Exp $ */
/*
- * Copyright (c) 2011, 2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011,2015,2017,2018,2020 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -14,6 +14,9 @@
* 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.
+ *
+ * Public interface to man(1) configuration management.
+ * For use by the main program and by the formatters.
*/
/* List of unique, absolute paths to manual trees. */
@@ -28,15 +31,18 @@ struct manpaths {
struct manoutput {
char *includes;
char *man;
+ char *outfilename;
char *paper;
char *style;
char *tag;
+ char *tagfilename;
size_t indent;
size_t width;
int fragment;
int mdoc;
int noval;
int synopsisonly;
+ int tag_found;
int toc;
};
diff --git a/mandoc.1 b/mandoc.1
index 298d5dc70610..f7490963b4bd 100644
--- a/mandoc.1
+++ b/mandoc.1
@@ -1,7 +1,7 @@
-.\" $Id: mandoc.1,v 1.240 2019/07/10 19:39:01 schwarze Exp $
+.\" $OpenBSD: mandoc.1,v 1.166 2020/02/15 15:28:01 schwarze Exp $
.\"
+.\" Copyright (c) 2012, 2014-2021 Ingo Schwarze <schwarze@openbsd.org>
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright (c) 2012, 2014-2019 Ingo Schwarze <schwarze@openbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@@ -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: July 10 2019 $
+.Dd $Mdocdate: August 14 2021 $
.Dt MANDOC 1
.Os
.Sh NAME
@@ -52,13 +52,13 @@ The options are as follows:
If the standard output is a terminal device and
.Fl c
is not specified, use
-.Xr more 1
+.Xr less 1
to paginate the output, just like
.Xr man 1
would.
.It Fl c
Copy the formatted manual pages to the standard output without using
-.Xr more 1
+.Xr less 1
to paginate them.
This is the default.
It can be specified to override
@@ -301,8 +301,8 @@ Format
input files in
.Xr mdoc 7
output style.
-Specifically, this suppresses the two additional blank lines near the
-top and the bottom of each page, and it implies
+This prints the operating system name rather than the page title
+on the right side of the footer line, and it implies
.Fl O Cm indent Ns =5 .
One useful application is for checking that
.Fl T Cm man
@@ -410,6 +410,30 @@ The file
is used for an external style-sheet.
This must be a valid absolute or
relative URI.
+.It Cm tag Ns Op = Ns Ar term
+Same syntax and semantics as for
+.Sx ASCII Output .
+This is implemented by passing a
+.Ic file://
+URI ending in a fragment identifier to the pager
+rather than passing merely a file name.
+When using this argument, use a pager supporting such URIs, for example
+.Bd -literal -offset 3n
+MANPAGER='lynx -force_html' man -T html -O tag=MANPAGER man
+MANPAGER='w3m -T text/html' man -T html -O tag=toc mandoc
+.Ed
+.Pp
+Consequently, for HTML output, this argument does not work with
+.Xr more 1
+or
+.Xr less 1 .
+For example,
+.Ql MANPAGER=less man -T html -O tag=toc mandoc
+does not work because
+.Xr less 1
+does not support
+.Ic file://
+URIs.
.It Cm toc
If an input file contains at least two non-standard sections,
print a table of contents near the beginning of the output.
@@ -443,13 +467,15 @@ This is useful for distributing manual sources to legacy systems
lacking
.Xr mdoc 7
formatters.
+Embedded
+.Xr eqn 7
+and
+.Xr tbl 7
+code is not supported.
.Pp
If the input format of a file is
.Xr man 7 ,
-the input is copied to the output, expanding any
-.Xr roff 7
-.Ic so
-requests.
+the input is copied to the output.
The parser is also run, and as usual, the
.Fl W
level controls which
@@ -628,7 +654,7 @@ It never affects the interpretation of input files.
Any non-empty value of the environment variable
.Ev MANPAGER
is used instead of the standard pagination program,
-.Xr more 1 ;
+.Xr less 1 ;
see
.Xr man 1
for details.
@@ -642,8 +668,7 @@ Specifies the pagination program to use when
.Ev MANPAGER
is not defined.
If neither PAGER nor MANPAGER is defined,
-.Xr more 1
-.Fl s
+.Xr less 1
is used.
Only used if
.Fl a
@@ -897,14 +922,6 @@ generated by CVS
or
.Ic NetBSD
keyword substitution as conventionally used in these operating systems.
-.It Sy "referenced manual not found"
-.Pq mdoc
-An
-.Ic \&Xr
-macro references a manual page that is not found in the base system.
-The path to look for base system manuals is configurable at compile
-time and defaults to
-.Pa /usr/share/man : /usr/X11R6/man .
.El
.Ss Style suggestions
.Bl -ohang
@@ -991,6 +1008,35 @@ list contains two consecutive
entries describing the same
.Ic \&Er
number.
+.It Sy "referenced manual not found"
+.Pq mdoc
+An
+.Ic \&Xr
+macro references a manual page that was not found.
+When running with
+.Fl W Cm base ,
+the search is restricted to the base system, by default to
+.Pa /usr/share/man : Ns Pa /usr/X11R6/man .
+This path can be configured at compile time using the
+.Dv MANPATH_BASE
+preprocessor macro.
+When running with
+.Fl W Cm style ,
+the search is done along the full search path as described in the
+.Xr man 1
+manual page, respecting the
+.Fl m
+and
+.Fl M
+command line options, the
+.Ev MANPATH
+environment variable, the
+.Xr man.conf 5
+file and falling back to the default of
+.Pa /usr/share/man : Ns Pa /usr/X11R6/man : Ns Pa /usr/local/man ,
+also configurable at compile time using the
+.Dv MANPATH_DEFAULT
+preprocessor macro.
.It Sy "trailing delimiter"
.Pq mdoc
The last argument of an
@@ -1020,6 +1066,9 @@ An
request occurs even though the document already switched to no-fill mode
and did not switch back to fill mode yet.
It has no effect.
+.It Sy "input text line longer than 80 bytes"
+Consider breaking the input text line
+at one of the blank characters before column 80.
.It Sy "verbatim \(dq--\(dq, maybe consider using \e(em"
.Pq mdoc
Even though the ASCII output device renders an em-dash as
@@ -1073,7 +1122,21 @@ macro lacks the mandatory section argument.
The section number in a
.Ic \&Dt
line is invalid, but still used.
-.It Sy "missing date, using today's date"
+.It Sy "filename/section mismatch"
+.Pq mdoc , man
+The name of the input file being processed is known and its file
+name extension starts with a non-zero digit, but the
+.Ic \&Dt
+or
+.Ic \&TH
+macro contains a
+.Ar section
+argument that starts with a different non-zero digit.
+The
+.Ar section
+argument is used as provided anyway.
+Consider checking whether the file name or the argument need a correction.
+.It Sy "missing date, using \(dq\(dq"
.Pq mdoc, man
The document was parsed as
.Xr mdoc 7
@@ -1811,6 +1874,10 @@ The invalid character is discarded.
A table layout specification contains an opening parenthesis,
but no matching closing parenthesis.
The rest of the input line, starting from the parenthesis, has no effect.
+.It Sy "ignoring excessive spacing in tbl layout"
+.Pq tbl
+A spacing modifier in a table layout is unreasonably large.
+The default spacing of 3n is used instead.
.It Sy "tbl without any data cells"
.Pq tbl
A table does not contain any data cells.
@@ -2247,6 +2314,26 @@ or
macro or of an undefined macro.
The macro is ignored, and its arguments are handled
as if they were a text line.
+.It Sy "skipping tbl in -Tman mode"
+.Pq mdoc , tbl
+An input file contains the
+.Ic \&TS
+macro.
+This message is only generated in
+.Fl T Cm man
+output mode, where
+.Xr tbl 7
+input is not supported.
+.It Sy "skipping eqn in -Tman mode"
+.Pq mdoc , eqn
+An input file contains the
+.Ic \&EQ
+macro.
+This message is only generated in
+.Fl T Cm man
+output mode, where
+.Xr eqn 7
+input is not supported.
.El
.Ss Bad command line arguments
.Bl -ohang
@@ -2284,6 +2371,14 @@ The
.Fl O Cm tag
option was specified but the tag was not found in any of the displayed
manual pages.
+.It Sy "\-Tmarkdown unsupported for man(7) input"
+.Pq man
+The
+.Fl T Cm markdown
+option was specified but an input file uses the
+.Xr man 7
+language.
+No output is produced for that input file.
.El
.Sh SEE ALSO
.Xr apropos 1 ,
diff --git a/mandoc.c b/mandoc.c
index 5a2be88e40df..6adf1a4318b2 100644
--- a/mandoc.c
+++ b/mandoc.c
@@ -1,7 +1,7 @@
-/* $Id: mandoc.c,v 1.116 2019/06/27 15:07:30 schwarze Exp $ */
+/* $Id: mandoc.c,v 1.119 2021/08/10 12:55:03 schwarze Exp $ */
/*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011-2015, 2017-2021 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -74,12 +74,12 @@ mandoc_font(const char *cp, int sz)
case 'C':
switch (cp[1]) {
case 'B':
- return ESCAPE_FONTBOLD;
+ return ESCAPE_FONTCB;
case 'I':
- return ESCAPE_FONTITALIC;
+ return ESCAPE_FONTCI;
case 'R':
case 'W':
- return ESCAPE_FONTCW;
+ return ESCAPE_FONTCR;
default:
return ESCAPE_ERROR;
}
@@ -203,7 +203,18 @@ mandoc_escape(const char **end, const char **start, int *sz)
case 'O':
case 'V':
case 'Y':
- gly = (*start)[-1] == 'f' ? ESCAPE_FONT : ESCAPE_IGNORE;
+ case '*':
+ switch ((*start)[-1]) {
+ case 'f':
+ gly = ESCAPE_FONT;
+ break;
+ case '*':
+ gly = ESCAPE_DEVICE;
+ break;
+ default:
+ gly = ESCAPE_IGNORE;
+ break;
+ }
switch (**start) {
case '(':
if ((*start)[-1] == 'O')
@@ -238,13 +249,6 @@ mandoc_escape(const char **end, const char **start, int *sz)
break;
}
break;
- case '*':
- if (strncmp(*start, "(.T", 3) != 0)
- abort();
- gly = ESCAPE_DEVICE;
- *start = ++*end;
- *sz = 2;
- break;
/*
* These escapes are of the form \X'Y', where 'X' is the trigger
@@ -459,6 +463,9 @@ mandoc_escape(const char **end, const char **start, int *sz)
+ 1 == *sz)
gly = ESCAPE_UNICODE;
break;
+ case ESCAPE_DEVICE:
+ assert(*sz == 2 && (*start)[0] == '.' && (*start)[1] == 'T');
+ break;
default:
break;
}
@@ -536,45 +543,59 @@ fail:
}
char *
-mandoc_normdate(struct roff_man *man, char *in, int ln, int pos)
+mandoc_normdate(struct roff_node *nch, struct roff_node *nbl)
{
char *cp;
time_t t;
- if (man->quick)
- return mandoc_strdup(in == NULL ? "" : in);
-
- /* No date specified: use today's date. */
+ /* No date specified. */
- if (in == NULL || *in == '\0')
- mandoc_msg(MANDOCERR_DATE_MISSING, ln, pos, NULL);
- if (in == NULL || *in == '\0' || strcmp(in, "$" "Mdocdate$") == 0)
+ if (nch == NULL) {
+ if (nbl == NULL)
+ mandoc_msg(MANDOCERR_DATE_MISSING, 0, 0, NULL);
+ else
+ mandoc_msg(MANDOCERR_DATE_MISSING, nbl->line,
+ nbl->pos, "%s", roff_name[nbl->tok]);
+ return mandoc_strdup("");
+ }
+ if (*nch->string == '\0') {
+ mandoc_msg(MANDOCERR_DATE_MISSING, nch->line,
+ nch->pos, "%s", roff_name[nbl->tok]);
+ return mandoc_strdup("");
+ }
+ if (strcmp(nch->string, "$" "Mdocdate$") == 0)
return time2a(time(NULL));
/* Valid mdoc(7) date format. */
- if (a2time(&t, "$" "Mdocdate: %b %d %Y $", in) ||
- a2time(&t, "%b %d, %Y", in)) {
+ if (a2time(&t, "$" "Mdocdate: %b %d %Y $", nch->string) ||
+ a2time(&t, "%b %d, %Y", nch->string)) {
cp = time2a(t);
if (t > time(NULL) + 86400)
- mandoc_msg(MANDOCERR_DATE_FUTURE, ln, pos, "%s", cp);
- else if (*in != '$' && strcmp(in, cp) != 0)
- mandoc_msg(MANDOCERR_DATE_NORM, ln, pos, "%s", cp);
+ mandoc_msg(MANDOCERR_DATE_FUTURE, nch->line,
+ nch->pos, "%s %s", roff_name[nbl->tok], cp);
+ else if (*nch->string != '$' &&
+ strcmp(nch->string, cp) != 0)
+ mandoc_msg(MANDOCERR_DATE_NORM, nch->line,
+ nch->pos, "%s %s", roff_name[nbl->tok], cp);
return cp;
}
/* In man(7), do not warn about the legacy format. */
- if (a2time(&t, "%Y-%m-%d", in) == 0)
- mandoc_msg(MANDOCERR_DATE_BAD, ln, pos, "%s", in);
+ if (a2time(&t, "%Y-%m-%d", nch->string) == 0)
+ mandoc_msg(MANDOCERR_DATE_BAD, nch->line, nch->pos,
+ "%s %s", roff_name[nbl->tok], nch->string);
else if (t > time(NULL) + 86400)
- mandoc_msg(MANDOCERR_DATE_FUTURE, ln, pos, "%s", in);
- else if (man->meta.macroset == MACROSET_MDOC)
- mandoc_msg(MANDOCERR_DATE_LEGACY, ln, pos, "Dd %s", in);
+ mandoc_msg(MANDOCERR_DATE_FUTURE, nch->line, nch->pos,
+ "%s %s", roff_name[nbl->tok], nch->string);
+ else if (nbl->tok == MDOC_Dd)
+ mandoc_msg(MANDOCERR_DATE_LEGACY, nch->line, nch->pos,
+ "Dd %s", nch->string);
/* Use any non-mdoc(7) date verbatim. */
- return mandoc_strdup(in);
+ return mandoc_strdup(nch->string);
}
int
diff --git a/mandoc.css b/mandoc.css
index d75700a28ba7..ceac503a79f6 100644
--- a/mandoc.css
+++ b/mandoc.css
@@ -1,4 +1,4 @@
-/* $Id: mandoc.css,v 1.46 2019/06/02 16:57:13 schwarze Exp $ */
+/* $Id: mandoc.css,v 1.48 2021/03/30 19:26:20 schwarze Exp $ */
/*
* Standard style sheet for mandoc(1) -Thtml and man.cgi(8).
*
@@ -31,6 +31,7 @@ td { vertical-align: top;
ul, ol, dl { margin-top: 0em;
margin-bottom: 0em; }
li, dt { margin-top: 1em; }
+pre { font-family: inherit; }
.permalink { border-bottom: thin dotted;
color: inherit;
@@ -135,12 +136,12 @@ h2.Ss { margin-top: 1.2em;
vertical-align: top; }
.Bl-tag > dd {
clear: right;
+ column-count: 1; /* Force block formatting context. */
width: 100%;
margin-top: 0em;
margin-left: 0em;
margin-bottom: 0.6em;
- vertical-align: top;
- overflow: auto; }
+ vertical-align: top; }
.Bl-compact { margin-top: 0em; }
.Bl-compact > dd {
margin-bottom: 0em; }
diff --git a/mandoc.h b/mandoc.h
index 4a7e7aa749ad..9837ff2ae9df 100644
--- a/mandoc.h
+++ b/mandoc.h
@@ -1,7 +1,7 @@
-/* $Id: mandoc.h,v 1.264 2019/07/14 18:16:13 schwarze Exp $ */
+/* $Id: mandoc.h,v 1.274 2021/08/14 13:53:08 schwarze Exp $ */
/*
+ * Copyright (c) 2012-2021 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2012-2019 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -16,6 +16,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Error handling, escape sequence, and character utilities.
+ * Can be used by all code in the mandoc package.
*/
#define ASCII_NBRSP 31 /* non-breaking space */
@@ -53,7 +54,6 @@ enum mandocerr {
MANDOCERR_ARCH_BAD, /* unknown architecture: Dt ... arch */
MANDOCERR_OS_ARG, /* operating system explicitly specified: Os ... */
MANDOCERR_RCS_MISSING, /* RCS id missing */
- MANDOCERR_XR_BAD, /* referenced manual not found: Xr name sec */
MANDOCERR_STYLE, /* ===== start of style suggestions ===== */
@@ -67,10 +67,12 @@ enum mandocerr {
MANDOCERR_BX, /* consider using OS macro: macro */
MANDOCERR_ER_ORDER, /* errnos out of order: Er ... */
MANDOCERR_ER_REP, /* duplicate errno: Er ... */
+ MANDOCERR_XR_BAD, /* referenced manual not found: Xr name sec */
MANDOCERR_DELIM, /* trailing delimiter: macro ... */
MANDOCERR_DELIM_NB, /* no blank before trailing delimiter: macro ... */
MANDOCERR_FI_SKIP, /* fill mode already enabled, skipping: fi */
MANDOCERR_NF_SKIP, /* fill mode already disabled, skipping: nf */
+ MANDOCERR_TEXT_LONG, /* input text line longer than 80 bytes */
MANDOCERR_DASHDASH, /* verbatim "--", maybe consider using \(em */
MANDOCERR_FUNC, /* function name without markup: name() */
MANDOCERR_SPACE_EOL, /* whitespace at end of input line */
@@ -83,7 +85,8 @@ enum mandocerr {
MANDOCERR_TH_NOTITLE, /* missing manual title, using "": [macro] */
MANDOCERR_MSEC_MISSING, /* missing manual section, using "": macro */
MANDOCERR_MSEC_BAD, /* unknown manual section: Dt ... section */
- MANDOCERR_DATE_MISSING, /* missing date, using today's date */
+ MANDOCERR_MSEC_FILE, /* filename/section mismatch: ... */
+ MANDOCERR_DATE_MISSING, /* missing date, using "": [macro] */
MANDOCERR_DATE_BAD, /* cannot parse date, using it verbatim: date */
MANDOCERR_DATE_FUTURE, /* date in the future, using it anyway: date */
MANDOCERR_OS_MISSING, /* missing Os macro, using "" */
@@ -187,6 +190,7 @@ enum mandocerr {
MANDOCERR_TBLLAYOUT_NONE, /* empty tbl layout */
MANDOCERR_TBLLAYOUT_CHAR, /* invalid character in tbl layout: char */
MANDOCERR_TBLLAYOUT_PAR, /* unmatched parenthesis in tbl layout */
+ MANDOCERR_TBLLAYOUT_SPC, /* ignoring excessive spacing in tbl layout */
MANDOCERR_TBLDATA_NONE, /* tbl without any data cells */
MANDOCERR_TBLDATA_SPAN, /* ignoring data in spanned tbl cell: data */
MANDOCERR_TBLDATA_EXTRA, /* ignoring extra tbl data cells: data */
@@ -223,6 +227,7 @@ enum mandocerr {
MANDOCERR_SHIFT, /* excessive shift: ..., but max is ... */
MANDOCERR_SO_PATH, /* NOT IMPLEMENTED: .so with absolute path or ".." */
MANDOCERR_SO_FAIL, /* .so request failed */
+ MANDOCERR_TG_SPC, /* skipping tag containing whitespace: tag */
MANDOCERR_ARG_SKIP, /* skipping all arguments: macro args */
MANDOCERR_ARG_EXCESS, /* skipping excess arguments: macro ... args */
MANDOCERR_DIVZERO, /* divide by zero */
@@ -240,6 +245,8 @@ enum mandocerr {
MANDOCERR_TBLOPT_EQN, /* eqn delim option in tbl: arg */
MANDOCERR_TBLLAYOUT_MOD, /* unsupported tbl layout modifier: m */
MANDOCERR_TBLMACRO, /* ignoring macro in table: macro */
+ MANDOCERR_TBL_TMAN, /* skipping tbl in -Tman mode */
+ MANDOCERR_EQN_TMAN, /* skipping eqn in -Tman mode */
MANDOCERR_BADARG, /* ===== start of bad invocations ===== */
@@ -250,6 +257,7 @@ enum mandocerr {
MANDOCERR_BADVAL_BAD, /* bad argument value */
MANDOCERR_BADVAL_DUPE, /* duplicate argument value */
MANDOCERR_TAG, /* no such tag */
+ MANDOCERR_MAN_TMARKDOWN, /* -Tmarkdown unsupported for man(7) input */
MANDOCERR_SYSERR, /* ===== start of system errors ===== */
@@ -284,7 +292,9 @@ enum mandoc_esc {
ESCAPE_FONTITALIC, /* italic font mode */
ESCAPE_FONTBI, /* bold italic font mode */
ESCAPE_FONTROMAN, /* roman font mode */
- ESCAPE_FONTCW, /* constant width font mode */
+ ESCAPE_FONTCR, /* constant width font mode */
+ ESCAPE_FONTCB, /* constant width bold font mode */
+ ESCAPE_FONTCI, /* constant width italic font mode */
ESCAPE_FONTPREV, /* previous font mode */
ESCAPE_NUMBERED, /* a numbered glyph */
ESCAPE_UNICODE, /* a unicode codepoint */
@@ -298,7 +308,7 @@ enum mandoc_esc {
};
-enum mandoc_esc mandoc_font(const char *, int sz);
+enum mandoc_esc mandoc_font(const char *, int);
enum mandoc_esc mandoc_escape(const char **, const char **, int *);
void mandoc_msg_setoutfile(FILE *);
const char *mandoc_msg_getinfilename(void);
diff --git a/mandoc_char.7 b/mandoc_char.7
index b46575d4d250..eb9e65acfc86 100644
--- a/mandoc_char.7
+++ b/mandoc_char.7
@@ -1,8 +1,8 @@
-.\" $Id: mandoc_char.7,v 1.76 2019/03/31 19:17:26 schwarze Exp $
+.\" $Id: mandoc_char.7,v 1.78 2020/10/31 11:45:16 schwarze Exp $
.\"
.\" Copyright (c) 2003 Jason McIntyre <jmc@openbsd.org>
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright (c) 2011,2013,2015,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2011,2013,2015,2017-2020 Ingo Schwarze <schwarze@openbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@@ -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: March 31 2019 $
+.Dd $Mdocdate: October 31 2020 $
.Dt MANDOC_CHAR 7
.Os
.Sh NAME
@@ -261,15 +261,15 @@ subsection of the
.Xr roff 7
manual.
.Pp
-Spacing:
+Spaces, non-breaking unless stated otherwise:
.Bl -column "Input" "Description" -offset indent -compact
.It Em Input Ta Em Description
-.It Sq \e\ \& Ta unpaddable non-breaking space
-.It \e\(ti Ta paddable non-breaking space
-.It \e0 Ta digit-width space allowing line break
+.It Sq \e\ \& Ta unpaddable space
+.It \e\(ti Ta paddable space
+.It \e0 Ta digit-width space
.It \e| Ta one-sixth \e(em narrow space, zero width in nroff mode
.It \e^ Ta one-twelfth \e(em half-narrow space, zero width in nroff
-.It \e& Ta zero-width non-breaking space
+.It \e& Ta zero-width space
.It \e) Ta zero-width space transparent to end-of-sentence detection
.It \e% Ta zero-width space allowing hyphenation
.It \e: Ta zero-width space allowing line break
@@ -709,11 +709,6 @@ Their syntax is similar to special characters, using
and
.Sq \e*[N]
.Pq N-character .
-For details, see the
-.Em Predefined Strings
-subsection of the
-.Xr roff 7
-manual.
.Bl -column "Input" "Rendered" "Description" -offset indent
.It Em Input Ta Em Rendered Ta Em Description
.It \e*(Ba Ta \*(Ba Ta vertical bar
diff --git a/mandoc_headers.3 b/mandoc_headers.3
index 2cda75cba8b3..7fe6d379f864 100644
--- a/mandoc_headers.3
+++ b/mandoc_headers.3
@@ -1,6 +1,6 @@
-.\" $Id: mandoc_headers.3,v 1.31 2019/03/17 18:21:45 schwarze Exp $
+.\" $Id: mandoc_headers.3,v 1.34 2021/08/10 12:55:03 schwarze Exp $
.\"
-.\" Copyright (c) 2014-2019 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2014-2021 Ingo Schwarze <schwarze@openbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@@ -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: March 17 2019 $
+.Dd $Mdocdate: August 10 2021 $
.Dt MANDOC_HEADERS 3
.Os
.Sh NAME
@@ -167,7 +167,11 @@ parse tree; can be used everywhere.
Requires
.In sys/types.h
for
-.Vt size_t .
+.Vt size_t
+and
+.Qq Pa mandoc.h
+for
+.Vt enum mandoc_esc .
.Pp
Provides
.Vt enum tbl_cellt ,
@@ -232,6 +236,30 @@ and the functions
.Fn mandoc_xr_get ,
and
.Fn mandoc_xr_free .
+.It Qq Pa tag.h
+Internal interfaces to tag syntax tree nodes,
+for use by validation modules only.
+.Pp
+Requires
+.In limits.h
+for
+.Dv INT_MAX .
+.Pp
+Provides the functions
+.Fn tag_alloc ,
+.Fn tag_put ,
+.Fn tag_check ,
+and
+.Fn tag_free
+and some
+.Dv TAG_*
+constants.
+.Pp
+Uses the type
+.Vt struct roff_node
+from
+.Qq Pa roff.h
+as an opaque type for function prototypes.
.El
.Pp
The following two require
@@ -587,6 +615,33 @@ When this header is included, the same file should not include
.Qq Pa html.h
or
.Qq Pa mansearch.h .
+.It Qq Pa tag_term.h
+Requires
+.In sys/types.h
+for
+.Vt size_t
+and
+.In stdio.h
+for
+.Vt FILE .
+.Pp
+Provides an interface to generate
+.Xr ctags 1
+files for the
+.Ic :t
+functionality mentioned in
+.Xr man 1 .
+.Pp
+Uses the type
+.Vt struct roff_node
+from
+.Qq Pa roff.h
+as an opaque type for function prototypes.
+.Pp
+When this header is included, the same file should not include
+.Qq Pa html.h
+or
+.Qq Pa mansearch.h .
.It Qq Pa html.h
Requires
.In sys/types.h
@@ -629,21 +684,10 @@ from
as opaque types for function prototypes.
.Pp
When this header is included, the same file should not include
-.Qq Pa term.h
+.Qq Pa term.h ,
+.Qq Pa tab_term.h ,
or
.Qq Pa mansearch.h .
-.It Qq Pa tag.h
-Requires
-.In sys/types.h
-for
-.Vt size_t .
-.Pp
-Provides an interface to generate
-.Xr ctags 1
-files for the
-.Ic :t
-functionality mentioned in
-.Xr man 1 .
.It Qq Pa main.h
Provides the top level steering functions for all formatters.
.Pp
@@ -696,6 +740,7 @@ as an opaque type for function prototypes.
When this header is included, the same file should not include
.Qq Pa out.h ,
.Qq Pa term.h ,
+.Qq Pa tab_term.h ,
or
.Qq Pa html.h .
.El
diff --git a/mandoc_html.3 b/mandoc_html.3
index 32407574a814..a77d0e04fce4 100644
--- a/mandoc_html.3
+++ b/mandoc_html.3
@@ -1,4 +1,4 @@
-.\" $Id: mandoc_html.3,v 1.19 2019/01/11 12:56:43 schwarze Exp $
+.\" $Id: mandoc_html.3,v 1.23 2020/04/24 13:13:06 schwarze Exp $
.\"
.\" Copyright (c) 2014, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
.\"
@@ -14,14 +14,18 @@
.\" 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 11 2019 $
+.Dd $Mdocdate: April 24 2020 $
.Dt MANDOC_HTML 3
.Os
.Sh NAME
.Nm mandoc_html
.Nd internals of the mandoc HTML formatter
.Sh SYNOPSIS
-.In "html.h"
+.In sys/types.h
+.Fd #include """mandoc.h"""
+.Fd #include """roff.h"""
+.Fd #include """out.h"""
+.Fd #include """html.h"""
.Ft void
.Fn print_gen_decls "struct html *h"
.Ft void
@@ -46,18 +50,42 @@
.Fa "const struct tag *suntil"
.Fc
.Ft void
+.Fn html_close_paragraph "struct html *h"
+.Ft enum roff_tok
+.Fo html_fillmode
+.Fa "struct html *h"
+.Fa "enum roff_tok tok"
+.Fc
+.Ft int
+.Fo html_setfont
+.Fa "struct html *h"
+.Fa "enum mandoc_esc font"
+.Fc
+.Ft void
.Fo print_text
.Fa "struct html *h"
.Fa "const char *word"
.Fc
+.Ft void
+.Fo print_tagged_text
+.Fa "struct html *h"
+.Fa "const char *word"
+.Fa "struct roff_node *n"
+.Fc
.Ft char *
.Fo html_make_id
.Fa "const struct roff_node *n"
+.Fa "int unique"
.Fc
-.Ft int
-.Fo html_strlen
-.Fa "const char *cp"
+.Ft struct tag *
+.Fo print_otag_id
+.Fa "struct html *h"
+.Fa "enum htmltag tag"
+.Fa "const char *cattr"
+.Fa "struct roff_node *n"
.Fc
+.Ft void
+.Fn print_endline "struct html *h"
.Sh DESCRIPTION
The mandoc HTML formatter is not a formal library.
However, as it is compiled into more than one program, in particular
@@ -96,7 +124,7 @@ These structures are declared in
Internal state of the HTML formatter.
.It Vt struct tag
One entry for the LIFO stack of HTML elements.
-Members are
+Members include
.Fa "enum htmltag tag"
and
.Fa "struct tag *next" .
@@ -105,10 +133,8 @@ and
The function
.Fn print_gen_decls
prints the opening
-.Ao Pf \&? Ic xml ? Ac
-and
.Aq Pf \&! Ic DOCTYPE
-declarations required for the current document type.
+declaration.
.Pp
The function
.Fn print_gen_comment
@@ -235,6 +261,59 @@ is used to close out all open elements up to and including
.Fn print_stagq
is a variant to close out all open elements up to but excluding
.Fa suntil .
+The function
+.Fn html_close_paragraph
+closes all open elements that establish phrasing context,
+thus returning to the innermost flow context.
+.Pp
+The function
+.Fn html_fillmode
+switches to fill mode if
+.Fa want
+is
+.Dv ROFF_fi
+or to no-fill mode if
+.Fa want
+is
+.Dv ROFF_nf .
+Switching from fill mode to no-fill mode closes the current paragraph
+and opens a
+.Aq Ic PRE
+element.
+Switching in the opposite direction closes the
+.Aq Ic PRE
+element, but does not open a new paragraph.
+If
+.Fa want
+matches the mode that is already active, no elements are closed nor opened.
+If
+.Fa want
+is
+.Dv TOKEN_NONE ,
+the mode remains as it is.
+.Pp
+The function
+.Fn html_setfont
+selects the
+.Fa font ,
+which can be
+.Dv ESCAPE_FONTROMAN ,
+.Dv ESCAPE_FONTBOLD ,
+.Dv ESCAPE_FONTITALIC ,
+.Dv ESCAPE_FONTBI ,
+or
+.Dv ESCAPE_FONTCW ,
+for future text output and internally remembers
+the font that was active before the change.
+If the
+.Fa font
+argument is
+.Dv ESCAPE_FONTPREV ,
+the current and the previous font are exchanged.
+This function only changes the internal state of the
+.Fa h
+object; no HTML elements are written yet.
+Subsequent text output will write font elements when needed.
.Pp
The function
.Fn print_text
@@ -256,24 +335,118 @@ and
functions.
.Pp
The function
-.Fn html_make_id
-takes a node containing one or more text children
-and returns a newly allocated string containing the concatenation
-of the child strings, with blanks replaced by underscores.
-If the node
+.Fn print_tagged_text
+is a variant of
+.Fn print_text
+that wraps
+.Fa word
+in an
+.Aq Ic A
+element of class
+.Qq permalink
+if
.Fa n
-contains any non-text child node,
+is not
+.Dv NULL
+and yields a segment identifier when passed to
+.Fn html_make_id .
+.Pp
+The function
.Fn html_make_id
-returns
+allocates a string to be used for the
+.Cm id
+attribute of an HTML element and/or as a segment identifier for a URI in an
+.Aq Ic A
+element.
+If
+.Fa n
+contains a
+.Fa tag
+attribute, it is used; otherwise, child nodes are used.
+If
+.Fa n
+is an
+.Ic \&Sh ,
+.Ic \&Ss ,
+.Ic \&Sx ,
+.Ic SH ,
+or
+.Ic SS
+node, the resulting string is the concatenation of the child strings;
+for other node types, only the first child is used.
+Bytes not permitted in URI-fragment strings are replaced by underscores.
+If any of the children to be used is not a text node,
+no string is generated and
.Dv NULL
-instead.
-The caller is responsible for freeing the returned string.
+is returned instead.
+If the
+.Fa unique
+argument is non-zero, deduplication is performed by appending an
+underscore and a decimal integer, if necessary.
+If the
+.Fa unique
+argument is 1, this is assumed to be the first call for this tag
+at this location, typically for use by
+.Dv NODE_ID ,
+so the integer is incremented before use.
+If the
+.Fa unique
+argument is 2, this is ssumed to be the second call for this tag
+at this location, typically for use by
+.Dv NODE_HREF ,
+so the existing integer, if any, is used without incrementing it.
.Pp
The function
-.Fn html_strlen
-counts the number of characters in
-.Fa cp .
-It is used as a crude estimate of the width needed to display a string.
+.Fn print_otag_id
+opens a
+.Fa tag
+element of class
+.Fa cattr
+for the node
+.Fa n .
+If the flag
+.Dv NODE_ID
+is set in
+.Fa n ,
+it attempts to generate an
+.Cm id
+attribute with
+.Fn html_make_id .
+If the flag
+.Dv NODE_HREF
+is set in
+.Fa n ,
+an
+.Aq Ic A
+element of class
+.Qq permalink
+is added:
+outside if
+.Fa n
+generates an element that can only occur in phrasing context,
+or inside otherwise.
+This function is a wrapper around
+.Fn html_make_id
+and
+.Fn print_otag ,
+automatically chosing the
+.Fa unique
+argument appropriately and setting the
+.Fa fmt
+arguments to
+.Qq chR
+and
+.Qq ci ,
+respectively.
+.Pp
+The function
+.Fn print_endline
+makes sure subsequent output starts on a new HTML output line.
+If nothing was printed on the current output line yet, it has no effect.
+Otherwise, it appends any buffered text to the current output line,
+ends the line, and updates the internal state of the
+.Fa h
+object.
.Pp
The functions
.Fn print_eqn ,
@@ -281,6 +454,46 @@ The functions
and
.Fn print_tblclose
are not yet documented.
+.Sh RETURN VALUES
+The functions
+.Fn print_otag
+and
+.Fn print_otag_id
+return a pointer to a new element on the stack of HTML elements.
+When
+.Fn print_otag_id
+opens two elements, a pointer to the outer one is returned.
+The memory pointed to is owned by the library and is automatically
+.Xr free 3 Ns d
+when
+.Fn print_tagq
+is called on it or when
+.Fn print_stagq
+is called on a parent element.
+.Pp
+The function
+.Fn html_fillmode
+returns
+.Dv ROFF_fi
+if fill mode was active before the call or
+.Dv ROFF_nf
+otherwise.
+.Pp
+The function
+.Fn html_make_id
+returns a newly allocated string or
+.Dv NULL
+if
+.Fa n
+lacks text data to create the attribute from.
+The caller is responsible for
+.Xr free 3 Ns ing
+the returned string after using it.
+.Pp
+In case of
+.Xr malloc 3
+failure, these functions do not return but call
+.Xr err 3 .
.Sh FILES
.Bl -tag -width mandoc_aux.c -compact
.It Pa main.h
@@ -303,6 +516,17 @@ HTML formatter
.It Pa eqn_html.c
.Xr eqn 7
HTML formatter
+.It Pa roff_html.c
+.Xr roff 7
+HTML formatter, handling requests like
+.Ic br ,
+.Ic ce ,
+.Ic fi ,
+.Ic ft ,
+.Ic nf ,
+.Ic rj ,
+and
+.Ic sp .
.It Pa out.h
declarations of data types and private functions
for shared use by all mandoc formatters,
diff --git a/mandoc_malloc.3 b/mandoc_malloc.3
index ae3ca16aa4a8..d73438575065 100644
--- a/mandoc_malloc.3
+++ b/mandoc_malloc.3
@@ -1,4 +1,4 @@
-.\" $Id: mandoc_malloc.3,v 1.2 2016/07/07 19:19:01 schwarze Exp $
+.\" $Id: mandoc_malloc.3,v 1.3 2021/09/17 18:50:21 schwarze Exp $
.\"
.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
.\"
@@ -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: July 7 2016 $
+.Dd $Mdocdate: September 17 2021 $
.Dt MANDOC_MALLOC 3
.Os
.Sh NAME
@@ -22,6 +22,7 @@
.Nm mandoc_realloc ,
.Nm mandoc_reallocarray ,
.Nm mandoc_calloc ,
+.Nm mandoc_recallocarray ,
.Nm mandoc_strdup ,
.Nm mandoc_strndup ,
.Nm mandoc_asprintf
@@ -49,6 +50,13 @@
.Fa "size_t nmemb"
.Fa "size_t size"
.Fc
+.Ft "void *"
+.Fo mandoc_recallocarray
+.Fa "void *ptr"
+.Fa "size_t oldnmemb"
+.Fa "size_t nmemb"
+.Fa "size_t size"
+.Fc
.Ft "char *"
.Fo mandoc_strdup
.Fa "const char *s"
@@ -82,12 +90,15 @@ The function
.Fn mandoc_malloc
allocates one new object, leaving the memory uninitialized.
The functions
-.Fn mandoc_realloc
+.Fn mandoc_realloc ,
+.Fn mandoc_reallocarray ,
and
-.Fn mandoc_reallocarray
+.Fn mandoc_recallocarray
change the size of an existing object or array, possibly moving it.
When shrinking the size, existing data is truncated; when growing,
-the additional memory is not initialized.
+only
+.Fn mandoc_recallocarray
+initializes the new elements to zero.
The function
.Fn mandoc_calloc
allocates a new array, initializing it to zero.
@@ -99,6 +110,9 @@ The argument
.Fa nmemb
is the new number of objects in the array.
The argument
+.Fa oldnmemb
+is the number of objects in the array before the call.
+The argument
.Fa ptr
is a pointer to the existing object or array to be resized; if it is
.Dv NULL ,
@@ -168,9 +182,13 @@ is a widespread extension that first appeared in the GNU C library.
The function
.Fn reallocarray
is an extension that first appeared in
-.Ox 5.6 .
-If it is not provided by the operating system, the mandoc build system
-uses a bundled portable implementation.
+.Ox 5.6 ,
+and
+.Fn recallocarray
+in
+.Ox 6.1 .
+If these two are not provided by the operating system,
+the mandoc build system uses bundled portable implementations.
.Sh HISTORY
The functions
.Fn mandoc_malloc ,
@@ -181,11 +199,12 @@ and
have been available since mandoc 1.9.12,
.Fn mandoc_strndup
since 1.11.5,
-and
.Fn mandoc_asprintf
-and
+since 1.12.4,
.Fn mandoc_reallocarray
-since 1.12.4 and 1.13.0.
+since 1.13.0, and
+.Fn mandoc_recallocarray
+since 1.14.2.
.Sh AUTHORS
.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
.An Ingo Schwarze Aq Mt schwarze@openbsd.org
diff --git a/mandoc_msg.c b/mandoc_msg.c
index e73dcfd830ff..beec5059a28c 100644
--- a/mandoc_msg.c
+++ b/mandoc_msg.c
@@ -1,7 +1,7 @@
-/* $Id: mandoc_msg.c,v 1.8 2019/07/14 18:16:13 schwarze Exp $ */
+/* $OpenBSD: mandoc_msg.c,v 1.8 2020/01/19 17:59:01 schwarze Exp $ */
/*
+ * Copyright (c) 2014-2021 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014-2019 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,6 +14,8 @@
* 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.
+ *
+ * Implementation of warning and error messages for mandoc(1).
*/
#include "config.h"
@@ -53,7 +55,6 @@ static const char *const type_message[MANDOCERR_MAX] = {
"unknown architecture",
"operating system explicitly specified",
"RCS id missing",
- "referenced manual not found",
"generic style suggestion",
@@ -67,10 +68,12 @@ static const char *const type_message[MANDOCERR_MAX] = {
"consider using OS macro",
"errnos out of order",
"duplicate errno",
+ "referenced manual not found",
"trailing delimiter",
"no blank before trailing delimiter",
"fill mode already enabled, skipping",
"fill mode already disabled, skipping",
+ "input text line longer than 80 bytes",
"verbatim \"--\", maybe consider using \\(em",
"function name without markup",
"whitespace at end of input line",
@@ -83,7 +86,8 @@ static const char *const type_message[MANDOCERR_MAX] = {
"missing manual title, using \"\"",
"missing manual section, using \"\"",
"unknown manual section",
- "missing date, using today's date",
+ "filename/section mismatch",
+ "missing date, using \"\"",
"cannot parse date, using it verbatim",
"date in the future, using it anyway",
"missing Os macro, using \"\"",
@@ -187,6 +191,7 @@ static const char *const type_message[MANDOCERR_MAX] = {
"empty tbl layout",
"invalid character in tbl layout",
"unmatched parenthesis in tbl layout",
+ "ignoring excessive spacing in tbl layout",
"tbl without any data cells",
"ignoring data in spanned tbl cell",
"ignoring extra tbl data cells",
@@ -223,6 +228,7 @@ static const char *const type_message[MANDOCERR_MAX] = {
"excessive shift",
"NOT IMPLEMENTED: .so with absolute path or \"..\"",
".so request failed",
+ "skipping tag containing whitespace",
"skipping all arguments",
"skipping excess arguments",
"divide by zero",
@@ -239,6 +245,8 @@ static const char *const type_message[MANDOCERR_MAX] = {
"eqn delim option in tbl",
"unsupported tbl layout modifier",
"ignoring macro in table",
+ "skipping tbl in -Tman mode",
+ "skipping eqn in -Tman mode",
/* bad command line arguments */
NULL,
@@ -249,6 +257,7 @@ static const char *const type_message[MANDOCERR_MAX] = {
"bad option value",
"duplicate option value",
"no such tag",
+ "-Tmarkdown unsupported for man(7) input",
/* system errors */
NULL,
diff --git a/mandoc_ohash.c b/mandoc_ohash.c
index 0627b469c60b..c4ebfcd428ed 100644
--- a/mandoc_ohash.c
+++ b/mandoc_ohash.c
@@ -1,4 +1,4 @@
-/* $Id: mandoc_ohash.c,v 1.2 2015/10/19 18:58:47 schwarze Exp $ */
+/* $Id: mandoc_ohash.c,v 1.3 2020/06/22 19:20:40 schwarze Exp $ */
/*
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -14,6 +14,8 @@
* 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"
+
#include <sys/types.h>
#include <stddef.h>
#include <stdint.h>
diff --git a/mandoc_parse.h b/mandoc_parse.h
index 61341f0d7f39..b8b29dd931c9 100644
--- a/mandoc_parse.h
+++ b/mandoc_parse.h
@@ -1,4 +1,4 @@
-/* $Id: mandoc_parse.h,v 1.4 2018/12/30 00:49:55 schwarze Exp $ */
+/* $Id: mandoc_parse.h,v 1.5 2019/11/09 14:39:49 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014,2015,2016,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
@@ -29,6 +29,7 @@
#define MPARSE_UTF8 (1 << 4) /* accept UTF-8 input */
#define MPARSE_LATIN1 (1 << 5) /* accept ISO-LATIN-1 input */
#define MPARSE_VALIDATE (1 << 6) /* call validation functions */
+#define MPARSE_COMMENT (1 << 7) /* save comments in the tree */
struct roff_meta;
diff --git a/mandoc_xr.c b/mandoc_xr.c
index da0a7f0cf23b..6d1b1a8d8ad2 100644
--- a/mandoc_xr.c
+++ b/mandoc_xr.c
@@ -1,4 +1,4 @@
-/* $Id: mandoc_xr.c,v 1.3 2017/07/02 21:18:29 schwarze Exp $ */
+/* $Id: mandoc_xr.c,v 1.4 2020/06/22 19:20:40 schwarze Exp $ */
/*
* Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -14,6 +14,8 @@
* 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"
+
#include <sys/types.h>
#include <assert.h>
diff --git a/mandocd.c b/mandocd.c
index 1a597b3867bc..60e40fed8023 100644
--- a/mandocd.c
+++ b/mandocd.c
@@ -1,4 +1,4 @@
-/* $Id: mandocd.c,v 1.11 2019/03/03 13:02:11 schwarze Exp $ */
+/* $Id: mandocd.c,v 1.12 2020/06/14 23:40:31 schwarze Exp $ */
/*
* Copyright (c) 2017 Michael Stapelberg <stapelberg@debian.org>
* Copyright (c) 2017, 2019 Ingo Schwarze <schwarze@openbsd.org>
@@ -17,7 +17,7 @@
*/
#include "config.h"
-#if HAVE_CMSG_XPG42
+#if NEED_XPG4_2
#define _XPG4_2
#endif
diff --git a/mandocdb.c b/mandocdb.c
index 64ac10115877..a3360fe44d01 100644
--- a/mandocdb.c
+++ b/mandocdb.c
@@ -1,7 +1,7 @@
-/* $Id: mandocdb.c,v 1.263 2019/05/03 18:17:12 schwarze Exp $ */
+/* $Id: mandocdb.c,v 1.269 2021/08/19 16:55:31 schwarze Exp $ */
/*
+ * Copyright (c) 2011-2020 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011-2019 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2016 Ed Maste <emaste@freebsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -15,6 +15,8 @@
* 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.
+ *
+ * Implementation of the makewhatis(8) program.
*/
#include "config.h"
@@ -118,7 +120,7 @@ struct mdoc_handler {
int mandocdb(int, char *[]);
static void dbadd(struct dba *, struct mpage *);
-static void dbadd_mlink(const struct mlink *mlink);
+static void dbadd_mlink(const struct mlink *);
static void dbprune(struct dba *);
static void dbwrite(struct dba *);
static void filescan(const char *);
@@ -163,6 +165,9 @@ static void putkey(const struct mpage *, char *, uint64_t);
static void putkeys(const struct mpage *, char *, size_t, uint64_t);
static void putmdockey(const struct mpage *,
const struct roff_node *, uint64_t, int);
+#ifdef READ_ALLOWED_PATH
+static int read_allowed(const char *);
+#endif
static int render_string(char **, size_t *);
static void say(const char *, const char *, ...)
__attribute__((__format__ (__printf__, 2, 3)));
@@ -179,6 +184,7 @@ static int write_utf8; /* write UTF-8 output; else ASCII */
static int exitcode; /* to be returned by main */
static enum op op; /* operational mode */
static char basedir[PATH_MAX]; /* current base directory */
+static size_t basedir_len; /* strlen(basedir) */
static struct mpage *mpage_head; /* list of distinct manual pages */
static struct ohash mpages; /* table of distinct manual pages */
static struct ohash mlinks; /* table of directory entries */
@@ -342,7 +348,7 @@ mandocdb(int argc, char *argv[])
* clobber each other.
*/
#define CHECKOP(_op, _ch) do \
- if (OP_DEFAULT != (_op)) { \
+ if ((_op) != OP_DEFAULT) { \
warnx("-%c: Conflicting option", (_ch)); \
goto usage; \
} while (/*CONSTCOND*/0)
@@ -351,7 +357,7 @@ mandocdb(int argc, char *argv[])
path_arg = NULL;
op = OP_DEFAULT;
- while (-1 != (ch = getopt(argc, argv, "aC:Dd:npQT:tu:v")))
+ while ((ch = getopt(argc, argv, "aC:Dd:npQT:tu:v")) != -1)
switch (ch) {
case 'a':
use_all = 1;
@@ -379,7 +385,7 @@ mandocdb(int argc, char *argv[])
mparse_options |= MPARSE_QUICK;
break;
case 'T':
- if (strcmp(optarg, "utf8")) {
+ if (strcmp(optarg, "utf8") != 0) {
warnx("-T%s: Unsupported output format",
optarg);
goto usage;
@@ -416,7 +422,7 @@ mandocdb(int argc, char *argv[])
}
#endif
- if (OP_CONFFILE == op && argc > 0) {
+ if (op == OP_CONFFILE && argc > 0) {
warnx("-C: Too many arguments");
goto usage;
}
@@ -427,13 +433,13 @@ mandocdb(int argc, char *argv[])
mandoc_ohash_init(&mpages, 6, offsetof(struct mpage, inodev));
mandoc_ohash_init(&mlinks, 6, offsetof(struct mlink, file));
- if (OP_UPDATE == op || OP_DELETE == op || OP_TEST == op) {
+ if (op == OP_UPDATE || op == OP_DELETE || op == OP_TEST) {
/*
* Most of these deal with a specific directory.
* Jump into that directory first.
*/
- if (OP_TEST != op && 0 == set_basedir(path_arg, 1))
+ if (op != OP_TEST && set_basedir(path_arg, 1) == 0)
goto out;
dba = nodb ? dba_new(128) : dba_read(MANDOC_DB);
@@ -454,11 +460,11 @@ mandocdb(int argc, char *argv[])
" from scratch", strerror(errno));
exitcode = (int)MANDOCLEVEL_OK;
op = OP_DEFAULT;
- if (0 == treescan())
+ if (treescan() == 0)
goto out;
dba = dba_new(128);
}
- if (OP_DELETE != op)
+ if (op != OP_DELETE)
mpages_merge(dba, mp);
if (nodb == 0)
dbwrite(dba);
@@ -492,7 +498,7 @@ mandocdb(int argc, char *argv[])
sz = strlen(conf.manpath.paths[j]);
if (sz && conf.manpath.paths[j][sz - 1] == '/')
conf.manpath.paths[j][--sz] = '\0';
- if (0 == sz)
+ if (sz == 0)
continue;
if (j) {
@@ -502,9 +508,9 @@ mandocdb(int argc, char *argv[])
offsetof(struct mlink, file));
}
- if ( ! set_basedir(conf.manpath.paths[j], argc > 0))
+ if (set_basedir(conf.manpath.paths[j], argc > 0) == 0)
continue;
- if (0 == treescan())
+ if (treescan() == 0)
continue;
dba = dba_new(128);
mpages_merge(dba, mp);
@@ -608,9 +614,9 @@ treescan(void)
say(path, "&realpath");
continue;
}
- if (strstr(buf, basedir) != buf
-#ifdef HOMEBREWDIR
- && strstr(buf, HOMEBREWDIR) != buf
+ if (strncmp(buf, basedir, basedir_len) != 0
+#ifdef READ_ALLOWED_PATH
+ && !read_allowed(buf)
#endif
) {
if (warnings) say("",
@@ -623,6 +629,8 @@ treescan(void)
say(path, "&stat");
continue;
}
+ if ((ff->fts_statp->st_mode & S_IFMT) != S_IFREG)
+ continue;
/* FALLTHROUGH */
/*
@@ -777,17 +785,17 @@ treescan(void)
* See treescan() for the fts(3) version of this.
*/
static void
-filescan(const char *file)
+filescan(const char *infile)
{
- char buf[PATH_MAX];
struct stat st;
struct mlink *mlink;
- char *p, *start;
+ char *linkfile, *p, *realdir, *start, *usefile;
+ size_t realdir_len;
assert(use_all);
- if (0 == strncmp(file, "./", 2))
- file += 2;
+ if (strncmp(infile, "./", 2) == 0)
+ infile += 2;
/*
* We have to do lstat(2) before realpath(3) loses
@@ -796,13 +804,13 @@ filescan(const char *file)
* we want to use the orginal file name, while for
* regular files, we want to use the real path.
*/
- if (-1 == lstat(file, &st)) {
+ if (lstat(infile, &st) == -1) {
exitcode = (int)MANDOCLEVEL_BADARG;
- say(file, "&lstat");
+ say(infile, "&lstat");
return;
- } else if (0 == ((S_IFREG | S_IFLNK) & st.st_mode)) {
+ } else if (S_ISREG(st.st_mode) == 0 && S_ISLNK(st.st_mode) == 0) {
exitcode = (int)MANDOCLEVEL_BADARG;
- say(file, "Not a regular file");
+ say(infile, "Not a regular file");
return;
}
@@ -810,23 +818,24 @@ filescan(const char *file)
* We have to resolve the file name to the real path
* in any case for the base directory check.
*/
- if (NULL == realpath(file, buf)) {
+ if ((usefile = realpath(infile, NULL)) == NULL) {
exitcode = (int)MANDOCLEVEL_BADARG;
- say(file, "&realpath");
+ say(infile, "&realpath");
return;
}
- if (OP_TEST == op)
- start = buf;
- else if (strstr(buf, basedir) == buf)
- start = buf + strlen(basedir);
-#ifdef HOMEBREWDIR
- else if (strstr(buf, HOMEBREWDIR) == buf)
- start = buf;
+ if (op == OP_TEST)
+ start = usefile;
+ else if (strncmp(usefile, basedir, basedir_len) == 0)
+ start = usefile + basedir_len;
+#ifdef READ_ALLOWED_PATH
+ else if (read_allowed(usefile))
+ start = usefile;
#endif
else {
exitcode = (int)MANDOCLEVEL_BADARG;
- say("", "%s: outside base directory", buf);
+ say("", "%s: outside base directory", infile);
+ free(usefile);
return;
}
@@ -834,25 +843,72 @@ filescan(const char *file)
* Now we are sure the file is inside our tree.
* If it is a symbolic link, ignore the real path
* and use the original name.
- * This implies passing stuff like "cat1/../man1/foo.1"
- * on the command line won't work. So don't do that.
- * Note the stat(2) can still fail if the link target
- * doesn't exist.
*/
- if (S_IFLNK & st.st_mode) {
- if (-1 == stat(buf, &st)) {
+ do {
+ if (S_ISLNK(st.st_mode) == 0)
+ break;
+
+ /*
+ * Some implementations of realpath(3) may succeed
+ * even if the target of the link does not exist,
+ * so check again for extra safety.
+ */
+ if (stat(usefile, &st) == -1) {
exitcode = (int)MANDOCLEVEL_BADARG;
- say(file, "&stat");
+ say(infile, "&stat");
+ free(usefile);
return;
}
- if (strlcpy(buf, file, sizeof(buf)) >= sizeof(buf)) {
- say(file, "Filename too long");
- return;
+ linkfile = mandoc_strdup(infile);
+ if (op == OP_TEST) {
+ free(usefile);
+ start = usefile = linkfile;
+ break;
}
- start = buf;
- if (OP_TEST != op && strstr(buf, basedir) == buf)
- start += strlen(basedir);
- }
+ if (strncmp(infile, basedir, basedir_len) == 0) {
+ free(usefile);
+ usefile = linkfile;
+ start = usefile + basedir_len;
+ break;
+ }
+
+ /*
+ * This symbolic link points into the basedir
+ * from the outside. Let's see whether any of
+ * the parent directories resolve to the basedir.
+ */
+ p = strchr(linkfile, '\0');
+ do {
+ while (*--p != '/')
+ continue;
+ *p = '\0';
+ if ((realdir = realpath(linkfile, NULL)) == NULL) {
+ exitcode = (int)MANDOCLEVEL_BADARG;
+ say(infile, "&realpath");
+ free(linkfile);
+ free(usefile);
+ return;
+ }
+ realdir_len = strlen(realdir) + 1;
+ free(realdir);
+ *p = '/';
+ } while (realdir_len > basedir_len);
+
+ /*
+ * If one of the directories resolves to the basedir,
+ * use the rest of the original name.
+ * Otherwise, the best we can do
+ * is to use the filename pointed to.
+ */
+ if (realdir_len == basedir_len) {
+ free(usefile);
+ usefile = linkfile;
+ start = p + 1;
+ } else {
+ free(linkfile);
+ start = usefile + basedir_len;
+ }
+ } while (/* CONSTCOND */ 0);
mlink = mandoc_calloc(1, sizeof(struct mlink));
mlink->dform = FORM_NONE;
@@ -860,6 +916,7 @@ filescan(const char *file)
sizeof(mlink->file)) {
say(start, "Filename too long");
free(mlink);
+ free(usefile);
return;
}
@@ -868,13 +925,13 @@ filescan(const char *file)
* 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)
+ if (op == OP_TEST || (start == usefile && *start == '/')) {
+ if (strncmp(usefile, "man/", 4) == 0)
+ start = usefile + 4;
+ else if ((start = strstr(usefile, "/man/")) != NULL)
start += 5;
else
- start = buf;
+ start = usefile;
}
/*
@@ -883,18 +940,18 @@ filescan(const char *file)
* If we find one of these and what's underneath is a directory,
* assume it's an architecture.
*/
- if (NULL != (p = strchr(start, '/'))) {
+ if ((p = strchr(start, '/')) != NULL) {
*p++ = '\0';
- if (0 == strncmp(start, "man", 3)) {
+ if (strncmp(start, "man", 3) == 0) {
mlink->dform = FORM_SRC;
mlink->dsec = start + 3;
- } else if (0 == strncmp(start, "cat", 3)) {
+ } else if (strncmp(start, "cat", 3) == 0) {
mlink->dform = FORM_CAT;
mlink->dsec = start + 3;
}
start = p;
- if (NULL != mlink->dsec && NULL != (p = strchr(start, '/'))) {
+ if (mlink->dsec != NULL && (p = strchr(start, '/')) != NULL) {
*p++ = '\0';
mlink->arch = start;
start = p;
@@ -906,10 +963,10 @@ filescan(const char *file)
* Suffix of `.0' indicates a catpage, `.1-9' is a manpage.
*/
p = strrchr(start, '\0');
- while (p-- > start && '/' != *p && '.' != *p)
- /* Loop. */ ;
+ while (p-- > start && *p != '/' && *p != '.')
+ continue;
- if ('.' == *p) {
+ if (*p == '.') {
*p++ = '\0';
mlink->fsec = p;
}
@@ -919,11 +976,12 @@ filescan(const char *file)
* Use the filename portion of the path.
*/
mlink->name = start;
- if (NULL != (p = strrchr(start, '/'))) {
+ if ((p = strrchr(start, '/')) != NULL) {
mlink->name = p + 1;
*p = '\0';
}
mlink_add(mlink, &st);
+ free(usefile);
}
static void
@@ -2250,7 +2308,6 @@ set_basedir(const char *targetdir, int report_baddir)
static char startdir[PATH_MAX];
static int getcwd_status; /* 1 = ok, 2 = failure */
static int chdir_status; /* 1 = changed directory */
- char *cp;
/*
* Remember the original working directory, if possible.
@@ -2259,8 +2316,8 @@ set_basedir(const char *targetdir, int report_baddir)
* Do not error out if the current directory is not
* searchable: Maybe it won't be needed after all.
*/
- if (0 == getcwd_status) {
- if (NULL == getcwd(startdir, sizeof(startdir))) {
+ if (getcwd_status == 0) {
+ if (getcwd(startdir, sizeof(startdir)) == NULL) {
getcwd_status = 2;
(void)strlcpy(startdir, strerror(errno),
sizeof(startdir));
@@ -2273,19 +2330,20 @@ set_basedir(const char *targetdir, int report_baddir)
* Do not use it any longer, not even for messages.
*/
*basedir = '\0';
+ basedir_len = 0;
/*
* If and only if the directory was changed earlier and
* the next directory to process is given as a relative path,
* first go back, or bail out if that is impossible.
*/
- if (chdir_status && '/' != *targetdir) {
- if (2 == getcwd_status) {
+ if (chdir_status && *targetdir != '/') {
+ if (getcwd_status == 2) {
exitcode = (int)MANDOCLEVEL_SYSERR;
say("", "getcwd: %s", startdir);
return 0;
}
- if (-1 == chdir(startdir)) {
+ if (chdir(startdir) == -1) {
exitcode = (int)MANDOCLEVEL_SYSERR;
say("", "&chdir %s", startdir);
return 0;
@@ -2297,48 +2355,71 @@ set_basedir(const char *targetdir, int report_baddir)
* pathname and append a trailing slash, such that
* we can reliably check whether files are inside.
*/
- if (NULL == realpath(targetdir, basedir)) {
+ if (realpath(targetdir, basedir) == NULL) {
if (report_baddir || errno != ENOENT) {
exitcode = (int)MANDOCLEVEL_BADARG;
say("", "&%s: realpath", targetdir);
}
+ *basedir = '\0';
return 0;
- } else if (-1 == chdir(basedir)) {
+ } else if (chdir(basedir) == -1) {
if (report_baddir || errno != ENOENT) {
exitcode = (int)MANDOCLEVEL_BADARG;
say("", "&chdir");
}
+ *basedir = '\0';
return 0;
}
chdir_status = 1;
- cp = strchr(basedir, '\0');
- if ('/' != cp[-1]) {
- if (cp - basedir >= PATH_MAX - 1) {
+ basedir_len = strlen(basedir);
+ if (basedir[basedir_len - 1] != '/') {
+ if (basedir_len >= PATH_MAX - 1) {
exitcode = (int)MANDOCLEVEL_SYSERR;
say("", "Filename too long");
+ *basedir = '\0';
+ basedir_len = 0;
return 0;
}
- *cp++ = '/';
- *cp = '\0';
+ basedir[basedir_len++] = '/';
+ basedir[basedir_len] = '\0';
}
return 1;
}
+#ifdef READ_ALLOWED_PATH
+static int
+read_allowed(const char *candidate)
+{
+ const char *cp;
+ size_t len;
+
+ for (cp = READ_ALLOWED_PATH;; cp += len) {
+ while (*cp == ':')
+ cp++;
+ if (*cp == '\0')
+ return 0;
+ len = strcspn(cp, ":");
+ if (strncmp(candidate, cp, len) == 0)
+ return 1;
+ }
+}
+#endif
+
static void
say(const char *file, const char *format, ...)
{
va_list ap;
int use_errno;
- if ('\0' != *basedir)
+ if (*basedir != '\0')
fprintf(stderr, "%s", basedir);
- if ('\0' != *basedir && '\0' != *file)
+ if (*basedir != '\0' && *file != '\0')
fputc('/', stderr);
- if ('\0' != *file)
+ if (*file != '\0')
fprintf(stderr, "%s", file);
use_errno = 1;
- if (NULL != format) {
+ if (format != NULL) {
switch (*format) {
case '&':
format++;
@@ -2351,15 +2432,15 @@ say(const char *file, const char *format, ...)
break;
}
}
- if (NULL != format) {
- if ('\0' != *basedir || '\0' != *file)
+ if (format != NULL) {
+ if (*basedir != '\0' || *file != '\0')
fputs(": ", stderr);
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
}
if (use_errno) {
- if ('\0' != *basedir || '\0' != *file || NULL != format)
+ if (*basedir != '\0' || *file != '\0' || format != NULL)
fputs(": ", stderr);
perror(NULL);
} else
diff --git a/manpath.c b/manpath.c
index e4578ccec364..255d748246d6 100644
--- a/manpath.c
+++ b/manpath.c
@@ -1,4 +1,4 @@
-/* $Id: manpath.c,v 1.40 2019/07/10 19:39:01 schwarze Exp $ */
+/* $Id: manpath.c,v 1.43 2020/08/27 14:59:47 schwarze Exp $ */
/*
* Copyright (c) 2011,2014,2015,2017-2019 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -163,7 +163,7 @@ manconf_free(struct manconf *conf)
static void
manconf_file(struct manconf *conf, const char *file)
{
- const char *const toks[] = { "manpath", "output", "_whatdb" };
+ const char *const toks[] = { "manpath", "output" };
char manpath_default[] = MANPATH_DEFAULT;
FILE *stream;
@@ -200,13 +200,6 @@ manconf_file(struct manconf *conf, const char *file)
}
switch (tok) {
- case 2: /* _whatdb */
- while (ep > cp && ep[-1] != '/')
- ep--;
- if (ep == cp)
- continue;
- *ep = '\0';
- /* FALLTHROUGH */
case 0: /* manpath */
manpath_add(&conf->manpath, cp, '\0');
*manpath_default = '\0';
@@ -230,8 +223,13 @@ int
manconf_output(struct manoutput *conf, const char *cp, int fromfile)
{
const char *const toks[] = {
+ /* Tokens requiring an argument. */
"includes", "man", "paper", "style", "indent", "width",
- "tag", "fragment", "mdoc", "noval", "toc"
+ "outfilename", "tagfilename",
+ /* Token taking an optional argument. */
+ "tag",
+ /* Tokens not taking arguments. */
+ "fragment", "mdoc", "noval", "toc"
};
const size_t ntoks = sizeof(toks) / sizeof(toks[0]);
@@ -252,11 +250,11 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile)
}
}
- if (tok < 6 && *cp == '\0') {
+ if (tok < 8 && *cp == '\0') {
mandoc_msg(MANDOCERR_BADVAL_MISS, 0, 0, "-O %s=?", toks[tok]);
return -1;
}
- if (tok > 6 && tok < ntoks && *cp != '\0') {
+ if (tok > 8 && tok < ntoks && *cp != '\0') {
mandoc_msg(MANDOCERR_BADVAL, 0, 0, "-O %s=%s", toks[tok], cp);
return -1;
}
@@ -313,22 +311,40 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile)
"-O width=%s is %s", cp, errstr);
return -1;
case 6:
+ if (conf->outfilename != NULL) {
+ oldval = mandoc_strdup(conf->outfilename);
+ break;
+ }
+ conf->outfilename = mandoc_strdup(cp);
+ return 0;
+ case 7:
+ if (conf->tagfilename != NULL) {
+ oldval = mandoc_strdup(conf->tagfilename);
+ break;
+ }
+ conf->tagfilename = mandoc_strdup(cp);
+ return 0;
+ /*
+ * If the index of the following token changes,
+ * do not forget to adjust the range check above the switch.
+ */
+ case 8:
if (conf->tag != NULL) {
oldval = mandoc_strdup(conf->tag);
break;
}
conf->tag = mandoc_strdup(cp);
return 0;
- case 7:
+ case 9:
conf->fragment = 1;
return 0;
- case 8:
+ case 10:
conf->mdoc = 1;
return 0;
- case 9:
+ case 11:
conf->noval = 1;
return 0;
- case 10:
+ case 12:
conf->toc = 1;
return 0;
default:
diff --git a/mdoc.7 b/mdoc.7
index deca4ba88c05..7ac6ff11c00d 100644
--- a/mdoc.7
+++ b/mdoc.7
@@ -1,7 +1,7 @@
-.\" $Id: mdoc.7,v 1.279 2019/07/15 19:20:30 schwarze Exp $
+.\" $Id: mdoc.7,v 1.287 2021/07/29 17:32:01 schwarze Exp $
.\"
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright (c) 2010, 2011, 2013-2018 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2010, 2011, 2013-2020 Ingo Schwarze <schwarze@openbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@@ -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: July 15 2019 $
+.Dd $Mdocdate: July 29 2021 $
.Dt MDOC 7
.Os
.Sh NAME
@@ -297,7 +297,7 @@ utility does this, that, and the other.
It usually follows with a breakdown of the options (if documenting a
command), such as:
.Bd -literal -offset indent
-The arguments are as follows:
+The options are as follows:
\&.Bl \-tag \-width Ds
\&.It Fl v
Print verbose information.
@@ -449,6 +449,7 @@ in the alphabetical
.It Ic \&Ss Ta subsection header (one line)
.It Ic \&Sx Ta internal cross reference to a section or subsection
.It Ic \&Xr Ta cross reference to another manual page: Ar name section
+.It Ic \&Tg Ta tag the definition of a Ar term Pq <= 1 arguments
.It Ic \&Pp Ta start a text paragraph (no arguments)
.El
.Ss Displays and lists
@@ -631,6 +632,7 @@ Close an
.Ic \&Ao
block.
Does not have any tail arguments.
+.Tg Ad
.It Ic \&Ad Ar address
Memory address.
Do not use this for postal addresses.
@@ -638,6 +640,7 @@ Do not use this for postal addresses.
Examples:
.Dl \&.Ad [0,$]
.Dl \&.Ad 0x00000000
+.Tg An
.It Ic \&An Fl split | nosplit | Ar first_name ... last_name
Author name.
Can be used both for the authors of the program, function, or driver
@@ -678,6 +681,7 @@ This macro is almost never useful.
See
.Ic \&Aq
for more details.
+.Tg Ap
.It Ic \&Ap
Inserts an apostrophe without any surrounding whitespace.
This is generally used as a grammatical device when referring to the verb
@@ -685,6 +689,7 @@ form of a function.
.Pp
Examples:
.Dl \&.Fn execve \&Ap d
+.Tg Aq
.It Ic \&Aq Ar line
Enclose the rest of the input line in angle brackets.
The only important use case is for email addresses.
@@ -729,6 +734,7 @@ as needed.
.Pp
See also
.Ic \&Ao .
+.Tg Ar
.It Ic \&Ar Op Ar placeholder ...
Command arguments.
If an argument is not provided, the string
@@ -747,6 +753,7 @@ for fixed strings to be passed verbatim as arguments, use
.Ic \&Fl
or
.Ic \&Cm .
+.Tg At
.It Ic \&At Op Ar version
Formats an
.At
@@ -784,6 +791,7 @@ Close a
.Ic \&Bo
block.
Does not have any tail arguments.
+.Tg Bd
.It Ic \&Bd Fl Ns Ar type Oo Fl offset Ar width Oc Op Fl compact
Begin a display block.
Display blocks are used to select a different indentation and
@@ -874,6 +882,7 @@ See also
.Ic \&D1
and
.Ic \&Dl .
+.Tg Bf
.It Ic \&Bf Fl emphasis | literal | symbolic | Cm \&Em | \&Li | \&Sy
Change the font mode for a scoped block of text.
The
@@ -900,6 +909,7 @@ See also
.Ic \&Em ,
and
.Ic \&Sy .
+.Tg Bk
.It Ic \&Bk Fl words
For each macro, keep its output together on the same output line,
until the end of the macro or the end of the input line is reached,
@@ -922,6 +932,7 @@ macro line:
.Pp
Be careful in using over-long lines within a keep block!
Doing so will clobber the right margin.
+.Tg Bl
.It Xo
.Ic \&Bl
.Fl Ns Ar type
@@ -1064,6 +1075,7 @@ Examples:
.Pp
See also
.Ic \&Bq .
+.Tg Bq
.It Ic \&Bq Ar line
Encloses its arguments in square brackets.
.Pp
@@ -1097,6 +1109,7 @@ Examples:
.Pp
See also
.Ic \&Brq .
+.Tg Brq
.It Ic \&Brq Ar line
Encloses its arguments in curly braces.
.Pp
@@ -1105,6 +1118,7 @@ Examples:
.Pp
See also
.Ic \&Bro .
+.Tg Bsx
.It Ic \&Bsx Op Ar version
Format the
.Bsx
@@ -1127,6 +1141,7 @@ and
Supported only for compatibility, do not use this in new manuals.
Prints
.Dq is currently in beta test.
+.Tg Bx
.It Ic \&Bx Op Ar version Op Ar variant
Format the
.Bx
@@ -1146,6 +1161,7 @@ See also
.Ic \&Nx ,
and
.Ic \&Ox .
+.Tg Cd
.It Ic \&Cd Ar line
Kernel configuration declaration.
This denotes strings accepted by
@@ -1161,6 +1177,7 @@ whitespace and align consecutive
.Ic \&Cd
declarations.
This practise is discouraged.
+.Tg Cm
.It Ic \&Cm Ar keyword ...
Command modifiers.
Typically used for fixed strings passed as arguments to interactive
@@ -1176,6 +1193,7 @@ Examples:
.Dl ".Ic set Fl o Cm vi"
.Dl ".Ic lookup Cm file bind"
.Dl ".Ic permit Ar identity Op Cm as Ar target"
+.Tg D1
.It Ic \&D1 Ar line
One-line indented display.
This is formatted by the default rules and is useful for simple indented
@@ -1201,8 +1219,10 @@ Close a
.Ic \&Do
block.
Does not have any tail arguments.
+.Tg Dd
.It Ic \&Dd Cm $\&Mdocdate$ | Ar month day , year
-Document date for display in the page footer.
+Document date for display in the page footer,
+by convention the date of the last change.
This is the mandatory first macro of any
.Nm
manual.
@@ -1248,6 +1268,7 @@ See also
.Ic \&Dt
and
.Ic \&Os .
+.Tg Dl
.It Ic \&Dl Ar line
One-line indented display.
This is formatted as literal text and is useful for commands and
@@ -1276,6 +1297,7 @@ April is the cruellest month
.Pp
See also
.Ic \&Dq .
+.Tg Dq
.It Ic \&Dq Ar line
Encloses its arguments in
.Dq typographic
@@ -1292,6 +1314,7 @@ See also
.Ic \&Sq ,
and
.Ic \&Do .
+.Tg Dt
.It Ic \&Dt Ar TITLE section Op Ar arch
Document title for display in the page header.
This is the mandatory second macro of any
@@ -1351,6 +1374,7 @@ See also
.Ic \&Dd
and
.Ic \&Os .
+.Tg Dv
.It Ic \&Dv Ar identifier ...
Defined variables such as preprocessor constants, constant symbols,
enumeration values, and so on.
@@ -1370,6 +1394,7 @@ for variable symbols, and
.Ic \&Fd
for listing preprocessor variable definitions in the
.Em SYNOPSIS .
+.Tg Dx
.It Ic \&Dx Op Ar version
Format the
.Dx
@@ -1411,6 +1436,7 @@ End a list context started by
.Ic \&Bl .
See also
.Ic \&It .
+.Tg Em
.It Ic \&Em Ar word ...
Request an italic font.
If the output device does not provide that, underline.
@@ -1450,6 +1476,7 @@ or any of the other enclosure macros.
It encloses its argument in the delimiters specified by the last
.Ic \&Es
macro.
+.Tg Eo
.It Ic \&Eo Op Ar opening_delimiter
An arbitrary enclosure.
The
@@ -1457,6 +1484,7 @@ The
argument is used as the enclosure head, for example, specifying \e(lq
will emulate
.Ic \&Do .
+.Tg Er
.It Ic \&Er Ar identifier ...
Error constants for definitions of the
.Va errno
@@ -1479,6 +1507,7 @@ or any of the other enclosure macros.
It takes two arguments, defining the delimiters to be used by subsequent
.Ic \&En
macros.
+.Tg Ev
.It Ic \&Ev Ar identifier ...
Environmental variables such as those specified in
.Xr environ 7 .
@@ -1490,6 +1519,7 @@ Examples:
See also
.Ic \&Dv
for general constants.
+.Tg Ex
.It Ic \&Ex Fl std Op Ar utility ...
Insert a standard sentence regarding command exit values of 0 on success
and >0 on failure.
@@ -1506,6 +1536,7 @@ arguments are treated as separate utilities.
.Pp
See also
.Ic \&Rv .
+.Tg Fa
.It Ic \&Fa Ar argument ...
Function argument or parameter.
Each argument may be a name and a type (recommended for the
@@ -1543,6 +1574,7 @@ See also
.It Ic \&Fc
End a function context started by
.Ic \&Fo .
+.Tg Fd
.It Ic \&Fd Pf # Ar directive Op Ar argument ...
Preprocessor directive, in particular for listing it in the
.Em SYNOPSIS .
@@ -1563,25 +1595,33 @@ See also
.Ic \&In ,
and
.Ic \&Dv .
+.Tg Fl
.It Ic \&Fl Op Ar word ...
Command-line flag or option.
Used when listing arguments to command-line utilities.
-Prints a fixed-width hyphen
-.Sq \-
-directly followed by each argument.
-If no arguments are provided, a hyphen is printed followed by a space.
-If the argument is a macro, a hyphen is prefixed to the subsequent macro
-output.
+For each argument, prints an ASCII hyphen-minus character
+.Sq \- ,
+immediately followed by the argument.
+If no arguments are provided, a hyphen-minus is printed followed by a space.
+If the argument is a macro, a hyphen-minus is prefixed
+to the subsequent macro output.
.Pp
Examples:
-.Dl ".Fl R Op Fl H | L | P"
-.Dl ".Op Fl 1AaCcdFfgHhikLlmnopqRrSsTtux"
-.Dl ".Fl type Cm d Fl name Pa CVS"
-.Dl ".Fl Ar signal_number"
-.Dl ".Fl o Fl"
+.Dl ".Nm du Op Fl H | L | P"
+.Dl ".Nm ls Op Fl 1AaCcdFfgHhikLlmnopqRrSsTtux"
+.Dl ".Nm route Cm add Fl inet Ar destination gateway"
+.Dl ".Nm locate.updatedb Op Fl \e-fcodes Ns = Ns Ar dbfile"
+.Dl ".Nm aucat Fl o Fl"
+.Dl ".Nm kill Fl Ar signal_number"
+.Pp
+For GNU-sytle long options, escaping the additional hyphen-minus is not
+strictly required, but may be safer with future versions of GNU troff; see
+.Xr mandoc_char 7
+for details.
.Pp
See also
.Ic \&Cm .
+.Tg Fn
.It Ic \&Fn Ar funcname Op Ar argument ...
A function name.
.Pp
@@ -1610,6 +1650,7 @@ See also
.Ic \&Fo ,
and
.Ic \&Ft .
+.Tg Fo
.It Ic \&Fo Ar funcname
Begin a function block.
This is a multi-line version of
@@ -1644,6 +1685,7 @@ This macro is obsolete.
No replacement markup is needed.
.Pp
It was used to show numerical function return values in an italic font.
+.Tg Ft
.It Ic \&Ft Ar functype
A function type.
.Pp
@@ -1663,6 +1705,7 @@ See also
.Ic \&Fn ,
and
.Ic \&Fo .
+.Tg Fx
.It Ic \&Fx Op Ar version
Format the
.Fx
@@ -1685,6 +1728,7 @@ and
This macro is not implemented in
.Xr mandoc 1 .
It was used to include the contents of a (header) file literally.
+.Tg Ic
.It Ic \&Ic Ar keyword ...
Internal or interactive command, or configuration instruction
in a configuration file.
@@ -1704,6 +1748,7 @@ or
is preferred for displaying code samples; the
.Ic \&Ic
macro is used when referring to an individual command name.
+.Tg In
.It Ic \&In Ar filename
The name of an include file.
This macro is most often used in section 2, 3, and 9 manual pages.
@@ -1723,6 +1768,7 @@ Examples:
.Pp
See also
.Sx MANUAL STRUCTURE .
+.Tg It
.It Ic \&It Op Ar head
A list item.
The syntax of this macro depends on the list type.
@@ -1813,6 +1859,7 @@ but not the whitespace before the semicolon.
.Pp
See also
.Ic \&Bl .
+.Tg Lb
.It Ic \&Lb Cm lib Ns Ar name
Specify a library.
.Pp
@@ -1833,6 +1880,7 @@ section as described in
Examples:
.Dl \&.Lb libz
.Dl \&.Lb libmandoc
+.Tg Li
.It Ic \&Li Ar word ...
Request a typewriter (literal) font.
Deprecated because on terminal output devices, this is usually
@@ -1843,24 +1891,27 @@ For literal displays, use
or
.Ic \&Bd Fl literal Pq multi-line
instead.
+.Tg Lk
.It Ic \&Lk Ar uri Op Ar display_name
Format a hyperlink.
.Pp
Examples:
-.Dl \&.Lk http://bsd.lv \(dqThe BSD.lv Project\(dq
-.Dl \&.Lk http://bsd.lv
+.Dl \&.Lk https://bsd.lv \(dqThe BSD.lv Project\(dq
+.Dl \&.Lk https://bsd.lv
.Pp
See also
.Ic \&Mt .
.It Ic \&Lp
Deprecated synonym for
.Ic \&Pp .
+.Tg Ms
.It Ic \&Ms Ar name
Display a mathematical symbol.
.Pp
Examples:
.Dl \&.Ms sigma
.Dl \&.Ms aleph
+.Tg Mt
.It Ic \&Mt Ar localpart Ns @ Ns Ar domain
Format a
.Dq mailto:
@@ -1869,6 +1920,7 @@ hyperlink.
Examples:
.Dl \&.Mt discuss@manpages.bsd.lv
.Dl \&.An Kristaps Dzonsons \&Aq \&Mt kristaps@bsd.lv
+.Tg Nd
.It Ic \&Nd Ar line
A one line description of the manual's content.
This is the mandatory last macro of the
@@ -1891,6 +1943,7 @@ arguments and will display macros verbatim.
.Pp
See also
.Ic \&Nm .
+.Tg Nm
.It Ic \&Nm Op Ar name
The name of the manual page, or \(em in particular in section 1, 6,
and 8 pages \(em of an additional command or feature documented in
@@ -1928,6 +1981,7 @@ of section 2, 3 and 9 manual pages, use the
macro rather than
.Ic \&Nm
to mark up the name of the manual page.
+.Tg No
.It Ic \&No Ar word ...
Normal text.
Closes the scope of any preceding in-line macro.
@@ -1952,6 +2006,7 @@ See also
.Ic \&Ql ,
and
.Ic \&Sy .
+.Tg Ns
.It Ic \&Ns
Suppress a space between the output of the preceding macro
and the following text or macro.
@@ -1971,6 +2026,7 @@ See also
.Ic \&No
and
.Ic \&Sm .
+.Tg Nx
.It Ic \&Nx Op Ar version
Format the
.Nx
@@ -2003,6 +2059,7 @@ Examples:
\&.Op Fl flag Ns Ar value
\&.Oc
.Ed
+.Tg Op
.It Ic \&Op Ar line
Optional part of a command line.
Prints the argument(s) in brackets.
@@ -2016,6 +2073,7 @@ Examples:
.Pp
See also
.Ic \&Oo .
+.Tg Os
.It Ic \&Os Op Ar system Op Ar version
Operating system version for display in the page footer.
This is the mandatory third macro of
@@ -2058,6 +2116,7 @@ Historical
.Nm
packages described it as
.Dq "old function type (FORTRAN)" .
+.Tg Ox
.It Ic \&Ox Op Ar version
Format the
.Ox
@@ -2076,6 +2135,7 @@ See also
.Ic \&Fx ,
and
.Ic \&Nx .
+.Tg Pa
.It Ic \&Pa Ar name ...
An absolute or relative file system path, or a file or directory name.
If an argument is not provided, the character
@@ -2091,6 +2151,7 @@ See also
.It Ic \&Pc
Close parenthesised context opened by
.Ic \&Po .
+.Tg Pf
.It Ic \&Pf Ar prefix macro Op Ar argument ...
Removes the space between its argument and the following macro.
It is equivalent to:
@@ -2114,6 +2175,7 @@ and
.It Ic \&Po Ar block
Multi-line version of
.Ic \&Pq .
+.Tg Pp
.It Ic \&Pp
Break a paragraph.
This will assert vertical space between prior and subsequent macros
@@ -2130,6 +2192,7 @@ or lists
unless the
.Fl compact
flag is given.
+.Tg Pq
.It Ic \&Pq Ar line
Parenthesised enclosure.
.Pp
@@ -2138,6 +2201,7 @@ See also
.It Ic \&Qc
Close quoted context opened by
.Ic \&Qo .
+.Tg Ql
.It Ic \&Ql Ar line
In-line literal display.
This can be used for complete command invocations and for multi-word
@@ -2151,6 +2215,7 @@ and
.It Ic \&Qo Ar block
Multi-line version of
.Ic \&Qq .
+.Tg Qq
.It Ic \&Qq Ar line
Encloses its arguments in
.Qq typewriter
@@ -2168,6 +2233,7 @@ Close an
.Ic \&Rs
block.
Does not have any tail arguments.
+.Tg Rs
.It Ic \&Rs
Begin a bibliographic
.Pq Dq reference
@@ -2208,6 +2274,7 @@ If an
block is used within a SEE ALSO section, a vertical space is asserted
before the rendered output, else the block continues on the current
line.
+.Tg Rv
.It Ic \&Rv Fl std Op Ar function ...
Insert a standard sentence regarding a function call's return value of 0
on success and \-1 on error, with the
@@ -2228,6 +2295,7 @@ See also
.It Ic \&Sc
Close single-quoted context opened by
.Ic \&So .
+.Tg Sh
.It Ic \&Sh Ar TITLE LINE
Begin a new section.
For a list of conventional manual sections, see
@@ -2246,6 +2314,7 @@ See also
.Ic \&Ss ,
and
.Ic \&Sx .
+.Tg Sm
.It Ic \&Sm Op Cm on | off
Switches the spacing mode for output generated from macros.
.Pp
@@ -2264,6 +2333,7 @@ Using this is not recommended because it makes the code harder to read.
.It Ic \&So Ar block
Multi-line version of
.Ic \&Sq .
+.Tg Sq
.It Ic \&Sq Ar line
Encloses its arguments in
.Sq typewriter
@@ -2274,6 +2344,7 @@ See also
.Ic \&Qq ,
and
.Ic \&So .
+.Tg Ss
.It Ic \&Ss Ar Title line
Begin a new subsection.
Unlike with
@@ -2296,6 +2367,7 @@ See also
.Ic \&Sh ,
and
.Ic \&Sx .
+.Tg St
.It Ic \&St Fl Ns Ar abbreviation
Replace an abbreviation for a standard with the full form.
The following standards are recognised.
@@ -2506,6 +2578,7 @@ Ethernet local area networks.
.St -ieee1275-94
.El
.El
+.Tg Sx
.It Ic \&Sx Ar Title line
Reference a section or subsection in the same manual page.
The referenced section or subsection name must be identical to the
@@ -2518,6 +2591,7 @@ See also
.Ic \&Sh
and
.Ic \&Ss .
+.Tg Sy
.It Ic \&Sy Ar word ...
Request a boldface font.
.Pp
@@ -2543,11 +2617,56 @@ See also
.Ic \&No ,
and
.Ic \&Ql .
+.Tg Ta
.It Ic \&Ta
Table cell separator in
.Ic \&Bl Fl column
lists; can only be used below
.Ic \&It .
+.Tg Tg
+.It Ic \&Tg Op Ar term
+Announce that the next input line starts a definition of the
+.Ar term .
+This macro must appear alone on its own input line.
+The argument defaults to the first argument of the first macro
+on the next line.
+The argument may not contain whitespace characters, not even when it is quoted.
+This macro is a
+.Xr mandoc 1
+extension and is typically ignored by other formatters.
+.Pp
+When viewing terminal output with
+.Xr less 1 ,
+the interactive
+.Ic :t
+command can be used to go to the definition of the
+.Ar term
+as described for the
+.Ev MANPAGER
+variable in
+.Xr man 1 ;
+when producing HTML output, a fragment identifier
+.Pq Ic id No attribute
+is generated, to be used for deep linking to this place of the document.
+.Pp
+In most cases, adding a
+.Ic \&Tg
+macro would be redundant because
+.Xr mandoc 1
+is able to automatically tag most definitions.
+This macro is intended for cases where automatic tagging of a
+.Ar term
+is unsatisfactory, for example if a definition is not tagged
+automatically (false negative) or if places are tagged that do
+not define the
+.Ar term
+(false positives).
+When there is at least one
+.Ic \&Tg
+macro for a
+.Ar term ,
+no other places are automatically marked as definitions of that
+.Ar term .
.It Ic \&Tn Ar word ...
Supported only for compatibility, do not use this in new manuals.
Even though the macro name
@@ -2562,6 +2681,7 @@ Prints out
Supported only for compatibility, do not use this in new manuals.
Prints out
.Dq Ux .
+.Tg Va
.It Ic \&Va Oo Ar type Oc Ar identifier ...
A variable name.
.Pp
@@ -2576,6 +2696,7 @@ For declarations of global variables in the
.Em SYNOPSIS
section, use
.Ic \&Vt .
+.Tg Vt
.It Ic \&Vt Ar type Op Ar identifier
A variable type.
.Pp
@@ -2619,6 +2740,7 @@ beyond the end of the input line.
This macro originally existed to work around the 9-argument limit
of historic
.Xr roff 7 .
+.Tg Xr
.It Ic \&Xr Ar name section
Link to another manual
.Pq Qq cross-reference .
@@ -2681,7 +2803,7 @@ column, if applicable, describes closure rules.
.Ss Block full-explicit
Multi-line scope closed by an explicit closing macro.
All macros contains bodies; only
-.Ic \s&Bf
+.Ic \&Bf
and
.Pq optionally
.Ic \&Bl
@@ -2912,6 +3034,7 @@ then the macro accepts an arbitrary number of arguments.
.It Ic \&St Ta \&No Ta Yes Ta 1
.It Ic \&Sx Ta Yes Ta Yes Ta >0
.It Ic \&Sy Ta Yes Ta Yes Ta >0
+.It Ic \&Tg Ta \&No Ta \&No Ta <2
.It Ic \&Tn Ta Yes Ta Yes Ta >0
.It Ic \&Ud Ta \&No Ta \&No Ta 0
.It Ic \&Ux Ta Yes Ta Yes Ta n
@@ -3039,17 +3162,6 @@ The following problematic behaviour is found in groff:
.Pp
.Bl -dash -compact
.It
-.Ic \&Dd
-with non-standard arguments behaves very strangely.
-When there are three arguments, they are printed verbatim.
-Any other number of arguments is replaced by the current date,
-but without any arguments the string
-.Dq Epoch
-is printed.
-.It
-.Ic \&Lk
-only accepts a single link-name argument; the remainder is misformatted.
-.It
.Ic \&Pa
does not format its arguments when used in the FILES section under
certain list types.
@@ -3057,9 +3169,6 @@ certain list types.
.Ic \&Ta
can only be called by other macros, but not at the beginning of a line.
.It
-.Ic \&%C
-is not implemented (up to and including groff-1.22.2).
-.It
.Sq \ef
.Pq font face
and
@@ -3109,10 +3218,16 @@ but produces large indentations.
.Xr tbl 7
.Pp
The web page
-.Lk http://mandoc.bsd.lv/mdoc/ "extended documentation for the mdoc language"
+.Lk https://mandoc.bsd.lv/mdoc/ "extended documentation for the mdoc language"
provides a few tutorial-style pages for beginners, an extensive style
guide for advanced authors, and an alphabetic index helping to choose
the best macros for various kinds of content.
+.Pp
+The manual page
+.Lk https://man.voidlinux.org/groff_mdoc "groff_mdoc(7)"
+contained in the
+.Dq groff
+package documents exactly the same language in a somewhat different style.
.Sh HISTORY
The
.Nm
diff --git a/mdoc.c b/mdoc.c
index bb3ec58bd0f7..475a6aa0ddb3 100644
--- a/mdoc.c
+++ b/mdoc.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc.c,v 1.274 2018/12/31 07:46:07 schwarze Exp $ */
+/* $Id: mdoc.c,v 1.275 2020/04/06 10:16:17 schwarze Exp $ */
/*
+ * Copyright (c) 2010, 2012-2018, 2020 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012-2018 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,6 +14,8 @@
* 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.
+ *
+ * Top level and utility functions of the mdoc(7) parser for mandoc(1).
*/
#include "config.h"
@@ -352,12 +354,13 @@ mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs)
mandoc_msg(MANDOCERR_SPACE_EOL, ln, offs - 1, NULL);
/*
- * If an initial macro or a list invocation, divert directly
- * into macro processing.
+ * If an initial or transparent macro or a list invocation,
+ * divert directly into macro processing.
*/
n = mdoc->last;
- if (n == NULL || tok == MDOC_It || tok == MDOC_El) {
+ if (n == NULL || tok == MDOC_It || tok == MDOC_El ||
+ roff_tok_transparent(tok)) {
(*mdoc_macro(tok)->fp)(mdoc, tok, ln, sv, &offs, buf);
return 1;
}
diff --git a/mdoc_html.c b/mdoc_html.c
index 87bf42a72ba0..c0a0a6a56978 100644
--- a/mdoc_html.c
+++ b/mdoc_html.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc_html.c,v 1.328 2019/03/01 10:57:18 schwarze Exp $ */
+/* $Id: mdoc_html.c,v 1.342 2021/03/30 19:26:20 schwarze Exp $ */
/*
+ * Copyright (c) 2014-2021 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014-2019 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,6 +14,8 @@
* 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.
+ *
+ * HTML formatter for mdoc(7) used by mandoc(1).
*/
#include "config.h"
@@ -47,13 +49,11 @@ struct mdoc_html_act {
void (*post)(MDOC_ARGS);
};
-static char *cond_id(const struct roff_node *);
static void print_mdoc_head(const struct roff_meta *,
struct html *);
static void print_mdoc_node(MDOC_ARGS);
static void print_mdoc_nodelist(MDOC_ARGS);
-static void synopsis_pre(struct html *,
- const struct roff_node *);
+static void synopsis_pre(struct html *, struct roff_node *);
static void mdoc_root_post(const struct roff_meta *,
struct html *);
@@ -73,9 +73,8 @@ static void mdoc_bk_post(MDOC_ARGS);
static int mdoc_bk_pre(MDOC_ARGS);
static int mdoc_bl_pre(MDOC_ARGS);
static int mdoc_cd_pre(MDOC_ARGS);
-static int mdoc_cm_pre(MDOC_ARGS);
+static int mdoc_code_pre(MDOC_ARGS);
static int mdoc_d1_pre(MDOC_ARGS);
-static int mdoc_dv_pre(MDOC_ARGS);
static int mdoc_fa_pre(MDOC_ARGS);
static int mdoc_fd_pre(MDOC_ARGS);
static int mdoc_fl_pre(MDOC_ARGS);
@@ -84,20 +83,15 @@ static int mdoc_ft_pre(MDOC_ARGS);
static int mdoc_em_pre(MDOC_ARGS);
static void mdoc_eo_post(MDOC_ARGS);
static int mdoc_eo_pre(MDOC_ARGS);
-static int mdoc_er_pre(MDOC_ARGS);
-static int mdoc_ev_pre(MDOC_ARGS);
static int mdoc_ex_pre(MDOC_ARGS);
static void mdoc_fo_post(MDOC_ARGS);
static int mdoc_fo_pre(MDOC_ARGS);
-static int mdoc_ic_pre(MDOC_ARGS);
static int mdoc_igndelim_pre(MDOC_ARGS);
static int mdoc_in_pre(MDOC_ARGS);
static int mdoc_it_pre(MDOC_ARGS);
static int mdoc_lb_pre(MDOC_ARGS);
-static int mdoc_li_pre(MDOC_ARGS);
static int mdoc_lk_pre(MDOC_ARGS);
static int mdoc_mt_pre(MDOC_ARGS);
-static int mdoc_ms_pre(MDOC_ARGS);
static int mdoc_nd_pre(MDOC_ARGS);
static int mdoc_nm_pre(MDOC_ARGS);
static int mdoc_no_pre(MDOC_ARGS);
@@ -115,6 +109,7 @@ 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_tg_pre(MDOC_ARGS);
static int mdoc_va_pre(MDOC_ARGS);
static int mdoc_vt_pre(MDOC_ARGS);
static int mdoc_xr_pre(MDOC_ARGS);
@@ -139,19 +134,19 @@ static const struct mdoc_html_act mdoc_html_acts[MDOC_MAX - MDOC_Dd] = {
{mdoc_ap_pre, NULL}, /* Ap */
{mdoc_ar_pre, NULL}, /* Ar */
{mdoc_cd_pre, NULL}, /* Cd */
- {mdoc_cm_pre, NULL}, /* Cm */
- {mdoc_dv_pre, NULL}, /* Dv */
- {mdoc_er_pre, NULL}, /* Er */
- {mdoc_ev_pre, NULL}, /* Ev */
+ {mdoc_code_pre, NULL}, /* Cm */
+ {mdoc_code_pre, NULL}, /* Dv */
+ {mdoc_code_pre, NULL}, /* Er */
+ {mdoc_code_pre, NULL}, /* Ev */
{mdoc_ex_pre, NULL}, /* Ex */
{mdoc_fa_pre, NULL}, /* Fa */
{mdoc_fd_pre, NULL}, /* Fd */
{mdoc_fl_pre, NULL}, /* Fl */
{mdoc_fn_pre, NULL}, /* Fn */
{mdoc_ft_pre, NULL}, /* Ft */
- {mdoc_ic_pre, NULL}, /* Ic */
+ {mdoc_code_pre, NULL}, /* Ic */
{mdoc_in_pre, NULL}, /* In */
- {mdoc_li_pre, NULL}, /* Li */
+ {mdoc_code_pre, NULL}, /* Li */
{mdoc_nd_pre, NULL}, /* Nd */
{mdoc_nm_pre, NULL}, /* Nm */
{mdoc_quote_pre, mdoc_quote_post}, /* Op */
@@ -192,7 +187,7 @@ static const struct mdoc_html_act mdoc_html_acts[MDOC_MAX - MDOC_Dd] = {
{mdoc_em_pre, NULL}, /* Em */
{mdoc_eo_pre, mdoc_eo_post}, /* Eo */
{mdoc_xx_pre, NULL}, /* Fx */
- {mdoc_ms_pre, NULL}, /* Ms */
+ {mdoc_no_pre, NULL}, /* Ms */
{mdoc_no_pre, NULL}, /* No */
{mdoc_ns_pre, NULL}, /* Ns */
{mdoc_xx_pre, NULL}, /* Nx */
@@ -241,6 +236,7 @@ static const struct mdoc_html_act mdoc_html_acts[MDOC_MAX - MDOC_Dd] = {
{mdoc__x_pre, mdoc__x_post}, /* %Q */
{mdoc__x_pre, mdoc__x_post}, /* %U */
{NULL, NULL}, /* Ta */
+ {mdoc_tg_pre, NULL}, /* Tg */
};
@@ -248,13 +244,15 @@ static const struct mdoc_html_act mdoc_html_acts[MDOC_MAX - MDOC_Dd] = {
* See the same function in mdoc_term.c for documentation.
*/
static void
-synopsis_pre(struct html *h, const struct roff_node *n)
+synopsis_pre(struct html *h, struct roff_node *n)
{
+ struct roff_node *np;
- if (NULL == n->prev || ! (NODE_SYNPRETTY & n->flags))
+ if ((n->flags & NODE_SYNPRETTY) == 0 ||
+ (np = roff_node_prev(n)) == NULL)
return;
- if (n->prev->tok == n->tok &&
+ if (np->tok == n->tok &&
MDOC_Fo != n->tok &&
MDOC_Ft != n->tok &&
MDOC_Fn != n->tok) {
@@ -262,7 +260,7 @@ synopsis_pre(struct html *h, const struct roff_node *n)
return;
}
- switch (n->prev->tok) {
+ switch (np->tok) {
case MDOC_Fd:
case MDOC_Fn:
case MDOC_Fo:
@@ -351,30 +349,40 @@ print_mdoc_node(MDOC_ARGS)
if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
return;
- html_fillmode(h, n->flags & NODE_NOFILL ? ROFF_nf : ROFF_fi);
+ if ((n->flags & NODE_NOFILL) == 0)
+ html_fillmode(h, ROFF_fi);
+ else if (html_fillmode(h, ROFF_nf) == ROFF_nf &&
+ n->tok != ROFF_fi && n->flags & NODE_LINE)
+ print_endline(h);
child = 1;
n->flags &= ~NODE_ENDED;
switch (n->type) {
case ROFFT_TEXT:
+ if (n->flags & NODE_LINE) {
+ switch (*n->string) {
+ case '\0':
+ h->col = 1;
+ print_endline(h);
+ return;
+ case ' ':
+ if ((h->flags & HTML_NONEWLINE) == 0 &&
+ (n->flags & NODE_NOFILL) == 0)
+ print_otag(h, TAG_BR, "");
+ break;
+ default:
+ break;
+ }
+ }
t = h->tag;
t->refcnt++;
-
- /* No tables in this mode... */
- assert(NULL == h->tblt);
-
- /*
- * Make sure that if we're in a literal mode already
- * (i.e., within a <PRE>) don't print the newline.
- */
- if (*n->string == ' ' && n->flags & NODE_LINE &&
- (h->flags & HTML_NONEWLINE) == 0 &&
- (n->flags & NODE_NOFILL) == 0)
- print_otag(h, TAG_BR, "");
- if (NODE_DELIMC & n->flags)
+ if (n->flags & NODE_DELIMC)
h->flags |= HTML_NOSPACE;
- print_text(h, n->string);
- if (NODE_DELIMO & n->flags)
+ if (n->flags & NODE_HREF)
+ print_tagged_text(h, n->string, n);
+ else
+ print_text(h, n->string);
+ if (n->flags & NODE_DELIMO)
h->flags |= HTML_NOSPACE;
break;
case ROFFT_EQN:
@@ -439,12 +447,6 @@ print_mdoc_node(MDOC_ARGS)
n->body->flags |= NODE_ENDED;
break;
}
-
- if (n->flags & NODE_NOFILL &&
- (n->next == NULL || n->next->flags & NODE_LINE)) {
- h->col++;
- print_endline(h);
- }
}
static void
@@ -502,20 +504,11 @@ mdoc_root_pre(const struct roff_meta *meta, struct html *h)
return 1;
}
-static char *
-cond_id(const struct roff_node *n)
+static int
+mdoc_code_pre(MDOC_ARGS)
{
- if (n->child != NULL &&
- n->child->type == ROFFT_TEXT &&
- (n->prev == NULL ||
- (n->prev->type == ROFFT_TEXT &&
- strcmp(n->prev->string, "|") == 0)) &&
- (n->parent->tok == MDOC_It ||
- (n->parent->tok == MDOC_Xo &&
- n->parent->parent->prev == NULL &&
- n->parent->parent->parent->tok == MDOC_It)))
- return html_make_id(n, 1);
- return NULL;
+ print_otag_id(h, TAG_CODE, roff_name[n->tok], n);
+ return 1;
}
static int
@@ -578,10 +571,7 @@ mdoc_sh_pre(MDOC_ARGS)
print_otag(h, TAG_SECTION, "c", "Sh");
break;
case ROFFT_HEAD:
- id = html_make_id(n, 1);
- print_otag(h, TAG_H1, "ci", "Sh", id);
- if (id != NULL)
- print_otag(h, TAG_A, "chR", "permalink", id);
+ print_otag_id(h, TAG_H1, "Sh", n);
break;
case ROFFT_BODY:
if (n->sec == SEC_AUTHORS)
@@ -596,64 +586,43 @@ mdoc_sh_pre(MDOC_ARGS)
static int
mdoc_ss_pre(MDOC_ARGS)
{
- char *id;
-
switch (n->type) {
case ROFFT_BLOCK:
html_close_paragraph(h);
print_otag(h, TAG_SECTION, "c", "Ss");
- return 1;
+ break;
case ROFFT_HEAD:
+ print_otag_id(h, TAG_H2, "Ss", n);
break;
case ROFFT_BODY:
- return 1;
+ break;
default:
abort();
}
-
- id = html_make_id(n, 1);
- print_otag(h, TAG_H2, "ci", "Ss", id);
- if (id != NULL)
- print_otag(h, TAG_A, "chR", "permalink", id);
return 1;
}
static int
mdoc_fl_pre(MDOC_ARGS)
{
- char *id;
-
- if ((id = cond_id(n)) != NULL)
- print_otag(h, TAG_A, "chR", "permalink", id);
- print_otag(h, TAG_CODE, "ci", "Fl", id);
+ struct roff_node *nn;
+ print_otag_id(h, TAG_CODE, "Fl", n);
print_text(h, "\\-");
- if (!(n->child == NULL &&
- (n->next == NULL ||
- n->next->type == ROFFT_TEXT ||
- n->next->flags & NODE_LINE)))
+ if (n->child != NULL ||
+ ((nn = roff_node_next(n)) != NULL &&
+ nn->type != ROFFT_TEXT &&
+ (nn->flags & NODE_LINE) == 0))
h->flags |= HTML_NOSPACE;
return 1;
}
static int
-mdoc_cm_pre(MDOC_ARGS)
-{
- char *id;
-
- if ((id = cond_id(n)) != NULL)
- print_otag(h, TAG_A, "chR", "permalink", id);
- print_otag(h, TAG_CODE, "ci", "Cm", id);
- return 1;
-}
-
-static int
mdoc_nd_pre(MDOC_ARGS)
{
switch (n->type) {
case ROFFT_BLOCK:
- html_close_paragraph(h);
return 1;
case ROFFT_HEAD:
return 0;
@@ -663,8 +632,7 @@ mdoc_nd_pre(MDOC_ARGS)
abort();
}
print_text(h, "\\(em");
- /* Cannot use TAG_SPAN because it may contain blocks. */
- print_otag(h, TAG_DIV, "c", "Nd");
+ print_otag(h, TAG_SPAN, "c", "Nd");
return 1;
}
@@ -722,6 +690,18 @@ mdoc_xr_pre(MDOC_ARGS)
}
static int
+mdoc_tg_pre(MDOC_ARGS)
+{
+ char *id;
+
+ if ((id = html_make_id(n, 1)) != NULL) {
+ print_tagq(h, print_otag(h, TAG_MARK, "i", id));
+ free(id);
+ }
+ return 0;
+}
+
+static int
mdoc_ns_pre(MDOC_ARGS)
{
@@ -765,7 +745,7 @@ mdoc_it_pre(MDOC_ARGS)
case ROFFT_HEAD:
return 0;
case ROFFT_BODY:
- print_otag(h, TAG_LI, "");
+ print_otag_id(h, TAG_LI, NULL, n);
break;
default:
break;
@@ -777,7 +757,7 @@ mdoc_it_pre(MDOC_ARGS)
case LIST_ohang:
switch (n->type) {
case ROFFT_HEAD:
- print_otag(h, TAG_DT, "");
+ print_otag_id(h, TAG_DT, NULL, n);
break;
case ROFFT_BODY:
print_otag(h, TAG_DD, "");
@@ -789,7 +769,7 @@ mdoc_it_pre(MDOC_ARGS)
case LIST_tag:
switch (n->type) {
case ROFFT_HEAD:
- print_otag(h, TAG_DT, "");
+ print_otag_id(h, TAG_DT, NULL, n);
break;
case ROFFT_BODY:
if (n->child == NULL) {
@@ -810,7 +790,7 @@ mdoc_it_pre(MDOC_ARGS)
print_otag(h, TAG_TD, "");
break;
default:
- print_otag(h, TAG_TR, "");
+ print_otag_id(h, TAG_TR, NULL, n);
}
default:
break;
@@ -876,8 +856,8 @@ mdoc_bl_pre(MDOC_ARGS)
case LIST_tag:
if (bl->offs)
print_otag(h, TAG_DIV, "c", "Bd-indent");
- print_otag(h, TAG_DL, "c", bl->comp ?
- "Bl-tag Bl-compact" : "Bl-tag");
+ print_otag_id(h, TAG_DL,
+ bl->comp ? "Bl-tag Bl-compact" : "Bl-tag", n->body);
return 1;
case LIST_column:
elemtype = TAG_TABLE;
@@ -890,14 +870,14 @@ mdoc_bl_pre(MDOC_ARGS)
(void)strlcat(cattr, " Bd-indent", sizeof(cattr));
if (bl->comp)
(void)strlcat(cattr, " Bl-compact", sizeof(cattr));
- print_otag(h, elemtype, "c", cattr);
+ print_otag_id(h, elemtype, cattr, n->body);
return 1;
}
static int
mdoc_ex_pre(MDOC_ARGS)
{
- if (n->prev)
+ if (roff_node_prev(n) != NULL)
print_otag(h, TAG_BR, "");
return 1;
}
@@ -912,7 +892,7 @@ mdoc_st_pre(MDOC_ARGS)
static int
mdoc_em_pre(MDOC_ARGS)
{
- print_otag(h, TAG_I, "c", "Em");
+ print_otag_id(h, TAG_I, "Em", n);
return 1;
}
@@ -922,15 +902,15 @@ mdoc_d1_pre(MDOC_ARGS)
switch (n->type) {
case ROFFT_BLOCK:
html_close_paragraph(h);
- break;
+ return 1;
case ROFFT_HEAD:
return 0;
case ROFFT_BODY:
- return 1;
+ break;
default:
abort();
}
- print_otag(h, TAG_DIV, "c", "Bd Bd-indent");
+ print_otag_id(h, TAG_DIV, "Bd Bd-indent", n);
if (n->tok == MDOC_Dl)
print_otag(h, TAG_CODE, "c", "Li");
return 1;
@@ -950,7 +930,7 @@ mdoc_sx_pre(MDOC_ARGS)
static int
mdoc_bd_pre(MDOC_ARGS)
{
- char buf[16];
+ char buf[20];
struct roff_node *nn;
int comp;
@@ -974,7 +954,7 @@ mdoc_bd_pre(MDOC_ARGS)
continue;
if (nn->tok == MDOC_Sh || nn->tok == MDOC_Ss)
comp = 1;
- if (nn->prev != NULL)
+ if (roff_node_prev(nn) != NULL)
break;
}
(void)strlcpy(buf, "Bd", sizeof(buf));
@@ -987,7 +967,10 @@ mdoc_bd_pre(MDOC_ARGS)
strcmp(n->norm->Bd.offs, "left") != 0)
(void)strlcat(buf, " Bd-indent", sizeof(buf));
- print_otag(h, TAG_DIV, "c", buf);
+ if (n->norm->Bd.type == DISP_literal)
+ (void)strlcat(buf, " Li", sizeof(buf));
+
+ print_otag_id(h, TAG_DIV, buf, n);
return 1;
}
@@ -1038,45 +1021,6 @@ mdoc_cd_pre(MDOC_ARGS)
}
static int
-mdoc_dv_pre(MDOC_ARGS)
-{
- char *id;
-
- if ((id = cond_id(n)) != NULL)
- print_otag(h, TAG_A, "chR", "permalink", id);
- print_otag(h, TAG_CODE, "ci", "Dv", id);
- return 1;
-}
-
-static int
-mdoc_ev_pre(MDOC_ARGS)
-{
- char *id;
-
- if ((id = cond_id(n)) != NULL)
- print_otag(h, TAG_A, "chR", "permalink", id);
- print_otag(h, TAG_CODE, "ci", "Ev", id);
- return 1;
-}
-
-static int
-mdoc_er_pre(MDOC_ARGS)
-{
- char *id;
-
- id = n->sec == SEC_ERRORS &&
- (n->parent->tok == MDOC_It ||
- (n->parent->tok == MDOC_Bq &&
- n->parent->parent->parent->tok == MDOC_It)) ?
- html_make_id(n, 1) : NULL;
-
- if (id != NULL)
- print_otag(h, TAG_A, "chR", "permalink", id);
- print_otag(h, TAG_CODE, "ci", "Er", id);
- return 1;
-}
-
-static int
mdoc_fa_pre(MDOC_ARGS)
{
const struct roff_node *nn;
@@ -1086,22 +1030,21 @@ mdoc_fa_pre(MDOC_ARGS)
print_otag(h, TAG_VAR, "c", "Fa");
return 1;
}
-
- for (nn = n->child; nn; nn = nn->next) {
+ for (nn = n->child; nn != NULL; nn = nn->next) {
t = print_otag(h, TAG_VAR, "c", "Fa");
print_text(h, nn->string);
print_tagq(h, t);
- if (nn->next) {
+ if (nn->next != NULL) {
h->flags |= HTML_NOSPACE;
print_text(h, ",");
}
}
-
- if (n->child && n->next && n->next->tok == MDOC_Fa) {
+ if (n->child != NULL &&
+ (nn = roff_node_next(n)) != NULL &&
+ nn->tok == MDOC_Fa) {
h->flags |= HTML_NOSPACE;
print_text(h, ",");
}
-
return 0;
}
@@ -1209,7 +1152,7 @@ mdoc_fn_pre(MDOC_ARGS)
print_tagq(h, t);
}
- t = print_otag(h, TAG_CODE, "c", "Fn");
+ t = print_otag_id(h, TAG_CODE, "Fn", n);
if (sp)
print_text(h, sp);
@@ -1272,9 +1215,21 @@ mdoc_skip_pre(MDOC_ARGS)
static int
mdoc_pp_pre(MDOC_ARGS)
{
- if ((n->flags & NODE_NOFILL) == 0) {
+ char *id;
+
+ if (n->flags & NODE_NOFILL) {
+ print_endline(h);
+ if (n->flags & NODE_ID)
+ mdoc_tg_pre(meta, n, h);
+ else {
+ h->col = 1;
+ print_endline(h);
+ }
+ } else {
html_close_paragraph(h);
- print_otag(h, TAG_P, "c", "Pp");
+ id = n->flags & NODE_ID ? html_make_id(n, 1) : NULL;
+ print_otag(h, TAG_P, "ci", "Pp", id);
+ free(id);
}
return 0;
}
@@ -1324,14 +1279,12 @@ mdoc_mt_pre(MDOC_ARGS)
for (n = n->child; n; n = n->next) {
assert(n->type == ROFFT_TEXT);
-
mandoc_asprintf(&cp, "mailto:%s", n->string);
t = print_otag(h, TAG_A, "ch", "Mt", cp);
print_text(h, n->string);
print_tagq(h, t);
free(cp);
}
-
return 0;
}
@@ -1340,30 +1293,30 @@ mdoc_fo_pre(MDOC_ARGS)
{
struct tag *t;
- if (n->type == ROFFT_BODY) {
+ switch (n->type) {
+ case ROFFT_BLOCK:
+ synopsis_pre(h, n);
+ return 1;
+ case ROFFT_HEAD:
+ if (n->child != NULL) {
+ t = print_otag_id(h, TAG_CODE, "Fn", n);
+ print_text(h, n->child->string);
+ print_tagq(h, t);
+ }
+ return 0;
+ case ROFFT_BODY:
h->flags |= HTML_NOSPACE;
print_text(h, "(");
h->flags |= HTML_NOSPACE;
return 1;
- } else if (n->type == ROFFT_BLOCK) {
- synopsis_pre(h, n);
- return 1;
+ default:
+ abort();
}
-
- if (n->child == NULL)
- return 0;
-
- assert(n->child->string);
- t = print_otag(h, TAG_CODE, "c", "Fn");
- print_text(h, n->child->string);
- print_tagq(h, t);
- return 0;
}
static void
mdoc_fo_post(MDOC_ARGS)
{
-
if (n->type != ROFFT_BODY)
return;
h->flags |= HTML_NOSPACE;
@@ -1413,22 +1366,10 @@ mdoc_in_pre(MDOC_ARGS)
assert(n->type == ROFFT_TEXT);
print_text(h, n->string);
}
-
return 0;
}
static int
-mdoc_ic_pre(MDOC_ARGS)
-{
- char *id;
-
- if ((id = cond_id(n)) != NULL)
- print_otag(h, TAG_A, "chR", "permalink", id);
- print_otag(h, TAG_CODE, "ci", "Ic", id);
- return 1;
-}
-
-static int
mdoc_va_pre(MDOC_ARGS)
{
print_otag(h, TAG_VAR, "c", "Va");
@@ -1438,7 +1379,6 @@ mdoc_va_pre(MDOC_ARGS)
static int
mdoc_ap_pre(MDOC_ARGS)
{
-
h->flags |= HTML_NOSPACE;
print_text(h, "\\(aq");
h->flags |= HTML_NOSPACE;
@@ -1477,20 +1417,8 @@ mdoc_bf_pre(MDOC_ARGS)
}
static int
-mdoc_ms_pre(MDOC_ARGS)
-{
- char *id;
-
- if ((id = cond_id(n)) != NULL)
- print_otag(h, TAG_A, "chR", "permalink", id);
- print_otag(h, TAG_SPAN, "ci", "Ms", id);
- return 1;
-}
-
-static int
mdoc_igndelim_pre(MDOC_ARGS)
{
-
h->flags |= HTML_IGNDELIM;
return 1;
}
@@ -1498,7 +1426,6 @@ mdoc_igndelim_pre(MDOC_ARGS)
static void
mdoc_pf_post(MDOC_ARGS)
{
-
if ( ! (n->next == NULL || n->next->flags & NODE_LINE))
h->flags |= HTML_NOSPACE;
}
@@ -1527,36 +1454,23 @@ mdoc_rs_pre(MDOC_ARGS)
static int
mdoc_no_pre(MDOC_ARGS)
{
- char *id;
-
- if ((id = cond_id(n)) != NULL)
- print_otag(h, TAG_A, "chR", "permalink", id);
- print_otag(h, TAG_SPAN, "ci", "No", id);
- return 1;
-}
-
-static int
-mdoc_li_pre(MDOC_ARGS)
-{
- char *id;
-
- if ((id = cond_id(n)) != NULL)
- print_otag(h, TAG_A, "chR", "permalink", id);
- print_otag(h, TAG_CODE, "ci", "Li", id);
+ print_otag_id(h, TAG_SPAN, roff_name[n->tok], n);
return 1;
}
static int
mdoc_sy_pre(MDOC_ARGS)
{
- print_otag(h, TAG_B, "c", "Sy");
+ print_otag_id(h, TAG_B, "Sy", n);
return 1;
}
static int
mdoc_lb_pre(MDOC_ARGS)
{
- if (SEC_LIBRARY == n->sec && NODE_LINE & n->flags && n->prev)
+ if (n->sec == SEC_LIBRARY &&
+ n->flags & NODE_LINE &&
+ roff_node_prev(n) != NULL)
print_otag(h, TAG_BR, "");
print_otag(h, TAG_SPAN, "c", "Lb");
@@ -1566,17 +1480,18 @@ mdoc_lb_pre(MDOC_ARGS)
static int
mdoc__x_pre(MDOC_ARGS)
{
- const char *cattr;
- enum htmltag t;
+ struct roff_node *nn;
+ const char *cattr;
+ enum htmltag t;
t = TAG_SPAN;
switch (n->tok) {
case MDOC__A:
cattr = "RsA";
- if (n->prev && MDOC__A == n->prev->tok)
- if (NULL == n->next || MDOC__A != n->next->tok)
- print_text(h, "and");
+ if ((nn = roff_node_prev(n)) != NULL && nn->tok == MDOC__A &&
+ ((nn = roff_node_next(n)) == NULL || nn->tok != MDOC__A))
+ print_text(h, "and");
break;
case MDOC__B:
t = TAG_I;
@@ -1631,19 +1546,21 @@ mdoc__x_pre(MDOC_ARGS)
static void
mdoc__x_post(MDOC_ARGS)
{
+ struct roff_node *nn;
- if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok)
- if (NULL == n->next->next || MDOC__A != n->next->next->tok)
- if (NULL == n->prev || MDOC__A != n->prev->tok)
- return;
+ if (n->tok == MDOC__A &&
+ (nn = roff_node_next(n)) != NULL && nn->tok == MDOC__A &&
+ ((nn = roff_node_next(nn)) == NULL || nn->tok != MDOC__A) &&
+ ((nn = roff_node_prev(n)) == NULL || nn->tok != MDOC__A))
+ return;
/* TODO: %U */
- if (NULL == n->parent || MDOC_Rs != n->parent->tok)
+ if (n->parent == NULL || n->parent->tok != MDOC_Rs)
return;
h->flags |= HTML_NOSPACE;
- print_text(h, n->next ? "," : ".");
+ print_text(h, roff_node_next(n) ? "," : ".");
}
static int
@@ -1700,7 +1617,7 @@ mdoc_quote_pre(MDOC_ARGS)
/*
* Give up on semantic markup for now.
* We cannot use TAG_SPAN because .Oo may contain blocks.
- * We cannot use TAG_IDIV because we might be in a
+ * We cannot use TAG_DIV because we might be in a
* phrasing context (like .Dl or .Pp); we cannot
* close out a .Pp at this point either because
* that would break the line.
@@ -1715,9 +1632,11 @@ mdoc_quote_pre(MDOC_ARGS)
break;
case MDOC_Do:
case MDOC_Dq:
+ print_text(h, "\\(lq");
+ break;
case MDOC_Qo:
case MDOC_Qq:
- print_text(h, "\\(lq");
+ print_text(h, "\"");
break;
case MDOC_Po:
case MDOC_Pq:
@@ -1773,12 +1692,14 @@ mdoc_quote_post(MDOC_ARGS)
else
print_text(h, n->norm->Es->child->next->string);
break;
- case MDOC_Qo:
- case MDOC_Qq:
case MDOC_Do:
case MDOC_Dq:
print_text(h, "\\(rq");
break;
+ case MDOC_Qo:
+ case MDOC_Qq:
+ print_text(h, "\"");
+ break;
case MDOC_Po:
case MDOC_Pq:
print_text(h, ")");
diff --git a/mdoc_macro.c b/mdoc_macro.c
index 3422945814f0..dd3885c702b7 100644
--- a/mdoc_macro.c
+++ b/mdoc_macro.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc_macro.c,v 1.232 2019/01/07 07:26:29 schwarze Exp $ */
+/* $Id: mdoc_macro.c,v 1.234 2020/01/19 18:02:00 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012-2019 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012-2020 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -61,7 +61,7 @@ static void rew_pending(struct roff_man *,
const struct roff_node *);
static const struct mdoc_macro mdoc_macros[MDOC_MAX - MDOC_Dd] = {
- { in_line_eoln, MDOC_PROLOGUE }, /* Dd */
+ { in_line_eoln, MDOC_PROLOGUE | MDOC_JOIN }, /* Dd */
{ in_line_eoln, MDOC_PROLOGUE }, /* Dt */
{ in_line_eoln, MDOC_PROLOGUE }, /* Os */
{ blk_full, MDOC_PARSED | MDOC_JOIN }, /* Sh */
@@ -200,6 +200,7 @@ static const struct mdoc_macro mdoc_macros[MDOC_MAX - MDOC_Dd] = {
{ in_line_eoln, MDOC_JOIN }, /* %Q */
{ in_line_eoln, 0 }, /* %U */
{ phrase_ta, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ta */
+ { in_line_eoln, 0 }, /* Tg */
};
diff --git a/mdoc_man.c b/mdoc_man.c
index 2e8f02ae56f2..0964cc6160a1 100644
--- a/mdoc_man.c
+++ b/mdoc_man.c
@@ -1,6 +1,6 @@
-/* $Id: mdoc_man.c,v 1.132 2019/01/04 03:17:36 schwarze Exp $ */
+/* $Id: mdoc_man.c,v 1.137 2021/07/04 15:38:26 schwarze Exp $ */
/*
- * Copyright (c) 2011-2019 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011-2021 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -113,7 +113,7 @@ static int pre_sm(DECL_ARGS);
static void pre_sp(DECL_ARGS);
static int pre_sect(DECL_ARGS);
static int pre_sy(DECL_ARGS);
-static void pre_syn(const struct roff_node *);
+static void pre_syn(struct roff_node *);
static void pre_ta(DECL_ARGS);
static int pre_vt(DECL_ARGS);
static int pre_xr(DECL_ARGS);
@@ -262,6 +262,7 @@ static const struct mdoc_man_act mdoc_man_acts[MDOC_MAX - MDOC_Dd] = {
{ NULL, NULL, post_percent, NULL, NULL }, /* %Q */
{ NULL, NULL, post_percent, NULL, NULL }, /* %U */
{ NULL, NULL, NULL, NULL, NULL }, /* Ta */
+ { NULL, pre_skip, NULL, NULL, NULL }, /* Tg */
};
static const struct mdoc_man_act *mdoc_man_act(enum roff_tok);
@@ -582,9 +583,9 @@ print_width(const struct mdoc_bl *bl, const struct roff_node *child)
/* Set up the current list. */
if (chsz > sz && bl->type != LIST_tag)
- print_block(".HP", 0);
+ print_block(".HP", MMAN_spc);
else {
- print_block(".TP", 0);
+ print_block(".TP", MMAN_spc);
remain = sz + 2;
}
if (numeric) {
@@ -649,7 +650,9 @@ print_node(DECL_ARGS)
* Break the line if we were parsed subsequent the current node.
* This makes the page structure be more consistent.
*/
- if (MMAN_spc & outflags && NODE_LINE & n->flags)
+ if (outflags & MMAN_spc &&
+ n->flags & NODE_LINE &&
+ !roff_node_transparent(n))
outflags |= MMAN_nl;
act = NULL;
@@ -657,7 +660,20 @@ print_node(DECL_ARGS)
do_sub = 1;
n->flags &= ~NODE_ENDED;
- if (n->type == ROFFT_TEXT) {
+ switch (n->type) {
+ case ROFFT_EQN:
+ case ROFFT_TBL:
+ mandoc_msg(n->type == ROFFT_EQN ? MANDOCERR_EQN_TMAN :
+ MANDOCERR_TBL_TMAN, n->line, n->pos, NULL);
+ outflags |= MMAN_PP | MMAN_sp | MMAN_nl;
+ print_word("The");
+ print_line(".B \\-T man", MMAN_nl);
+ print_word("output mode does not support");
+ print_word(n->type == ROFFT_EQN ? "eqn(7)" : "tbl(7)");
+ print_word("input.");
+ outflags |= MMAN_PP | MMAN_sp | MMAN_nl;
+ return;
+ case ROFFT_TEXT:
/*
* Make sure that we don't happen to start with a
* control character at the start of a line.
@@ -677,19 +693,18 @@ print_node(DECL_ARGS)
outflags &= ~(MMAN_spc | MMAN_spc_force);
else if (outflags & MMAN_Sm)
outflags |= MMAN_spc;
- } else if (n->tok < ROFF_MAX) {
- (*roff_man_acts[n->tok])(meta, n);
- return;
- } else {
- /*
- * Conditionally run the pre-node action handler for a
- * node.
- */
+ break;
+ default:
+ if (n->tok < ROFF_MAX) {
+ (*roff_man_acts[n->tok])(meta, n);
+ return;
+ }
act = mdoc_man_act(n->tok);
cond = act->cond == NULL || (*act->cond)(meta, n);
if (cond && act->pre != NULL &&
(n->end == ENDBODY_NOT || n->child != NULL))
do_sub = (*act->pre)(meta, n);
+ break;
}
/*
@@ -776,13 +791,20 @@ post_font(DECL_ARGS)
static void
post_percent(DECL_ARGS)
{
+ struct roff_node *np, *nn, *nnn;
if (mdoc_man_act(n->tok)->pre == pre_em)
font_pop();
- if (n->next) {
- print_word(",");
- if (n->prev && n->prev->tok == n->tok &&
- n->next->tok == n->tok)
+
+ if ((nn = roff_node_next(n)) != NULL) {
+ np = roff_node_prev(n);
+ nnn = nn == NULL ? NULL : roff_node_next(nn);
+ if (nn->tok != n->tok ||
+ (np != NULL && np->tok == n->tok) ||
+ (nnn != NULL && nnn->tok == n->tok))
+ print_word(",");
+ if (nn->tok == n->tok &&
+ (nnn == NULL || nnn->tok != n->tok))
print_word("and");
} else {
print_word(".");
@@ -850,13 +872,15 @@ post_sect(DECL_ARGS)
/* See mdoc_term.c, synopsis_pre() for comments. */
static void
-pre_syn(const struct roff_node *n)
+pre_syn(struct roff_node *n)
{
+ struct roff_node *np;
- if (NULL == n->prev || ! (NODE_SYNPRETTY & n->flags))
+ if ((n->flags & NODE_SYNPRETTY) == 0 ||
+ (np = roff_node_prev(n)) == NULL)
return;
- if (n->prev->tok == n->tok &&
+ if (np->tok == n->tok &&
MDOC_Ft != n->tok &&
MDOC_Fo != n->tok &&
MDOC_Fn != n->tok) {
@@ -864,7 +888,7 @@ pre_syn(const struct roff_node *n)
return;
}
- switch (n->prev->tok) {
+ switch (np->tok) {
case MDOC_Fd:
case MDOC_Fn:
case MDOC_Fo:
@@ -940,11 +964,10 @@ static int
pre_bd(DECL_ARGS)
{
outflags &= ~(MMAN_PP | MMAN_sp | MMAN_br);
-
- if (DISP_unfilled == n->norm->Bd.type ||
- DISP_literal == n->norm->Bd.type)
+ if (n->norm->Bd.type == DISP_unfilled ||
+ n->norm->Bd.type == DISP_literal)
print_line(".nf", 0);
- if (0 == n->norm->Bd.comp && NULL != n->parent->prev)
+ if (n->norm->Bd.comp == 0 && roff_node_prev(n->parent) != NULL)
outflags |= MMAN_sp;
print_offs(n->norm->Bd.offs, 1);
return 1;
@@ -976,7 +999,7 @@ post_bd(DECL_ARGS)
}
/* Maybe we are inside an enclosing list? */
- if (NULL != n->parent->next)
+ if (roff_node_next(n->parent) != NULL)
mid_it();
}
@@ -1101,16 +1124,15 @@ post_bl(DECL_ARGS)
print_line(".RE", MMAN_nl);
assert(Bl_stack_len);
Bl_stack_len--;
- assert(0 == Bl_stack[Bl_stack_len]);
+ assert(Bl_stack[Bl_stack_len] == 0);
} else {
outflags |= MMAN_PP | MMAN_nl;
outflags &= ~(MMAN_sp | MMAN_br);
}
/* Maybe we are inside an enclosing list? */
- if (NULL != n->parent->next)
+ if (roff_node_next(n->parent) != NULL)
mid_it();
-
}
static void
@@ -1122,7 +1144,6 @@ pre_br(DECL_ARGS)
static int
pre_dl(DECL_ARGS)
{
-
print_offs("6n", 0);
return 1;
}
@@ -1130,11 +1151,10 @@ pre_dl(DECL_ARGS)
static void
post_dl(DECL_ARGS)
{
-
print_line(".RE", MMAN_nl);
/* Maybe we are inside an enclosing list? */
- if (NULL != n->parent->next)
+ if (roff_node_next(n->parent) != NULL)
mid_it();
}
@@ -1235,15 +1255,15 @@ pre_fa(DECL_ARGS)
static void
post_fa(DECL_ARGS)
{
+ struct roff_node *nn;
- if (NULL != n->next && MDOC_Fa == n->next->tok)
+ if ((nn = roff_node_next(n)) != NULL && nn->tok == MDOC_Fa)
print_word(",");
}
static int
pre_fd(DECL_ARGS)
{
-
pre_syn(n);
font_push('B');
return 1;
@@ -1252,7 +1272,6 @@ pre_fd(DECL_ARGS)
static void
post_fd(DECL_ARGS)
{
-
font_pop();
outflags |= MMAN_br;
}
@@ -1260,7 +1279,6 @@ post_fd(DECL_ARGS)
static int
pre_fl(DECL_ARGS)
{
-
font_push('B');
print_word("\\-");
if (n->child != NULL)
@@ -1271,12 +1289,13 @@ pre_fl(DECL_ARGS)
static void
post_fl(DECL_ARGS)
{
+ struct roff_node *nn;
font_pop();
- if (!(n->child != NULL ||
- n->next == NULL ||
- n->next->type == ROFFT_TEXT ||
- n->next->flags & NODE_LINE))
+ if (n->child == NULL &&
+ ((nn = roff_node_next(n)) != NULL &&
+ nn->type != ROFFT_TEXT &&
+ (nn->flags & NODE_LINE) == 0))
outflags &= ~MMAN_spc;
}
@@ -1419,9 +1438,9 @@ pre_it(DECL_ARGS)
case ROFFT_HEAD:
outflags |= MMAN_PP | MMAN_nl;
bln = n->parent->parent;
- if (0 == bln->norm->Bl.comp ||
- (NULL == n->parent->prev &&
- NULL == bln->parent->prev))
+ if (bln->norm->Bl.comp == 0 ||
+ (n->parent->prev == NULL &&
+ roff_node_prev(bln->parent) == NULL))
outflags |= MMAN_sp;
outflags &= ~MMAN_br;
switch (bln->norm->Bl.type) {
@@ -1633,17 +1652,22 @@ pre_nm(DECL_ARGS)
{
char *name;
- if (n->type == ROFFT_BLOCK) {
+ switch (n->type) {
+ case ROFFT_BLOCK:
outflags |= MMAN_Bk;
pre_syn(n);
- }
- if (n->type != ROFFT_ELEM && n->type != ROFFT_HEAD)
return 1;
+ case ROFFT_HEAD:
+ case ROFFT_ELEM:
+ break;
+ default:
+ return 1;
+ }
name = n->child == NULL ? NULL : n->child->string;
- if (NULL == name)
+ if (name == NULL)
return 0;
if (n->type == ROFFT_HEAD) {
- if (NULL == n->parent->prev)
+ if (roff_node_prev(n->parent) == NULL)
outflags |= MMAN_sp;
print_block(".HP", 0);
printf(" %dn", man_strlen(name) + 1);
diff --git a/mdoc_markdown.c b/mdoc_markdown.c
index 88e37c0b188b..63d8e1705580 100644
--- a/mdoc_markdown.c
+++ b/mdoc_markdown.c
@@ -1,6 +1,6 @@
-/* $Id: mdoc_markdown.c,v 1.31 2019/07/01 22:56:24 schwarze Exp $ */
+/* $Id: mdoc_markdown.c,v 1.37 2021/08/10 12:55:03 schwarze Exp $ */
/*
- * Copyright (c) 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2017, 2018, 2020 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -13,7 +13,11 @@
* 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.
+ *
+ * Markdown formatter for mdoc(7) used by mandoc(1).
*/
+#include "config.h"
+
#include <sys/types.h>
#include <assert.h>
@@ -29,16 +33,16 @@
#include "main.h"
struct md_act {
- int (*cond)(struct roff_node *n);
- int (*pre)(struct roff_node *n);
- void (*post)(struct roff_node *n);
+ int (*cond)(struct roff_node *);
+ int (*pre)(struct roff_node *);
+ void (*post)(struct roff_node *);
const char *prefix; /* pre-node string constant */
const char *suffix; /* post-node string constant */
};
static void md_nodelist(struct roff_node *);
static void md_node(struct roff_node *);
-static const char *md_stack(char c);
+static const char *md_stack(char);
static void md_preword(void);
static void md_rawword(const char *);
static void md_word(const char *);
@@ -226,6 +230,7 @@ static const struct md_act md_acts[MDOC_MAX - MDOC_Dd] = {
{ NULL, NULL, md_post_pc, NULL, NULL }, /* %Q */
{ NULL, md_pre_Lk, md_post_pc, NULL, NULL }, /* %U */
{ NULL, NULL, NULL, NULL, NULL }, /* Ta */
+ { NULL, md_pre_skip, NULL, NULL, NULL }, /* Tg */
};
static const struct md_act *md_act(enum roff_tok);
@@ -309,7 +314,9 @@ md_node(struct roff_node *n)
if (outflags & MD_nonl)
outflags &= ~(MD_nl | MD_sp);
- else if (outflags & MD_spc && n->flags & NODE_LINE)
+ else if (outflags & MD_spc &&
+ n->flags & NODE_LINE &&
+ !roff_node_transparent(n))
outflags |= MD_nl;
act = NULL;
@@ -596,16 +603,18 @@ md_word(const char *s)
md_rawword("markdown");
continue;
case ESCAPE_FONTBOLD:
+ case ESCAPE_FONTCB:
nextfont = "**";
break;
case ESCAPE_FONTITALIC:
+ case ESCAPE_FONTCI:
nextfont = "*";
break;
case ESCAPE_FONTBI:
nextfont = "***";
break;
case ESCAPE_FONT:
- case ESCAPE_FONTCW:
+ case ESCAPE_FONTCR:
case ESCAPE_FONTROMAN:
nextfont = "";
break;
@@ -786,14 +795,17 @@ md_post_word(struct roff_node *n)
static void
md_post_pc(struct roff_node *n)
{
+ struct roff_node *nn;
+
md_post_raw(n);
if (n->parent->tok != MDOC_Rs)
return;
- if (n->next != NULL) {
+
+ if ((nn = roff_node_next(n)) != NULL) {
md_word(",");
- if (n->prev != NULL &&
- n->prev->tok == n->tok &&
- n->next->tok == n->tok)
+ if (nn->tok == n->tok &&
+ (nn = roff_node_prev(n)) != NULL &&
+ nn->tok == n->tok)
md_word("and");
} else {
md_word(".");
@@ -810,10 +822,13 @@ md_pre_skip(struct roff_node *n)
static void
md_pre_syn(struct roff_node *n)
{
- if (n->prev == NULL || ! (n->flags & NODE_SYNPRETTY))
+ struct roff_node *np;
+
+ if ((n->flags & NODE_SYNPRETTY) == 0 ||
+ (np = roff_node_prev(n)) == NULL)
return;
- if (n->prev->tok == n->tok &&
+ if (np->tok == n->tok &&
n->tok != MDOC_Ft &&
n->tok != MDOC_Fo &&
n->tok != MDOC_Fn) {
@@ -821,7 +836,7 @@ md_pre_syn(struct roff_node *n)
return;
}
- switch (n->prev->tok) {
+ switch (np->tok) {
case MDOC_Fd:
case MDOC_Fn:
case MDOC_Fo:
@@ -1052,7 +1067,9 @@ md_pre_Fa(struct roff_node *n)
static void
md_post_Fa(struct roff_node *n)
{
- if (n->next != NULL && n->next->tok == MDOC_Fa)
+ struct roff_node *nn;
+
+ if ((nn = roff_node_next(n)) != NULL && nn->tok == MDOC_Fa)
md_word(",");
}
@@ -1074,9 +1091,11 @@ md_post_Fd(struct roff_node *n)
static void
md_post_Fl(struct roff_node *n)
{
+ struct roff_node *nn;
+
md_post_raw(n);
- if (n->child == NULL && n->next != NULL &&
- n->next->type != ROFFT_TEXT && !(n->next->flags & NODE_LINE))
+ if (n->child == NULL && (nn = roff_node_next(n)) != NULL &&
+ nn->type != ROFFT_TEXT && (nn->flags & NODE_LINE) == 0)
outflags &= ~MD_spc;
}
diff --git a/mdoc_state.c b/mdoc_state.c
index f9a585e73623..d696ff27e06c 100644
--- a/mdoc_state.c
+++ b/mdoc_state.c
@@ -1,4 +1,4 @@
-/* $Id: mdoc_state.c,v 1.15 2019/01/01 07:42:04 schwarze Exp $ */
+/* $Id: mdoc_state.c,v 1.17 2020/06/22 19:20:40 schwarze Exp $ */
/*
* Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -14,6 +14,8 @@
* 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"
+
#include <sys/types.h>
#include <assert.h>
@@ -157,6 +159,7 @@ static const state_handler state_handlers[MDOC_MAX - MDOC_Dd] = {
NULL, /* %Q */
NULL, /* %U */
NULL, /* Ta */
+ NULL, /* Tg */
};
diff --git a/mdoc_term.c b/mdoc_term.c
index 18f0ff09e2c7..42392c7c0a59 100644
--- a/mdoc_term.c
+++ b/mdoc_term.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc_term.c,v 1.374 2019/06/27 12:20:18 schwarze Exp $ */
+/* $Id: mdoc_term.c,v 1.380 2020/04/06 10:16:17 schwarze Exp $ */
/*
+ * Copyright (c) 2010, 2012-2020 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012-2019 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -15,6 +15,9 @@
* 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.
+ *
+ * Plain text formatter for mdoc(7), used by mandoc(1)
+ * for ASCII, UTF-8, PostScript, and PDF output.
*/
#include "config.h"
@@ -33,7 +36,7 @@
#include "mdoc.h"
#include "out.h"
#include "term.h"
-#include "tag.h"
+#include "term_tag.h"
#include "main.h"
struct termpair {
@@ -54,14 +57,12 @@ struct mdoc_term_act {
static int a2width(const struct termp *, const char *);
static void print_bvspace(struct termp *,
- const struct roff_node *,
- const struct roff_node *);
+ struct roff_node *, struct roff_node *);
static void print_mdoc_node(DECL_ARGS);
static void print_mdoc_nodelist(DECL_ARGS);
static void print_mdoc_head(struct termp *, const struct roff_meta *);
static void print_mdoc_foot(struct termp *, const struct roff_meta *);
-static void synopsis_pre(struct termp *,
- const struct roff_node *);
+static void synopsis_pre(struct termp *, struct roff_node *);
static void termp____post(DECL_ARGS);
static void termp__t_post(DECL_ARGS);
@@ -91,11 +92,8 @@ static int termp_bf_pre(DECL_ARGS);
static int termp_bk_pre(DECL_ARGS);
static int termp_bl_pre(DECL_ARGS);
static int termp_bold_pre(DECL_ARGS);
-static int termp_cd_pre(DECL_ARGS);
static int termp_d1_pre(DECL_ARGS);
static int termp_eo_pre(DECL_ARGS);
-static int termp_em_pre(DECL_ARGS);
-static int termp_er_pre(DECL_ARGS);
static int termp_ex_pre(DECL_ARGS);
static int termp_fa_pre(DECL_ARGS);
static int termp_fd_pre(DECL_ARGS);
@@ -117,8 +115,6 @@ static int termp_skip_pre(DECL_ARGS);
static int termp_sm_pre(DECL_ARGS);
static int termp_pp_pre(DECL_ARGS);
static int termp_ss_pre(DECL_ARGS);
-static int termp_sy_pre(DECL_ARGS);
-static int termp_tag_pre(DECL_ARGS);
static int termp_under_pre(DECL_ARGS);
static int termp_vt_pre(DECL_ARGS);
static int termp_xr_pre(DECL_ARGS);
@@ -142,11 +138,11 @@ static const struct mdoc_term_act mdoc_term_acts[MDOC_MAX - MDOC_Dd] = {
{ termp_an_pre, NULL }, /* An */
{ termp_ap_pre, NULL }, /* Ap */
{ termp_under_pre, NULL }, /* Ar */
- { termp_cd_pre, NULL }, /* Cd */
+ { termp_fd_pre, NULL }, /* Cd */
{ termp_bold_pre, NULL }, /* Cm */
{ termp_li_pre, NULL }, /* Dv */
- { termp_er_pre, NULL }, /* Er */
- { termp_tag_pre, NULL }, /* Ev */
+ { NULL, NULL }, /* Er */
+ { NULL, NULL }, /* Ev */
{ termp_ex_pre, NULL }, /* Ex */
{ termp_fa_pre, NULL }, /* Fa */
{ termp_fd_pre, termp_fd_post }, /* Fd */
@@ -193,7 +189,7 @@ static const struct mdoc_term_act mdoc_term_acts[MDOC_MAX - MDOC_Dd] = {
{ termp_quote_pre, termp_quote_post }, /* Dq */
{ NULL, NULL }, /* Ec */ /* FIXME: no space */
{ NULL, NULL }, /* Ef */
- { termp_em_pre, NULL }, /* Em */
+ { termp_under_pre, NULL }, /* Em */
{ termp_eo_pre, termp_eo_post }, /* Eo */
{ termp_xx_pre, termp_xx_post }, /* Fx */
{ termp_bold_pre, NULL }, /* Ms */
@@ -216,7 +212,7 @@ static const struct mdoc_term_act mdoc_term_acts[MDOC_MAX - MDOC_Dd] = {
{ termp_quote_pre, termp_quote_post }, /* Sq */
{ termp_sm_pre, NULL }, /* Sm */
{ termp_under_pre, NULL }, /* Sx */
- { termp_sy_pre, NULL }, /* Sy */
+ { termp_bold_pre, NULL }, /* Sy */
{ NULL, NULL }, /* Tn */
{ termp_xx_pre, termp_xx_post }, /* Ux */
{ NULL, NULL }, /* Xc */
@@ -245,10 +241,9 @@ static const struct mdoc_term_act mdoc_term_acts[MDOC_MAX - MDOC_Dd] = {
{ NULL, termp____post }, /* %Q */
{ NULL, termp____post }, /* %U */
{ NULL, NULL }, /* Ta */
+ { termp_skip_pre, NULL }, /* Tg */
};
-static int fn_prio;
-
void
terminal_mdoc(void *arg, const struct roff_meta *mdoc)
@@ -301,7 +296,6 @@ terminal_mdoc(void *arg, const struct roff_meta *mdoc)
static void
print_mdoc_nodelist(DECL_ARGS)
{
-
while (n != NULL) {
print_mdoc_node(p, pair, meta, n);
n = n->next;
@@ -341,6 +335,10 @@ print_mdoc_node(DECL_ARGS)
memset(&npair, 0, sizeof(struct termpair));
npair.ppair = pair;
+ if (n->flags & NODE_ID && n->tok != MDOC_Pp &&
+ (n->tok != MDOC_It || n->type != ROFFT_BLOCK))
+ term_tag_write(n, p->line);
+
/*
* Keeps only work until the end of a line. If a keep was
* invoked in a prior line, revert it to PREKEEP.
@@ -580,29 +578,20 @@ a2width(const struct termp *p, const char *v)
* too.
*/
static void
-print_bvspace(struct termp *p,
- const struct roff_node *bl,
- const struct roff_node *n)
+print_bvspace(struct termp *p, struct roff_node *bl, struct roff_node *n)
{
- const struct roff_node *nn;
-
- assert(n);
+ struct roff_node *nn;
term_newln(p);
- if (MDOC_Bd == bl->tok && bl->norm->Bd.comp)
- return;
- if (MDOC_Bl == bl->tok && bl->norm->Bl.comp)
+ if ((bl->tok == MDOC_Bd && bl->norm->Bd.comp) ||
+ (bl->tok == MDOC_Bl && bl->norm->Bl.comp))
return;
/* Do not vspace directly after Ss/Sh. */
nn = n;
- while (nn->prev != NULL &&
- (nn->prev->type == ROFFT_COMMENT ||
- nn->prev->flags & NODE_NOPRT))
- nn = nn->prev;
- while (nn->prev == NULL) {
+ while (roff_node_prev(nn) == NULL) {
do {
nn = nn->parent;
if (nn->type == ROFFT_ROOT)
@@ -615,22 +604,18 @@ print_bvspace(struct termp *p,
break;
}
- /* A `-column' does not assert vspace within the list. */
-
- if (MDOC_Bl == bl->tok && LIST_column == bl->norm->Bl.type)
- if (n->prev && MDOC_It == n->prev->tok)
- return;
-
- /* A `-diag' without body does not vspace. */
-
- if (MDOC_Bl == bl->tok && LIST_diag == bl->norm->Bl.type)
- if (n->prev && MDOC_It == n->prev->tok) {
- assert(n->prev->body);
- if (NULL == n->prev->body->child)
- return;
- }
+ /*
+ * No vertical space after:
+ * items in .Bl -column
+ * items without a body in .Bl -diag
+ */
- term_vspace(p);
+ if (bl->tok != MDOC_Bl ||
+ n->prev == NULL || n->prev->tok != MDOC_It ||
+ (bl->norm->Bl.type != LIST_column &&
+ (bl->norm->Bl.type != LIST_diag ||
+ n->prev->body->child != NULL)))
+ term_vspace(p);
}
@@ -646,6 +631,8 @@ termp_it_pre(DECL_ARGS)
if (n->type == ROFFT_BLOCK) {
print_bvspace(p, n->parent->parent, n);
+ if (n->flags & NODE_ID)
+ term_tag_write(n, p->line);
return 1;
}
@@ -1018,38 +1005,44 @@ termp_nm_pre(DECL_ARGS)
p->flags |= TERMP_HANG;
}
}
-
- term_fontpush(p, TERMFONT_BOLD);
- return 1;
+ return termp_bold_pre(p, pair, meta, n);
}
static void
termp_nm_post(DECL_ARGS)
{
-
- if (n->type == ROFFT_BLOCK) {
+ switch (n->type) {
+ case ROFFT_BLOCK:
p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
- } else if (n->type == ROFFT_HEAD &&
- NULL != n->next && NULL != n->next->child) {
+ break;
+ case ROFFT_HEAD:
+ if (n->next == NULL || n->next->child == NULL)
+ break;
term_flushln(p);
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
p->trailspace = 0;
- } else if (n->type == ROFFT_BODY && n->child != NULL)
- term_flushln(p);
+ break;
+ case ROFFT_BODY:
+ if (n->child != NULL)
+ term_flushln(p);
+ break;
+ default:
+ break;
+ }
}
static int
termp_fl_pre(DECL_ARGS)
{
+ struct roff_node *nn;
- termp_tag_pre(p, pair, meta, n);
term_fontpush(p, TERMFONT_BOLD);
term_word(p, "\\-");
- if (!(n->child == NULL &&
- (n->next == NULL ||
- n->next->type == ROFFT_TEXT ||
- n->next->flags & NODE_LINE)))
+ if (n->child != NULL ||
+ ((nn = roff_node_next(n)) != NULL &&
+ nn->type != ROFFT_TEXT &&
+ (nn->flags & NODE_LINE) == 0))
p->flags |= TERMP_NOSPACE;
return 1;
@@ -1058,10 +1051,11 @@ termp_fl_pre(DECL_ARGS)
static int
termp__a_pre(DECL_ARGS)
{
+ struct roff_node *nn;
- if (n->prev && MDOC__A == n->prev->tok)
- if (NULL == n->next || MDOC__A != n->next->tok)
- term_word(p, "and");
+ if ((nn = roff_node_prev(n)) != NULL && nn->tok == MDOC__A &&
+ ((nn = roff_node_next(n)) == NULL || nn->tok != MDOC__A))
+ term_word(p, "and");
return 1;
}
@@ -1102,10 +1096,9 @@ termp_ns_pre(DECL_ARGS)
static int
termp_rs_pre(DECL_ARGS)
{
-
if (SEC_SEE_ALSO != n->sec)
return 1;
- if (n->type == ROFFT_BLOCK && n->prev != NULL)
+ if (n->type == ROFFT_BLOCK && roff_node_prev(n) != NULL)
term_vspace(p);
return 1;
}
@@ -1120,7 +1113,6 @@ termp_ex_pre(DECL_ARGS)
static int
termp_nd_pre(DECL_ARGS)
{
-
if (n->type == ROFFT_BODY)
term_word(p, "\\(en");
return 1;
@@ -1129,14 +1121,20 @@ termp_nd_pre(DECL_ARGS)
static int
termp_bl_pre(DECL_ARGS)
{
-
- return n->type != ROFFT_HEAD;
+ switch (n->type) {
+ case ROFFT_BLOCK:
+ term_newln(p);
+ return 1;
+ case ROFFT_HEAD:
+ return 0;
+ default:
+ return 1;
+ }
}
static void
termp_bl_post(DECL_ARGS)
{
-
if (n->type != ROFFT_BLOCK)
return;
term_newln(p);
@@ -1150,7 +1148,6 @@ termp_bl_post(DECL_ARGS)
static int
termp_xr_pre(DECL_ARGS)
{
-
if (NULL == (n = n->child))
return 0;
@@ -1179,13 +1176,12 @@ termp_xr_pre(DECL_ARGS)
* macro combos).
*/
static void
-synopsis_pre(struct termp *p, const struct roff_node *n)
+synopsis_pre(struct termp *p, struct roff_node *n)
{
- /*
- * Obviously, if we're not in a SYNOPSIS or no prior macros
- * exist, do nothing.
- */
- if (NULL == n->prev || ! (NODE_SYNPRETTY & n->flags))
+ struct roff_node *np;
+
+ if ((n->flags & NODE_SYNPRETTY) == 0 ||
+ (np = roff_node_prev(n)) == NULL)
return;
/*
@@ -1193,7 +1189,7 @@ synopsis_pre(struct termp *p, const struct roff_node *n)
* newline and return. UNLESS we're `Fo', `Fn', `Fn', in which
* case we soldier on.
*/
- if (n->prev->tok == n->tok &&
+ if (np->tok == n->tok &&
MDOC_Ft != n->tok &&
MDOC_Fo != n->tok &&
MDOC_Fn != n->tok) {
@@ -1206,7 +1202,7 @@ synopsis_pre(struct termp *p, const struct roff_node *n)
* another (or Fn/Fo, which we've let slip through) then assert
* vertical space, else only newline and move on.
*/
- switch (n->prev->tok) {
+ switch (np->tok) {
case MDOC_Fd:
case MDOC_Fn:
case MDOC_Fo:
@@ -1215,7 +1211,7 @@ synopsis_pre(struct termp *p, const struct roff_node *n)
term_vspace(p);
break;
case MDOC_Ft:
- if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
+ if (n->tok != MDOC_Fn && n->tok != MDOC_Fo) {
term_vspace(p);
break;
}
@@ -1229,24 +1225,22 @@ synopsis_pre(struct termp *p, const struct roff_node *n)
static int
termp_vt_pre(DECL_ARGS)
{
-
- if (n->type == ROFFT_ELEM) {
- synopsis_pre(p, n);
- return termp_under_pre(p, pair, meta, n);
- } else if (n->type == ROFFT_BLOCK) {
+ switch (n->type) {
+ case ROFFT_ELEM:
+ return termp_ft_pre(p, pair, meta, n);
+ case ROFFT_BLOCK:
synopsis_pre(p, n);
return 1;
- } else if (n->type == ROFFT_HEAD)
+ case ROFFT_HEAD:
return 0;
-
- return termp_under_pre(p, pair, meta, n);
+ default:
+ return termp_under_pre(p, pair, meta, n);
+ }
}
static int
termp_bold_pre(DECL_ARGS)
{
-
- termp_tag_pre(p, pair, meta, n);
term_fontpush(p, TERMFONT_BOLD);
return 1;
}
@@ -1254,7 +1248,6 @@ termp_bold_pre(DECL_ARGS)
static int
termp_fd_pre(DECL_ARGS)
{
-
synopsis_pre(p, n);
return termp_bold_pre(p, pair, meta, n);
}
@@ -1262,13 +1255,13 @@ termp_fd_pre(DECL_ARGS)
static void
termp_fd_post(DECL_ARGS)
{
-
term_newln(p);
}
static int
termp_sh_pre(DECL_ARGS)
{
+ struct roff_node *np;
switch (n->type) {
case ROFFT_BLOCK:
@@ -1276,30 +1269,20 @@ termp_sh_pre(DECL_ARGS)
* Vertical space before sections, except
* when the previous section was empty.
*/
- if (n->prev == NULL ||
- n->prev->tok != MDOC_Sh ||
- (n->prev->body != NULL &&
- n->prev->body->child != NULL))
+ if ((np = roff_node_prev(n)) == NULL ||
+ np->tok != MDOC_Sh ||
+ (np->body != NULL && np->body->child != NULL))
term_vspace(p);
break;
case ROFFT_HEAD:
- term_fontpush(p, TERMFONT_BOLD);
- break;
+ return termp_bold_pre(p, pair, meta, n);
case ROFFT_BODY:
p->tcol->offset = term_len(p, p->defindent);
term_tab_set(p, NULL);
term_tab_set(p, "T");
term_tab_set(p, ".5i");
- switch (n->sec) {
- case SEC_DESCRIPTION:
- fn_prio = 0;
- break;
- case SEC_AUTHORS:
+ if (n->sec == SEC_AUTHORS)
p->flags &= ~(TERMP_SPLIT|TERMP_NOSPLIT);
- break;
- default:
- break;
- }
break;
default:
break;
@@ -1310,7 +1293,6 @@ termp_sh_pre(DECL_ARGS)
static void
termp_sh_post(DECL_ARGS)
{
-
switch (n->type) {
case ROFFT_HEAD:
term_newln(p);
@@ -1327,15 +1309,13 @@ termp_sh_post(DECL_ARGS)
static void
termp_lb_post(DECL_ARGS)
{
-
- if (SEC_LIBRARY == n->sec && NODE_LINE & n->flags)
+ if (n->sec == SEC_LIBRARY && n->flags & NODE_LINE)
term_newln(p);
}
static int
termp_d1_pre(DECL_ARGS)
{
-
if (n->type != ROFFT_BLOCK)
return 1;
term_newln(p);
@@ -1349,11 +1329,8 @@ termp_d1_pre(DECL_ARGS)
static int
termp_ft_pre(DECL_ARGS)
{
-
- /* NB: NODE_LINE does not effect this! */
synopsis_pre(p, n);
- term_fontpush(p, TERMFONT_UNDER);
- return 1;
+ return termp_under_pre(p, pair, meta, n);
}
static int
@@ -1362,11 +1339,9 @@ termp_fn_pre(DECL_ARGS)
size_t rmargin = 0;
int pretty;
- pretty = NODE_SYNPRETTY & n->flags;
-
synopsis_pre(p, n);
-
- if (NULL == (n = n->child))
+ pretty = n->flags & NODE_SYNPRETTY;
+ if ((n = n->child) == NULL)
return 0;
if (pretty) {
@@ -1380,9 +1355,6 @@ termp_fn_pre(DECL_ARGS)
term_word(p, n->string);
term_fontpop(p);
- if (n->sec == SEC_DESCRIPTION || n->sec == SEC_CUSTOM)
- tag_put(n->string, ++fn_prio, p->line);
-
if (pretty) {
term_flushln(p);
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
@@ -1417,7 +1389,6 @@ termp_fn_pre(DECL_ARGS)
term_word(p, ";");
term_flushln(p);
}
-
return 0;
}
@@ -1426,23 +1397,25 @@ termp_fa_pre(DECL_ARGS)
{
const struct roff_node *nn;
- if (n->parent->tok != MDOC_Fo) {
- term_fontpush(p, TERMFONT_UNDER);
- return 1;
- }
+ if (n->parent->tok != MDOC_Fo)
+ return termp_under_pre(p, pair, meta, n);
- for (nn = n->child; nn; nn = nn->next) {
+ for (nn = n->child; nn != NULL; nn = nn->next) {
term_fontpush(p, TERMFONT_UNDER);
p->flags |= TERMP_NBRWORD;
term_word(p, nn->string);
term_fontpop(p);
-
- if (nn->next || (n->next && n->next->tok == MDOC_Fa)) {
+ if (nn->next != NULL) {
p->flags |= TERMP_NOSPACE;
term_word(p, ",");
}
}
-
+ if (n->child != NULL &&
+ (nn = roff_node_next(n)) != NULL &&
+ nn->tok == MDOC_Fa) {
+ p->flags |= TERMP_NOSPACE;
+ term_word(p, ",");
+ }
return 0;
}
@@ -1522,30 +1495,23 @@ termp_xx_post(DECL_ARGS)
static void
termp_pf_post(DECL_ARGS)
{
-
- if ( ! (n->next == NULL || n->next->flags & NODE_LINE))
+ if (n->next != NULL && (n->next->flags & NODE_LINE) == 0)
p->flags |= TERMP_NOSPACE;
}
static int
termp_ss_pre(DECL_ARGS)
{
- struct roff_node *nn;
-
switch (n->type) {
case ROFFT_BLOCK:
- term_newln(p);
- for (nn = n->prev; nn != NULL; nn = nn->prev)
- if (nn->type != ROFFT_COMMENT &&
- (nn->flags & NODE_NOPRT) == 0)
- break;
- if (nn != NULL)
+ if (roff_node_prev(n) == NULL)
+ term_newln(p);
+ else
term_vspace(p);
break;
case ROFFT_HEAD:
- term_fontpush(p, TERMFONT_BOLD);
p->tcol->offset = term_len(p, (p->defindent+1)/2);
- break;
+ return termp_bold_pre(p, pair, meta, n);
case ROFFT_BODY:
p->tcol->offset = term_len(p, p->defindent);
term_tab_set(p, NULL);
@@ -1555,34 +1521,21 @@ termp_ss_pre(DECL_ARGS)
default:
break;
}
-
return 1;
}
static void
termp_ss_post(DECL_ARGS)
{
-
if (n->type == ROFFT_HEAD || n->type == ROFFT_BODY)
term_newln(p);
}
static int
-termp_cd_pre(DECL_ARGS)
-{
-
- synopsis_pre(p, n);
- term_fontpush(p, TERMFONT_BOLD);
- return 1;
-}
-
-static int
termp_in_pre(DECL_ARGS)
{
-
synopsis_pre(p, n);
-
- if (NODE_SYNPRETTY & n->flags && NODE_LINE & n->flags) {
+ if (n->flags & NODE_SYNPRETTY && n->flags & NODE_LINE) {
term_fontpush(p, TERMFONT_BOLD);
term_word(p, "#include");
term_word(p, "<");
@@ -1590,7 +1543,6 @@ termp_in_pre(DECL_ARGS)
term_word(p, "<");
term_fontpush(p, TERMFONT_UNDER);
}
-
p->flags |= TERMP_NOSPACE;
return 1;
}
@@ -1598,36 +1550,32 @@ termp_in_pre(DECL_ARGS)
static void
termp_in_post(DECL_ARGS)
{
-
- if (NODE_SYNPRETTY & n->flags)
+ if (n->flags & NODE_SYNPRETTY)
term_fontpush(p, TERMFONT_BOLD);
-
p->flags |= TERMP_NOSPACE;
term_word(p, ">");
-
- if (NODE_SYNPRETTY & n->flags)
+ if (n->flags & NODE_SYNPRETTY)
term_fontpop(p);
}
static int
termp_pp_pre(DECL_ARGS)
{
- fn_prio = 0;
term_vspace(p);
+ if (n->flags & NODE_ID)
+ term_tag_write(n, p->line);
return 0;
}
static int
termp_skip_pre(DECL_ARGS)
{
-
return 0;
}
static int
termp_quote_pre(DECL_ARGS)
{
-
if (n->type != ROFFT_BODY && n->type != ROFFT_ELEM)
return 1;
@@ -1784,17 +1732,15 @@ termp_eo_post(DECL_ARGS)
static int
termp_fo_pre(DECL_ARGS)
{
- size_t rmargin = 0;
- int pretty;
-
- pretty = NODE_SYNPRETTY & n->flags;
+ size_t rmargin;
- if (n->type == ROFFT_BLOCK) {
+ switch (n->type) {
+ case ROFFT_BLOCK:
synopsis_pre(p, n);
return 1;
- } else if (n->type == ROFFT_BODY) {
- if (pretty) {
- rmargin = p->tcol->rmargin;
+ case ROFFT_BODY:
+ rmargin = p->tcol->rmargin;
+ if (n->flags & NODE_SYNPRETTY) {
p->tcol->rmargin = p->tcol->offset + term_len(p, 4);
p->flags |= TERMP_NOBREAK | TERMP_BRIND |
TERMP_HANG;
@@ -1802,7 +1748,7 @@ termp_fo_pre(DECL_ARGS)
p->flags |= TERMP_NOSPACE;
term_word(p, "(");
p->flags |= TERMP_NOSPACE;
- if (pretty) {
+ if (n->flags & NODE_SYNPRETTY) {
term_flushln(p);
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND |
TERMP_HANG);
@@ -1811,30 +1757,21 @@ termp_fo_pre(DECL_ARGS)
p->tcol->rmargin = rmargin;
}
return 1;
+ default:
+ return termp_bold_pre(p, pair, meta, n);
}
-
- if (NULL == n->child)
- return 0;
-
- /* XXX: we drop non-initial arguments as per groff. */
-
- assert(n->child->string);
- term_fontpush(p, TERMFONT_BOLD);
- term_word(p, n->child->string);
- return 0;
}
static void
termp_fo_post(DECL_ARGS)
{
-
if (n->type != ROFFT_BODY)
return;
p->flags |= TERMP_NOSPACE;
term_word(p, ")");
- if (NODE_SYNPRETTY & n->flags) {
+ if (n->flags & NODE_SYNPRETTY) {
p->flags |= TERMP_NOSPACE;
term_word(p, ";");
term_flushln(p);
@@ -1844,29 +1781,30 @@ termp_fo_post(DECL_ARGS)
static int
termp_bf_pre(DECL_ARGS)
{
-
- if (n->type == ROFFT_HEAD)
+ switch (n->type) {
+ case ROFFT_HEAD:
return 0;
- else if (n->type != ROFFT_BODY)
+ case ROFFT_BODY:
+ break;
+ default:
return 1;
-
- if (FONT_Em == n->norm->Bf.font)
- term_fontpush(p, TERMFONT_UNDER);
- else if (FONT_Sy == n->norm->Bf.font)
- term_fontpush(p, TERMFONT_BOLD);
- else
- term_fontpush(p, TERMFONT_NONE);
-
- return 1;
+ }
+ switch (n->norm->Bf.font) {
+ case FONT_Em:
+ return termp_under_pre(p, pair, meta, n);
+ case FONT_Sy:
+ return termp_bold_pre(p, pair, meta, n);
+ default:
+ return termp_li_pre(p, pair, meta, n);
+ }
}
static int
termp_sm_pre(DECL_ARGS)
{
-
- if (NULL == n->child)
+ if (n->child == NULL)
p->flags ^= TERMP_NONOSPACE;
- else if (0 == strcmp("on", n->child->string))
+ else if (strcmp(n->child->string, "on") == 0)
p->flags &= ~TERMP_NONOSPACE;
else
p->flags |= TERMP_NONOSPACE;
@@ -1880,7 +1818,6 @@ termp_sm_pre(DECL_ARGS)
static int
termp_ap_pre(DECL_ARGS)
{
-
p->flags |= TERMP_NOSPACE;
term_word(p, "'");
p->flags |= TERMP_NOSPACE;
@@ -1890,24 +1827,26 @@ termp_ap_pre(DECL_ARGS)
static void
termp____post(DECL_ARGS)
{
+ struct roff_node *nn;
/*
* Handle lists of authors. In general, print each followed by
* a comma. Don't print the comma if there are only two
* authors.
*/
- if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok)
- if (NULL == n->next->next || MDOC__A != n->next->next->tok)
- if (NULL == n->prev || MDOC__A != n->prev->tok)
- return;
+ if (n->tok == MDOC__A &&
+ (nn = roff_node_next(n)) != NULL && nn->tok == MDOC__A &&
+ ((nn = roff_node_next(nn)) == NULL || nn->tok != MDOC__A) &&
+ ((nn = roff_node_prev(n)) == NULL || nn->tok != MDOC__A))
+ return;
/* TODO: %U. */
- if (NULL == n->parent || MDOC_Rs != n->parent->tok)
+ if (n->parent == NULL || n->parent->tok != MDOC_Rs)
return;
p->flags |= TERMP_NOSPACE;
- if (NULL == n->next) {
+ if (roff_node_next(n) == NULL) {
term_word(p, ".");
p->flags |= TERMP_SENTENCE;
} else
@@ -1917,8 +1856,6 @@ termp____post(DECL_ARGS)
static int
termp_li_pre(DECL_ARGS)
{
-
- termp_tag_pre(p, pair, meta, n);
term_fontpush(p, TERMFONT_NONE);
return 1;
}
@@ -1968,7 +1905,6 @@ termp_lk_pre(DECL_ARGS)
static int
termp_bk_pre(DECL_ARGS)
{
-
switch (n->type) {
case ROFFT_BLOCK:
break;
@@ -1981,107 +1917,47 @@ termp_bk_pre(DECL_ARGS)
default:
abort();
}
-
return 1;
}
static void
termp_bk_post(DECL_ARGS)
{
-
if (n->type == ROFFT_BODY)
p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
}
+/*
+ * If we are in an `Rs' and there is a journal present,
+ * then quote us instead of underlining us (for disambiguation).
+ */
static void
termp__t_post(DECL_ARGS)
{
-
- /*
- * If we're in an `Rs' and there's a journal present, then quote
- * us instead of underlining us (for disambiguation).
- */
- if (n->parent && MDOC_Rs == n->parent->tok &&
+ if (n->parent != NULL && n->parent->tok == MDOC_Rs &&
n->parent->norm->Rs.quote_T)
termp_quote_post(p, pair, meta, n);
-
termp____post(p, pair, meta, n);
}
static int
termp__t_pre(DECL_ARGS)
{
-
- /*
- * If we're in an `Rs' and there's a journal present, then quote
- * us instead of underlining us (for disambiguation).
- */
- if (n->parent && MDOC_Rs == n->parent->tok &&
+ if (n->parent != NULL && n->parent->tok == MDOC_Rs &&
n->parent->norm->Rs.quote_T)
return termp_quote_pre(p, pair, meta, n);
-
- term_fontpush(p, TERMFONT_UNDER);
- return 1;
+ else
+ return termp_under_pre(p, pair, meta, n);
}
static int
termp_under_pre(DECL_ARGS)
{
-
term_fontpush(p, TERMFONT_UNDER);
return 1;
}
static int
-termp_em_pre(DECL_ARGS)
-{
- if (n->child != NULL &&
- n->child->type == ROFFT_TEXT)
- tag_put(n->child->string, 0, p->line);
- term_fontpush(p, TERMFONT_UNDER);
- return 1;
-}
-
-static int
-termp_sy_pre(DECL_ARGS)
-{
- if (n->child != NULL &&
- n->child->type == ROFFT_TEXT)
- tag_put(n->child->string, 0, p->line);
- term_fontpush(p, TERMFONT_BOLD);
- return 1;
-}
-
-static int
-termp_er_pre(DECL_ARGS)
-{
-
- if (n->sec == SEC_ERRORS &&
- (n->parent->tok == MDOC_It ||
- (n->parent->tok == MDOC_Bq &&
- n->parent->parent->parent->tok == MDOC_It)))
- tag_put(n->child->string, 1, p->line);
- return 1;
-}
-
-static int
-termp_tag_pre(DECL_ARGS)
-{
-
- if (n->child != NULL &&
- n->child->type == ROFFT_TEXT &&
- (n->prev == NULL ||
- (n->prev->type == ROFFT_TEXT &&
- strcmp(n->prev->string, "|") == 0)) &&
- (n->parent->tok == MDOC_It ||
- (n->parent->tok == MDOC_Xo &&
- n->parent->parent->prev == NULL &&
- n->parent->parent->parent->tok == MDOC_It)))
- tag_put(n->child->string, 1, p->line);
- return 1;
-}
-
-static int
termp_abort_pre(DECL_ARGS)
{
abort();
diff --git a/mdoc_validate.c b/mdoc_validate.c
index 11cdf00b56cb..e1cd3ae1edcb 100644
--- a/mdoc_validate.c
+++ b/mdoc_validate.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc_validate.c,v 1.374 2019/06/27 15:07:30 schwarze Exp $ */
+/* $Id: mdoc_validate.c,v 1.389 2021/07/18 11:41:23 schwarze Exp $ */
/*
+ * Copyright (c) 2010-2020 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2019 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -15,6 +15,8 @@
* 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.
+ *
+ * Validation module for mdoc(7) syntax trees used by mandoc(1).
*/
#include "config.h"
@@ -39,6 +41,7 @@
#include "libmandoc.h"
#include "roff_int.h"
#include "libmdoc.h"
+#include "tag.h"
/* FIXME: .Bl -diag can't have non-text children in HEAD. */
@@ -82,16 +85,18 @@ static void post_dd(POST_ARGS);
static void post_delim(POST_ARGS);
static void post_delim_nb(POST_ARGS);
static void post_dt(POST_ARGS);
+static void post_em(POST_ARGS);
static void post_en(POST_ARGS);
+static void post_er(POST_ARGS);
static void post_es(POST_ARGS);
static void post_eoln(POST_ARGS);
static void post_ex(POST_ARGS);
static void post_fa(POST_ARGS);
+static void post_fl(POST_ARGS);
static void post_fn(POST_ARGS);
static void post_fname(POST_ARGS);
static void post_fo(POST_ARGS);
static void post_hyph(POST_ARGS);
-static void post_ignpar(POST_ARGS);
static void post_it(POST_ARGS);
static void post_lb(POST_ARGS);
static void post_nd(POST_ARGS);
@@ -104,6 +109,7 @@ static void post_prevpar(POST_ARGS);
static void post_root(POST_ARGS);
static void post_rs(POST_ARGS);
static void post_rv(POST_ARGS);
+static void post_section(POST_ARGS);
static void post_sh(POST_ARGS);
static void post_sh_head(POST_ARGS);
static void post_sh_name(POST_ARGS);
@@ -113,6 +119,8 @@ static void post_sm(POST_ARGS);
static void post_st(POST_ARGS);
static void post_std(POST_ARGS);
static void post_sx(POST_ARGS);
+static void post_tag(POST_ARGS);
+static void post_tg(POST_ARGS);
static void post_useless(POST_ARGS);
static void post_xr(POST_ARGS);
static void post_xx(POST_ARGS);
@@ -122,7 +130,7 @@ static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = {
post_dt, /* Dt */
post_os, /* Os */
post_sh, /* Sh */
- post_ignpar, /* Ss */
+ post_section, /* Ss */
post_par, /* Pp */
post_display, /* D1 */
post_display, /* Dl */
@@ -136,19 +144,19 @@ static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = {
NULL, /* Ap */
post_defaults, /* Ar */
NULL, /* Cd */
- post_delim_nb, /* Cm */
- post_delim_nb, /* Dv */
- post_delim_nb, /* Er */
- post_delim_nb, /* Ev */
+ post_tag, /* Cm */
+ post_tag, /* Dv */
+ post_er, /* Er */
+ post_tag, /* Ev */
post_ex, /* Ex */
post_fa, /* Fa */
NULL, /* Fd */
- post_delim_nb, /* Fl */
+ post_fl, /* Fl */
post_fn, /* Fn */
post_delim_nb, /* Ft */
- post_delim_nb, /* Ic */
+ post_tag, /* Ic */
post_delim_nb, /* In */
- post_defaults, /* Li */
+ post_tag, /* Li */
post_nd, /* Nd */
post_nm, /* Nm */
post_delim_nb, /* Op */
@@ -156,7 +164,7 @@ static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = {
post_defaults, /* Pa */
post_rv, /* Rv */
post_st, /* St */
- post_delim_nb, /* Va */
+ post_tag, /* Va */
post_delim_nb, /* Vt */
post_xr, /* Xr */
NULL, /* %A */
@@ -186,11 +194,11 @@ static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = {
NULL, /* Dq */
NULL, /* Ec */
NULL, /* Ef */
- post_delim_nb, /* Em */
+ post_em, /* Em */
NULL, /* Eo */
post_xx, /* Fx */
- post_delim_nb, /* Ms */
- NULL, /* No */
+ post_tag, /* Ms */
+ post_tag, /* No */
post_ns, /* Ns */
post_xx, /* Nx */
post_xx, /* Ox */
@@ -209,7 +217,7 @@ static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = {
post_delim_nb, /* Sq */
post_sm, /* Sm */
post_sx, /* Sx */
- post_delim_nb, /* Sy */
+ post_em, /* Sy */
post_useless, /* Tn */
post_xx, /* Ux */
NULL, /* Xc */
@@ -238,6 +246,7 @@ static const v_post mdoc_valids[MDOC_MAX - MDOC_Dd] = {
NULL, /* %Q */
NULL, /* %U */
NULL, /* Ta */
+ post_tg, /* Tg */
};
#define RSORD_MAX 14 /* Number of `Rs' blocks. */
@@ -285,6 +294,8 @@ static const char * const secnames[SEC__MAX] = {
NULL
};
+static int fn_prio = TAG_STRONG;
+
/* Validate the subtree rooted at mdoc->last. */
void
@@ -1090,6 +1101,125 @@ post_st(POST_ARGS)
}
static void
+post_tg(POST_ARGS)
+{
+ struct roff_node *n; /* The .Tg node. */
+ struct roff_node *nch; /* The first child of the .Tg node. */
+ struct roff_node *nn; /* The next node after the .Tg node. */
+ struct roff_node *np; /* The parent of the next node. */
+ struct roff_node *nt; /* The TEXT node containing the tag. */
+ size_t len; /* The number of bytes in the tag. */
+
+ /* Find the next node. */
+ n = mdoc->last;
+ for (nn = n; nn != NULL; nn = nn->parent) {
+ if (nn->next != NULL) {
+ nn = nn->next;
+ break;
+ }
+ }
+
+ /* Find the tag. */
+ nt = nch = n->child;
+ if (nch == NULL && nn != NULL && nn->child != NULL &&
+ nn->child->type == ROFFT_TEXT)
+ nt = nn->child;
+
+ /* Validate the tag. */
+ if (nt == NULL || *nt->string == '\0')
+ mandoc_msg(MANDOCERR_MACRO_EMPTY, n->line, n->pos, "Tg");
+ if (nt == NULL) {
+ roff_node_delete(mdoc, n);
+ return;
+ }
+ len = strcspn(nt->string, " \t\\");
+ if (nt->string[len] != '\0')
+ mandoc_msg(MANDOCERR_TG_SPC, nt->line,
+ nt->pos + len, "Tg %s", nt->string);
+
+ /* Keep only the first argument. */
+ if (nch != NULL && nch->next != NULL) {
+ mandoc_msg(MANDOCERR_ARG_EXCESS, nch->next->line,
+ nch->next->pos, "Tg ... %s", nch->next->string);
+ while (nch->next != NULL)
+ roff_node_delete(mdoc, nch->next);
+ }
+
+ /* Drop the macro if the first argument is invalid. */
+ if (len == 0 || nt->string[len] != '\0') {
+ roff_node_delete(mdoc, n);
+ return;
+ }
+
+ /* By default, tag the .Tg node itself. */
+ if (nn == NULL || nn->flags & NODE_ID)
+ nn = n;
+
+ /* Explicit tagging of specific macros. */
+ switch (nn->tok) {
+ case MDOC_Sh:
+ case MDOC_Ss:
+ case MDOC_Fo:
+ nn = nn->head->child == NULL ? n : nn->head;
+ break;
+ case MDOC_It:
+ np = nn->parent;
+ while (np->tok != MDOC_Bl)
+ np = np->parent;
+ switch (np->norm->Bl.type) {
+ case LIST_column:
+ break;
+ case LIST_diag:
+ case LIST_hang:
+ case LIST_inset:
+ case LIST_ohang:
+ case LIST_tag:
+ nn = nn->head;
+ break;
+ case LIST_bullet:
+ case LIST_dash:
+ case LIST_enum:
+ case LIST_hyphen:
+ case LIST_item:
+ nn = nn->body->child == NULL ? n : nn->body;
+ break;
+ default:
+ abort();
+ }
+ break;
+ case MDOC_Bd:
+ case MDOC_Bl:
+ case MDOC_D1:
+ case MDOC_Dl:
+ nn = nn->body->child == NULL ? n : nn->body;
+ break;
+ case MDOC_Pp:
+ break;
+ case MDOC_Cm:
+ case MDOC_Dv:
+ case MDOC_Em:
+ case MDOC_Er:
+ case MDOC_Ev:
+ case MDOC_Fl:
+ case MDOC_Fn:
+ case MDOC_Ic:
+ case MDOC_Li:
+ case MDOC_Ms:
+ case MDOC_No:
+ case MDOC_Sy:
+ if (nn->child == NULL)
+ nn = n;
+ break;
+ default:
+ nn = n;
+ break;
+ }
+ tag_put(nt->string, TAG_MANUAL, nn);
+ if (nn != n)
+ n->flags |= NODE_NOPRT;
+}
+
+static void
post_obsolete(POST_ARGS)
{
struct roff_node *n;
@@ -1181,22 +1311,32 @@ post_bf(POST_ARGS)
static void
post_fname(POST_ARGS)
{
- const struct roff_node *n;
+ struct roff_node *n, *nch;
const char *cp;
size_t pos;
- n = mdoc->last->child;
- pos = strcspn(n->string, "()");
- cp = n->string + pos;
- if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*')))
- mandoc_msg(MANDOCERR_FN_PAREN, n->line, n->pos + pos,
- "%s", n->string);
+ n = mdoc->last;
+ nch = n->child;
+ cp = nch->string;
+ if (*cp == '(') {
+ if (cp[strlen(cp + 1)] == ')')
+ return;
+ pos = 0;
+ } else {
+ pos = strcspn(cp, "()");
+ if (cp[pos] == '\0') {
+ if (n->sec == SEC_DESCRIPTION ||
+ n->sec == SEC_CUSTOM)
+ tag_put(NULL, fn_prio++, n);
+ return;
+ }
+ }
+ mandoc_msg(MANDOCERR_FN_PAREN, nch->line, nch->pos + pos, "%s", cp);
}
static void
post_fn(POST_ARGS)
{
-
post_fname(mdoc);
post_fa(mdoc);
}
@@ -1360,38 +1500,29 @@ post_display(POST_ARGS)
static void
post_defaults(POST_ARGS)
{
- struct roff_node *nn;
+ struct roff_node *n;
- if (mdoc->last->child != NULL) {
+ n = mdoc->last;
+ if (n->child != NULL) {
post_delim_nb(mdoc);
return;
}
-
- /*
- * The `Ar' defaults to "file ..." if no value is provided as an
- * argument; the `Mt' and `Pa' macros use "~"; the `Li' just
- * gets an empty string.
- */
-
- nn = mdoc->last;
- switch (nn->tok) {
+ mdoc->next = ROFF_NEXT_CHILD;
+ switch (n->tok) {
case MDOC_Ar:
- mdoc->next = ROFF_NEXT_CHILD;
- roff_word_alloc(mdoc, nn->line, nn->pos, "file");
- mdoc->last->flags |= NODE_NOSRC;
- roff_word_alloc(mdoc, nn->line, nn->pos, "...");
+ roff_word_alloc(mdoc, n->line, n->pos, "file");
mdoc->last->flags |= NODE_NOSRC;
+ roff_word_alloc(mdoc, n->line, n->pos, "...");
break;
case MDOC_Pa:
case MDOC_Mt:
- mdoc->next = ROFF_NEXT_CHILD;
- roff_word_alloc(mdoc, nn->line, nn->pos, "~");
- mdoc->last->flags |= NODE_NOSRC;
+ roff_word_alloc(mdoc, n->line, n->pos, "~");
break;
default:
abort();
}
- mdoc->last = nn;
+ mdoc->last->flags |= NODE_NOSRC;
+ mdoc->last = n;
}
static void
@@ -1445,23 +1576,82 @@ post_an(POST_ARGS)
}
static void
-post_en(POST_ARGS)
+post_em(POST_ARGS)
{
+ post_tag(mdoc);
+ tag_put(NULL, TAG_FALLBACK, mdoc->last);
+}
+static void
+post_en(POST_ARGS)
+{
post_obsolete(mdoc);
if (mdoc->last->type == ROFFT_BLOCK)
mdoc->last->norm->Es = mdoc->last_es;
}
static void
-post_es(POST_ARGS)
+post_er(POST_ARGS)
{
+ struct roff_node *n;
+
+ n = mdoc->last;
+ if (n->sec == SEC_ERRORS &&
+ (n->parent->tok == MDOC_It ||
+ (n->parent->tok == MDOC_Bq &&
+ n->parent->parent->parent->tok == MDOC_It)))
+ tag_put(NULL, TAG_STRONG, n);
+ post_delim_nb(mdoc);
+}
+
+static void
+post_tag(POST_ARGS)
+{
+ struct roff_node *n;
+
+ n = mdoc->last;
+ if ((n->prev == NULL ||
+ (n->prev->type == ROFFT_TEXT &&
+ strcmp(n->prev->string, "|") == 0)) &&
+ (n->parent->tok == MDOC_It ||
+ (n->parent->tok == MDOC_Xo &&
+ n->parent->parent->prev == NULL &&
+ n->parent->parent->parent->tok == MDOC_It)))
+ tag_put(NULL, TAG_STRONG, n);
+ post_delim_nb(mdoc);
+}
+static void
+post_es(POST_ARGS)
+{
post_obsolete(mdoc);
mdoc->last_es = mdoc->last;
}
static void
+post_fl(POST_ARGS)
+{
+ struct roff_node *n;
+ char *cp;
+
+ /*
+ * Transform ".Fl Fl long" to ".Fl \-long",
+ * resulting for example in better HTML output.
+ */
+
+ n = mdoc->last;
+ if (n->prev != NULL && n->prev->tok == MDOC_Fl &&
+ n->prev->child == NULL && n->child != NULL &&
+ (n->flags & NODE_LINE) == 0) {
+ mandoc_asprintf(&cp, "\\-%s", n->child->string);
+ free(n->child->string);
+ n->child->string = cp;
+ roff_node_delete(mdoc, n->prev);
+ }
+ post_tag(mdoc);
+}
+
+static void
post_xx(POST_ARGS)
{
struct roff_node *n;
@@ -1553,8 +1743,8 @@ post_it(POST_ARGS)
if ((nch = nit->head->child) != NULL)
mandoc_msg(MANDOCERR_ARG_SKIP,
nit->line, nit->pos, "It %s",
- nch->string == NULL ? roff_name[nch->tok] :
- nch->string);
+ nch->type == ROFFT_TEXT ? nch->string :
+ roff_name[nch->tok]);
break;
case LIST_column:
cols = (int)nbl->norm->Bl.ncols;
@@ -1717,8 +1907,7 @@ post_bl_head(POST_ARGS)
static void
post_bl(POST_ARGS)
{
- struct roff_node *nparent, *nprev; /* of the Bl block */
- struct roff_node *nblock, *nbody; /* of the Bl */
+ struct roff_node *nbody; /* of the Bl */
struct roff_node *nchild, *nnext; /* of the Bl body */
const char *prev_Er;
int order;
@@ -1739,88 +1928,73 @@ post_bl(POST_ARGS)
if (nbody->end != ENDBODY_NOT)
return;
- nchild = nbody->child;
- if (nchild == NULL) {
- mandoc_msg(MANDOCERR_BLK_EMPTY,
- nbody->line, nbody->pos, "Bl");
- return;
+ /*
+ * Up to the first item, move nodes before the list,
+ * but leave transparent nodes where they are
+ * if they precede an item.
+ * The next non-transparent node is kept in nchild.
+ * It only needs to be updated after a non-transparent
+ * node was moved out, and at the very beginning
+ * when no node at all was moved yet.
+ */
+
+ nchild = mdoc->last;
+ for (;;) {
+ if (nchild == mdoc->last)
+ nchild = roff_node_child(nbody);
+ if (nchild == NULL) {
+ mdoc->last = nbody;
+ mandoc_msg(MANDOCERR_BLK_EMPTY,
+ nbody->line, nbody->pos, "Bl");
+ return;
+ }
+ if (nchild->tok == MDOC_It) {
+ mdoc->last = nbody;
+ break;
+ }
+ mandoc_msg(MANDOCERR_BL_MOVE, nbody->child->line,
+ nbody->child->pos, "%s", roff_name[nbody->child->tok]);
+ if (nbody->parent->prev == NULL) {
+ mdoc->last = nbody->parent->parent;
+ mdoc->next = ROFF_NEXT_CHILD;
+ } else {
+ mdoc->last = nbody->parent->prev;
+ mdoc->next = ROFF_NEXT_SIBLING;
+ }
+ roff_node_relink(mdoc, nbody->child);
}
+
+ /*
+ * We have reached the first item,
+ * so moving nodes out is no longer possible.
+ * But in .Bl -column, the first rows may be implicit,
+ * that is, they may not start with .It macros.
+ * Such rows may be followed by nodes generated on the
+ * roff level, for example .TS.
+ * Wrap such roff nodes into an implicit row.
+ */
+
while (nchild != NULL) {
- nnext = nchild->next;
- if (nchild->tok == MDOC_It ||
- (nchild->tok == MDOC_Sm &&
- nnext != NULL && nnext->tok == MDOC_It)) {
- nchild = nnext;
+ if (nchild->tok == MDOC_It) {
+ nchild = roff_node_next(nchild);
continue;
}
-
- /*
- * In .Bl -column, the first rows may be implicit,
- * that is, they may not start with .It macros.
- * Such rows may be followed by nodes generated on the
- * roff level, for example .TS, which cannot be moved
- * out of the list. In that case, wrap such roff nodes
- * into an implicit row.
- */
-
- if (nchild->prev != NULL) {
- mdoc->last = nchild;
- mdoc->next = ROFF_NEXT_SIBLING;
- roff_block_alloc(mdoc, nchild->line,
- nchild->pos, MDOC_It);
- roff_head_alloc(mdoc, nchild->line,
- nchild->pos, MDOC_It);
+ nnext = nchild->next;
+ mdoc->last = nchild->prev;
+ mdoc->next = ROFF_NEXT_SIBLING;
+ roff_block_alloc(mdoc, nchild->line, nchild->pos, MDOC_It);
+ roff_head_alloc(mdoc, nchild->line, nchild->pos, MDOC_It);
+ mdoc->next = ROFF_NEXT_SIBLING;
+ roff_body_alloc(mdoc, nchild->line, nchild->pos, MDOC_It);
+ while (nchild->tok != MDOC_It) {
+ roff_node_relink(mdoc, nchild);
+ if (nnext == NULL)
+ break;
+ nchild = nnext;
+ nnext = nchild->next;
mdoc->next = ROFF_NEXT_SIBLING;
- roff_body_alloc(mdoc, nchild->line,
- nchild->pos, MDOC_It);
- while (nchild->tok != MDOC_It) {
- roff_node_relink(mdoc, nchild);
- if ((nchild = nnext) == NULL)
- break;
- nnext = nchild->next;
- mdoc->next = ROFF_NEXT_SIBLING;
- }
- mdoc->last = nbody;
- continue;
}
-
- mandoc_msg(MANDOCERR_BL_MOVE, nchild->line, nchild->pos,
- "%s", roff_name[nchild->tok]);
-
- /*
- * Move the node out of the Bl block.
- * First, collect all required node pointers.
- */
-
- nblock = nbody->parent;
- nprev = nblock->prev;
- nparent = nblock->parent;
-
- /*
- * Unlink this child.
- */
-
- nbody->child = nnext;
- if (nnext == NULL)
- nbody->last = NULL;
- else
- nnext->prev = NULL;
-
- /*
- * Relink this child.
- */
-
- nchild->parent = nparent;
- nchild->prev = nprev;
- nchild->next = nblock;
-
- nblock->prev = nchild;
- if (nprev == NULL)
- nparent->child = nchild;
- else
- nprev->next = nchild;
-
- nchild = nnext;
+ mdoc->last = nbody;
}
if (mdoc->meta.os_e != MANDOC_OS_NETBSD)
@@ -1903,7 +2077,7 @@ post_root(POST_ARGS)
/* Add missing prologue data. */
if (mdoc->meta.date == NULL)
- mdoc->meta.date = mandoc_normdate(mdoc, NULL, 0, 0);
+ mdoc->meta.date = mandoc_normdate(NULL, NULL);
if (mdoc->meta.title == NULL) {
mandoc_msg(MANDOCERR_DT_NOTITLE, 0, 0, "EOF");
@@ -2048,10 +2222,11 @@ post_rs(POST_ARGS)
static void
post_hyph(POST_ARGS)
{
- struct roff_node *nch;
+ struct roff_node *n, *nch;
char *cp;
- for (nch = mdoc->last->child; nch != NULL; nch = nch->next) {
+ n = mdoc->last;
+ for (nch = n->child; nch != NULL; nch = nch->next) {
if (nch->type != ROFFT_TEXT)
continue;
cp = nch->string;
@@ -2060,8 +2235,11 @@ post_hyph(POST_ARGS)
while (*(++cp) != '\0')
if (*cp == '-' &&
isalpha((unsigned char)cp[-1]) &&
- isalpha((unsigned char)cp[1]))
+ isalpha((unsigned char)cp[1])) {
+ if (n->tag == NULL && n->flags & NODE_ID)
+ n->tag = mandoc_strdup(nch->string);
*cp = ASCII_HYPH;
+ }
}
}
@@ -2086,8 +2264,7 @@ post_sx(POST_ARGS)
static void
post_sh(POST_ARGS)
{
-
- post_ignpar(mdoc);
+ post_section(mdoc);
switch (mdoc->last->type) {
case ROFFT_HEAD:
@@ -2318,6 +2495,8 @@ post_sh_head(POST_ARGS)
roff_setreg(mdoc->roff, "nS", 0, '=');
mdoc->flags &= ~MDOC_SYNOPSIS;
}
+ if (sec == SEC_DESCRIPTION)
+ fn_prio = TAG_STRONG;
/* Mark our last section. */
@@ -2418,15 +2597,31 @@ post_xr(POST_ARGS)
}
static void
-post_ignpar(POST_ARGS)
+post_section(POST_ARGS)
{
- struct roff_node *np;
+ struct roff_node *n, *nch;
+ char *cp, *tag;
- switch (mdoc->last->type) {
+ n = mdoc->last;
+ switch (n->type) {
case ROFFT_BLOCK:
post_prevpar(mdoc);
return;
case ROFFT_HEAD:
+ tag = NULL;
+ deroff(&tag, n);
+ if (tag != NULL) {
+ for (cp = tag; *cp != '\0'; cp++)
+ if (*cp == ' ')
+ *cp = '_';
+ if ((nch = n->child) != NULL &&
+ nch->type == ROFFT_TEXT &&
+ strcmp(nch->string, tag) == 0)
+ tag_put(NULL, TAG_STRONG, n);
+ else
+ tag_put(tag, TAG_FALLBACK, n);
+ free(tag);
+ }
post_delim(mdoc);
post_hyph(mdoc);
return;
@@ -2435,42 +2630,40 @@ post_ignpar(POST_ARGS)
default:
return;
}
-
- if ((np = mdoc->last->child) != NULL)
- if (np->tok == MDOC_Pp ||
- np->tok == ROFF_br || np->tok == ROFF_sp) {
- mandoc_msg(MANDOCERR_PAR_SKIP, np->line, np->pos,
- "%s after %s", roff_name[np->tok],
- roff_name[mdoc->last->tok]);
- roff_node_delete(mdoc, np);
- }
-
- if ((np = mdoc->last->last) != NULL)
- if (np->tok == MDOC_Pp || np->tok == ROFF_br) {
- mandoc_msg(MANDOCERR_PAR_SKIP, np->line, np->pos,
- "%s at the end of %s", roff_name[np->tok],
- roff_name[mdoc->last->tok]);
- roff_node_delete(mdoc, np);
- }
+ if ((nch = n->child) != NULL &&
+ (nch->tok == MDOC_Pp || nch->tok == ROFF_br ||
+ nch->tok == ROFF_sp)) {
+ mandoc_msg(MANDOCERR_PAR_SKIP, nch->line, nch->pos,
+ "%s after %s", roff_name[nch->tok],
+ roff_name[n->tok]);
+ roff_node_delete(mdoc, nch);
+ }
+ if ((nch = n->last) != NULL &&
+ (nch->tok == MDOC_Pp || nch->tok == ROFF_br)) {
+ mandoc_msg(MANDOCERR_PAR_SKIP, nch->line, nch->pos,
+ "%s at the end of %s", roff_name[nch->tok],
+ roff_name[n->tok]);
+ roff_node_delete(mdoc, nch);
+ }
}
static void
post_prevpar(POST_ARGS)
{
- struct roff_node *n;
+ struct roff_node *n, *np;
n = mdoc->last;
- if (NULL == n->prev)
- return;
if (n->type != ROFFT_ELEM && n->type != ROFFT_BLOCK)
return;
+ if ((np = roff_node_prev(n)) == NULL)
+ return;
/*
* Don't allow `Pp' prior to a paragraph-type
* block: `Pp' or non-compact `Bd' or `Bl'.
*/
- if (n->prev->tok != MDOC_Pp && n->prev->tok != ROFF_br)
+ if (np->tok != MDOC_Pp && np->tok != ROFF_br)
return;
if (n->tok == MDOC_Bl && n->norm->Bl.comp)
return;
@@ -2479,9 +2672,9 @@ post_prevpar(POST_ARGS)
if (n->tok == MDOC_It && n->parent->norm->Bl.comp)
return;
- mandoc_msg(MANDOCERR_PAR_SKIP, n->prev->line, n->prev->pos,
- "%s before %s", roff_name[n->prev->tok], roff_name[n->tok]);
- roff_node_delete(mdoc, n->prev);
+ mandoc_msg(MANDOCERR_PAR_SKIP, np->line, np->pos,
+ "%s before %s", roff_name[np->tok], roff_name[n->tok]);
+ roff_node_delete(mdoc, np);
}
static void
@@ -2489,6 +2682,7 @@ post_par(POST_ARGS)
{
struct roff_node *np;
+ fn_prio = TAG_STRONG;
post_prevpar(mdoc);
np = mdoc->last;
@@ -2501,7 +2695,6 @@ static void
post_dd(POST_ARGS)
{
struct roff_node *n;
- char *datestr;
n = mdoc->last;
n->flags |= NODE_NOPRT;
@@ -2518,10 +2711,10 @@ post_dd(POST_ARGS)
mandoc_msg(MANDOCERR_PROLOG_ORDER,
n->line, n->pos, "Dd after Os");
- datestr = NULL;
- deroff(&datestr, n);
- mdoc->meta.date = mandoc_normdate(mdoc, datestr, n->line, n->pos);
- free(datestr);
+ if (mdoc->quick && n != NULL)
+ mdoc->meta.date = mandoc_strdup("");
+ else
+ mdoc->meta.date = mandoc_normdate(n->child, n);
}
static void
@@ -2596,8 +2789,14 @@ post_dt(POST_ARGS)
mandoc_msg(MANDOCERR_MSEC_BAD,
nn->line, nn->pos, "Dt ... %s", nn->string);
mdoc->meta.vol = mandoc_strdup(nn->string);
- } else
+ } else {
mdoc->meta.vol = mandoc_strdup(cp);
+ if (mdoc->filesec != '\0' &&
+ mdoc->filesec != *nn->string &&
+ *nn->string >= '1' && *nn->string <= '9')
+ mandoc_msg(MANDOCERR_MSEC_FILE, nn->line, nn->pos,
+ "*.%c vs Dt ... %c", mdoc->filesec, *nn->string);
+ }
/* Optional third argument: architecture. */
diff --git a/out.c b/out.c
index d0b0d0a2ace3..12333e38ffde 100644
--- a/out.c
+++ b/out.c
@@ -1,7 +1,8 @@
-/* $Id: out.c,v 1.78 2019/03/29 21:27:06 schwarze Exp $ */
+/* $Id: out.c,v 1.82 2021/09/07 17:07:58 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011,2014,2015,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 2014, 2015, 2017, 2018, 2019, 2021
+ * Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -22,11 +23,13 @@
#include <assert.h>
#include <ctype.h>
#include <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "mandoc_aux.h"
+#include "mandoc.h"
#include "tbl.h"
#include "out.h"
@@ -120,7 +123,6 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp_first,
const struct tbl_dat *dp;
struct roffcol *col;
struct tbl_colgroup *first_group, **gp, *g;
- size_t *colwidth;
size_t ewidth, min1, min2, wanted, width, xwidth;
int done, icol, maxcol, necol, nxcol, quirkcol;
@@ -209,13 +211,25 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp_first,
}
/*
- * Column spacings are needed for span width calculations,
- * so set the default values now.
+ * The minimum width of columns explicitly specified
+ * in the layout is 1n.
*/
- for (icol = 0; icol <= maxcol; icol++)
- if (tbl->cols[icol].spacing == SIZE_MAX || icol == maxcol)
- tbl->cols[icol].spacing = 3;
+ if (maxcol < sp_first->opts->cols - 1)
+ maxcol = sp_first->opts->cols - 1;
+ for (icol = 0; icol <= maxcol; icol++) {
+ col = tbl->cols + icol;
+ if (col->width < 1)
+ col->width = 1;
+
+ /*
+ * Column spacings are needed for span width
+ * calculations, so set the default values now.
+ */
+
+ if (col->spacing == SIZE_MAX || icol == maxcol)
+ col->spacing = 3;
+ }
/*
* Replace the minimum widths with the missing widths,
@@ -242,33 +256,21 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp_first,
gp = &(*gp)->next;
}
- colwidth = mandoc_reallocarray(NULL, maxcol + 1, sizeof(*colwidth));
while (first_group != NULL) {
/*
- * Rebuild the array of the widths of all columns
- * participating in spans that require expansion.
- */
-
- for (icol = 0; icol <= maxcol; icol++)
- colwidth[icol] = SIZE_MAX;
- for (g = first_group; g != NULL; g = g->next)
- for (icol = g->startcol; icol <= g->endcol; icol++)
- colwidth[icol] = tbl->cols[icol].width;
-
- /*
* Find the smallest and second smallest column width
* among the columns which may need expamsion.
*/
min1 = min2 = SIZE_MAX;
for (icol = 0; icol <= maxcol; icol++) {
- if (min1 > colwidth[icol]) {
+ width = tbl->cols[icol].width;
+ if (min1 > width) {
min2 = min1;
- min1 = colwidth[icol];
- } else if (min1 < colwidth[icol] &&
- min2 > colwidth[icol])
- min2 = colwidth[icol];
+ min1 = width;
+ } else if (min1 < width && min2 > width)
+ min2 = width;
}
/*
@@ -290,26 +292,22 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp_first,
width = min2;
if (wanted > width)
wanted = width;
- for (icol = g->startcol; icol <= g->endcol; icol++)
- if (colwidth[icol] == min1 ||
- (colwidth[icol] < min2 &&
- colwidth[icol] > width))
- colwidth[icol] = width;
}
- /* Record the effect of the widening on the group list. */
+ /* Record the effect of the widening. */
gp = &first_group;
while ((g = *gp) != NULL) {
done = 0;
for (icol = g->startcol; icol <= g->endcol; icol++) {
- if (colwidth[icol] != wanted ||
- tbl->cols[icol].width == wanted)
+ if (tbl->cols[icol].width != min1)
continue;
if (g->wanted <= wanted - min1) {
+ tbl->cols[icol].width += g->wanted;
done = 1;
break;
}
+ tbl->cols[icol].width = wanted;
g->wanted -= wanted - min1;
}
if (done) {
@@ -318,14 +316,7 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp_first,
} else
gp = &(*gp)->next;
}
-
- /* Record the effect of the widening on the columns. */
-
- for (icol = 0; icol <= maxcol; icol++)
- if (colwidth[icol] == wanted)
- tbl->cols[icol].width = wanted;
}
- free(colwidth);
/*
* Align numbers with text.
@@ -340,8 +331,6 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp_first,
col = tbl->cols + icol;
if (col->width > col->nwidth)
col->decimal += (col->width - col->nwidth) / 2;
- else
- col->width = col->nwidth;
if (col->flags & TBL_CELL_EQUAL) {
necol++;
if (ewidth < col->width)
@@ -549,5 +538,7 @@ tblcalc_number(struct rofftbl *tbl, struct roffcol *col,
if (totsz > col->nwidth)
col->nwidth = totsz;
+ if (col->nwidth > col->width)
+ col->width = col->nwidth;
return totsz;
}
diff --git a/out.h b/out.h
index dec6a8f87324..e621cbb7b92e 100644
--- a/out.h
+++ b/out.h
@@ -1,4 +1,4 @@
-/* $Id: out.h,v 1.33 2018/08/18 20:18:14 schwarze Exp $ */
+/* $Id: out.h,v 1.34 2020/04/03 11:35:01 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
@@ -14,6 +14,8 @@
* 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.
+ *
+ * Utilities for use by multiple mandoc(1) formatters.
*/
enum roffscale {
@@ -64,5 +66,5 @@ struct rofftbl {
struct tbl_span;
const char *a2roffsu(const char *, struct roffsu *, enum roffscale);
-void tblcalc(struct rofftbl *tbl,
+void tblcalc(struct rofftbl *,
const struct tbl_span *, size_t, size_t);
diff --git a/read.c b/read.c
index b3858061e710..5b33edbe9cef 100644
--- a/read.c
+++ b/read.c
@@ -1,7 +1,7 @@
-/* $Id: read.c,v 1.214 2019/07/10 19:39:01 schwarze Exp $ */
+/* $Id: read.c,v 1.220 2021/06/27 17:57:54 schwarze Exp $ */
/*
+ * Copyright (c) 2010-2020 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2019 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2010, 2012 Joerg Sonnenberger <joerg@netbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -15,6 +15,12 @@
* 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.
+ *
+ * Top-level functions of the mandoc(3) parser:
+ * Parser and input encoding selection, decompression,
+ * handling of input bytes, characters, lines, and files,
+ * handling of roff(7) loops and file inclusion,
+ * and steering of the various parsers.
*/
#include "config.h"
@@ -41,6 +47,7 @@
#include "mandoc_parse.h"
#include "libmandoc.h"
#include "roff_int.h"
+#include "tag.h"
#define REPARSE_LIMIT 1000
@@ -147,6 +154,7 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
struct buf *firstln, *lastln, *thisln, *loop;
char *cp;
size_t pos; /* byte number in the ln buffer */
+ size_t spos; /* at the start of the current line parse */
int line_result, result;
int of;
int lnn; /* line number in the real file */
@@ -173,6 +181,7 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
curp->filenc & MPARSE_LATIN1)
curp->filenc = preconv_cue(&blk, i);
}
+ spos = pos;
while (i < blk.sz && (start || blk.buf[i] != '\0')) {
@@ -272,7 +281,8 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
of = 0;
rerun:
- line_result = roff_parseln(curp->roff, curp->line, &ln, &of);
+ line_result = roff_parseln(curp->roff, curp->line,
+ &ln, &of, start && spos == 0 ? pos : 0);
/* Process options. */
@@ -547,7 +557,7 @@ mparse_readfd(struct mparse *curp, int fd, const char *filename)
struct buf blk;
struct buf *save_primary;
- const char *save_filename;
+ const char *save_filename, *cp;
size_t offset;
int save_filenc, save_lineno;
int with_mmap;
@@ -555,7 +565,13 @@ mparse_readfd(struct mparse *curp, int fd, const char *filename)
if (recursion_depth > 64) {
mandoc_msg(MANDOCERR_ROFFLOOP, curp->line, 0, NULL);
return;
- }
+ } else if (recursion_depth == 0 &&
+ (cp = strrchr(filename, '.')) != NULL &&
+ cp[1] >= '1' && cp[1] <= '9')
+ curp->man->filesec = cp[1];
+ else
+ curp->man->filesec = '\0';
+
if (read_whole_file(curp, fd, &blk, &with_mmap) == -1)
return;
@@ -664,22 +680,26 @@ mparse_alloc(int options, enum mandoc_os os_e, const char *os_s)
}
curp->man->meta.first->tok = TOKEN_NONE;
curp->man->meta.os_e = os_e;
+ tag_alloc();
return curp;
}
void
mparse_reset(struct mparse *curp)
{
+ tag_free();
roff_reset(curp->roff);
roff_man_reset(curp->man);
free_buf_list(curp->secondary);
curp->secondary = NULL;
curp->gzip = 0;
+ tag_alloc();
}
void
mparse_free(struct mparse *curp)
{
+ tag_free();
roffhash_free(curp->man->mdocmac);
roffhash_free(curp->man->manmac);
roff_man_free(curp->man);
@@ -697,6 +717,7 @@ mparse_result(struct mparse *curp)
mdoc_validate(curp->man);
else
man_validate(curp->man);
+ tag_postprocess(curp->man, curp->man->meta.first);
}
return &curp->man->meta;
}
diff --git a/roff.7 b/roff.7
index f129750b1b0e..6c2e3583f69b 100644
--- a/roff.7
+++ b/roff.7
@@ -1,4 +1,4 @@
-.\" $Id: roff.7,v 1.114 2019/07/15 19:20:30 schwarze Exp $
+.\" $Id: roff.7,v 1.116 2021/09/18 12:23:06 schwarze Exp $
.\"
.\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2010-2019 Ingo Schwarze <schwarze@openbsd.org>
@@ -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: July 15 2019 $
+.Dd $Mdocdate: September 18 2021 $
.Dt ROFF 7
.Os
.Sh NAME
@@ -624,7 +624,7 @@ Its syntax can be either
.Pp
or
.Bd -literal -offset indent
-.Pf . Ic \&de Ar macroname Ar endmacro
+.Pf . Ic \&de Ar macroname endmacro
.Ar definition
.Pf . Ar endmacro
.Ed
@@ -2331,7 +2331,7 @@ for
.At v2 ,
then ported nroff to C as troff, which Brian W. Kernighan released with
.At v7 .
-In 1989, James Clarke re-implemented troff in C++, naming it groff.
+In 1989, James Clark re-implemented troff in C++, naming it groff.
.Sh AUTHORS
.An -nosplit
This
diff --git a/roff.c b/roff.c
index f26d9f01f226..de75a260f5a7 100644
--- a/roff.c
+++ b/roff.c
@@ -1,7 +1,7 @@
-/* $Id: roff.c,v 1.366 2019/07/01 22:56:24 schwarze Exp $ */
+/* $Id: roff.c,v 1.378 2021/08/10 12:55:04 schwarze Exp $ */
/*
+ * Copyright (c) 2010-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,6 +14,8 @@
* 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.
+ *
+ * Implementation of the roff(7) parser for mandoc(1).
*/
#include "config.h"
@@ -190,13 +192,14 @@ static int roff_cc(ROFF_ARGS);
static int roff_ccond(struct roff *, int, int);
static int roff_char(ROFF_ARGS);
static int roff_cond(ROFF_ARGS);
+static int roff_cond_checkend(ROFF_ARGS);
static int roff_cond_text(ROFF_ARGS);
static int roff_cond_sub(ROFF_ARGS);
static int roff_ds(ROFF_ARGS);
static int roff_ec(ROFF_ARGS);
static int roff_eo(ROFF_ARGS);
static int roff_eqndelim(struct roff *, struct buf *, int);
-static int roff_evalcond(struct roff *r, int, char *, int *);
+static int roff_evalcond(struct roff *, int, char *, int *);
static int roff_evalnum(struct roff *, int,
const char *, int *, int *, int);
static int roff_evalpar(struct roff *, int,
@@ -355,7 +358,7 @@ const char *__roff_name[MAN_MAX + 1] = {
"Lk", "Mt", "Brq", "Bro",
"Brc", "%C", "Es", "En",
"Dx", "%Q", "%U", "Ta",
- NULL,
+ "Tg", NULL,
"TH", "SH", "SS", "TP",
"TQ",
"LP", "PP", "P", "IP",
@@ -771,6 +774,7 @@ void
roff_reset(struct roff *r)
{
roff_free1(r);
+ r->options |= MPARSE_COMMENT;
r->format = r->options & (MPARSE_MDOC | MPARSE_MAN);
r->control = '\0';
r->escape = '\\';
@@ -800,7 +804,7 @@ roff_alloc(int options)
r = mandoc_calloc(1, sizeof(struct roff));
r->reqtab = roffhash_alloc(0, ROFF_RENAMED);
- r->options = options;
+ r->options = options | MPARSE_COMMENT;
r->format = options & (MPARSE_MDOC | MPARSE_MAN);
r->mstackpos = -1;
r->rstackpos = -1;
@@ -1100,6 +1104,7 @@ roff_node_free(struct roff_node *n)
free(n->norm);
eqn_box_free(n->eqn);
free(n->string);
+ free(n->tag);
free(n);
}
@@ -1113,13 +1118,72 @@ roff_node_delete(struct roff_man *man, struct roff_node *n)
roff_node_free(n);
}
+int
+roff_node_transparent(struct roff_node *n)
+{
+ if (n == NULL)
+ return 0;
+ if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
+ return 1;
+ return roff_tok_transparent(n->tok);
+}
+
+int
+roff_tok_transparent(enum roff_tok tok)
+{
+ switch (tok) {
+ case ROFF_ft:
+ case ROFF_ll:
+ case ROFF_mc:
+ case ROFF_po:
+ case ROFF_ta:
+ case MDOC_Db:
+ case MDOC_Es:
+ case MDOC_Sm:
+ case MDOC_Tg:
+ case MAN_DT:
+ case MAN_UC:
+ case MAN_PD:
+ case MAN_AT:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+struct roff_node *
+roff_node_child(struct roff_node *n)
+{
+ for (n = n->child; roff_node_transparent(n); n = n->next)
+ continue;
+ return n;
+}
+
+struct roff_node *
+roff_node_prev(struct roff_node *n)
+{
+ do {
+ n = n->prev;
+ } while (roff_node_transparent(n));
+ return n;
+}
+
+struct roff_node *
+roff_node_next(struct roff_node *n)
+{
+ do {
+ n = n->next;
+ } while (roff_node_transparent(n));
+ return n;
+}
+
void
deroff(char **dest, const struct roff_node *n)
{
char *cp;
size_t sz;
- if (n->type != ROFFT_TEXT) {
+ if (n->string == NULL) {
for (n = n->child; n != NULL; n = n->next)
deroff(dest, n);
return;
@@ -1246,7 +1310,7 @@ roff_expand(struct roff *r, struct buf *buf, int ln, int pos, char newesc)
* in the syntax tree.
*/
- if (newesc != ASCII_ESC && r->format == 0) {
+ if (newesc != ASCII_ESC && r->options & MPARSE_COMMENT) {
while (*ep == ' ' || *ep == '\t')
ep--;
ep[1] = '\0';
@@ -1759,7 +1823,7 @@ roff_parsetext(struct roff *r, struct buf *buf, int pos, int *offs)
}
int
-roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
+roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs, size_t len)
{
enum roff_tok t;
int e;
@@ -1770,6 +1834,14 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
ppos = pos = *offs;
+ if (len > 80 && r->tbl == NULL && r->eqn == NULL &&
+ (r->man->flags & ROFF_NOFILL) == 0 &&
+ strchr(" .\\", buf->buf[pos]) == NULL &&
+ buf->buf[pos] != r->control &&
+ strcspn(buf->buf, " ") < 80)
+ mandoc_msg(MANDOCERR_TEXT_LONG, ln, (int)len - 1,
+ "%.20s...", buf->buf + pos);
+
/* Handle in-line equation delimiters. */
if (r->tbl == NULL &&
@@ -1815,8 +1887,10 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
roff_addtbl(r->man, ln, r->tbl);
return e;
}
- if ( ! ctl)
+ if ( ! ctl) {
+ r->options &= ~MPARSE_COMMENT;
return roff_parsetext(r, buf, pos, offs) | e;
+ }
/* Skip empty request lines. */
@@ -1839,6 +1913,7 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
/* No scope is open. This is a new request or macro. */
+ r->options &= ~MPARSE_COMMENT;
spos = pos;
t = roff_parse(r, buf->buf, &pos, ln, ppos);
@@ -1968,14 +2043,13 @@ roff_parse(struct roff *r, char *buf, int *pos, int ln, int ppos)
/* --- handling of request blocks ----------------------------------------- */
+/*
+ * Close a macro definition block or an "ignore" block.
+ */
static int
roff_cblock(ROFF_ARGS)
{
-
- /*
- * A block-close `..' should only be invoked as a child of an
- * ignore macro, otherwise raise a warning and just ignore it.
- */
+ int rr;
if (r->last == NULL) {
mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "..");
@@ -1984,26 +2058,38 @@ roff_cblock(ROFF_ARGS)
switch (r->last->tok) {
case ROFF_am:
- /* ROFF_am1 is remapped to ROFF_am in roff_block(). */
case ROFF_ami:
case ROFF_de:
- /* ROFF_de1 is remapped to ROFF_de in roff_block(). */
case ROFF_dei:
case ROFF_ig:
break;
+ case ROFF_am1:
+ case ROFF_de1:
+ /* Remapped in roff_block(). */
+ abort();
default:
mandoc_msg(MANDOCERR_BLK_NOTOPEN, ln, ppos, "..");
return ROFF_IGN;
}
+ roffnode_pop(r);
+ roffnode_cleanscope(r);
+
+ /*
+ * If a conditional block with braces is still open,
+ * check for "\}" block end markers.
+ */
+
+ if (r->last != NULL && r->last->endspan < 0) {
+ rr = 1; /* If arguments follow "\}", warn about them. */
+ roff_cond_checkend(r, tok, buf, ln, ppos, pos, &rr);
+ }
+
if (buf->buf[pos] != '\0')
mandoc_msg(MANDOCERR_ARG_SKIP, ln, pos,
".. %s", buf->buf + pos);
- roffnode_pop(r);
- roffnode_cleanscope(r);
return ROFF_IGN;
-
}
/*
@@ -2016,7 +2102,7 @@ roffnode_cleanscope(struct roff *r)
int inloop;
inloop = 0;
- while (r->last != NULL) {
+ while (r->last != NULL && r->last->endspan > 0) {
if (--r->last->endspan != 0)
break;
inloop += roffnode_pop(r);
@@ -2025,7 +2111,7 @@ roffnode_cleanscope(struct roff *r)
}
/*
- * Handle the closing \} of a conditional block.
+ * Handle the closing "\}" of a conditional block.
* Apart from generating warnings, this only pops nodes.
* Return the number of loops ended.
*/
@@ -2245,13 +2331,20 @@ roff_block_text(ROFF_ARGS)
return ROFF_IGN;
}
+/*
+ * Check for a closing "\}" and handle it.
+ * In this function, the final "int *offs" argument is used for
+ * different purposes than elsewhere:
+ * Input: *offs == 0: caller wants to discard arguments following \}
+ * *offs == 1: caller wants to preserve text following \}
+ * Output: *offs = 0: tell caller to discard input line
+ * *offs = 1: tell caller to use input line
+ */
static int
-roff_cond_sub(ROFF_ARGS)
+roff_cond_checkend(ROFF_ARGS)
{
- struct roffnode *bl;
char *ep;
int endloop, irc, rr;
- enum roff_tok t;
irc = ROFF_IGN;
rr = r->last->rule;
@@ -2261,23 +2354,28 @@ roff_cond_sub(ROFF_ARGS)
irc |= endloop;
/*
- * If `\}' occurs on a macro line without a preceding macro,
- * drop the line completely.
+ * If "\}" occurs on a macro line without a preceding macro or
+ * a text line contains nothing else, drop the line completely.
*/
ep = buf->buf + pos;
- if (ep[0] == '\\' && ep[1] == '}')
+ if (ep[0] == '\\' && ep[1] == '}' && (ep[2] == '\0' || *offs == 0))
rr = 0;
/*
- * The closing delimiter `\}' rewinds the conditional scope
+ * The closing delimiter "\}" rewinds the conditional scope
* but is otherwise ignored when interpreting the line.
*/
while ((ep = strchr(ep, '\\')) != NULL) {
switch (ep[1]) {
case '}':
- memmove(ep, ep + 2, strlen(ep + 2) + 1);
+ if (ep[2] == '\0')
+ ep[0] = '\0';
+ else if (rr)
+ ep[1] = '&';
+ else
+ memmove(ep, ep + 2, strlen(ep + 2) + 1);
if (roff_ccond(r, ln, ep - buf->buf))
irc |= endloop;
break;
@@ -2289,13 +2387,40 @@ roff_cond_sub(ROFF_ARGS)
break;
}
}
+ *offs = rr;
+ return irc;
+}
+
+/*
+ * Parse and process a request or macro line in conditional scope.
+ */
+static int
+roff_cond_sub(ROFF_ARGS)
+{
+ struct roffnode *bl;
+ int irc, rr;
+ enum roff_tok t;
+
+ rr = 0; /* If arguments follow "\}", skip them. */
+ irc = roff_cond_checkend(r, tok, buf, ln, ppos, pos, &rr);
+ t = roff_parse(r, buf->buf, &pos, ln, ppos);
+
+ /* For now, let high level macros abort .ce mode. */
+
+ if (roffce_node != NULL &&
+ (t == TOKEN_NONE || t == ROFF_Dd || t == ROFF_EQ ||
+ t == ROFF_TH || t == ROFF_TS)) {
+ r->man->last = roffce_node;
+ r->man->next = ROFF_NEXT_SIBLING;
+ roffce_lines = 0;
+ roffce_node = NULL;
+ }
/*
* Fully handle known macros when they are structurally
* required or when the conditional evaluated to true.
*/
- t = roff_parse(r, buf->buf, &pos, ln, ppos);
if (t == ROFF_break) {
if (irc & ROFF_LOOPMASK)
irc = ROFF_IGN | ROFF_LOOPEXIT;
@@ -2314,48 +2439,16 @@ roff_cond_sub(ROFF_ARGS)
return irc;
}
+/*
+ * Parse and process a text line in conditional scope.
+ */
static int
roff_cond_text(ROFF_ARGS)
{
- char *ep;
- int endloop, irc, rr;
+ int irc, rr;
- irc = ROFF_IGN;
- rr = r->last->rule;
- endloop = tok != ROFF_while ? ROFF_IGN :
- rr ? ROFF_LOOPCONT : ROFF_LOOPEXIT;
- if (roffnode_cleanscope(r))
- irc |= endloop;
-
- /*
- * If `\}' occurs on a text line with neither preceding
- * nor following characters, drop the line completely.
- */
-
- ep = buf->buf + pos;
- if (strcmp(ep, "\\}") == 0)
- rr = 0;
-
- /*
- * The closing delimiter `\}' rewinds the conditional scope
- * but is otherwise ignored when interpreting the line.
- */
-
- while ((ep = strchr(ep, '\\')) != NULL) {
- switch (ep[1]) {
- case '}':
- memmove(ep, ep + 2, strlen(ep + 2) + 1);
- if (roff_ccond(r, ln, ep - buf->buf))
- irc |= endloop;
- break;
- case '\0':
- ++ep;
- break;
- default:
- ep += 2;
- break;
- }
- }
+ rr = 1; /* If arguments follow "\}", preserve them. */
+ irc = roff_cond_checkend(r, tok, buf, ln, ppos, pos, &rr);
if (rr)
irc |= ROFF_CONT;
return irc;
@@ -3574,7 +3667,9 @@ roff_char(ROFF_ARGS)
case ESCAPE_FONTITALIC:
case ESCAPE_FONTBOLD:
case ESCAPE_FONTBI:
- case ESCAPE_FONTCW:
+ case ESCAPE_FONTCR:
+ case ESCAPE_FONTCB:
+ case ESCAPE_FONTCI:
case ESCAPE_FONTPREV:
font++;
break;
diff --git a/roff.h b/roff.h
index 49b0927513d4..2933eb9c0bf8 100644
--- a/roff.h
+++ b/roff.h
@@ -1,7 +1,7 @@
-/* $Id: roff.h,v 1.69 2019/03/04 13:01:57 schwarze Exp $ */
+/* $Id: roff.h,v 1.74 2020/04/08 11:56:03 schwarze Exp $ */
/*
+ * Copyright (c) 2013-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -437,6 +437,7 @@ enum roff_tok {
MDOC__Q,
MDOC__U,
MDOC_Ta,
+ MDOC_Tg,
MDOC_MAX,
MAN_TH,
MAN_SH,
@@ -505,6 +506,7 @@ struct roff_node {
struct mdoc_arg *args; /* BLOCK/ELEM */
union mdoc_data *norm; /* Normalized arguments. */
char *string; /* TEXT */
+ char *tag; /* For less(1) :t and HTML id=. */
struct tbl_span *span; /* TBL */
struct eqn_box *eqn; /* EQN */
int line; /* Input file line number. */
@@ -521,6 +523,8 @@ struct roff_node {
#define NODE_NOFILL (1 << 8) /* Fill mode switched off. */
#define NODE_NOSRC (1 << 9) /* Generated node, not in input file. */
#define NODE_NOPRT (1 << 10) /* Shall not print anything. */
+#define NODE_ID (1 << 11) /* Target for deep linking. */
+#define NODE_HREF (1 << 12) /* Link to another place in this page. */
int prev_font; /* Before entering this node. */
int aux; /* Decoded node data, type-dependent. */
enum roff_tok tok; /* Request or macro ID. */
@@ -548,5 +552,10 @@ struct roff_meta {
extern const char *const *roff_name;
-int arch_valid(const char *, enum mandoc_os);
-void deroff(char **, const struct roff_node *);
+int arch_valid(const char *, enum mandoc_os);
+void deroff(char **, const struct roff_node *);
+struct roff_node *roff_node_child(struct roff_node *);
+struct roff_node *roff_node_next(struct roff_node *);
+struct roff_node *roff_node_prev(struct roff_node *);
+int roff_node_transparent(struct roff_node *);
+int roff_tok_transparent(enum roff_tok);
diff --git a/roff_html.c b/roff_html.c
index e525aa2ede68..3cc7c19a8a51 100644
--- a/roff_html.c
+++ b/roff_html.c
@@ -1,4 +1,4 @@
-/* $Id: roff_html.c,v 1.20 2019/04/30 15:53:01 schwarze Exp $ */
+/* $Id: roff_html.c,v 1.21 2020/06/22 19:20:40 schwarze Exp $ */
/*
* Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2017, 2018, 2019 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,6 +15,8 @@
* 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"
+
#include <sys/types.h>
#include <assert.h>
diff --git a/roff_int.h b/roff_int.h
index d033f86aceec..e0700a742910 100644
--- a/roff_int.h
+++ b/roff_int.h
@@ -1,7 +1,7 @@
-/* $Id: roff_int.h,v 1.16 2019/01/05 00:36:50 schwarze Exp $ */
+/* $OpenBSD: roff_int.h,v 1.16 2019/01/05 00:36:46 schwarze Exp $ */
/*
+ * Copyright (c) 2013-2015, 2017-2020 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -59,6 +59,7 @@ struct roff_man {
enum roff_sec lastsec; /* Last section seen. */
enum roff_sec lastnamed; /* Last standard section seen. */
enum roff_next next; /* Where to put the next node. */
+ char filesec; /* Section digit in the file name. */
};
diff --git a/roff_term.c b/roff_term.c
index f10bb61d2cdd..115d850fb261 100644
--- a/roff_term.c
+++ b/roff_term.c
@@ -1,6 +1,6 @@
-/* $Id: roff_term.c,v 1.19 2019/01/04 03:24:33 schwarze Exp $ */
+/* $OpenBSD: roff_term.c,v 1.20 2020/09/03 17:37:06 schwarze Exp $ */
/*
- * Copyright (c) 2010,2014,2015,2017-2019 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010,2014,2015,2017-2020 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,6 +14,8 @@
* 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"
+
#include <sys/types.h>
#include <assert.h>
@@ -110,9 +112,11 @@ roff_term_pre_ft(ROFF_TERM_ARGS)
cp = n->child->string;
switch (mandoc_font(cp, (int)strlen(cp))) {
case ESCAPE_FONTBOLD:
+ case ESCAPE_FONTCB:
term_fontrepl(p, TERMFONT_BOLD);
break;
case ESCAPE_FONTITALIC:
+ case ESCAPE_FONTCI:
term_fontrepl(p, TERMFONT_UNDER);
break;
case ESCAPE_FONTBI:
@@ -122,7 +126,7 @@ roff_term_pre_ft(ROFF_TERM_ARGS)
term_fontlast(p);
break;
case ESCAPE_FONTROMAN:
- case ESCAPE_FONTCW:
+ case ESCAPE_FONTCR:
term_fontrepl(p, TERMFONT_NONE);
break;
default:
@@ -155,9 +159,13 @@ static void
roff_term_pre_po(ROFF_TERM_ARGS)
{
struct roffsu su;
- static int po, polast;
+ static int po, pouse, polast;
int ponew;
+ /* Revert the currently active page offset. */
+ p->tcol->offset -= pouse;
+
+ /* Determine the requested page offset. */
if (n->child != NULL &&
a2roffsu(n->child->string, &su, SCALE_EM) != NULL) {
ponew = term_hen(p, &su);
@@ -166,11 +174,15 @@ roff_term_pre_po(ROFF_TERM_ARGS)
ponew += po;
} else
ponew = polast;
+
+ /* Remeber both the previous and the newly requested offset. */
polast = po;
po = ponew;
- ponew = po - polast + (int)p->tcol->offset;
- p->tcol->offset = ponew > 0 ? ponew : 0;
+ /* Truncate to the range [-offset, 60], remember, and apply it. */
+ pouse = po >= 60 ? 60 :
+ po < -(int)p->tcol->offset ? -(int)p->tcol->offset : po;
+ p->tcol->offset += pouse;
}
static void
@@ -208,6 +220,7 @@ roff_term_pre_ti(ROFF_TERM_ARGS)
{
struct roffsu su;
const char *cp;
+ const size_t maxoff = 72;
int len, sign;
roff_term_pre_br(p, n);
@@ -228,17 +241,26 @@ roff_term_pre_ti(ROFF_TERM_ARGS)
return;
len = term_hen(p, &su);
- if (sign == 0) {
+ switch (sign) {
+ case 1:
+ if (p->tcol->offset + len <= maxoff)
+ p->ti = len;
+ else if (p->tcol->offset < maxoff)
+ p->ti = maxoff - p->tcol->offset;
+ else
+ p->ti = 0;
+ break;
+ case -1:
+ if ((size_t)len < p->tcol->offset)
+ p->ti = -len;
+ else
+ p->ti = -p->tcol->offset;
+ break;
+ default:
+ if ((size_t)len > maxoff)
+ len = maxoff;
p->ti = len - p->tcol->offset;
- p->tcol->offset = len;
- } else if (sign == 1) {
- p->ti = len;
- p->tcol->offset += len;
- } else if ((size_t)len < p->tcol->offset) {
- p->ti = -len;
- p->tcol->offset -= len;
- } else {
- p->ti = -p->tcol->offset;
- p->tcol->offset = 0;
+ break;
}
+ p->tcol->offset += p->ti;
}
diff --git a/roff_validate.c b/roff_validate.c
index 9080f28797af..74eedafb9581 100644
--- a/roff_validate.c
+++ b/roff_validate.c
@@ -1,6 +1,6 @@
-/* $Id: roff_validate.c,v 1.18 2018/12/31 09:02:37 schwarze Exp $ */
+/* $Id: roff_validate.c,v 1.20 2020/06/22 19:20:40 schwarze Exp $ */
/*
- * Copyright (c) 2010, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2017, 2018, 2020 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,6 +14,8 @@
* 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"
+
#include <sys/types.h>
#include <assert.h>
@@ -75,7 +77,7 @@ roff_valid_br(ROFF_VALID_ARGS)
return;
}
- if ((np = n->prev) == NULL)
+ if ((np = roff_node_prev(n)) == NULL)
return;
switch (np->tok) {
@@ -129,7 +131,7 @@ roff_valid_sp(ROFF_VALID_ARGS)
{
struct roff_node *np;
- if ((np = n->prev) == NULL)
+ if ((np = roff_node_prev(n)) == NULL)
return;
switch (np->tok) {
diff --git a/soelim.c b/soelim.c
index 3ef30820e318..33d60e458826 100644
--- a/soelim.c
+++ b/soelim.c
@@ -1,4 +1,4 @@
-/* $Id: soelim.c,v 1.5 2015/11/07 14:22:29 schwarze Exp $ */
+/* $Id: soelim.c,v 1.6 2021/09/19 18:14:24 schwarze Exp $ */
/*
* Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org>
* All rights reserved.
@@ -104,16 +104,16 @@ soelim_file(FILE *f, int flag)
}
walk = line + 3;
- if (!isspace(*walk) && ((flag & C_OPTION) == 0)) {
+ if (!isspace((unsigned char)*walk) && (flag & C_OPTION) == 0) {
printf("%s", line);
continue;
}
- while (isspace(*walk))
+ while (isspace((unsigned char)*walk))
walk++;
cp = walk;
- while (*cp != '\0' && !isspace(*cp))
+ while (*cp != '\0' && !isspace((unsigned char)*cp))
cp++;
*cp = 0;
if (cp < line + linelen)
diff --git a/tag.c b/tag.c
index d5e7f89c1a50..fcaad99f2e2e 100644
--- a/tag.c
+++ b/tag.c
@@ -1,6 +1,6 @@
-/* $Id: tag.c,v 1.24 2019/07/22 03:21:50 schwarze Exp $ */
+/* $Id: tag.c,v 1.36 2020/04/19 16:36:16 schwarze Exp $ */
/*
- * Copyright (c) 2015, 2016, 2018, 2019 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2015,2016,2018,2019,2020 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -13,142 +13,109 @@
* 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.
+ *
+ * Functions to tag syntax tree nodes.
+ * For internal use by mandoc(1) validation modules only.
*/
#include "config.h"
#include <sys/types.h>
-#include <errno.h>
+#include <assert.h>
#include <limits.h>
-#include <signal.h>
#include <stddef.h>
#include <stdint.h>
-#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
#include "mandoc_aux.h"
#include "mandoc_ohash.h"
-#include "mandoc.h"
+#include "roff.h"
+#include "mdoc.h"
+#include "roff_int.h"
#include "tag.h"
struct tag_entry {
- size_t *lines;
- size_t maxlines;
- size_t nlines;
+ struct roff_node **nodes;
+ size_t maxnodes;
+ size_t nnodes;
int prio;
char s[];
};
-static void tag_signal(int) __attribute__((__noreturn__));
+static void tag_move_href(struct roff_man *,
+ struct roff_node *, const char *);
+static void tag_move_id(struct roff_node *);
static struct ohash tag_data;
-static struct tag_files tag_files;
/*
- * Prepare for using a pager.
- * Not all pagers are capable of using a tag file,
- * but for simplicity, create it anyway.
+ * Set up the ohash table to collect nodes
+ * where various marked-up terms are documented.
*/
-struct tag_files *
-tag_init(void)
+void
+tag_alloc(void)
{
- struct sigaction sa;
- int ofd;
-
- ofd = -1;
- tag_files.tfd = -1;
- tag_files.tcpgid = -1;
-
- /* Clean up when dying from a signal. */
-
- memset(&sa, 0, sizeof(sa));
- sigfillset(&sa.sa_mask);
- sa.sa_handler = tag_signal;
- sigaction(SIGHUP, &sa, NULL);
- sigaction(SIGINT, &sa, NULL);
- sigaction(SIGTERM, &sa, NULL);
-
- /*
- * POSIX requires that a process calling tcsetpgrp(3)
- * from the background gets a SIGTTOU signal.
- * In that case, do not stop.
- */
-
- sa.sa_handler = SIG_IGN;
- sigaction(SIGTTOU, &sa, NULL);
-
- /* Save the original standard output for use by the pager. */
-
- if ((tag_files.ofd = dup(STDOUT_FILENO)) == -1) {
- mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno));
- goto fail;
- }
+ mandoc_ohash_init(&tag_data, 4, offsetof(struct tag_entry, s));
+}
- /* Create both temporary output files. */
+void
+tag_free(void)
+{
+ struct tag_entry *entry;
+ unsigned int slot;
- (void)strlcpy(tag_files.ofn, "/tmp/man.XXXXXXXXXX",
- sizeof(tag_files.ofn));
- (void)strlcpy(tag_files.tfn, "/tmp/man.XXXXXXXXXX",
- sizeof(tag_files.tfn));
- if ((ofd = mkstemp(tag_files.ofn)) == -1) {
- mandoc_msg(MANDOCERR_MKSTEMP, 0, 0,
- "%s: %s", tag_files.ofn, strerror(errno));
- goto fail;
- }
- if ((tag_files.tfd = mkstemp(tag_files.tfn)) == -1) {
- mandoc_msg(MANDOCERR_MKSTEMP, 0, 0,
- "%s: %s", tag_files.tfn, strerror(errno));
- goto fail;
- }
- if (dup2(ofd, STDOUT_FILENO) == -1) {
- mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno));
- goto fail;
+ if (tag_data.info.free == NULL)
+ return;
+ entry = ohash_first(&tag_data, &slot);
+ while (entry != NULL) {
+ free(entry->nodes);
+ free(entry);
+ entry = ohash_next(&tag_data, &slot);
}
- close(ofd);
-
- /*
- * Set up the ohash table to collect output line numbers
- * where various marked-up terms are documented.
- */
-
- mandoc_ohash_init(&tag_data, 4, offsetof(struct tag_entry, s));
- return &tag_files;
-
-fail:
- tag_unlink();
- if (ofd != -1)
- close(ofd);
- if (tag_files.ofd != -1)
- close(tag_files.ofd);
- if (tag_files.tfd != -1)
- close(tag_files.tfd);
- *tag_files.ofn = '\0';
- *tag_files.tfn = '\0';
- tag_files.ofd = -1;
- tag_files.tfd = -1;
- return NULL;
+ ohash_delete(&tag_data);
+ tag_data.info.free = NULL;
}
/*
- * Set the line number where a term is defined,
+ * Set a node where a term is defined,
* unless it is already defined at a lower priority.
*/
void
-tag_put(const char *s, int prio, size_t line)
+tag_put(const char *s, int prio, struct roff_node *n)
{
struct tag_entry *entry;
+ struct roff_node *nold;
const char *se;
size_t len;
unsigned int slot;
- if (tag_files.tfd <= 0)
- return;
+ assert(prio <= TAG_FALLBACK);
- if (s[0] == '\\' && (s[1] == '&' || s[1] == 'e'))
- s += 2;
+ if (s == NULL) {
+ if (n->child == NULL || n->child->type != ROFFT_TEXT)
+ return;
+ s = n->child->string;
+ switch (s[0]) {
+ case '-':
+ s++;
+ break;
+ case '\\':
+ switch (s[1]) {
+ case '&':
+ case '-':
+ case 'e':
+ s += 2;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
/*
* Skip whitespace and escapes and whatever follows,
@@ -160,137 +127,201 @@ tag_put(const char *s, int prio, size_t line)
return;
se = s + len;
- if (*se != '\0')
- prio = INT_MAX;
+ if (*se != '\0' && prio < TAG_WEAK)
+ prio = TAG_WEAK;
slot = ohash_qlookupi(&tag_data, s, &se);
entry = ohash_find(&tag_data, slot);
- if (entry == NULL) {
-
- /* Build a new entry. */
+ /* Build a new entry. */
+ if (entry == NULL) {
entry = mandoc_malloc(sizeof(*entry) + len + 1);
memcpy(entry->s, s, len);
entry->s[len] = '\0';
- entry->lines = NULL;
- entry->maxlines = entry->nlines = 0;
+ entry->nodes = NULL;
+ entry->maxnodes = entry->nnodes = 0;
ohash_insert(&tag_data, slot, entry);
+ }
- } else {
-
- /*
- * Lower priority numbers take precedence,
- * but 0 is special.
- * A tag with priority 0 is only used
- * if the tag occurs exactly once.
- */
+ /*
+ * Lower priority numbers take precedence.
+ * If a better entry is already present, ignore the new one.
+ */
- if (prio == 0) {
- if (entry->prio == 0)
- entry->prio = -1;
+ else if (entry->prio < prio)
return;
- }
- /* A better entry is already present, ignore the new one. */
+ /*
+ * If the existing entry is worse, clear it.
+ * In addition, a tag with priority TAG_FALLBACK
+ * is only used if the tag occurs exactly once.
+ */
- if (entry->prio > 0 && entry->prio < prio)
+ else if (entry->prio > prio || prio == TAG_FALLBACK) {
+ while (entry->nnodes > 0) {
+ nold = entry->nodes[--entry->nnodes];
+ nold->flags &= ~NODE_ID;
+ free(nold->tag);
+ nold->tag = NULL;
+ }
+ if (prio == TAG_FALLBACK) {
+ entry->prio = TAG_DELETE;
return;
-
- /* The existing entry is worse, clear it. */
-
- if (entry->prio < 1 || entry->prio > prio)
- entry->nlines = 0;
+ }
}
- /* Remember the new line. */
+ /* Remember the new node. */
- if (entry->maxlines == entry->nlines) {
- entry->maxlines += 4;
- entry->lines = mandoc_reallocarray(entry->lines,
- entry->maxlines, sizeof(*entry->lines));
+ if (entry->maxnodes == entry->nnodes) {
+ entry->maxnodes += 4;
+ entry->nodes = mandoc_reallocarray(entry->nodes,
+ entry->maxnodes, sizeof(*entry->nodes));
}
- entry->lines[entry->nlines++] = line;
+ entry->nodes[entry->nnodes++] = n;
entry->prio = prio;
+ n->flags |= NODE_ID;
+ if (n->child == NULL || n->child->string != s || *se != '\0') {
+ assert(n->tag == NULL);
+ n->tag = mandoc_strndup(s, len);
+ }
+}
+
+int
+tag_exists(const char *tag)
+{
+ return ohash_find(&tag_data, ohash_qlookup(&tag_data, tag)) != NULL;
}
/*
- * Write out the tags file using the previously collected
- * information and clear the ohash table while going along.
+ * For in-line elements, move the link target
+ * to the enclosing paragraph when appropriate.
*/
-void
-tag_write(void)
+static void
+tag_move_id(struct roff_node *n)
{
- FILE *stream;
- struct tag_entry *entry;
- size_t i;
- unsigned int slot;
- int empty;
+ struct roff_node *np;
- if (tag_files.tfd <= 0)
- return;
- if (tag_files.tagname != NULL && ohash_find(&tag_data,
- ohash_qlookup(&tag_data, tag_files.tagname)) == NULL) {
- mandoc_msg(MANDOCERR_TAG, 0, 0, "%s", tag_files.tagname);
- tag_files.tagname = NULL;
- }
- if ((stream = fdopen(tag_files.tfd, "w")) == NULL)
- mandoc_msg(MANDOCERR_FDOPEN, 0, 0, "%s", strerror(errno));
- empty = 1;
- entry = ohash_first(&tag_data, &slot);
- while (entry != NULL) {
- if (stream != NULL && entry->prio >= 0) {
- for (i = 0; i < entry->nlines; i++) {
- fprintf(stream, "%s %s %zu\n",
- entry->s, tag_files.ofn, entry->lines[i]);
- empty = 0;
+ np = n;
+ for (;;) {
+ if (np->prev != NULL)
+ np = np->prev;
+ else if ((np = np->parent) == NULL)
+ return;
+ switch (np->tok) {
+ case MDOC_It:
+ switch (np->parent->parent->norm->Bl.type) {
+ case LIST_column:
+ /* Target the ROFFT_BLOCK = <tr>. */
+ np = np->parent;
+ break;
+ case LIST_diag:
+ case LIST_hang:
+ case LIST_inset:
+ case LIST_ohang:
+ case LIST_tag:
+ /* Target the ROFFT_HEAD = <dt>. */
+ np = np->parent->head;
+ break;
+ default:
+ /* Target the ROFF_BODY = <li>. */
+ break;
+ }
+ /* FALLTHROUGH */
+ case MDOC_Pp: /* Target the ROFFT_ELEM = <p>. */
+ if (np->tag == NULL) {
+ np->tag = mandoc_strdup(n->tag == NULL ?
+ n->child->string : n->tag);
+ np->flags |= NODE_ID;
+ n->flags &= ~NODE_ID;
}
+ return;
+ case MDOC_Sh:
+ case MDOC_Ss:
+ case MDOC_Bd:
+ case MDOC_Bl:
+ case MDOC_D1:
+ case MDOC_Dl:
+ case MDOC_Rs:
+ /* Do not move past major blocks. */
+ return;
+ default:
+ /*
+ * Move past in-line content and partial
+ * blocks, for example .It Xo or .It Bq Er.
+ */
+ break;
}
- free(entry->lines);
- free(entry);
- entry = ohash_next(&tag_data, &slot);
- }
- ohash_delete(&tag_data);
- if (stream != NULL)
- fclose(stream);
- else
- close(tag_files.tfd);
- tag_files.tfd = -1;
- if (empty) {
- unlink(tag_files.tfn);
- *tag_files.tfn = '\0';
}
}
-void
-tag_unlink(void)
+/*
+ * When a paragraph is tagged and starts with text,
+ * move the permalink to the first few words.
+ */
+static void
+tag_move_href(struct roff_man *man, struct roff_node *n, const char *tag)
{
- pid_t tc_pgid;
-
- if (tag_files.tcpgid != -1) {
- tc_pgid = tcgetpgrp(tag_files.ofd);
- if (tc_pgid == tag_files.pager_pid ||
- tc_pgid == getpgid(0) ||
- getpgid(tc_pgid) == -1)
- (void)tcsetpgrp(tag_files.ofd, tag_files.tcpgid);
+ char *cp;
+
+ if (n == NULL || n->type != ROFFT_TEXT ||
+ *n->string == '\0' || *n->string == ' ')
+ return;
+
+ cp = n->string;
+ while (cp != NULL && cp - n->string < 5)
+ cp = strchr(cp + 1, ' ');
+
+ /* If the first text node is longer, split it. */
+
+ if (cp != NULL && cp[1] != '\0') {
+ man->last = n;
+ man->next = ROFF_NEXT_SIBLING;
+ roff_word_alloc(man, n->line,
+ n->pos + (cp - n->string), cp + 1);
+ man->last->flags = n->flags & ~NODE_LINE;
+ *cp = '\0';
}
- if (*tag_files.ofn != '\0')
- unlink(tag_files.ofn);
- if (*tag_files.tfn != '\0')
- unlink(tag_files.tfn);
+
+ assert(n->tag == NULL);
+ n->tag = mandoc_strdup(tag);
+ n->flags |= NODE_HREF;
}
-static void
-tag_signal(int signum)
+/*
+ * When all tags have been set, decide where to put
+ * the associated permalinks, and maybe move some tags
+ * to the beginning of the respective paragraphs.
+ */
+void
+tag_postprocess(struct roff_man *man, struct roff_node *n)
{
- struct sigaction sa;
-
- tag_unlink();
- memset(&sa, 0, sizeof(sa));
- sigemptyset(&sa.sa_mask);
- sa.sa_handler = SIG_DFL;
- sigaction(signum, &sa, NULL);
- kill(getpid(), signum);
- /* NOTREACHED */
- _exit(1);
+ if (n->flags & NODE_ID) {
+ switch (n->tok) {
+ case MDOC_Pp:
+ tag_move_href(man, n->next, n->tag);
+ break;
+ case MDOC_Bd:
+ case MDOC_D1:
+ case MDOC_Dl:
+ tag_move_href(man, n->child, n->tag);
+ break;
+ case MDOC_Bl:
+ /* XXX No permalink for now. */
+ break;
+ default:
+ if (n->type == ROFFT_ELEM || n->tok == MDOC_Fo)
+ tag_move_id(n);
+ if (n->tok != MDOC_Tg)
+ n->flags |= NODE_HREF;
+ else if ((n->flags & NODE_ID) == 0) {
+ n->flags |= NODE_NOPRT;
+ free(n->tag);
+ n->tag = NULL;
+ }
+ break;
+ }
+ }
+ for (n = n->child; n != NULL; n = n->next)
+ tag_postprocess(man, n);
}
diff --git a/tag.h b/tag.h
index bbd40b737e11..1eace6fd515e 100644
--- a/tag.h
+++ b/tag.h
@@ -1,6 +1,6 @@
-/* $Id: tag.h,v 1.8 2018/11/22 11:30:23 schwarze Exp $ */
+/* $Id: tag.h,v 1.14 2020/04/18 20:40:10 schwarze Exp $ */
/*
- * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2015, 2018, 2019, 2020 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -13,20 +13,23 @@
* 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.
+ *
+ * Internal interfaces to tag syntax tree nodes.
+ * For use by mandoc(1) validation modules only.
*/
-struct tag_files {
- char ofn[20];
- char tfn[20];
- char *tagname;
- int ofd;
- int tfd;
- pid_t tcpgid;
- pid_t pager_pid;
-};
-
+/*
+ * Tagging priorities.
+ * Lower numbers indicate higher importance.
+ */
+#define TAG_MANUAL 1 /* Set with a .Tg macro. */
+#define TAG_STRONG 2 /* Good automatic tagging. */
+#define TAG_WEAK (INT_MAX - 2) /* Dubious automatic tagging. */
+#define TAG_FALLBACK (INT_MAX - 1) /* Tag only used if unique. */
+#define TAG_DELETE (INT_MAX) /* Tag not used at all. */
-struct tag_files *tag_init(void);
-void tag_put(const char *, int, size_t);
-void tag_write(void);
-void tag_unlink(void);
+void tag_alloc(void);
+int tag_exists(const char *);
+void tag_put(const char *, int, struct roff_node *);
+void tag_postprocess(struct roff_man *, struct roff_node *);
+void tag_free(void);
diff --git a/tbl.7 b/tbl.7
index e7953ea0a4e8..4ecc354c4ea3 100644
--- a/tbl.7
+++ b/tbl.7
@@ -1,4 +1,4 @@
-.\" $Id: tbl.7,v 1.34 2019/03/02 21:03:02 schwarze Exp $
+.\" $Id: tbl.7,v 1.37 2021/09/18 12:34:27 schwarze Exp $
.\"
.\" Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2014,2015,2017,2018,2019 Ingo Schwarze <schwarze@openbsd.org>
@@ -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: March 2 2019 $
+.Dd $Mdocdate: September 18 2021 $
.Dt TBL 7
.Os
.Sh NAME
@@ -94,7 +94,7 @@ Allow page breaks within the table.
This is a GNU extension and currently ignored.
.It Cm nospaces
Ignore leading and trailing spaces in data cells.
-This is a GNU extension and currently ignored.
+This is a GNU extension.
.It Cm nowarn
Suppress warnings about tables exceeding the current line length.
This is a GNU extension and currently ignored.
@@ -178,10 +178,11 @@ of any other column also having the
.Cm e
modifier.
.It Cm f
-The next character selects the font to use for this cell.
+The next one or two characters select the font to use for this cell.
+One-character font names must be followed by a blank or period.
See the
.Xr roff 7
-manual for supported one-character font names.
+manual for supported font names.
.It Cm i
Use an italic font for the contents of this cell.
.It Cm m
@@ -416,7 +417,7 @@ equations inside tables.
.Xr roff 7
.Rs
.%A M. E. Lesk
-.%T Tbl\(emA Program to Format Tables
+.%T Tbl \(em A Program to Format Tables
.%D June 11, 1976
.Re
.Sh HISTORY
diff --git a/tbl.h b/tbl.h
index 365ae929edf4..0fccb440551c 100644
--- a/tbl.h
+++ b/tbl.h
@@ -1,7 +1,7 @@
-/* $Id: tbl.h,v 1.1 2018/12/12 21:54:35 schwarze Exp $ */
+/* $Id: tbl.h,v 1.2 2021/08/10 12:55:04 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014,2015,2017,2018,2021 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -57,14 +57,13 @@ struct tbl_cell {
int vert; /* Width of subsequent vertical line. */
int col; /* Column number, starting from 0. */
int flags;
-#define TBL_CELL_BOLD (1 << 0) /* b, B, fB */
-#define TBL_CELL_ITALIC (1 << 1) /* i, I, fI */
#define TBL_CELL_TALIGN (1 << 2) /* t, T */
#define TBL_CELL_UP (1 << 3) /* u, U */
#define TBL_CELL_BALIGN (1 << 4) /* d, D */
#define TBL_CELL_WIGN (1 << 5) /* z, Z */
#define TBL_CELL_EQUAL (1 << 6) /* e, E */
#define TBL_CELL_WMAX (1 << 7) /* x, X */
+ enum mandoc_esc font;
enum tbl_cellt pos;
};
diff --git a/tbl_data.c b/tbl_data.c
index 9a58d3256239..fe0259f9227a 100644
--- a/tbl_data.c
+++ b/tbl_data.c
@@ -1,7 +1,7 @@
-/* $Id: tbl_data.c,v 1.52 2019/02/09 16:00:39 schwarze Exp $ */
+/* $Id: tbl_data.c,v 1.59 2021/09/10 13:24:38 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011,2015,2017,2018,2019 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011,2015,2017-2019,2021 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -21,6 +21,7 @@
#include <assert.h>
#include <ctype.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -45,16 +46,20 @@ getdata(struct tbl_node *tbl, struct tbl_span *dp,
struct tbl_dat *dat, *pdat;
struct tbl_cell *cp;
struct tbl_span *pdp;
- int sv;
+ const char *ccp;
+ int startpos, endpos;
/*
* Determine the length of the string in the cell
* and advance the parse point to the end of the cell.
*/
- sv = *pos;
- while (p[*pos] != '\0' && p[*pos] != tbl->opts.tab)
- (*pos)++;
+ startpos = *pos;
+ ccp = p + startpos;
+ while (*ccp != '\0' && *ccp != tbl->opts.tab)
+ if (*ccp++ == '\\')
+ mandoc_escape(&ccp, NULL, NULL);
+ *pos = ccp - p;
/* Advance to the next layout cell, skipping spanners. */
@@ -73,12 +78,14 @@ getdata(struct tbl_node *tbl, struct tbl_span *dp,
if (dp->layout->last->col + 1 < dp->opts->cols) {
cp = mandoc_calloc(1, sizeof(*cp));
cp->pos = TBL_CELL_LEFT;
+ cp->font = ESCAPE_FONTROMAN;
+ cp->spacing = SIZE_MAX;
dp->layout->last->next = cp;
cp->col = dp->layout->last->col + 1;
dp->layout->last = cp;
} else {
mandoc_msg(MANDOCERR_TBLDATA_EXTRA,
- ln, sv, "%s", p + sv);
+ ln, startpos, "%s", p + startpos);
while (p[*pos] != '\0')
(*pos)++;
return;
@@ -103,7 +110,8 @@ getdata(struct tbl_node *tbl, struct tbl_span *dp,
*/
if (cp->pos == TBL_CELL_DOWN ||
- (*pos - sv == 2 && p[sv] == '\\' && p[sv + 1] == '^')) {
+ (*pos - startpos == 2 &&
+ p[startpos] == '\\' && p[startpos + 1] == '^')) {
pdp = dp;
while ((pdp = pdp->prev) != NULL) {
pdat = pdp->first;
@@ -139,18 +147,29 @@ getdata(struct tbl_node *tbl, struct tbl_span *dp,
dp->last->next = dat;
dp->last = dat;
+ /* Strip leading and trailing spaces, if requested. */
+
+ endpos = *pos;
+ if (dp->opts->opts & TBL_OPT_NOSPACE) {
+ while (p[startpos] == ' ')
+ startpos++;
+ while (endpos > startpos && p[endpos - 1] == ' ')
+ endpos--;
+ }
+
/*
* Check for a continued-data scope opening. This consists of a
* trailing `T{' at the end of the line. Subsequent lines,
* until a standalone `T}', are included in our cell.
*/
- if (*pos - sv == 2 && p[sv] == 'T' && p[sv + 1] == '{') {
+ if (endpos - startpos == 2 &&
+ p[startpos] == 'T' && p[startpos + 1] == '{') {
tbl->part = TBL_PART_CDATA;
return;
}
- dat->string = mandoc_strndup(p + sv, *pos - sv);
+ dat->string = mandoc_strndup(p + startpos, endpos - startpos);
if (p[*pos] != '\0')
(*pos)++;
@@ -171,7 +190,7 @@ getdata(struct tbl_node *tbl, struct tbl_span *dp,
dat->layout->pos == TBL_CELL_DOWN) &&
dat->pos == TBL_DATA_DATA && *dat->string != '\0')
mandoc_msg(MANDOCERR_TBLDATA_SPAN,
- ln, sv, "%s", dat->string);
+ ln, startpos, "%s", dat->string);
}
void
@@ -184,6 +203,9 @@ tbl_cdata(struct tbl_node *tbl, int ln, const char *p, int pos)
if (p[pos] == 'T' && p[pos + 1] == '}') {
pos += 2;
+ if (tbl->opts.opts & TBL_OPT_NOSPACE)
+ while (p[pos] == ' ')
+ pos++;
if (p[pos] == tbl->opts.tab) {
tbl->part = TBL_PART_DATA;
pos++;
@@ -242,10 +264,11 @@ tbl_data(struct tbl_node *tbl, int ln, const char *p, int pos)
struct tbl_cell *cp;
struct tbl_span *sp;
- rp = (sp = tbl->last_span) == NULL ? tbl->first_row :
- sp->pos == TBL_SPAN_DATA && sp->layout->next != NULL ?
- sp->layout->next : sp->layout;
-
+ for (sp = tbl->last_span; sp != NULL; sp = sp->prev)
+ if (sp->pos == TBL_SPAN_DATA)
+ break;
+ rp = sp == NULL ? tbl->first_row :
+ sp->layout->next == NULL ? sp->layout : sp->layout->next;
assert(rp != NULL);
if (p[1] == '\0') {
diff --git a/tbl_html.c b/tbl_html.c
index e137757dc16c..65c8ae8f887c 100644
--- a/tbl_html.c
+++ b/tbl_html.c
@@ -1,7 +1,7 @@
-/* $Id: tbl_html.c,v 1.33 2019/03/17 18:21:45 schwarze Exp $ */
+/* $Id: tbl_html.c,v 1.38 2021/09/09 16:52:52 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014,2015,2017,2018,2021 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -115,10 +115,14 @@ print_tbl(struct html *h, const struct tbl_span *sp)
const struct tbl_dat *dp;
const struct tbl_cell *cp;
const struct tbl_span *psp;
+ const struct roffcol *col;
struct tag *tt;
const char *hspans, *vspans, *halign, *valign;
const char *bborder, *lborder, *rborder;
+ const char *ccp;
char hbuf[4], vbuf[4];
+ size_t sz;
+ enum mandoc_esc save_font;
int i;
if (h->tblt == NULL)
@@ -240,8 +244,40 @@ print_tbl(struct html *h, const struct tbl_span *sp)
"vertical-align", valign,
"text-align", halign,
"border-right-style", rborder);
- if (dp->string != NULL)
+ if (dp->layout->pos == TBL_CELL_HORIZ ||
+ dp->layout->pos == TBL_CELL_DHORIZ ||
+ dp->pos == TBL_DATA_HORIZ ||
+ dp->pos == TBL_DATA_DHORIZ)
+ print_otag(h, TAG_HR, "");
+ else if (dp->string != NULL) {
+ save_font = h->metac;
+ html_setfont(h, dp->layout->font);
+ if (dp->layout->pos == TBL_CELL_LONG)
+ print_text(h, "\\[u2003]"); /* em space */
print_text(h, dp->string);
+ if (dp->layout->pos == TBL_CELL_NUMBER) {
+ col = h->tbl.cols + dp->layout->col;
+ if (col->decimal < col->nwidth) {
+ if ((ccp = strrchr(dp->string,
+ sp->opts->decimal)) == NULL) {
+ /* Punctuation space. */
+ print_text(h, "\\[u2008]");
+ ccp = strchr(dp->string, '\0');
+ } else
+ ccp++;
+ sz = col->nwidth - col->decimal;
+ while (--sz > 0) {
+ if (*ccp == '\0')
+ /* Figure space. */
+ print_text(h,
+ "\\[u2007]");
+ else
+ ccp++;
+ }
+ }
+ }
+ html_setfont(h, save_font);
+ }
}
print_tagq(h, tt);
diff --git a/tbl_layout.c b/tbl_layout.c
index 58599705c18c..171a8dbb1b49 100644
--- a/tbl_layout.c
+++ b/tbl_layout.c
@@ -1,7 +1,8 @@
-/* $Id: tbl_layout.c,v 1.48 2018/12/14 05:18:03 schwarze Exp $ */
+/* $Id: tbl_layout.c,v 1.50 2021/08/10 12:55:04 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2012, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2012, 2014, 2015, 2017, 2020, 2021
+ * Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -65,7 +66,10 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
int ln, const char *p, int *pos)
{
char *endptr;
+ unsigned long spacing;
size_t sz;
+ int isz;
+ enum mandoc_esc fontesc;
mod:
while (p[*pos] == ' ' || p[*pos] == '\t')
@@ -93,14 +97,18 @@ mod:
/* Parse numerical spacing from modifier string. */
if (isdigit((unsigned char)p[*pos])) {
- cp->spacing = strtoull(p + *pos, &endptr, 10);
+ if ((spacing = strtoul(p + *pos, &endptr, 10)) > 9)
+ mandoc_msg(MANDOCERR_TBLLAYOUT_SPC, ln, *pos,
+ "%lu", spacing);
+ else
+ cp->spacing = spacing;
*pos = endptr - p;
goto mod;
}
switch (tolower((unsigned char)p[(*pos)++])) {
case 'b':
- cp->flags |= TBL_CELL_BOLD;
+ cp->font = ESCAPE_FONTBOLD;
goto mod;
case 'd':
cp->flags |= TBL_CELL_BALIGN;
@@ -111,7 +119,7 @@ mod:
case 'f':
break;
case 'i':
- cp->flags |= TBL_CELL_ITALIC;
+ cp->font = ESCAPE_FONTITALIC;
goto mod;
case 'm':
mandoc_msg(MANDOCERR_TBLLAYOUT_MOD, ln, *pos, "m");
@@ -165,40 +173,34 @@ mod:
goto mod;
}
+ while (p[*pos] == ' ' || p[*pos] == '\t')
+ (*pos)++;
+
/* Ignore parenthised font names for now. */
if (p[*pos] == '(')
goto mod;
- /* Support only one-character font-names for now. */
-
- if (p[*pos] == '\0' || (p[*pos + 1] != ' ' && p[*pos + 1] != '.')) {
+ isz = 0;
+ if (p[*pos] != '\0')
+ isz++;
+ if (strchr(" \t.", p[*pos + isz]) == NULL)
+ isz++;
+
+ fontesc = mandoc_font(p + *pos, isz);
+
+ switch (fontesc) {
+ case ESCAPE_FONTPREV:
+ case ESCAPE_ERROR:
mandoc_msg(MANDOCERR_FT_BAD,
ln, *pos, "TS %s", p + *pos - 1);
- if (p[*pos] != '\0')
- (*pos)++;
- if (p[*pos] != '\0')
- (*pos)++;
- goto mod;
- }
-
- switch (p[(*pos)++]) {
- case '3':
- case 'B':
- cp->flags |= TBL_CELL_BOLD;
- goto mod;
- case '2':
- case 'I':
- cp->flags |= TBL_CELL_ITALIC;
- goto mod;
- case '1':
- case 'R':
- goto mod;
+ break;
default:
- mandoc_msg(MANDOCERR_FT_BAD,
- ln, *pos - 1, "TS f%c", p[*pos - 1]);
- goto mod;
+ cp->font = fontesc;
+ break;
}
+ *pos += isz;
+ goto mod;
}
static void
@@ -357,6 +359,7 @@ cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos)
p = mandoc_calloc(1, sizeof(*p));
p->spacing = SIZE_MAX;
+ p->font = ESCAPE_FONTROMAN;
p->pos = pos;
if ((pp = rp->last) != NULL) {
diff --git a/tbl_term.c b/tbl_term.c
index de88d61c15e1..eac125586c4d 100644
--- a/tbl_term.c
+++ b/tbl_term.c
@@ -1,7 +1,7 @@
-/* $Id: tbl_term.c,v 1.72 2019/07/01 22:56:24 schwarze Exp $ */
+/* $Id: tbl_term.c,v 1.75 2021/08/10 12:55:04 schwarze Exp $ */
/*
* Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011-2019 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011-2021 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -190,17 +190,6 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
tblcalc(&tp->tbl, sp, tp->tcol->offset, tp->tcol->rmargin);
- /* Tables leak .ta settings to subsequent text. */
-
- term_tab_set(tp, NULL);
- coloff = sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) ||
- sp->opts->lvert;
- for (ic = 0; ic < sp->opts->cols; ic++) {
- coloff += tp->tbl.cols[ic].width;
- term_tab_iset(coloff);
- coloff += tp->tbl.cols[ic].spacing;
- }
-
/* Center the table as a whole. */
offset = tp->tcol->offset;
@@ -267,11 +256,11 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
hspans--;
continue;
}
- if (dp == NULL)
- continue;
- hspans = dp->hspans;
- if (ic || sp->layout->first->pos != TBL_CELL_SPAN)
+ if (dp != NULL &&
+ (ic || sp->layout->first->pos != TBL_CELL_SPAN)) {
+ hspans = dp->hspans;
dp = dp->next;
+ }
}
/* Set up a column for a right vertical frame. */
@@ -302,11 +291,11 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
tp->tcol++;
tp->col = 0;
tbl_data(tp, sp->opts, cp, dp, tp->tbl.cols + ic);
- if (dp == NULL)
- continue;
- hspans = dp->hspans;
- if (cp->pos != TBL_CELL_SPAN)
+ if (dp != NULL &&
+ (ic || sp->layout->first->pos != TBL_CELL_SPAN)) {
+ hspans = dp->hspans;
dp = dp->next;
+ }
}
break;
}
@@ -425,11 +414,10 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
cp = cp->next;
continue;
}
- if (dp != NULL) {
+ if (dp != NULL && (ic ||
+ sp->layout->first->pos != TBL_CELL_SPAN)) {
hspans = dp->hspans;
- if (ic || sp->layout->first->pos
- != TBL_CELL_SPAN)
- dp = dp->next;
+ dp = dp->next;
}
/*
@@ -935,10 +923,24 @@ tbl_word(struct termp *tp, const struct tbl_dat *dp)
int prev_font;
prev_font = tp->fonti;
- if (dp->layout->flags & TBL_CELL_BOLD)
- term_fontpush(tp, TERMFONT_BOLD);
- else if (dp->layout->flags & TBL_CELL_ITALIC)
- term_fontpush(tp, TERMFONT_UNDER);
+ switch (dp->layout->font) {
+ case ESCAPE_FONTBI:
+ term_fontpush(tp, TERMFONT_BI);
+ break;
+ case ESCAPE_FONTBOLD:
+ case ESCAPE_FONTCB:
+ term_fontpush(tp, TERMFONT_BOLD);
+ break;
+ case ESCAPE_FONTITALIC:
+ case ESCAPE_FONTCI:
+ term_fontpush(tp, TERMFONT_UNDER);
+ break;
+ case ESCAPE_FONTROMAN:
+ case ESCAPE_FONTCR:
+ break;
+ default:
+ abort();
+ }
term_word(tp, dp->string);
diff --git a/term.c b/term.c
index 3b9277aaabbc..fb0351d91f1d 100644
--- a/term.c
+++ b/term.c
@@ -1,7 +1,7 @@
-/* $Id: term.c,v 1.281 2019/06/03 20:23:41 schwarze Exp $ */
+/* $Id: term.c,v 1.283 2021/08/10 12:55:04 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2019 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2020 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -38,8 +38,7 @@ static void bufferc(struct termp *, char);
static void encode(struct termp *, const char *, size_t);
static void encode1(struct termp *, int);
static void endline(struct termp *);
-static void term_field(struct termp *, size_t, size_t,
- size_t, size_t);
+static void term_field(struct termp *, size_t, size_t);
static void term_fill(struct termp *, size_t *, size_t *,
size_t);
@@ -127,8 +126,7 @@ term_flushln(struct termp *p)
* and with the BRNEVER flag, never break it at all.
*/
- vtarget = p->flags & TERMP_BRNEVER ? SIZE_MAX :
- (p->flags & TERMP_NOBREAK) == 0 ? vfield :
+ vtarget = (p->flags & TERMP_NOBREAK) == 0 ? vfield :
p->maxrmargin > p->viscol + vbl ?
p->maxrmargin - p->viscol - vbl : 0;
@@ -137,7 +135,8 @@ term_flushln(struct termp *p)
* If there is whitespace only, print nothing.
*/
- term_fill(p, &nbr, &vbr, vtarget);
+ term_fill(p, &nbr, &vbr,
+ p->flags & TERMP_BRNEVER ? SIZE_MAX : vtarget);
if (nbr == 0)
break;
@@ -156,7 +155,7 @@ term_flushln(struct termp *p)
/* Finally, print the field content. */
- term_field(p, vbl, nbr, vbr, vtarget);
+ term_field(p, vbl, nbr);
/*
* If there is no text left in the field, exit the loop.
@@ -345,12 +344,10 @@ term_fill(struct termp *p, size_t *nbr, size_t *vbr, size_t vtarget)
/*
* Print the contents of one field
* with an indentation of vbl visual columns,
- * an input string length of nbr characters,
- * an output width of vbr visual columns,
- * and a desired field width of vtarget visual columns.
+ * and an input string length of nbr characters.
*/
static void
-term_field(struct termp *p, size_t vbl, size_t nbr, size_t vbr, size_t vtarget)
+term_field(struct termp *p, size_t vbl, size_t nbr)
{
size_t ic; /* Character position in the input buffer. */
size_t vis; /* Visual position of the current character. */
@@ -592,16 +589,18 @@ term_word(struct termp *p, const char *word)
uc = *seq;
break;
case ESCAPE_FONTBOLD:
+ case ESCAPE_FONTCB:
term_fontrepl(p, TERMFONT_BOLD);
continue;
case ESCAPE_FONTITALIC:
+ case ESCAPE_FONTCI:
term_fontrepl(p, TERMFONT_UNDER);
continue;
case ESCAPE_FONTBI:
term_fontrepl(p, TERMFONT_BI);
continue;
case ESCAPE_FONT:
- case ESCAPE_FONTCW:
+ case ESCAPE_FONTCR:
case ESCAPE_FONTROMAN:
term_fontrepl(p, TERMFONT_NONE);
continue;
diff --git a/term_ascii.c b/term_ascii.c
index 368623cac105..bf7e9b639e04 100644
--- a/term_ascii.c
+++ b/term_ascii.c
@@ -1,7 +1,7 @@
-/* $Id: term_ascii.c,v 1.64 2018/11/28 14:23:06 schwarze Exp $ */
+/* $Id: term_ascii.c,v 1.66 2020/09/09 13:45:05 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014,2015,2017,2018,2020 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -232,7 +232,10 @@ ascii_endline(struct termp *p)
{
p->line++;
- p->tcol->offset -= p->ti;
+ if ((int)p->tcol->offset > p->ti)
+ p->tcol->offset -= p->ti;
+ else
+ p->tcol->offset = 0;
p->ti = 0;
putchar('\n');
}
@@ -242,7 +245,14 @@ ascii_advance(struct termp *p, size_t len)
{
size_t i;
- assert(len < UINT16_MAX);
+ /*
+ * XXX We used to have "assert(len < UINT16_MAX)" here.
+ * that is not quite right because the input document
+ * can trigger that by merely providing large input.
+ * For now, simply truncate.
+ */
+ if (len > 256)
+ len = 256;
for (i = 0; i < len; i++)
putchar(' ');
}
@@ -380,7 +390,14 @@ locale_advance(struct termp *p, size_t len)
{
size_t i;
- assert(len < UINT16_MAX);
+ /*
+ * XXX We used to have "assert(len < UINT16_MAX)" here.
+ * that is not quite right because the input document
+ * can trigger that by merely providing large input.
+ * For now, simply truncate.
+ */
+ if (len > 256)
+ len = 256;
for (i = 0; i < len; i++)
putwchar(L' ');
}
@@ -390,7 +407,10 @@ locale_endline(struct termp *p)
{
p->line++;
- p->tcol->offset -= p->ti;
+ if ((int)p->tcol->offset > p->ti)
+ p->tcol->offset -= p->ti;
+ else
+ p->tcol->offset = 0;
p->ti = 0;
putwchar(L'\n');
}
diff --git a/term_ps.c b/term_ps.c
index 2cd94c923156..374d3d9a6abd 100644
--- a/term_ps.c
+++ b/term_ps.c
@@ -1,7 +1,7 @@
-/* $Id: term_ps.c,v 1.91 2017/11/10 23:42:52 schwarze Exp $ */
+/* $Id: term_ps.c,v 1.92 2020/09/06 14:45:22 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2014,2015,2016,2017,2020 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2017 Marc Espie <espie@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -1252,7 +1252,10 @@ ps_endline(struct termp *p)
ps_closepage(p);
- p->tcol->offset -= p->ti;
+ if ((int)p->tcol->offset > p->ti)
+ p->tcol->offset -= p->ti;
+ else
+ p->tcol->offset = 0;
p->ti = 0;
}
diff --git a/term_tab.c b/term_tab.c
index 3343244f3c8f..84b4c00c6e65 100644
--- a/term_tab.c
+++ b/term_tab.c
@@ -1,4 +1,4 @@
-/* $Id: term_tab.c,v 1.5 2018/12/16 00:21:05 schwarze Exp $ */
+/* $Id: term_tab.c,v 1.6 2020/06/22 19:20:40 schwarze Exp $ */
/*
* Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -14,6 +14,8 @@
* 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"
+
#include <sys/types.h>
#include <stddef.h>
diff --git a/term_tag.c b/term_tag.c
new file mode 100644
index 000000000000..c26b942531fc
--- /dev/null
+++ b/term_tag.c
@@ -0,0 +1,227 @@
+/* $Id: term_tag.c,v 1.6 2021/03/30 17:16:55 schwarze Exp $ */
+/*
+ * Copyright (c) 2015,2016,2018,2019,2020 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * 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.
+ *
+ * Functions to write a ctags(1) file.
+ * For use by the mandoc(1) ASCII and UTF-8 formatters only.
+ */
+#include "config.h"
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mandoc.h"
+#include "roff.h"
+#include "roff_int.h"
+#include "tag.h"
+#include "term_tag.h"
+
+static void tag_signal(int) __attribute__((__noreturn__));
+
+static struct tag_files tag_files;
+
+
+/*
+ * Prepare for using a pager.
+ * Not all pagers are capable of using a tag file,
+ * but for simplicity, create it anyway.
+ */
+struct tag_files *
+term_tag_init(const char *outfilename, const char *suffix,
+ const char *tagfilename)
+{
+ struct sigaction sa;
+ int ofd; /* In /tmp/, dup(2)ed to stdout. */
+ int tfd;
+
+ ofd = tfd = -1;
+ tag_files.tfs = NULL;
+ tag_files.tcpgid = -1;
+
+ /* Clean up when dying from a signal. */
+
+ memset(&sa, 0, sizeof(sa));
+ sigfillset(&sa.sa_mask);
+ sa.sa_handler = tag_signal;
+ sigaction(SIGHUP, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
+
+ /*
+ * POSIX requires that a process calling tcsetpgrp(3)
+ * from the background gets a SIGTTOU signal.
+ * In that case, do not stop.
+ */
+
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGTTOU, &sa, NULL);
+
+ /* Save the original standard output for use by the pager. */
+
+ if ((tag_files.ofd = dup(STDOUT_FILENO)) == -1) {
+ mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno));
+ goto fail;
+ }
+
+ /* Create both temporary output files. */
+
+ if (outfilename == NULL) {
+ (void)snprintf(tag_files.ofn, sizeof(tag_files.ofn),
+ "/tmp/man.XXXXXXXXXX%s", suffix);
+ if ((ofd = mkstemps(tag_files.ofn, strlen(suffix))) == -1) {
+ mandoc_msg(MANDOCERR_MKSTEMP, 0, 0,
+ "%s: %s", tag_files.ofn, strerror(errno));
+ goto fail;
+ }
+ } else {
+ (void)strlcpy(tag_files.ofn, outfilename,
+ sizeof(tag_files.ofn));
+ unlink(outfilename);
+ ofd = open(outfilename, O_WRONLY | O_CREAT | O_EXCL, 0644);
+ if (ofd == -1) {
+ mandoc_msg(MANDOCERR_OPEN, 0, 0,
+ "%s: %s", outfilename, strerror(errno));
+ goto fail;
+ }
+ }
+ if (tagfilename == NULL) {
+ (void)strlcpy(tag_files.tfn, "/tmp/man.XXXXXXXXXX",
+ sizeof(tag_files.tfn));
+ if ((tfd = mkstemp(tag_files.tfn)) == -1) {
+ mandoc_msg(MANDOCERR_MKSTEMP, 0, 0,
+ "%s: %s", tag_files.tfn, strerror(errno));
+ goto fail;
+ }
+ } else {
+ (void)strlcpy(tag_files.tfn, tagfilename,
+ sizeof(tag_files.tfn));
+ unlink(tagfilename);
+ tfd = open(tagfilename, O_WRONLY | O_CREAT | O_EXCL, 0644);
+ if (tfd == -1) {
+ mandoc_msg(MANDOCERR_OPEN, 0, 0,
+ "%s: %s", tagfilename, strerror(errno));
+ goto fail;
+ }
+ }
+ if ((tag_files.tfs = fdopen(tfd, "w")) == NULL) {
+ mandoc_msg(MANDOCERR_FDOPEN, 0, 0, "%s", strerror(errno));
+ goto fail;
+ }
+ tfd = -1;
+ if (dup2(ofd, STDOUT_FILENO) == -1) {
+ mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno));
+ goto fail;
+ }
+ close(ofd);
+ return &tag_files;
+
+fail:
+ term_tag_unlink();
+ if (ofd != -1)
+ close(ofd);
+ if (tfd != -1)
+ close(tfd);
+ if (tag_files.ofd != -1) {
+ close(tag_files.ofd);
+ tag_files.ofd = -1;
+ }
+ return NULL;
+}
+
+void
+term_tag_write(struct roff_node *n, size_t line)
+{
+ const char *cp;
+ int len;
+
+ if (tag_files.tfs == NULL)
+ return;
+ cp = n->tag == NULL ? n->child->string : n->tag;
+ if (cp[0] == '\\' && (cp[1] == '&' || cp[1] == 'e'))
+ cp += 2;
+ len = strcspn(cp, " \t\\");
+ fprintf(tag_files.tfs, "%.*s %s %zu\n",
+ len, cp, tag_files.ofn, line);
+}
+
+/*
+ * Close both output files and restore the original standard output
+ * to the terminal. In the unlikely case that the latter fails,
+ * trying to start a pager would be useless, so report the failure
+ * to the main program.
+ */
+int
+term_tag_close(void)
+{
+ int irc = 0;
+
+ if (tag_files.tfs != NULL) {
+ fclose(tag_files.tfs);
+ tag_files.tfs = NULL;
+ }
+ if (tag_files.ofd != -1) {
+ fflush(stdout);
+ if ((irc = dup2(tag_files.ofd, STDOUT_FILENO)) == -1)
+ mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno));
+ close(tag_files.ofd);
+ tag_files.ofd = -1;
+ }
+ return irc;
+}
+
+void
+term_tag_unlink(void)
+{
+ pid_t tc_pgid;
+
+ if (tag_files.tcpgid != -1) {
+ tc_pgid = tcgetpgrp(STDOUT_FILENO);
+ if (tc_pgid == tag_files.pager_pid ||
+ tc_pgid == getpgid(0) ||
+ getpgid(tc_pgid) == -1)
+ (void)tcsetpgrp(STDOUT_FILENO, tag_files.tcpgid);
+ }
+ if (strncmp(tag_files.ofn, "/tmp/man.", 9) == 0) {
+ unlink(tag_files.ofn);
+ *tag_files.ofn = '\0';
+ }
+ if (strncmp(tag_files.tfn, "/tmp/man.", 9) == 0) {
+ unlink(tag_files.tfn);
+ *tag_files.tfn = '\0';
+ }
+}
+
+static void
+tag_signal(int signum)
+{
+ struct sigaction sa;
+
+ term_tag_unlink();
+ memset(&sa, 0, sizeof(sa));
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = SIG_DFL;
+ sigaction(signum, &sa, NULL);
+ kill(getpid(), signum);
+ /* NOTREACHED */
+ _exit(1);
+}
diff --git a/term_tag.h b/term_tag.h
new file mode 100644
index 000000000000..f82b1a6e9223
--- /dev/null
+++ b/term_tag.h
@@ -0,0 +1,34 @@
+/* $Id: term_tag.h,v 1.4 2021/03/30 17:16:55 schwarze Exp $ */
+/*
+ * Copyright (c) 2015, 2018, 2019, 2020 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * 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.
+ *
+ * Internal interfaces to write a ctags(1) file.
+ * For use by the mandoc(1) ASCII and UTF-8 formatters only.
+ */
+
+struct tag_files {
+ char ofn[80]; /* Output file name. */
+ char tfn[80]; /* Tag file name. */
+ FILE *tfs; /* Tag file object. */
+ int ofd; /* Original output file descriptor. */
+ pid_t tcpgid; /* Process group controlling the terminal. */
+ pid_t pager_pid; /* Process ID of the pager. */
+};
+
+
+struct tag_files *term_tag_init(const char *, const char *, const char *);
+void term_tag_write(struct roff_node *, size_t);
+int term_tag_close(void);
+void term_tag_unlink(void);
diff --git a/test-attribute.c b/test-attribute.c
new file mode 100644
index 000000000000..adbcc9268252
--- /dev/null
+++ b/test-attribute.c
@@ -0,0 +1,48 @@
+/* $Id: test-attribute.c,v 1.1 2020/06/22 20:00:38 schwarze Exp $ */
+/*
+ * Copyright (c) 2020 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void var_arg(const char *, ...)
+ __attribute__((__format__ (__printf__, 1, 2)));
+void no_ret(int)
+ __attribute__((__noreturn__));
+
+void
+var_arg(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+}
+
+void
+no_ret(int i)
+{
+ exit(i);
+}
+
+int
+main(void)
+{
+ var_arg("Test output: %d\n", 42);
+ no_ret(0);
+}
diff --git a/test-mkstemps.c b/test-mkstemps.c
new file mode 100644
index 000000000000..31460dcae428
--- /dev/null
+++ b/test-mkstemps.c
@@ -0,0 +1,12 @@
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main(void)
+{
+ char filename[] = "/tmp/temp.XXXXXX.suffix";
+
+ if (mkstemps(filename, 7) == -1)
+ return 1;
+ return unlink(filename) == -1;
+}
diff --git a/tree.c b/tree.c
index 649c0804c8b9..12e841a50b78 100644
--- a/tree.c
+++ b/tree.c
@@ -1,7 +1,7 @@
-/* $Id: tree.c,v 1.84 2019/01/01 05:56:34 schwarze Exp $ */
+/* $Id: tree.c,v 1.91 2021/09/07 10:59:18 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013-2015, 2017-2021 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,6 +14,9 @@
* 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.
+ *
+ * Formatting module to let mandoc(1) show
+ * a human readable representation of the syntax tree.
*/
#include "config.h"
@@ -33,7 +36,9 @@
#include "eqn.h"
#include "main.h"
+static void print_attr(const struct roff_node *);
static void print_box(const struct eqn_box *, int);
+static void print_cellt(enum tbl_cellt);
static void print_man(const struct roff_node *, int);
static void print_meta(const struct roff_meta *);
static void print_mdoc(const struct roff_node *, int);
@@ -187,28 +192,8 @@ print_mdoc(const struct roff_node *n, int indent)
if (argv[i].sz > 0)
printf(" ]");
}
-
- putchar(' ');
- if (n->flags & NODE_DELIMO)
- putchar('(');
- if (n->flags & NODE_LINE)
- putchar('*');
- printf("%d:%d", n->line, n->pos + 1);
- if (n->flags & NODE_DELIMC)
- putchar(')');
- if (n->flags & NODE_EOS)
- putchar('.');
- if (n->flags & NODE_BROKEN)
- printf(" BROKEN");
- if (n->flags & NODE_NOFILL)
- printf(" NOFILL");
- if (n->flags & NODE_NOSRC)
- printf(" NOSRC");
- if (n->flags & NODE_NOPRT)
- printf(" NOPRT");
- putchar('\n');
+ print_attr(n);
}
-
if (n->eqn)
print_box(n->eqn->first, indent + 4);
if (n->child)
@@ -289,19 +274,9 @@ print_man(const struct roff_node *n, int indent)
} else {
for (i = 0; i < indent; i++)
putchar(' ');
- printf("%s (%s) ", p, t);
- if (n->flags & NODE_LINE)
- putchar('*');
- printf("%d:%d", n->line, n->pos + 1);
- if (n->flags & NODE_DELIMC)
- putchar(')');
- if (n->flags & NODE_EOS)
- putchar('.');
- if (n->flags & NODE_NOFILL)
- printf(" NOFILL");
- putchar('\n');
+ printf("%s (%s)", p, t);
+ print_attr(n);
}
-
if (n->eqn)
print_box(n->eqn->first, indent + 4);
if (n->child)
@@ -312,6 +287,40 @@ print_man(const struct roff_node *n, int indent)
}
static void
+print_attr(const struct roff_node *n)
+{
+ putchar(' ');
+ if (n->flags & NODE_DELIMO)
+ putchar('(');
+ if (n->flags & NODE_LINE)
+ putchar('*');
+ printf("%d:%d", n->line, n->pos + 1);
+ if (n->flags & NODE_DELIMC)
+ putchar(')');
+ if (n->flags & NODE_EOS)
+ putchar('.');
+ if (n->flags & NODE_ID) {
+ printf(" ID");
+ if (n->flags & NODE_HREF)
+ printf("=HREF");
+ } else if (n->flags & NODE_HREF)
+ printf(" HREF");
+ else if (n->tag != NULL)
+ printf(" STRAYTAG");
+ if (n->tag != NULL)
+ printf("=%s", n->tag);
+ if (n->flags & NODE_BROKEN)
+ printf(" BROKEN");
+ if (n->flags & NODE_NOFILL)
+ printf(" NOFILL");
+ if (n->flags & NODE_NOSRC)
+ printf(" NOSRC");
+ if (n->flags & NODE_NOPRT)
+ printf(" NOPRT");
+ putchar('\n');
+}
+
+static void
print_box(const struct eqn_box *ep, int indent)
{
int i;
@@ -374,11 +383,72 @@ print_box(const struct eqn_box *ep, int indent)
}
static void
+print_cellt(enum tbl_cellt pos)
+{
+ switch(pos) {
+ case TBL_CELL_LEFT:
+ putchar('L');
+ break;
+ case TBL_CELL_LONG:
+ putchar('a');
+ break;
+ case TBL_CELL_CENTRE:
+ putchar('c');
+ break;
+ case TBL_CELL_RIGHT:
+ putchar('r');
+ break;
+ case TBL_CELL_NUMBER:
+ putchar('n');
+ break;
+ case TBL_CELL_SPAN:
+ putchar('s');
+ break;
+ case TBL_CELL_DOWN:
+ putchar('^');
+ break;
+ case TBL_CELL_HORIZ:
+ putchar('-');
+ break;
+ case TBL_CELL_DHORIZ:
+ putchar('=');
+ break;
+ case TBL_CELL_MAX:
+ putchar('#');
+ break;
+ }
+}
+
+static void
print_span(const struct tbl_span *sp, int indent)
{
const struct tbl_dat *dp;
+ const struct tbl_cell *cp;
int i;
+ if (sp->prev == NULL) {
+ for (i = 0; i < indent; i++)
+ putchar(' ');
+ printf("%d", sp->opts->cols);
+ if (sp->opts->opts & TBL_OPT_CENTRE)
+ fputs(" center", stdout);
+ if (sp->opts->opts & TBL_OPT_EXPAND)
+ fputs(" expand", stdout);
+ if (sp->opts->opts & TBL_OPT_ALLBOX)
+ fputs(" allbox", stdout);
+ if (sp->opts->opts & TBL_OPT_BOX)
+ fputs(" box", stdout);
+ if (sp->opts->opts & TBL_OPT_DBOX)
+ fputs(" doublebox", stdout);
+ if (sp->opts->opts & TBL_OPT_NOKEEP)
+ fputs(" nokeep", stdout);
+ if (sp->opts->opts & TBL_OPT_NOSPACE)
+ fputs(" nospaces", stdout);
+ if (sp->opts->opts & TBL_OPT_NOWARN)
+ fputs(" nowarn", stdout);
+ printf(" (tbl options) %d:1\n", sp->line);
+ }
+
for (i = 0; i < indent; i++)
putchar(' ');
@@ -392,31 +462,72 @@ print_span(const struct tbl_span *sp, int indent)
putchar(' ');
break;
default:
+ for (cp = sp->layout->first; cp != NULL; cp = cp->next)
+ print_cellt(cp->pos);
+ putchar(' ');
for (dp = sp->first; dp; dp = dp->next) {
+ if ((cp = dp->layout) == NULL)
+ putchar('*');
+ else {
+ printf("%d", cp->col);
+ print_cellt(dp->layout->pos);
+ switch (cp->font) {
+ case ESCAPE_FONTROMAN:
+ break;
+ case ESCAPE_FONTBOLD:
+ putchar('b');
+ break;
+ case ESCAPE_FONTITALIC:
+ putchar('i');
+ break;
+ case ESCAPE_FONTBI:
+ fputs("bi", stdout);
+ break;
+ case ESCAPE_FONTCR:
+ putchar('c');
+ break;
+ case ESCAPE_FONTCB:
+ fputs("cb", stdout);
+ break;
+ case ESCAPE_FONTCI:
+ fputs("ci", stdout);
+ break;
+ default:
+ abort();
+ }
+ if (cp->flags & TBL_CELL_TALIGN)
+ putchar('t');
+ if (cp->flags & TBL_CELL_UP)
+ putchar('u');
+ if (cp->flags & TBL_CELL_BALIGN)
+ putchar('d');
+ if (cp->flags & TBL_CELL_WIGN)
+ putchar('z');
+ if (cp->flags & TBL_CELL_EQUAL)
+ putchar('e');
+ if (cp->flags & TBL_CELL_WMAX)
+ putchar('x');
+ }
switch (dp->pos) {
case TBL_DATA_HORIZ:
case TBL_DATA_NHORIZ:
putchar('-');
- putchar(' ');
- continue;
+ break;
case TBL_DATA_DHORIZ:
case TBL_DATA_NDHORIZ:
putchar('=');
- putchar(' ');
- continue;
+ break;
default:
+ putchar(dp->block ? '{' : '[');
+ if (dp->string != NULL)
+ fputs(dp->string, stdout);
+ putchar(dp->block ? '}' : ']');
break;
}
- printf("[\"%s\"", dp->string ? dp->string : "");
if (dp->hspans)
printf(">%d", dp->hspans);
if (dp->vspans)
printf("v%d", dp->vspans);
- if (dp->layout == NULL)
- putchar('*');
- else if (dp->layout->pos == TBL_CELL_DOWN)
- putchar('^');
- putchar(']');
putchar(' ');
}
break;