mandoc: import version 1.14.6

MFC after: 3 weeks
This commit is contained in:
Baptiste Daroussin 2021-11-15 16:54:38 +01:00
commit 6d38604fc5
105 changed files with 5052 additions and 2919 deletions

View File

@ -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

View File

@ -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>

View File

@ -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' \
$< > $@

View File

@ -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

View File

@ -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 ---

View File

@ -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:
@ -32,6 +32,43 @@ Many issues are annotated for difficulty as follows:
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"

View File

@ -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

View File

@ -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",

View File

@ -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");

View File

@ -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

View File

@ -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);

View File

@ -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. */

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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*/

View File

@ -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

View File

@ -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*/

View File

@ -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 */

View File

@ -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

View File

@ -1,16 +1,13 @@
#include "config.h"
/* $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 $ */
#if HAVE_STRINGLIST
int dummy;
#else
/* $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;
}

View File

@ -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);

View File

@ -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;
/* 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(s));
while (*s != '\0') {
if (n != 1) {
*d++ = *s;
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

View File

@ -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

View File

@ -1,15 +1,8 @@
#include "config.h"
/* $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 $ */
#if HAVE_STRNDUP
int dummy;
#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

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -2,10 +2,6 @@
#error "Do not use C++. See the INSTALL file."
#endif
#if !defined(__GNUC__) || (__GNUC__ < 4)
#define __attribute__(x)
#endif
#include <sys/types.h>
#define MAN_CONF_FILE "/etc/man.conf"
@ -13,7 +9,6 @@
#define MANPATH_DEFAULT "/usr/share/man:/usr/local/man"
#define OSENUM MANDOC_OS_OTHER
#define UTF8_LOCALE "en_US.UTF-8"
#define HAVE_CMSG_XPG42 0
#define HAVE_DIRENT_NAMLEN 1
#define HAVE_ENDIAN 0
#define HAVE_ERR 1
@ -24,6 +19,7 @@
#define HAVE_ISBLANK 1
#define HAVE_LESS_T 1
#define HAVE_MKDTEMP 1
#define HAVE_MKSTEMPS 1
#define HAVE_NTOHL 1
#define HAVE_PLEDGE 0
#define HAVE_PROGNAME 1
@ -44,6 +40,7 @@
#define HAVE_VASPRINTF 1
#define HAVE_WCHAR 1
#define HAVE_OHASH 1
#define NEED_XPG4_2 0
#define BINM_APROPOS "apropos"
#define BINM_CATMAN "catman"
@ -51,5 +48,6 @@
#define BINM_MAN "man"
#define BINM_SOELIM "soelim"
#define BINM_WHATIS "whatis"
#define BINM_PAGER "less"
extern void *recallocarray(void *, size_t, size_t, size_t);

View File

@ -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
runtest strtonum STRTONUM "" -D_OPENBSD_SOURCE || true
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
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,64 +389,46 @@ 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"
fi
if [ "${HAVE_NANOSLEEP}" -eq 0 ]; then
echo "FATAL: nanosleep: no" 1>&2
echo "FATAL: nanosleep: no" 1>&3
exit 1
fi
if [ ${BUILD_CATMAN} -gt 0 ]; then
# --- recvmsg ---
if [ -n "${LD_RECVMSG}" ]; then
runtest recvmsg RECVMSG "${LD_RECVMSG}" || true
elif singletest recvmsg RECVMSG; then
:
elif runtest recvmsg RECVMSG "-lsocket"; then
LD_RECVMSG="-lsocket"
fi
if [ "${HAVE_RECVMSG}" -eq 0 ]; then
echo "FATAL: recvmsg: no" 1>&2
echo "FATAL: recvmsg: no" 1>&3
echo "Without recvmsg(2), you cannot BUILD_CATMAN." 1>&2
exit 1
fi
# --- cmsg ---
if singletest cmsg CMSG; then
:
elif runtest cmsg CMSG "-D_XPG4_2"; then
HAVE_CMSG_XPG42=1
fi
if [ "${HAVE_CMSG}" -eq 0 ]; then
echo "FATAL: cmsg: no" 1>&2
echo "FATAL: cmsg: no" 1>&3
echo "Without CMSG_FIRSTHDR(3), you cannot BUILD_CATMAN." 1>&2
exit 1
fi
fi
# --- ohash ---
if ismanual ohash OHASH "${HAVE_OHASH}"; then
:
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 [ "${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
FATAL=1
fi
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 [ ${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"
echo "selected LDADD=\"${LDADD}\"" 1>&2
@ -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}

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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:

View File

@ -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);

View File

@ -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(' ');
}
/*

View File

@ -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_TITLE,
TAG_DIV,
TAG_IDIV,
TAG_SECTION,
TAG_H1,
TAG_H2,
TAG_SPAN,
TAG_LINK,
TAG_BR,
TAG_A,
TAG_STYLE,
TAG_TITLE,
TAG_BODY,
TAG_DIV,
TAG_SECTION,
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 *);

View File

@ -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 *);

File diff suppressed because it is too large Load Diff

View File

@ -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 .
.It Fl m Ar path
Augment the list of standard directories which
.Nm
searches 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
.Fl M
option or the
This option also overrides the environment variable
.Ev MANPATH
environment variable.
and any directories specified in the
.Xr man.conf 5
file.
.It Fl m Ar path
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 those specified using the
.Fl M
option, the
.Ev MANPATH
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

View File

@ -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
reference was written by
macros to groff in 2007.
.Pp
The
.Xr mandoc 1
program and this
.Nm
reference were written by
.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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;
}
}
}

View File

@ -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 */

View File

@ -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;
};

View File

@ -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 ,

View File

@ -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 @@ time2a(time_t t)
}
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. */
/* No date specified: use today's date. */
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

View File

@ -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; }

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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,
.Fn html_make_id
returns
is not
.Dv NULL
instead.
The caller is responsible for freeing the returned string.
and yields a segment identifier when passed to
.Fn html_make_id .
.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 html_make_id
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
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 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,

View File

@ -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

View File

@ -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,

View File

@ -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>

View File

@ -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;

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}
@ -721,6 +689,18 @@ mdoc_xr_pre(MDOC_ARGS)
return 0;
}
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;
}
@ -1037,45 +1020,6 @@ mdoc_cd_pre(MDOC_ARGS)
return 1;
}
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)
{
@ -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,21 +1366,9 @@ 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)
{
@ -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;
@ -1476,21 +1416,9 @@ mdoc_bf_pre(MDOC_ARGS)
return 1;
}
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, ")");

View File

@ -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 */
};

View File

@ -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);

View File

@ -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;
}

View File

@ -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 */
};

View File

@ -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. */
/*
* No vertical space after:
* items in .Bl -column
* items without a body in .Bl -diag
*/
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;
}
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;
size_t rmargin;
pretty = NODE_SYNPRETTY & n->flags;
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,106 +1917,46 @@ 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)
{

View File

@ -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
@ -1089,6 +1100,125 @@ post_st(POST_ARGS)
mdoc->last= n;
}
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)
{
@ -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
@ -1444,23 +1575,82 @@ post_an(POST_ARGS)
nch->line, nch->pos, "An ... %s", nch->string);
}
static void
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_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)
{
@ -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;
}
while (nchild != NULL) {
nnext = nchild->next;
if (nchild->tok == MDOC_It ||
(nchild->tok == MDOC_Sm &&
nnext != NULL && nnext->tok == MDOC_It)) {
nchild = nnext;
continue;
}
/*
* 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.
*/
/*
* 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);
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;
}
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) {
if (nchild->tok == MDOC_It) {
nchild = roff_node_next(nchild);
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;
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;
}
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. */

View File

@ -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,20 +256,8 @@ 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.
@ -263,12 +265,12 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp_first,
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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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>

View File

@ -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. */
};

View File

@ -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;
}

View File

@ -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) {

View File

@ -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)

View File

@ -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;
}
/* Create both temporary output files. */
(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;
}
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;
void
tag_free(void)
{
struct tag_entry *entry;
unsigned int slot;
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);
}
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);
/* Build a new entry. */
if (entry == NULL) {
/* Build a new entry. */
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.
* If a better entry is already present, ignore the new one.
*/
/*
* Lower priority numbers take precedence,
* but 0 is special.
* A tag with priority 0 is only used
* if the tag occurs exactly once.
*/
else if (entry->prio < prio)
return;
if (prio == 0) {
if (entry->prio == 0)
entry->prio = -1;
/*
* 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.
*/
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;
}
/* A better entry is already present, ignore the new one. */
if (entry->prio > 0 && entry->prio < prio)
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.
*/
static void
tag_move_id(struct roff_node *n)
{
struct roff_node *np;
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;
}
}
}
/*
* 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)
{
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';
}
assert(n->tag == NULL);
n->tag = mandoc_strdup(tag);
n->flags |= NODE_HREF;
}
/*
* 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_write(void)
tag_postprocess(struct roff_man *man, struct roff_node *n)
{
FILE *stream;
struct tag_entry *entry;
size_t i;
unsigned int slot;
int empty;
if (tag_files.tfd <= 0)
return;
if (tag_files.tagname != NULL && ohash_find(&tag_data,
ohash_qlookup(&tag_data, tag_files.tagname)) == NULL) {
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;
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;
}
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)
{
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);
}
if (*tag_files.ofn != '\0')
unlink(tag_files.ofn);
if (*tag_files.tfn != '\0')
unlink(tag_files.tfn);
}
static void
tag_signal(int signum)
{
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);
for (n = n->child; n != NULL; n = n->next)
tag_postprocess(man, n);
}

View File

@ -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);

View File

@ -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

View File

@ -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;
};

View File

@ -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') {

View File

@ -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);

View File

@ -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 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
/* 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 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
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 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
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. */
isz = 0;
if (p[*pos] != '\0')
isz++;
if (strchr(" \t.", p[*pos + isz]) == NULL)
isz++;
fontesc = mandoc_font(p + *pos, isz);
if (p[*pos] == '\0' || (p[*pos + 1] != ' ' && p[*pos + 1] != '.')) {
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) {

View File

@ -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);

View File

@ -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;

View File

@ -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');
}

View File

@ -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;
}

View File

@ -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>

227
contrib/mandoc/term_tag.c Normal file
View File

@ -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);
}

Some files were not shown because too many files have changed in this diff Show More