Import mandoc 1.4.5
This commit is contained in:
parent
1f1d4007ae
commit
8f0c701250
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/mandoc/dist/; revision=345685 svn path=/vendor/mandoc/1.14.5/; revision=345686; tag=vendor/mandoc/1.14.5
7
INSTALL
7
INSTALL
@ -1,4 +1,4 @@
|
||||
$Id: INSTALL,v 1.22 2018/07/31 15:34:00 schwarze Exp $
|
||||
$Id: INSTALL,v 1.23 2019/03/06 15:58:10 schwarze Exp $
|
||||
|
||||
About the portable mandoc distribution
|
||||
--------------------------------------
|
||||
@ -18,7 +18,7 @@ tech@ mailing list, too.
|
||||
|
||||
Enjoy using the mandoc toolset!
|
||||
|
||||
Ingo Schwarze, Karlsruhe, August 2018
|
||||
Ingo Schwarze, Karlsruhe, March 2019
|
||||
|
||||
|
||||
Installation
|
||||
@ -67,7 +67,8 @@ 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.
|
||||
first. In particular, regarding Solaris systems, 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
|
||||
|
11
LICENSE
11
LICENSE
@ -1,8 +1,8 @@
|
||||
$Id: LICENSE,v 1.19 2018/07/31 10:18:15 schwarze Exp $
|
||||
$Id: LICENSE,v 1.21 2018/11/26 17:11:11 schwarze Exp $
|
||||
|
||||
With the exceptions noted below, all code and documentation
|
||||
contained in the mandoc toolkit is protected by the Copyright
|
||||
of the following developers:
|
||||
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>
|
||||
@ -12,13 +12,14 @@ Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
|
||||
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) 2008, 2017 Otto Moerbeek <otto@drijf.net>
|
||||
Copyright (c) 2004 Ted Unangst <tedu@openbsd.org>
|
||||
Copyright (c) 1994 Christos Zoulas <christos@netbsd.org>
|
||||
Copyright (c) 2003, 2007, 2008, 2014 Jason McIntyre <jmc@openbsd.org>
|
||||
|
||||
See the individual source files for information about who contributed
|
||||
See the individual files for information about who contributed
|
||||
to which file during which years.
|
||||
|
||||
|
||||
|
60
Makefile
60
Makefile
@ -1,7 +1,7 @@
|
||||
# $Id: Makefile,v 1.519 2018/07/31 15:34:00 schwarze Exp $
|
||||
# $Id: Makefile,v 1.530 2019/03/06 16:08:41 schwarze Exp $
|
||||
#
|
||||
# Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
# Copyright (c) 2011, 2013-2018 Ingo Schwarze <schwarze@openbsd.org>
|
||||
# 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,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.
|
||||
|
||||
VERSION = 1.14.4
|
||||
VERSION = 1.14.5
|
||||
|
||||
# === LIST OF FILES ====================================================
|
||||
|
||||
@ -37,9 +37,9 @@ TESTSRCS = test-be32toh.c \
|
||||
test-PATH_MAX.c \
|
||||
test-pledge.c \
|
||||
test-progname.c \
|
||||
test-recvmsg.c \
|
||||
test-reallocarray.c \
|
||||
test-recallocarray.c \
|
||||
test-recvmsg.c \
|
||||
test-rewb-bsd.c \
|
||||
test-rewb-sysv.c \
|
||||
test-sandbox_init.c \
|
||||
@ -54,7 +54,8 @@ TESTSRCS = test-be32toh.c \
|
||||
test-vasprintf.c \
|
||||
test-wchar.c
|
||||
|
||||
SRCS = att.c \
|
||||
SRCS = arch.c \
|
||||
att.c \
|
||||
catman.c \
|
||||
cgi.c \
|
||||
chars.c \
|
||||
@ -96,6 +97,7 @@ SRCS = att.c \
|
||||
man_validate.c \
|
||||
mandoc.c \
|
||||
mandoc_aux.c \
|
||||
mandoc_msg.c \
|
||||
mandoc_ohash.c \
|
||||
mandoc_xr.c \
|
||||
mandocd.c \
|
||||
@ -155,13 +157,14 @@ DISTFILES = INSTALL \
|
||||
dbm_map.h \
|
||||
demandoc.1 \
|
||||
eqn.7 \
|
||||
eqn.h \
|
||||
eqn_parse.h \
|
||||
gmdiff \
|
||||
html.h \
|
||||
lib.in \
|
||||
libman.h \
|
||||
libmandoc.h \
|
||||
libmdoc.h \
|
||||
libroff.h \
|
||||
main.h \
|
||||
makewhatis.8 \
|
||||
man.1 \
|
||||
@ -184,6 +187,7 @@ DISTFILES = INSTALL \
|
||||
mandoc_html.3 \
|
||||
mandoc_malloc.3 \
|
||||
mandoc_ohash.h \
|
||||
mandoc_parse.h \
|
||||
mandoc_xr.h \
|
||||
mandocd.8 \
|
||||
mansearch.3 \
|
||||
@ -198,10 +202,12 @@ DISTFILES = INSTALL \
|
||||
roff.h \
|
||||
roff_int.h \
|
||||
soelim.1 \
|
||||
st.in \
|
||||
tag.h \
|
||||
tbl.3 \
|
||||
tbl.7 \
|
||||
tbl.h \
|
||||
tbl_int.h \
|
||||
tbl_parse.h \
|
||||
term.h \
|
||||
$(SRCS) \
|
||||
$(TESTSRCS)
|
||||
@ -230,9 +236,11 @@ LIBROFF_OBJS = eqn.o \
|
||||
LIBMANDOC_OBJS = $(LIBMAN_OBJS) \
|
||||
$(LIBMDOC_OBJS) \
|
||||
$(LIBROFF_OBJS) \
|
||||
arch.o \
|
||||
chars.o \
|
||||
mandoc.o \
|
||||
mandoc_aux.o \
|
||||
mandoc_msg.o \
|
||||
mandoc_ohash.o \
|
||||
mandoc_xr.o \
|
||||
msec.o \
|
||||
@ -320,6 +328,7 @@ SOELIM_OBJS = soelim.o \
|
||||
WWW_MANS = apropos.1.html \
|
||||
demandoc.1.html \
|
||||
man.1.html \
|
||||
man.options.1.html \
|
||||
mandoc.1.html \
|
||||
soelim.1.html \
|
||||
man.cgi.3.html \
|
||||
@ -336,20 +345,27 @@ WWW_MANS = apropos.1.html \
|
||||
eqn.7.html \
|
||||
man.7.html \
|
||||
mandoc_char.7.html \
|
||||
mandocd.8.html \
|
||||
mdoc.7.html \
|
||||
roff.7.html \
|
||||
tbl.7.html \
|
||||
catman.8.html \
|
||||
makewhatis.8.html \
|
||||
man.cgi.8.html \
|
||||
mandocd.8.html
|
||||
|
||||
WWW_INCS = eqn.h.html \
|
||||
html.h.html \
|
||||
man.h.html \
|
||||
manconf.h.html \
|
||||
mandoc.h.html \
|
||||
mandoc_aux.h.html \
|
||||
mandoc_parse.h.html \
|
||||
mansearch.h.html \
|
||||
mdoc.h.html \
|
||||
roff.h.html
|
||||
roff.h.html \
|
||||
tbl.h.html \
|
||||
tbl_int.h.html \
|
||||
tbl_parse.h.html
|
||||
|
||||
# === USER CONFIGURATION ===============================================
|
||||
|
||||
@ -361,9 +377,9 @@ all: mandoc demandoc soelim $(BUILD_TARGETS) Makefile.local
|
||||
|
||||
install: base-install $(INSTALL_TARGETS)
|
||||
|
||||
www: $(WWW_MANS)
|
||||
www: $(WWW_MANS) $(WWW_INCS)
|
||||
|
||||
$(WWW_MANS): mandoc
|
||||
$(WWW_MANS) $(WWW_INCS): mandoc
|
||||
|
||||
.PHONY: base-install cgi-install install www-install
|
||||
.PHONY: clean distclean depend
|
||||
@ -382,7 +398,7 @@ clean:
|
||||
rm -f mandocd catman catman.o $(MANDOCD_OBJS)
|
||||
rm -f demandoc $(DEMANDOC_OBJS)
|
||||
rm -f soelim $(SOELIM_OBJS)
|
||||
rm -f $(WWW_MANS) mandoc.tar.gz mandoc.sha256
|
||||
rm -f $(WWW_MANS) $(WWW_INCS) mandoc*.tar.gz mandoc*.sha256
|
||||
rm -rf *.dSYM
|
||||
|
||||
base-install: mandoc demandoc soelim
|
||||
@ -420,8 +436,8 @@ lib-install: libmandoc.a
|
||||
mkdir -p $(DESTDIR)$(INCLUDEDIR)
|
||||
mkdir -p $(DESTDIR)$(MANDIR)/man3
|
||||
$(INSTALL_LIB) libmandoc.a $(DESTDIR)$(LIBDIR)
|
||||
$(INSTALL_LIB) man.h mandoc.h mandoc_aux.h mdoc.h roff.h \
|
||||
$(DESTDIR)$(INCLUDEDIR)
|
||||
$(INSTALL_LIB) eqn.h man.h mandoc.h mandoc_aux.h mandoc_parse.h \
|
||||
mdoc.h roff.h tbl.h $(DESTDIR)$(INCLUDEDIR)
|
||||
$(INSTALL_MAN) mandoc.3 mandoc_escape.3 mandoc_malloc.3 \
|
||||
mansearch.3 mchars_alloc.3 tbl.3 $(DESTDIR)$(MANDIR)/man3
|
||||
|
||||
@ -475,11 +491,14 @@ uninstall:
|
||||
rm -f $(DESTDIR)$(MANDIR)/man3/mansearch.3
|
||||
rm -f $(DESTDIR)$(MANDIR)/man3/mchars_alloc.3
|
||||
rm -f $(DESTDIR)$(MANDIR)/man3/tbl.3
|
||||
rm -f $(DESTDIR)$(INCLUDEDIR)/eqn.h
|
||||
rm -f $(DESTDIR)$(INCLUDEDIR)/man.h
|
||||
rm -f $(DESTDIR)$(INCLUDEDIR)/mandoc.h
|
||||
rm -f $(DESTDIR)$(INCLUDEDIR)/mandoc_aux.h
|
||||
rm -f $(DESTDIR)$(INCLUDEDIR)/mandoc_parse.h
|
||||
rm -f $(DESTDIR)$(INCLUDEDIR)/mdoc.h
|
||||
rm -f $(DESTDIR)$(INCLUDEDIR)/roff.h
|
||||
rm -f $(DESTDIR)$(INCLUDEDIR)/tbl.h
|
||||
[ ! -e $(DESTDIR)$(INCLUDEDIR) ] || rmdir $(DESTDIR)$(INCLUDEDIR)
|
||||
|
||||
regress: all
|
||||
@ -516,7 +535,9 @@ soelim: $(SOELIM_OBJS)
|
||||
# --- maintainer targets ---
|
||||
|
||||
www-install: www
|
||||
$(INSTALL_DATA) $(WWW_MANS) mandoc.css $(HTDOCDIR)
|
||||
$(INSTALL_DATA) mandoc.css $(HTDOCDIR)
|
||||
$(INSTALL_DATA) $(WWW_MANS) $(HTDOCDIR)/man
|
||||
$(INSTALL_DATA) $(WWW_INCS) $(HTDOCDIR)/includes
|
||||
|
||||
depend: config.h
|
||||
mkdep -f Makefile.depend $(CFLAGS) $(SRCS)
|
||||
@ -564,6 +585,10 @@ mandoc-$(VERSION).tar.gz: $(DISTFILES)
|
||||
( cd .dist/ && tar zcf ../$@ mandoc-$(VERSION) )
|
||||
rm -rf .dist/
|
||||
|
||||
dist-install: dist
|
||||
$(INSTALL_DATA) mandoc-$(VERSION).tar.gz mandoc-$(VERSION).sha256 \
|
||||
$(HTDOCDIR)/snapshots
|
||||
|
||||
# === SUFFIX RULES =====================================================
|
||||
|
||||
.SUFFIXES: .1 .3 .5 .7 .8 .h
|
||||
@ -573,5 +598,6 @@ mandoc-$(VERSION).tar.gz: $(DISTFILES)
|
||||
highlight -I $< > $@
|
||||
|
||||
.1.1.html .3.3.html .5.5.html .7.7.html .8.8.html: mandoc
|
||||
./mandoc -Thtml -Wall,stop \
|
||||
-Ostyle=mandoc.css,man=%N.%S.html,includes=%I.html $< > $@
|
||||
mandoc -Thtml -Wwarning,stop \
|
||||
-O 'style=/mandoc.css,man=/man/%N.%S.html;https://man.openbsd.org/%N.%S,includes=/includes/%I.html' \
|
||||
$< > $@
|
||||
|
@ -1,6 +1,7 @@
|
||||
att.o: att.c config.h mandoc.h roff.h mdoc.h libmdoc.h
|
||||
arch.o: arch.c config.h roff.h
|
||||
att.o: att.c config.h roff.h libmdoc.h
|
||||
catman.o: catman.c config.h compat_fts.h
|
||||
cgi.o: cgi.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h main.h manconf.h mansearch.h cgi.h
|
||||
cgi.o: cgi.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h main.h manconf.h mansearch.h cgi.h
|
||||
chars.o: chars.c config.h mandoc.h mandoc_aux.h mandoc_ohash.h compat_ohash.h libmandoc.h
|
||||
compat_err.o: compat_err.c config.h
|
||||
compat_fts.o: compat_fts.c config.h compat_fts.h
|
||||
@ -26,54 +27,55 @@ dba_read.o: dba_read.c 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
|
||||
demandoc.o: demandoc.c config.h mandoc.h roff.h man.h mdoc.h
|
||||
eqn.o: eqn.c config.h mandoc_aux.h mandoc.h roff.h libmandoc.h libroff.h
|
||||
eqn_html.o: eqn_html.c config.h mandoc.h out.h html.h
|
||||
eqn_term.o: eqn_term.c config.h mandoc.h out.h term.h
|
||||
demandoc.o: demandoc.c config.h mandoc.h roff.h man.h mdoc.h mandoc_parse.h
|
||||
eqn.o: eqn.c config.h mandoc_aux.h mandoc.h roff.h eqn.h libmandoc.h eqn_parse.h
|
||||
eqn_html.o: eqn_html.c config.h mandoc.h eqn.h out.h html.h
|
||||
eqn_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 mandoc.h roff.h mdoc.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 tag.h main.h manconf.h mansearch.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
|
||||
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 main.h
|
||||
man_term.o: man_term.c config.h mandoc_aux.h roff.h man.h out.h term.h main.h
|
||||
man_validate.o: man_validate.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h
|
||||
mandoc.o: mandoc.c config.h mandoc_aux.h mandoc.h roff.h libmandoc.h
|
||||
mandoc.o: mandoc.c config.h mandoc_aux.h mandoc.h roff.h libmandoc.h roff_int.h
|
||||
mandoc_aux.o: mandoc_aux.c config.h mandoc.h mandoc_aux.h
|
||||
mandoc_msg.o: mandoc_msg.c mandoc.h
|
||||
mandoc_ohash.o: mandoc_ohash.c mandoc_aux.h mandoc_ohash.h compat_ohash.h
|
||||
mandoc_xr.o: mandoc_xr.c mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc_xr.h
|
||||
mandocd.o: mandocd.c config.h mandoc.h roff.h mdoc.h man.h main.h manconf.h
|
||||
mandocdb.o: mandocdb.c config.h compat_fts.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h mdoc.h man.h manconf.h mansearch.h dba_array.h dba.h
|
||||
mandocd.o: mandocd.c config.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h main.h manconf.h
|
||||
mandocdb.o: mandocdb.c config.h compat_fts.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h manconf.h mansearch.h dba_array.h dba.h
|
||||
manpath.o: manpath.c config.h mandoc_aux.h manconf.h
|
||||
mansearch.o: mansearch.c config.h mandoc.h mandoc_aux.h mandoc_ohash.h compat_ohash.h manconf.h mansearch.h dbm.h
|
||||
mansearch.o: mansearch.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h manconf.h mansearch.h dbm.h
|
||||
mdoc.o: mdoc.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h
|
||||
mdoc_argv.o: mdoc_argv.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h
|
||||
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 libmdoc.h
|
||||
mdoc_term.o: mdoc_term.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h out.h term.h tag.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
|
||||
msec.o: msec.c config.h mandoc.h libmandoc.h msec.in
|
||||
out.o: out.c config.h mandoc_aux.h mandoc.h out.h
|
||||
preconv.o: preconv.c config.h mandoc.h libmandoc.h
|
||||
read.o: read.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h libmandoc.h
|
||||
roff.o: roff.c config.h mandoc.h mandoc_aux.h mandoc_ohash.h compat_ohash.h roff.h libmandoc.h roff_int.h libroff.h predefs.in
|
||||
out.o: out.c config.h mandoc_aux.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
|
||||
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
|
||||
soelim.o: soelim.c config.h compat_stringlist.h
|
||||
st.o: st.c config.h mandoc.h roff.h mdoc.h libmdoc.h st.in
|
||||
st.o: st.c config.h mandoc.h roff.h libmdoc.h
|
||||
tag.o: tag.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h tag.h
|
||||
tbl.o: tbl.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h
|
||||
tbl_data.o: tbl_data.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h
|
||||
tbl_html.o: tbl_html.c config.h mandoc.h out.h html.h
|
||||
tbl_layout.o: tbl_layout.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h
|
||||
tbl_opts.o: tbl_opts.c config.h mandoc.h libmandoc.h libroff.h
|
||||
tbl_term.o: tbl_term.c config.h mandoc.h out.h term.h
|
||||
tbl.o: tbl.c config.h mandoc_aux.h mandoc.h tbl.h libmandoc.h tbl_parse.h tbl_int.h
|
||||
tbl_data.o: tbl_data.c config.h mandoc_aux.h mandoc.h tbl.h libmandoc.h tbl_int.h
|
||||
tbl_html.o: tbl_html.c config.h mandoc.h tbl.h out.h html.h
|
||||
tbl_layout.o: tbl_layout.c config.h mandoc_aux.h mandoc.h tbl.h libmandoc.h tbl_int.h
|
||||
tbl_opts.o: tbl_opts.c config.h mandoc.h tbl.h libmandoc.h tbl_int.h
|
||||
tbl_term.o: tbl_term.c config.h mandoc.h tbl.h out.h term.h
|
||||
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
|
||||
tree.o: tree.c config.h mandoc.h roff.h mdoc.h man.h main.h
|
||||
tree.o: tree.c config.h mandoc.h roff.h mdoc.h man.h tbl.h eqn.h main.h
|
||||
|
76
NEWS
76
NEWS
@ -1,7 +1,81 @@
|
||||
$Id: NEWS,v 1.32 2018/08/08 14:47:38 schwarze Exp $
|
||||
$Id: NEWS,v 1.34 2019/03/10 09:32:00 schwarze Exp $
|
||||
|
||||
This file lists the most important changes in the mandoc.bsd.lv distribution.
|
||||
|
||||
Changes in version 1.14.5, released on March 10, 2019
|
||||
|
||||
--- MAJOR NEW FEATURES ---
|
||||
* apropos(1): improve POSIX compliance by accepting case-insensitive
|
||||
extended regular expressions by default
|
||||
* new -O tag[=term] output option (open a page at the definition of a term)
|
||||
* tbl(7) -T html: spanning and horizontal and vertical alignment of cells
|
||||
* tbl(7) -T html: draw lines on the edges of table cells
|
||||
* tbl(7) -T utf8: render lines with the Unicode box drawing characters
|
||||
* mandoc is now able to handle the manual pages of the groff package.
|
||||
--- MINOR NEW FEATURES ---
|
||||
* -T html: new option -O toc (table of contents)
|
||||
* -T html: second argument to -O man to support local and remote links
|
||||
* mdoc(7) .Bd -centered now fills the text contained in it
|
||||
* man-ext .SY and .YS macros (synopsis block)
|
||||
* man-ext .TQ macro (tagged paragraph without vertical space before it)
|
||||
* tbl(7) \& explicit alignment indicator
|
||||
* roff(7) .shift, .while, and .return requests
|
||||
* roff(7) .char request (output glyph definition)
|
||||
* roff(7) .nop request (no operation)
|
||||
* roff(7) .ft request: handle the CB, CI, and CR fonts
|
||||
* roff(7) .if c conditional (character available)
|
||||
* roff(7) \\$@ escape sequence (insert all macro arguments, quoted)
|
||||
* roff(7) \*(.T predefined string (interpolate output device name)
|
||||
* roff(7) \[charNNN] escape sequence (for printable ASCII characters)
|
||||
* roff(7) \# escape sequence (line continuation with comment)
|
||||
--- HTML OUTPUT SYNTAX CORRECTIONS ---
|
||||
* Render .br and \p as <br/>, not as an empty <div>.
|
||||
* Render .Pp and .PP as <p> and automatically close it when needed.
|
||||
* Stop writing empty list elements for non-compact .Bl -tag lists.
|
||||
* Do not put <p> inside <a> if .UR or .MT contain .PP.
|
||||
* Implement tooltips purely in CSS rather than abusing title= attributes.
|
||||
--- MINOR FUNCTIONAL IMPROVEMENTS ---
|
||||
* many improvements to the handling of fill and no-fill mode
|
||||
* tbl(7): better column widths in the presence of horizontal spans
|
||||
* several minor improvements to escape sequence handling
|
||||
* several minor improvements to manual font handling
|
||||
* portability: autodetect need for _GNU_SOURCE or _OPENBSD_SOURCE
|
||||
* portability: autodetect whether less(1) supports the -T option
|
||||
* large numbers of bugfixes of diverse kinds
|
||||
--- STRUCTURAL IMPROVEMENTS ---
|
||||
* Disentangle eqn(7) and tbl(7) from other parser header files,
|
||||
and clean up some parser data structures.
|
||||
* Substantially simplify error and warning message infrastructure.
|
||||
--- THANKS TO ---
|
||||
* John Gardner for crucial help implementing tooltips in CSS.
|
||||
* Alexander Bluhm, Raphael Graf, Ted Unangst (OpenBSD)
|
||||
and Daniel Sabogal (Alpine Linux) for patches.
|
||||
* Anthony Bentley and Jason McIntyre (OpenBSD) for documentation patches,
|
||||
suggesting new features, bug reports, and useful discussions.
|
||||
* Kyle Evans and Baptiste Daroussin (FreeBSD) for minor patches.
|
||||
* Pali Rohar for suggesting multiple new features and for reporting
|
||||
several bugs and missing features.
|
||||
* Klemens Nanni (OpenBSD) for suggesting multiple new features.
|
||||
* Kristaps Dzonsons (bsd.lv), Marc Espie (OpenBSD), Adam Kalisz,
|
||||
and Laura Morales for suggesting new features.
|
||||
* Wolfram Schneider and Yuri Pankov (FreeBSD) for reporting missing features.
|
||||
* Edward Tomasz Napierala (FreeBSD) for suggesting a feature improvement.
|
||||
* Thomas Klausner (NetBSD) and Sevan Janiyan (SmartOS)
|
||||
for bug reports and release testing.
|
||||
* Bryan Steele, Janne Johansson, Kurt Mosiejczuk, Mike Belopuhov, Theo
|
||||
Buehler, Todd Miller (OpenBSD), Andreas Gustafsson, Christos Zoulas,
|
||||
Robert Elz (NetBSD), Kurt Jaeger (FreeBSD), Fabio Scotoni, Kelvin
|
||||
Sherlock, Mark Harris, Orestis Ioannou, Raf Czlonka, and Sean Farrell
|
||||
for bug reports.
|
||||
* Ulrich Spoerlein (FreeBSD), Leah Neukirchen (Void Linux),
|
||||
Matej Cepl (openSUSE), and Jan Stary (MacOS X) for release testing.
|
||||
* Brian Callahan and Stuart Henderson (OpenBSD) for help
|
||||
with the OpenBSD groff port.
|
||||
* Bertrand Garrigues, Branden Robinson, Ralph Corderoy, and Werner
|
||||
Lemberg (GNU troff) for checking groff patches.
|
||||
* Scott Cheloha, Theo de Raadt (OpenBSD)
|
||||
and Natanael Copa (Alpine Linux) for useful discussions.
|
||||
|
||||
Changes in version 1.14.4, released on August 8, 2018
|
||||
|
||||
--- MAJOR NEW FEATURES ---
|
||||
|
124
TODO
124
TODO
@ -1,6 +1,6 @@
|
||||
************************************************************************
|
||||
* Official mandoc TODO.
|
||||
* $Id: TODO,v 1.258 2018/08/06 14:16:30 schwarze Exp $
|
||||
* $Id: TODO,v 1.289 2019/03/04 13:01:57 schwarze Exp $
|
||||
************************************************************************
|
||||
|
||||
Many issues are annotated for difficulty as follows:
|
||||
@ -38,18 +38,6 @@ are mere guesses, and some may be wrong.
|
||||
|
||||
--- missing roff features ----------------------------------------------
|
||||
|
||||
- .nop prints its arguments as text,
|
||||
see groff(7) for an example
|
||||
|
||||
- .ft CB selects constant-width bold font
|
||||
see groff_out(7) for examples
|
||||
|
||||
- \*(.T prints the device being used,
|
||||
see groff_char(7) for an example
|
||||
|
||||
- \[charNN], \[charNNN] prints a single-byte codepoint
|
||||
see groff_char(7) for examples
|
||||
|
||||
- .ad (adjust margins)
|
||||
.ad l -- adjust left margin only (flush left)
|
||||
.ad r -- adjust right margin only (flush right)
|
||||
@ -69,34 +57,11 @@ are mere guesses, and some may be wrong.
|
||||
reported by brad@ Sat, 15 Jan 2011 15:45:23 -0500
|
||||
loc *** exist *** algo *** size ** imp *
|
||||
|
||||
- .while and .shift
|
||||
found by jca@ in ratpoison(1) Sun, 30 Jun 2013 12:01:09 +0200
|
||||
loc * exist ** algo ** size ** imp **
|
||||
|
||||
- \w'' improve width measurements
|
||||
would not be very useful without an expression parser, see below
|
||||
needed for Tcl_NewStringObj(3) via wiz@ Wed, 5 Mar 2014 22:27:43 +0100
|
||||
loc ** exist *** algo *** size * imp ***
|
||||
|
||||
- \\ in high-level macro arguments
|
||||
Currently, \\ is expanded in two situations:
|
||||
1) macro and string definition (roff.c setstrn())
|
||||
2) macro argument parsing (mandoc.c mandoc_getarg())
|
||||
For user defined macros, the second happens in time because of ROFF_REPARSE.
|
||||
But for standard high-level macros, it only happens after entering the
|
||||
high level parsers, which is too late because the code doesn't get
|
||||
back to roff.c roff_res() from that point. Because this requires
|
||||
distinguishing requests, user-defined macros and standard macros
|
||||
on the roff_res() level, it is hard to solve without the parser reorg.
|
||||
Found by naddy@ in devel/cutils cobfusc(1) Mon, 16 Feb 2015 19:10:52 +0100
|
||||
loc *** exist *** algo *** size ** imp *
|
||||
|
||||
- check for missing roff escape sequences, implement those that are
|
||||
trivial even if not usually appearing in manual pages, gracefully
|
||||
ignore the non-trivial ones, document what they are supposed to do
|
||||
and what mandoc does instead
|
||||
loc * exist ** algo * size * imp *
|
||||
|
||||
--- missing mdoc features ----------------------------------------------
|
||||
|
||||
- .Bl -column .Xo support is missing
|
||||
@ -112,13 +77,6 @@ are mere guesses, and some may be wrong.
|
||||
from jmc@ Wed, 14 Jul 2010 18:10:32 +0100
|
||||
loc * exist *** algo *** size ** imp **
|
||||
|
||||
- .Bd -centered implies -filled, not -unfilled, which is not
|
||||
easy to implement; it requires code similar to .ce, which
|
||||
we don't have either.
|
||||
Besides, groff has bug causing text right *before* .Bd -centered
|
||||
to be centered as well.
|
||||
loc *** exist *** algo ** size ** imp ** (parser reorg would help)
|
||||
|
||||
- .Bd -filled should not be the same as .Bd -ragged, but align both
|
||||
the left and right margin. In groff, it is implemented in terms
|
||||
of .ad b, which we don't have either. Found in cksum(1).
|
||||
@ -174,15 +132,6 @@ are mere guesses, and some may be wrong.
|
||||
|
||||
--- missing man features -----------------------------------------------
|
||||
|
||||
- .SY and .YS,
|
||||
used by many groff manual pages
|
||||
|
||||
- preserve punctuation following .ME,
|
||||
see ditroff(7) for an example
|
||||
|
||||
- .TQ tagged paragraph continuation,
|
||||
see groff_diff(7) for examples
|
||||
|
||||
- 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.
|
||||
@ -193,18 +142,10 @@ are mere guesses, and some may be wrong.
|
||||
|
||||
--- missing tbl features -----------------------------------------------
|
||||
|
||||
- the "s" layout column specifier is used for placement of data
|
||||
into columns, but ignored during column width calculations
|
||||
synaptics(4) found by tedu@ Mon, 17 Aug 2015 21:17:42 -0400
|
||||
loc * exist ** algo *** size * imp **
|
||||
|
||||
- vertical centering in cells vertically spanned with ^
|
||||
pali dot rohar at gmail dot com 16 Jul 2018 13:03:35 +0200
|
||||
loc * exist *** algo *** size ** imp *
|
||||
|
||||
- support .ds requests inside tbl(7) code,
|
||||
see tbl(1) for an example
|
||||
|
||||
- support mdoc(7) and man(7) macros inside tbl(7) code;
|
||||
probably requires the parser reorg and letting tbl(7)
|
||||
use roff_node such that macro sets can mix;
|
||||
@ -212,35 +153,24 @@ are mere guesses, and some may be wrong.
|
||||
loc *** exist ** algo *** size ** imp ***
|
||||
|
||||
- look at the POSIX manuals in the books/man-pages-posix port,
|
||||
they use some unsupported tbl(7) features.
|
||||
they use some unsupported tbl(7) features, mostly macros in tbl(7).
|
||||
loc * exist ** algo ** size ** imp ***
|
||||
|
||||
- look what Joerg Schilling manual pages use
|
||||
Thu, 19 Mar 2015 18:31:48 +0100
|
||||
|
||||
- use Unicode U+2500 to U+256C for table borders
|
||||
in tbl(7) -Tutf-8 output
|
||||
suggested by bentley@ Tue, 14 Oct 2014 04:10:55 -0600
|
||||
loc * exist ** algo * size * imp **
|
||||
|
||||
- implement horizontal and vertical alignment in HTML output
|
||||
pali dot rohar at gmail dot com 16 Jul 2018 13:03:35 +0200
|
||||
loc * exist * algo * size * imp ***
|
||||
|
||||
- implement cell spanning in HTML output
|
||||
pali dot rohar at gmail dot com 16 Jul 2018 13:03:35 +0200
|
||||
loc * exist * algo ** size ** imp **
|
||||
|
||||
- implement table borders in HTML output
|
||||
pali dot rohar at gmail dot com 16 Jul 2018 13:03:35 +0200
|
||||
loc * exist * algo ** size ** imp **
|
||||
|
||||
--- missing eqn features -----------------------------------------------
|
||||
|
||||
- In a matrix, break the output line after each matrix line.
|
||||
Found in the discussion at CDBUG 2015.
|
||||
Suggested by Avi Weinstock.
|
||||
loc * exist * algo * size * imp **
|
||||
Found in the discussion at CDBUG 2015. Suggested by Avi Weinstock.
|
||||
This may not be the ideal solution after all: eqn(7) matrices
|
||||
are lists of columns, so Avi's proposal would show each *column*
|
||||
on its own *line*, which is likely to cause confusion.
|
||||
A better solution, but much harder to implement, would be to
|
||||
actually show the coordinates of column vectors on different
|
||||
terminal output lines, using the clumnated output facilities
|
||||
developed for .Bl -tag, .Bl -column, and also used for tbl(7).
|
||||
loc * exist * algo ** size ** imp **
|
||||
|
||||
- The "size" keyword is parsed, but ignored by the formatter.
|
||||
loc * exist * algo * size * imp *
|
||||
@ -341,9 +271,6 @@ are mere guesses, and some may be wrong.
|
||||
* formatting issues: ugly output
|
||||
************************************************************************
|
||||
|
||||
- .UR can nest inside .TP,
|
||||
see roff(7) for examples
|
||||
|
||||
- revisit empty in-line macros
|
||||
look at the difference between "Em x Em ." and "Sq x Em ."
|
||||
Carsten Kunze Fri, 12 Dec 2014 00:15:41 +0100
|
||||
@ -400,6 +327,8 @@ are mere guesses, and some may be wrong.
|
||||
|
||||
- a line starting with "\fB something" counts as starting with whitespace
|
||||
and triggers a line break; found in audio/normalize-mp3(1)
|
||||
This will become easier once escape sequences are represented
|
||||
by syntax tree nodes.
|
||||
loc ** exist * algo ** size * imp **
|
||||
|
||||
- formatting /usr/local/man/man1/latex2man.1 with groff and mandoc
|
||||
@ -421,17 +350,6 @@ are mere guesses, and some may be wrong.
|
||||
|
||||
--- HTML issues --------------------------------------------------------
|
||||
|
||||
- wrap Sh and Ss content into <div>
|
||||
Laura Morales <lauretas at mail dot com> 21 Apr 2018 18:10:48 +0200
|
||||
(Evaluate whether this is really useful and has no adverse
|
||||
side effects before implementing; if it is possible,
|
||||
it does seem cleaner.)
|
||||
loc ** exist ** algo * size * imp ***
|
||||
|
||||
- format ".IP *" etc. as <ul> rather than <dl>
|
||||
https://github.com/Debian/debiman/issues/67
|
||||
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
|
||||
@ -558,18 +476,11 @@ are mere guesses, and some may be wrong.
|
||||
all over mdoc_macro.c and all subtly different.
|
||||
loc ** exist ** algo ** size ** imp **
|
||||
|
||||
- style message about suspicious uses of - vs. \- vs. \(mi
|
||||
e.g. -1 is likely wrong (from the mdoclint TODO)
|
||||
|
||||
- warn about punctuation - e.g. ',' and ';' - at the beginning
|
||||
of a text line, if it is likely intended to follow the preceding
|
||||
output without intervening whitespace, in particular after a
|
||||
macro line (from the mdoclint TODO)
|
||||
|
||||
- mandoc_special does not really check the escape sequence,
|
||||
but just the overall format
|
||||
loc ** exist ** algo *** size ** imp **
|
||||
|
||||
- makewhatis -p complains about language subdirectories:
|
||||
/usr/local/man//ru: Unknown directory part
|
||||
|
||||
@ -578,9 +489,6 @@ are mere guesses, and some may be wrong.
|
||||
* documentation issues
|
||||
************************************************************************
|
||||
|
||||
- dashes, hyphens, and minus signs in manual pages
|
||||
jmc@ Fri, 28 Mar 2014 07:19:27 +0000
|
||||
|
||||
- mark macros as: page structure domain, manual domain, general text domain
|
||||
is this useful?
|
||||
|
||||
@ -606,10 +514,6 @@ are mere guesses, and some may be wrong.
|
||||
Found by Aaron M. Ucko in the GNU Hurd via Bdale Garbee,
|
||||
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=829624
|
||||
|
||||
- We use the input line number at several places to distinguish
|
||||
same-line from different-line input. That plainly doesn't work
|
||||
with user-defined macros, leading to random breakage.
|
||||
|
||||
- Is it possible to further simplify ENDBODY_SPACE?
|
||||
|
||||
- Find better ways to prevent endless loops
|
||||
@ -629,8 +533,6 @@ are mere guesses, and some may be wrong.
|
||||
output through libz.
|
||||
- Privilege separation (see OpenSSH).
|
||||
- Enable caching support via HTTP 304 and If-Modified-Since.
|
||||
- Have Mac OSX systems automatically disable -static compilation of the
|
||||
CGI: -static isn't supported.
|
||||
|
||||
************************************************************************
|
||||
* to improve in the groff_mdoc(7) macros
|
||||
|
61
apropos.1
61
apropos.1
@ -1,7 +1,7 @@
|
||||
.\" $Id: apropos.1,v 1.47 2018/02/23 18:54:02 schwarze Exp $
|
||||
.\" $Id: apropos.1,v 1.49 2018/11/22 12:33:52 schwarze Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
.\" Copyright (c) 2011, 2012, 2014, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
.\" Copyright (c) 2011,2012,2014,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
|
||||
@ -15,7 +15,7 @@
|
||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd $Mdocdate: February 23 2018 $
|
||||
.Dd $Mdocdate: November 22 2018 $
|
||||
.Dt APROPOS 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -51,8 +51,7 @@ searches for
|
||||
.Xr makewhatis 8
|
||||
databases in the default paths stipulated by
|
||||
.Xr man 1
|
||||
and uses case-insensitive substring matching
|
||||
.Pq the Cm = No operator
|
||||
and uses case-insensitive extended regular expression matching
|
||||
over manual names and descriptions
|
||||
.Pq the Li \&Nm No and Li \&Nd No macro keys .
|
||||
Multiple terms imply pairwise
|
||||
@ -93,7 +92,7 @@ format.
|
||||
Search for all words in
|
||||
.Ar expression
|
||||
in manual page names only.
|
||||
The search is case insensitive and matches whole words only.
|
||||
The search is case-insensitive and matches whole words only.
|
||||
In this mode, macro keys, comparison operators, and logical operators
|
||||
are not available.
|
||||
.It Fl k
|
||||
@ -123,7 +122,7 @@ Restrict the search to pages for the specified
|
||||
.Xr machine 1
|
||||
architecture.
|
||||
.Ar arch
|
||||
is case insensitive.
|
||||
is case-insensitive.
|
||||
By default, pages for all architectures are shown.
|
||||
.It Fl s Ar section
|
||||
Restrict the search to the specified section of the manual.
|
||||
@ -199,7 +198,7 @@ Operator
|
||||
.Cm =
|
||||
evaluates a substring, while
|
||||
.Cm \(ti
|
||||
evaluates a regular expression.
|
||||
evaluates a case-sensitive extended regular expression.
|
||||
.It Fl i Ar term
|
||||
If
|
||||
.Ar term
|
||||
@ -208,26 +207,10 @@ is evaluated case-insensitively.
|
||||
Has no effect on substring terms.
|
||||
.El
|
||||
.Pp
|
||||
Results are sorted according to the following criteria:
|
||||
.Bl -enum
|
||||
.It
|
||||
The manpath directory tree the page is found in, according to the
|
||||
order specified with
|
||||
.Fl M ,
|
||||
.Fl m ,
|
||||
the
|
||||
.Ev MANPATH
|
||||
environment variable, the
|
||||
.Xr man.conf 5
|
||||
configuration file, or the default documented in
|
||||
.Xr man.conf 5 .
|
||||
.It
|
||||
The section number in ascending numerical order.
|
||||
.It
|
||||
The page name in ascending
|
||||
Results are sorted first according to the section number in ascending
|
||||
numerical order, then by the page name in ascending
|
||||
.Xr ascii 7
|
||||
alphabetical order, case-insensitive.
|
||||
.El
|
||||
.Pp
|
||||
Each output line is formatted as
|
||||
.Pp
|
||||
@ -339,7 +322,7 @@ function arguments appearing on
|
||||
.Ic \&Fn
|
||||
lines
|
||||
.It Li \&Fn
|
||||
fuction names marked up with
|
||||
function names marked up with
|
||||
.Ic \&Fo
|
||||
macros
|
||||
.It Li \&In
|
||||
@ -407,7 +390,7 @@ Search for
|
||||
.Qq .cf
|
||||
as a substring of manual names and descriptions:
|
||||
.Pp
|
||||
.Dl $ apropos .cf
|
||||
.Dl $ apropos =.cf
|
||||
.Pp
|
||||
Include matches for
|
||||
.Qq .cnf
|
||||
@ -415,9 +398,9 @@ and
|
||||
.Qq .conf
|
||||
as well:
|
||||
.Pp
|
||||
.Dl $ apropos .cf .cnf .conf
|
||||
.Dl $ apropos =.cf =.cnf =.conf
|
||||
.Pp
|
||||
Search in names and descriptions using a regular expression:
|
||||
Search in names and descriptions using a case-sensitive regular expression:
|
||||
.Pp
|
||||
.Dl $ apropos \(aq\(tiset.?[ug]id\(aq
|
||||
.Pp
|
||||
@ -448,6 +431,24 @@ The following two invocations are equivalent:
|
||||
.Xr man 1 ,
|
||||
.Xr re_format 7 ,
|
||||
.Xr makewhatis 8
|
||||
.Sh STANDARDS
|
||||
The
|
||||
.Nm
|
||||
utility is compliant with the
|
||||
.St -p1003.1-2008
|
||||
specification of
|
||||
.Xr man 1
|
||||
.Fl k .
|
||||
.Pp
|
||||
All options, the
|
||||
.Nm whatis
|
||||
command, support for logical operators, macro keys,
|
||||
substring matching, sorting of results, the environment variables
|
||||
.Ev MANPAGER
|
||||
and
|
||||
.Ev MANPATH ,
|
||||
the database format, and the configuration file
|
||||
are extensions to that specification.
|
||||
.Sh HISTORY
|
||||
Part of the functionality of
|
||||
.Nm whatis
|
||||
|
54
arch.c
Normal file
54
arch.c
Normal file
@ -0,0 +1,54 @@
|
||||
/* $Id: arch.c,v 1.14 2019/03/04 13:01:57 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "roff.h"
|
||||
|
||||
int
|
||||
arch_valid(const char *arch, enum mandoc_os os)
|
||||
{
|
||||
const char *openbsd_arch[] = {
|
||||
"alpha", "amd64", "arm64", "armv7", "hppa", "i386",
|
||||
"landisk", "loongson", "luna88k", "macppc", "mips64",
|
||||
"octeon", "sgi", "socppc", "sparc64", NULL
|
||||
};
|
||||
const char *netbsd_arch[] = {
|
||||
"acorn26", "acorn32", "algor", "alpha", "amiga",
|
||||
"arc", "atari",
|
||||
"bebox", "cats", "cesfic", "cobalt", "dreamcast",
|
||||
"emips", "evbarm", "evbmips", "evbppc", "evbsh3", "evbsh5",
|
||||
"hp300", "hpcarm", "hpcmips", "hpcsh", "hppa",
|
||||
"i386", "ibmnws", "luna68k",
|
||||
"mac68k", "macppc", "mipsco", "mmeye", "mvme68k", "mvmeppc",
|
||||
"netwinder", "news68k", "newsmips", "next68k",
|
||||
"pc532", "playstation2", "pmax", "pmppc", "prep",
|
||||
"sandpoint", "sbmips", "sgimips", "shark",
|
||||
"sparc", "sparc64", "sun2", "sun3",
|
||||
"vax", "walnut", "x68k", "x86", "x86_64", "xen", NULL
|
||||
};
|
||||
const char **arches[] = { NULL, netbsd_arch, openbsd_arch };
|
||||
const char **arch_p;
|
||||
|
||||
if ((arch_p = arches[os]) == NULL)
|
||||
return 1;
|
||||
for (; *arch_p != NULL; arch_p++)
|
||||
if (strcmp(*arch_p, arch) == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
4
att.c
4
att.c
@ -1,4 +1,4 @@
|
||||
/* $Id: att.c,v 1.16 2017/06/24 14:38:32 schwarze Exp $ */
|
||||
/* $Id: att.c,v 1.18 2018/12/13 11:55:46 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
*
|
||||
@ -19,9 +19,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "roff.h"
|
||||
#include "mdoc.h"
|
||||
#include "libmdoc.h"
|
||||
|
||||
#define LINE(x, y) \
|
||||
|
156
cgi.c
156
cgi.c
@ -1,7 +1,7 @@
|
||||
/* $Id: cgi.c,v 1.158 2018/05/29 20:32:45 schwarze Exp $ */
|
||||
/* $Id: cgi.c,v 1.166 2019/03/06 12:32:41 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@usta.de>
|
||||
* 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
|
||||
@ -38,6 +38,7 @@
|
||||
#include "roff.h"
|
||||
#include "mdoc.h"
|
||||
#include "man.h"
|
||||
#include "mandoc_parse.h"
|
||||
#include "main.h"
|
||||
#include "manconf.h"
|
||||
#include "mansearch.h"
|
||||
@ -69,6 +70,7 @@ 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 parse_manpath_conf(struct req *);
|
||||
static void parse_path_info(struct req *req, const char *path);
|
||||
static void parse_query_string(struct req *, const char *);
|
||||
@ -90,6 +92,7 @@ static void resp_format(const struct req *, const char *);
|
||||
static void resp_searchform(const struct req *, enum focus);
|
||||
static void resp_show(const struct req *, const char *);
|
||||
static void set_query_attr(char **, char **);
|
||||
static int validate_arch(const char *);
|
||||
static int validate_filename(const char *);
|
||||
static int validate_manpath(const struct req *, const char *);
|
||||
static int validate_urifrag(const char *);
|
||||
@ -315,6 +318,18 @@ http_decode(char *p)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
http_encode(const char *p)
|
||||
{
|
||||
for (; *p != '\0'; p++) {
|
||||
if (isalnum((unsigned char)*p) == 0 &&
|
||||
strchr("-._~", *p) == NULL)
|
||||
printf("%%%2.2X", (unsigned char)*p);
|
||||
else
|
||||
putchar(*p);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
resp_begin_http(int code, const char *msg)
|
||||
{
|
||||
@ -489,6 +504,18 @@ validate_manpath(const struct req *req, const char* manpath)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
validate_arch(const char *arch)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < arch_MAX; i++)
|
||||
if (strcmp(arch, arch_names[i]) == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
validate_filename(const char *file)
|
||||
{
|
||||
@ -562,9 +589,11 @@ pg_redirect(const struct req *req, const char *name)
|
||||
printf("%s/", req->q.manpath);
|
||||
if (req->q.arch != NULL)
|
||||
printf("%s/", req->q.arch);
|
||||
printf("%s", name);
|
||||
if (req->q.sec != NULL)
|
||||
printf(".%s", req->q.sec);
|
||||
http_encode(name);
|
||||
if (req->q.sec != NULL) {
|
||||
putchar('.');
|
||||
http_encode(req->q.sec);
|
||||
}
|
||||
printf("\r\nContent-Type: text/html; charset=utf-8\r\n\r\n");
|
||||
}
|
||||
|
||||
@ -820,7 +849,7 @@ resp_format(const struct req *req, const char *file)
|
||||
{
|
||||
struct manoutput conf;
|
||||
struct mparse *mp;
|
||||
struct roff_man *man;
|
||||
struct roff_meta *meta;
|
||||
void *vp;
|
||||
int fd;
|
||||
int usepath;
|
||||
@ -831,37 +860,26 @@ resp_format(const struct req *req, const char *file)
|
||||
}
|
||||
|
||||
mchars_alloc();
|
||||
mp = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1,
|
||||
MANDOCERR_MAX, NULL, MANDOC_OS_OTHER, req->q.manpath);
|
||||
mp = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1 |
|
||||
MPARSE_VALIDATE, MANDOC_OS_OTHER, req->q.manpath);
|
||||
mparse_readfd(mp, fd, file);
|
||||
close(fd);
|
||||
meta = mparse_result(mp);
|
||||
|
||||
memset(&conf, 0, sizeof(conf));
|
||||
conf.fragment = 1;
|
||||
conf.style = mandoc_strdup(CSS_DIR "/mandoc.css");
|
||||
conf.toc = 1;
|
||||
usepath = strcmp(req->q.manpath, req->p[0]);
|
||||
mandoc_asprintf(&conf.man, "/%s%s%s%s%%N.%%S",
|
||||
scriptname, *scriptname == '\0' ? "" : "/",
|
||||
usepath ? req->q.manpath : "", usepath ? "/" : "");
|
||||
|
||||
mparse_result(mp, &man, NULL);
|
||||
if (man == NULL) {
|
||||
warnx("fatal mandoc error: %s/%s", req->q.manpath, file);
|
||||
pg_error_internal();
|
||||
mparse_free(mp);
|
||||
mchars_free();
|
||||
return;
|
||||
}
|
||||
|
||||
vp = html_alloc(&conf);
|
||||
|
||||
if (man->macroset == MACROSET_MDOC) {
|
||||
mdoc_validate(man);
|
||||
html_mdoc(vp, man);
|
||||
} else {
|
||||
man_validate(man);
|
||||
html_man(vp, man);
|
||||
}
|
||||
if (meta->macroset == MACROSET_MDOC)
|
||||
html_mdoc(vp, meta);
|
||||
else
|
||||
html_man(vp, meta);
|
||||
|
||||
html_free(vp);
|
||||
mparse_free(mp);
|
||||
@ -1089,7 +1107,7 @@ main(void)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if ( ! (NULL == req.q.arch || validate_urifrag(req.q.arch))) {
|
||||
if (req.q.arch != NULL && validate_arch(req.q.arch) == 0) {
|
||||
pg_error_badrequest(
|
||||
"You specified an invalid architecture.");
|
||||
return EXIT_FAILURE;
|
||||
@ -1115,80 +1133,74 @@ main(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* If PATH_INFO is not a file name, translate it to a query.
|
||||
* Translate PATH_INFO to a query.
|
||||
*/
|
||||
static void
|
||||
parse_path_info(struct req *req, const char *path)
|
||||
{
|
||||
char *dir[4];
|
||||
int i;
|
||||
const char *name, *sec, *end;
|
||||
|
||||
req->isquery = 0;
|
||||
req->q.equal = 1;
|
||||
req->q.manpath = mandoc_strdup(path);
|
||||
req->q.manpath = NULL;
|
||||
req->q.arch = NULL;
|
||||
|
||||
/* Mandatory manual page name. */
|
||||
if ((req->q.query = strrchr(req->q.manpath, '/')) == NULL) {
|
||||
req->q.query = req->q.manpath;
|
||||
req->q.manpath = NULL;
|
||||
} else
|
||||
*req->q.query++ = '\0';
|
||||
if ((name = strrchr(path, '/')) == NULL)
|
||||
name = path;
|
||||
else
|
||||
name++;
|
||||
|
||||
/* Optional trailing section. */
|
||||
if ((req->q.sec = strrchr(req->q.query, '.')) != NULL) {
|
||||
if(isdigit((unsigned char)req->q.sec[1])) {
|
||||
*req->q.sec++ = '\0';
|
||||
req->q.sec = mandoc_strdup(req->q.sec);
|
||||
} else
|
||||
req->q.sec = NULL;
|
||||
sec = strrchr(name, '.');
|
||||
if (sec != NULL && isdigit((unsigned char)*++sec)) {
|
||||
req->q.query = mandoc_strndup(name, sec - name - 1);
|
||||
req->q.sec = mandoc_strdup(sec);
|
||||
} else {
|
||||
req->q.query = mandoc_strdup(name);
|
||||
req->q.sec = NULL;
|
||||
}
|
||||
|
||||
/* Handle the case of name[.section] only. */
|
||||
if (req->q.manpath == NULL)
|
||||
if (name == path)
|
||||
return;
|
||||
req->q.query = mandoc_strdup(req->q.query);
|
||||
|
||||
/* Split directory components. */
|
||||
dir[i = 0] = req->q.manpath;
|
||||
while ((dir[i + 1] = strchr(dir[i], '/')) != NULL) {
|
||||
if (++i == 3) {
|
||||
pg_error_badrequest(
|
||||
"You specified too many directory components.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
*dir[i]++ = '\0';
|
||||
}
|
||||
|
||||
/* Optional manpath. */
|
||||
if ((i = validate_manpath(req, req->q.manpath)) == 0)
|
||||
end = strchr(path, '/');
|
||||
req->q.manpath = mandoc_strndup(path, end - path);
|
||||
if (validate_manpath(req, req->q.manpath)) {
|
||||
path = end + 1;
|
||||
if (name == path)
|
||||
return;
|
||||
} else {
|
||||
free(req->q.manpath);
|
||||
req->q.manpath = NULL;
|
||||
else if (dir[1] == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Optional section. */
|
||||
if (strncmp(dir[i], "man", 3) == 0) {
|
||||
if (strncmp(path, "man", 3) == 0 || strncmp(path, "cat", 3) == 0) {
|
||||
path += 3;
|
||||
end = strchr(path, '/');
|
||||
free(req->q.sec);
|
||||
req->q.sec = mandoc_strdup(dir[i++] + 3);
|
||||
req->q.sec = mandoc_strndup(path, end - path);
|
||||
path = end + 1;
|
||||
if (name == path)
|
||||
return;
|
||||
}
|
||||
if (dir[i] == NULL) {
|
||||
if (req->q.manpath == NULL)
|
||||
free(dir[0]);
|
||||
return;
|
||||
|
||||
/* Optional architecture. */
|
||||
end = strchr(path, '/');
|
||||
if (end + 1 != name) {
|
||||
pg_error_badrequest(
|
||||
"You specified too many directory components.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (dir[i + 1] != NULL) {
|
||||
req->q.arch = mandoc_strndup(path, end - path);
|
||||
if (validate_arch(req->q.arch) == 0) {
|
||||
pg_error_badrequest(
|
||||
"You specified an invalid directory component.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Optional architecture. */
|
||||
if (i) {
|
||||
req->q.arch = mandoc_strdup(dir[i]);
|
||||
if (req->q.manpath == NULL)
|
||||
free(dir[0]);
|
||||
} else
|
||||
req->q.arch = dir[0];
|
||||
}
|
||||
|
||||
/*
|
||||
|
37
chars.c
37
chars.c
@ -1,7 +1,7 @@
|
||||
/* $Id: chars.c,v 1.73 2017/08/23 13:01:29 schwarze Exp $ */
|
||||
/* $Id: chars.c,v 1.78 2018/12/15 19:30:26 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2011,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
|
||||
@ -23,6 +23,7 @@
|
||||
#include <ctype.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -47,20 +48,13 @@ static struct ln lines[] = {
|
||||
{ " ", ascii_nbrsp, 0x00a0 },
|
||||
{ "~", ascii_nbrsp, 0x00a0 },
|
||||
{ "0", " ", 0x2002 },
|
||||
{ "|", "", 0 },
|
||||
{ "^", "", 0 },
|
||||
{ "&", "", 0 },
|
||||
{ "%", "", 0 },
|
||||
{ ":", ascii_break, 0 },
|
||||
/* XXX The following three do not really belong here. */
|
||||
{ "t", "", 0 },
|
||||
{ "c", "", 0 },
|
||||
{ "}", "", 0 },
|
||||
|
||||
/* Lines. */
|
||||
{ "ba", "|", 0x007c },
|
||||
{ "br", "|", 0x2502 },
|
||||
{ "ul", "_", 0x005f },
|
||||
{ "_", "_", 0x005f },
|
||||
{ "ru", "_", 0x005f },
|
||||
{ "rn", "-", 0x203e },
|
||||
{ "bb", "|", 0x00a6 },
|
||||
@ -82,10 +76,10 @@ static struct ln lines[] = {
|
||||
{ "sh", "#", 0x0023 },
|
||||
{ "CR", "<cr>", 0x21b5 },
|
||||
{ "OK", "\\/", 0x2713 },
|
||||
{ "CL", "<club>", 0x2663 },
|
||||
{ "SP", "<spade>", 0x2660 },
|
||||
{ "HE", "<heart>", 0x2665 },
|
||||
{ "DI", "<diamond>", 0x2666 },
|
||||
{ "CL", "C", 0x2663 },
|
||||
{ "SP", "S", 0x2660 },
|
||||
{ "HE", "H", 0x2665 },
|
||||
{ "DI", "D", 0x2666 },
|
||||
|
||||
/* Legal symbols. */
|
||||
{ "co", "(C)", 0x00a9 },
|
||||
@ -240,7 +234,7 @@ static struct ln lines[] = {
|
||||
{ "Ah", "<Aleph>", 0x2135 },
|
||||
{ "Im", "<Im>", 0x2111 },
|
||||
{ "Re", "<Re>", 0x211c },
|
||||
{ "wp", "P", 0x2118 },
|
||||
{ "wp", "p", 0x2118 },
|
||||
{ "pd", "<del>", 0x2202 },
|
||||
{ "-h", "/h", 0x210f },
|
||||
{ "hbar", "/h", 0x210f },
|
||||
@ -287,6 +281,7 @@ static struct ln lines[] = {
|
||||
{ "ho", ",", 0x02db },
|
||||
{ "ha", "^", 0x005e },
|
||||
{ "ti", "~", 0x007e },
|
||||
{ "u02DC", "~", 0x02dc },
|
||||
|
||||
/* Accented letters. */
|
||||
{ "'A", "'\bA", 0x00c1 },
|
||||
@ -294,11 +289,13 @@ static struct ln lines[] = {
|
||||
{ "'I", "'\bI", 0x00cd },
|
||||
{ "'O", "'\bO", 0x00d3 },
|
||||
{ "'U", "'\bU", 0x00da },
|
||||
{ "'Y", "'\bY", 0x00dd },
|
||||
{ "'a", "'\ba", 0x00e1 },
|
||||
{ "'e", "'\be", 0x00e9 },
|
||||
{ "'i", "'\bi", 0x00ed },
|
||||
{ "'o", "'\bo", 0x00f3 },
|
||||
{ "'u", "'\bu", 0x00fa },
|
||||
{ "'y", "'\by", 0x00fd },
|
||||
{ "`A", "`\bA", 0x00c0 },
|
||||
{ "`E", "`\bE", 0x00c8 },
|
||||
{ "`I", "`\bI", 0x00cc },
|
||||
@ -359,7 +356,7 @@ static struct ln lines[] = {
|
||||
{ "Eu", "EUR", 0x20ac },
|
||||
{ "eu", "EUR", 0x20ac },
|
||||
{ "Ye", "=\bY", 0x00a5 },
|
||||
{ "Po", "GBP", 0x00a3 },
|
||||
{ "Po", "-\bL", 0x00a3 },
|
||||
{ "Cs", "o\bx", 0x00a4 },
|
||||
{ "Fn", ",\bf", 0x0192 },
|
||||
|
||||
@ -460,7 +457,7 @@ mchars_spec2cp(const char *p, size_t sz)
|
||||
|
||||
end = p + sz;
|
||||
ln = ohash_find(&mchars, ohash_qlookupi(&mchars, p, &end));
|
||||
return ln != NULL ? ln->unicode : sz == 1 ? (unsigned char)*p : -1;
|
||||
return ln != NULL ? ln->unicode : -1;
|
||||
}
|
||||
|
||||
int
|
||||
@ -490,10 +487,8 @@ mchars_spec2str(const char *p, size_t sz, size_t *rsz)
|
||||
|
||||
end = p + sz;
|
||||
ln = ohash_find(&mchars, ohash_qlookupi(&mchars, p, &end));
|
||||
if (ln == NULL) {
|
||||
*rsz = 1;
|
||||
return sz == 1 ? p : NULL;
|
||||
}
|
||||
if (ln == NULL)
|
||||
return NULL;
|
||||
|
||||
*rsz = strlen(ln->ascii);
|
||||
return ln->ascii;
|
||||
|
142
configure
vendored
142
configure
vendored
@ -1,8 +1,8 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# $Id: configure,v 1.66 2018/07/31 15:34:00 schwarze Exp $
|
||||
# $Id: configure,v 1.70 2019/03/06 16:04:31 schwarze Exp $
|
||||
#
|
||||
# Copyright (c) 2014,2015,2016,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
|
||||
# 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
|
||||
@ -37,6 +37,7 @@ SOURCEDIR=`dirname "$0"`
|
||||
|
||||
MANPATH_BASE="/usr/share/man:/usr/X11R6/man"
|
||||
MANPATH_DEFAULT="/usr/share/man:/usr/X11R6/man:/usr/local/man"
|
||||
OSENUM=
|
||||
OSNAME=
|
||||
UTF8_LOCALE=
|
||||
|
||||
@ -64,6 +65,7 @@ HAVE_FTS_COMPARE_CONST=
|
||||
HAVE_GETLINE=
|
||||
HAVE_GETSUBOPT=
|
||||
HAVE_ISBLANK=
|
||||
HAVE_LESS_T=
|
||||
HAVE_MKDTEMP=
|
||||
HAVE_NANOSLEEP=
|
||||
HAVE_NTOHL=
|
||||
@ -90,6 +92,9 @@ HAVE_SYS_ENDIAN=
|
||||
HAVE_VASPRINTF=
|
||||
HAVE_WCHAR=
|
||||
|
||||
NEED_GNU_SOURCE=0
|
||||
NEED_OPENBSD_SOURCE=0
|
||||
|
||||
PREFIX="/usr/local"
|
||||
BINDIR=
|
||||
SBINDIR=
|
||||
@ -154,31 +159,34 @@ ismanual() {
|
||||
# In case of failure, do not decide anything yet.
|
||||
# Arguments: test file name, test var name, additional CFLAGS
|
||||
singletest() {
|
||||
n=${1}${3}${4}
|
||||
cat 1>&3 << __HEREDOC__
|
||||
testing ${1}${3} ...
|
||||
${COMP} -o test-${1} test-${1}.c ${3}
|
||||
testing ${n} ...
|
||||
${COMP} -o test-${1} test-${1}.c ${3} ${4}
|
||||
__HEREDOC__
|
||||
|
||||
if ${COMP} -o "test-${1}" "${SOURCEDIR}/test-${1}.c" ${3} 1>&3 2>&3
|
||||
if ${COMP} -o "test-${1}" "${SOURCEDIR}/test-${1}.c" ${3} ${4} 1>&3 2>&3
|
||||
then
|
||||
echo "partial result of ${1}${3}: ${CC} succeeded" 1>&3
|
||||
echo "partial result of ${n}: ${CC} succeeded" 1>&3
|
||||
else
|
||||
echo "result of ${1}${3}: ${CC} failed with exit status $?" 1>&3
|
||||
echo "result of compiling ${1}${3}: no" 1>&3
|
||||
echo "result of ${n}: ${CC} failed with exit status $?" 1>&3
|
||||
echo "result of compiling ${n}: no" 1>&3
|
||||
echo 1>&3
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ./test-${1} 1>&3 2>&3; then
|
||||
echo "tested ${1}${3}: yes" 1>&2
|
||||
echo "result of running ${1}${3}: yes" 1>&3
|
||||
echo "tested ${n}: yes" 1>&2
|
||||
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
|
||||
rm "test-${1}"
|
||||
return 0
|
||||
else
|
||||
echo "result of ${1}${3}: execution failed with exit status $?" 1>&3
|
||||
echo "result of running ${1}${3}: no" 1>&3
|
||||
echo "result of ${n}: execution failed with exit status $?" 1>&3
|
||||
echo "result of running ${n}: no" 1>&3
|
||||
echo 1>&3
|
||||
rm "test-${1}"
|
||||
return 1
|
||||
@ -191,8 +199,8 @@ __HEREDOC__
|
||||
runtest() {
|
||||
eval _manual=\${HAVE_${2}}
|
||||
ismanual "${1}" "${2}" "${_manual}" && return 0
|
||||
singletest "${1}" "${2}" "${3}" && return 0
|
||||
echo "tested ${1}${3}: no" 1>&2
|
||||
singletest "${1}" "${2}" "${3}" "${4}" && return 0
|
||||
echo "tested ${1}${3}${4}: no" 1>&2
|
||||
eval HAVE_${2}=0
|
||||
return 1
|
||||
}
|
||||
@ -213,28 +221,52 @@ get_locale() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
# --- operating system -------------------------------------------------
|
||||
|
||||
if [ -n "${OSENUM}" ]; then
|
||||
echo "OSENUM specified manually: ${OSENUM}" 1>&2
|
||||
echo "OSENUM specified manually: ${OSENUM}" 1>&3
|
||||
else
|
||||
OSDETECT=`uname`
|
||||
if [ "X${OSDETECT}" = "XNetBSD" ]; then
|
||||
OSENUM=MANDOC_OS_NETBSD
|
||||
elif [ "X${OSDETECT}" = "XOpenBSD" ]; then
|
||||
OSENUM=MANDOC_OS_OPENBSD
|
||||
else
|
||||
OSENUM=MANDOC_OS_OTHER
|
||||
fi
|
||||
echo "tested operating system: ${OSDETECT} -> OSENUM=${OSENUM}" 1>&2
|
||||
echo "tested operating system: ${OSDETECT} -> OSENUM=${OSENUM}" 1>&3
|
||||
unset OSDETECT
|
||||
fi
|
||||
echo 1>&3
|
||||
|
||||
# --- compiler options -------------------------------------------------
|
||||
|
||||
DEFCFLAGS="-g -W -Wall -Wmissing-prototypes -Wstrict-prototypes -Wwrite-strings -Wno-unused-parameter"
|
||||
|
||||
if [ -n "${CFLAGS}" ]; then
|
||||
COMP="${CC} ${CFLAGS}"
|
||||
echo "selected CFLAGS=\"${CFLAGS}\" (manual)" 1>&2
|
||||
echo "selected CFLAGS=\"${CFLAGS}\" (manual)" 1>&3
|
||||
echo 1>&3
|
||||
else
|
||||
CFLAGS="-g -W -Wall -Wmissing-prototypes -Wstrict-prototypes"
|
||||
CFLAGS="${CFLAGS} -Wwrite-strings -Wno-unused-parameter"
|
||||
COMP="${CC} ${CFLAGS} -Wno-unused -Werror"
|
||||
echo -n "tested ${CC} -W: " 1>&2
|
||||
echo -n "testing ${CC} -W: " 1>&3
|
||||
runtest noop WFLAG || true
|
||||
if [ "${HAVE_WFLAG}" -eq 0 ]; then
|
||||
CFLAGS="-g"
|
||||
COMP="${CC} ${CFLAGS}"
|
||||
fi
|
||||
echo "selected CFLAGS=\"${CFLAGS}\"" 1>&2
|
||||
echo "selected CFLAGS=\"${CFLAGS}\"" 1>&3
|
||||
echo 1>&3
|
||||
else
|
||||
COMP="${CC} ${DEFCFLAGS} -Wno-unused -Werror"
|
||||
fi
|
||||
echo -n "tested ${CC} -W: " 1>&2
|
||||
echo -n "testing ${CC} -W: " 1>&3
|
||||
runtest noop WFLAG || true
|
||||
|
||||
if [ -n "${CFLAGS}" ]; then
|
||||
echo "CFLAGS specified manually:" 1>&3
|
||||
elif [ ${HAVE_WFLAG} -eq 0 ]; then
|
||||
CFLAGS="-g"
|
||||
else
|
||||
CFLAGS="${DEFCFLAGS}"
|
||||
fi
|
||||
echo "selected CFLAGS=\"${CFLAGS}\"" 1>&2
|
||||
echo "selected CFLAGS=\"${CFLAGS}\"" 1>&3
|
||||
echo 1>&3
|
||||
|
||||
COMP="${CC} ${CFLAGS}"
|
||||
[ ${HAVE_WFLAG} -eq 0 ] || COMP="${COMP} -Wno-unused -Werror"
|
||||
|
||||
if [ -n "${STATIC}" ]; then
|
||||
echo "selected STATIC=\"${STATIC}\" (manual)" 1>&2
|
||||
@ -257,7 +289,8 @@ runtest be32toh SYS_ENDIAN -DSYS_ENDIAN || true
|
||||
runtest EFTYPE EFTYPE || true
|
||||
runtest err ERR || true
|
||||
runtest getline GETLINE || true
|
||||
runtest getsubopt GETSUBOPT || true
|
||||
singletest getsubopt GETSUBOPT || \
|
||||
runtest getsubopt GETSUBOPT -D_GNU_SOURCE || true
|
||||
runtest isblank ISBLANK || true
|
||||
runtest mkdtemp MKDTEMP || true
|
||||
runtest ntohl NTOHL || true
|
||||
@ -266,19 +299,25 @@ runtest PATH_MAX PATH_MAX || true
|
||||
runtest pledge PLEDGE || true
|
||||
runtest sandbox_init SANDBOX_INIT || true
|
||||
runtest progname PROGNAME || true
|
||||
runtest reallocarray REALLOCARRAY || true
|
||||
runtest recallocarray RECALLOCARRAY || true
|
||||
singletest reallocarray REALLOCARRAY || \
|
||||
runtest reallocarray REALLOCARRAY -D_OPENBSD_SOURCE || true
|
||||
singletest recallocarray RECALLOCARRAY || \
|
||||
runtest recallocarray RECALLOCARRAY -D_OPENBSD_SOURCE || true
|
||||
runtest rewb-bsd REWB_BSD || true
|
||||
runtest rewb-sysv REWB_SYSV || true
|
||||
runtest strcasestr STRCASESTR || true
|
||||
singletest strcasestr STRCASESTR || \
|
||||
runtest strcasestr STRCASESTR -D_GNU_SOURCE || true
|
||||
runtest stringlist STRINGLIST || true
|
||||
runtest strlcat STRLCAT || true
|
||||
runtest strlcpy STRLCPY || true
|
||||
runtest strndup STRNDUP || true
|
||||
runtest strptime STRPTIME || true
|
||||
singletest strptime STRPTIME || \
|
||||
runtest strptime STRPTIME -D_GNU_SOURCE || true
|
||||
runtest strsep STRSEP || true
|
||||
runtest strtonum STRTONUM || true
|
||||
runtest vasprintf VASPRINTF || true
|
||||
singletest strtonum STRTONUM || \
|
||||
runtest strtonum STRTONUM -D_OPENBSD_SOURCE || true
|
||||
singletest vasprintf VASPRINTF || \
|
||||
runtest vasprintf VASPRINTF -D_GNU_SOURCE || true
|
||||
|
||||
if [ ${HAVE_ENDIAN} -eq 0 -a \
|
||||
${HAVE_SYS_ENDIAN} -eq 0 -a \
|
||||
@ -296,9 +335,25 @@ else
|
||||
runtest fts FTS || true
|
||||
fi
|
||||
|
||||
if ismanual "less -T" LESS_T ${HAVE_LESS_T}; then
|
||||
:
|
||||
elif less -ET /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 1>&3
|
||||
else
|
||||
HAVE_LESS_T=0
|
||||
echo "tested less -T: no" 1>&2
|
||||
echo "tested less -T: no" 1>&3
|
||||
echo 1>&3
|
||||
fi
|
||||
|
||||
# --- wide character and locale support ---
|
||||
if get_locale; then
|
||||
runtest wchar WCHAR -DUTF8_LOCALE=\"${UTF8_LOCALE}\" || true
|
||||
singletest wchar WCHAR -DUTF8_LOCALE=\"${UTF8_LOCALE}\" || \
|
||||
runtest wchar WCHAR -D_GNU_SOURCE \
|
||||
-DUTF8_LOCALE=\"${UTF8_LOCALE}\" || true
|
||||
else
|
||||
HAVE_WCHAR=0
|
||||
echo "tested wchar: no (no UTF8_LOCALE)" 1>&2
|
||||
@ -383,12 +438,11 @@ cat << __HEREDOC__
|
||||
#define __attribute__(x)
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__MINT__)
|
||||
#define _GNU_SOURCE /* See test-*.c what needs this. */
|
||||
#endif
|
||||
|
||||
__HEREDOC__
|
||||
|
||||
[ ${NEED_GNU_SOURCE} -eq 0 ] || echo "#define _GNU_SOURCE"
|
||||
[ ${NEED_OPENBSD_SOURCE} -eq 0 ] || echo "#define _OPENBSD_SOURCE"
|
||||
|
||||
[ ${HAVE_GETLINE} -eq 0 -o \
|
||||
${HAVE_REALLOCARRAY} -eq 0 -o ${HAVE_RECALLOCARRAY} -eq 0 -o \
|
||||
${HAVE_STRLCAT} -eq 0 -o ${HAVE_STRLCPY} -eq 0 -o \
|
||||
@ -401,6 +455,7 @@ echo
|
||||
echo "#define MAN_CONF_FILE \"/etc/${MANM_MANCONF}\""
|
||||
echo "#define MANPATH_BASE \"${MANPATH_BASE}\""
|
||||
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}\""
|
||||
@ -422,6 +477,7 @@ cat << __HEREDOC__
|
||||
#define HAVE_GETLINE ${HAVE_GETLINE}
|
||||
#define HAVE_GETSUBOPT ${HAVE_GETSUBOPT}
|
||||
#define HAVE_ISBLANK ${HAVE_ISBLANK}
|
||||
#define HAVE_LESS_T ${HAVE_LESS_T}
|
||||
#define HAVE_MKDTEMP ${HAVE_MKDTEMP}
|
||||
#define HAVE_NTOHL ${HAVE_NTOHL}
|
||||
#define HAVE_PLEDGE ${HAVE_PLEDGE}
|
||||
|
@ -1,6 +1,6 @@
|
||||
# $Id: configure.local.example,v 1.34 2018/07/31 15:34:00 schwarze Exp $
|
||||
# $Id: configure.local.example,v 1.36 2019/03/06 10:18:58 schwarze Exp $
|
||||
#
|
||||
# Copyright (c) 2014,2015,2016,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
|
||||
# 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
|
||||
@ -67,6 +67,17 @@ MANPATH_DEFAULT="/usr/share/man:/usr/X11R6/man:/usr/local/man"
|
||||
|
||||
MANPATH_BASE="/usr/share/man:/usr/X11R6/man"
|
||||
|
||||
# When man(1) is called with the -S option and no manual page is
|
||||
# found matching the requested name and the requested architecture,
|
||||
# it tries to figure out whether the requested architecture is valid
|
||||
# for the present operating system. Normally, ./configure detects
|
||||
# the operating system using uname(1). If that fails or is not
|
||||
# desired, either of the following lines can be used:
|
||||
|
||||
OSENUM=MANDOC_OS_NETBSD
|
||||
OSENUM=MANDOC_OS_OPENBSD
|
||||
OSENUM=MANDOC_OS_OTHER
|
||||
|
||||
# In manual pages written in the mdoc(7) language, the operating system
|
||||
# version is displayed in the page footer line. If an operating system
|
||||
# is specified as an argument to the .Os macro, that is always used.
|
||||
@ -77,7 +88,7 @@ MANPATH_BASE="/usr/share/man:/usr/X11R6/man"
|
||||
# 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.3"
|
||||
OSNAME="OpenBSD 6.5"
|
||||
|
||||
# The following installation directories are used.
|
||||
# It is possible to set only one or a few of these variables,
|
||||
@ -293,6 +304,7 @@ HAVE_FTS_COMPARE_CONST=0 # Setting this implies HAVE_FTS=1.
|
||||
HAVE_GETLINE=0
|
||||
HAVE_GETSUBOPT=0
|
||||
HAVE_ISBLANK=0
|
||||
HAVE_LESS_T=0
|
||||
HAVE_MKDTEMP=0
|
||||
HAVE_NTOHL=0
|
||||
HAVE_O_DIRECTORY=0
|
||||
|
8
dbm.c
8
dbm.c
@ -1,4 +1,4 @@
|
||||
/* $Id: dbm.c,v 1.5 2016/10/18 22:27:25 schwarze Exp $ */
|
||||
/* $Id: dbm.c,v 1.6 2018/11/19 19:22:07 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
|
||||
*
|
||||
@ -151,17 +151,17 @@ dbm_page_get(int32_t ip)
|
||||
assert(ip < npages);
|
||||
res.name = dbm_get(pages[ip].name);
|
||||
if (res.name == NULL)
|
||||
res.name = "(NULL)";
|
||||
res.name = "(NULL)\0";
|
||||
res.sect = dbm_get(pages[ip].sect);
|
||||
if (res.sect == NULL)
|
||||
res.sect = "(NULL)";
|
||||
res.sect = "(NULL)\0";
|
||||
res.arch = pages[ip].arch ? dbm_get(pages[ip].arch) : NULL;
|
||||
res.desc = dbm_get(pages[ip].desc);
|
||||
if (res.desc == NULL)
|
||||
res.desc = "(NULL)";
|
||||
res.file = dbm_get(pages[ip].file);
|
||||
if (res.file == NULL)
|
||||
res.file = " (NULL)";
|
||||
res.file = " (NULL)\0";
|
||||
res.addr = dbm_addr(pages + ip);
|
||||
return &res;
|
||||
}
|
||||
|
24
demandoc.c
24
demandoc.c
@ -1,4 +1,4 @@
|
||||
/* $Id: demandoc.c,v 1.29 2017/06/24 14:38:32 schwarze Exp $ */
|
||||
/* $Id: demandoc.c,v 1.33 2019/03/03 11:01:15 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
*
|
||||
@ -29,6 +29,7 @@
|
||||
#include "roff.h"
|
||||
#include "man.h"
|
||||
#include "mdoc.h"
|
||||
#include "mandoc_parse.h"
|
||||
|
||||
static void pline(int, int *, int *, int);
|
||||
static void pman(const struct roff_node *, int *, int *, int);
|
||||
@ -78,8 +79,8 @@ main(int argc, char *argv[])
|
||||
argv += optind;
|
||||
|
||||
mchars_alloc();
|
||||
mp = mparse_alloc(MPARSE_SO, MANDOCERR_MAX, NULL,
|
||||
MANDOC_OS_OTHER, NULL);
|
||||
mp = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1 |
|
||||
MPARSE_VALIDATE, MANDOC_OS_OTHER, NULL);
|
||||
assert(mp);
|
||||
|
||||
if (argc < 1)
|
||||
@ -109,24 +110,19 @@ usage(void)
|
||||
static void
|
||||
pmandoc(struct mparse *mp, int fd, const char *fn, int list)
|
||||
{
|
||||
struct roff_man *man;
|
||||
struct roff_meta *meta;
|
||||
int line, col;
|
||||
|
||||
mparse_readfd(mp, fd, fn);
|
||||
close(fd);
|
||||
mparse_result(mp, &man, NULL);
|
||||
meta = mparse_result(mp);
|
||||
line = 1;
|
||||
col = 0;
|
||||
|
||||
if (man == NULL)
|
||||
return;
|
||||
if (man->macroset == MACROSET_MDOC) {
|
||||
mdoc_validate(man);
|
||||
pmdoc(man->first->child, &line, &col, list);
|
||||
} else {
|
||||
man_validate(man);
|
||||
pman(man->first->child, &line, &col, list);
|
||||
}
|
||||
if (meta->macroset == MACROSET_MDOC)
|
||||
pmdoc(meta->first->child, &line, &col, list);
|
||||
else
|
||||
pman(meta->first->child, &line, &col, list);
|
||||
|
||||
if ( ! list)
|
||||
putchar('\n');
|
||||
|
93
eqn.c
93
eqn.c
@ -1,7 +1,7 @@
|
||||
/* $Id: eqn.c,v 1.78 2017/07/15 16:26:17 schwarze Exp $ */
|
||||
/* $Id: eqn.c,v 1.83 2018/12/14 06:33:14 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 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
|
||||
@ -30,8 +30,9 @@
|
||||
#include "mandoc_aux.h"
|
||||
#include "mandoc.h"
|
||||
#include "roff.h"
|
||||
#include "eqn.h"
|
||||
#include "libmandoc.h"
|
||||
#include "libroff.h"
|
||||
#include "eqn_parse.h"
|
||||
|
||||
#define EQN_NEST_MAX 128 /* maximum nesting of defines */
|
||||
#define STRNEQ(p1, sz1, p2, sz2) \
|
||||
@ -284,6 +285,13 @@ enum parse_mode {
|
||||
MODE_TOK
|
||||
};
|
||||
|
||||
struct eqn_def {
|
||||
char *key;
|
||||
size_t keysz;
|
||||
char *val;
|
||||
size_t valsz;
|
||||
};
|
||||
|
||||
static struct eqn_box *eqn_box_alloc(struct eqn_node *, struct eqn_box *);
|
||||
static struct eqn_box *eqn_box_makebinary(struct eqn_node *,
|
||||
struct eqn_box *);
|
||||
@ -295,12 +303,11 @@ static void eqn_undef(struct eqn_node *);
|
||||
|
||||
|
||||
struct eqn_node *
|
||||
eqn_alloc(struct mparse *parse)
|
||||
eqn_alloc(void)
|
||||
{
|
||||
struct eqn_node *ep;
|
||||
|
||||
ep = mandoc_calloc(1, sizeof(*ep));
|
||||
ep->parse = parse;
|
||||
ep->gsize = EQN_DEFSIZE;
|
||||
return ep;
|
||||
}
|
||||
@ -399,7 +406,7 @@ eqn_next(struct eqn_node *ep, enum parse_mode mode)
|
||||
ep->end = strchr(ep->start + 1, *ep->start);
|
||||
ep->start++; /* Skip opening quote. */
|
||||
if (ep->end == NULL) {
|
||||
mandoc_msg(MANDOCERR_ARG_QUOTE, ep->parse,
|
||||
mandoc_msg(MANDOCERR_ARG_QUOTE,
|
||||
ep->node->line, ep->node->pos, NULL);
|
||||
ep->end = strchr(ep->start, '\0');
|
||||
}
|
||||
@ -420,7 +427,7 @@ eqn_next(struct eqn_node *ep, enum parse_mode mode)
|
||||
if ((def = eqn_def_find(ep)) == NULL)
|
||||
break;
|
||||
if (++lim > EQN_NEST_MAX) {
|
||||
mandoc_msg(MANDOCERR_ROFFLOOP, ep->parse,
|
||||
mandoc_msg(MANDOCERR_ROFFLOOP,
|
||||
ep->node->line, ep->node->pos, NULL);
|
||||
return EQN_TOK_EOF;
|
||||
}
|
||||
@ -468,6 +475,8 @@ eqn_next(struct eqn_node *ep, enum parse_mode mode)
|
||||
void
|
||||
eqn_box_free(struct eqn_box *bp)
|
||||
{
|
||||
if (bp == NULL)
|
||||
return;
|
||||
|
||||
if (bp->first)
|
||||
eqn_box_free(bp->first);
|
||||
@ -482,6 +491,16 @@ eqn_box_free(struct eqn_box *bp)
|
||||
free(bp);
|
||||
}
|
||||
|
||||
struct eqn_box *
|
||||
eqn_box_new(void)
|
||||
{
|
||||
struct eqn_box *bp;
|
||||
|
||||
bp = mandoc_calloc(1, sizeof(*bp));
|
||||
bp->expectargs = UINT_MAX;
|
||||
return bp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a box as the last child of the parent node.
|
||||
*/
|
||||
@ -490,10 +509,9 @@ eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent)
|
||||
{
|
||||
struct eqn_box *bp;
|
||||
|
||||
bp = mandoc_calloc(1, sizeof(struct eqn_box));
|
||||
bp = eqn_box_new();
|
||||
bp->parent = parent;
|
||||
bp->parent->args++;
|
||||
bp->expectargs = UINT_MAX;
|
||||
bp->font = bp->parent->font;
|
||||
bp->size = ep->gsize;
|
||||
|
||||
@ -542,7 +560,7 @@ static void
|
||||
eqn_delim(struct eqn_node *ep)
|
||||
{
|
||||
if (ep->end[0] == '\0' || ep->end[1] == '\0') {
|
||||
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
|
||||
mandoc_msg(MANDOCERR_REQ_EMPTY,
|
||||
ep->node->line, ep->node->pos, "delim");
|
||||
if (ep->end[0] != '\0')
|
||||
ep->end++;
|
||||
@ -569,7 +587,7 @@ eqn_undef(struct eqn_node *ep)
|
||||
struct eqn_def *def;
|
||||
|
||||
if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) {
|
||||
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
|
||||
mandoc_msg(MANDOCERR_REQ_EMPTY,
|
||||
ep->node->line, ep->node->pos, "undef");
|
||||
return;
|
||||
}
|
||||
@ -588,7 +606,7 @@ eqn_def(struct eqn_node *ep)
|
||||
int i;
|
||||
|
||||
if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF) {
|
||||
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
|
||||
mandoc_msg(MANDOCERR_REQ_EMPTY,
|
||||
ep->node->line, ep->node->pos, "define");
|
||||
return;
|
||||
}
|
||||
@ -617,7 +635,7 @@ eqn_def(struct eqn_node *ep)
|
||||
}
|
||||
|
||||
if (eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF) {
|
||||
mandoc_vmsg(MANDOCERR_REQ_EMPTY, ep->parse,
|
||||
mandoc_msg(MANDOCERR_REQ_EMPTY,
|
||||
ep->node->line, ep->node->pos, "define %s", def->key);
|
||||
free(def->key);
|
||||
free(def->val);
|
||||
@ -666,7 +684,7 @@ eqn_parse(struct eqn_node *ep)
|
||||
case EQN_TOK_TDEFINE:
|
||||
if (eqn_next(ep, MODE_NOSUB) == EQN_TOK_EOF ||
|
||||
eqn_next(ep, MODE_QUOTED) == EQN_TOK_EOF)
|
||||
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
|
||||
mandoc_msg(MANDOCERR_REQ_EMPTY,
|
||||
ep->node->line, ep->node->pos, "tdefine");
|
||||
break;
|
||||
case EQN_TOK_DELIM:
|
||||
@ -674,8 +692,8 @@ eqn_parse(struct eqn_node *ep)
|
||||
break;
|
||||
case EQN_TOK_GFONT:
|
||||
if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF)
|
||||
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
|
||||
ep->node->line, ep->node->pos, eqn_toks[tok]);
|
||||
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line,
|
||||
ep->node->pos, "%s", eqn_toks[tok]);
|
||||
break;
|
||||
case EQN_TOK_MARK:
|
||||
case EQN_TOK_LINEUP:
|
||||
@ -690,8 +708,8 @@ eqn_parse(struct eqn_node *ep)
|
||||
case EQN_TOK_DOT:
|
||||
case EQN_TOK_DOTDOT:
|
||||
if (parent->last == NULL) {
|
||||
mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
|
||||
ep->node->line, ep->node->pos, eqn_toks[tok]);
|
||||
mandoc_msg(MANDOCERR_EQN_NOBOX, ep->node->line,
|
||||
ep->node->pos, "%s", eqn_toks[tok]);
|
||||
cur = eqn_box_alloc(ep, parent);
|
||||
cur->type = EQN_TEXT;
|
||||
cur->text = mandoc_strdup("");
|
||||
@ -735,8 +753,8 @@ eqn_parse(struct eqn_node *ep)
|
||||
case EQN_TOK_DOWN:
|
||||
case EQN_TOK_UP:
|
||||
if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF)
|
||||
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
|
||||
ep->node->line, ep->node->pos, eqn_toks[tok]);
|
||||
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line,
|
||||
ep->node->pos, "%s", eqn_toks[tok]);
|
||||
break;
|
||||
case EQN_TOK_FAT:
|
||||
case EQN_TOK_ROMAN:
|
||||
@ -773,14 +791,14 @@ eqn_parse(struct eqn_node *ep)
|
||||
case EQN_TOK_GSIZE:
|
||||
/* Accept two values: integral size and a single. */
|
||||
if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
|
||||
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
|
||||
ep->node->line, ep->node->pos, eqn_toks[tok]);
|
||||
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line,
|
||||
ep->node->pos, "%s", eqn_toks[tok]);
|
||||
break;
|
||||
}
|
||||
size = mandoc_strntoi(ep->start, ep->toksz, 10);
|
||||
if (-1 == size) {
|
||||
mandoc_msg(MANDOCERR_IT_NONUM, ep->parse,
|
||||
ep->node->line, ep->node->pos, eqn_toks[tok]);
|
||||
mandoc_msg(MANDOCERR_IT_NONUM, ep->node->line,
|
||||
ep->node->pos, "%s", eqn_toks[tok]);
|
||||
break;
|
||||
}
|
||||
if (EQN_TOK_GSIZE == tok) {
|
||||
@ -804,8 +822,8 @@ eqn_parse(struct eqn_node *ep)
|
||||
* and keep on reading.
|
||||
*/
|
||||
if (parent->last == NULL) {
|
||||
mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
|
||||
ep->node->line, ep->node->pos, eqn_toks[tok]);
|
||||
mandoc_msg(MANDOCERR_EQN_NOBOX, ep->node->line,
|
||||
ep->node->pos, "%s", eqn_toks[tok]);
|
||||
cur = eqn_box_alloc(ep, parent);
|
||||
cur->type = EQN_TEXT;
|
||||
cur->text = mandoc_strdup("");
|
||||
@ -871,8 +889,8 @@ eqn_parse(struct eqn_node *ep)
|
||||
* rebalance and continue reading.
|
||||
*/
|
||||
if (parent->last == NULL) {
|
||||
mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
|
||||
ep->node->line, ep->node->pos, eqn_toks[tok]);
|
||||
mandoc_msg(MANDOCERR_EQN_NOBOX, ep->node->line,
|
||||
ep->node->pos, "%s", eqn_toks[tok]);
|
||||
cur = eqn_box_alloc(ep, parent);
|
||||
cur->type = EQN_TEXT;
|
||||
cur->text = mandoc_strdup("");
|
||||
@ -898,16 +916,16 @@ eqn_parse(struct eqn_node *ep)
|
||||
cur->left != NULL))
|
||||
break;
|
||||
if (cur == NULL) {
|
||||
mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->parse,
|
||||
ep->node->line, ep->node->pos, eqn_toks[tok]);
|
||||
mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->node->line,
|
||||
ep->node->pos, "%s", eqn_toks[tok]);
|
||||
break;
|
||||
}
|
||||
parent = cur;
|
||||
if (EQN_TOK_RIGHT == tok) {
|
||||
if (eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
|
||||
mandoc_msg(MANDOCERR_REQ_EMPTY,
|
||||
ep->parse, ep->node->line,
|
||||
ep->node->pos, eqn_toks[tok]);
|
||||
ep->node->line, ep->node->pos,
|
||||
"%s", eqn_toks[tok]);
|
||||
break;
|
||||
}
|
||||
/* Handling depends on right/left. */
|
||||
@ -941,8 +959,8 @@ eqn_parse(struct eqn_node *ep)
|
||||
parent = parent->parent;
|
||||
if (EQN_TOK_LEFT == tok &&
|
||||
eqn_next(ep, MODE_SUB) == EQN_TOK_EOF) {
|
||||
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
|
||||
ep->node->line, ep->node->pos, eqn_toks[tok]);
|
||||
mandoc_msg(MANDOCERR_REQ_EMPTY, ep->node->line,
|
||||
ep->node->pos, "%s", eqn_toks[tok]);
|
||||
break;
|
||||
}
|
||||
parent = eqn_box_alloc(ep, parent);
|
||||
@ -975,8 +993,8 @@ eqn_parse(struct eqn_node *ep)
|
||||
if (cur->type == EQN_PILE)
|
||||
break;
|
||||
if (cur == NULL) {
|
||||
mandoc_msg(MANDOCERR_IT_STRAY, ep->parse,
|
||||
ep->node->line, ep->node->pos, eqn_toks[tok]);
|
||||
mandoc_msg(MANDOCERR_IT_STRAY, ep->node->line,
|
||||
ep->node->pos, "%s", eqn_toks[tok]);
|
||||
break;
|
||||
}
|
||||
parent = eqn_box_alloc(ep, cur);
|
||||
@ -1092,6 +1110,9 @@ eqn_free(struct eqn_node *p)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (p == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < (int)p->defsz; i++) {
|
||||
free(p->defs[i].key);
|
||||
free(p->defs[i].val);
|
||||
|
72
eqn.h
Normal file
72
eqn.h
Normal file
@ -0,0 +1,72 @@
|
||||
/* $Id: eqn.h,v 1.1 2018/12/13 05:23:38 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Public data types for eqn(7) syntax trees.
|
||||
*/
|
||||
|
||||
enum eqn_boxt {
|
||||
EQN_TEXT, /* Text, e.g. number, variable, operator, ... */
|
||||
EQN_SUBEXPR, /* Nested eqn(7) subexpression. */
|
||||
EQN_LIST, /* List, for example in braces. */
|
||||
EQN_PILE, /* Vertical pile. */
|
||||
EQN_MATRIX /* List of columns. */
|
||||
};
|
||||
|
||||
enum eqn_fontt {
|
||||
EQNFONT_NONE = 0,
|
||||
EQNFONT_ROMAN,
|
||||
EQNFONT_BOLD,
|
||||
EQNFONT_FAT,
|
||||
EQNFONT_ITALIC,
|
||||
EQNFONT__MAX
|
||||
};
|
||||
|
||||
enum eqn_post {
|
||||
EQNPOS_NONE = 0,
|
||||
EQNPOS_SUP,
|
||||
EQNPOS_SUBSUP,
|
||||
EQNPOS_SUB,
|
||||
EQNPOS_TO,
|
||||
EQNPOS_FROM,
|
||||
EQNPOS_FROMTO,
|
||||
EQNPOS_OVER,
|
||||
EQNPOS_SQRT,
|
||||
EQNPOS__MAX
|
||||
};
|
||||
|
||||
/*
|
||||
* A "box" is a parsed mathematical expression as defined by the eqn.7
|
||||
* grammar.
|
||||
*/
|
||||
struct eqn_box {
|
||||
struct eqn_box *parent;
|
||||
struct eqn_box *prev;
|
||||
struct eqn_box *next;
|
||||
struct eqn_box *first; /* First child node. */
|
||||
struct eqn_box *last; /* Last child node. */
|
||||
char *text; /* Text (or NULL). */
|
||||
char *left; /* Left-hand fence. */
|
||||
char *right; /* Right-hand fence. */
|
||||
char *top; /* Symbol above. */
|
||||
char *bottom; /* Symbol below. */
|
||||
size_t expectargs; /* Maximal number of arguments. */
|
||||
size_t args; /* Actual number of arguments. */
|
||||
int size; /* Font size. */
|
||||
#define EQN_DEFSIZE INT_MIN
|
||||
enum eqn_boxt type; /* Type of node. */
|
||||
enum eqn_fontt font; /* Font in this box. */
|
||||
enum eqn_post pos; /* Position of the next box. */
|
||||
};
|
@ -1,4 +1,4 @@
|
||||
/* $Id: eqn_html.c,v 1.17 2017/07/14 13:32:35 schwarze Exp $ */
|
||||
/* $Id: eqn_html.c,v 1.18 2018/12/13 05:23:38 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
@ -26,6 +26,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "eqn.h"
|
||||
#include "out.h"
|
||||
#include "html.h"
|
||||
|
||||
|
48
eqn_parse.h
Normal file
48
eqn_parse.h
Normal file
@ -0,0 +1,48 @@
|
||||
/* $Id: eqn_parse.h,v 1.3 2018/12/14 06:33:14 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2014, 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
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* External interface of the eqn(7) parser.
|
||||
* For use in the roff(7) and eqn(7) parsers only.
|
||||
*/
|
||||
|
||||
struct roff_node;
|
||||
struct eqn_box;
|
||||
struct eqn_def;
|
||||
|
||||
struct eqn_node {
|
||||
struct roff_node *node; /* Syntax tree of this equation. */
|
||||
struct eqn_def *defs; /* Array of definitions. */
|
||||
char *data; /* Source code of this equation. */
|
||||
char *start; /* First byte of the current token. */
|
||||
char *end; /* First byte of the next token. */
|
||||
size_t defsz; /* Number of definitions. */
|
||||
size_t sz; /* Length of the source code. */
|
||||
size_t toksz; /* Length of the current token. */
|
||||
int gsize; /* Default point size. */
|
||||
int delim; /* In-line delimiters enabled. */
|
||||
char odelim; /* In-line opening delimiter. */
|
||||
char cdelim; /* In-line closing delimiter. */
|
||||
};
|
||||
|
||||
|
||||
struct eqn_node *eqn_alloc(void);
|
||||
struct eqn_box *eqn_box_new(void);
|
||||
void eqn_box_free(struct eqn_box *);
|
||||
void eqn_free(struct eqn_node *);
|
||||
void eqn_parse(struct eqn_node *);
|
||||
void eqn_read(struct eqn_node *, const char *);
|
||||
void eqn_reset(struct eqn_node *);
|
@ -1,4 +1,4 @@
|
||||
/* $Id: eqn_term.c,v 1.17 2017/08/23 21:56:20 schwarze Exp $ */
|
||||
/* $Id: eqn_term.c,v 1.19 2018/12/13 05:23:38 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
@ -25,7 +25,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "eqn.h"
|
||||
#include "out.h"
|
||||
#include "term.h"
|
||||
|
||||
@ -106,7 +106,7 @@ eqn_box(struct termp *p, const struct eqn_box *bp)
|
||||
/* Special box types. */
|
||||
|
||||
if (bp->pos == EQNPOS_SQRT) {
|
||||
term_word(p, "sqrt");
|
||||
term_word(p, "\\(sr");
|
||||
if (bp->first != NULL) {
|
||||
p->flags |= TERMP_NOSPACE;
|
||||
eqn_box(p, bp->first);
|
||||
|
4
gmdiff
4
gmdiff
@ -36,7 +36,7 @@ elif [ "X$1" = "X-u" ]; then
|
||||
MOPT="-Ios=OpenBSD -Wall -Tutf8 $MOPT"
|
||||
COLPIPE="cat"
|
||||
else
|
||||
ROFF="groff -et -ww -mtty-char -Tascii -P -c"
|
||||
ROFF="groff -ket -ww -mtty-char -Tascii -P -c"
|
||||
MOPT="-Ios=OpenBSD -Wall -Tascii $MOPT"
|
||||
COLPIPE="cat"
|
||||
fi
|
||||
@ -51,7 +51,7 @@ while [ -n "$1" ]; do
|
||||
for i in roff mandoc; do
|
||||
[ -s /tmp/$i.err ] && echo "$i errors:" && cat /tmp/$i.err
|
||||
done
|
||||
diff -au /tmp/roff.out /tmp/mandoc.out 2>&1
|
||||
diff -au $DIFFOPT /tmp/roff.out /tmp/mandoc.out 2>&1
|
||||
done
|
||||
|
||||
exit 0
|
||||
|
275
html.c
275
html.c
@ -1,7 +1,7 @@
|
||||
/* $Id: html.c,v 1.238 2018/06/25 16:54:59 schwarze Exp $ */
|
||||
/* $Id: html.c,v 1.254 2019/03/03 13:02:11 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-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
|
||||
@ -18,6 +18,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
@ -62,6 +63,7 @@ static const struct htmldata htmltags[TAG_MAX] = {
|
||||
{"title", HTML_NLAROUND},
|
||||
{"div", HTML_NLAROUND},
|
||||
{"div", 0},
|
||||
{"section", HTML_NLALL},
|
||||
{"h1", HTML_NLAROUND},
|
||||
{"h2", HTML_NLAROUND},
|
||||
{"span", 0},
|
||||
@ -77,6 +79,7 @@ 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},
|
||||
@ -107,6 +110,7 @@ static const struct htmldata htmltags[TAG_MAX] = {
|
||||
/* Avoid duplicate HTML id= attributes. */
|
||||
static struct ohash id_unique;
|
||||
|
||||
static void html_reset_internal(struct html *);
|
||||
static void print_byte(struct html *, char);
|
||||
static void print_endword(struct html *);
|
||||
static void print_indent(struct html *);
|
||||
@ -116,7 +120,6 @@ static void print_ctag(struct html *, struct tag *);
|
||||
static int print_escape(struct html *, char);
|
||||
static int print_encode(struct html *, const char *, const char *, int);
|
||||
static void print_href(struct html *, const char *, const char *, int);
|
||||
static void print_metaf(struct html *, enum mandoc_esc);
|
||||
|
||||
|
||||
void *
|
||||
@ -128,31 +131,32 @@ html_alloc(const struct manoutput *outopts)
|
||||
|
||||
h->tag = NULL;
|
||||
h->style = outopts->style;
|
||||
h->base_man = outopts->man;
|
||||
if ((h->base_man1 = outopts->man) == NULL)
|
||||
h->base_man2 = NULL;
|
||||
else if ((h->base_man2 = strchr(h->base_man1, ';')) != NULL)
|
||||
*h->base_man2++ = '\0';
|
||||
h->base_includes = outopts->includes;
|
||||
if (outopts->fragment)
|
||||
h->oflags |= HTML_FRAGMENT;
|
||||
if (outopts->toc)
|
||||
h->oflags |= HTML_TOC;
|
||||
|
||||
mandoc_ohash_init(&id_unique, 4, 0);
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
void
|
||||
html_free(void *p)
|
||||
static void
|
||||
html_reset_internal(struct html *h)
|
||||
{
|
||||
struct tag *tag;
|
||||
struct html *h;
|
||||
char *cp;
|
||||
unsigned int slot;
|
||||
|
||||
h = (struct html *)p;
|
||||
while ((tag = h->tag) != NULL) {
|
||||
h->tag = tag->next;
|
||||
free(tag);
|
||||
}
|
||||
free(h);
|
||||
|
||||
cp = ohash_first(&id_unique, &slot);
|
||||
while (cp != NULL) {
|
||||
free(cp);
|
||||
@ -161,6 +165,20 @@ html_free(void *p)
|
||||
ohash_delete(&id_unique);
|
||||
}
|
||||
|
||||
void
|
||||
html_reset(void *p)
|
||||
{
|
||||
html_reset_internal(p);
|
||||
mandoc_ohash_init(&id_unique, 4, 0);
|
||||
}
|
||||
|
||||
void
|
||||
html_free(void *p)
|
||||
{
|
||||
html_reset_internal(p);
|
||||
free(p);
|
||||
}
|
||||
|
||||
void
|
||||
print_gen_head(struct html *h)
|
||||
{
|
||||
@ -204,7 +222,7 @@ print_gen_head(struct html *h)
|
||||
print_tagq(h, t);
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
print_metaf(struct html *h, enum mandoc_esc deco)
|
||||
{
|
||||
enum htmlfont font;
|
||||
@ -222,12 +240,15 @@ print_metaf(struct html *h, enum mandoc_esc deco)
|
||||
case ESCAPE_FONTBI:
|
||||
font = HTMLFONT_BI;
|
||||
break;
|
||||
case ESCAPE_FONTCW:
|
||||
font = HTMLFONT_CW;
|
||||
break;
|
||||
case ESCAPE_FONT:
|
||||
case ESCAPE_FONTROMAN:
|
||||
font = HTMLFONT_NONE;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
return;
|
||||
}
|
||||
|
||||
if (h->metaf) {
|
||||
@ -249,11 +270,69 @@ print_metaf(struct html *h, enum mandoc_esc deco)
|
||||
h->metaf = print_otag(h, TAG_B, "");
|
||||
print_otag(h, TAG_I, "");
|
||||
break;
|
||||
case HTMLFONT_CW:
|
||||
h->metaf = print_otag(h, TAG_SPAN, "c", "Li");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
html_close_paragraph(struct html *h)
|
||||
{
|
||||
struct tag *t;
|
||||
|
||||
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);
|
||||
break;
|
||||
case TAG_A:
|
||||
print_tagq(h, t);
|
||||
continue;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ROFF_nf switches to no-fill mode, ROFF_fi to fill mode.
|
||||
* TOKEN_NONE does not switch. The old mode is returned.
|
||||
*/
|
||||
enum roff_tok
|
||||
html_fillmode(struct html *h, enum roff_tok want)
|
||||
{
|
||||
struct tag *t;
|
||||
enum roff_tok had;
|
||||
|
||||
for (t = h->tag; t != NULL; t = t->next)
|
||||
if (t->tag == TAG_PRE)
|
||||
break;
|
||||
|
||||
had = t == NULL ? ROFF_fi : ROFF_nf;
|
||||
|
||||
if (want != had) {
|
||||
switch (want) {
|
||||
case ROFF_fi:
|
||||
print_tagq(h, t);
|
||||
break;
|
||||
case ROFF_nf:
|
||||
html_close_paragraph(h);
|
||||
print_otag(h, TAG_PRE, "");
|
||||
break;
|
||||
case TOKEN_NONE:
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
return had;
|
||||
}
|
||||
|
||||
char *
|
||||
html_make_id(const struct roff_node *n, int unique)
|
||||
{
|
||||
@ -345,7 +424,6 @@ static int
|
||||
print_encode(struct html *h, const char *p, const char *pend, int norecurse)
|
||||
{
|
||||
char numbuf[16];
|
||||
struct tag *t;
|
||||
const char *seq;
|
||||
size_t sz;
|
||||
int c, len, breakline, nospace;
|
||||
@ -371,9 +449,7 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse)
|
||||
|
||||
if (breakline &&
|
||||
(p >= pend || *p == ' ' || *p == ASCII_NBRSP)) {
|
||||
t = print_otag(h, TAG_DIV, "");
|
||||
print_text(h, "\\~");
|
||||
print_tagq(h, t);
|
||||
print_otag(h, TAG_BR, "");
|
||||
breakline = 0;
|
||||
while (p < pend && (*p == ' ' || *p == ASCII_NBRSP))
|
||||
p++;
|
||||
@ -393,22 +469,25 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse)
|
||||
continue;
|
||||
|
||||
esc = mandoc_escape(&p, &seq, &len);
|
||||
if (ESCAPE_ERROR == esc)
|
||||
break;
|
||||
|
||||
switch (esc) {
|
||||
case ESCAPE_FONT:
|
||||
case ESCAPE_FONTPREV:
|
||||
case ESCAPE_FONTBOLD:
|
||||
case ESCAPE_FONTITALIC:
|
||||
case ESCAPE_FONTBI:
|
||||
case ESCAPE_FONTCW:
|
||||
case ESCAPE_FONTROMAN:
|
||||
if (0 == norecurse)
|
||||
if (0 == norecurse) {
|
||||
h->flags |= HTML_NOSPACE;
|
||||
print_metaf(h, esc);
|
||||
h->flags &= ~HTML_NOSPACE;
|
||||
}
|
||||
continue;
|
||||
case ESCAPE_SKIPCHAR:
|
||||
h->flags |= HTML_SKIPCHAR;
|
||||
continue;
|
||||
case ESCAPE_ERROR:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -433,6 +512,12 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse)
|
||||
if (c <= 0)
|
||||
continue;
|
||||
break;
|
||||
case ESCAPE_UNDEF:
|
||||
c = *seq;
|
||||
break;
|
||||
case ESCAPE_DEVICE:
|
||||
print_word(h, "html");
|
||||
continue;
|
||||
case ESCAPE_BREAK:
|
||||
breakline = 1;
|
||||
continue;
|
||||
@ -464,9 +549,21 @@ print_encode(struct html *h, const char *p, const char *pend, int norecurse)
|
||||
static void
|
||||
print_href(struct html *h, const char *name, const char *sec, int man)
|
||||
{
|
||||
struct stat sb;
|
||||
const char *p, *pp;
|
||||
char *filename;
|
||||
|
||||
if (man) {
|
||||
pp = h->base_man1;
|
||||
if (h->base_man2 != NULL) {
|
||||
mandoc_asprintf(&filename, "%s.%s", name, sec);
|
||||
if (stat(filename, &sb) == -1)
|
||||
pp = h->base_man2;
|
||||
free(filename);
|
||||
}
|
||||
} else
|
||||
pp = h->base_includes;
|
||||
|
||||
pp = man ? h->base_man : h->base_includes;
|
||||
while ((p = strchr(pp, '%')) != NULL) {
|
||||
print_encode(h, pp, p, 1);
|
||||
if (man && p[1] == 'S') {
|
||||
@ -492,7 +589,7 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
|
||||
struct tag *t;
|
||||
const char *attr;
|
||||
char *arg1, *arg2;
|
||||
int tflags;
|
||||
int style_written, tflags;
|
||||
|
||||
tflags = htmltags[tag].flags;
|
||||
|
||||
@ -502,6 +599,8 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
|
||||
t = mandoc_malloc(sizeof(struct tag));
|
||||
t->tag = tag;
|
||||
t->next = h->tag;
|
||||
t->refcnt = 0;
|
||||
t->closed = 0;
|
||||
h->tag = t;
|
||||
} else
|
||||
t = NULL;
|
||||
@ -532,7 +631,7 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
while (*fmt != '\0') {
|
||||
while (*fmt != '\0' && *fmt != 's') {
|
||||
|
||||
/* Parse attributes and arguments. */
|
||||
|
||||
@ -548,10 +647,6 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
|
||||
case 'i':
|
||||
attr = "id";
|
||||
break;
|
||||
case 's':
|
||||
attr = "style";
|
||||
arg2 = va_arg(ap, char *);
|
||||
break;
|
||||
case '?':
|
||||
attr = arg1;
|
||||
arg1 = va_arg(ap, char *);
|
||||
@ -584,26 +679,33 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
|
||||
print_encode(h, arg1, NULL, 1);
|
||||
fmt++;
|
||||
break;
|
||||
case 'T':
|
||||
print_encode(h, arg1, NULL, 1);
|
||||
print_word(h, "\" title=\"");
|
||||
print_encode(h, arg1, NULL, 1);
|
||||
fmt++;
|
||||
break;
|
||||
default:
|
||||
if (arg2 == NULL)
|
||||
print_encode(h, arg1, NULL, 1);
|
||||
else {
|
||||
print_word(h, arg1);
|
||||
print_byte(h, ':');
|
||||
print_byte(h, ' ');
|
||||
print_word(h, arg2);
|
||||
print_byte(h, ';');
|
||||
}
|
||||
print_encode(h, arg1, NULL, 1);
|
||||
break;
|
||||
}
|
||||
print_byte(h, '"');
|
||||
}
|
||||
|
||||
style_written = 0;
|
||||
while (*fmt++ == 's') {
|
||||
arg1 = va_arg(ap, char *);
|
||||
arg2 = va_arg(ap, char *);
|
||||
if (arg2 == NULL)
|
||||
continue;
|
||||
print_byte(h, ' ');
|
||||
if (style_written == 0) {
|
||||
print_word(h, "style=\"");
|
||||
style_written = 1;
|
||||
}
|
||||
print_word(h, arg1);
|
||||
print_byte(h, ':');
|
||||
print_byte(h, ' ');
|
||||
print_word(h, arg2);
|
||||
print_byte(h, ';');
|
||||
}
|
||||
if (style_written)
|
||||
print_byte(h, '"');
|
||||
|
||||
va_end(ap);
|
||||
|
||||
/* Accommodate for "well-formed" singleton escaping. */
|
||||
@ -631,33 +733,32 @@ print_ctag(struct html *h, struct tag *tag)
|
||||
{
|
||||
int tflags;
|
||||
|
||||
/*
|
||||
* Remember to close out and nullify the current
|
||||
* meta-font and table, if applicable.
|
||||
*/
|
||||
if (tag == h->metaf)
|
||||
h->metaf = NULL;
|
||||
if (tag == h->tblt)
|
||||
h->tblt = NULL;
|
||||
if (tag->closed == 0) {
|
||||
tag->closed = 1;
|
||||
if (tag == h->metaf)
|
||||
h->metaf = NULL;
|
||||
if (tag == h->tblt)
|
||||
h->tblt = NULL;
|
||||
|
||||
tflags = htmltags[tag->tag].flags;
|
||||
|
||||
if (tflags & HTML_INDENT)
|
||||
h->indent--;
|
||||
if (tflags & HTML_NOINDENT)
|
||||
h->noindent--;
|
||||
if (tflags & HTML_NLEND)
|
||||
print_endline(h);
|
||||
print_indent(h);
|
||||
print_byte(h, '<');
|
||||
print_byte(h, '/');
|
||||
print_word(h, htmltags[tag->tag].name);
|
||||
print_byte(h, '>');
|
||||
if (tflags & HTML_NLAFTER)
|
||||
print_endline(h);
|
||||
|
||||
h->tag = tag->next;
|
||||
free(tag);
|
||||
tflags = htmltags[tag->tag].flags;
|
||||
if (tflags & HTML_INDENT)
|
||||
h->indent--;
|
||||
if (tflags & HTML_NOINDENT)
|
||||
h->noindent--;
|
||||
if (tflags & HTML_NLEND)
|
||||
print_endline(h);
|
||||
print_indent(h);
|
||||
print_byte(h, '<');
|
||||
print_byte(h, '/');
|
||||
print_word(h, htmltags[tag->tag].name);
|
||||
print_byte(h, '>');
|
||||
if (tflags & HTML_NLAFTER)
|
||||
print_endline(h);
|
||||
}
|
||||
if (tag->refcnt == 0) {
|
||||
h->tag = tag->next;
|
||||
free(tag);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -717,6 +818,9 @@ print_text(struct html *h, const char *word)
|
||||
h->metaf = print_otag(h, TAG_B, "");
|
||||
print_otag(h, TAG_I, "");
|
||||
break;
|
||||
case HTMLFONT_CW:
|
||||
h->metaf = print_otag(h, TAG_SPAN, "c", "Li");
|
||||
break;
|
||||
default:
|
||||
print_indent(h);
|
||||
break;
|
||||
@ -741,36 +845,33 @@ print_text(struct html *h, const char *word)
|
||||
void
|
||||
print_tagq(struct html *h, const struct tag *until)
|
||||
{
|
||||
struct tag *tag;
|
||||
struct tag *this, *next;
|
||||
|
||||
while ((tag = h->tag) != NULL) {
|
||||
print_ctag(h, tag);
|
||||
if (until && tag == until)
|
||||
return;
|
||||
for (this = h->tag; this != NULL; this = next) {
|
||||
next = this == until ? NULL : this->next;
|
||||
print_ctag(h, this);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Close out all open elements up to but excluding suntil.
|
||||
* Note that a paragraph just inside stays open together with it
|
||||
* because paragraphs include subsequent phrasing content.
|
||||
*/
|
||||
void
|
||||
print_stagq(struct html *h, const struct tag *suntil)
|
||||
{
|
||||
struct tag *tag;
|
||||
struct tag *this, *next;
|
||||
|
||||
while ((tag = h->tag) != NULL) {
|
||||
if (suntil && tag == suntil)
|
||||
return;
|
||||
print_ctag(h, tag);
|
||||
for (this = h->tag; this != NULL; this = next) {
|
||||
next = this->next;
|
||||
if (this == suntil || (next == suntil &&
|
||||
(this->tag == TAG_P || this->tag == TAG_PRE)))
|
||||
break;
|
||||
print_ctag(h, this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_paragraph(struct html *h)
|
||||
{
|
||||
struct tag *t;
|
||||
|
||||
t = print_otag(h, TAG_DIV, "c", "Pp");
|
||||
print_tagq(h, t);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* Low level output functions.
|
||||
|
19
html.h
19
html.h
@ -1,7 +1,7 @@
|
||||
/* $Id: html.h,v 1.92 2018/06/25 16:54:59 schwarze Exp $ */
|
||||
/* $Id: html.h,v 1.102 2019/03/01 10:57:18 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* 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
|
||||
@ -24,6 +24,7 @@ enum htmltag {
|
||||
TAG_TITLE,
|
||||
TAG_DIV,
|
||||
TAG_IDIV,
|
||||
TAG_SECTION,
|
||||
TAG_H1,
|
||||
TAG_H2,
|
||||
TAG_SPAN,
|
||||
@ -39,6 +40,7 @@ enum htmltag {
|
||||
TAG_DL,
|
||||
TAG_DT,
|
||||
TAG_DD,
|
||||
TAG_P,
|
||||
TAG_PRE,
|
||||
TAG_VAR,
|
||||
TAG_CITE,
|
||||
@ -72,11 +74,14 @@ enum htmlfont {
|
||||
HTMLFONT_BOLD,
|
||||
HTMLFONT_ITALIC,
|
||||
HTMLFONT_BI,
|
||||
HTMLFONT_CW,
|
||||
HTMLFONT_MAX
|
||||
};
|
||||
|
||||
struct tag {
|
||||
struct tag *next;
|
||||
int refcnt;
|
||||
int closed;
|
||||
enum htmltag tag;
|
||||
};
|
||||
|
||||
@ -87,12 +92,12 @@ struct html {
|
||||
#define HTML_KEEP (1 << 2)
|
||||
#define HTML_PREKEEP (1 << 3)
|
||||
#define HTML_NONOSPACE (1 << 4) /* never add spaces */
|
||||
#define HTML_LITERAL (1 << 5) /* literal (e.g., <PRE>) context */
|
||||
#define HTML_SKIPCHAR (1 << 6) /* skip the next character */
|
||||
#define HTML_NOSPLIT (1 << 7) /* do not break line before .An */
|
||||
#define HTML_SPLIT (1 << 8) /* break line before .An */
|
||||
#define HTML_NONEWLINE (1 << 9) /* No line break in nofill mode. */
|
||||
#define HTML_BUFFER (1 << 10) /* Collect a word to see if it fits. */
|
||||
#define HTML_TOCDONE (1 << 11) /* The TOC was already written. */
|
||||
size_t indent; /* current output indentation level */
|
||||
int noindent; /* indent disabled by <pre> */
|
||||
size_t col; /* current output byte position */
|
||||
@ -101,7 +106,8 @@ struct html {
|
||||
struct tag *tag; /* last open tag */
|
||||
struct rofftbl tbl; /* current table */
|
||||
struct tag *tblt; /* current open table scope */
|
||||
char *base_man; /* base for manpage href */
|
||||
char *base_man1; /* bases for manpage href */
|
||||
char *base_man2;
|
||||
char *base_includes; /* base for include href */
|
||||
char *style; /* style-sheet URI */
|
||||
struct tag *metaf; /* current open font scope */
|
||||
@ -109,6 +115,7 @@ struct html {
|
||||
enum htmlfont metac; /* current font mode */
|
||||
int oflags; /* output options */
|
||||
#define HTML_FRAGMENT (1 << 0) /* don't emit HTML/HEAD/BODY */
|
||||
#define HTML_TOC (1 << 1) /* emit a table of contents */
|
||||
};
|
||||
|
||||
|
||||
@ -121,6 +128,7 @@ void roff_html_pre(struct html *, const struct roff_node *);
|
||||
void print_gen_comment(struct html *, struct roff_node *);
|
||||
void print_gen_decls(struct html *);
|
||||
void print_gen_head(struct html *);
|
||||
void print_metaf(struct html *, enum mandoc_esc);
|
||||
struct tag *print_otag(struct html *, enum htmltag, const char *, ...);
|
||||
void print_tagq(struct html *, const struct tag *);
|
||||
void print_stagq(struct html *, const struct tag *);
|
||||
@ -128,7 +136,8 @@ void print_text(struct html *, const char *);
|
||||
void print_tblclose(struct html *);
|
||||
void print_tbl(struct html *, const struct tbl_span *);
|
||||
void print_eqn(struct html *, const struct eqn_box *);
|
||||
void print_paragraph(struct html *);
|
||||
void print_endline(struct html *);
|
||||
|
||||
void html_close_paragraph(struct html *);
|
||||
enum roff_tok html_fillmode(struct html *, enum roff_tok);
|
||||
char *html_make_id(const struct roff_node *, int);
|
||||
|
5
lib.c
5
lib.c
@ -1,4 +1,4 @@
|
||||
/* $Id: lib.c,v 1.14 2017/06/24 14:38:32 schwarze Exp $ */
|
||||
/* $Id: lib.c,v 1.15 2018/12/13 11:55:46 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
*
|
||||
@ -17,12 +17,9 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "roff.h"
|
||||
#include "mdoc.h"
|
||||
#include "libmdoc.h"
|
||||
|
||||
#define LINE(x, y) \
|
||||
|
3
lib.in
3
lib.in
@ -1,4 +1,4 @@
|
||||
/* $Id: lib.in,v 1.20 2017/08/20 02:30:27 schwarze Exp $ */
|
||||
/* $Id: lib.in,v 1.21 2019/03/04 17:35:21 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2009, 2012 Joerg Sonnenberger <joerg@netbsd.org>
|
||||
@ -29,6 +29,7 @@ LINE("libalias", "Packet Aliasing Library (libalias, \\-lalias)")
|
||||
LINE("libarchive", "Streaming Archive Library (libarchive, \\-larchive)")
|
||||
LINE("libarm", "ARM Architecture Library (libarm, \\-larm)")
|
||||
LINE("libarm32", "ARM32 Architecture Library (libarm32, \\-larm32)")
|
||||
LINE("libbe", "Boot Environment Library (libbe, \\-lbe)")
|
||||
LINE("libbluetooth", "Bluetooth Library (libbluetooth, \\-lbluetooth)")
|
||||
LINE("libbsdxml", "eXpat XML parser library (libbsdxml, \\-lbsdxml)")
|
||||
LINE("libbsm", "Basic Security Module Library (libbsm, \\-lbsm)")
|
||||
|
22
libman.h
22
libman.h
@ -1,7 +1,7 @@
|
||||
/* $Id: libman.h,v 1.81 2017/04/29 12:45:41 schwarze Exp $ */
|
||||
/* $Id: libman.h,v 1.86 2018/12/31 10:04:39 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2014, 2015, 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
|
||||
@ -16,6 +16,9 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
struct roff_node;
|
||||
struct roff_man;
|
||||
|
||||
#define MACRO_PROT_ARGS struct roff_man *man, \
|
||||
enum roff_tok tok, \
|
||||
int line, \
|
||||
@ -26,15 +29,14 @@
|
||||
struct man_macro {
|
||||
void (*fp)(MACRO_PROT_ARGS);
|
||||
int flags;
|
||||
#define MAN_SCOPED (1 << 0) /* Optional next-line scope. */
|
||||
#define MAN_NSCOPED (1 << 1) /* Allowed in next-line element scope. */
|
||||
#define MAN_BSCOPE (1 << 2) /* Break next-line block scope. */
|
||||
#define MAN_JOIN (1 << 3) /* Join arguments together. */
|
||||
#define MAN_BSCOPED (1 << 0) /* Optional next-line block scope. */
|
||||
#define MAN_ESCOPED (1 << 1) /* Optional next-line element scope. */
|
||||
#define MAN_NSCOPED (1 << 2) /* Allowed in next-line element scope. */
|
||||
#define MAN_XSCOPE (1 << 3) /* Exit next-line block scope. */
|
||||
#define MAN_JOIN (1 << 4) /* Join arguments together. */
|
||||
};
|
||||
|
||||
extern const struct man_macro *const man_macros;
|
||||
const struct man_macro *man_macro(enum roff_tok);
|
||||
|
||||
|
||||
void man_node_validate(struct roff_man *);
|
||||
void man_state(struct roff_man *, struct roff_node *);
|
||||
void man_descope(struct roff_man *, int, int, char *);
|
||||
void man_unscope(struct roff_man *, const struct roff_node *);
|
||||
|
54
libmandoc.h
54
libmandoc.h
@ -1,7 +1,7 @@
|
||||
/* $Id: libmandoc.h,v 1.71 2018/04/09 22:27:04 schwarze Exp $ */
|
||||
/* $Id: libmandoc.h,v 1.77 2018/12/21 17:15:18 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* 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
|
||||
@ -16,31 +16,38 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
enum rofferr {
|
||||
ROFF_CONT, /* continue processing line */
|
||||
ROFF_RERUN, /* re-run roff interpreter with offset */
|
||||
ROFF_APPEND, /* re-run main parser, appending next line */
|
||||
ROFF_REPARSE, /* re-run main parser on the result */
|
||||
ROFF_SO, /* include another file */
|
||||
ROFF_IGN, /* ignore current line */
|
||||
};
|
||||
/*
|
||||
* Return codes passed from the roff parser to the main parser.
|
||||
*/
|
||||
|
||||
/* Main instruction: what to do with the returned line. */
|
||||
#define ROFF_IGN 0x000 /* Don't do anything with it. */
|
||||
#define ROFF_CONT 0x001 /* Give it to the high-level parser. */
|
||||
#define ROFF_RERUN 0x002 /* Re-run the roff parser with an offset. */
|
||||
#define ROFF_REPARSE 0x004 /* Recursively run the main parser on it. */
|
||||
#define ROFF_SO 0x008 /* Include the named file. */
|
||||
#define ROFF_MASK 0x00f /* Only one of these bits should be set. */
|
||||
|
||||
/* Options for further parsing, to be OR'ed with the above. */
|
||||
#define ROFF_APPEND 0x010 /* Append the next line to this one. */
|
||||
#define ROFF_USERCALL 0x020 /* Start execution of a new macro. */
|
||||
#define ROFF_USERRET 0x040 /* Abort execution of the current macro. */
|
||||
#define ROFF_WHILE 0x100 /* Start a new .while loop. */
|
||||
#define ROFF_LOOPCONT 0x200 /* Iterate the current .while loop. */
|
||||
#define ROFF_LOOPEXIT 0x400 /* Exit the current .while loop. */
|
||||
#define ROFF_LOOPMASK 0xf00
|
||||
|
||||
|
||||
struct buf {
|
||||
char *buf;
|
||||
size_t sz;
|
||||
char *buf;
|
||||
size_t sz;
|
||||
struct buf *next;
|
||||
};
|
||||
|
||||
|
||||
struct mparse;
|
||||
struct roff;
|
||||
struct roff_man;
|
||||
|
||||
void mandoc_msg(enum mandocerr, struct mparse *,
|
||||
int, int, const char *);
|
||||
void mandoc_vmsg(enum mandocerr, struct mparse *,
|
||||
int, int, const char *, ...)
|
||||
__attribute__((__format__ (__printf__, 5, 6)));
|
||||
char *mandoc_getarg(struct mparse *, char **, int, int *);
|
||||
char *mandoc_normdate(struct roff_man *, char *, int, int);
|
||||
int mandoc_eos(const char *, size_t);
|
||||
int mandoc_strntoi(const char *, size_t, int);
|
||||
@ -57,17 +64,18 @@ int preconv_encode(const struct buf *, size_t *,
|
||||
struct buf *, size_t *, int *);
|
||||
|
||||
void roff_free(struct roff *);
|
||||
struct roff *roff_alloc(struct mparse *, int);
|
||||
struct roff *roff_alloc(int);
|
||||
void roff_reset(struct roff *);
|
||||
void roff_man_free(struct roff_man *);
|
||||
struct roff_man *roff_man_alloc(struct roff *, struct mparse *,
|
||||
const char *, int);
|
||||
struct roff_man *roff_man_alloc(struct roff *, const char *, int);
|
||||
void roff_man_reset(struct roff_man *);
|
||||
enum rofferr roff_parseln(struct roff *, int, struct buf *, int *);
|
||||
int roff_parseln(struct roff *, int, struct buf *, int *);
|
||||
void roff_userret(struct roff *);
|
||||
void roff_endparse(struct roff *);
|
||||
void roff_setreg(struct roff *, const char *, int, char sign);
|
||||
int roff_getreg(struct roff *, const char *);
|
||||
char *roff_strdup(const struct roff *, const char *);
|
||||
char *roff_getarg(struct roff *, char **, int, int *);
|
||||
int roff_getcontrol(const struct roff *,
|
||||
const char *, int *);
|
||||
int roff_getformat(const struct roff *);
|
||||
|
16
libmdoc.h
16
libmdoc.h
@ -1,7 +1,7 @@
|
||||
/* $Id: libmdoc.h,v 1.112 2017/05/30 16:22:03 schwarze Exp $ */
|
||||
/* $Id: libmdoc.h,v 1.117 2018/12/31 04:55:46 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* 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
|
||||
@ -16,6 +16,10 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
struct roff_node;
|
||||
struct roff_man;
|
||||
struct mdoc_arg;
|
||||
|
||||
#define MACRO_PROT_ARGS struct roff_man *mdoc, \
|
||||
enum roff_tok tok, \
|
||||
int line, \
|
||||
@ -38,6 +42,7 @@ enum margserr {
|
||||
ARGS_ERROR,
|
||||
ARGS_EOLN, /* end-of-line */
|
||||
ARGS_WORD, /* normal word */
|
||||
ARGS_ALLOC, /* normal word from roff_getarg() */
|
||||
ARGS_PUNCT, /* series of punctuation */
|
||||
ARGS_PHRASE /* Bl -column phrase */
|
||||
};
|
||||
@ -59,10 +64,8 @@ enum mdelim {
|
||||
DELIM_MAX
|
||||
};
|
||||
|
||||
extern const struct mdoc_macro *const mdoc_macros;
|
||||
const struct mdoc_macro *mdoc_macro(enum roff_tok);
|
||||
|
||||
|
||||
void mdoc_macro(MACRO_PROT_ARGS);
|
||||
void mdoc_elem_alloc(struct roff_man *, int, int,
|
||||
enum roff_tok, struct mdoc_arg *);
|
||||
struct roff_node *mdoc_block_alloc(struct roff_man *, int, int,
|
||||
@ -71,10 +74,7 @@ void mdoc_tail_alloc(struct roff_man *, int, int,
|
||||
enum roff_tok);
|
||||
struct roff_node *mdoc_endbody_alloc(struct roff_man *, int, int,
|
||||
enum roff_tok, struct roff_node *);
|
||||
void mdoc_node_relink(struct roff_man *, struct roff_node *);
|
||||
void mdoc_node_validate(struct roff_man *);
|
||||
void mdoc_state(struct roff_man *, struct roff_node *);
|
||||
void mdoc_state_reset(struct roff_man *);
|
||||
const char *mdoc_a2arch(const char *);
|
||||
const char *mdoc_a2att(const char *);
|
||||
const char *mdoc_a2lib(const char *);
|
||||
|
223
main.c
223
main.c
@ -1,7 +1,7 @@
|
||||
/* $Id: main.c,v 1.306 2018/05/14 14:10:23 schwarze Exp $ */
|
||||
/* $Id: main.c,v 1.322 2019/03/06 10:18:58 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2010-2012, 2014-2018 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2010-2012, 2014-2019 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
@ -21,7 +21,6 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/param.h> /* MACHINE */
|
||||
#include <sys/termios.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <assert.h>
|
||||
@ -40,6 +39,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@ -49,6 +49,7 @@
|
||||
#include "roff.h"
|
||||
#include "mdoc.h"
|
||||
#include "man.h"
|
||||
#include "mandoc_parse.h"
|
||||
#include "tag.h"
|
||||
#include "main.h"
|
||||
#include "manconf.h"
|
||||
@ -81,7 +82,6 @@ struct curparse {
|
||||
void *outdata; /* data for output */
|
||||
char *os_s; /* operating system for display */
|
||||
int wstop; /* stop after a file with a warning */
|
||||
enum mandocerr mmin; /* ignore messages below this */
|
||||
enum mandoc_os os_e; /* check base system conventions */
|
||||
enum outt outtype; /* which output to use */
|
||||
};
|
||||
@ -89,7 +89,7 @@ struct curparse {
|
||||
|
||||
int mandocdb(int, char *[]);
|
||||
|
||||
static void check_xr(const char *);
|
||||
static void check_xr(void);
|
||||
static int fs_lookup(const struct manpaths *,
|
||||
size_t ipath, const char *,
|
||||
const char *, const char *,
|
||||
@ -99,8 +99,6 @@ static int fs_search(const struct mansearch *,
|
||||
struct manpage **, size_t *);
|
||||
static int koptions(int *, char *);
|
||||
static void moptions(int *, char *);
|
||||
static void mmsg(enum mandocerr, enum mandoclevel,
|
||||
const char *, int, int, const char *);
|
||||
static void outdata_alloc(struct curparse *);
|
||||
static void parse(struct curparse *, int, const char *);
|
||||
static void passthrough(const char *, int, int);
|
||||
@ -112,8 +110,6 @@ static int woptions(struct curparse *, char *);
|
||||
static const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9};
|
||||
static char help_arg[] = "help";
|
||||
static char *help_argv[] = {help_arg, NULL};
|
||||
static enum mandoclevel rc;
|
||||
static FILE *mmsg_stream;
|
||||
|
||||
|
||||
int
|
||||
@ -127,7 +123,7 @@ main(int argc, char *argv[])
|
||||
struct manpage *res, *resp;
|
||||
const char *progname, *sec, *thisarg;
|
||||
char *conf_file, *defpaths, *auxpaths;
|
||||
char *oarg;
|
||||
char *oarg, *tagarg;
|
||||
unsigned char *uc;
|
||||
size_t i, sz;
|
||||
int prio, best_prio;
|
||||
@ -152,6 +148,7 @@ main(int argc, char *argv[])
|
||||
setprogname(progname);
|
||||
#endif
|
||||
|
||||
mandoc_msg_setoutfile(stderr);
|
||||
if (strncmp(progname, "mandocdb", 8) == 0 ||
|
||||
strcmp(progname, BINM_MAKEWHATIS) == 0)
|
||||
return mandocdb(argc, argv);
|
||||
@ -191,10 +188,8 @@ main(int argc, char *argv[])
|
||||
|
||||
memset(&curp, 0, sizeof(struct curparse));
|
||||
curp.outtype = OUTT_LOCALE;
|
||||
curp.mmin = MANDOCERR_MAX;
|
||||
curp.outopts = &conf.output;
|
||||
options = MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1;
|
||||
mmsg_stream = stderr;
|
||||
|
||||
use_pager = 1;
|
||||
tag_files = NULL;
|
||||
@ -314,6 +309,9 @@ main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (curp.outtype != OUTT_TREE || !curp.outopts->noval)
|
||||
options |= MPARSE_VALIDATE;
|
||||
|
||||
if (outmode == OUTMODE_FLN ||
|
||||
outmode == OUTMODE_LST ||
|
||||
!isatty(STDOUT_FILENO))
|
||||
@ -371,7 +369,16 @@ main(int argc, char *argv[])
|
||||
#endif
|
||||
}
|
||||
|
||||
rc = MANDOCLEVEL_OK;
|
||||
/*
|
||||
* Use the first argument for -O tag in addition to
|
||||
* using it as a search term for man(1) or apropos(1).
|
||||
*/
|
||||
|
||||
if (conf.output.tag != NULL && *conf.output.tag == '\0') {
|
||||
tagarg = argc > 0 && search.argmode == ARG_EXPR ?
|
||||
strchr(*argv, '=') : NULL;
|
||||
conf.output.tag = tagarg == NULL ? *argv : tagarg + 1;
|
||||
}
|
||||
|
||||
/* man(1), whatis(1), apropos(1) */
|
||||
|
||||
@ -405,7 +412,6 @@ main(int argc, char *argv[])
|
||||
res[sz].names = NULL;
|
||||
res[sz].output = NULL;
|
||||
res[sz].ipath = SIZE_MAX;
|
||||
res[sz].bits = 0;
|
||||
res[sz].sec = 10;
|
||||
res[sz].form = FORM_SRC;
|
||||
sz++;
|
||||
@ -415,7 +421,7 @@ main(int argc, char *argv[])
|
||||
if (sz == 0) {
|
||||
if (search.argmode != ARG_NAME)
|
||||
warnx("nothing appropriate");
|
||||
rc = MANDOCLEVEL_BADARG;
|
||||
mandoc_msg_setrc(MANDOCLEVEL_BADARG);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -483,19 +489,17 @@ main(int argc, char *argv[])
|
||||
moptions(&options, auxpaths);
|
||||
|
||||
mchars_alloc();
|
||||
curp.mp = mparse_alloc(options, curp.mmin, mmsg,
|
||||
curp.os_e, curp.os_s);
|
||||
|
||||
/*
|
||||
* Conditionally start up the lookaside buffer before parsing.
|
||||
*/
|
||||
if (OUTT_MAN == curp.outtype)
|
||||
mparse_keep(curp.mp);
|
||||
curp.mp = mparse_alloc(options, curp.os_e, curp.os_s);
|
||||
|
||||
if (argc < 1) {
|
||||
if (use_pager)
|
||||
if (use_pager) {
|
||||
tag_files = tag_init();
|
||||
parse(&curp, STDIN_FILENO, "<stdin>");
|
||||
tag_files->tagname = conf.output.tag;
|
||||
}
|
||||
thisarg = "<stdin>";
|
||||
mandoc_msg_setinfilename(thisarg);
|
||||
parse(&curp, STDIN_FILENO, thisarg);
|
||||
mandoc_msg_setinfilename(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -519,22 +523,25 @@ main(int argc, char *argv[])
|
||||
(void)chdir(conf.manpath.paths[resp->ipath]);
|
||||
else if (startdir != -1)
|
||||
(void)fchdir(startdir);
|
||||
}
|
||||
thisarg = resp->file;
|
||||
} else
|
||||
thisarg = *argv;
|
||||
|
||||
fd = mparse_open(curp.mp, resp != NULL ? resp->file : *argv);
|
||||
fd = mparse_open(curp.mp, thisarg);
|
||||
if (fd != -1) {
|
||||
if (use_pager) {
|
||||
tag_files = tag_init();
|
||||
use_pager = 0;
|
||||
tag_files = tag_init();
|
||||
tag_files->tagname = conf.output.tag;
|
||||
}
|
||||
|
||||
if (resp == NULL)
|
||||
parse(&curp, fd, *argv);
|
||||
else if (resp->form == FORM_SRC)
|
||||
parse(&curp, fd, resp->file);
|
||||
mandoc_msg_setinfilename(thisarg);
|
||||
if (resp == NULL || resp->form == FORM_SRC)
|
||||
parse(&curp, fd, thisarg);
|
||||
else
|
||||
passthrough(resp->file, fd,
|
||||
conf.output.synopsisonly);
|
||||
mandoc_msg_setinfilename(NULL);
|
||||
|
||||
if (ferror(stdout)) {
|
||||
if (tag_files != NULL) {
|
||||
@ -543,7 +550,7 @@ main(int argc, char *argv[])
|
||||
tag_files = NULL;
|
||||
} else
|
||||
warn("stdout");
|
||||
rc = MANDOCLEVEL_SYSERR;
|
||||
mandoc_msg_setrc(MANDOCLEVEL_SYSERR);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -552,10 +559,11 @@ main(int argc, char *argv[])
|
||||
outdata_alloc(&curp);
|
||||
terminal_sepline(curp.outdata);
|
||||
}
|
||||
} else if (rc < MANDOCLEVEL_ERROR)
|
||||
rc = MANDOCLEVEL_ERROR;
|
||||
} else
|
||||
mandoc_msg(MANDOCERR_FILE, 0, 0,
|
||||
"%s: %s", thisarg, strerror(errno));
|
||||
|
||||
if (MANDOCLEVEL_OK != rc && curp.wstop)
|
||||
if (curp.wstop && mandoc_msg_getrc() != MANDOCLEVEL_OK)
|
||||
break;
|
||||
|
||||
if (resp != NULL)
|
||||
@ -646,7 +654,7 @@ main(int argc, char *argv[])
|
||||
|
||||
if (pid == -1) {
|
||||
warn("wait");
|
||||
rc = MANDOCLEVEL_SYSERR;
|
||||
mandoc_msg_setrc(MANDOCLEVEL_SYSERR);
|
||||
break;
|
||||
}
|
||||
if (!WIFSTOPPED(status))
|
||||
@ -656,8 +664,7 @@ main(int argc, char *argv[])
|
||||
}
|
||||
tag_unlink();
|
||||
}
|
||||
|
||||
return (int)rc;
|
||||
return (int)mandoc_msg_getrc();
|
||||
}
|
||||
|
||||
static void
|
||||
@ -755,7 +762,6 @@ fs_lookup(const struct manpaths *paths, size_t ipath,
|
||||
page->names = NULL;
|
||||
page->output = NULL;
|
||||
page->ipath = ipath;
|
||||
page->bits = NAME_FILE & NAME_MASK;
|
||||
page->sec = (*sec >= '1' && *sec <= '9') ? *sec - '1' + 1 : 10;
|
||||
page->form = form;
|
||||
return 1;
|
||||
@ -790,8 +796,18 @@ fs_search(const struct mansearch *cfg, const struct manpaths *paths,
|
||||
return 1;
|
||||
}
|
||||
if (res != NULL && *ressz == lastsz &&
|
||||
strchr(*argv, '/') == NULL)
|
||||
warnx("No entry for %s in the manual.", *argv);
|
||||
strchr(*argv, '/') == NULL) {
|
||||
if (cfg->arch != NULL &&
|
||||
arch_valid(cfg->arch, OSENUM) == 0)
|
||||
warnx("Unknown architecture \"%s\".",
|
||||
cfg->arch);
|
||||
else if (cfg->sec == NULL)
|
||||
warnx("No entry for %s in the manual.",
|
||||
*argv);
|
||||
else
|
||||
warnx("No entry for %s in section %s "
|
||||
"of the manual.", *argv, cfg->sec);
|
||||
}
|
||||
lastsz = *ressz;
|
||||
argv++;
|
||||
argc--;
|
||||
@ -802,101 +818,92 @@ fs_search(const struct mansearch *cfg, const struct manpaths *paths,
|
||||
static void
|
||||
parse(struct curparse *curp, int fd, const char *file)
|
||||
{
|
||||
enum mandoclevel rctmp;
|
||||
struct roff_man *man;
|
||||
struct roff_meta *meta;
|
||||
|
||||
/* Begin by parsing the file itself. */
|
||||
|
||||
assert(file);
|
||||
assert(fd >= 0);
|
||||
|
||||
rctmp = mparse_readfd(curp->mp, fd, file);
|
||||
mparse_readfd(curp->mp, fd, file);
|
||||
if (fd != STDIN_FILENO)
|
||||
close(fd);
|
||||
if (rc < rctmp)
|
||||
rc = rctmp;
|
||||
|
||||
/*
|
||||
* With -Wstop and warnings or errors of at least the requested
|
||||
* level, do not produce output.
|
||||
*/
|
||||
|
||||
if (rctmp != MANDOCLEVEL_OK && curp->wstop)
|
||||
if (curp->wstop && mandoc_msg_getrc() != MANDOCLEVEL_OK)
|
||||
return;
|
||||
|
||||
if (curp->outdata == NULL)
|
||||
outdata_alloc(curp);
|
||||
else if (curp->outtype == OUTT_HTML)
|
||||
html_reset(curp);
|
||||
|
||||
mparse_result(curp->mp, &man, NULL);
|
||||
mandoc_xr_reset();
|
||||
meta = mparse_result(curp->mp);
|
||||
|
||||
/* Execute the out device, if it exists. */
|
||||
|
||||
if (man == NULL)
|
||||
return;
|
||||
mandoc_xr_reset();
|
||||
if (man->macroset == MACROSET_MDOC) {
|
||||
if (curp->outtype != OUTT_TREE || !curp->outopts->noval)
|
||||
mdoc_validate(man);
|
||||
if (meta->macroset == MACROSET_MDOC) {
|
||||
switch (curp->outtype) {
|
||||
case OUTT_HTML:
|
||||
html_mdoc(curp->outdata, man);
|
||||
html_mdoc(curp->outdata, meta);
|
||||
break;
|
||||
case OUTT_TREE:
|
||||
tree_mdoc(curp->outdata, man);
|
||||
tree_mdoc(curp->outdata, meta);
|
||||
break;
|
||||
case OUTT_MAN:
|
||||
man_mdoc(curp->outdata, man);
|
||||
man_mdoc(curp->outdata, meta);
|
||||
break;
|
||||
case OUTT_PDF:
|
||||
case OUTT_ASCII:
|
||||
case OUTT_UTF8:
|
||||
case OUTT_LOCALE:
|
||||
case OUTT_PS:
|
||||
terminal_mdoc(curp->outdata, man);
|
||||
terminal_mdoc(curp->outdata, meta);
|
||||
break;
|
||||
case OUTT_MARKDOWN:
|
||||
markdown_mdoc(curp->outdata, man);
|
||||
markdown_mdoc(curp->outdata, meta);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (man->macroset == MACROSET_MAN) {
|
||||
if (curp->outtype != OUTT_TREE || !curp->outopts->noval)
|
||||
man_validate(man);
|
||||
if (meta->macroset == MACROSET_MAN) {
|
||||
switch (curp->outtype) {
|
||||
case OUTT_HTML:
|
||||
html_man(curp->outdata, man);
|
||||
html_man(curp->outdata, meta);
|
||||
break;
|
||||
case OUTT_TREE:
|
||||
tree_man(curp->outdata, man);
|
||||
tree_man(curp->outdata, meta);
|
||||
break;
|
||||
case OUTT_MAN:
|
||||
man_man(curp->outdata, man);
|
||||
mparse_copy(curp->mp);
|
||||
break;
|
||||
case OUTT_PDF:
|
||||
case OUTT_ASCII:
|
||||
case OUTT_UTF8:
|
||||
case OUTT_LOCALE:
|
||||
case OUTT_PS:
|
||||
terminal_man(curp->outdata, man);
|
||||
terminal_man(curp->outdata, meta);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (curp->mmin < MANDOCERR_STYLE)
|
||||
check_xr(file);
|
||||
mparse_updaterc(curp->mp, &rc);
|
||||
if (mandoc_msg_getmin() < MANDOCERR_STYLE)
|
||||
check_xr();
|
||||
}
|
||||
|
||||
static void
|
||||
check_xr(const char *file)
|
||||
check_xr(void)
|
||||
{
|
||||
static struct manpaths paths;
|
||||
struct mansearch search;
|
||||
struct mandoc_xr *xr;
|
||||
char *cp;
|
||||
size_t sz;
|
||||
|
||||
if (paths.sz == 0)
|
||||
@ -915,13 +922,12 @@ check_xr(const char *file)
|
||||
if (fs_search(&search, &paths, 1, &xr->name, NULL, &sz))
|
||||
continue;
|
||||
if (xr->count == 1)
|
||||
mandoc_asprintf(&cp, "Xr %s %s", xr->name, xr->sec);
|
||||
mandoc_msg(MANDOCERR_XR_BAD, xr->line,
|
||||
xr->pos + 1, "Xr %s %s", xr->name, xr->sec);
|
||||
else
|
||||
mandoc_asprintf(&cp, "Xr %s %s (%d times)",
|
||||
mandoc_msg(MANDOCERR_XR_BAD, xr->line,
|
||||
xr->pos + 1, "Xr %s %s (%d times)",
|
||||
xr->name, xr->sec, xr->count);
|
||||
mmsg(MANDOCERR_XR_BAD, MANDOCLEVEL_STYLE,
|
||||
file, xr->line, xr->pos + 1, cp);
|
||||
free(cp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1020,8 +1026,7 @@ passthrough(const char *file, int fd, int synopsis_only)
|
||||
fail:
|
||||
free(line);
|
||||
warn("%s: SYSERR: %s", file, syscall);
|
||||
if (rc < MANDOCLEVEL_SYSERR)
|
||||
rc = MANDOCLEVEL_SYSERR;
|
||||
mandoc_msg_setrc(MANDOCLEVEL_SYSERR);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1063,8 +1068,8 @@ toptions(struct curparse *curp, char *arg)
|
||||
curp->outtype = OUTT_ASCII;
|
||||
else if (0 == strcmp(arg, "lint")) {
|
||||
curp->outtype = OUTT_LINT;
|
||||
curp->mmin = MANDOCERR_BASE;
|
||||
mmsg_stream = stdout;
|
||||
mandoc_msg_setoutfile(stdout);
|
||||
mandoc_msg_setmin(MANDOCERR_BASE);
|
||||
} else if (0 == strcmp(arg, "tree"))
|
||||
curp->outtype = OUTT_TREE;
|
||||
else if (0 == strcmp(arg, "man"))
|
||||
@ -1115,29 +1120,29 @@ woptions(struct curparse *curp, char *arg)
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
curp->mmin = MANDOCERR_BASE;
|
||||
mandoc_msg_setmin(MANDOCERR_BASE);
|
||||
break;
|
||||
case 3:
|
||||
curp->mmin = MANDOCERR_STYLE;
|
||||
mandoc_msg_setmin(MANDOCERR_STYLE);
|
||||
break;
|
||||
case 4:
|
||||
curp->mmin = MANDOCERR_WARNING;
|
||||
mandoc_msg_setmin(MANDOCERR_WARNING);
|
||||
break;
|
||||
case 5:
|
||||
curp->mmin = MANDOCERR_ERROR;
|
||||
mandoc_msg_setmin(MANDOCERR_ERROR);
|
||||
break;
|
||||
case 6:
|
||||
curp->mmin = MANDOCERR_UNSUPP;
|
||||
mandoc_msg_setmin(MANDOCERR_UNSUPP);
|
||||
break;
|
||||
case 7:
|
||||
curp->mmin = MANDOCERR_MAX;
|
||||
mandoc_msg_setmin(MANDOCERR_MAX);
|
||||
break;
|
||||
case 8:
|
||||
curp->mmin = MANDOCERR_BASE;
|
||||
mandoc_msg_setmin(MANDOCERR_BASE);
|
||||
curp->os_e = MANDOC_OS_OPENBSD;
|
||||
break;
|
||||
case 9:
|
||||
curp->mmin = MANDOCERR_BASE;
|
||||
mandoc_msg_setmin(MANDOCERR_BASE);
|
||||
curp->os_e = MANDOC_OS_NETBSD;
|
||||
break;
|
||||
default:
|
||||
@ -1148,29 +1153,6 @@ woptions(struct curparse *curp, char *arg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
mmsg(enum mandocerr t, enum mandoclevel lvl,
|
||||
const char *file, int line, int col, const char *msg)
|
||||
{
|
||||
const char *mparse_msg;
|
||||
|
||||
fprintf(mmsg_stream, "%s: %s:", getprogname(),
|
||||
file == NULL ? "<stdin>" : file);
|
||||
|
||||
if (line)
|
||||
fprintf(mmsg_stream, "%d:%d:", line, col + 1);
|
||||
|
||||
fprintf(mmsg_stream, " %s", mparse_strlevel(lvl));
|
||||
|
||||
if ((mparse_msg = mparse_strerror(t)) != NULL)
|
||||
fprintf(mmsg_stream, ": %s", mparse_msg);
|
||||
|
||||
if (msg)
|
||||
fprintf(mmsg_stream, ": %s", msg);
|
||||
|
||||
fputc('\n', mmsg_stream);
|
||||
}
|
||||
|
||||
static pid_t
|
||||
spawn_pager(struct tag_files *tag_files)
|
||||
{
|
||||
@ -1179,8 +1161,10 @@ spawn_pager(struct tag_files *tag_files)
|
||||
char *argv[MAX_PAGER_ARGS];
|
||||
const char *pager;
|
||||
char *cp;
|
||||
#if HAVE_LESS_T
|
||||
size_t cmdlen;
|
||||
int argc;
|
||||
#endif
|
||||
int argc, use_ofn;
|
||||
pid_t pager_pid;
|
||||
|
||||
pager = getenv("MANPAGER");
|
||||
@ -1196,7 +1180,7 @@ spawn_pager(struct tag_files *tag_files)
|
||||
*/
|
||||
|
||||
argc = 0;
|
||||
while (argc + 4 < MAX_PAGER_ARGS) {
|
||||
while (argc + 5 < MAX_PAGER_ARGS) {
|
||||
argv[argc++] = cp;
|
||||
cp = strchr(cp, ' ');
|
||||
if (cp == NULL)
|
||||
@ -1210,14 +1194,23 @@ spawn_pager(struct tag_files *tag_files)
|
||||
|
||||
/* For less(1), use the tag file. */
|
||||
|
||||
use_ofn = 1;
|
||||
#if HAVE_LESS_T
|
||||
if ((cmdlen = strlen(argv[0])) >= 4) {
|
||||
cp = argv[0] + cmdlen - 4;
|
||||
if (strcmp(cp, "less") == 0) {
|
||||
argv[argc++] = mandoc_strdup("-T");
|
||||
argv[argc++] = tag_files->tfn;
|
||||
if (tag_files->tagname != NULL) {
|
||||
argv[argc++] = mandoc_strdup("-t");
|
||||
argv[argc++] = tag_files->tagname;
|
||||
use_ofn = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
argv[argc++] = tag_files->ofn;
|
||||
#endif
|
||||
if (use_ofn)
|
||||
argv[argc++] = tag_files->ofn;
|
||||
argv[argc] = NULL;
|
||||
|
||||
switch (pager_pid = fork()) {
|
||||
|
24
main.h
24
main.h
@ -1,7 +1,7 @@
|
||||
/* $Id: main.h,v 1.27 2017/03/03 14:23:23 schwarze Exp $ */
|
||||
/* $Id: main.h,v 1.30 2019/03/03 13:02:11 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2014, 2015, 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,7 +16,7 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
struct roff_man;
|
||||
struct roff_meta;
|
||||
struct manoutput;
|
||||
|
||||
/*
|
||||
@ -27,15 +27,15 @@ struct manoutput;
|
||||
*/
|
||||
|
||||
void *html_alloc(const struct manoutput *);
|
||||
void html_mdoc(void *, const struct roff_man *);
|
||||
void html_man(void *, const struct roff_man *);
|
||||
void html_mdoc(void *, const struct roff_meta *);
|
||||
void html_man(void *, const struct roff_meta *);
|
||||
void html_reset(void *);
|
||||
void html_free(void *);
|
||||
|
||||
void tree_mdoc(void *, const struct roff_man *);
|
||||
void tree_man(void *, const struct roff_man *);
|
||||
void tree_mdoc(void *, const struct roff_meta *);
|
||||
void tree_man(void *, const struct roff_meta *);
|
||||
|
||||
void man_mdoc(void *, const struct roff_man *);
|
||||
void man_man(void *, const struct roff_man *);
|
||||
void man_mdoc(void *, const struct roff_meta *);
|
||||
|
||||
void *locale_alloc(const struct manoutput *);
|
||||
void *utf8_alloc(const struct manoutput *);
|
||||
@ -46,8 +46,8 @@ void *pdf_alloc(const struct manoutput *);
|
||||
void *ps_alloc(const struct manoutput *);
|
||||
void pspdf_free(void *);
|
||||
|
||||
void terminal_mdoc(void *, const struct roff_man *);
|
||||
void terminal_man(void *, const struct roff_man *);
|
||||
void terminal_mdoc(void *, const struct roff_meta *);
|
||||
void terminal_man(void *, const struct roff_meta *);
|
||||
void terminal_sepline(void *);
|
||||
|
||||
void markdown_mdoc(void *, const struct roff_man *);
|
||||
void markdown_mdoc(void *, const struct roff_meta *);
|
||||
|
25
man.1
25
man.1
@ -1,9 +1,9 @@
|
||||
.\" $Id: man.1,v 1.33 2018/04/19 23:41:16 schwarze Exp $
|
||||
.\" $Id: man.1,v 1.35 2019/03/09 15:55:01 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-2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
.\" Copyright (c) 2010, 2011, 2014-2018 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: April 19 2018 $
|
||||
.Dd $Mdocdate: March 9 2019 $
|
||||
.Dt MAN 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -218,12 +218,24 @@ Guidelines for writing
|
||||
man pages can be found in
|
||||
.Xr mdoc 7 .
|
||||
.Pp
|
||||
The
|
||||
.Xr mandoc.db 5
|
||||
database is used for looking up manual page entries.
|
||||
In cases where the database is absent, outdated, or corrupt,
|
||||
.Nm
|
||||
falls back to looking for files called
|
||||
.Ar name . Ns Ar section .
|
||||
If both a formatted and an unformatted version of the same manual page,
|
||||
for example
|
||||
.Pa cat1/foo.0
|
||||
and
|
||||
.Pa man1/foo.1 ,
|
||||
exist in the same directory, only the unformatted version is used.
|
||||
The database is kept up to date with
|
||||
.Xr makewhatis 8 ,
|
||||
which is run by the
|
||||
.Xr weekly 8
|
||||
maintenance script.
|
||||
.Sh ENVIRONMENT
|
||||
.Bl -tag -width MANPATHX
|
||||
.It Ev MACHINE
|
||||
@ -266,6 +278,13 @@ and
|
||||
can be used to move to the next and to the previous place providing
|
||||
information about the term last searched for with
|
||||
.Ic :t .
|
||||
The
|
||||
.Fl O Cm tag Ns Op = Ns Ar term
|
||||
option documented in the
|
||||
.Xr mandoc 1
|
||||
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
|
||||
|
170
man.c
170
man.c
@ -1,7 +1,7 @@
|
||||
/* $Id: man.c,v 1.176 2017/06/28 12:52:45 schwarze Exp $ */
|
||||
/* $Id: man.c,v 1.187 2019/01/05 00:36:50 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2013-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2011 Joerg Sonnenberger <joerg@netbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
@ -35,7 +35,7 @@
|
||||
#include "roff_int.h"
|
||||
#include "libman.h"
|
||||
|
||||
static void man_descope(struct roff_man *, int, int);
|
||||
static char *man_hasc(char *);
|
||||
static int man_ptext(struct roff_man *, int, char *, int);
|
||||
static int man_pmacro(struct roff_man *, int, char *, int);
|
||||
|
||||
@ -52,38 +52,62 @@ man_parseln(struct roff_man *man, int ln, char *buf, int offs)
|
||||
man_ptext(man, ln, buf, offs);
|
||||
}
|
||||
|
||||
static void
|
||||
man_descope(struct roff_man *man, int line, int offs)
|
||||
/*
|
||||
* If the string ends with \c, return a pointer to the backslash.
|
||||
* Otherwise, return NULL.
|
||||
*/
|
||||
static char *
|
||||
man_hasc(char *start)
|
||||
{
|
||||
char *cp, *ep;
|
||||
|
||||
ep = strchr(start, '\0') - 2;
|
||||
if (ep < start || ep[0] != '\\' || ep[1] != 'c')
|
||||
return NULL;
|
||||
for (cp = ep; cp > start; cp--)
|
||||
if (cp[-1] != '\\')
|
||||
break;
|
||||
return (ep - cp) % 2 ? NULL : ep;
|
||||
}
|
||||
|
||||
void
|
||||
man_descope(struct roff_man *man, int line, int offs, char *start)
|
||||
{
|
||||
/* Trailing \c keeps next-line scope open. */
|
||||
|
||||
if (start != NULL && man_hasc(start) != NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Co-ordinate what happens with having a next-line scope open:
|
||||
* first close out the element scope (if applicable), then close
|
||||
* out the block scope (also if applicable).
|
||||
* first close out the element scopes (if applicable),
|
||||
* then close out the block scope (also if applicable).
|
||||
*/
|
||||
|
||||
if (man->flags & MAN_ELINE) {
|
||||
while (man->last->parent->type != ROFFT_ROOT &&
|
||||
man_macro(man->last->parent->tok)->flags & MAN_ESCOPED)
|
||||
man_unscope(man, man->last->parent);
|
||||
man->flags &= ~MAN_ELINE;
|
||||
man_unscope(man, man->last->parent);
|
||||
}
|
||||
if ( ! (man->flags & MAN_BLINE))
|
||||
return;
|
||||
man->flags &= ~MAN_BLINE;
|
||||
man_unscope(man, man->last->parent);
|
||||
roff_body_alloc(man, line, offs, man->last->tok);
|
||||
man->flags &= ~(MAN_BLINE | ROFF_NONOFILL);
|
||||
}
|
||||
|
||||
static int
|
||||
man_ptext(struct roff_man *man, int line, char *buf, int offs)
|
||||
{
|
||||
int i;
|
||||
const char *cp, *sp;
|
||||
char *ep;
|
||||
|
||||
/* Literal free-form text whitespace is preserved. */
|
||||
/* In no-fill mode, whitespace is preserved on text lines. */
|
||||
|
||||
if (man->flags & MAN_LITERAL) {
|
||||
if (man->flags & ROFF_NOFILL) {
|
||||
roff_word_alloc(man, line, offs, buf + offs);
|
||||
man_descope(man, line, offs);
|
||||
man_descope(man, line, offs, buf + offs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -98,26 +122,15 @@ man_ptext(struct roff_man *man, int line, char *buf, int offs)
|
||||
|
||||
if (buf[i] == '\0') {
|
||||
if (man->flags & (MAN_ELINE | MAN_BLINE)) {
|
||||
mandoc_msg(MANDOCERR_BLK_BLANK, man->parse,
|
||||
line, 0, NULL);
|
||||
mandoc_msg(MANDOCERR_BLK_BLANK, line, 0, NULL);
|
||||
return 1;
|
||||
}
|
||||
if (man->last->tok == MAN_SH || man->last->tok == MAN_SS)
|
||||
return 1;
|
||||
switch (man->last->type) {
|
||||
case ROFFT_TEXT:
|
||||
sp = man->last->string;
|
||||
cp = ep = strchr(sp, '\0') - 2;
|
||||
if (cp < sp || cp[0] != '\\' || cp[1] != 'c')
|
||||
break;
|
||||
while (cp > sp && cp[-1] == '\\')
|
||||
cp--;
|
||||
if ((ep - cp) % 2)
|
||||
break;
|
||||
if (man->last->type == ROFFT_TEXT &&
|
||||
((ep = man_hasc(man->last->string)) != NULL)) {
|
||||
*ep = '\0';
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
roff_elem_alloc(man, line, offs, ROFF_sp);
|
||||
man->next = ROFF_NEXT_SIBLING;
|
||||
@ -134,8 +147,7 @@ man_ptext(struct roff_man *man, int line, char *buf, int offs)
|
||||
|
||||
if (' ' == buf[i - 1] || '\t' == buf[i - 1]) {
|
||||
if (i > 1 && '\\' != buf[i - 2])
|
||||
mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
|
||||
line, i - 1, NULL);
|
||||
mandoc_msg(MANDOCERR_SPACE_EOL, line, i - 1, NULL);
|
||||
|
||||
for (--i; i && ' ' == buf[i]; i--)
|
||||
/* Spin back to non-space. */ ;
|
||||
@ -157,7 +169,7 @@ man_ptext(struct roff_man *man, int line, char *buf, int offs)
|
||||
if (mandoc_eos(buf, (size_t)i))
|
||||
man->last->flags |= NODE_EOS;
|
||||
|
||||
man_descope(man, line, offs);
|
||||
man_descope(man, line, offs, buf + offs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -180,8 +192,7 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
|
||||
if (sz > 0 && sz < 4)
|
||||
tok = roffhash_find(man->manmac, buf + ppos, sz);
|
||||
if (tok == TOKEN_NONE) {
|
||||
mandoc_msg(MANDOCERR_MACRO, man->parse,
|
||||
ln, ppos, buf + ppos - 1);
|
||||
mandoc_msg(MANDOCERR_MACRO, ln, ppos, "%s", buf + ppos - 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -211,8 +222,7 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
|
||||
*/
|
||||
|
||||
if (buf[offs] == '\0' && buf[offs - 1] == ' ')
|
||||
mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
|
||||
ln, offs - 1, NULL);
|
||||
mandoc_msg(MANDOCERR_SPACE_EOL, ln, offs - 1, NULL);
|
||||
|
||||
/*
|
||||
* Some macros break next-line scopes; otherwise, remember
|
||||
@ -230,16 +240,12 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
|
||||
* page, that's very likely what the author intended.
|
||||
*/
|
||||
|
||||
if (bline) {
|
||||
cp = strchr(buf + offs, '\0') - 2;
|
||||
if (cp >= buf && cp[0] == '\\' && cp[1] == 'c')
|
||||
bline = 0;
|
||||
}
|
||||
if (bline && man_hasc(buf + offs))
|
||||
bline = 0;
|
||||
|
||||
/* Call to handler... */
|
||||
|
||||
assert(man_macros[tok].fp);
|
||||
(*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf);
|
||||
(*man_macro(tok)->fp)(man, tok, ln, ppos, &offs, buf);
|
||||
|
||||
/* In quick mode (for mandocdb), abort after the NAME section. */
|
||||
|
||||
@ -256,15 +262,15 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
|
||||
* unless the next-line scope is allowed to continue.
|
||||
*/
|
||||
|
||||
if ( ! bline || man->flags & MAN_ELINE ||
|
||||
man_macros[tok].flags & MAN_NSCOPED)
|
||||
if (bline == 0 ||
|
||||
(man->flags & MAN_BLINE) == 0 ||
|
||||
man->flags & MAN_ELINE ||
|
||||
man_macro(tok)->flags & MAN_NSCOPED)
|
||||
return 1;
|
||||
|
||||
assert(man->flags & MAN_BLINE);
|
||||
man->flags &= ~MAN_BLINE;
|
||||
|
||||
man_unscope(man, man->last->parent);
|
||||
roff_body_alloc(man, ln, ppos, man->last->tok);
|
||||
man->flags &= ~(MAN_BLINE | ROFF_NONOFILL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -280,17 +286,17 @@ man_breakscope(struct roff_man *man, int tok)
|
||||
*/
|
||||
|
||||
if (man->flags & MAN_ELINE && (tok < MAN_TH ||
|
||||
! (man_macros[tok].flags & MAN_NSCOPED))) {
|
||||
(man_macro(tok)->flags & MAN_NSCOPED) == 0)) {
|
||||
n = man->last;
|
||||
if (n->type == ROFFT_TEXT)
|
||||
n = n->parent;
|
||||
if (n->tok < MAN_TH ||
|
||||
man_macros[n->tok].flags & MAN_NSCOPED)
|
||||
(man_macro(n->tok)->flags & (MAN_NSCOPED | MAN_ESCOPED))
|
||||
== MAN_NSCOPED)
|
||||
n = n->parent;
|
||||
|
||||
mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
|
||||
n->line, n->pos, "%s breaks %s",
|
||||
roff_name[tok], roff_name[n->tok]);
|
||||
mandoc_msg(MANDOCERR_BLK_LINE, n->line, n->pos,
|
||||
"%s breaks %s", roff_name[tok], roff_name[n->tok]);
|
||||
|
||||
roff_node_delete(man, n);
|
||||
man->flags &= ~MAN_ELINE;
|
||||
@ -302,12 +308,12 @@ man_breakscope(struct roff_man *man, int tok)
|
||||
*/
|
||||
|
||||
if (man->flags & MAN_BLINE &&
|
||||
(tok == MAN_nf || tok == MAN_fi) &&
|
||||
(tok == ROFF_nf || tok == ROFF_fi) &&
|
||||
(man->last->tok == MAN_SH || man->last->tok == MAN_SS)) {
|
||||
n = man->last;
|
||||
man_unscope(man, n);
|
||||
roff_body_alloc(man, n->line, n->pos, n->tok);
|
||||
man->flags &= ~MAN_BLINE;
|
||||
man->flags &= ~(MAN_BLINE | ROFF_NONOFILL);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -316,68 +322,24 @@ man_breakscope(struct roff_man *man, int tok)
|
||||
* Delete the block that is being broken.
|
||||
*/
|
||||
|
||||
if (man->flags & MAN_BLINE && (tok < MAN_TH ||
|
||||
man_macros[tok].flags & MAN_BSCOPE)) {
|
||||
if (man->flags & MAN_BLINE && tok != ROFF_nf && tok != ROFF_fi &&
|
||||
(tok < MAN_TH || man_macro(tok)->flags & MAN_XSCOPE)) {
|
||||
n = man->last;
|
||||
if (n->type == ROFFT_TEXT)
|
||||
n = n->parent;
|
||||
if (n->tok < MAN_TH ||
|
||||
(man_macros[n->tok].flags & MAN_BSCOPE) == 0)
|
||||
(man_macro(n->tok)->flags & MAN_XSCOPE) == 0)
|
||||
n = n->parent;
|
||||
|
||||
assert(n->type == ROFFT_HEAD);
|
||||
n = n->parent;
|
||||
assert(n->type == ROFFT_BLOCK);
|
||||
assert(man_macros[n->tok].flags & MAN_SCOPED);
|
||||
assert(man_macro(n->tok)->flags & MAN_BSCOPED);
|
||||
|
||||
mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
|
||||
n->line, n->pos, "%s breaks %s",
|
||||
roff_name[tok], roff_name[n->tok]);
|
||||
mandoc_msg(MANDOCERR_BLK_LINE, n->line, n->pos,
|
||||
"%s breaks %s", roff_name[tok], roff_name[n->tok]);
|
||||
|
||||
roff_node_delete(man, n);
|
||||
man->flags &= ~MAN_BLINE;
|
||||
man->flags &= ~(MAN_BLINE | ROFF_NONOFILL);
|
||||
}
|
||||
}
|
||||
|
||||
const struct mparse *
|
||||
man_mparse(const struct roff_man *man)
|
||||
{
|
||||
|
||||
assert(man && man->parse);
|
||||
return man->parse;
|
||||
}
|
||||
|
||||
void
|
||||
man_state(struct roff_man *man, struct roff_node *n)
|
||||
{
|
||||
|
||||
switch(n->tok) {
|
||||
case MAN_nf:
|
||||
case MAN_EX:
|
||||
if (man->flags & MAN_LITERAL && ! (n->flags & NODE_VALID))
|
||||
mandoc_msg(MANDOCERR_NF_SKIP, man->parse,
|
||||
n->line, n->pos, "nf");
|
||||
man->flags |= MAN_LITERAL;
|
||||
break;
|
||||
case MAN_fi:
|
||||
case MAN_EE:
|
||||
if ( ! (man->flags & MAN_LITERAL) &&
|
||||
! (n->flags & NODE_VALID))
|
||||
mandoc_msg(MANDOCERR_FI_SKIP, man->parse,
|
||||
n->line, n->pos, "fi");
|
||||
man->flags &= ~MAN_LITERAL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
man->last->flags |= NODE_VALID;
|
||||
}
|
||||
|
||||
void
|
||||
man_validate(struct roff_man *man)
|
||||
{
|
||||
|
||||
man->last = man->first;
|
||||
man_node_validate(man);
|
||||
man->flags &= ~MAN_LITERAL;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
.\" $Id: man.conf.5,v 1.5 2017/08/22 18:17:52 schwarze Exp $
|
||||
.\" $Id: man.conf.5,v 1.6 2018/10/02 14:56:47 schwarze Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
|
||||
.\" Copyright (c) 2015, 2017 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: August 22 2017 $
|
||||
.Dd $Mdocdate: October 2 2018 $
|
||||
.Dt MAN.CONF 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -98,6 +98,7 @@ manual.
|
||||
.It Ic man Ta string Ta Cm html Ta path for \&Xr links
|
||||
.It Ic paper Ta string Ta Cm ps , pdf Ta paper size
|
||||
.It Ic style Ta string Ta Cm html Ta CSS file
|
||||
.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
|
||||
|
3
man.h
3
man.h
@ -1,4 +1,4 @@
|
||||
/* $Id: man.h,v 1.78 2017/04/24 23:06:18 schwarze Exp $ */
|
||||
/* $Id: man.h,v 1.79 2018/08/23 19:33:27 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
|
||||
@ -18,5 +18,4 @@
|
||||
|
||||
struct roff_man;
|
||||
|
||||
const struct mparse *man_mparse(const struct roff_man *);
|
||||
void man_validate(struct roff_man *);
|
||||
|
471
man_html.c
471
man_html.c
@ -1,7 +1,7 @@
|
||||
/* $Id: man_html.c,v 1.153 2018/07/27 17:49:31 schwarze Exp $ */
|
||||
/* $Id: man_html.c,v 1.173 2019/03/02 16:30:53 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2013,2014,2015,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* 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
|
||||
@ -33,26 +33,22 @@
|
||||
#include "html.h"
|
||||
#include "main.h"
|
||||
|
||||
/* FIXME: have PD set the default vspace width. */
|
||||
|
||||
#define MAN_ARGS const struct roff_meta *man, \
|
||||
const struct roff_node *n, \
|
||||
struct html *h
|
||||
|
||||
struct htmlman {
|
||||
struct man_html_act {
|
||||
int (*pre)(MAN_ARGS);
|
||||
int (*post)(MAN_ARGS);
|
||||
};
|
||||
|
||||
static void print_bvspace(struct html *,
|
||||
const struct roff_node *);
|
||||
static void print_man_head(const struct roff_meta *,
|
||||
struct html *);
|
||||
static void print_man_nodelist(MAN_ARGS);
|
||||
static void print_man_node(MAN_ARGS);
|
||||
static int fillmode(struct html *, int);
|
||||
static char list_continues(const struct roff_node *,
|
||||
const struct roff_node *);
|
||||
static int man_B_pre(MAN_ARGS);
|
||||
static int man_HP_pre(MAN_ARGS);
|
||||
static int man_IP_pre(MAN_ARGS);
|
||||
static int man_I_pre(MAN_ARGS);
|
||||
static int man_OP_pre(MAN_ARGS);
|
||||
@ -60,8 +56,9 @@ static int man_PP_pre(MAN_ARGS);
|
||||
static int man_RS_pre(MAN_ARGS);
|
||||
static int man_SH_pre(MAN_ARGS);
|
||||
static int man_SM_pre(MAN_ARGS);
|
||||
static int man_SS_pre(MAN_ARGS);
|
||||
static int man_SY_pre(MAN_ARGS);
|
||||
static int man_UR_pre(MAN_ARGS);
|
||||
static int man_abort_pre(MAN_ARGS);
|
||||
static int man_alt_pre(MAN_ARGS);
|
||||
static int man_ign_pre(MAN_ARGS);
|
||||
static int man_in_pre(MAN_ARGS);
|
||||
@ -70,16 +67,17 @@ static void man_root_post(const struct roff_meta *,
|
||||
static void man_root_pre(const struct roff_meta *,
|
||||
struct html *);
|
||||
|
||||
static const struct htmlman __mans[MAN_MAX - MAN_TH] = {
|
||||
static const struct man_html_act man_html_acts[MAN_MAX - MAN_TH] = {
|
||||
{ NULL, NULL }, /* TH */
|
||||
{ man_SH_pre, NULL }, /* SH */
|
||||
{ man_SS_pre, NULL }, /* SS */
|
||||
{ man_SH_pre, NULL }, /* SS */
|
||||
{ man_IP_pre, NULL }, /* TP */
|
||||
{ man_PP_pre, NULL }, /* LP */
|
||||
{ man_IP_pre, NULL }, /* TQ */
|
||||
{ man_abort_pre, NULL }, /* LP */
|
||||
{ man_PP_pre, NULL }, /* PP */
|
||||
{ man_PP_pre, NULL }, /* P */
|
||||
{ man_abort_pre, NULL }, /* P */
|
||||
{ man_IP_pre, NULL }, /* IP */
|
||||
{ man_HP_pre, NULL }, /* HP */
|
||||
{ man_PP_pre, NULL }, /* HP */
|
||||
{ man_SM_pre, NULL }, /* SM */
|
||||
{ man_SM_pre, NULL }, /* SB */
|
||||
{ man_alt_pre, NULL }, /* BI */
|
||||
@ -91,8 +89,6 @@ static const struct htmlman __mans[MAN_MAX - MAN_TH] = {
|
||||
{ man_I_pre, NULL }, /* I */
|
||||
{ man_alt_pre, NULL }, /* IR */
|
||||
{ man_alt_pre, NULL }, /* RI */
|
||||
{ NULL, NULL }, /* nf */
|
||||
{ NULL, NULL }, /* fi */
|
||||
{ NULL, NULL }, /* RE */
|
||||
{ man_RS_pre, NULL }, /* RS */
|
||||
{ man_ign_pre, NULL }, /* DT */
|
||||
@ -100,6 +96,8 @@ static const struct htmlman __mans[MAN_MAX - MAN_TH] = {
|
||||
{ man_ign_pre, NULL }, /* PD */
|
||||
{ man_ign_pre, NULL }, /* AT */
|
||||
{ man_in_pre, NULL }, /* in */
|
||||
{ man_SY_pre, NULL }, /* SY */
|
||||
{ NULL, NULL }, /* YS */
|
||||
{ man_OP_pre, NULL }, /* OP */
|
||||
{ NULL, NULL }, /* EX */
|
||||
{ NULL, NULL }, /* EE */
|
||||
@ -108,34 +106,10 @@ static const struct htmlman __mans[MAN_MAX - MAN_TH] = {
|
||||
{ man_UR_pre, NULL }, /* MT */
|
||||
{ NULL, NULL }, /* ME */
|
||||
};
|
||||
static const struct htmlman *const mans = __mans - MAN_TH;
|
||||
|
||||
|
||||
/*
|
||||
* Printing leading vertical space before a block.
|
||||
* This is used for the paragraph macros.
|
||||
* The rules are pretty simple, since there's very little nesting going
|
||||
* on here. Basically, if we're the first within another block (SS/SH),
|
||||
* then don't emit vertical space. If we are (RS), then do. If not the
|
||||
* first, print it.
|
||||
*/
|
||||
static void
|
||||
print_bvspace(struct html *h, const struct roff_node *n)
|
||||
{
|
||||
|
||||
if (n->body && n->body->child)
|
||||
if (n->body->child->type == ROFFT_TBL)
|
||||
return;
|
||||
|
||||
if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS)
|
||||
if (NULL == n->prev)
|
||||
return;
|
||||
|
||||
print_paragraph(h);
|
||||
}
|
||||
|
||||
void
|
||||
html_man(void *arg, const struct roff_man *man)
|
||||
html_man(void *arg, const struct roff_meta *man)
|
||||
{
|
||||
struct html *h;
|
||||
struct roff_node *n;
|
||||
@ -147,19 +121,19 @@ html_man(void *arg, const struct roff_man *man)
|
||||
if ((h->oflags & HTML_FRAGMENT) == 0) {
|
||||
print_gen_decls(h);
|
||||
print_otag(h, TAG_HTML, "");
|
||||
if (n->type == ROFFT_COMMENT)
|
||||
if (n != NULL && n->type == ROFFT_COMMENT)
|
||||
print_gen_comment(h, n);
|
||||
t = print_otag(h, TAG_HEAD, "");
|
||||
print_man_head(&man->meta, h);
|
||||
print_man_head(man, h);
|
||||
print_tagq(h, t);
|
||||
print_otag(h, TAG_BODY, "");
|
||||
}
|
||||
|
||||
man_root_pre(&man->meta, h);
|
||||
man_root_pre(man, h);
|
||||
t = print_otag(h, TAG_DIV, "c", "manual-text");
|
||||
print_man_nodelist(&man->meta, n, h);
|
||||
print_man_nodelist(man, n, h);
|
||||
print_tagq(h, t);
|
||||
man_root_post(&man->meta, h);
|
||||
man_root_post(man, h);
|
||||
print_tagq(h, NULL);
|
||||
}
|
||||
|
||||
@ -178,7 +152,6 @@ print_man_head(const struct roff_meta *man, struct html *h)
|
||||
static void
|
||||
print_man_nodelist(MAN_ARGS)
|
||||
{
|
||||
|
||||
while (n != NULL) {
|
||||
print_man_node(man, n, h);
|
||||
n = n->next;
|
||||
@ -188,99 +161,33 @@ print_man_nodelist(MAN_ARGS)
|
||||
static void
|
||||
print_man_node(MAN_ARGS)
|
||||
{
|
||||
static int want_fillmode = MAN_fi;
|
||||
static int save_fillmode;
|
||||
|
||||
struct tag *t;
|
||||
int child;
|
||||
|
||||
/*
|
||||
* Handle fill mode switch requests up front,
|
||||
* they would just cause trouble in the subsequent code.
|
||||
*/
|
||||
|
||||
switch (n->tok) {
|
||||
case MAN_nf:
|
||||
case MAN_EX:
|
||||
want_fillmode = MAN_nf;
|
||||
if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
|
||||
return;
|
||||
case MAN_fi:
|
||||
case MAN_EE:
|
||||
want_fillmode = MAN_fi;
|
||||
if (fillmode(h, 0) == MAN_fi)
|
||||
print_otag(h, TAG_BR, "");
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set up fill mode for the upcoming node. */
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
save_fillmode = 0;
|
||||
/* Some block macros suspend or cancel .nf. */
|
||||
switch (n->tok) {
|
||||
case MAN_TP: /* Tagged paragraphs */
|
||||
case MAN_IP: /* temporarily disable .nf */
|
||||
case MAN_HP: /* for the head. */
|
||||
save_fillmode = want_fillmode;
|
||||
/* FALLTHROUGH */
|
||||
case MAN_SH: /* Section headers */
|
||||
case MAN_SS: /* permanently cancel .nf. */
|
||||
want_fillmode = MAN_fi;
|
||||
/* FALLTHROUGH */
|
||||
case MAN_PP: /* These have no head. */
|
||||
case MAN_LP: /* They will simply */
|
||||
case MAN_P: /* reopen .nf in the body. */
|
||||
case MAN_RS:
|
||||
case MAN_UR:
|
||||
case MAN_MT:
|
||||
fillmode(h, MAN_fi);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ROFFT_TBL:
|
||||
fillmode(h, MAN_fi);
|
||||
break;
|
||||
case ROFFT_ELEM:
|
||||
/*
|
||||
* Some in-line macros produce tags and/or text
|
||||
* in the handler, so they require fill mode to be
|
||||
* configured up front just like for text nodes.
|
||||
* For the others, keep the traditional approach
|
||||
* of doing the same, for now.
|
||||
*/
|
||||
fillmode(h, want_fillmode);
|
||||
break;
|
||||
case ROFFT_TEXT:
|
||||
if (fillmode(h, want_fillmode) == MAN_fi &&
|
||||
want_fillmode == MAN_fi &&
|
||||
n->flags & NODE_LINE && *n->string == ' ' &&
|
||||
(h->flags & HTML_NONEWLINE) == 0)
|
||||
print_otag(h, TAG_BR, "");
|
||||
if (*n->string != '\0')
|
||||
break;
|
||||
print_paragraph(h);
|
||||
return;
|
||||
case ROFFT_COMMENT:
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Produce output for this node. */
|
||||
html_fillmode(h, n->flags & NODE_NOFILL ? ROFF_nf : ROFF_fi);
|
||||
|
||||
child = 1;
|
||||
switch (n->type) {
|
||||
case ROFFT_TEXT:
|
||||
if (*n->string == '\0') {
|
||||
print_endline(h);
|
||||
return;
|
||||
}
|
||||
if (*n->string == ' ' && n->flags & NODE_LINE &&
|
||||
(h->flags & HTML_NONEWLINE) == 0)
|
||||
print_endline(h);
|
||||
else if (n->flags & NODE_DELIMC)
|
||||
h->flags |= HTML_NOSPACE;
|
||||
t = h->tag;
|
||||
t->refcnt++;
|
||||
print_text(h, n->string);
|
||||
break;
|
||||
case ROFFT_EQN:
|
||||
t = h->tag;
|
||||
t->refcnt++;
|
||||
print_eqn(h, n->eqn);
|
||||
break;
|
||||
case ROFFT_TBL:
|
||||
@ -306,62 +213,51 @@ print_man_node(MAN_ARGS)
|
||||
* the "meta" table state. This will be reopened on the
|
||||
* next table element.
|
||||
*/
|
||||
if (h->tblt)
|
||||
if (h->tblt != NULL)
|
||||
print_tblclose(h);
|
||||
|
||||
t = h->tag;
|
||||
t->refcnt++;
|
||||
if (n->tok < ROFF_MAX) {
|
||||
roff_html_pre(h, n);
|
||||
child = 0;
|
||||
break;
|
||||
t->refcnt--;
|
||||
print_stagq(h, t);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(n->tok >= MAN_TH && n->tok < MAN_MAX);
|
||||
if (mans[n->tok].pre)
|
||||
child = (*mans[n->tok].pre)(man, n, h);
|
||||
|
||||
/* Some block macros resume .nf in the body. */
|
||||
if (save_fillmode && n->type == ROFFT_BODY)
|
||||
want_fillmode = save_fillmode;
|
||||
|
||||
if (man_html_acts[n->tok - MAN_TH].pre != NULL)
|
||||
child = (*man_html_acts[n->tok - MAN_TH].pre)(man,
|
||||
n, h);
|
||||
break;
|
||||
}
|
||||
|
||||
if (child && n->child)
|
||||
if (child && n->child != NULL)
|
||||
print_man_nodelist(man, n->child, h);
|
||||
|
||||
/* This will automatically close out any font scope. */
|
||||
print_stagq(h, t);
|
||||
|
||||
if (fillmode(h, 0) == MAN_nf &&
|
||||
n->next != NULL && n->next->flags & NODE_LINE)
|
||||
print_endline(h);
|
||||
}
|
||||
|
||||
/*
|
||||
* MAN_nf switches to no-fill mode, MAN_fi to fill mode.
|
||||
* Other arguments do not switch.
|
||||
* The old mode is returned.
|
||||
*/
|
||||
static int
|
||||
fillmode(struct html *h, int want)
|
||||
{
|
||||
struct tag *pre;
|
||||
int had;
|
||||
|
||||
for (pre = h->tag; pre != NULL; pre = pre->next)
|
||||
if (pre->tag == TAG_PRE)
|
||||
break;
|
||||
|
||||
had = pre == NULL ? MAN_fi : MAN_nf;
|
||||
|
||||
if (want && want != had) {
|
||||
if (want == MAN_nf)
|
||||
print_otag(h, TAG_PRE, "");
|
||||
else
|
||||
print_tagq(h, pre);
|
||||
t->refcnt--;
|
||||
if (n->type == ROFFT_BLOCK &&
|
||||
(n->tok == MAN_IP || n->tok == MAN_TP || n->tok == MAN_TQ)) {
|
||||
t = h->tag;
|
||||
while (t->tag != TAG_DL && t->tag != TAG_UL)
|
||||
t = t->next;
|
||||
/*
|
||||
* Close the list if no further item of the same type
|
||||
* follows; otherwise, close the item only.
|
||||
*/
|
||||
if (list_continues(n, n->next) == '\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);
|
||||
}
|
||||
return had;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -382,7 +278,7 @@ man_root_pre(const struct roff_meta *man, struct html *h)
|
||||
print_stagq(h, tt);
|
||||
|
||||
print_otag(h, TAG_TD, "c", "head-vol");
|
||||
if (NULL != man->vol)
|
||||
if (man->vol != NULL)
|
||||
print_text(h, man->vol);
|
||||
print_stagq(h, tt);
|
||||
|
||||
@ -405,7 +301,7 @@ man_root_post(const struct roff_meta *man, struct html *h)
|
||||
print_stagq(h, tt);
|
||||
|
||||
print_otag(h, TAG_TD, "c", "foot-os");
|
||||
if (man->os)
|
||||
if (man->os != NULL)
|
||||
print_text(h, man->os);
|
||||
print_tagq(h, t);
|
||||
}
|
||||
@ -413,13 +309,32 @@ man_root_post(const struct roff_meta *man, struct html *h)
|
||||
static int
|
||||
man_SH_pre(MAN_ARGS)
|
||||
{
|
||||
char *id;
|
||||
const char *class;
|
||||
char *id;
|
||||
enum htmltag tag;
|
||||
|
||||
if (n->type == ROFFT_HEAD) {
|
||||
if (n->tok == MAN_SH) {
|
||||
tag = TAG_H1;
|
||||
class = "Sh";
|
||||
} else {
|
||||
tag = TAG_H2;
|
||||
class = "Ss";
|
||||
}
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
html_close_paragraph(h);
|
||||
print_otag(h, TAG_SECTION, "c", class);
|
||||
break;
|
||||
case ROFFT_HEAD:
|
||||
id = html_make_id(n, 1);
|
||||
print_otag(h, TAG_H1, "cTi", "Sh", id);
|
||||
print_otag(h, tag, "ci", class, id);
|
||||
if (id != NULL)
|
||||
print_otag(h, TAG_A, "chR", "permalink", id);
|
||||
break;
|
||||
case ROFFT_BODY:
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -428,11 +343,11 @@ static int
|
||||
man_alt_pre(MAN_ARGS)
|
||||
{
|
||||
const struct roff_node *nn;
|
||||
struct tag *t;
|
||||
int i;
|
||||
enum htmltag fp;
|
||||
struct tag *t;
|
||||
|
||||
for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
|
||||
for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i++) {
|
||||
switch (n->tok) {
|
||||
case MAN_BI:
|
||||
fp = i % 2 ? TAG_I : TAG_B;
|
||||
@ -474,87 +389,134 @@ static int
|
||||
man_SM_pre(MAN_ARGS)
|
||||
{
|
||||
print_otag(h, TAG_SMALL, "");
|
||||
if (MAN_SB == n->tok)
|
||||
if (n->tok == MAN_SB)
|
||||
print_otag(h, TAG_B, "");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
man_SS_pre(MAN_ARGS)
|
||||
{
|
||||
char *id;
|
||||
|
||||
if (n->type == ROFFT_HEAD) {
|
||||
id = html_make_id(n, 1);
|
||||
print_otag(h, TAG_H2, "cTi", "Ss", id);
|
||||
if (id != NULL)
|
||||
print_otag(h, TAG_A, "chR", "permalink", id);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
man_PP_pre(MAN_ARGS)
|
||||
{
|
||||
|
||||
if (n->type == ROFFT_HEAD)
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
html_close_paragraph(h);
|
||||
break;
|
||||
case ROFFT_HEAD:
|
||||
return 0;
|
||||
else if (n->type == ROFFT_BLOCK)
|
||||
print_bvspace(h, n);
|
||||
|
||||
case ROFFT_BODY:
|
||||
if (n->child != NULL &&
|
||||
(n->child->flags & NODE_NOFILL) == 0)
|
||||
print_otag(h, TAG_P, "c",
|
||||
n->tok == MAN_PP ? "Pp" : "Pp HP");
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char
|
||||
list_continues(const struct roff_node *n1, const struct roff_node *n2)
|
||||
{
|
||||
const char *s1, *s2;
|
||||
char c1, c2;
|
||||
|
||||
if (n1 == NULL || n1->type != ROFFT_BLOCK ||
|
||||
n2 == NULL || n2->type != ROFFT_BLOCK)
|
||||
return '\0';
|
||||
if ((n1->tok == MAN_TP || n1->tok == MAN_TQ) &&
|
||||
(n2->tok == MAN_TP || n2->tok == MAN_TQ))
|
||||
return ' ';
|
||||
if (n1->tok != MAN_IP || n2->tok != MAN_IP)
|
||||
return '\0';
|
||||
n1 = n1->head->child;
|
||||
n2 = n2->head->child;
|
||||
s1 = n1 == NULL ? "" : n1->string;
|
||||
s2 = n2 == NULL ? "" : n2->string;
|
||||
c1 = strcmp(s1, "*") == 0 ? '*' :
|
||||
strcmp(s1, "\\-") == 0 ? '-' :
|
||||
strcmp(s1, "\\(bu") == 0 ? 'b' : ' ';
|
||||
c2 = strcmp(s2, "*") == 0 ? '*' :
|
||||
strcmp(s2, "\\-") == 0 ? '-' :
|
||||
strcmp(s2, "\\(bu") == 0 ? 'b' : ' ';
|
||||
return c1 != c2 ? '\0' : c1 == 'b' ? '*' : c1;
|
||||
}
|
||||
|
||||
static int
|
||||
man_IP_pre(MAN_ARGS)
|
||||
{
|
||||
const struct roff_node *nn;
|
||||
const char *list_class;
|
||||
enum htmltag list_elem, body_elem;
|
||||
char list_type;
|
||||
|
||||
if (n->type == ROFFT_BODY) {
|
||||
print_otag(h, TAG_DD, "");
|
||||
nn = n->type == ROFFT_BLOCK ? n : n->parent;
|
||||
if ((list_type = list_continues(nn->prev, nn)) == '\0') {
|
||||
/* Start a new list. */
|
||||
if ((list_type = list_continues(nn, nn->next)) == '\0')
|
||||
list_type = ' ';
|
||||
switch (list_type) {
|
||||
case ' ':
|
||||
list_class = "Bl-tag";
|
||||
list_elem = TAG_DL;
|
||||
break;
|
||||
case '*':
|
||||
list_class = "Bl-bullet";
|
||||
list_elem = TAG_UL;
|
||||
break;
|
||||
case '-':
|
||||
list_class = "Bl-dash";
|
||||
list_elem = TAG_UL;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
} else {
|
||||
/* Continue a list that was started earlier. */
|
||||
list_class = NULL;
|
||||
list_elem = TAG_MAX;
|
||||
}
|
||||
body_elem = list_type == ' ' ? TAG_DD : TAG_LI;
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
html_close_paragraph(h);
|
||||
if (list_elem != TAG_MAX)
|
||||
print_otag(h, list_elem, "c", list_class);
|
||||
return 1;
|
||||
} else if (n->type != ROFFT_HEAD) {
|
||||
print_otag(h, TAG_DL, "c", "Bl-tag");
|
||||
case ROFFT_HEAD:
|
||||
if (body_elem == TAG_LI)
|
||||
return 0;
|
||||
print_otag(h, TAG_DT, "");
|
||||
break;
|
||||
case ROFFT_BODY:
|
||||
print_otag(h, body_elem, "");
|
||||
return 1;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
/* FIXME: width specification. */
|
||||
|
||||
print_otag(h, TAG_DT, "");
|
||||
|
||||
/* For IP, only print the first header element. */
|
||||
|
||||
if (MAN_IP == n->tok && n->child)
|
||||
print_man_node(man, n->child, h);
|
||||
|
||||
/* For TP, only print next-line header elements. */
|
||||
|
||||
if (MAN_TP == n->tok) {
|
||||
switch(n->tok) {
|
||||
case MAN_IP: /* Only print the first header element. */
|
||||
if (n->child != NULL)
|
||||
print_man_node(man, n->child, h);
|
||||
break;
|
||||
case MAN_TP: /* Only print next-line header elements. */
|
||||
case MAN_TQ:
|
||||
nn = n->child;
|
||||
while (NULL != nn && 0 == (NODE_LINE & nn->flags))
|
||||
while (nn != NULL && (NODE_LINE & nn->flags) == 0)
|
||||
nn = nn->next;
|
||||
while (NULL != nn) {
|
||||
while (nn != NULL) {
|
||||
print_man_node(man, nn, h);
|
||||
nn = nn->next;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
man_HP_pre(MAN_ARGS)
|
||||
{
|
||||
if (n->type == ROFFT_HEAD)
|
||||
return 0;
|
||||
|
||||
if (n->type == ROFFT_BLOCK) {
|
||||
print_bvspace(h, n);
|
||||
print_otag(h, TAG_DIV, "c", "HP");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
man_OP_pre(MAN_ARGS)
|
||||
{
|
||||
@ -564,14 +526,14 @@ man_OP_pre(MAN_ARGS)
|
||||
h->flags |= HTML_NOSPACE;
|
||||
tt = print_otag(h, TAG_SPAN, "c", "Op");
|
||||
|
||||
if (NULL != (n = n->child)) {
|
||||
if ((n = n->child) != NULL) {
|
||||
print_otag(h, TAG_B, "");
|
||||
print_text(h, n->string);
|
||||
}
|
||||
|
||||
print_stagq(h, tt);
|
||||
|
||||
if (NULL != n && NULL != n->next) {
|
||||
if (n != NULL && n->next != NULL) {
|
||||
print_otag(h, TAG_I, "");
|
||||
print_text(h, n->next->string);
|
||||
}
|
||||
@ -606,17 +568,46 @@ man_in_pre(MAN_ARGS)
|
||||
static int
|
||||
man_ign_pre(MAN_ARGS)
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
man_RS_pre(MAN_ARGS)
|
||||
{
|
||||
if (n->type == ROFFT_HEAD)
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
html_close_paragraph(h);
|
||||
break;
|
||||
case ROFFT_HEAD:
|
||||
return 0;
|
||||
if (n->type == ROFFT_BLOCK)
|
||||
case ROFFT_BODY:
|
||||
print_otag(h, TAG_DIV, "c", "Bd-indent");
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
man_SY_pre(MAN_ARGS)
|
||||
{
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
html_close_paragraph(h);
|
||||
print_otag(h, TAG_TABLE, "c", "Nm");
|
||||
print_otag(h, TAG_TR, "");
|
||||
break;
|
||||
case ROFFT_HEAD:
|
||||
print_otag(h, TAG_TD, "");
|
||||
print_otag(h, TAG_CODE, "c", "Nm");
|
||||
break;
|
||||
case ROFFT_BODY:
|
||||
print_otag(h, TAG_TD, "");
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -624,16 +615,17 @@ static int
|
||||
man_UR_pre(MAN_ARGS)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
n = n->child;
|
||||
assert(n->type == ROFFT_HEAD);
|
||||
if (n->child != NULL) {
|
||||
assert(n->child->type == ROFFT_TEXT);
|
||||
if (n->tok == MAN_MT) {
|
||||
mandoc_asprintf(&cp, "mailto:%s", n->child->string);
|
||||
print_otag(h, TAG_A, "cTh", "Mt", cp);
|
||||
print_otag(h, TAG_A, "ch", "Mt", cp);
|
||||
free(cp);
|
||||
} else
|
||||
print_otag(h, TAG_A, "cTh", "Lk", n->child->string);
|
||||
print_otag(h, TAG_A, "ch", "Lk", n->child->string);
|
||||
}
|
||||
|
||||
assert(n->next->type == ROFFT_BODY);
|
||||
@ -641,6 +633,11 @@ man_UR_pre(MAN_ARGS)
|
||||
n = n->next;
|
||||
|
||||
print_man_nodelist(man, n->child, h);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
man_abort_pre(MAN_ARGS)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
218
man_macro.c
218
man_macro.c
@ -1,7 +1,7 @@
|
||||
/* $Id: man_macro.c,v 1.123 2017/06/25 11:45:37 schwarze Exp $ */
|
||||
/* $Id: man_macro.c,v 1.144 2019/01/05 18:59:46 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2012-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2012-2015, 2017-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
|
||||
@ -22,6 +22,7 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -40,47 +41,54 @@ static int man_args(struct roff_man *, int,
|
||||
int *, char *, char **);
|
||||
static void rew_scope(struct roff_man *, enum roff_tok);
|
||||
|
||||
const struct man_macro __man_macros[MAN_MAX - MAN_TH] = {
|
||||
{ in_line_eoln, MAN_BSCOPE }, /* TH */
|
||||
{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SH */
|
||||
{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SS */
|
||||
{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* TP */
|
||||
{ blk_imp, MAN_BSCOPE }, /* LP */
|
||||
{ blk_imp, MAN_BSCOPE }, /* PP */
|
||||
{ blk_imp, MAN_BSCOPE }, /* P */
|
||||
{ blk_imp, MAN_BSCOPE }, /* IP */
|
||||
{ blk_imp, MAN_BSCOPE }, /* HP */
|
||||
{ in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* SM */
|
||||
{ in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* SB */
|
||||
static const struct man_macro man_macros[MAN_MAX - MAN_TH] = {
|
||||
{ in_line_eoln, MAN_XSCOPE }, /* TH */
|
||||
{ blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* SH */
|
||||
{ blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* SS */
|
||||
{ blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* TP */
|
||||
{ blk_imp, MAN_XSCOPE | MAN_BSCOPED }, /* TQ */
|
||||
{ blk_imp, MAN_XSCOPE }, /* LP */
|
||||
{ blk_imp, MAN_XSCOPE }, /* PP */
|
||||
{ blk_imp, MAN_XSCOPE }, /* P */
|
||||
{ blk_imp, MAN_XSCOPE }, /* IP */
|
||||
{ blk_imp, MAN_XSCOPE }, /* HP */
|
||||
{ in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* SM */
|
||||
{ in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* SB */
|
||||
{ in_line_eoln, 0 }, /* BI */
|
||||
{ in_line_eoln, 0 }, /* IB */
|
||||
{ in_line_eoln, 0 }, /* BR */
|
||||
{ in_line_eoln, 0 }, /* RB */
|
||||
{ in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* R */
|
||||
{ in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* B */
|
||||
{ in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* I */
|
||||
{ in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* R */
|
||||
{ in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* B */
|
||||
{ in_line_eoln, MAN_NSCOPED | MAN_ESCOPED | MAN_JOIN }, /* I */
|
||||
{ in_line_eoln, 0 }, /* IR */
|
||||
{ in_line_eoln, 0 }, /* RI */
|
||||
{ in_line_eoln, MAN_NSCOPED }, /* nf */
|
||||
{ in_line_eoln, MAN_NSCOPED }, /* fi */
|
||||
{ blk_close, MAN_BSCOPE }, /* RE */
|
||||
{ blk_exp, MAN_BSCOPE }, /* RS */
|
||||
{ blk_close, MAN_XSCOPE }, /* RE */
|
||||
{ blk_exp, MAN_XSCOPE }, /* RS */
|
||||
{ in_line_eoln, 0 }, /* DT */
|
||||
{ in_line_eoln, 0 }, /* UC */
|
||||
{ in_line_eoln, MAN_NSCOPED }, /* PD */
|
||||
{ in_line_eoln, 0 }, /* AT */
|
||||
{ in_line_eoln, MAN_NSCOPED }, /* in */
|
||||
{ blk_imp, MAN_XSCOPE }, /* SY */
|
||||
{ blk_close, MAN_XSCOPE }, /* YS */
|
||||
{ in_line_eoln, 0 }, /* OP */
|
||||
{ in_line_eoln, MAN_BSCOPE }, /* EX */
|
||||
{ in_line_eoln, MAN_BSCOPE }, /* EE */
|
||||
{ blk_exp, MAN_BSCOPE }, /* UR */
|
||||
{ blk_close, MAN_BSCOPE }, /* UE */
|
||||
{ blk_exp, MAN_BSCOPE }, /* MT */
|
||||
{ blk_close, MAN_BSCOPE }, /* ME */
|
||||
{ in_line_eoln, MAN_XSCOPE }, /* EX */
|
||||
{ in_line_eoln, MAN_XSCOPE }, /* EE */
|
||||
{ blk_exp, MAN_XSCOPE }, /* UR */
|
||||
{ blk_close, MAN_XSCOPE }, /* UE */
|
||||
{ blk_exp, MAN_XSCOPE }, /* MT */
|
||||
{ blk_close, MAN_XSCOPE }, /* ME */
|
||||
};
|
||||
const struct man_macro *const man_macros = __man_macros - MAN_TH;
|
||||
|
||||
|
||||
const struct man_macro *
|
||||
man_macro(enum roff_tok tok)
|
||||
{
|
||||
assert(tok >= MAN_TH && tok <= MAN_MAX);
|
||||
return man_macros + (tok - MAN_TH);
|
||||
}
|
||||
|
||||
void
|
||||
man_unscope(struct roff_man *man, const struct roff_node *to)
|
||||
{
|
||||
@ -94,9 +102,10 @@ man_unscope(struct roff_man *man, const struct roff_node *to)
|
||||
|
||||
if (to == NULL && ! (n->flags & NODE_VALID)) {
|
||||
if (man->flags & (MAN_BLINE | MAN_ELINE) &&
|
||||
man_macros[n->tok].flags & MAN_SCOPED) {
|
||||
mandoc_vmsg(MANDOCERR_BLK_LINE,
|
||||
man->parse, n->line, n->pos,
|
||||
man_macro(n->tok)->flags &
|
||||
(MAN_BSCOPED | MAN_NSCOPED)) {
|
||||
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;
|
||||
@ -111,9 +120,9 @@ man_unscope(struct roff_man *man, const struct roff_node *to)
|
||||
continue;
|
||||
}
|
||||
if (n->type == ROFFT_BLOCK &&
|
||||
man_macros[n->tok].fp == blk_exp)
|
||||
man_macro(n->tok)->fp == blk_exp)
|
||||
mandoc_msg(MANDOCERR_BLK_NOEND,
|
||||
man->parse, n->line, n->pos,
|
||||
n->line, n->pos, "%s",
|
||||
roff_name[n->tok]);
|
||||
}
|
||||
|
||||
@ -175,7 +184,7 @@ rew_scope(struct roff_man *man, enum roff_tok tok)
|
||||
}
|
||||
if (tok != MAN_SH && (n->tok == MAN_SH ||
|
||||
(tok != MAN_SS && (n->tok == MAN_SS ||
|
||||
man_macros[n->tok].fp == blk_exp))))
|
||||
man_macro(n->tok)->fp == blk_exp))))
|
||||
return;
|
||||
man_unscope(man, n);
|
||||
n = man->last;
|
||||
@ -189,33 +198,39 @@ rew_scope(struct roff_man *man, enum roff_tok tok)
|
||||
void
|
||||
blk_close(MACRO_PROT_ARGS)
|
||||
{
|
||||
enum roff_tok ntok;
|
||||
enum roff_tok ctok, ntok;
|
||||
const struct roff_node *nn;
|
||||
char *p;
|
||||
int nrew, target;
|
||||
char *p, *ep;
|
||||
int cline, cpos, la, nrew, target;
|
||||
|
||||
nrew = 1;
|
||||
switch (tok) {
|
||||
case MAN_RE:
|
||||
ntok = MAN_RS;
|
||||
la = *pos;
|
||||
if ( ! man_args(man, line, pos, buf, &p))
|
||||
break;
|
||||
for (nn = man->last->parent; nn; nn = nn->parent)
|
||||
if (nn->tok == ntok && nn->type == ROFFT_BLOCK)
|
||||
nrew++;
|
||||
target = strtol(p, &p, 10);
|
||||
if (*p != '\0')
|
||||
mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
|
||||
line, p - buf, "RE ... %s", p);
|
||||
target = strtol(p, &ep, 10);
|
||||
if (*ep != '\0')
|
||||
mandoc_msg(MANDOCERR_ARG_EXCESS, line,
|
||||
la + (buf[la] == '"') + (int)(ep - p),
|
||||
"RE ... %s", ep);
|
||||
free(p);
|
||||
if (target == 0)
|
||||
target = 1;
|
||||
nrew -= target;
|
||||
if (nrew < 1) {
|
||||
mandoc_vmsg(MANDOCERR_RE_NOTOPEN, man->parse,
|
||||
mandoc_msg(MANDOCERR_RE_NOTOPEN,
|
||||
line, ppos, "RE %d", target);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case MAN_YS:
|
||||
ntok = MAN_SY;
|
||||
break;
|
||||
case MAN_UE:
|
||||
ntok = MAN_UR;
|
||||
break;
|
||||
@ -231,25 +246,47 @@ blk_close(MACRO_PROT_ARGS)
|
||||
break;
|
||||
|
||||
if (nn == NULL) {
|
||||
mandoc_msg(MANDOCERR_BLK_NOTOPEN, man->parse,
|
||||
line, ppos, roff_name[tok]);
|
||||
mandoc_msg(MANDOCERR_BLK_NOTOPEN,
|
||||
line, ppos, "%s", roff_name[tok]);
|
||||
rew_scope(man, MAN_PP);
|
||||
} else {
|
||||
line = man->last->line;
|
||||
ppos = man->last->pos;
|
||||
ntok = man->last->tok;
|
||||
man_unscope(man, nn);
|
||||
|
||||
if (tok == MAN_RE && nn->head->aux > 0)
|
||||
roff_setreg(man->roff, "an-margin",
|
||||
nn->head->aux, '-');
|
||||
|
||||
/* Move a trailing paragraph behind the block. */
|
||||
|
||||
if (ntok == MAN_LP || ntok == MAN_PP || ntok == MAN_P) {
|
||||
*pos = strlen(buf);
|
||||
blk_imp(man, ntok, line, ppos, pos, buf);
|
||||
if (tok == MAN_RE) {
|
||||
roff_elem_alloc(man, line, ppos, ROFF_br);
|
||||
man->last->flags |= NODE_LINE |
|
||||
NODE_VALID | NODE_ENDED;
|
||||
man->next = ROFF_NEXT_SIBLING;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
cline = man->last->line;
|
||||
cpos = man->last->pos;
|
||||
ctok = man->last->tok;
|
||||
man_unscope(man, nn);
|
||||
|
||||
if (tok == MAN_RE && nn->head->aux > 0)
|
||||
roff_setreg(man->roff, "an-margin", nn->head->aux, '-');
|
||||
|
||||
/* Trailing text. */
|
||||
|
||||
if (buf[*pos] != '\0') {
|
||||
roff_word_alloc(man, line, ppos, buf + *pos);
|
||||
man->last->flags |= NODE_DELIMC;
|
||||
if (mandoc_eos(man->last->string, strlen(man->last->string)))
|
||||
man->last->flags |= NODE_EOS;
|
||||
}
|
||||
|
||||
/* Move a trailing paragraph behind the block. */
|
||||
|
||||
if (ctok == MAN_LP || ctok == MAN_PP || ctok == MAN_P) {
|
||||
*pos = strlen(buf);
|
||||
blk_imp(man, ctok, cline, cpos, pos, buf);
|
||||
}
|
||||
|
||||
/* Synopsis blocks need an explicit end marker for spacing. */
|
||||
|
||||
if (tok == MAN_YS && man->last == nn) {
|
||||
roff_elem_alloc(man, line, ppos, tok);
|
||||
man_unscope(man, man->last);
|
||||
}
|
||||
}
|
||||
|
||||
@ -260,7 +297,10 @@ blk_exp(MACRO_PROT_ARGS)
|
||||
char *p;
|
||||
int la;
|
||||
|
||||
rew_scope(man, tok);
|
||||
if (tok == MAN_RS) {
|
||||
rew_scope(man, tok);
|
||||
man->flags |= ROFF_NONOFILL;
|
||||
}
|
||||
roff_block_alloc(man, line, ppos, tok);
|
||||
head = roff_head_alloc(man, line, ppos, tok);
|
||||
|
||||
@ -275,14 +315,16 @@ blk_exp(MACRO_PROT_ARGS)
|
||||
roff_setreg(man->roff, "an-margin",
|
||||
head->aux, '+');
|
||||
}
|
||||
free(p);
|
||||
}
|
||||
|
||||
if (buf[*pos] != '\0')
|
||||
mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse, line,
|
||||
*pos, "%s ... %s", roff_name[tok], buf + *pos);
|
||||
mandoc_msg(MANDOCERR_ARG_EXCESS, line, *pos,
|
||||
"%s ... %s", roff_name[tok], buf + *pos);
|
||||
|
||||
man_unscope(man, head);
|
||||
roff_body_alloc(man, line, ppos, tok);
|
||||
man->flags &= ~ROFF_NONOFILL;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -299,9 +341,10 @@ blk_imp(MACRO_PROT_ARGS)
|
||||
struct roff_node *n;
|
||||
|
||||
rew_scope(man, tok);
|
||||
n = roff_block_alloc(man, line, ppos, tok);
|
||||
if (n->tok == MAN_SH || n->tok == MAN_SS)
|
||||
man->flags &= ~MAN_LITERAL;
|
||||
man->flags |= ROFF_NONOFILL;
|
||||
if (tok == MAN_SH || tok == MAN_SS)
|
||||
man->flags &= ~ROFF_NOFILL;
|
||||
roff_block_alloc(man, line, ppos, tok);
|
||||
n = roff_head_alloc(man, line, ppos, tok);
|
||||
|
||||
/* Add line arguments. */
|
||||
@ -311,16 +354,17 @@ blk_imp(MACRO_PROT_ARGS)
|
||||
if ( ! man_args(man, line, pos, buf, &p))
|
||||
break;
|
||||
roff_word_alloc(man, line, la, p);
|
||||
free(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* For macros having optional next-line scope,
|
||||
* keep the head open if there were no arguments.
|
||||
* For `TP', always keep the head open.
|
||||
* For `TP' and `TQ', always keep the head open.
|
||||
*/
|
||||
|
||||
if (man_macros[tok].flags & MAN_SCOPED &&
|
||||
(tok == MAN_TP || n == man->last)) {
|
||||
if (man_macro(tok)->flags & MAN_BSCOPED &&
|
||||
(tok == MAN_TP || tok == MAN_TQ || n == man->last)) {
|
||||
man->flags |= MAN_BLINE;
|
||||
return;
|
||||
}
|
||||
@ -329,6 +373,7 @@ blk_imp(MACRO_PROT_ARGS)
|
||||
|
||||
man_unscope(man, n);
|
||||
roff_body_alloc(man, line, ppos, tok);
|
||||
man->flags &= ~ROFF_NONOFILL;
|
||||
}
|
||||
|
||||
void
|
||||
@ -341,27 +386,26 @@ in_line_eoln(MACRO_PROT_ARGS)
|
||||
roff_elem_alloc(man, line, ppos, tok);
|
||||
n = man->last;
|
||||
|
||||
if (tok == MAN_EX)
|
||||
man->flags |= ROFF_NOFILL;
|
||||
else if (tok == MAN_EE)
|
||||
man->flags &= ~ROFF_NOFILL;
|
||||
|
||||
for (;;) {
|
||||
if (buf[*pos] != '\0' && (tok == MAN_fi || tok == MAN_nf)) {
|
||||
mandoc_vmsg(MANDOCERR_ARG_SKIP,
|
||||
man->parse, line, *pos, "%s %s",
|
||||
roff_name[tok], buf + *pos);
|
||||
break;
|
||||
}
|
||||
if (buf[*pos] != '\0' && man->last != n && tok == MAN_PD) {
|
||||
mandoc_vmsg(MANDOCERR_ARG_EXCESS,
|
||||
man->parse, line, *pos, "%s ... %s",
|
||||
roff_name[tok], buf + *pos);
|
||||
mandoc_msg(MANDOCERR_ARG_EXCESS, line, *pos,
|
||||
"%s ... %s", roff_name[tok], buf + *pos);
|
||||
break;
|
||||
}
|
||||
la = *pos;
|
||||
if ( ! man_args(man, line, pos, buf, &p))
|
||||
break;
|
||||
if (man_macros[tok].flags & MAN_JOIN &&
|
||||
if (man_macro(tok)->flags & MAN_JOIN &&
|
||||
man->last->type == ROFFT_TEXT)
|
||||
roff_word_append(man, p);
|
||||
else
|
||||
roff_word_alloc(man, line, la, p);
|
||||
free(p);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -374,13 +418,12 @@ in_line_eoln(MACRO_PROT_ARGS)
|
||||
man->last->flags |= NODE_EOS;
|
||||
|
||||
/*
|
||||
* If no arguments are specified and this is MAN_SCOPED (i.e.,
|
||||
* If no arguments are specified and this is MAN_ESCOPED (i.e.,
|
||||
* next-line scoped), then set our mode to indicate that we're
|
||||
* waiting for terms to load into our context.
|
||||
*/
|
||||
|
||||
if (n == man->last && man_macros[tok].flags & MAN_SCOPED) {
|
||||
assert( ! (man_macros[tok].flags & MAN_NSCOPED));
|
||||
if (n == man->last && man_macro(tok)->flags & MAN_ESCOPED) {
|
||||
man->flags |= MAN_ELINE;
|
||||
return;
|
||||
}
|
||||
@ -391,18 +434,21 @@ in_line_eoln(MACRO_PROT_ARGS)
|
||||
/* Rewind our element scope. */
|
||||
|
||||
for ( ; man->last; man->last = man->last->parent) {
|
||||
man_state(man, man->last);
|
||||
man->last->flags |= NODE_VALID;
|
||||
if (man->last == n)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Rewind next-line scoped ancestors, if any. */
|
||||
|
||||
if (man_macro(tok)->flags & MAN_ESCOPED)
|
||||
man_descope(man, line, ppos, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
man_endparse(struct roff_man *man)
|
||||
{
|
||||
|
||||
man_unscope(man, man->first);
|
||||
man->flags &= ~MAN_LITERAL;
|
||||
man_unscope(man, man->meta.first);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -417,6 +463,6 @@ man_args(struct roff_man *man, int line, int *pos, char *buf, char **v)
|
||||
if ('\0' == *start)
|
||||
return 0;
|
||||
|
||||
*v = mandoc_getarg(man->parse, v, line, pos);
|
||||
*v = roff_getarg(man->roff, v, line, pos);
|
||||
return 1;
|
||||
}
|
||||
|
323
man_term.c
323
man_term.c
@ -1,7 +1,7 @@
|
||||
/* $Id: man_term.c,v 1.211 2018/06/10 15:12:35 schwarze Exp $ */
|
||||
/* $Id: man_term.c,v 1.228 2019/01/05 21:18:26 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2010-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* 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
|
||||
@ -27,7 +27,6 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc_aux.h"
|
||||
#include "mandoc.h"
|
||||
#include "roff.h"
|
||||
#include "man.h"
|
||||
#include "out.h"
|
||||
@ -37,8 +36,6 @@
|
||||
#define MAXMARGINS 64 /* maximum number of indented scopes */
|
||||
|
||||
struct mtermp {
|
||||
int fl;
|
||||
#define MANT_LITERAL (1 << 0)
|
||||
int lmargin[MAXMARGINS]; /* margins (incl. vis. page) */
|
||||
int lmargincur; /* index of current margin */
|
||||
int lmarginsz; /* actual number of nested margins */
|
||||
@ -51,7 +48,7 @@ struct mtermp {
|
||||
struct roff_node *n, \
|
||||
const struct roff_meta *meta
|
||||
|
||||
struct termact {
|
||||
struct man_term_act {
|
||||
int (*pre)(DECL_ARGS);
|
||||
void (*post)(DECL_ARGS);
|
||||
int flags;
|
||||
@ -78,8 +75,10 @@ static int pre_PP(DECL_ARGS);
|
||||
static int pre_RS(DECL_ARGS);
|
||||
static int pre_SH(DECL_ARGS);
|
||||
static int pre_SS(DECL_ARGS);
|
||||
static int pre_SY(DECL_ARGS);
|
||||
static int pre_TP(DECL_ARGS);
|
||||
static int pre_UR(DECL_ARGS);
|
||||
static int pre_abort(DECL_ARGS);
|
||||
static int pre_alternate(DECL_ARGS);
|
||||
static int pre_ign(DECL_ARGS);
|
||||
static int pre_in(DECL_ARGS);
|
||||
@ -89,18 +88,19 @@ static void post_IP(DECL_ARGS);
|
||||
static void post_HP(DECL_ARGS);
|
||||
static void post_RS(DECL_ARGS);
|
||||
static void post_SH(DECL_ARGS);
|
||||
static void post_SS(DECL_ARGS);
|
||||
static void post_SY(DECL_ARGS);
|
||||
static void post_TP(DECL_ARGS);
|
||||
static void post_UR(DECL_ARGS);
|
||||
|
||||
static const struct termact __termacts[MAN_MAX - MAN_TH] = {
|
||||
static const struct man_term_act man_term_acts[MAN_MAX - MAN_TH] = {
|
||||
{ NULL, NULL, 0 }, /* TH */
|
||||
{ pre_SH, post_SH, 0 }, /* SH */
|
||||
{ pre_SS, post_SS, 0 }, /* SS */
|
||||
{ pre_SS, post_SH, 0 }, /* SS */
|
||||
{ pre_TP, post_TP, 0 }, /* TP */
|
||||
{ pre_PP, NULL, 0 }, /* LP */
|
||||
{ pre_TP, post_TP, 0 }, /* TQ */
|
||||
{ pre_abort, NULL, 0 }, /* LP */
|
||||
{ pre_PP, NULL, 0 }, /* PP */
|
||||
{ pre_PP, NULL, 0 }, /* P */
|
||||
{ pre_abort, NULL, 0 }, /* P */
|
||||
{ pre_IP, post_IP, 0 }, /* IP */
|
||||
{ pre_HP, post_HP, 0 }, /* HP */
|
||||
{ NULL, NULL, 0 }, /* SM */
|
||||
@ -114,8 +114,6 @@ static const struct termact __termacts[MAN_MAX - MAN_TH] = {
|
||||
{ pre_I, NULL, 0 }, /* I */
|
||||
{ pre_alternate, NULL, 0 }, /* IR */
|
||||
{ pre_alternate, NULL, 0 }, /* RI */
|
||||
{ pre_literal, NULL, 0 }, /* nf */
|
||||
{ pre_literal, NULL, 0 }, /* fi */
|
||||
{ NULL, NULL, 0 }, /* RE */
|
||||
{ pre_RS, post_RS, 0 }, /* RS */
|
||||
{ pre_DT, NULL, 0 }, /* DT */
|
||||
@ -123,6 +121,8 @@ static const struct termact __termacts[MAN_MAX - MAN_TH] = {
|
||||
{ pre_PD, NULL, MAN_NOTEXT }, /* PD */
|
||||
{ pre_ign, NULL, 0 }, /* AT */
|
||||
{ pre_in, NULL, MAN_NOTEXT }, /* in */
|
||||
{ pre_SY, post_SY, 0 }, /* SY */
|
||||
{ NULL, NULL, 0 }, /* YS */
|
||||
{ pre_OP, NULL, 0 }, /* OP */
|
||||
{ pre_literal, NULL, 0 }, /* EX */
|
||||
{ pre_literal, NULL, 0 }, /* EE */
|
||||
@ -131,15 +131,22 @@ static const struct termact __termacts[MAN_MAX - MAN_TH] = {
|
||||
{ pre_UR, post_UR, 0 }, /* MT */
|
||||
{ NULL, NULL, 0 }, /* ME */
|
||||
};
|
||||
static const struct termact *termacts = __termacts - MAN_TH;
|
||||
static const struct man_term_act *man_term_act(enum roff_tok);
|
||||
|
||||
|
||||
static const struct man_term_act *
|
||||
man_term_act(enum roff_tok tok)
|
||||
{
|
||||
assert(tok >= MAN_TH && tok <= MAN_MAX);
|
||||
return man_term_acts + (tok - MAN_TH);
|
||||
}
|
||||
|
||||
void
|
||||
terminal_man(void *arg, const struct roff_man *man)
|
||||
terminal_man(void *arg, const struct roff_meta *man)
|
||||
{
|
||||
struct mtermp mt;
|
||||
struct termp *p;
|
||||
struct roff_node *n;
|
||||
struct mtermp mt;
|
||||
size_t save_defindent;
|
||||
|
||||
p = (struct termp *)arg;
|
||||
@ -151,7 +158,7 @@ terminal_man(void *arg, const struct roff_man *man)
|
||||
term_tab_set(p, "T");
|
||||
term_tab_set(p, ".5i");
|
||||
|
||||
memset(&mt, 0, sizeof(struct mtermp));
|
||||
memset(&mt, 0, sizeof(mt));
|
||||
mt.lmargin[mt.lmargincur] = term_len(p, p->defindent);
|
||||
mt.offset = term_len(p, p->defindent);
|
||||
mt.pardist = 1;
|
||||
@ -164,18 +171,17 @@ terminal_man(void *arg, const struct roff_man *man)
|
||||
!strcmp(n->child->child->string, "SYNOPSIS")) {
|
||||
if (n->child->next->child != NULL)
|
||||
print_man_nodelist(p, &mt,
|
||||
n->child->next->child,
|
||||
&man->meta);
|
||||
n->child->next->child, man);
|
||||
term_newln(p);
|
||||
break;
|
||||
}
|
||||
n = n->next;
|
||||
}
|
||||
} else {
|
||||
term_begin(p, print_man_head, print_man_foot, &man->meta);
|
||||
term_begin(p, print_man_head, print_man_foot, man);
|
||||
p->flags |= TERMP_NOSPACE;
|
||||
if (n != NULL)
|
||||
print_man_nodelist(p, &mt, n, &man->meta);
|
||||
print_man_nodelist(p, &mt, n, man);
|
||||
term_end(p);
|
||||
}
|
||||
p->defindent = save_defindent;
|
||||
@ -196,12 +202,12 @@ print_bvspace(struct termp *p, const struct roff_node *n, int pardist)
|
||||
|
||||
term_newln(p);
|
||||
|
||||
if (n->body && n->body->child)
|
||||
if (n->body != NULL && n->body->child != NULL)
|
||||
if (n->body->child->type == ROFFT_TBL)
|
||||
return;
|
||||
|
||||
if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS)
|
||||
if (NULL == n->prev)
|
||||
if (n->prev == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < pardist; i++)
|
||||
@ -209,17 +215,21 @@ print_bvspace(struct termp *p, const struct roff_node *n, int pardist)
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
pre_abort(DECL_ARGS)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
static int
|
||||
pre_ign(DECL_ARGS)
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
pre_I(DECL_ARGS)
|
||||
{
|
||||
|
||||
term_fontrepl(p, TERMFONT_UNDER);
|
||||
return 1;
|
||||
}
|
||||
@ -227,14 +237,8 @@ pre_I(DECL_ARGS)
|
||||
static int
|
||||
pre_literal(DECL_ARGS)
|
||||
{
|
||||
|
||||
term_newln(p);
|
||||
|
||||
if (n->tok == MAN_nf || n->tok == MAN_EX)
|
||||
mt->fl |= MANT_LITERAL;
|
||||
else
|
||||
mt->fl &= ~MANT_LITERAL;
|
||||
|
||||
/*
|
||||
* Unlike .IP and .TP, .HP does not have a HEAD.
|
||||
* So in case a second call to term_flushln() is needed,
|
||||
@ -247,7 +251,6 @@ pre_literal(DECL_ARGS)
|
||||
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
|
||||
p->flags |= TERMP_NOSPACE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -272,7 +275,7 @@ pre_alternate(DECL_ARGS)
|
||||
{
|
||||
enum termfont font[2];
|
||||
struct roff_node *nn;
|
||||
int savelit, i;
|
||||
int i;
|
||||
|
||||
switch (n->tok) {
|
||||
case MAN_RB:
|
||||
@ -302,29 +305,21 @@ pre_alternate(DECL_ARGS)
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
savelit = MANT_LITERAL & mt->fl;
|
||||
mt->fl &= ~MANT_LITERAL;
|
||||
|
||||
for (i = 0, nn = n->child; nn; nn = nn->next, i = 1 - i) {
|
||||
for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i = 1 - i) {
|
||||
term_fontrepl(p, font[i]);
|
||||
if (savelit && NULL == nn->next)
|
||||
mt->fl |= MANT_LITERAL;
|
||||
assert(nn->type == ROFFT_TEXT);
|
||||
term_word(p, nn->string);
|
||||
if (nn->flags & NODE_EOS)
|
||||
p->flags |= TERMP_SENTENCE;
|
||||
if (nn->next)
|
||||
if (nn->next != NULL)
|
||||
p->flags |= TERMP_NOSPACE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
pre_B(DECL_ARGS)
|
||||
{
|
||||
|
||||
term_fontrepl(p, TERMFONT_BOLD);
|
||||
return 1;
|
||||
}
|
||||
@ -332,20 +327,19 @@ pre_B(DECL_ARGS)
|
||||
static int
|
||||
pre_OP(DECL_ARGS)
|
||||
{
|
||||
|
||||
term_word(p, "[");
|
||||
p->flags |= TERMP_NOSPACE;
|
||||
p->flags |= TERMP_KEEP | TERMP_NOSPACE;
|
||||
|
||||
if (NULL != (n = n->child)) {
|
||||
if ((n = n->child) != NULL) {
|
||||
term_fontrepl(p, TERMFONT_BOLD);
|
||||
term_word(p, n->string);
|
||||
}
|
||||
if (NULL != n && NULL != n->next) {
|
||||
if (n != NULL && n->next != NULL) {
|
||||
term_fontrepl(p, TERMFONT_UNDER);
|
||||
term_word(p, n->next->string);
|
||||
}
|
||||
|
||||
term_fontrepl(p, TERMFONT_NONE);
|
||||
p->flags &= ~TERMP_KEEP;
|
||||
p->flags |= TERMP_NOSPACE;
|
||||
term_word(p, "]");
|
||||
return 0;
|
||||
@ -369,9 +363,9 @@ pre_in(DECL_ARGS)
|
||||
cp = n->child->string;
|
||||
less = 0;
|
||||
|
||||
if ('-' == *cp)
|
||||
if (*cp == '-')
|
||||
less = -1;
|
||||
else if ('+' == *cp)
|
||||
else if (*cp == '+')
|
||||
less = 1;
|
||||
else
|
||||
cp--;
|
||||
@ -413,13 +407,18 @@ pre_HP(DECL_ARGS)
|
||||
case ROFFT_BLOCK:
|
||||
print_bvspace(p, n, mt->pardist);
|
||||
return 1;
|
||||
case ROFFT_HEAD:
|
||||
return 0;
|
||||
case ROFFT_BODY:
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
abort();
|
||||
}
|
||||
|
||||
if ( ! (MANT_LITERAL & mt->fl)) {
|
||||
if (n->child == NULL)
|
||||
return 0;
|
||||
|
||||
if ((n->child->flags & NODE_NOFILL) == 0) {
|
||||
p->flags |= TERMP_NOBREAK | TERMP_BRIND;
|
||||
p->trailspace = 2;
|
||||
}
|
||||
@ -445,8 +444,10 @@ pre_HP(DECL_ARGS)
|
||||
static void
|
||||
post_HP(DECL_ARGS)
|
||||
{
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
case ROFFT_HEAD:
|
||||
break;
|
||||
case ROFFT_BODY:
|
||||
term_newln(p);
|
||||
|
||||
@ -466,25 +467,27 @@ post_HP(DECL_ARGS)
|
||||
p->tcol->rmargin = p->maxrmargin;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
pre_PP(DECL_ARGS)
|
||||
{
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
|
||||
print_bvspace(p, n, mt->pardist);
|
||||
break;
|
||||
default:
|
||||
case ROFFT_HEAD:
|
||||
return 0;
|
||||
case ROFFT_BODY:
|
||||
p->tcol->offset = mt->offset;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
return n->type != ROFFT_HEAD;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -492,21 +495,21 @@ pre_IP(DECL_ARGS)
|
||||
{
|
||||
struct roffsu su;
|
||||
const struct roff_node *nn;
|
||||
int len, savelit;
|
||||
int len;
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_BODY:
|
||||
p->flags |= TERMP_NOSPACE;
|
||||
break;
|
||||
case ROFFT_BLOCK:
|
||||
print_bvspace(p, n, mt->pardist);
|
||||
return 1;
|
||||
case ROFFT_HEAD:
|
||||
p->flags |= TERMP_NOBREAK;
|
||||
p->trailspace = 1;
|
||||
break;
|
||||
case ROFFT_BLOCK:
|
||||
print_bvspace(p, n, mt->pardist);
|
||||
/* FALLTHROUGH */
|
||||
case ROFFT_BODY:
|
||||
p->flags |= TERMP_NOSPACE;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Calculate the offset from the optional second argument. */
|
||||
@ -526,33 +529,25 @@ pre_IP(DECL_ARGS)
|
||||
case ROFFT_HEAD:
|
||||
p->tcol->offset = mt->offset;
|
||||
p->tcol->rmargin = mt->offset + len;
|
||||
|
||||
savelit = MANT_LITERAL & mt->fl;
|
||||
mt->fl &= ~MANT_LITERAL;
|
||||
|
||||
if (n->child)
|
||||
if (n->child != NULL)
|
||||
print_man_node(p, mt, n->child, meta);
|
||||
|
||||
if (savelit)
|
||||
mt->fl |= MANT_LITERAL;
|
||||
|
||||
return 0;
|
||||
case ROFFT_BODY:
|
||||
p->tcol->offset = mt->offset + len;
|
||||
p->tcol->rmargin = p->maxrmargin;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
abort();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
post_IP(DECL_ARGS)
|
||||
{
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
break;
|
||||
case ROFFT_HEAD:
|
||||
term_flushln(p);
|
||||
p->flags &= ~TERMP_NOBREAK;
|
||||
@ -564,7 +559,7 @@ post_IP(DECL_ARGS)
|
||||
p->tcol->offset = mt->offset;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
@ -573,9 +568,13 @@ pre_TP(DECL_ARGS)
|
||||
{
|
||||
struct roffsu su;
|
||||
struct roff_node *nn;
|
||||
int len, savelit;
|
||||
int len;
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
if (n->tok == MAN_TP)
|
||||
print_bvspace(p, n, mt->pardist);
|
||||
return 1;
|
||||
case ROFFT_HEAD:
|
||||
p->flags |= TERMP_NOBREAK | TERMP_BRTRSP;
|
||||
p->trailspace = 1;
|
||||
@ -583,11 +582,8 @@ pre_TP(DECL_ARGS)
|
||||
case ROFFT_BODY:
|
||||
p->flags |= TERMP_NOSPACE;
|
||||
break;
|
||||
case ROFFT_BLOCK:
|
||||
print_bvspace(p, n, mt->pardist);
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
return 1;
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Calculate offset. */
|
||||
@ -609,21 +605,15 @@ pre_TP(DECL_ARGS)
|
||||
p->tcol->offset = mt->offset;
|
||||
p->tcol->rmargin = mt->offset + len;
|
||||
|
||||
savelit = MANT_LITERAL & mt->fl;
|
||||
mt->fl &= ~MANT_LITERAL;
|
||||
|
||||
/* Don't print same-line elements. */
|
||||
nn = n->child;
|
||||
while (NULL != nn && 0 == (NODE_LINE & nn->flags))
|
||||
while (nn != NULL && (nn->flags & NODE_LINE) == 0)
|
||||
nn = nn->next;
|
||||
|
||||
while (NULL != nn) {
|
||||
while (nn != NULL) {
|
||||
print_man_node(p, mt, nn, meta);
|
||||
nn = nn->next;
|
||||
}
|
||||
|
||||
if (savelit)
|
||||
mt->fl |= MANT_LITERAL;
|
||||
return 0;
|
||||
case ROFFT_BODY:
|
||||
p->tcol->offset = mt->offset + len;
|
||||
@ -632,17 +622,17 @@ pre_TP(DECL_ARGS)
|
||||
p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
abort();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
post_TP(DECL_ARGS)
|
||||
{
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
break;
|
||||
case ROFFT_HEAD:
|
||||
term_flushln(p);
|
||||
break;
|
||||
@ -651,7 +641,7 @@ post_TP(DECL_ARGS)
|
||||
p->tcol->offset = mt->offset;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
@ -662,7 +652,6 @@ pre_SS(DECL_ARGS)
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
mt->fl &= ~MANT_LITERAL;
|
||||
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
|
||||
mt->offset = term_len(p, p->defindent);
|
||||
|
||||
@ -674,7 +663,7 @@ pre_SS(DECL_ARGS)
|
||||
do {
|
||||
n = n->prev;
|
||||
} while (n != NULL && n->tok >= MAN_TH &&
|
||||
termacts[n->tok].flags & MAN_NOTEXT);
|
||||
man_term_act(n->tok)->flags & MAN_NOTEXT);
|
||||
if (n == NULL || n->type == ROFFT_COMMENT ||
|
||||
(n->tok == MAN_SS && n->body->child == NULL))
|
||||
break;
|
||||
@ -698,26 +687,9 @@ pre_SS(DECL_ARGS)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
post_SS(DECL_ARGS)
|
||||
{
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_HEAD:
|
||||
term_newln(p);
|
||||
break;
|
||||
case ROFFT_BODY:
|
||||
term_newln(p);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
pre_SH(DECL_ARGS)
|
||||
{
|
||||
@ -725,7 +697,6 @@ pre_SH(DECL_ARGS)
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
mt->fl &= ~MANT_LITERAL;
|
||||
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
|
||||
mt->offset = term_len(p, p->defindent);
|
||||
|
||||
@ -737,7 +708,7 @@ pre_SH(DECL_ARGS)
|
||||
do {
|
||||
n = n->prev;
|
||||
} while (n != NULL && n->tok >= MAN_TH &&
|
||||
termacts[n->tok].flags & MAN_NOTEXT);
|
||||
man_term_act(n->tok)->flags & MAN_NOTEXT);
|
||||
if (n == NULL || n->type == ROFFT_COMMENT ||
|
||||
(n->tok == MAN_SH && n->body->child == NULL))
|
||||
break;
|
||||
@ -759,25 +730,23 @@ pre_SH(DECL_ARGS)
|
||||
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
abort();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
post_SH(DECL_ARGS)
|
||||
{
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_HEAD:
|
||||
term_newln(p);
|
||||
case ROFFT_BLOCK:
|
||||
break;
|
||||
case ROFFT_HEAD:
|
||||
case ROFFT_BODY:
|
||||
term_newln(p);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
@ -792,8 +761,10 @@ pre_RS(DECL_ARGS)
|
||||
return 1;
|
||||
case ROFFT_HEAD:
|
||||
return 0;
|
||||
default:
|
||||
case ROFFT_BODY:
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
n = n->parent->head;
|
||||
@ -821,42 +792,99 @@ pre_RS(DECL_ARGS)
|
||||
static void
|
||||
post_RS(DECL_ARGS)
|
||||
{
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
return;
|
||||
case ROFFT_HEAD:
|
||||
return;
|
||||
default:
|
||||
term_newln(p);
|
||||
case ROFFT_BODY:
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
term_newln(p);
|
||||
mt->offset -= n->parent->head->aux;
|
||||
p->tcol->offset = mt->offset;
|
||||
|
||||
if (--mt->lmarginsz < MAXMARGINS)
|
||||
mt->lmargincur = mt->lmarginsz;
|
||||
}
|
||||
|
||||
static int
|
||||
pre_SY(DECL_ARGS)
|
||||
{
|
||||
const struct roff_node *nn;
|
||||
int len;
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
if (n->prev == NULL || n->prev->tok != MAN_SY)
|
||||
print_bvspace(p, n, mt->pardist);
|
||||
return 1;
|
||||
case ROFFT_HEAD:
|
||||
case ROFFT_BODY:
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
nn = n->parent->head->child;
|
||||
len = nn == NULL ? 1 : term_strlen(p, nn->string) + 1;
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_HEAD:
|
||||
p->tcol->offset = mt->offset;
|
||||
p->tcol->rmargin = mt->offset + len;
|
||||
if (n->next->child == NULL ||
|
||||
(n->next->child->flags & NODE_NOFILL) == 0)
|
||||
p->flags |= TERMP_NOBREAK;
|
||||
term_fontrepl(p, TERMFONT_BOLD);
|
||||
break;
|
||||
case ROFFT_BODY:
|
||||
mt->lmargin[mt->lmargincur] = len;
|
||||
p->tcol->offset = mt->offset + len;
|
||||
p->tcol->rmargin = p->maxrmargin;
|
||||
p->flags |= TERMP_NOSPACE;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
post_SY(DECL_ARGS)
|
||||
{
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
break;
|
||||
case ROFFT_HEAD:
|
||||
term_flushln(p);
|
||||
p->flags &= ~TERMP_NOBREAK;
|
||||
break;
|
||||
case ROFFT_BODY:
|
||||
term_newln(p);
|
||||
p->tcol->offset = mt->offset;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
pre_UR(DECL_ARGS)
|
||||
{
|
||||
|
||||
return n->type != ROFFT_HEAD;
|
||||
}
|
||||
|
||||
static void
|
||||
post_UR(DECL_ARGS)
|
||||
{
|
||||
|
||||
if (n->type != ROFFT_BLOCK)
|
||||
return;
|
||||
|
||||
term_word(p, "<");
|
||||
p->flags |= TERMP_NOSPACE;
|
||||
|
||||
if (NULL != n->child->child)
|
||||
if (n->child->child != NULL)
|
||||
print_man_node(p, mt, n->child->child, meta);
|
||||
|
||||
p->flags |= TERMP_NOSPACE;
|
||||
@ -866,7 +894,8 @@ post_UR(DECL_ARGS)
|
||||
static void
|
||||
print_man_node(DECL_ARGS)
|
||||
{
|
||||
int c;
|
||||
const struct man_term_act *act;
|
||||
int c;
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_TEXT:
|
||||
@ -884,6 +913,8 @@ print_man_node(DECL_ARGS)
|
||||
} else if (*n->string == ' ' && n->flags & NODE_LINE &&
|
||||
(p->flags & TERMP_NONEWLINE) == 0)
|
||||
term_newln(p);
|
||||
else if (n->flags & NODE_DELIMC)
|
||||
p->flags |= TERMP_NOSPACE;
|
||||
|
||||
term_word(p, n->string);
|
||||
goto out;
|
||||
@ -910,20 +941,20 @@ print_man_node(DECL_ARGS)
|
||||
return;
|
||||
}
|
||||
|
||||
assert(n->tok >= MAN_TH && n->tok <= MAN_MAX);
|
||||
if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
|
||||
act = man_term_act(n->tok);
|
||||
if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM)
|
||||
term_fontrepl(p, TERMFONT_NONE);
|
||||
|
||||
c = 1;
|
||||
if (termacts[n->tok].pre)
|
||||
c = (*termacts[n->tok].pre)(p, mt, n, meta);
|
||||
if (act->pre != NULL)
|
||||
c = (*act->pre)(p, mt, n, meta);
|
||||
|
||||
if (c && n->child)
|
||||
if (c && n->child != NULL)
|
||||
print_man_nodelist(p, mt, n->child, meta);
|
||||
|
||||
if (termacts[n->tok].post)
|
||||
(*termacts[n->tok].post)(p, mt, n, meta);
|
||||
if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
|
||||
if (act->post != NULL)
|
||||
(*act->post)(p, mt, n, meta);
|
||||
if ((act->flags & MAN_NOTEXT) == 0 && n->tok != MAN_SM)
|
||||
term_fontrepl(p, TERMFONT_NONE);
|
||||
|
||||
out:
|
||||
@ -934,7 +965,7 @@ print_man_node(DECL_ARGS)
|
||||
* -man doesn't have nested macros, we don't need to be
|
||||
* more specific than this.
|
||||
*/
|
||||
if (mt->fl & MANT_LITERAL &&
|
||||
if (n->flags & NODE_NOFILL &&
|
||||
! (p->flags & (TERMP_NOBREAK | TERMP_NONEWLINE)) &&
|
||||
(n->next == NULL || n->next->flags & NODE_LINE)) {
|
||||
p->flags |= TERMP_BRNEVER | TERMP_NOSPACE;
|
||||
@ -949,15 +980,13 @@ print_man_node(DECL_ARGS)
|
||||
p->tcol->rmargin = p->maxrmargin;
|
||||
}
|
||||
}
|
||||
if (NODE_EOS & n->flags)
|
||||
if (n->flags & NODE_EOS)
|
||||
p->flags |= TERMP_SENTENCE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
print_man_nodelist(DECL_ARGS)
|
||||
{
|
||||
|
||||
while (n != NULL) {
|
||||
print_man_node(p, mt, n, meta);
|
||||
n = n->next;
|
||||
@ -992,7 +1021,7 @@ print_man_foot(struct termp *p, const struct roff_meta *meta)
|
||||
}
|
||||
mandoc_asprintf(&title, "%s(%s)",
|
||||
meta->title, meta->msec);
|
||||
} else if (meta->os) {
|
||||
} else if (meta->os != NULL) {
|
||||
title = mandoc_strdup(meta->os);
|
||||
} else {
|
||||
title = mandoc_strdup("");
|
||||
|
211
man_validate.c
211
man_validate.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $Id: man_validate.c,v 1.146 2018/12/31 10:04:39 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2010, 2012-2018 Ingo Schwarze <schwarze@openbsd.org>
|
||||
@ -24,6 +24,7 @@
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
@ -40,28 +41,32 @@
|
||||
|
||||
typedef void (*v_check)(CHKARGS);
|
||||
|
||||
static void check_abort(CHKARGS);
|
||||
static void check_par(CHKARGS);
|
||||
static void check_part(CHKARGS);
|
||||
static void check_root(CHKARGS);
|
||||
static void check_text(CHKARGS);
|
||||
|
||||
static void post_AT(CHKARGS);
|
||||
static void post_EE(CHKARGS);
|
||||
static void post_EX(CHKARGS);
|
||||
static void post_IP(CHKARGS);
|
||||
static void post_OP(CHKARGS);
|
||||
static void post_SH(CHKARGS);
|
||||
static void post_TH(CHKARGS);
|
||||
static void post_UC(CHKARGS);
|
||||
static void post_UR(CHKARGS);
|
||||
static void post_in(CHKARGS);
|
||||
static void post_vs(CHKARGS);
|
||||
|
||||
static const v_check __man_valids[MAN_MAX - MAN_TH] = {
|
||||
static const v_check man_valids[MAN_MAX - MAN_TH] = {
|
||||
post_TH, /* TH */
|
||||
NULL, /* SH */
|
||||
NULL, /* SS */
|
||||
post_SH, /* SH */
|
||||
post_SH, /* SS */
|
||||
NULL, /* TP */
|
||||
check_par, /* LP */
|
||||
NULL, /* TQ */
|
||||
check_abort,/* LP */
|
||||
check_par, /* PP */
|
||||
check_par, /* P */
|
||||
check_abort,/* P */
|
||||
post_IP, /* IP */
|
||||
NULL, /* HP */
|
||||
NULL, /* SM */
|
||||
@ -75,8 +80,6 @@ static const v_check __man_valids[MAN_MAX - MAN_TH] = {
|
||||
NULL, /* I */
|
||||
NULL, /* IR */
|
||||
NULL, /* RI */
|
||||
NULL, /* nf */
|
||||
NULL, /* fi */
|
||||
NULL, /* RE */
|
||||
check_part, /* RS */
|
||||
NULL, /* DT */
|
||||
@ -84,33 +87,56 @@ static const v_check __man_valids[MAN_MAX - MAN_TH] = {
|
||||
NULL, /* PD */
|
||||
post_AT, /* AT */
|
||||
post_in, /* in */
|
||||
NULL, /* SY */
|
||||
NULL, /* YS */
|
||||
post_OP, /* OP */
|
||||
NULL, /* EX */
|
||||
NULL, /* EE */
|
||||
post_EX, /* EX */
|
||||
post_EE, /* EE */
|
||||
post_UR, /* UR */
|
||||
NULL, /* UE */
|
||||
post_UR, /* MT */
|
||||
NULL, /* ME */
|
||||
};
|
||||
static const v_check *man_valids = __man_valids - MAN_TH;
|
||||
|
||||
|
||||
/* Validate the subtree rooted at man->last. */
|
||||
void
|
||||
man_node_validate(struct roff_man *man)
|
||||
man_validate(struct roff_man *man)
|
||||
{
|
||||
struct roff_node *n;
|
||||
const v_check *cp;
|
||||
|
||||
/*
|
||||
* Translate obsolete macros such that later code
|
||||
* does not need to look for them.
|
||||
*/
|
||||
|
||||
n = man->last;
|
||||
switch (n->tok) {
|
||||
case MAN_LP:
|
||||
case MAN_P:
|
||||
n->tok = MAN_PP;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over all children, recursing into each one
|
||||
* in turn, depth-first.
|
||||
*/
|
||||
|
||||
man->last = man->last->child;
|
||||
while (man->last != NULL) {
|
||||
man_node_validate(man);
|
||||
man_validate(man);
|
||||
if (man->last == n)
|
||||
man->last = man->last->child;
|
||||
else
|
||||
man->last = man->last->next;
|
||||
}
|
||||
|
||||
/* Finally validate the macro itself. */
|
||||
|
||||
man->last = n;
|
||||
man->next = ROFF_NEXT_SIBLING;
|
||||
switch (n->type) {
|
||||
@ -126,23 +152,15 @@ man_node_validate(struct roff_man *man)
|
||||
break;
|
||||
default:
|
||||
if (n->tok < ROFF_MAX) {
|
||||
switch (n->tok) {
|
||||
case ROFF_br:
|
||||
case ROFF_sp:
|
||||
post_vs(man, n);
|
||||
break;
|
||||
default:
|
||||
roff_validate(man);
|
||||
break;
|
||||
}
|
||||
roff_validate(man);
|
||||
break;
|
||||
}
|
||||
assert(n->tok >= MAN_TH && n->tok < MAN_MAX);
|
||||
cp = man_valids + n->tok;
|
||||
cp = man_valids + (n->tok - MAN_TH);
|
||||
if (*cp)
|
||||
(*cp)(man, n);
|
||||
if (man->last == n)
|
||||
man_state(man, n);
|
||||
n->flags |= NODE_VALID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -153,14 +171,12 @@ check_root(CHKARGS)
|
||||
assert((man->flags & (MAN_BLINE | MAN_ELINE)) == 0);
|
||||
|
||||
if (n->last == NULL || n->last->type == ROFFT_COMMENT)
|
||||
mandoc_msg(MANDOCERR_DOC_EMPTY, man->parse,
|
||||
n->line, n->pos, NULL);
|
||||
mandoc_msg(MANDOCERR_DOC_EMPTY, n->line, n->pos, NULL);
|
||||
else
|
||||
man->meta.hasbody = 1;
|
||||
|
||||
if (NULL == man->meta.title) {
|
||||
mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse,
|
||||
n->line, n->pos, NULL);
|
||||
mandoc_msg(MANDOCERR_TH_NOTITLE, n->line, n->pos, NULL);
|
||||
|
||||
/*
|
||||
* If a title hasn't been set, do so now (by
|
||||
@ -175,23 +191,43 @@ check_root(CHKARGS)
|
||||
|
||||
if (man->meta.os_e &&
|
||||
(man->meta.rcsids & (1 << man->meta.os_e)) == 0)
|
||||
mandoc_msg(MANDOCERR_RCS_MISSING, man->parse, 0, 0,
|
||||
mandoc_msg(MANDOCERR_RCS_MISSING, 0, 0,
|
||||
man->meta.os_e == MANDOC_OS_OPENBSD ?
|
||||
"(OpenBSD)" : "(NetBSD)");
|
||||
}
|
||||
|
||||
static void
|
||||
check_abort(CHKARGS)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
static void
|
||||
check_text(CHKARGS)
|
||||
{
|
||||
char *cp, *p;
|
||||
|
||||
if (MAN_LITERAL & man->flags)
|
||||
if (n->flags & NODE_NOFILL)
|
||||
return;
|
||||
|
||||
cp = n->string;
|
||||
for (p = cp; NULL != (p = strchr(p, '\t')); p++)
|
||||
mandoc_msg(MANDOCERR_FI_TAB, man->parse,
|
||||
n->line, n->pos + (p - cp), NULL);
|
||||
mandoc_msg(MANDOCERR_FI_TAB,
|
||||
n->line, n->pos + (int)(p - cp), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
post_EE(CHKARGS)
|
||||
{
|
||||
if ((n->flags & NODE_NOFILL) == 0)
|
||||
mandoc_msg(MANDOCERR_FI_SKIP, n->line, n->pos, "EE");
|
||||
}
|
||||
|
||||
static void
|
||||
post_EX(CHKARGS)
|
||||
{
|
||||
if (n->flags & NODE_NOFILL)
|
||||
mandoc_msg(MANDOCERR_NF_SKIP, n->line, n->pos, "EX");
|
||||
}
|
||||
|
||||
static void
|
||||
@ -199,21 +235,55 @@ post_OP(CHKARGS)
|
||||
{
|
||||
|
||||
if (n->child == NULL)
|
||||
mandoc_msg(MANDOCERR_OP_EMPTY, man->parse,
|
||||
n->line, n->pos, "OP");
|
||||
mandoc_msg(MANDOCERR_OP_EMPTY, n->line, n->pos, "OP");
|
||||
else if (n->child->next != NULL && n->child->next->next != NULL) {
|
||||
n = n->child->next->next;
|
||||
mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
|
||||
mandoc_msg(MANDOCERR_ARG_EXCESS,
|
||||
n->line, n->pos, "OP ... %s", n->string);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
post_SH(CHKARGS)
|
||||
{
|
||||
struct roff_node *nc;
|
||||
|
||||
if (n->type != ROFFT_BODY || (nc = n->child) == NULL)
|
||||
return;
|
||||
|
||||
if (nc->tok == MAN_PP && nc->body->child != NULL) {
|
||||
while (nc->body->last != NULL) {
|
||||
man->next = ROFF_NEXT_CHILD;
|
||||
roff_node_relink(man, nc->body->last);
|
||||
man->last = n;
|
||||
}
|
||||
}
|
||||
|
||||
if (nc->tok == MAN_PP || nc->tok == ROFF_sp || nc->tok == ROFF_br) {
|
||||
mandoc_msg(MANDOCERR_PAR_SKIP, nc->line, nc->pos,
|
||||
"%s after %s", roff_name[nc->tok], roff_name[n->tok]);
|
||||
roff_node_delete(man, nc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Trailing PP is empty, so it is deleted by check_par().
|
||||
* Trailing sp is significant.
|
||||
*/
|
||||
|
||||
if ((nc = n->last) != NULL && nc->tok == ROFF_br) {
|
||||
mandoc_msg(MANDOCERR_PAR_SKIP,
|
||||
nc->line, nc->pos, "%s at the end of %s",
|
||||
roff_name[nc->tok], roff_name[n->tok]);
|
||||
roff_node_delete(man, nc);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
post_UR(CHKARGS)
|
||||
{
|
||||
if (n->type == ROFFT_HEAD && n->child == NULL)
|
||||
mandoc_msg(MANDOCERR_UR_NOHEAD, man->parse,
|
||||
n->line, n->pos, roff_name[n->tok]);
|
||||
mandoc_msg(MANDOCERR_UR_NOHEAD, n->line, n->pos,
|
||||
"%s", roff_name[n->tok]);
|
||||
check_part(man, n);
|
||||
}
|
||||
|
||||
@ -222,8 +292,8 @@ check_part(CHKARGS)
|
||||
{
|
||||
|
||||
if (n->type == ROFFT_BODY && n->child == NULL)
|
||||
mandoc_msg(MANDOCERR_BLK_EMPTY, man->parse,
|
||||
n->line, n->pos, roff_name[n->tok]);
|
||||
mandoc_msg(MANDOCERR_BLK_EMPTY, n->line, n->pos,
|
||||
"%s", roff_name[n->tok]);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -236,15 +306,22 @@ check_par(CHKARGS)
|
||||
roff_node_delete(man, n);
|
||||
break;
|
||||
case ROFFT_BODY:
|
||||
if (n->child != NULL &&
|
||||
(n->child->tok == ROFF_sp || n->child->tok == ROFF_br)) {
|
||||
mandoc_msg(MANDOCERR_PAR_SKIP,
|
||||
n->child->line, n->child->pos,
|
||||
"%s after %s", roff_name[n->child->tok],
|
||||
roff_name[n->tok]);
|
||||
roff_node_delete(man, n->child);
|
||||
}
|
||||
if (n->child == NULL)
|
||||
mandoc_vmsg(MANDOCERR_PAR_SKIP,
|
||||
man->parse, n->line, n->pos,
|
||||
mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos,
|
||||
"%s empty", roff_name[n->tok]);
|
||||
break;
|
||||
case ROFFT_HEAD:
|
||||
if (n->child != NULL)
|
||||
mandoc_vmsg(MANDOCERR_ARG_SKIP,
|
||||
man->parse, n->line, n->pos, "%s %s%s",
|
||||
mandoc_msg(MANDOCERR_ARG_SKIP,
|
||||
n->line, n->pos, "%s %s%s",
|
||||
roff_name[n->tok], n->child->string,
|
||||
n->child->next != NULL ? " ..." : "");
|
||||
break;
|
||||
@ -264,8 +341,7 @@ post_IP(CHKARGS)
|
||||
break;
|
||||
case ROFFT_BODY:
|
||||
if (n->parent->head->child == NULL && n->child == NULL)
|
||||
mandoc_vmsg(MANDOCERR_PAR_SKIP,
|
||||
man->parse, n->line, n->pos,
|
||||
mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos,
|
||||
"%s empty", roff_name[n->tok]);
|
||||
break;
|
||||
default:
|
||||
@ -298,9 +374,8 @@ post_TH(CHKARGS)
|
||||
/* Only warn about this once... */
|
||||
if (isalpha((unsigned char)*p) &&
|
||||
! isupper((unsigned char)*p)) {
|
||||
mandoc_vmsg(MANDOCERR_TITLE_CASE,
|
||||
man->parse, n->line,
|
||||
n->pos + (p - n->string),
|
||||
mandoc_msg(MANDOCERR_TITLE_CASE, n->line,
|
||||
n->pos + (int)(p - n->string),
|
||||
"TH %s", n->string);
|
||||
break;
|
||||
}
|
||||
@ -308,8 +383,7 @@ post_TH(CHKARGS)
|
||||
man->meta.title = mandoc_strdup(n->string);
|
||||
} else {
|
||||
man->meta.title = mandoc_strdup("");
|
||||
mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse,
|
||||
nb->line, nb->pos, "TH");
|
||||
mandoc_msg(MANDOCERR_TH_NOTITLE, nb->line, nb->pos, "TH");
|
||||
}
|
||||
|
||||
/* TITLE ->MSEC<- DATE OS VOL */
|
||||
@ -320,7 +394,7 @@ post_TH(CHKARGS)
|
||||
man->meta.msec = mandoc_strdup(n->string);
|
||||
else {
|
||||
man->meta.msec = mandoc_strdup("");
|
||||
mandoc_vmsg(MANDOCERR_MSEC_MISSING, man->parse,
|
||||
mandoc_msg(MANDOCERR_MSEC_MISSING,
|
||||
nb->line, nb->pos, "TH %s", man->meta.title);
|
||||
}
|
||||
|
||||
@ -334,7 +408,7 @@ post_TH(CHKARGS)
|
||||
mandoc_normdate(man, n->string, n->line, n->pos);
|
||||
} else {
|
||||
man->meta.date = mandoc_strdup("");
|
||||
mandoc_msg(MANDOCERR_DATE_MISSING, man->parse,
|
||||
mandoc_msg(MANDOCERR_DATE_MISSING,
|
||||
n ? n->line : nb->line,
|
||||
n ? n->pos : nb->pos, "TH");
|
||||
}
|
||||
@ -362,7 +436,7 @@ post_TH(CHKARGS)
|
||||
man->meta.vol = mandoc_strdup(p);
|
||||
|
||||
if (n != NULL && (n = n->next) != NULL)
|
||||
mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
|
||||
mandoc_msg(MANDOCERR_ARG_EXCESS,
|
||||
n->line, n->pos, "TH ... %s", n->string);
|
||||
|
||||
/*
|
||||
@ -463,32 +537,3 @@ post_in(CHKARGS)
|
||||
free(n->child->string);
|
||||
n->child->string = s;
|
||||
}
|
||||
|
||||
static void
|
||||
post_vs(CHKARGS)
|
||||
{
|
||||
|
||||
if (NULL != n->prev)
|
||||
return;
|
||||
|
||||
switch (n->parent->tok) {
|
||||
case MAN_SH:
|
||||
case MAN_SS:
|
||||
case MAN_PP:
|
||||
case MAN_LP:
|
||||
case MAN_P:
|
||||
mandoc_vmsg(MANDOCERR_PAR_SKIP, man->parse, n->line, n->pos,
|
||||
"%s after %s", roff_name[n->tok],
|
||||
roff_name[n->parent->tok]);
|
||||
/* FALLTHROUGH */
|
||||
case TOKEN_NONE:
|
||||
/*
|
||||
* Don't warn about this because it occurs in pod2man
|
||||
* and would cause considerable (unfixable) warnage.
|
||||
*/
|
||||
roff_node_delete(man, n);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* $Id: manconf.h,v 1.5 2017/07/01 09:47:30 schwarze Exp $ */
|
||||
/* $Id: manconf.h,v 1.7 2018/11/22 11:30:23 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2011, 2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
@ -30,12 +30,14 @@ struct manoutput {
|
||||
char *man;
|
||||
char *paper;
|
||||
char *style;
|
||||
char *tag;
|
||||
size_t indent;
|
||||
size_t width;
|
||||
int fragment;
|
||||
int mdoc;
|
||||
int synopsisonly;
|
||||
int noval;
|
||||
int synopsisonly;
|
||||
int toc;
|
||||
};
|
||||
|
||||
struct manconf {
|
||||
|
138
mandoc.1
138
mandoc.1
@ -1,4 +1,4 @@
|
||||
.\" $Id: mandoc.1,v 1.226 2018/07/28 18:34:15 schwarze Exp $
|
||||
.\" $Id: mandoc.1,v 1.237 2019/02/23 18:53:54 schwarze Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
.\" Copyright (c) 2012, 2014-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: July 28 2018 $
|
||||
.Dd $Mdocdate: February 23 2019 $
|
||||
.Dt MANDOC 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -256,10 +256,28 @@ where
|
||||
is the back-space character number 8.
|
||||
Emboldened characters are rendered as
|
||||
.Sq c Ns \e[bs] Ns c .
|
||||
This markup is typically converted to appropriate terminal sequences by
|
||||
the pager or
|
||||
.Xr ul 1 .
|
||||
To remove the markup, pipe the output to
|
||||
.Xr col 1
|
||||
.Fl b
|
||||
instead.
|
||||
.Pp
|
||||
The special characters documented in
|
||||
.Xr mandoc_char 7
|
||||
are rendered best-effort in an ASCII equivalent.
|
||||
In particular, opening and closing
|
||||
.Sq single quotes
|
||||
are represented as characters number 0x60 and 0x27, respectively,
|
||||
which agrees with all ASCII standards from 1965 to the latest
|
||||
revision (2012) and which matches the traditional way in which
|
||||
.Xr roff 7
|
||||
formatters represent single quotes in ASCII output.
|
||||
This correct ASCII rendering may look strange with modern
|
||||
Unicode-compatible fonts because contrary to ASCII, Unicode uses
|
||||
the code point U+0060 for the grave accent only, never for an opening
|
||||
quote.
|
||||
.Pp
|
||||
The following
|
||||
.Fl O
|
||||
@ -290,6 +308,26 @@ One useful application is for checking that
|
||||
output formats in the same way as the
|
||||
.Xr mdoc 7
|
||||
source it was generated from.
|
||||
.It Cm tag Ns Op = Ns Ar term
|
||||
If the formatted manual page is opened in a pager,
|
||||
go to the definition of the
|
||||
.Ar term
|
||||
rather than showing the manual page from the beginning.
|
||||
If no
|
||||
.Ar term
|
||||
is specified, reuse the first command line argument that is not a
|
||||
.Ar section
|
||||
number.
|
||||
If that argument is in
|
||||
.Xr apropos 1
|
||||
.Ar key Ns = Ns Ar val
|
||||
format, only the
|
||||
.Ar val
|
||||
is used rather than the argument as a whole.
|
||||
This is useful for commands like
|
||||
.Ql man -akO tag Ic=ulimit
|
||||
to search for a keyword and jump right to its definition
|
||||
in the matching manual pages.
|
||||
.It Cm width Ns = Ns Ar width
|
||||
The output width is set to
|
||||
.Ar width
|
||||
@ -308,9 +346,9 @@ Equations rendered from
|
||||
.Xr eqn 7
|
||||
blocks use MathML.
|
||||
.Pp
|
||||
The
|
||||
.Pa mandoc.css
|
||||
file documents style-sheet classes available for customising output.
|
||||
The file
|
||||
.Pa /usr/share/misc/mandoc.css
|
||||
documents style-sheet classes available for customising output.
|
||||
If a style-sheet is not specified with
|
||||
.Fl O Cm style ,
|
||||
.Fl T Cm html
|
||||
@ -345,7 +383,7 @@ Instances of
|
||||
are replaced with the include filename.
|
||||
The default is not to present a
|
||||
hyperlink.
|
||||
.It Cm man Ns = Ns Ar fmt
|
||||
.It Cm man Ns = Ns Ar fmt Ns Op ; Ns Ar fmt
|
||||
The string
|
||||
.Ar fmt ,
|
||||
for example,
|
||||
@ -361,12 +399,19 @@ are replaced with the linked manual's name and section, respectively.
|
||||
If no section is included, section 1 is assumed.
|
||||
The default is not to
|
||||
present a hyperlink.
|
||||
If two formats are given and a file
|
||||
.Ar %N.%S
|
||||
exists in the current directory, the first format is used;
|
||||
otherwise, the second format is used.
|
||||
.It Cm style Ns = Ns Ar style.css
|
||||
The file
|
||||
.Ar style.css
|
||||
is used for an external style-sheet.
|
||||
This must be a valid absolute or
|
||||
relative URI.
|
||||
.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.
|
||||
.El
|
||||
.Ss Locale Output
|
||||
By default,
|
||||
@ -667,10 +712,10 @@ To page manuals to the terminal:
|
||||
.Dl $ mandoc -l mandoc.1 man.1 apropos.1 makewhatis.8
|
||||
.Pp
|
||||
To produce HTML manuals with
|
||||
.Pa mandoc.css
|
||||
.Pa /usr/share/misc/mandoc.css
|
||||
as the style-sheet:
|
||||
.Pp
|
||||
.Dl $ mandoc \-T html -O style=mandoc.css mdoc.7 \*(Gt mdoc.7.html
|
||||
.Dl $ mandoc \-T html -O style=/usr/share/misc/mandoc.css mdoc.7 > mdoc.7.html
|
||||
.Pp
|
||||
To check over a large set of manuals:
|
||||
.Pp
|
||||
@ -678,7 +723,7 @@ To check over a large set of manuals:
|
||||
.Pp
|
||||
To produce a series of PostScript manuals for A4 paper:
|
||||
.Pp
|
||||
.Dl $ mandoc \-T ps \-O paper=a4 mdoc.7 man.7 \*(Gt manuals.ps
|
||||
.Dl $ mandoc \-T ps \-O paper=a4 mdoc.7 man.7 > manuals.ps
|
||||
.Pp
|
||||
Convert a modern
|
||||
.Xr mdoc 7
|
||||
@ -688,20 +733,36 @@ format, for use on systems lacking an
|
||||
.Xr mdoc 7
|
||||
parser:
|
||||
.Pp
|
||||
.Dl $ mandoc \-T man foo.mdoc \*(Gt foo.man
|
||||
.Dl $ mandoc \-T man foo.mdoc > foo.man
|
||||
.Sh DIAGNOSTICS
|
||||
Messages displayed by
|
||||
.Nm
|
||||
follow this format:
|
||||
.Bd -ragged -offset indent
|
||||
.Nm :
|
||||
.Ar file : Ns Ar line : Ns Ar column : level : message : macro args
|
||||
.Ar file : Ns Ar line : Ns Ar column : level : message : macro arguments
|
||||
.Pq Ar os
|
||||
.Ed
|
||||
.Pp
|
||||
Line and column numbers start at 1.
|
||||
The first three fields identify the
|
||||
.Ar file
|
||||
name,
|
||||
.Ar line
|
||||
number, and
|
||||
.Ar column
|
||||
number of the input file where the message was triggered.
|
||||
The line and column numbers start at 1.
|
||||
Both are omitted for messages referring to an input file as a whole.
|
||||
Macro names and arguments are omitted where meaningless.
|
||||
All
|
||||
.Ar level
|
||||
and
|
||||
.Ar message
|
||||
strings are explained below.
|
||||
The name of the
|
||||
.Ar macro
|
||||
triggering the message and its
|
||||
.Ar arguments
|
||||
are omitted where meaningless.
|
||||
The
|
||||
.Ar os
|
||||
operating system specifier is omitted for messages that are relevant
|
||||
@ -1606,6 +1667,12 @@ or
|
||||
.Cm off .
|
||||
The invalid argument is moved out of the macro, which leaves the macro
|
||||
empty, causing it to toggle the spacing mode.
|
||||
.It Sy "argument contains two font escapes"
|
||||
.Pq roff
|
||||
The second argument of a
|
||||
.Ic char
|
||||
request contains more than one font escape sequence.
|
||||
A wrong font may remain active after using the character.
|
||||
.It Sy "unknown font, skipping request"
|
||||
.Pq man , tbl
|
||||
A
|
||||
@ -1651,7 +1718,8 @@ Start it on a new input line to help formatters produce correct spacing.
|
||||
.It Sy "invalid escape sequence"
|
||||
.Pq roff
|
||||
An escape sequence has an invalid opening argument delimiter, lacks the
|
||||
closing argument delimiter, or the argument has too few characters.
|
||||
closing argument delimiter, the argument is of an invalid form, or it is
|
||||
a character escape sequence with an invalid name.
|
||||
If the argument is incomplete,
|
||||
.Ic \e*
|
||||
and
|
||||
@ -1664,6 +1732,12 @@ and
|
||||
.Ic \ew
|
||||
to the length of the incomplete argument.
|
||||
All other invalid escape sequences are ignored.
|
||||
.It Sy "undefined escape, printing literally"
|
||||
.Pq roff
|
||||
In an escape sequence, the first character
|
||||
right after the leading backslash is invalid.
|
||||
That character is printed literally,
|
||||
which is equivalent to ignoring the backslash.
|
||||
.It Sy "undefined string, using \(dq\(dq"
|
||||
.Pq roff
|
||||
If a string is used without being defined before,
|
||||
@ -1807,6 +1881,13 @@ or
|
||||
macro.
|
||||
It may be mistyped or unsupported.
|
||||
The request or macro is discarded including its arguments.
|
||||
.It Sy "skipping request outside macro"
|
||||
.Pq roff
|
||||
A
|
||||
.Ic shift
|
||||
or
|
||||
.Ic return
|
||||
request occurs outside any macro definition and has no effect.
|
||||
.It Sy "skipping insecure request"
|
||||
.Pq roff
|
||||
An input file attempted to run a shell command
|
||||
@ -1916,6 +1997,14 @@ When parsing for a request or a user-defined macro name to be called,
|
||||
only the escape sequence is discarded.
|
||||
The characters preceding it are used as the request or macro name,
|
||||
the characters following it are used as the arguments to the request or macro.
|
||||
.It Sy "using macro argument outside macro"
|
||||
.Pq roff
|
||||
The escape sequence \e$ occurs outside any macro definition
|
||||
and expands to the empty string.
|
||||
.It Sy "argument number is not numeric"
|
||||
.Pq roff
|
||||
The argument of the escape sequence \e$ is not a digit;
|
||||
the escape sequence expands to the empty string.
|
||||
.It Sy "NOT IMPLEMENTED: Bd -file"
|
||||
.Pq mdoc
|
||||
For security reasons, the
|
||||
@ -1944,6 +2033,13 @@ macro fails to specify the list type.
|
||||
The argument of a
|
||||
.Ic \&ce
|
||||
request is not a number.
|
||||
.It Sy "argument is not a character"
|
||||
.Pq roff
|
||||
The first argument of a
|
||||
.Ic char
|
||||
request is neither a single ASCII character
|
||||
nor a single character escape sequence.
|
||||
The request is ignored including all its arguments.
|
||||
.It Sy "missing manual name, using \(dq\(dq"
|
||||
.Pq mdoc
|
||||
The first call to
|
||||
@ -1978,6 +2074,13 @@ or
|
||||
.Ic \&gsize
|
||||
statement has a non-numeric or negative argument or no argument at all.
|
||||
The invalid request or statement is ignored.
|
||||
.It Sy "excessive shift"
|
||||
.Pq roff
|
||||
The argument of a
|
||||
.Ic shift
|
||||
request is larger than the number of arguments of the macro that is
|
||||
currently being executed.
|
||||
All macro arguments are deleted and \en(.$ is set to zero.
|
||||
.It Sy "NOT IMPLEMENTED: .so with absolute path or \(dq..\(dq"
|
||||
.Pq roff
|
||||
For security reasons,
|
||||
@ -2100,6 +2203,13 @@ implementations but not by
|
||||
.Nm
|
||||
was found in an input file.
|
||||
It is replaced by a question mark.
|
||||
.It Sy "unsupported escape sequence"
|
||||
.Pq roff
|
||||
An input file contains an escape sequence supported by GNU troff
|
||||
or Heirloom troff but not by
|
||||
.Nm ,
|
||||
and it is likely that this will cause information loss
|
||||
or considerable misformatting.
|
||||
.It Sy "unsupported roff request"
|
||||
.Pq roff
|
||||
An input file contains a
|
||||
|
187
mandoc.3
187
mandoc.3
@ -1,4 +1,4 @@
|
||||
.\" $Id: mandoc.3,v 1.41 2017/07/04 23:40:01 schwarze Exp $
|
||||
.\" $Id: mandoc.3,v 1.44 2018/12/30 00:49:55 schwarze Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
.\" Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
@ -15,30 +15,23 @@
|
||||
.\" 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 4 2017 $
|
||||
.Dd $Mdocdate: December 30 2018 $
|
||||
.Dt MANDOC 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm mandoc ,
|
||||
.Nm deroff ,
|
||||
.Nm mandocmsg ,
|
||||
.Nm man_mparse ,
|
||||
.Nm man_validate ,
|
||||
.Nm mdoc_validate ,
|
||||
.Nm mparse_alloc ,
|
||||
.Nm mparse_copy ,
|
||||
.Nm mparse_free ,
|
||||
.Nm mparse_getkeep ,
|
||||
.Nm mparse_keep ,
|
||||
.Nm mparse_open ,
|
||||
.Nm mparse_readfd ,
|
||||
.Nm mparse_reset ,
|
||||
.Nm mparse_result ,
|
||||
.Nm mparse_strerror ,
|
||||
.Nm mparse_strlevel ,
|
||||
.Nm mparse_updaterc
|
||||
.Nm mparse_result
|
||||
.Nd mandoc macro compiler library
|
||||
.Sh SYNOPSIS
|
||||
.In sys/types.h
|
||||
.In stdio.h
|
||||
.In mandoc.h
|
||||
.Pp
|
||||
.Fd "#define ASCII_NBRSP"
|
||||
@ -47,38 +40,23 @@
|
||||
.Ft struct mparse *
|
||||
.Fo mparse_alloc
|
||||
.Fa "int options"
|
||||
.Fa "enum mandocerr mmin"
|
||||
.Fa "mandocmsg mmsg"
|
||||
.Fa "enum mandoc_os oe_e"
|
||||
.Fa "char *os_s"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo (*mandocmsg)
|
||||
.Fa "enum mandocerr errtype"
|
||||
.Fa "enum mandoclevel level"
|
||||
.Fa "const char *file"
|
||||
.Fa "int line"
|
||||
.Fa "int col"
|
||||
.Fa "const char *msg"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo mparse_free
|
||||
.Fa "struct mparse *parse"
|
||||
.Fc
|
||||
.Ft const char *
|
||||
.Fo mparse_getkeep
|
||||
.Fa "const struct mparse *parse"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo mparse_keep
|
||||
.Fa "struct mparse *parse"
|
||||
.Fo mparse_copy
|
||||
.Fa "const struct mparse *parse"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo mparse_open
|
||||
.Fa "struct mparse *parse"
|
||||
.Fa "const char *fname"
|
||||
.Fc
|
||||
.Ft "enum mandoclevel"
|
||||
.Ft void
|
||||
.Fo mparse_readfd
|
||||
.Fa "struct mparse *parse"
|
||||
.Fa "int fd"
|
||||
@ -88,24 +66,9 @@
|
||||
.Fo mparse_reset
|
||||
.Fa "struct mparse *parse"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Ft struct roff_meta *
|
||||
.Fo mparse_result
|
||||
.Fa "struct mparse *parse"
|
||||
.Fa "struct roff_man **man"
|
||||
.Fa "char **sodest"
|
||||
.Fc
|
||||
.Ft "const char *"
|
||||
.Fo mparse_strerror
|
||||
.Fa "enum mandocerr"
|
||||
.Fc
|
||||
.Ft "const char *"
|
||||
.Fo mparse_strlevel
|
||||
.Fa "enum mandoclevel"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo mparse_updaterc
|
||||
.Fa "struct mparse *parse"
|
||||
.Fa "enum mandoclevel *rc"
|
||||
.Fc
|
||||
.In roff.h
|
||||
.Ft void
|
||||
@ -118,22 +81,10 @@
|
||||
.In mdoc.h
|
||||
.Vt extern const char * const * mdoc_argnames;
|
||||
.Vt extern const char * const * mdoc_macronames;
|
||||
.Ft void
|
||||
.Fo mdoc_validate
|
||||
.Fa "struct roff_man *mdoc"
|
||||
.Fc
|
||||
.In sys/types.h
|
||||
.In mandoc.h
|
||||
.In man.h
|
||||
.Vt extern const char * const * man_macronames;
|
||||
.Ft "const struct mparse *"
|
||||
.Fo man_mparse
|
||||
.Fa "const struct roff_man *man"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo man_validate
|
||||
.Fa "struct roff_man *man"
|
||||
.Fc
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm mandoc
|
||||
@ -174,27 +125,13 @@ close it with
|
||||
retrieve the syntax tree with
|
||||
.Fn mparse_result ;
|
||||
.It
|
||||
depending on whether the
|
||||
.Fa macroset
|
||||
member of the returned
|
||||
.Vt struct roff_man
|
||||
is
|
||||
.Dv MACROSET_MDOC
|
||||
or
|
||||
.Dv MACROSET_MAN ,
|
||||
validate it with
|
||||
.Fn mdoc_validate
|
||||
or
|
||||
.Fn man_validate ,
|
||||
respectively;
|
||||
.It
|
||||
if information about the validity of the input is needed, fetch it with
|
||||
.Fn mparse_updaterc ;
|
||||
.It
|
||||
iterate over parse nodes with starting from the
|
||||
.Fa first
|
||||
member of the returned
|
||||
.Vt struct roff_man ;
|
||||
.Vt struct roff_meta ;
|
||||
.It
|
||||
free all allocated memory with
|
||||
.Fn mparse_free
|
||||
@ -232,9 +169,6 @@ and freed with
|
||||
This may be used across parsed input if
|
||||
.Fn mparse_reset
|
||||
is called between parses.
|
||||
.It Vt "mandocmsg"
|
||||
A prototype for a function to handle error and warning
|
||||
messages emitted by the parser.
|
||||
.El
|
||||
.Ss Functions
|
||||
.Bl -ohang
|
||||
@ -245,35 +179,11 @@ including text contained in its child nodes.
|
||||
To be used on children of the
|
||||
.Fa first
|
||||
member of
|
||||
.Vt struct roff_man .
|
||||
.Vt struct roff_meta .
|
||||
When it is no longer needed, the pointer returned from
|
||||
.Fn deroff
|
||||
can be passed to
|
||||
.Xr free 3 .
|
||||
.It Fn man_mparse
|
||||
Get the parser used for the current output.
|
||||
Declared in
|
||||
.In man.h ,
|
||||
implemented in
|
||||
.Pa man.c .
|
||||
.It Fn man_validate
|
||||
Validate the
|
||||
.Dv MACROSET_MAN
|
||||
parse tree obtained with
|
||||
.Fn mparse_result .
|
||||
Declared in
|
||||
.In man.h ,
|
||||
implemented in
|
||||
.Pa man.c .
|
||||
.It Fn mdoc_validate
|
||||
Validate the
|
||||
.Dv MACROSET_MDOC
|
||||
parse tree obtained with
|
||||
.Fn mparse_result .
|
||||
Declared in
|
||||
.In mdoc.h ,
|
||||
implemented in
|
||||
.Pa mdoc.c .
|
||||
.It Fn mparse_alloc
|
||||
Allocate a parser.
|
||||
The arguments have the following effect:
|
||||
@ -295,8 +205,8 @@ file inclusion requests are always honoured.
|
||||
Otherwise, if the request is the only content in an input file,
|
||||
only the file name is remembered, to be returned in the
|
||||
.Fa sodest
|
||||
argument of
|
||||
.Fn mparse_result .
|
||||
field of
|
||||
.Vt struct roff_meta .
|
||||
.Pp
|
||||
When the
|
||||
.Dv MPARSE_QUICK
|
||||
@ -305,24 +215,14 @@ This is for example useful in
|
||||
.Xr makewhatis 8
|
||||
.Fl Q
|
||||
to quickly build minimal databases.
|
||||
.It Ar mmin
|
||||
Can be set to
|
||||
.Dv MANDOCERR_BASE ,
|
||||
.Dv MANDOCERR_STYLE ,
|
||||
.Dv MANDOCERR_WARNING ,
|
||||
.Dv MANDOCERR_ERROR ,
|
||||
.Dv MANDOCERR_UNSUPP ,
|
||||
or
|
||||
.Dv MANDOCERR_MAX .
|
||||
Messages below the selected level will be suppressed.
|
||||
.It Ar mmsg
|
||||
A callback function to handle errors and warnings.
|
||||
See
|
||||
.Pa main.c
|
||||
for an example.
|
||||
If printing of error messages is not desired,
|
||||
.Dv NULL
|
||||
may be passed.
|
||||
.Pp
|
||||
When the
|
||||
.Dv MARSE_VALIDATE
|
||||
bit is set,
|
||||
.Fn mparse_result
|
||||
runs the validation functions before returning the syntax tree.
|
||||
This is almost always required, except in certain debugging scenarios,
|
||||
for example to dump unvalidated syntax trees.
|
||||
.It Ar os_e
|
||||
Operating system to check base system conventions for.
|
||||
If
|
||||
@ -361,19 +261,9 @@ Declared in
|
||||
.In mandoc.h ,
|
||||
implemented in
|
||||
.Pa read.c .
|
||||
.It Fn mparse_getkeep
|
||||
Acquire the keep buffer.
|
||||
Must follow a call of
|
||||
.Fn mparse_keep .
|
||||
Declared in
|
||||
.In mandoc.h ,
|
||||
implemented in
|
||||
.Pa read.c .
|
||||
.It Fn mparse_keep
|
||||
Instruct the parser to retain a copy of its parsed input.
|
||||
This can be acquired with subsequent
|
||||
.Fn mparse_getkeep
|
||||
calls.
|
||||
.It Fn mparse_copy
|
||||
Dump a copy of the input to the standard output; used for
|
||||
.Fl man T Ns Cm man .
|
||||
Declared in
|
||||
.In mandoc.h ,
|
||||
implemented in
|
||||
@ -421,35 +311,6 @@ implemented in
|
||||
.Pa read.c .
|
||||
.It Fn mparse_result
|
||||
Obtain the result of a parse.
|
||||
One of the two pointers will be filled in.
|
||||
Declared in
|
||||
.In mandoc.h ,
|
||||
implemented in
|
||||
.Pa read.c .
|
||||
.It Fn mparse_strerror
|
||||
Return a statically-allocated string representation of an error code.
|
||||
Declared in
|
||||
.In mandoc.h ,
|
||||
implemented in
|
||||
.Pa read.c .
|
||||
.It Fn mparse_strlevel
|
||||
Return a statically-allocated string representation of a level code.
|
||||
Declared in
|
||||
.In mandoc.h ,
|
||||
implemented in
|
||||
.Pa read.c .
|
||||
.It Fn mparse_updaterc
|
||||
If the highest warning or error level that occurred during the current
|
||||
.Fa parse
|
||||
is higher than
|
||||
.Pf * Fa rc ,
|
||||
update
|
||||
.Pf * Fa rc
|
||||
accordingly.
|
||||
This is useful after calling
|
||||
.Fn mdoc_validate
|
||||
or
|
||||
.Fn man_validate .
|
||||
Declared in
|
||||
.In mandoc.h ,
|
||||
implemented in
|
||||
|
318
mandoc.c
318
mandoc.c
@ -1,4 +1,4 @@
|
||||
/* $Id: mandoc.c,v 1.104 2018/07/28 18:34:15 schwarze Exp $ */
|
||||
/* $Id: mandoc.c,v 1.114 2018/12/30 00:49:55 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2011-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
|
||||
@ -32,16 +32,70 @@
|
||||
#include "mandoc.h"
|
||||
#include "roff.h"
|
||||
#include "libmandoc.h"
|
||||
#include "roff_int.h"
|
||||
|
||||
static int a2time(time_t *, const char *, const char *);
|
||||
static char *time2a(time_t);
|
||||
|
||||
|
||||
enum mandoc_esc
|
||||
mandoc_font(const char *cp, int sz)
|
||||
{
|
||||
switch (sz) {
|
||||
case 0:
|
||||
return ESCAPE_FONTPREV;
|
||||
case 1:
|
||||
switch (cp[0]) {
|
||||
case 'B':
|
||||
case '3':
|
||||
return ESCAPE_FONTBOLD;
|
||||
case 'I':
|
||||
case '2':
|
||||
return ESCAPE_FONTITALIC;
|
||||
case 'P':
|
||||
return ESCAPE_FONTPREV;
|
||||
case 'R':
|
||||
case '1':
|
||||
return ESCAPE_FONTROMAN;
|
||||
case '4':
|
||||
return ESCAPE_FONTBI;
|
||||
default:
|
||||
return ESCAPE_ERROR;
|
||||
}
|
||||
case 2:
|
||||
switch (cp[0]) {
|
||||
case 'B':
|
||||
switch (cp[1]) {
|
||||
case 'I':
|
||||
return ESCAPE_FONTBI;
|
||||
default:
|
||||
return ESCAPE_ERROR;
|
||||
}
|
||||
case 'C':
|
||||
switch (cp[1]) {
|
||||
case 'B':
|
||||
return ESCAPE_FONTBOLD;
|
||||
case 'I':
|
||||
return ESCAPE_FONTITALIC;
|
||||
case 'R':
|
||||
case 'W':
|
||||
return ESCAPE_FONTCW;
|
||||
default:
|
||||
return ESCAPE_ERROR;
|
||||
}
|
||||
default:
|
||||
return ESCAPE_ERROR;
|
||||
}
|
||||
default:
|
||||
return ESCAPE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
enum mandoc_esc
|
||||
mandoc_escape(const char **end, const char **start, int *sz)
|
||||
{
|
||||
const char *local_start;
|
||||
int local_sz;
|
||||
int local_sz, c, i;
|
||||
char term;
|
||||
enum mandoc_esc gly;
|
||||
|
||||
@ -55,6 +109,14 @@ mandoc_escape(const char **end, const char **start, int *sz)
|
||||
if (NULL == sz)
|
||||
sz = &local_sz;
|
||||
|
||||
/*
|
||||
* Treat "\E" just like "\";
|
||||
* it only makes a difference in copy mode.
|
||||
*/
|
||||
|
||||
if (**end == 'E')
|
||||
++*end;
|
||||
|
||||
/*
|
||||
* Beyond the backslash, at least one input character
|
||||
* is part of the escape sequence. With one exception
|
||||
@ -77,6 +139,10 @@ mandoc_escape(const char **end, const char **start, int *sz)
|
||||
*sz = 2;
|
||||
break;
|
||||
case '[':
|
||||
if (**start == ' ') {
|
||||
++*end;
|
||||
return ESCAPE_ERROR;
|
||||
}
|
||||
gly = ESCAPE_SPECIAL;
|
||||
term = ']';
|
||||
break;
|
||||
@ -91,11 +157,26 @@ mandoc_escape(const char **end, const char **start, int *sz)
|
||||
/*
|
||||
* Escapes taking no arguments at all.
|
||||
*/
|
||||
case 'd':
|
||||
case 'u':
|
||||
case '!':
|
||||
case '?':
|
||||
return ESCAPE_UNSUPP;
|
||||
case '%':
|
||||
case '&':
|
||||
case ')':
|
||||
case ',':
|
||||
case '/':
|
||||
case '^':
|
||||
case 'a':
|
||||
case 'd':
|
||||
case 'r':
|
||||
case 't':
|
||||
case 'u':
|
||||
case '{':
|
||||
case '|':
|
||||
case '}':
|
||||
return ESCAPE_IGNORE;
|
||||
case 'c':
|
||||
return ESCAPE_NOSPACE;
|
||||
case 'p':
|
||||
return ESCAPE_BREAK;
|
||||
|
||||
@ -113,32 +194,57 @@ mandoc_escape(const char **end, const char **start, int *sz)
|
||||
* 'X' is the trigger. These have opaque sub-strings.
|
||||
*/
|
||||
case 'F':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'k':
|
||||
case 'M':
|
||||
case 'm':
|
||||
case 'n':
|
||||
case 'O':
|
||||
case 'V':
|
||||
case 'Y':
|
||||
gly = ESCAPE_IGNORE;
|
||||
/* FALLTHROUGH */
|
||||
case 'f':
|
||||
if (ESCAPE_ERROR == gly)
|
||||
gly = ESCAPE_FONT;
|
||||
gly = (*start)[-1] == 'f' ? ESCAPE_FONT : ESCAPE_IGNORE;
|
||||
switch (**start) {
|
||||
case '(':
|
||||
if ((*start)[-1] == 'O')
|
||||
gly = ESCAPE_ERROR;
|
||||
*start = ++*end;
|
||||
*sz = 2;
|
||||
break;
|
||||
case '[':
|
||||
if ((*start)[-1] == 'O')
|
||||
gly = (*start)[1] == '5' ?
|
||||
ESCAPE_UNSUPP : ESCAPE_ERROR;
|
||||
*start = ++*end;
|
||||
term = ']';
|
||||
break;
|
||||
default:
|
||||
if ((*start)[-1] == 'O') {
|
||||
switch (**start) {
|
||||
case '0':
|
||||
gly = ESCAPE_UNSUPP;
|
||||
break;
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
break;
|
||||
default:
|
||||
gly = ESCAPE_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*sz = 1;
|
||||
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
|
||||
@ -250,18 +356,29 @@ mandoc_escape(const char **end, const char **start, int *sz)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Anything else is assumed to be a glyph.
|
||||
* In this case, pass back the character after the backslash.
|
||||
* Several special characters can be encoded as
|
||||
* one-byte escape sequences without using \[].
|
||||
*/
|
||||
default:
|
||||
case ' ':
|
||||
case '\'':
|
||||
case '-':
|
||||
case '.':
|
||||
case '0':
|
||||
case ':':
|
||||
case '_':
|
||||
case '`':
|
||||
case 'e':
|
||||
case '~':
|
||||
gly = ESCAPE_SPECIAL;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
if (gly == ESCAPE_ERROR)
|
||||
gly = ESCAPE_UNDEF;
|
||||
*start = --*end;
|
||||
*sz = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
assert(ESCAPE_ERROR != gly);
|
||||
|
||||
/*
|
||||
* Read up to the terminating character,
|
||||
* paying attention to nested escapes.
|
||||
@ -284,6 +401,15 @@ mandoc_escape(const char **end, const char **start, int *sz)
|
||||
}
|
||||
}
|
||||
*sz = (*end)++ - *start;
|
||||
|
||||
/*
|
||||
* The file chars.c only provides one common list
|
||||
* of character names, but \[-] == \- is the only
|
||||
* one of the characters with one-byte names that
|
||||
* allows enclosing the name in brackets.
|
||||
*/
|
||||
if (gly == ESCAPE_SPECIAL && *sz == 1 && **start != '-')
|
||||
return ESCAPE_ERROR;
|
||||
} else {
|
||||
assert(*sz > 0);
|
||||
if ((size_t)*sz > strlen(*start))
|
||||
@ -295,43 +421,25 @@ mandoc_escape(const char **end, const char **start, int *sz)
|
||||
|
||||
switch (gly) {
|
||||
case ESCAPE_FONT:
|
||||
if (2 == *sz) {
|
||||
if ('C' == **start) {
|
||||
/*
|
||||
* Treat constant-width font modes
|
||||
* just like regular font modes.
|
||||
*/
|
||||
(*start)++;
|
||||
(*sz)--;
|
||||
} else {
|
||||
if ('B' == (*start)[0] && 'I' == (*start)[1])
|
||||
gly = ESCAPE_FONTBI;
|
||||
break;
|
||||
}
|
||||
} else if (1 != *sz)
|
||||
break;
|
||||
|
||||
switch (**start) {
|
||||
case '3':
|
||||
case 'B':
|
||||
gly = ESCAPE_FONTBOLD;
|
||||
break;
|
||||
case '2':
|
||||
case 'I':
|
||||
gly = ESCAPE_FONTITALIC;
|
||||
break;
|
||||
case 'P':
|
||||
gly = ESCAPE_FONTPREV;
|
||||
break;
|
||||
case '1':
|
||||
case 'R':
|
||||
gly = ESCAPE_FONTROMAN;
|
||||
break;
|
||||
}
|
||||
gly = mandoc_font(*start, *sz);
|
||||
break;
|
||||
case ESCAPE_SPECIAL:
|
||||
if (1 == *sz && 'c' == **start)
|
||||
gly = ESCAPE_NOSPACE;
|
||||
if (**start == 'c') {
|
||||
if (*sz < 6 || *sz > 7 ||
|
||||
strncmp(*start, "char", 4) != 0 ||
|
||||
(int)strspn(*start + 4, "0123456789") + 4 < *sz)
|
||||
break;
|
||||
c = 0;
|
||||
for (i = 4; i < *sz; i++)
|
||||
c = 10 * c + ((*start)[i] - '0');
|
||||
if (c < 0x21 || (c > 0x7e && c < 0xa0) || c > 0xff)
|
||||
break;
|
||||
*start += 4;
|
||||
*sz -= 4;
|
||||
gly = ESCAPE_NUMBERED;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unicode escapes are defined in groff as \[u0000]
|
||||
* to \[u10FFFF], where the contained value must be
|
||||
@ -358,101 +466,6 @@ mandoc_escape(const char **end, const char **start, int *sz)
|
||||
return gly;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a quoted or unquoted roff-style request or macro argument.
|
||||
* Return a pointer to the parsed argument, which is either the original
|
||||
* pointer or advanced by one byte in case the argument is quoted.
|
||||
* NUL-terminate the argument in place.
|
||||
* Collapse pairs of quotes inside quoted arguments.
|
||||
* Advance the argument pointer to the next argument,
|
||||
* or to the NUL byte terminating the argument line.
|
||||
*/
|
||||
char *
|
||||
mandoc_getarg(struct mparse *parse, char **cpp, int ln, int *pos)
|
||||
{
|
||||
char *start, *cp;
|
||||
int quoted, pairs, white;
|
||||
|
||||
/* Quoting can only start with a new word. */
|
||||
start = *cpp;
|
||||
quoted = 0;
|
||||
if ('"' == *start) {
|
||||
quoted = 1;
|
||||
start++;
|
||||
}
|
||||
|
||||
pairs = 0;
|
||||
white = 0;
|
||||
for (cp = start; '\0' != *cp; cp++) {
|
||||
|
||||
/*
|
||||
* Move the following text left
|
||||
* after quoted quotes and after "\\" and "\t".
|
||||
*/
|
||||
if (pairs)
|
||||
cp[-pairs] = cp[0];
|
||||
|
||||
if ('\\' == cp[0]) {
|
||||
/*
|
||||
* In copy mode, translate double to single
|
||||
* backslashes and backslash-t to literal tabs.
|
||||
*/
|
||||
switch (cp[1]) {
|
||||
case 't':
|
||||
cp[0] = '\t';
|
||||
/* FALLTHROUGH */
|
||||
case '\\':
|
||||
pairs++;
|
||||
cp++;
|
||||
break;
|
||||
case ' ':
|
||||
/* Skip escaped blanks. */
|
||||
if (0 == quoted)
|
||||
cp++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (0 == quoted) {
|
||||
if (' ' == cp[0]) {
|
||||
/* Unescaped blanks end unquoted args. */
|
||||
white = 1;
|
||||
break;
|
||||
}
|
||||
} else if ('"' == cp[0]) {
|
||||
if ('"' == cp[1]) {
|
||||
/* Quoted quotes collapse. */
|
||||
pairs++;
|
||||
cp++;
|
||||
} else {
|
||||
/* Unquoted quotes end quoted args. */
|
||||
quoted = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Quoted argument without a closing quote. */
|
||||
if (1 == quoted)
|
||||
mandoc_msg(MANDOCERR_ARG_QUOTE, parse, ln, *pos, NULL);
|
||||
|
||||
/* NUL-terminate this argument and move to the next one. */
|
||||
if (pairs)
|
||||
cp[-pairs] = '\0';
|
||||
if ('\0' != *cp) {
|
||||
*cp++ = '\0';
|
||||
while (' ' == *cp)
|
||||
cp++;
|
||||
}
|
||||
*pos += (int)(cp - start) + (quoted ? 1 : 0);
|
||||
*cpp = cp;
|
||||
|
||||
if ('\0' == *cp && (white || ' ' == cp[-1]))
|
||||
mandoc_msg(MANDOCERR_SPACE_EOL, parse, ln, *pos, NULL);
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
static int
|
||||
a2time(time_t *t, const char *fmt, const char *p)
|
||||
{
|
||||
@ -529,7 +542,7 @@ mandoc_normdate(struct roff_man *man, char *in, int ln, int pos)
|
||||
/* No date specified: use today's date. */
|
||||
|
||||
if (in == NULL || *in == '\0' || strcmp(in, "$" "Mdocdate$") == 0) {
|
||||
mandoc_msg(MANDOCERR_DATE_MISSING, man->parse, ln, pos, NULL);
|
||||
mandoc_msg(MANDOCERR_DATE_MISSING, ln, pos, NULL);
|
||||
return time2a(time(NULL));
|
||||
}
|
||||
|
||||
@ -539,23 +552,20 @@ mandoc_normdate(struct roff_man *man, char *in, int ln, int pos)
|
||||
a2time(&t, "%b %d, %Y", in)) {
|
||||
cp = time2a(t);
|
||||
if (t > time(NULL) + 86400)
|
||||
mandoc_msg(MANDOCERR_DATE_FUTURE, man->parse,
|
||||
ln, pos, cp);
|
||||
mandoc_msg(MANDOCERR_DATE_FUTURE, ln, pos, "%s", cp);
|
||||
else if (*in != '$' && strcmp(in, cp) != 0)
|
||||
mandoc_msg(MANDOCERR_DATE_NORM, man->parse,
|
||||
ln, pos, cp);
|
||||
mandoc_msg(MANDOCERR_DATE_NORM, ln, pos, "%s", 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, man->parse, ln, pos, in);
|
||||
mandoc_msg(MANDOCERR_DATE_BAD, ln, pos, "%s", in);
|
||||
else if (t > time(NULL) + 86400)
|
||||
mandoc_msg(MANDOCERR_DATE_FUTURE, man->parse, ln, pos, in);
|
||||
else if (man->macroset == MACROSET_MDOC)
|
||||
mandoc_vmsg(MANDOCERR_DATE_LEGACY, man->parse,
|
||||
ln, pos, "Dd %s", in);
|
||||
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);
|
||||
|
||||
/* Use any non-mdoc(7) date verbatim. */
|
||||
|
||||
|
114
mandoc.css
114
mandoc.css
@ -1,6 +1,11 @@
|
||||
/* $Id: mandoc.css,v 1.36 2018/07/23 22:51:26 schwarze Exp $ */
|
||||
/* $Id: mandoc.css,v 1.45 2019/03/01 10:57:18 schwarze Exp $ */
|
||||
/*
|
||||
* Standard style sheet for mandoc(1) -Thtml and man.cgi(8).
|
||||
*
|
||||
* Written by Ingo Schwarze <schwarze@openbsd.org>.
|
||||
* I place this file into the public domain.
|
||||
* Permission to use, copy, modify, and distribute it for any purpose
|
||||
* with or without fee is hereby granted, without any conditions.
|
||||
*/
|
||||
|
||||
/* Global defaults. */
|
||||
@ -8,8 +13,16 @@
|
||||
html { max-width: 65em; }
|
||||
body { font-family: Helvetica,Arial,sans-serif; }
|
||||
table { margin-top: 0em;
|
||||
margin-bottom: 0em; }
|
||||
td { vertical-align: top; }
|
||||
margin-bottom: 0em;
|
||||
border-collapse: collapse; }
|
||||
/* Some browsers set border-color in a browser style for tbody,
|
||||
* but not for table, resulting in inconsistent border styling. */
|
||||
tbody { border-color: inherit; }
|
||||
tr { border-color: inherit; }
|
||||
td { vertical-align: top;
|
||||
padding-left: 0.2em;
|
||||
padding-right: 0.2em;
|
||||
border-color: inherit; }
|
||||
ul, ol, dl { margin-top: 0em;
|
||||
margin-bottom: 0em; }
|
||||
li, dt { margin-top: 1em; }
|
||||
@ -52,12 +65,14 @@ td.foot-os { text-align: right; }
|
||||
|
||||
.manual-text {
|
||||
margin-left: 3.8em; }
|
||||
.Nd { display: inline; }
|
||||
.Sh { margin-top: 1.2em;
|
||||
.Nd { }
|
||||
section.Sh { }
|
||||
h1.Sh { margin-top: 1.2em;
|
||||
margin-bottom: 0.6em;
|
||||
margin-left: -3.2em;
|
||||
font-size: 110%; }
|
||||
.Ss { margin-top: 1.2em;
|
||||
section.Ss { }
|
||||
h2.Ss { margin-top: 1.2em;
|
||||
margin-bottom: 0.6em;
|
||||
margin-left: -1.2em;
|
||||
font-size: 105%; }
|
||||
@ -106,20 +121,25 @@ td.foot-os { text-align: right; }
|
||||
.Bl-ohang > dt { }
|
||||
.Bl-ohang > dd {
|
||||
margin-left: 0em; }
|
||||
.Bl-tag { margin-left: 5.5em; }
|
||||
.Bl-tag { margin-top: 0.6em;
|
||||
margin-left: 5.5em; }
|
||||
.Bl-tag > dt {
|
||||
float: left;
|
||||
margin-top: 0em;
|
||||
margin-left: -5.5em;
|
||||
padding-right: 1.2em;
|
||||
padding-right: 0.5em;
|
||||
vertical-align: top; }
|
||||
.Bl-tag > dd {
|
||||
clear: right;
|
||||
width: 100%;
|
||||
margin-top: 0em;
|
||||
margin-left: 0em;
|
||||
margin-bottom: 0.6em;
|
||||
vertical-align: top;
|
||||
overflow: auto; }
|
||||
.Bl-compact { margin-top: 0em; }
|
||||
.Bl-compact > dd {
|
||||
margin-bottom: 0em; }
|
||||
.Bl-compact > dt {
|
||||
margin-top: 0em; }
|
||||
|
||||
@ -151,7 +171,7 @@ td.foot-os { text-align: right; }
|
||||
.RsV { }
|
||||
|
||||
.eqn { }
|
||||
.tbl { }
|
||||
.tbl td { vertical-align: middle; }
|
||||
|
||||
.HP { margin-left: 3.8em;
|
||||
text-indent: -3.8em; }
|
||||
@ -236,12 +256,86 @@ a.In { }
|
||||
font-weight: normal;
|
||||
font-family: monospace; }
|
||||
|
||||
/* Tooltip support. */
|
||||
|
||||
h1.Sh, h2.Ss { position: relative; }
|
||||
.An, .Ar, .Cd, .Cm, .Dv, .Em, .Er, .Ev, .Fa, .Fd, .Fl, .Fn, .Ft,
|
||||
.Ic, code.In, .Lb, .Lk, .Ms, .Mt, .Nd, code.Nm, .Pa, .Rs,
|
||||
.St, .Sx, .Sy, .Va, .Vt, .Xr {
|
||||
display: inline-block;
|
||||
position: relative; }
|
||||
|
||||
.An::before { content: "An"; }
|
||||
.Ar::before { content: "Ar"; }
|
||||
.Cd::before { content: "Cd"; }
|
||||
.Cm::before { content: "Cm"; }
|
||||
.Dv::before { content: "Dv"; }
|
||||
.Em::before { content: "Em"; }
|
||||
.Er::before { content: "Er"; }
|
||||
.Ev::before { content: "Ev"; }
|
||||
.Fa::before { content: "Fa"; }
|
||||
.Fd::before { content: "Fd"; }
|
||||
.Fl::before { content: "Fl"; }
|
||||
.Fn::before { content: "Fn"; }
|
||||
.Ft::before { content: "Ft"; }
|
||||
.Ic::before { content: "Ic"; }
|
||||
code.In::before { content: "In"; }
|
||||
.Lb::before { content: "Lb"; }
|
||||
.Lk::before { content: "Lk"; }
|
||||
.Ms::before { content: "Ms"; }
|
||||
.Mt::before { content: "Mt"; }
|
||||
.Nd::before { content: "Nd"; }
|
||||
code.Nm::before { content: "Nm"; }
|
||||
.Pa::before { content: "Pa"; }
|
||||
.Rs::before { content: "Rs"; }
|
||||
h1.Sh::before { content: "Sh"; }
|
||||
h2.Ss::before { content: "Ss"; }
|
||||
.St::before { content: "St"; }
|
||||
.Sx::before { content: "Sx"; }
|
||||
.Sy::before { content: "Sy"; }
|
||||
.Va::before { content: "Va"; }
|
||||
.Vt::before { content: "Vt"; }
|
||||
.Xr::before { content: "Xr"; }
|
||||
|
||||
.An::before, .Ar::before, .Cd::before, .Cm::before,
|
||||
.Dv::before, .Em::before, .Er::before, .Ev::before,
|
||||
.Fa::before, .Fd::before, .Fl::before, .Fn::before, .Ft::before,
|
||||
.Ic::before, code.In::before, .Lb::before, .Lk::before,
|
||||
.Ms::before, .Mt::before, .Nd::before, code.Nm::before,
|
||||
.Pa::before, .Rs::before,
|
||||
h1.Sh::before, h2.Ss::before, .St::before, .Sx::before, .Sy::before,
|
||||
.Va::before, .Vt::before, .Xr::before {
|
||||
opacity: 0;
|
||||
transition: .15s ease opacity;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
bottom: 100%;
|
||||
box-shadow: 0 0 .35em #000;
|
||||
padding: .15em .25em;
|
||||
white-space: nowrap;
|
||||
font-family: Helvetica,Arial,sans-serif;
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
color: black;
|
||||
background: #fff; }
|
||||
.An:hover::before, .Ar:hover::before, .Cd:hover::before, .Cm:hover::before,
|
||||
.Dv:hover::before, .Em:hover::before, .Er:hover::before, .Ev:hover::before,
|
||||
.Fa:hover::before, .Fd:hover::before, .Fl:hover::before, .Fn:hover::before,
|
||||
.Ft:hover::before, .Ic:hover::before, code.In:hover::before,
|
||||
.Lb:hover::before, .Lk:hover::before, .Ms:hover::before, .Mt:hover::before,
|
||||
.Nd:hover::before, code.Nm:hover::before, .Pa:hover::before,
|
||||
.Rs:hover::before, h1.Sh:hover::before, h2.Ss:hover::before, .St:hover::before,
|
||||
.Sx:hover::before, .Sy:hover::before, .Va:hover::before, .Vt:hover::before,
|
||||
.Xr:hover::before {
|
||||
opacity: 1;
|
||||
pointer-events: inherit; }
|
||||
|
||||
/* Overrides to avoid excessive margins on small devices. */
|
||||
|
||||
@media (max-width: 37.5em) {
|
||||
.manual-text {
|
||||
margin-left: 0.5em; }
|
||||
.Sh, .Ss { margin-left: 0em; }
|
||||
h1.Sh, h2.Ss { margin-left: 0em; }
|
||||
.Bd-indent { margin-left: 2em; }
|
||||
.Bl-hang > dd {
|
||||
margin-left: 2em; }
|
||||
|
241
mandoc.h
241
mandoc.h
@ -1,7 +1,7 @@
|
||||
/* $Id: mandoc.h,v 1.248 2018/07/28 18:34:15 schwarze Exp $ */
|
||||
/* $Id: mandoc.h,v 1.262 2018/12/16 00:17:02 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 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.
|
||||
*
|
||||
* Error handling, escape sequence, and character utilities.
|
||||
*/
|
||||
|
||||
#define ASCII_NBRSP 31 /* non-breaking space */
|
||||
@ -158,6 +160,7 @@ enum mandocerr {
|
||||
MANDOCERR_LB_BAD, /* unknown library name: Lb ... */
|
||||
MANDOCERR_RS_BAD, /* invalid content in Rs block: macro */
|
||||
MANDOCERR_SM_BAD, /* invalid Boolean argument: macro arg */
|
||||
MANDOCERR_CHAR_FONT, /* argument contains two font escapes */
|
||||
MANDOCERR_FT_BAD, /* unknown font, skipping request: ft font */
|
||||
MANDOCERR_TR_ODD, /* odd number of characters in request: tr char */
|
||||
|
||||
@ -166,6 +169,7 @@ enum mandocerr {
|
||||
MANDOCERR_FI_TAB, /* tab in filled text */
|
||||
MANDOCERR_EOS, /* new sentence, new line */
|
||||
MANDOCERR_ESC_BAD, /* invalid escape sequence: esc */
|
||||
MANDOCERR_ESC_UNDEF, /* undefined escape, printing literally: char */
|
||||
MANDOCERR_STR_UNDEF, /* undefined string, using "": name */
|
||||
|
||||
/* related to tables */
|
||||
@ -195,6 +199,7 @@ enum mandocerr {
|
||||
MANDOCERR_ROFFLOOP, /* input stack limit exceeded, infinite loop? */
|
||||
MANDOCERR_CHAR_BAD, /* skipping bad character: number */
|
||||
MANDOCERR_MACRO, /* skipping unknown macro: macro */
|
||||
MANDOCERR_REQ_NOMAC, /* skipping request outside macro: ... */
|
||||
MANDOCERR_REQ_INSEC, /* skipping insecure request: request */
|
||||
MANDOCERR_IT_STRAY, /* skipping item outside list: It ... */
|
||||
MANDOCERR_TA_STRAY, /* skipping column outside column list: Ta */
|
||||
@ -205,14 +210,18 @@ enum mandocerr {
|
||||
|
||||
/* related to request and macro arguments */
|
||||
MANDOCERR_NAMESC, /* escaped character not allowed in a name: name */
|
||||
MANDOCERR_ARG_UNDEF, /* using macro argument outside macro */
|
||||
MANDOCERR_ARG_NONUM, /* argument number is not numeric */
|
||||
MANDOCERR_BD_FILE, /* NOT IMPLEMENTED: Bd -file */
|
||||
MANDOCERR_BD_NOARG, /* skipping display without arguments: Bd */
|
||||
MANDOCERR_BL_NOTYPE, /* missing list type, using -item: Bl */
|
||||
MANDOCERR_CE_NONUM, /* argument is not numeric, using 1: ce ... */
|
||||
MANDOCERR_CHAR_ARG, /* argument is not a character: char ... */
|
||||
MANDOCERR_NM_NONAME, /* missing manual name, using "": Nm */
|
||||
MANDOCERR_OS_UNAME, /* uname(3) system call failed, using UNKNOWN */
|
||||
MANDOCERR_ST_BAD, /* unknown standard specifier: St standard */
|
||||
MANDOCERR_IT_NONUM, /* skipping request without numeric argument */
|
||||
MANDOCERR_SHIFT, /* excessive shift: ..., but max is ... */
|
||||
MANDOCERR_SO_PATH, /* NOT IMPLEMENTED: .so with absolute path or ".." */
|
||||
MANDOCERR_SO_FAIL, /* .so request failed */
|
||||
MANDOCERR_ARG_SKIP, /* skipping all arguments: macro args */
|
||||
@ -223,7 +232,12 @@ enum mandocerr {
|
||||
|
||||
MANDOCERR_TOOLARGE, /* input too large */
|
||||
MANDOCERR_CHAR_UNSUPP, /* unsupported control character: number */
|
||||
MANDOCERR_ESC_UNSUPP, /* unsupported escape sequence: escape */
|
||||
MANDOCERR_REQ_UNSUPP, /* unsupported roff request: request */
|
||||
MANDOCERR_WHILE_NEST, /* nested .while loops */
|
||||
MANDOCERR_WHILE_OUTOF, /* end of scope with open .while loop */
|
||||
MANDOCERR_WHILE_INTO, /* end of .while loop in inner scope */
|
||||
MANDOCERR_WHILE_FAIL, /* cannot continue this .while loop */
|
||||
MANDOCERR_TBLOPT_EQN, /* eqn delim option in tbl: arg */
|
||||
MANDOCERR_TBLLAYOUT_MOD, /* unsupported tbl layout modifier: m */
|
||||
MANDOCERR_TBLMACRO, /* ignoring macro in table: macro */
|
||||
@ -231,206 +245,22 @@ enum mandocerr {
|
||||
MANDOCERR_MAX
|
||||
};
|
||||
|
||||
struct tbl_opts {
|
||||
char tab; /* cell-separator */
|
||||
char decimal; /* decimal point */
|
||||
int opts;
|
||||
#define TBL_OPT_CENTRE (1 << 0)
|
||||
#define TBL_OPT_EXPAND (1 << 1)
|
||||
#define TBL_OPT_BOX (1 << 2)
|
||||
#define TBL_OPT_DBOX (1 << 3)
|
||||
#define TBL_OPT_ALLBOX (1 << 4)
|
||||
#define TBL_OPT_NOKEEP (1 << 5)
|
||||
#define TBL_OPT_NOSPACE (1 << 6)
|
||||
#define TBL_OPT_NOWARN (1 << 7)
|
||||
int cols; /* number of columns */
|
||||
int lvert; /* width of left vertical line */
|
||||
int rvert; /* width of right vertical line */
|
||||
};
|
||||
|
||||
enum tbl_cellt {
|
||||
TBL_CELL_CENTRE, /* c, C */
|
||||
TBL_CELL_RIGHT, /* r, R */
|
||||
TBL_CELL_LEFT, /* l, L */
|
||||
TBL_CELL_NUMBER, /* n, N */
|
||||
TBL_CELL_SPAN, /* s, S */
|
||||
TBL_CELL_LONG, /* a, A */
|
||||
TBL_CELL_DOWN, /* ^ */
|
||||
TBL_CELL_HORIZ, /* _, - */
|
||||
TBL_CELL_DHORIZ, /* = */
|
||||
TBL_CELL_MAX
|
||||
};
|
||||
|
||||
/*
|
||||
* A cell in a layout row.
|
||||
*/
|
||||
struct tbl_cell {
|
||||
struct tbl_cell *next;
|
||||
char *wstr; /* min width represented as a string */
|
||||
size_t width; /* minimum column width */
|
||||
size_t spacing; /* to the right of the column */
|
||||
int vert; /* width of subsequent vertical line */
|
||||
int col; /* column number, starting from 0 */
|
||||
int flags;
|
||||
#define TBL_CELL_TALIGN (1 << 0) /* t, T */
|
||||
#define TBL_CELL_BALIGN (1 << 1) /* d, D */
|
||||
#define TBL_CELL_BOLD (1 << 2) /* fB, B, b */
|
||||
#define TBL_CELL_ITALIC (1 << 3) /* fI, I, i */
|
||||
#define TBL_CELL_EQUAL (1 << 4) /* e, E */
|
||||
#define TBL_CELL_UP (1 << 5) /* u, U */
|
||||
#define TBL_CELL_WIGN (1 << 6) /* z, Z */
|
||||
#define TBL_CELL_WMAX (1 << 7) /* x, X */
|
||||
enum tbl_cellt pos;
|
||||
};
|
||||
|
||||
/*
|
||||
* A layout row.
|
||||
*/
|
||||
struct tbl_row {
|
||||
struct tbl_row *next;
|
||||
struct tbl_cell *first;
|
||||
struct tbl_cell *last;
|
||||
int vert; /* width of left vertical line */
|
||||
};
|
||||
|
||||
enum tbl_datt {
|
||||
TBL_DATA_NONE, /* has no data */
|
||||
TBL_DATA_DATA, /* consists of data/string */
|
||||
TBL_DATA_HORIZ, /* horizontal line */
|
||||
TBL_DATA_DHORIZ, /* double-horizontal line */
|
||||
TBL_DATA_NHORIZ, /* squeezed horizontal line */
|
||||
TBL_DATA_NDHORIZ /* squeezed double-horizontal line */
|
||||
};
|
||||
|
||||
/*
|
||||
* A cell within a row of data. The "string" field contains the actual
|
||||
* string value that's in the cell. The rest is layout.
|
||||
*/
|
||||
struct tbl_dat {
|
||||
struct tbl_cell *layout; /* layout cell */
|
||||
struct tbl_dat *next;
|
||||
char *string; /* data (NULL if not TBL_DATA_DATA) */
|
||||
int spans; /* how many spans follow */
|
||||
int block; /* T{ text block T} */
|
||||
enum tbl_datt pos;
|
||||
};
|
||||
|
||||
enum tbl_spant {
|
||||
TBL_SPAN_DATA, /* span consists of data */
|
||||
TBL_SPAN_HORIZ, /* span is horizontal line */
|
||||
TBL_SPAN_DHORIZ /* span is double horizontal line */
|
||||
};
|
||||
|
||||
/*
|
||||
* A row of data in a table.
|
||||
*/
|
||||
struct tbl_span {
|
||||
struct tbl_opts *opts;
|
||||
struct tbl_row *layout; /* layout row */
|
||||
struct tbl_dat *first;
|
||||
struct tbl_dat *last;
|
||||
struct tbl_span *prev;
|
||||
struct tbl_span *next;
|
||||
int line; /* parse line */
|
||||
enum tbl_spant pos;
|
||||
};
|
||||
|
||||
enum eqn_boxt {
|
||||
EQN_TEXT, /* text (number, variable, whatever) */
|
||||
EQN_SUBEXPR, /* nested `eqn' subexpression */
|
||||
EQN_LIST, /* list (braces, etc.) */
|
||||
EQN_PILE, /* vertical pile */
|
||||
EQN_MATRIX /* pile of piles */
|
||||
};
|
||||
|
||||
enum eqn_fontt {
|
||||
EQNFONT_NONE = 0,
|
||||
EQNFONT_ROMAN,
|
||||
EQNFONT_BOLD,
|
||||
EQNFONT_FAT,
|
||||
EQNFONT_ITALIC,
|
||||
EQNFONT__MAX
|
||||
};
|
||||
|
||||
enum eqn_post {
|
||||
EQNPOS_NONE = 0,
|
||||
EQNPOS_SUP,
|
||||
EQNPOS_SUBSUP,
|
||||
EQNPOS_SUB,
|
||||
EQNPOS_TO,
|
||||
EQNPOS_FROM,
|
||||
EQNPOS_FROMTO,
|
||||
EQNPOS_OVER,
|
||||
EQNPOS_SQRT,
|
||||
EQNPOS__MAX
|
||||
};
|
||||
|
||||
enum eqn_pilet {
|
||||
EQNPILE_NONE = 0,
|
||||
EQNPILE_PILE,
|
||||
EQNPILE_CPILE,
|
||||
EQNPILE_RPILE,
|
||||
EQNPILE_LPILE,
|
||||
EQNPILE_COL,
|
||||
EQNPILE_CCOL,
|
||||
EQNPILE_RCOL,
|
||||
EQNPILE_LCOL,
|
||||
EQNPILE__MAX
|
||||
};
|
||||
|
||||
/*
|
||||
* A "box" is a parsed mathematical expression as defined by the eqn.7
|
||||
* grammar.
|
||||
*/
|
||||
struct eqn_box {
|
||||
int size; /* font size of expression */
|
||||
#define EQN_DEFSIZE INT_MIN
|
||||
enum eqn_boxt type; /* type of node */
|
||||
struct eqn_box *first; /* first child node */
|
||||
struct eqn_box *last; /* last child node */
|
||||
struct eqn_box *next; /* node sibling */
|
||||
struct eqn_box *prev; /* node sibling */
|
||||
struct eqn_box *parent; /* node sibling */
|
||||
char *text; /* text (or NULL) */
|
||||
char *left; /* fence left-hand */
|
||||
char *right; /* fence right-hand */
|
||||
char *top; /* expression over-symbol */
|
||||
char *bottom; /* expression under-symbol */
|
||||
size_t args; /* arguments in parent */
|
||||
size_t expectargs; /* max arguments in parent */
|
||||
enum eqn_post pos; /* position of next box */
|
||||
enum eqn_fontt font; /* font of box */
|
||||
enum eqn_pilet pile; /* equation piling */
|
||||
};
|
||||
|
||||
/*
|
||||
* Parse options.
|
||||
*/
|
||||
#define MPARSE_MDOC 1 /* assume -mdoc */
|
||||
#define MPARSE_MAN 2 /* assume -man */
|
||||
#define MPARSE_SO 4 /* honour .so requests */
|
||||
#define MPARSE_QUICK 8 /* abort the parse early */
|
||||
#define MPARSE_UTF8 16 /* accept UTF-8 input */
|
||||
#define MPARSE_LATIN1 32 /* accept ISO-LATIN-1 input */
|
||||
|
||||
enum mandoc_os {
|
||||
MANDOC_OS_OTHER = 0,
|
||||
MANDOC_OS_NETBSD,
|
||||
MANDOC_OS_OPENBSD
|
||||
};
|
||||
|
||||
enum mandoc_esc {
|
||||
ESCAPE_ERROR = 0, /* bail! unparsable escape */
|
||||
ESCAPE_UNSUPP, /* unsupported escape; ignore it */
|
||||
ESCAPE_IGNORE, /* escape to be ignored */
|
||||
ESCAPE_UNDEF, /* undefined escape; print literal character */
|
||||
ESCAPE_SPECIAL, /* a regular special character */
|
||||
ESCAPE_FONT, /* a generic font mode */
|
||||
ESCAPE_FONTBOLD, /* bold font mode */
|
||||
ESCAPE_FONTITALIC, /* italic font mode */
|
||||
ESCAPE_FONTBI, /* bold italic font mode */
|
||||
ESCAPE_FONTROMAN, /* roman font mode */
|
||||
ESCAPE_FONTCW, /* constant width font mode */
|
||||
ESCAPE_FONTPREV, /* previous font mode */
|
||||
ESCAPE_NUMBERED, /* a numbered glyph */
|
||||
ESCAPE_UNICODE, /* a unicode codepoint */
|
||||
ESCAPE_DEVICE, /* print the output device name */
|
||||
ESCAPE_BREAK, /* break the output line */
|
||||
ESCAPE_NOSPACE, /* suppress space if the last on a line */
|
||||
ESCAPE_HORIZ, /* horizontal movement */
|
||||
@ -439,14 +269,18 @@ enum mandoc_esc {
|
||||
ESCAPE_OVERSTRIKE /* overstrike all chars in the argument */
|
||||
};
|
||||
|
||||
typedef void (*mandocmsg)(enum mandocerr, enum mandoclevel,
|
||||
const char *, int, int, const char *);
|
||||
|
||||
|
||||
struct mparse;
|
||||
struct roff_man;
|
||||
|
||||
enum mandoc_esc mandoc_font(const char *, int sz);
|
||||
enum mandoc_esc mandoc_escape(const char **, const char **, int *);
|
||||
void mandoc_msg_setoutfile(FILE *);
|
||||
const char *mandoc_msg_getinfilename(void);
|
||||
void mandoc_msg_setinfilename(const char *);
|
||||
enum mandocerr mandoc_msg_getmin(void);
|
||||
void mandoc_msg_setmin(enum mandocerr);
|
||||
enum mandoclevel mandoc_msg_getrc(void);
|
||||
void mandoc_msg_setrc(enum mandoclevel);
|
||||
void mandoc_msg(enum mandocerr, int, int, const char *, ...)
|
||||
__attribute__((__format__ (__printf__, 4, 5)));
|
||||
void mchars_alloc(void);
|
||||
void mchars_free(void);
|
||||
int mchars_num2char(const char *, size_t);
|
||||
@ -454,18 +288,3 @@ const char *mchars_uc2str(int);
|
||||
int mchars_num2uc(const char *, size_t);
|
||||
int mchars_spec2cp(const char *, size_t);
|
||||
const char *mchars_spec2str(const char *, size_t, size_t *);
|
||||
struct mparse *mparse_alloc(int, enum mandocerr, mandocmsg,
|
||||
enum mandoc_os, const char *);
|
||||
void mparse_free(struct mparse *);
|
||||
void mparse_keep(struct mparse *);
|
||||
int mparse_open(struct mparse *, const char *);
|
||||
enum mandoclevel mparse_readfd(struct mparse *, int, const char *);
|
||||
enum mandoclevel mparse_readmem(struct mparse *, void *, size_t,
|
||||
const char *);
|
||||
void mparse_reset(struct mparse *);
|
||||
void mparse_result(struct mparse *,
|
||||
struct roff_man **, char **);
|
||||
const char *mparse_getkeep(const struct mparse *);
|
||||
const char *mparse_strerror(enum mandocerr);
|
||||
const char *mparse_strlevel(enum mandoclevel);
|
||||
void mparse_updaterc(struct mparse *, enum mandoclevel *);
|
||||
|
@ -1,8 +1,8 @@
|
||||
.\" $Id: mandoc_char.7,v 1.72 2018/08/08 14:30:48 schwarze Exp $
|
||||
.\" $Id: mandoc_char.7,v 1.75 2018/12/15 19:30:26 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 Ingo Schwarze <schwarze@openbsd.org>
|
||||
.\" Copyright (c) 2011,2013,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
|
||||
@ -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: August 8 2018 $
|
||||
.Dd $Mdocdate: December 15 2018 $
|
||||
.Dt MANDOC_CHAR 7
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -266,11 +266,13 @@ Spacing:
|
||||
.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 unpaddable, breaking digit-width space
|
||||
.It \e0 Ta digit-width space allowing line break
|
||||
.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 space
|
||||
.It \e& Ta zero-width non-breaking 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
|
||||
.El
|
||||
.Pp
|
||||
Lines:
|
||||
@ -543,11 +545,13 @@ Accented letters:
|
||||
.It \e(\(aqI Ta \('I Ta acute I
|
||||
.It \e(\(aqO Ta \('O Ta acute O
|
||||
.It \e(\(aqU Ta \('U Ta acute U
|
||||
.It \e(\(aqY Ta \('Y Ta acute Y
|
||||
.It \e(\(aqa Ta \('a Ta acute a
|
||||
.It \e(\(aqe Ta \('e Ta acute e
|
||||
.It \e(\(aqi Ta \('i Ta acute i
|
||||
.It \e(\(aqo Ta \('o Ta acute o
|
||||
.It \e(\(aqu Ta \('u Ta acute u
|
||||
.It \e(\(aqy Ta \('y Ta acute y
|
||||
.It \e(\(gaA Ta \(`A Ta grave A
|
||||
.It \e(\(gaE Ta \(`E Ta grave E
|
||||
.It \e(\(gaI Ta \(`I Ta grave I
|
||||
@ -761,14 +765,16 @@ For backward compatibility with existing manuals,
|
||||
.Xr mandoc 1
|
||||
also supports the
|
||||
.Pp
|
||||
.Dl \eN\(aq Ns Ar number Ns \(aq
|
||||
.Dl \eN\(aq Ns Ar number Ns \(aq and \e[ Ns Cm char Ns Ar number ]
|
||||
.Pp
|
||||
escape sequence, inserting the character
|
||||
escape sequences, inserting the character
|
||||
.Ar number
|
||||
from the current character set into the output.
|
||||
Of course, this is inherently non-portable and is already marked
|
||||
as deprecated in the Heirloom roff manual.
|
||||
For example, do not use \eN\(aq34\(aq, use \e(dq, or even the plain
|
||||
as deprecated in the Heirloom roff manual;
|
||||
on top of that, the second form is a GNU extension.
|
||||
For example, do not use \eN\(aq34\(aq or \e[char34], use \e(dq,
|
||||
or even the plain
|
||||
.Sq \(dq
|
||||
character where possible.
|
||||
.Sh COMPATIBILITY
|
||||
|
386
mandoc_headers.3
386
mandoc_headers.3
@ -1,4 +1,4 @@
|
||||
.Dd $Mdocdate: July 8 2017 $
|
||||
.Dd $Mdocdate: December 30 2018 $
|
||||
.Dt MANDOC_HEADERS 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -25,15 +25,15 @@ separate from each other:
|
||||
.Pp
|
||||
.Bl -dash -offset indent -compact
|
||||
.It
|
||||
.Xr roff 7
|
||||
parser
|
||||
.It
|
||||
.Xr mdoc 7
|
||||
parser
|
||||
.It
|
||||
.Xr man 7
|
||||
parser
|
||||
.It
|
||||
.Xr roff 7
|
||||
parser
|
||||
.It
|
||||
.Xr tbl 7
|
||||
parser
|
||||
.It
|
||||
@ -45,6 +45,8 @@ terminal formatters
|
||||
HTML formatters
|
||||
.It
|
||||
search tools
|
||||
.It
|
||||
main programs
|
||||
.El
|
||||
.Pp
|
||||
Note that mere usage of an opaque struct type does
|
||||
@ -56,14 +58,18 @@ any other mandoc header.
|
||||
These headers should be included before any other mandoc headers.
|
||||
.Bl -tag -width Ds
|
||||
.It Qq Pa mandoc_aux.h
|
||||
Memory allocation utility functions; can be used everywhere.
|
||||
.Pp
|
||||
Requires
|
||||
.In sys/types.h
|
||||
for
|
||||
.Vt size_t .
|
||||
.Pp
|
||||
Provides the utility functions documented in
|
||||
Provides the functions documented in
|
||||
.Xr mandoc_malloc 3 .
|
||||
.It Qq Pa mandoc_ohash.h
|
||||
Hashing utility functions; can be used everywhere.
|
||||
.Pp
|
||||
Requires
|
||||
.In stddef.h
|
||||
for
|
||||
@ -78,73 +84,37 @@ Includes
|
||||
and provides
|
||||
.Fn mandoc_ohash_init .
|
||||
.It Qq Pa mandoc.h
|
||||
Error handling, escape sequence, and character utilities;
|
||||
can be used everywhere.
|
||||
.Pp
|
||||
Requires
|
||||
.In sys/types.h
|
||||
for
|
||||
.Vt size_t .
|
||||
.Vt size_t
|
||||
and
|
||||
.In stdio.h
|
||||
for
|
||||
.Vt FILE .
|
||||
.Pp
|
||||
Provides
|
||||
.Vt enum mandoc_esc ,
|
||||
.Vt enum mandocerr ,
|
||||
.Vt enum mandoclevel ,
|
||||
.Vt enum mandoc_os ,
|
||||
.Vt enum tbl_cellt ,
|
||||
.Vt enum tbl_datt ,
|
||||
.Vt enum tbl_spant ,
|
||||
.Vt enum eqn_boxt ,
|
||||
.Vt enum eqn_fontt ,
|
||||
.Vt enum eqn_pilet ,
|
||||
.Vt enum eqn_post ,
|
||||
.Vt struct tbl_opts ,
|
||||
.Vt struct tbl_cell ,
|
||||
.Vt struct tbl_row ,
|
||||
.Vt struct tbl_dat ,
|
||||
.Vt struct tbl_span ,
|
||||
.Vt struct eqn_box ,
|
||||
the function prototype typedef
|
||||
.Fn mandocmsg ,
|
||||
the function
|
||||
.Xr mandoc_escape 3 ,
|
||||
the functions described in
|
||||
.Xr mchars_alloc 3 ,
|
||||
and the functions
|
||||
.Fn mparse_*
|
||||
described in
|
||||
.Xr mandoc 3 .
|
||||
.Pp
|
||||
Uses the opaque type
|
||||
.Vt struct mparse
|
||||
from
|
||||
.Pa read.c
|
||||
for function prototypes.
|
||||
Uses the type
|
||||
.Vt struct roff_man
|
||||
from
|
||||
.Pa roff.h
|
||||
as an opaque type for function prototypes.
|
||||
.It Qq Pa mandoc_xr.h
|
||||
Provides
|
||||
.Vt struct mandoc_xr
|
||||
and the functions
|
||||
.Fn mandoc_xr_reset ,
|
||||
.Fn mandoc_xr_add ,
|
||||
.Fn mandoc_xr_get ,
|
||||
and
|
||||
.Fn mandoc_xr_free .
|
||||
and the
|
||||
.Fn mandoc_msg*
|
||||
functions.
|
||||
.It Qq Pa roff.h
|
||||
Requires
|
||||
.Qq Pa mandoc_ohash.h
|
||||
for
|
||||
.Vt struct ohash
|
||||
and
|
||||
.Qq Pa mandoc.h
|
||||
for
|
||||
.Vt enum mandoc_os .
|
||||
Common data types for all syntax trees and related functions;
|
||||
can be used everywhere.
|
||||
.Pp
|
||||
Provides
|
||||
.Vt enum mandoc_os ,
|
||||
.Vt enum mdoc_endbody ,
|
||||
.Vt enum roff_macroset ,
|
||||
.Vt enum roff_next ,
|
||||
.Vt enum roff_sec ,
|
||||
.Vt enum roff_tok ,
|
||||
.Vt enum roff_type ,
|
||||
@ -153,21 +123,99 @@ Provides
|
||||
.Vt struct roff_node ,
|
||||
the constant array
|
||||
.Va roff_name
|
||||
and the functions
|
||||
.Fn deroff ,
|
||||
.Fn roffhash_alloc ,
|
||||
.Fn roffhash_find ,
|
||||
.Fn roffhash_free ,
|
||||
and
|
||||
.Fn roff_validate .
|
||||
and the function
|
||||
.Fn deroff .
|
||||
.Pp
|
||||
Uses pointers to the types
|
||||
.Vt struct ohash
|
||||
from
|
||||
.Pa mandoc_ohash.h ,
|
||||
.Vt struct mdoc_arg
|
||||
and
|
||||
.Vt union mdoc_data
|
||||
from
|
||||
.Pa mdoc.h
|
||||
.Pa mdoc.h ,
|
||||
.Vt struct tbl_span
|
||||
from
|
||||
.Pa tbl.h ,
|
||||
and
|
||||
.Vt struct eqn_box
|
||||
from
|
||||
.Pa eqn.h
|
||||
as opaque struct members.
|
||||
.It Qq Pa tbl.h
|
||||
Data structures for the
|
||||
.Xr tbl 7
|
||||
parse tree; can be used everywhere.
|
||||
.Pp
|
||||
Requires
|
||||
.In sys/types.h
|
||||
for
|
||||
.Vt size_t .
|
||||
.Pp
|
||||
Provides
|
||||
.Vt enum tbl_cellt ,
|
||||
.Vt enum tbl_datt ,
|
||||
.Vt enum tbl_spant ,
|
||||
.Vt struct tbl_opts ,
|
||||
.Vt struct tbl_cell ,
|
||||
.Vt struct tbl_row ,
|
||||
.Vt struct tbl_dat ,
|
||||
and
|
||||
.Vt struct tbl_span .
|
||||
.It Qq Pa eqn.h
|
||||
Data structures for the
|
||||
.Xr eqn 7
|
||||
parse tree; can be used everywhere.
|
||||
.Pp
|
||||
Requires
|
||||
.In sys/types.h
|
||||
for
|
||||
.Vt size_t .
|
||||
.Pp
|
||||
Provides
|
||||
.Vt enum eqn_boxt ,
|
||||
.Vt enum eqn_fontt ,
|
||||
.Vt enum eqn_post ,
|
||||
and
|
||||
.Vt struct eqn_box .
|
||||
.It Qq Pa mandoc_parse.h
|
||||
Top level parser interface, for use in the main program
|
||||
and in the main parser, but not in formatters.
|
||||
.Pp
|
||||
Requires
|
||||
.Pa mandoc.h
|
||||
for
|
||||
.Vt enum mandocerr
|
||||
and
|
||||
.Vt enum mandoclevel
|
||||
and
|
||||
.Pa roff.h
|
||||
for
|
||||
.Vt enum mandoc_os .
|
||||
.Pp
|
||||
Uses the opaque type
|
||||
.Vt struct mparse
|
||||
from
|
||||
.Pa read.c
|
||||
for function prototypes.
|
||||
Uses
|
||||
.Vt struct roff_meta
|
||||
from
|
||||
.Pa roff.h
|
||||
as an opaque type for function prototypes.
|
||||
.It Qq Pa mandoc_xr.h
|
||||
Cross reference validation; intended for use in the main program
|
||||
and in parsers, but not in formatters.
|
||||
.Pp
|
||||
Provides
|
||||
.Vt struct mandoc_xr
|
||||
and the functions
|
||||
.Fn mandoc_xr_reset ,
|
||||
.Fn mandoc_xr_add ,
|
||||
.Fn mandoc_xr_get ,
|
||||
and
|
||||
.Fn mandoc_xr_free .
|
||||
.El
|
||||
.Pp
|
||||
The following two require
|
||||
@ -200,27 +248,24 @@ and the functions
|
||||
described in
|
||||
.Xr mandoc 3 .
|
||||
.Pp
|
||||
Uses the type
|
||||
.Vt struct roff_man
|
||||
Uses the types
|
||||
.Vt struct roff_node
|
||||
from
|
||||
.Pa roff.h
|
||||
as an opaque type for function prototypes.
|
||||
and
|
||||
.Vt struct roff_man
|
||||
from
|
||||
.Pa roff_int.h
|
||||
as opaque types for function prototypes.
|
||||
.Pp
|
||||
When this header is included, the same file should not include
|
||||
.Pa libman.h
|
||||
or
|
||||
.Pa libroff.h .
|
||||
internals of different parsers.
|
||||
.It Qq Pa man.h
|
||||
Provides the functions
|
||||
.Fn man_*
|
||||
described in
|
||||
.Xr mandoc 3 .
|
||||
.Pp
|
||||
Uses the opaque type
|
||||
.Vt struct mparse
|
||||
from
|
||||
.Pa read.c
|
||||
for function prototypes.
|
||||
Uses the type
|
||||
.Vt struct roff_man
|
||||
from
|
||||
@ -228,12 +273,10 @@ from
|
||||
as an opaque type for function prototypes.
|
||||
.Pp
|
||||
When this header is included, the same file should not include
|
||||
.Pa libmdoc.h
|
||||
or
|
||||
.Pa libroff.h .
|
||||
internals of different parsers.
|
||||
.El
|
||||
.Ss Parser internals
|
||||
The following headers require inclusion of a parser interface header
|
||||
Most of the following headers require inclusion of a parser interface header
|
||||
before they can be included.
|
||||
All parser interface headers should precede all parser internal headers.
|
||||
When any parser internal headers are included, the same file should
|
||||
@ -250,16 +293,11 @@ for
|
||||
.Vt enum mandocerr .
|
||||
.Pp
|
||||
Provides
|
||||
.Vt enum rofferr ,
|
||||
.Vt struct buf ,
|
||||
utility functions needed by multiple parsers,
|
||||
and the top-level functions to call the parsers.
|
||||
.Pp
|
||||
Uses the opaque types
|
||||
.Vt struct mparse
|
||||
from
|
||||
.Pa read.c
|
||||
and
|
||||
Uses the opaque type
|
||||
.Vt struct roff
|
||||
from
|
||||
.Pa roff.c
|
||||
@ -270,14 +308,28 @@ from
|
||||
.Pa roff.h
|
||||
as an opaque type for function prototypes.
|
||||
.It Qq Pa roff_int.h
|
||||
Parser internals shared by multiple parsers.
|
||||
Can be used in all parsers, but not in main programs or formatters.
|
||||
.Pp
|
||||
Requires
|
||||
.Qq Pa roff.h
|
||||
for
|
||||
.Vt enum roff_type .
|
||||
.Vt enum roff_type
|
||||
and
|
||||
.Vt enum roff_tok .
|
||||
.Pp
|
||||
Provides functions named
|
||||
Provides
|
||||
.Vt enum roff_next ,
|
||||
.Vt struct roff_man ,
|
||||
functions named
|
||||
.Fn roff_*
|
||||
to handle roff nodes and the two special functions
|
||||
to handle roff nodes,
|
||||
.Fn roffhash_alloc ,
|
||||
.Fn roffhash_find ,
|
||||
.Fn roffhash_free ,
|
||||
and
|
||||
.Fn roff_validate ,
|
||||
and the two special functions
|
||||
.Fn man_breakscope
|
||||
and
|
||||
.Fn mdoc_argv_free
|
||||
@ -285,11 +337,17 @@ because the latter two are needed by
|
||||
.Qq Pa roff.c .
|
||||
.Pp
|
||||
Uses the types
|
||||
.Vt struct roff_man
|
||||
and
|
||||
.Vt struct roff_node
|
||||
.Vt struct ohash
|
||||
from
|
||||
.Pa roff.h
|
||||
.Pa mandoc_ohash.h ,
|
||||
.Vt struct roff_node
|
||||
and
|
||||
.Vt struct roff_meta
|
||||
from
|
||||
.Pa roff.h ,
|
||||
.Vt struct roff
|
||||
from
|
||||
.Pa roff.c ,
|
||||
and
|
||||
.Vt struct mdoc_arg
|
||||
from
|
||||
@ -301,11 +359,7 @@ Requires
|
||||
for
|
||||
.Vt enum roff_tok
|
||||
and
|
||||
.Qq Pa mdoc.h
|
||||
for
|
||||
.Vt enum mdoc_*
|
||||
and
|
||||
.Vt struct mdoc_* .
|
||||
.Vt enum roff_sec .
|
||||
.Pp
|
||||
Provides
|
||||
.Vt enum margserr ,
|
||||
@ -315,23 +369,21 @@ and many functions internal to the
|
||||
.Xr mdoc 7
|
||||
parser.
|
||||
.Pp
|
||||
Uses the opaque type
|
||||
.Vt struct mparse
|
||||
from
|
||||
.Pa read.c .
|
||||
Uses the types
|
||||
.Vt struct roff_man
|
||||
and
|
||||
.Vt struct roff_node
|
||||
from
|
||||
.Pa roff.h
|
||||
.Pa roff.h ,
|
||||
.Vt struct roff_man
|
||||
from
|
||||
.Pa roff_int.h ,
|
||||
and
|
||||
.Vt struct mdoc_arg
|
||||
from
|
||||
.Pa mdoc.h
|
||||
as opaque types for function prototypes.
|
||||
.Pp
|
||||
When this header is included, the same file should not include
|
||||
.Pa man.h ,
|
||||
.Pa libman.h ,
|
||||
or
|
||||
.Pa libroff.h .
|
||||
interfaces of different parsers.
|
||||
.It Qq Pa libman.h
|
||||
Requires
|
||||
.Qq Pa roff.h
|
||||
@ -345,52 +397,109 @@ and some functions internal to the
|
||||
parser.
|
||||
.Pp
|
||||
Uses the types
|
||||
.Vt struct roff_man
|
||||
and
|
||||
.Vt struct roff_node
|
||||
from
|
||||
.Pa roff.h
|
||||
and
|
||||
.Vt struct roff_man
|
||||
from
|
||||
.Pa roff_int.h
|
||||
as opaque types for function prototypes.
|
||||
.Pp
|
||||
When this header is included, the same file should not include
|
||||
.Pa mdoc.h ,
|
||||
.Pa libmdoc.h ,
|
||||
or
|
||||
.Pa libroff.h .
|
||||
.It Qq Pa libroff.h
|
||||
interfaces of different parsers.
|
||||
.It Qq Pa eqn_parse.h
|
||||
External interface of the
|
||||
.Xr eqn 7
|
||||
parser, for use in the
|
||||
.Xr roff 7
|
||||
and
|
||||
.Xr eqn 7
|
||||
parsers only.
|
||||
.Pp
|
||||
Requires
|
||||
.In sys/types.h
|
||||
for
|
||||
.Vt size_t
|
||||
.Vt size_t .
|
||||
.Pp
|
||||
Provides
|
||||
.Vt struct eqn_node
|
||||
and the functions
|
||||
.Fn eqn_alloc ,
|
||||
.Fn eqn_box_new ,
|
||||
.Fn eqn_box_free ,
|
||||
.Fn eqn_free ,
|
||||
.Fn eqn_parse ,
|
||||
.Fn eqn_read ,
|
||||
and
|
||||
.Qq Pa mandoc.h
|
||||
.Fn eqn_reset .
|
||||
.Pp
|
||||
Uses the type
|
||||
.Vt struct eqn_box
|
||||
from
|
||||
.Pa mandoc.h
|
||||
as an opaque type for function prototypes.
|
||||
Uses the types
|
||||
.Vt struct roff_node
|
||||
from
|
||||
.Pa roff.h
|
||||
and
|
||||
.Vt struct eqn_def
|
||||
from
|
||||
.Pa eqn.c
|
||||
as opaque struct members.
|
||||
.Pp
|
||||
When this header is included, the same file should not include
|
||||
internals of different parsers.
|
||||
.It Qq Pa tbl_parse.h
|
||||
External interface of the
|
||||
.Xr tbl 7
|
||||
parser, for use in the
|
||||
.Xr roff 7
|
||||
and
|
||||
.Xr tbl 7
|
||||
parsers only.
|
||||
.Pp
|
||||
Provides the functions documented in
|
||||
.Xr tbl 3 .
|
||||
.Pp
|
||||
Uses the types
|
||||
.Vt struct tbl_span
|
||||
from
|
||||
.Pa tbl.h
|
||||
and
|
||||
.Vt struct tbl_node
|
||||
from
|
||||
.Pa tbl_int.h
|
||||
as opaque types for function prototypes.
|
||||
.Pp
|
||||
When this header is included, the same file should not include
|
||||
internals of different parsers.
|
||||
.It Qq Pa tbl_int.h
|
||||
Internal interfaces of the
|
||||
.Xr tbl 7
|
||||
parser, for use inside the
|
||||
.Xr tbl 7
|
||||
parser only.
|
||||
.Pp
|
||||
Requires
|
||||
.Qq Pa tbl.h
|
||||
for
|
||||
.Vt struct tbl_*
|
||||
and
|
||||
.Vt struct eqn_box .
|
||||
.Vt struct tbl_opts .
|
||||
.Pp
|
||||
Provides
|
||||
.Vt enum tbl_part ,
|
||||
.Vt struct tbl_node ,
|
||||
.Vt struct eqn_def ,
|
||||
.Vt struct eqn_node ,
|
||||
and many functions internal to the
|
||||
.Xr tbl 7
|
||||
and the functions
|
||||
.Fn tbl_option ,
|
||||
.Fn tbl_layout ,
|
||||
.Fn tbl_data ,
|
||||
.Fn tbl_cdata ,
|
||||
and
|
||||
.Xr eqn 7
|
||||
parsers.
|
||||
.Pp
|
||||
Uses the opaque type
|
||||
.Vt struct mparse
|
||||
from
|
||||
.Pa read.c .
|
||||
.Fn tbl_reset .
|
||||
.Pp
|
||||
When this header is included, the same file should not include
|
||||
.Pa man.h ,
|
||||
.Pa mdoc.h ,
|
||||
.Pa libman.h ,
|
||||
or
|
||||
.Pa libmdoc.h .
|
||||
interfaces of different parsers.
|
||||
.El
|
||||
.Ss Formatter interface
|
||||
These headers should be included after any parser interface headers.
|
||||
@ -466,7 +575,10 @@ or
|
||||
Requires
|
||||
.In sys/types.h
|
||||
for
|
||||
.Vt size_t
|
||||
.Vt size_t ,
|
||||
.Pa mandoc.h
|
||||
for
|
||||
.Vt enum mandoc_esc ,
|
||||
and
|
||||
.Qq Pa out.h
|
||||
for
|
||||
@ -517,7 +629,7 @@ functionality mentioned in
|
||||
Provides the top level steering functions for all formatters.
|
||||
.Pp
|
||||
Uses the type
|
||||
.Vt struct roff_man
|
||||
.Vt struct roff_meta
|
||||
from
|
||||
.Pa roff.h
|
||||
as an opaque type for function prototypes.
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $Id: mandoc_html.3,v 1.17 2018/06/25 16:54:59 schwarze Exp $
|
||||
.\" $Id: mandoc_html.3,v 1.19 2019/01/11 12:56:43 schwarze Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2014, 2017, 2018 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: June 25 2018 $
|
||||
.Dd $Mdocdate: January 11 2019 $
|
||||
.Dt MANDOC_HTML 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -167,11 +167,6 @@ the respective attribute is not written.
|
||||
Print a
|
||||
.Cm class
|
||||
attribute.
|
||||
This attribute letter can optionally be followed by the modifier letter
|
||||
.Cm T .
|
||||
In that case, a
|
||||
.Cm title
|
||||
attribute with the same value is also printed.
|
||||
.It Cm h
|
||||
Print a
|
||||
.Cm href
|
||||
@ -216,6 +211,14 @@ It requires two
|
||||
.Va char *
|
||||
arguments.
|
||||
The first is the name of the style property, the second its value.
|
||||
The name must not be
|
||||
.Dv NULL .
|
||||
The
|
||||
.Cm s
|
||||
.Ar fmt
|
||||
letter can be repeated, each repetition requiring an additional pair of
|
||||
.Va char *
|
||||
arguments.
|
||||
.El
|
||||
.Pp
|
||||
.Fn print_otag
|
||||
|
329
mandoc_msg.c
Normal file
329
mandoc_msg.c
Normal file
@ -0,0 +1,329 @@
|
||||
/* $Id: mandoc_msg.c,v 1.6 2019/03/06 15:55:38 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2014,2015,2016,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
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
|
||||
static const enum mandocerr lowest_type[MANDOCLEVEL_MAX] = {
|
||||
MANDOCERR_OK,
|
||||
MANDOCERR_OK,
|
||||
MANDOCERR_WARNING,
|
||||
MANDOCERR_ERROR,
|
||||
MANDOCERR_UNSUPP,
|
||||
MANDOCERR_MAX,
|
||||
MANDOCERR_MAX
|
||||
};
|
||||
|
||||
static const char *const level_name[MANDOCLEVEL_MAX] = {
|
||||
"SUCCESS",
|
||||
"STYLE",
|
||||
"WARNING",
|
||||
"ERROR",
|
||||
"UNSUPP",
|
||||
"BADARG",
|
||||
"SYSERR"
|
||||
};
|
||||
|
||||
static const char *const type_message[MANDOCERR_MAX] = {
|
||||
"ok",
|
||||
|
||||
"base system convention",
|
||||
|
||||
"Mdocdate found",
|
||||
"Mdocdate missing",
|
||||
"unknown architecture",
|
||||
"operating system explicitly specified",
|
||||
"RCS id missing",
|
||||
"referenced manual not found",
|
||||
|
||||
"generic style suggestion",
|
||||
|
||||
"legacy man(7) date format",
|
||||
"normalizing date format to",
|
||||
"lower case character in document title",
|
||||
"duplicate RCS id",
|
||||
"possible typo in section name",
|
||||
"unterminated quoted argument",
|
||||
"useless macro",
|
||||
"consider using OS macro",
|
||||
"errnos out of order",
|
||||
"duplicate errno",
|
||||
"trailing delimiter",
|
||||
"no blank before trailing delimiter",
|
||||
"fill mode already enabled, skipping",
|
||||
"fill mode already disabled, skipping",
|
||||
"verbatim \"--\", maybe consider using \\(em",
|
||||
"function name without markup",
|
||||
"whitespace at end of input line",
|
||||
"bad comment style",
|
||||
|
||||
"generic warning",
|
||||
|
||||
/* related to the prologue */
|
||||
"missing manual title, using UNTITLED",
|
||||
"missing manual title, using \"\"",
|
||||
"missing manual section, using \"\"",
|
||||
"unknown manual section",
|
||||
"missing date, using today's date",
|
||||
"cannot parse date, using it verbatim",
|
||||
"date in the future, using it anyway",
|
||||
"missing Os macro, using \"\"",
|
||||
"late prologue macro",
|
||||
"prologue macros out of order",
|
||||
|
||||
/* related to document structure */
|
||||
".so is fragile, better use ln(1)",
|
||||
"no document body",
|
||||
"content before first section header",
|
||||
"first section is not \"NAME\"",
|
||||
"NAME section without Nm before Nd",
|
||||
"NAME section without description",
|
||||
"description not at the end of NAME",
|
||||
"bad NAME section content",
|
||||
"missing comma before name",
|
||||
"missing description line, using \"\"",
|
||||
"description line outside NAME section",
|
||||
"sections out of conventional order",
|
||||
"duplicate section title",
|
||||
"unexpected section",
|
||||
"cross reference to self",
|
||||
"unusual Xr order",
|
||||
"unusual Xr punctuation",
|
||||
"AUTHORS section without An macro",
|
||||
|
||||
/* related to macros and nesting */
|
||||
"obsolete macro",
|
||||
"macro neither callable nor escaped",
|
||||
"skipping paragraph macro",
|
||||
"moving paragraph macro out of list",
|
||||
"skipping no-space macro",
|
||||
"blocks badly nested",
|
||||
"nested displays are not portable",
|
||||
"moving content out of list",
|
||||
"first macro on line",
|
||||
"line scope broken",
|
||||
"skipping blank line in line scope",
|
||||
|
||||
/* related to missing macro arguments */
|
||||
"skipping empty request",
|
||||
"conditional request controls empty scope",
|
||||
"skipping empty macro",
|
||||
"empty block",
|
||||
"empty argument, using 0n",
|
||||
"missing display type, using -ragged",
|
||||
"list type is not the first argument",
|
||||
"missing -width in -tag list, using 6n",
|
||||
"missing utility name, using \"\"",
|
||||
"missing function name, using \"\"",
|
||||
"empty head in list item",
|
||||
"empty list item",
|
||||
"missing argument, using next line",
|
||||
"missing font type, using \\fR",
|
||||
"unknown font type, using \\fR",
|
||||
"nothing follows prefix",
|
||||
"empty reference block",
|
||||
"missing section argument",
|
||||
"missing -std argument, adding it",
|
||||
"missing option string, using \"\"",
|
||||
"missing resource identifier, using \"\"",
|
||||
"missing eqn box, using \"\"",
|
||||
|
||||
/* related to bad macro arguments */
|
||||
"duplicate argument",
|
||||
"skipping duplicate argument",
|
||||
"skipping duplicate display type",
|
||||
"skipping duplicate list type",
|
||||
"skipping -width argument",
|
||||
"wrong number of cells",
|
||||
"unknown AT&T UNIX version",
|
||||
"comma in function argument",
|
||||
"parenthesis in function name",
|
||||
"unknown library name",
|
||||
"invalid content in Rs block",
|
||||
"invalid Boolean argument",
|
||||
"argument contains two font escapes",
|
||||
"unknown font, skipping request",
|
||||
"odd number of characters in request",
|
||||
|
||||
/* related to plain text */
|
||||
"blank line in fill mode, using .sp",
|
||||
"tab in filled text",
|
||||
"new sentence, new line",
|
||||
"invalid escape sequence",
|
||||
"undefined escape, printing literally",
|
||||
"undefined string, using \"\"",
|
||||
|
||||
/* related to tables */
|
||||
"tbl line starts with span",
|
||||
"tbl column starts with span",
|
||||
"skipping vertical bar in tbl layout",
|
||||
|
||||
"generic error",
|
||||
|
||||
/* related to tables */
|
||||
"non-alphabetic character in tbl options",
|
||||
"skipping unknown tbl option",
|
||||
"missing tbl option argument",
|
||||
"wrong tbl option argument size",
|
||||
"empty tbl layout",
|
||||
"invalid character in tbl layout",
|
||||
"unmatched parenthesis in tbl layout",
|
||||
"tbl without any data cells",
|
||||
"ignoring data in spanned tbl cell",
|
||||
"ignoring extra tbl data cells",
|
||||
"data block open at end of tbl",
|
||||
|
||||
/* related to document structure and macros */
|
||||
NULL,
|
||||
"duplicate prologue macro",
|
||||
"skipping late title macro",
|
||||
"input stack limit exceeded, infinite loop?",
|
||||
"skipping bad character",
|
||||
"skipping unknown macro",
|
||||
"ignoring request outside macro",
|
||||
"skipping insecure request",
|
||||
"skipping item outside list",
|
||||
"skipping column outside column list",
|
||||
"skipping end of block that is not open",
|
||||
"fewer RS blocks open, skipping",
|
||||
"inserting missing end of block",
|
||||
"appending missing end of block",
|
||||
|
||||
/* related to request and macro arguments */
|
||||
"escaped character not allowed in a name",
|
||||
"using macro argument outside macro",
|
||||
"argument number is not numeric",
|
||||
"NOT IMPLEMENTED: Bd -file",
|
||||
"skipping display without arguments",
|
||||
"missing list type, using -item",
|
||||
"argument is not numeric, using 1",
|
||||
"argument is not a character",
|
||||
"missing manual name, using \"\"",
|
||||
"uname(3) system call failed, using UNKNOWN",
|
||||
"unknown standard specifier",
|
||||
"skipping request without numeric argument",
|
||||
"excessive shift",
|
||||
"NOT IMPLEMENTED: .so with absolute path or \"..\"",
|
||||
".so request failed",
|
||||
"skipping all arguments",
|
||||
"skipping excess arguments",
|
||||
"divide by zero",
|
||||
|
||||
"unsupported feature",
|
||||
"input too large",
|
||||
"unsupported control character",
|
||||
"unsupported escape sequence",
|
||||
"unsupported roff request",
|
||||
"nested .while loops",
|
||||
"end of scope with open .while loop",
|
||||
"end of .while loop in inner scope",
|
||||
"cannot continue this .while loop",
|
||||
"eqn delim option in tbl",
|
||||
"unsupported tbl layout modifier",
|
||||
"ignoring macro in table",
|
||||
};
|
||||
|
||||
static FILE *fileptr = NULL;
|
||||
static const char *filename = NULL;
|
||||
static enum mandocerr min_type = MANDOCERR_MAX;
|
||||
static enum mandoclevel rc = MANDOCLEVEL_OK;
|
||||
|
||||
|
||||
void
|
||||
mandoc_msg_setoutfile(FILE *fp)
|
||||
{
|
||||
fileptr = fp;
|
||||
}
|
||||
|
||||
const char *
|
||||
mandoc_msg_getinfilename(void)
|
||||
{
|
||||
return filename;
|
||||
}
|
||||
|
||||
void
|
||||
mandoc_msg_setinfilename(const char *fn)
|
||||
{
|
||||
filename = fn;
|
||||
}
|
||||
|
||||
enum mandocerr
|
||||
mandoc_msg_getmin(void)
|
||||
{
|
||||
return min_type;
|
||||
}
|
||||
|
||||
void
|
||||
mandoc_msg_setmin(enum mandocerr t)
|
||||
{
|
||||
min_type = t;
|
||||
}
|
||||
|
||||
enum mandoclevel
|
||||
mandoc_msg_getrc(void)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
void
|
||||
mandoc_msg_setrc(enum mandoclevel level)
|
||||
{
|
||||
if (rc < level)
|
||||
rc = level;
|
||||
}
|
||||
|
||||
void
|
||||
mandoc_msg(enum mandocerr t, int line, int col, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
enum mandoclevel level;
|
||||
|
||||
if (t < min_type && t != MANDOCERR_FILE)
|
||||
return;
|
||||
|
||||
level = MANDOCLEVEL_UNSUPP;
|
||||
while (t < lowest_type[level])
|
||||
level--;
|
||||
mandoc_msg_setrc(level);
|
||||
|
||||
if (fileptr == NULL)
|
||||
return;
|
||||
|
||||
fprintf(fileptr, "%s:", getprogname());
|
||||
if (filename != NULL)
|
||||
fprintf(fileptr, " %s:", filename);
|
||||
|
||||
if (line > 0)
|
||||
fprintf(fileptr, "%d:%d:", line, col + 1);
|
||||
|
||||
fprintf(fileptr, " %s", level_name[level]);
|
||||
if (type_message[t] != NULL)
|
||||
fprintf(fileptr, ": %s", type_message[t]);
|
||||
|
||||
if (fmt != NULL) {
|
||||
fprintf(fileptr, ": ");
|
||||
va_start(ap, fmt);
|
||||
vfprintf(fileptr, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
fputc('\n', fileptr);
|
||||
}
|
43
mandoc_parse.h
Normal file
43
mandoc_parse.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* $Id: mandoc_parse.h,v 1.4 2018/12/30 00:49:55 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2014,2015,2016,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
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Top level parser interface. For use in the main program
|
||||
* and in the main parser, but not in formatters.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Parse options.
|
||||
*/
|
||||
#define MPARSE_MDOC (1 << 0) /* assume -mdoc */
|
||||
#define MPARSE_MAN (1 << 1) /* assume -man */
|
||||
#define MPARSE_SO (1 << 2) /* honour .so requests */
|
||||
#define MPARSE_QUICK (1 << 3) /* abort the parse early */
|
||||
#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 */
|
||||
|
||||
|
||||
struct roff_meta;
|
||||
struct mparse;
|
||||
|
||||
struct mparse *mparse_alloc(int, enum mandoc_os, const char *);
|
||||
void mparse_copy(const struct mparse *);
|
||||
void mparse_free(struct mparse *);
|
||||
int mparse_open(struct mparse *, const char *);
|
||||
void mparse_readfd(struct mparse *, int, const char *);
|
||||
void mparse_reset(struct mparse *);
|
||||
struct roff_meta *mparse_result(struct mparse *);
|
33
mandocd.c
33
mandocd.c
@ -1,7 +1,7 @@
|
||||
/* $Id: mandocd.c,v 1.6 2017/06/24 14:38:32 schwarze Exp $ */
|
||||
/* $Id: mandocd.c,v 1.11 2019/03/03 13:02:11 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2017 Michael Stapelberg <stapelberg@debian.org>
|
||||
* Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 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
|
||||
@ -38,6 +38,7 @@
|
||||
#include "roff.h"
|
||||
#include "mdoc.h"
|
||||
#include "man.h"
|
||||
#include "mandoc_parse.h"
|
||||
#include "main.h"
|
||||
#include "manconf.h"
|
||||
|
||||
@ -170,8 +171,8 @@ main(int argc, char *argv[])
|
||||
errx(1, "file descriptor %s %s", argv[1], errstr);
|
||||
|
||||
mchars_alloc();
|
||||
parser = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1,
|
||||
MANDOCERR_MAX, NULL, MANDOC_OS_OTHER, defos);
|
||||
parser = mparse_alloc(MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1 |
|
||||
MPARSE_VALIDATE, MANDOC_OS_OTHER, defos);
|
||||
|
||||
memset(&options, 0, sizeof(options));
|
||||
switch (outtype) {
|
||||
@ -212,6 +213,8 @@ main(int argc, char *argv[])
|
||||
|
||||
process(parser, outtype, formatter);
|
||||
mparse_reset(parser);
|
||||
if (outtype == OUTT_HTML)
|
||||
html_reset(formatter);
|
||||
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
@ -243,35 +246,29 @@ main(int argc, char *argv[])
|
||||
static void
|
||||
process(struct mparse *parser, enum outt outtype, void *formatter)
|
||||
{
|
||||
struct roff_man *man;
|
||||
struct roff_meta *meta;
|
||||
|
||||
mparse_readfd(parser, STDIN_FILENO, "<unixfd>");
|
||||
mparse_result(parser, &man, NULL);
|
||||
|
||||
if (man == NULL)
|
||||
return;
|
||||
|
||||
if (man->macroset == MACROSET_MDOC) {
|
||||
mdoc_validate(man);
|
||||
meta = mparse_result(parser);
|
||||
if (meta->macroset == MACROSET_MDOC) {
|
||||
switch (outtype) {
|
||||
case OUTT_ASCII:
|
||||
case OUTT_UTF8:
|
||||
terminal_mdoc(formatter, man);
|
||||
terminal_mdoc(formatter, meta);
|
||||
break;
|
||||
case OUTT_HTML:
|
||||
html_mdoc(formatter, man);
|
||||
html_mdoc(formatter, meta);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (man->macroset == MACROSET_MAN) {
|
||||
man_validate(man);
|
||||
if (meta->macroset == MACROSET_MAN) {
|
||||
switch (outtype) {
|
||||
case OUTT_ASCII:
|
||||
case OUTT_UTF8:
|
||||
terminal_man(formatter, man);
|
||||
terminal_man(formatter, meta);
|
||||
break;
|
||||
case OUTT_HTML:
|
||||
html_man(formatter, man);
|
||||
html_man(formatter, meta);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
72
mandocdb.c
72
mandocdb.c
@ -1,7 +1,7 @@
|
||||
/* $Id: mandocdb.c,v 1.258 2018/02/23 18:25:57 schwarze Exp $ */
|
||||
/* $Id: mandocdb.c,v 1.262 2018/12/30 00:49:55 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2011-2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2011-2018 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2016 Ed Maste <emaste@freebsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
@ -52,6 +52,7 @@
|
||||
#include "roff.h"
|
||||
#include "mdoc.h"
|
||||
#include "man.h"
|
||||
#include "mandoc_parse.h"
|
||||
#include "manconf.h"
|
||||
#include "mansearch.h"
|
||||
#include "dba_array.h"
|
||||
@ -185,7 +186,7 @@ static struct ohash names; /* table of all names */
|
||||
static struct ohash strings; /* table of all strings */
|
||||
static uint64_t name_mask;
|
||||
|
||||
static const struct mdoc_handler __mdocs[MDOC_MAX - MDOC_Dd] = {
|
||||
static const struct mdoc_handler mdoc_handlers[MDOC_MAX - MDOC_Dd] = {
|
||||
{ NULL, 0, NODE_NOPRT }, /* Dd */
|
||||
{ NULL, 0, NODE_NOPRT }, /* Dt */
|
||||
{ NULL, 0, NODE_NOPRT }, /* Os */
|
||||
@ -307,7 +308,6 @@ static const struct mdoc_handler __mdocs[MDOC_MAX - MDOC_Dd] = {
|
||||
{ NULL, 0, 0 }, /* %U */
|
||||
{ NULL, 0, 0 }, /* Ta */
|
||||
};
|
||||
static const struct mdoc_handler *const mdocs = __mdocs - MDOC_Dd;
|
||||
|
||||
|
||||
int
|
||||
@ -347,6 +347,7 @@ mandocdb(int argc, char *argv[])
|
||||
goto usage; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
mparse_options = MPARSE_VALIDATE;
|
||||
path_arg = NULL;
|
||||
op = OP_DEFAULT;
|
||||
|
||||
@ -422,8 +423,7 @@ mandocdb(int argc, char *argv[])
|
||||
|
||||
exitcode = (int)MANDOCLEVEL_OK;
|
||||
mchars_alloc();
|
||||
mp = mparse_alloc(mparse_options, MANDOCERR_MAX, NULL,
|
||||
MANDOC_OS_OTHER, NULL);
|
||||
mp = mparse_alloc(mparse_options, MANDOC_OS_OTHER, NULL);
|
||||
mandoc_ohash_init(&mpages, 6, offsetof(struct mpage, inodev));
|
||||
mandoc_ohash_init(&mlinks, 6, offsetof(struct mlink, file));
|
||||
|
||||
@ -1116,8 +1116,7 @@ mpages_merge(struct dba *dba, struct mparse *mp)
|
||||
{
|
||||
struct mpage *mpage, *mpage_dest;
|
||||
struct mlink *mlink, *mlink_dest;
|
||||
struct roff_man *man;
|
||||
char *sodest;
|
||||
struct roff_meta *meta;
|
||||
char *cp;
|
||||
int fd;
|
||||
|
||||
@ -1130,8 +1129,7 @@ mpages_merge(struct dba *dba, struct mparse *mp)
|
||||
mandoc_ohash_init(&names, 4, offsetof(struct str, key));
|
||||
mandoc_ohash_init(&strings, 6, offsetof(struct str, key));
|
||||
mparse_reset(mp);
|
||||
man = NULL;
|
||||
sodest = NULL;
|
||||
meta = NULL;
|
||||
|
||||
if ((fd = mparse_open(mp, mlink->file)) == -1) {
|
||||
say(mlink->file, "&open");
|
||||
@ -1146,14 +1144,14 @@ mpages_merge(struct dba *dba, struct mparse *mp)
|
||||
mparse_readfd(mp, fd, mlink->file);
|
||||
close(fd);
|
||||
fd = -1;
|
||||
mparse_result(mp, &man, &sodest);
|
||||
meta = mparse_result(mp);
|
||||
}
|
||||
|
||||
if (sodest != NULL) {
|
||||
if (meta != NULL && meta->sodest != NULL) {
|
||||
mlink_dest = ohash_find(&mlinks,
|
||||
ohash_qlookup(&mlinks, sodest));
|
||||
ohash_qlookup(&mlinks, meta->sodest));
|
||||
if (mlink_dest == NULL) {
|
||||
mandoc_asprintf(&cp, "%s.gz", sodest);
|
||||
mandoc_asprintf(&cp, "%s.gz", meta->sodest);
|
||||
mlink_dest = ohash_find(&mlinks,
|
||||
ohash_qlookup(&mlinks, cp));
|
||||
free(cp);
|
||||
@ -1190,39 +1188,36 @@ mpages_merge(struct dba *dba, struct mparse *mp)
|
||||
mpage->mlinks = NULL;
|
||||
}
|
||||
goto nextpage;
|
||||
} else if (man != NULL && man->macroset == MACROSET_MDOC) {
|
||||
mdoc_validate(man);
|
||||
} else if (meta != NULL && meta->macroset == MACROSET_MDOC) {
|
||||
mpage->form = FORM_SRC;
|
||||
mpage->sec = man->meta.msec;
|
||||
mpage->sec = meta->msec;
|
||||
mpage->sec = mandoc_strdup(
|
||||
mpage->sec == NULL ? "" : mpage->sec);
|
||||
mpage->arch = man->meta.arch;
|
||||
mpage->arch = meta->arch;
|
||||
mpage->arch = mandoc_strdup(
|
||||
mpage->arch == NULL ? "" : mpage->arch);
|
||||
mpage->title = mandoc_strdup(man->meta.title);
|
||||
} else if (man != NULL && man->macroset == MACROSET_MAN) {
|
||||
man_validate(man);
|
||||
if (*man->meta.msec != '\0' ||
|
||||
*man->meta.title != '\0') {
|
||||
mpage->title = mandoc_strdup(meta->title);
|
||||
} else if (meta != NULL && meta->macroset == MACROSET_MAN) {
|
||||
if (*meta->msec != '\0' || *meta->title != '\0') {
|
||||
mpage->form = FORM_SRC;
|
||||
mpage->sec = mandoc_strdup(man->meta.msec);
|
||||
mpage->sec = mandoc_strdup(meta->msec);
|
||||
mpage->arch = mandoc_strdup(mlink->arch);
|
||||
mpage->title = mandoc_strdup(man->meta.title);
|
||||
mpage->title = mandoc_strdup(meta->title);
|
||||
} else
|
||||
man = NULL;
|
||||
meta = NULL;
|
||||
}
|
||||
|
||||
assert(mpage->desc == NULL);
|
||||
if (man == NULL) {
|
||||
if (meta == NULL) {
|
||||
mpage->form = FORM_CAT;
|
||||
mpage->sec = mandoc_strdup(mlink->dsec);
|
||||
mpage->arch = mandoc_strdup(mlink->arch);
|
||||
mpage->title = mandoc_strdup(mlink->name);
|
||||
parse_cat(mpage, fd);
|
||||
} else if (man->macroset == MACROSET_MDOC)
|
||||
parse_mdoc(mpage, &man->meta, man->first);
|
||||
} else if (meta->macroset == MACROSET_MDOC)
|
||||
parse_mdoc(mpage, meta, meta->first);
|
||||
else
|
||||
parse_man(mpage, &man->meta, man->first);
|
||||
parse_man(mpage, meta, meta->first);
|
||||
if (mpage->desc == NULL) {
|
||||
mpage->desc = mandoc_strdup(mlink->name);
|
||||
if (warnings)
|
||||
@ -1546,25 +1541,28 @@ static void
|
||||
parse_mdoc(struct mpage *mpage, const struct roff_meta *meta,
|
||||
const struct roff_node *n)
|
||||
{
|
||||
const struct mdoc_handler *handler;
|
||||
|
||||
for (n = n->child; n != NULL; n = n->next) {
|
||||
if (n->tok == TOKEN_NONE ||
|
||||
n->tok < ROFF_MAX ||
|
||||
n->flags & mdocs[n->tok].taboo)
|
||||
if (n->tok == TOKEN_NONE || n->tok < ROFF_MAX)
|
||||
continue;
|
||||
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
|
||||
handler = mdoc_handlers + (n->tok - MDOC_Dd);
|
||||
if (n->flags & handler->taboo)
|
||||
continue;
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_ELEM:
|
||||
case ROFFT_BLOCK:
|
||||
case ROFFT_HEAD:
|
||||
case ROFFT_BODY:
|
||||
case ROFFT_TAIL:
|
||||
if (mdocs[n->tok].fp != NULL &&
|
||||
(*mdocs[n->tok].fp)(mpage, meta, n) == 0)
|
||||
if (handler->fp != NULL &&
|
||||
(*handler->fp)(mpage, meta, n) == 0)
|
||||
break;
|
||||
if (mdocs[n->tok].mask)
|
||||
if (handler->mask)
|
||||
putmdockey(mpage, n->child,
|
||||
mdocs[n->tok].mask, mdocs[n->tok].taboo);
|
||||
handler->mask, handler->taboo);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
|
24
manpath.c
24
manpath.c
@ -1,6 +1,6 @@
|
||||
/* $Id: manpath.c,v 1.35 2017/07/01 09:47:30 schwarze Exp $ */
|
||||
/* $Id: manpath.c,v 1.37 2018/11/22 11:30:23 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2011,2014,2015,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
@ -232,8 +232,8 @@ int
|
||||
manconf_output(struct manoutput *conf, const char *cp, int fromfile)
|
||||
{
|
||||
const char *const toks[] = {
|
||||
"includes", "man", "paper", "style",
|
||||
"indent", "width", "fragment", "mdoc", "noval"
|
||||
"includes", "man", "paper", "style", "indent", "width",
|
||||
"tag", "fragment", "mdoc", "noval", "toc"
|
||||
};
|
||||
|
||||
const char *errstr;
|
||||
@ -257,7 +257,7 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile)
|
||||
warnx("-O %s=?: Missing argument value", toks[tok]);
|
||||
return -1;
|
||||
}
|
||||
if ((tok == 6 || tok == 7) && *cp != '\0') {
|
||||
if (tok > 6 && *cp != '\0') {
|
||||
warnx("-O %s: Does not take a value: %s", toks[tok], cp);
|
||||
return -1;
|
||||
}
|
||||
@ -312,14 +312,24 @@ manconf_output(struct manoutput *conf, const char *cp, int fromfile)
|
||||
warnx("-O width=%s is %s", cp, errstr);
|
||||
return -1;
|
||||
case 6:
|
||||
conf->fragment = 1;
|
||||
if (conf->tag != NULL) {
|
||||
oldval = mandoc_strdup(conf->tag);
|
||||
break;
|
||||
}
|
||||
conf->tag = mandoc_strdup(cp);
|
||||
return 0;
|
||||
case 7:
|
||||
conf->mdoc = 1;
|
||||
conf->fragment = 1;
|
||||
return 0;
|
||||
case 8:
|
||||
conf->mdoc = 1;
|
||||
return 0;
|
||||
case 9:
|
||||
conf->noval = 1;
|
||||
return 0;
|
||||
case 10:
|
||||
conf->toc = 1;
|
||||
return 0;
|
||||
default:
|
||||
if (fromfile)
|
||||
warnx("-O %s: Bad argument", cp);
|
||||
|
18
mansearch.c
18
mansearch.c
@ -1,7 +1,7 @@
|
||||
/* $Id: mansearch.c,v 1.77 2017/08/22 17:50:11 schwarze Exp $ */
|
||||
/* $Id: mansearch.c,v 1.80 2018/12/13 11:55:46 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2013-2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2013-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
|
||||
@ -36,7 +36,6 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "mandoc_aux.h"
|
||||
#include "mandoc_ohash.h"
|
||||
#include "manconf.h"
|
||||
@ -201,7 +200,6 @@ mansearch(const struct mansearch *search,
|
||||
mpage->names = buildnames(page);
|
||||
mpage->output = buildoutput(outkey, page);
|
||||
mpage->ipath = i;
|
||||
mpage->bits = rp->bits;
|
||||
mpage->sec = *page->sect - '0';
|
||||
if (mpage->sec < 0 || mpage->sec > 9)
|
||||
mpage->sec = 10;
|
||||
@ -296,10 +294,8 @@ manmerge_term(struct expr *e, struct ohash *htab)
|
||||
break;
|
||||
slot = ohash_lookup_memory(htab,
|
||||
(char *)&res, sizeof(res.page), res.page);
|
||||
if ((rp = ohash_find(htab, slot)) != NULL) {
|
||||
rp->bits |= res.bits;
|
||||
if ((rp = ohash_find(htab, slot)) != NULL)
|
||||
continue;
|
||||
}
|
||||
rp = mandoc_malloc(sizeof(*rp));
|
||||
*rp = res;
|
||||
ohash_insert(htab, slot, rp);
|
||||
@ -412,8 +408,7 @@ manpage_compare(const void *vp1, const void *vp2)
|
||||
|
||||
mp1 = vp1;
|
||||
mp2 = vp2;
|
||||
if ((diff = mp2->bits - mp1->bits) ||
|
||||
(diff = mp1->sec - mp2->sec))
|
||||
if ((diff = mp1->sec - mp2->sec))
|
||||
return diff;
|
||||
|
||||
/* Fall back to alphabetic ordering of names. */
|
||||
@ -774,8 +769,9 @@ exprterm(const struct mansearch *search, int argc, char *argv[], int *argi)
|
||||
cs = 0;
|
||||
} else if ((val = strpbrk(argv[*argi], "=~")) == NULL) {
|
||||
e->bits = TYPE_Nm | TYPE_Nd;
|
||||
e->match.type = DBM_SUB;
|
||||
e->match.str = argv[*argi];
|
||||
e->match.type = DBM_REGEX;
|
||||
val = argv[*argi];
|
||||
cs = 0;
|
||||
} else {
|
||||
if (val == argv[*argi])
|
||||
e->bits = TYPE_Nm | TYPE_Nd;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: mansearch.h,v 1.28 2017/04/17 20:05:08 schwarze Exp $ */
|
||||
/* $Id: mansearch.h,v 1.29 2018/11/22 12:01:46 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2013, 2014, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
@ -93,7 +93,6 @@ struct manpage {
|
||||
char *names; /* a list of names with sections */
|
||||
char *output; /* user-defined additional output */
|
||||
size_t ipath; /* number of the manpath */
|
||||
uint64_t bits; /* name type mask */
|
||||
int sec; /* section number, 10 means invalid */
|
||||
enum form form;
|
||||
};
|
||||
|
59
mdoc.c
59
mdoc.c
@ -1,7 +1,7 @@
|
||||
/* $Id: mdoc.c,v 1.268 2017/08/11 16:56:21 schwarze Exp $ */
|
||||
/* $Id: mdoc.c,v 1.274 2018/12/31 07:46:07 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2010, 2012-2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* 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
|
||||
@ -79,13 +79,6 @@ mdoc_parseln(struct roff_man *mdoc, int ln, char *buf, int offs)
|
||||
mdoc_ptext(mdoc, ln, buf, offs);
|
||||
}
|
||||
|
||||
void
|
||||
mdoc_macro(MACRO_PROT_ARGS)
|
||||
{
|
||||
assert(tok >= MDOC_Dd && tok < MDOC_MAX);
|
||||
(*mdoc_macros[tok].fp)(mdoc, tok, line, ppos, pos, buf);
|
||||
}
|
||||
|
||||
void
|
||||
mdoc_tail_alloc(struct roff_man *mdoc, int line, int pos, enum roff_tok tok)
|
||||
{
|
||||
@ -162,15 +155,6 @@ mdoc_elem_alloc(struct roff_man *mdoc, int line, int pos,
|
||||
mdoc->next = ROFF_NEXT_CHILD;
|
||||
}
|
||||
|
||||
void
|
||||
mdoc_node_relink(struct roff_man *mdoc, struct roff_node *p)
|
||||
{
|
||||
|
||||
roff_node_unlink(mdoc, p);
|
||||
p->prev = p->next = NULL;
|
||||
roff_node_append(mdoc, p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse free-form text, that is, a line that does not begin with the
|
||||
* control character.
|
||||
@ -196,7 +180,8 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
|
||||
(n->parent != NULL && n->parent->tok == MDOC_Bl &&
|
||||
n->parent->norm->Bl.type == LIST_column)) {
|
||||
mdoc->flags |= MDOC_FREECOL;
|
||||
mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf);
|
||||
(*mdoc_macro(MDOC_It)->fp)(mdoc, MDOC_It,
|
||||
line, offs, &offs, buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -225,7 +210,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
|
||||
* Strip trailing tabs in literal context only;
|
||||
* outside, they affect the next line.
|
||||
*/
|
||||
if (MDOC_LITERAL & mdoc->flags)
|
||||
if (mdoc->flags & ROFF_NOFILL)
|
||||
continue;
|
||||
break;
|
||||
case '\\':
|
||||
@ -242,8 +227,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
|
||||
*end = '\0';
|
||||
|
||||
if (ws)
|
||||
mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
|
||||
line, (int)(ws-buf), NULL);
|
||||
mandoc_msg(MANDOCERR_SPACE_EOL, line, (int)(ws - buf), NULL);
|
||||
|
||||
/*
|
||||
* Blank lines are allowed in no-fill mode
|
||||
@ -251,7 +235,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
|
||||
* but add a single vertical space elsewhere.
|
||||
*/
|
||||
|
||||
if (buf[offs] == '\0' && ! (mdoc->flags & MDOC_LITERAL)) {
|
||||
if (buf[offs] == '\0' && (mdoc->flags & ROFF_NOFILL) == 0) {
|
||||
switch (mdoc->last->type) {
|
||||
case ROFFT_TEXT:
|
||||
sp = mdoc->last->string;
|
||||
@ -267,8 +251,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
mandoc_msg(MANDOCERR_FI_BLANK, mdoc->parse,
|
||||
line, (int)(c - buf), NULL);
|
||||
mandoc_msg(MANDOCERR_FI_BLANK, line, (int)(c - buf), NULL);
|
||||
roff_elem_alloc(mdoc, line, offs, ROFF_sp);
|
||||
mdoc->last->flags |= NODE_VALID | NODE_ENDED;
|
||||
mdoc->next = ROFF_NEXT_SIBLING;
|
||||
@ -277,7 +260,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
|
||||
|
||||
roff_word_alloc(mdoc, line, offs, buf+offs);
|
||||
|
||||
if (mdoc->flags & MDOC_LITERAL)
|
||||
if (mdoc->flags & ROFF_NOFILL)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
@ -308,8 +291,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
|
||||
if (*c == ' ')
|
||||
c++;
|
||||
if (isupper((unsigned char)(*c)))
|
||||
mandoc_msg(MANDOCERR_EOS, mdoc->parse,
|
||||
line, (int)(c - buf), NULL);
|
||||
mandoc_msg(MANDOCERR_EOS, line, (int)(c - buf), NULL);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -337,8 +319,7 @@ mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs)
|
||||
if (sz == 2 || sz == 3)
|
||||
tok = roffhash_find(mdoc->mdocmac, buf + sv, sz);
|
||||
if (tok == TOKEN_NONE) {
|
||||
mandoc_msg(MANDOCERR_MACRO, mdoc->parse,
|
||||
ln, sv, buf + sv - 1);
|
||||
mandoc_msg(MANDOCERR_MACRO, ln, sv, "%s", buf + sv - 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -368,8 +349,7 @@ mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs)
|
||||
*/
|
||||
|
||||
if ('\0' == buf[offs] && ' ' == buf[offs - 1])
|
||||
mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
|
||||
ln, offs - 1, NULL);
|
||||
mandoc_msg(MANDOCERR_SPACE_EOL, ln, offs - 1, NULL);
|
||||
|
||||
/*
|
||||
* If an initial macro or a list invocation, divert directly
|
||||
@ -378,7 +358,7 @@ mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs)
|
||||
|
||||
n = mdoc->last;
|
||||
if (n == NULL || tok == MDOC_It || tok == MDOC_El) {
|
||||
mdoc_macro(mdoc, tok, ln, sv, &offs, buf);
|
||||
(*mdoc_macro(tok)->fp)(mdoc, tok, ln, sv, &offs, buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -394,13 +374,13 @@ mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs)
|
||||
(n->parent != NULL && n->parent->tok == MDOC_Bl &&
|
||||
n->parent->norm->Bl.type == LIST_column)) {
|
||||
mdoc->flags |= MDOC_FREECOL;
|
||||
mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf);
|
||||
(*mdoc_macro(MDOC_It)->fp)(mdoc, MDOC_It, ln, sv, &sv, buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Normal processing of a macro. */
|
||||
|
||||
mdoc_macro(mdoc, tok, ln, sv, &offs, buf);
|
||||
(*mdoc_macro(tok)->fp)(mdoc, tok, ln, sv, &offs, buf);
|
||||
|
||||
/* In quick mode (for mandocdb), abort after the NAME section. */
|
||||
|
||||
@ -448,12 +428,3 @@ mdoc_isdelim(const char *p)
|
||||
|
||||
return DELIM_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
mdoc_validate(struct roff_man *mdoc)
|
||||
{
|
||||
|
||||
mdoc->last = mdoc->first;
|
||||
mdoc_node_validate(mdoc);
|
||||
mdoc_state_reset(mdoc);
|
||||
}
|
||||
|
5
mdoc.h
5
mdoc.h
@ -1,4 +1,4 @@
|
||||
/* $Id: mdoc.h,v 1.145 2017/04/24 23:06:18 schwarze Exp $ */
|
||||
/* $Id: mdoc.h,v 1.146 2018/12/30 00:49:55 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
|
||||
@ -16,6 +16,9 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
struct roff_node;
|
||||
struct roff_man;
|
||||
|
||||
enum mdocargt {
|
||||
MDOC_Split, /* -split */
|
||||
MDOC_Nosplit, /* -nospli */
|
||||
|
53
mdoc_argv.c
53
mdoc_argv.c
@ -1,7 +1,7 @@
|
||||
/* $Id: mdoc_argv.c,v 1.115 2017/05/30 16:22:03 schwarze Exp $ */
|
||||
/* $Id: mdoc_argv.c,v 1.119 2018/12/21 17:15:19 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2012, 2014-2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2012, 2014-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
|
||||
@ -144,7 +144,7 @@ static const enum mdocargt args_Bl[] = {
|
||||
MDOC_ARG_MAX
|
||||
};
|
||||
|
||||
static const struct mdocarg __mdocargs[MDOC_MAX - MDOC_Dd] = {
|
||||
static const struct mdocarg mdocargs[MDOC_MAX - MDOC_Dd] = {
|
||||
{ ARGSFL_NONE, NULL }, /* Dd */
|
||||
{ ARGSFL_NONE, NULL }, /* Dt */
|
||||
{ ARGSFL_NONE, NULL }, /* Os */
|
||||
@ -266,7 +266,6 @@ static const struct mdocarg __mdocargs[MDOC_MAX - MDOC_Dd] = {
|
||||
{ ARGSFL_NONE, NULL }, /* %U */
|
||||
{ ARGSFL_NONE, NULL }, /* Ta */
|
||||
};
|
||||
static const struct mdocarg *const mdocargs = __mdocargs - MDOC_Dd;
|
||||
|
||||
|
||||
/*
|
||||
@ -290,7 +289,7 @@ mdoc_argv(struct roff_man *mdoc, int line, enum roff_tok tok,
|
||||
/* Which flags does this macro support? */
|
||||
|
||||
assert(tok >= MDOC_Dd && tok < MDOC_MAX);
|
||||
argtable = mdocargs[tok].argvs;
|
||||
argtable = mdocargs[tok - MDOC_Dd].argvs;
|
||||
if (argtable == NULL)
|
||||
return;
|
||||
|
||||
@ -368,7 +367,7 @@ mdoc_argv(struct roff_man *mdoc, int line, enum roff_tok tok,
|
||||
/* Prepare for parsing the next flag. */
|
||||
|
||||
*pos = ipos;
|
||||
argtable = mdocargs[tok].argvs;
|
||||
argtable = mdocargs[tok - MDOC_Dd].argvs;
|
||||
}
|
||||
}
|
||||
|
||||
@ -417,12 +416,9 @@ mdoc_args(struct roff_man *mdoc, int line, int *pos,
|
||||
char *buf, enum roff_tok tok, char **v)
|
||||
{
|
||||
struct roff_node *n;
|
||||
char *v_local;
|
||||
enum argsflag fl;
|
||||
|
||||
if (v == NULL)
|
||||
v = &v_local;
|
||||
fl = tok == TOKEN_NONE ? ARGSFL_NONE : mdocargs[tok].flags;
|
||||
fl = tok == TOKEN_NONE ? ARGSFL_NONE : mdocargs[tok - MDOC_Dd].flags;
|
||||
|
||||
/*
|
||||
* We know that we're in an `It', so it's reasonable to expect
|
||||
@ -449,18 +445,20 @@ args(struct roff_man *mdoc, int line, int *pos,
|
||||
char *buf, enum argsflag fl, char **v)
|
||||
{
|
||||
char *p;
|
||||
char *v_local;
|
||||
int pairs;
|
||||
|
||||
if (buf[*pos] == '\0') {
|
||||
if (mdoc->flags & MDOC_PHRASELIT &&
|
||||
! (mdoc->flags & MDOC_PHRASE)) {
|
||||
mandoc_msg(MANDOCERR_ARG_QUOTE,
|
||||
mdoc->parse, line, *pos, NULL);
|
||||
mandoc_msg(MANDOCERR_ARG_QUOTE, line, *pos, NULL);
|
||||
mdoc->flags &= ~MDOC_PHRASELIT;
|
||||
}
|
||||
return ARGS_EOLN;
|
||||
}
|
||||
|
||||
if (v == NULL)
|
||||
v = &v_local;
|
||||
*v = buf + *pos;
|
||||
|
||||
if (fl == ARGSFL_DELIM && args_checkpunct(buf, *pos))
|
||||
@ -506,7 +504,7 @@ args(struct roff_man *mdoc, int line, int *pos,
|
||||
p = strchr(*v, '\0');
|
||||
if (p[-1] == ' ')
|
||||
mandoc_msg(MANDOCERR_SPACE_EOL,
|
||||
mdoc->parse, line, *pos, NULL);
|
||||
line, *pos, NULL);
|
||||
*pos += (int)(p - *v);
|
||||
}
|
||||
|
||||
@ -527,13 +525,12 @@ args(struct roff_man *mdoc, int line, int *pos,
|
||||
* Whitespace is NOT involved in literal termination.
|
||||
*/
|
||||
|
||||
if (mdoc->flags & MDOC_PHRASELIT || buf[*pos] == '\"') {
|
||||
if ( ! (mdoc->flags & MDOC_PHRASELIT))
|
||||
if (mdoc->flags & MDOC_PHRASELIT ||
|
||||
(mdoc->flags & MDOC_PHRASE && buf[*pos] == '\"')) {
|
||||
if ((mdoc->flags & MDOC_PHRASELIT) == 0) {
|
||||
*v = &buf[++(*pos)];
|
||||
|
||||
if (mdoc->flags & MDOC_PHRASE)
|
||||
mdoc->flags |= MDOC_PHRASELIT;
|
||||
|
||||
}
|
||||
pairs = 0;
|
||||
for ( ; buf[*pos]; (*pos)++) {
|
||||
/* Move following text left after quoted quotes. */
|
||||
@ -554,7 +551,7 @@ args(struct roff_man *mdoc, int line, int *pos,
|
||||
if (buf[*pos] == '\0') {
|
||||
if ( ! (mdoc->flags & MDOC_PHRASE))
|
||||
mandoc_msg(MANDOCERR_ARG_QUOTE,
|
||||
mdoc->parse, line, *pos, NULL);
|
||||
line, *pos, NULL);
|
||||
return ARGS_WORD;
|
||||
}
|
||||
|
||||
@ -568,14 +565,15 @@ args(struct roff_man *mdoc, int line, int *pos,
|
||||
(*pos)++;
|
||||
|
||||
if ('\0' == buf[*pos])
|
||||
mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
|
||||
line, *pos, NULL);
|
||||
mandoc_msg(MANDOCERR_SPACE_EOL, line, *pos, NULL);
|
||||
|
||||
return ARGS_WORD;
|
||||
}
|
||||
|
||||
p = &buf[*pos];
|
||||
*v = mandoc_getarg(mdoc->parse, &p, line, pos);
|
||||
*v = roff_getarg(mdoc->roff, &p, line, pos);
|
||||
if (v == &v_local)
|
||||
free(*v);
|
||||
|
||||
/*
|
||||
* After parsing the last word in this phrase,
|
||||
@ -586,7 +584,7 @@ args(struct roff_man *mdoc, int line, int *pos,
|
||||
mdoc->flags &= ~MDOC_PHRASEQL;
|
||||
mdoc->flags |= MDOC_PHRASEQF;
|
||||
}
|
||||
return ARGS_WORD;
|
||||
return ARGS_ALLOC;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -657,7 +655,9 @@ argv_multi(struct roff_man *mdoc, int line,
|
||||
v->value = mandoc_reallocarray(v->value,
|
||||
v->sz + MULTI_STEP, sizeof(char *));
|
||||
|
||||
v->value[(int)v->sz] = mandoc_strdup(p);
|
||||
if (ac != ARGS_ALLOC)
|
||||
p = mandoc_strdup(p);
|
||||
v->value[(int)v->sz] = p;
|
||||
}
|
||||
}
|
||||
|
||||
@ -672,7 +672,10 @@ argv_single(struct roff_man *mdoc, int line,
|
||||
if (ac == ARGS_EOLN)
|
||||
return;
|
||||
|
||||
if (ac != ARGS_ALLOC)
|
||||
p = mandoc_strdup(p);
|
||||
|
||||
v->sz = 1;
|
||||
v->value = mandoc_malloc(sizeof(char *));
|
||||
v->value[0] = mandoc_strdup(p);
|
||||
v->value[0] = p;
|
||||
}
|
||||
|
445
mdoc_html.c
445
mdoc_html.c
@ -1,7 +1,7 @@
|
||||
/* $Id: mdoc_html.c,v 1.310 2018/07/27 17:49:31 schwarze Exp $ */
|
||||
/* $Id: mdoc_html.c,v 1.328 2019/03/01 10:57:18 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2014,2015,2016,2017,2018 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* 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
|
||||
@ -42,7 +42,7 @@
|
||||
#define MIN(a,b) ((/*CONSTCOND*/(a)<(b))?(a):(b))
|
||||
#endif
|
||||
|
||||
struct htmlmdoc {
|
||||
struct mdoc_html_act {
|
||||
int (*pre)(MDOC_ARGS);
|
||||
void (*post)(MDOC_ARGS);
|
||||
};
|
||||
@ -62,6 +62,7 @@ static int mdoc_root_pre(const struct roff_meta *,
|
||||
|
||||
static void mdoc__x_post(MDOC_ARGS);
|
||||
static int mdoc__x_pre(MDOC_ARGS);
|
||||
static int mdoc_abort_pre(MDOC_ARGS);
|
||||
static int mdoc_ad_pre(MDOC_ARGS);
|
||||
static int mdoc_an_pre(MDOC_ARGS);
|
||||
static int mdoc_ap_pre(MDOC_ARGS);
|
||||
@ -119,7 +120,7 @@ static int mdoc_vt_pre(MDOC_ARGS);
|
||||
static int mdoc_xr_pre(MDOC_ARGS);
|
||||
static int mdoc_xx_pre(MDOC_ARGS);
|
||||
|
||||
static const struct htmlmdoc __mdocs[MDOC_MAX - MDOC_Dd] = {
|
||||
static const struct mdoc_html_act mdoc_html_acts[MDOC_MAX - MDOC_Dd] = {
|
||||
{NULL, NULL}, /* Dd */
|
||||
{NULL, NULL}, /* Dt */
|
||||
{NULL, NULL}, /* Os */
|
||||
@ -154,7 +155,7 @@ static const struct htmlmdoc __mdocs[MDOC_MAX - MDOC_Dd] = {
|
||||
{mdoc_nd_pre, NULL}, /* Nd */
|
||||
{mdoc_nm_pre, NULL}, /* Nm */
|
||||
{mdoc_quote_pre, mdoc_quote_post}, /* Op */
|
||||
{mdoc_ft_pre, NULL}, /* Ot */
|
||||
{mdoc_abort_pre, NULL}, /* Ot */
|
||||
{mdoc_pa_pre, NULL}, /* Pa */
|
||||
{mdoc_ex_pre, NULL}, /* Rv */
|
||||
{mdoc_st_pre, NULL}, /* St */
|
||||
@ -227,7 +228,7 @@ static const struct htmlmdoc __mdocs[MDOC_MAX - MDOC_Dd] = {
|
||||
{mdoc_em_pre, NULL}, /* Fr */
|
||||
{NULL, NULL}, /* Ud */
|
||||
{mdoc_lb_pre, NULL}, /* Lb */
|
||||
{mdoc_pp_pre, NULL}, /* Lp */
|
||||
{mdoc_abort_pre, NULL}, /* Lp */
|
||||
{mdoc_lk_pre, NULL}, /* Lk */
|
||||
{mdoc_mt_pre, NULL}, /* Mt */
|
||||
{mdoc_quote_pre, mdoc_quote_post}, /* Brq */
|
||||
@ -241,7 +242,6 @@ static const struct htmlmdoc __mdocs[MDOC_MAX - MDOC_Dd] = {
|
||||
{mdoc__x_pre, mdoc__x_post}, /* %U */
|
||||
{NULL, NULL}, /* Ta */
|
||||
};
|
||||
static const struct htmlmdoc *const mdocs = __mdocs - MDOC_Dd;
|
||||
|
||||
|
||||
/*
|
||||
@ -268,22 +268,21 @@ synopsis_pre(struct html *h, const struct roff_node *n)
|
||||
case MDOC_Fo:
|
||||
case MDOC_In:
|
||||
case MDOC_Vt:
|
||||
print_paragraph(h);
|
||||
break;
|
||||
case MDOC_Ft:
|
||||
if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
|
||||
print_paragraph(h);
|
||||
if (n->tok != MDOC_Fn && n->tok != MDOC_Fo)
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
print_otag(h, TAG_BR, "");
|
||||
break;
|
||||
return;
|
||||
}
|
||||
html_close_paragraph(h);
|
||||
print_otag(h, TAG_P, "c", "Pp");
|
||||
}
|
||||
|
||||
void
|
||||
html_mdoc(void *arg, const struct roff_man *mdoc)
|
||||
html_mdoc(void *arg, const struct roff_meta *mdoc)
|
||||
{
|
||||
struct html *h;
|
||||
struct roff_node *n;
|
||||
@ -295,19 +294,19 @@ html_mdoc(void *arg, const struct roff_man *mdoc)
|
||||
if ((h->oflags & HTML_FRAGMENT) == 0) {
|
||||
print_gen_decls(h);
|
||||
print_otag(h, TAG_HTML, "");
|
||||
if (n->type == ROFFT_COMMENT)
|
||||
if (n != NULL && n->type == ROFFT_COMMENT)
|
||||
print_gen_comment(h, n);
|
||||
t = print_otag(h, TAG_HEAD, "");
|
||||
print_mdoc_head(&mdoc->meta, h);
|
||||
print_mdoc_head(mdoc, h);
|
||||
print_tagq(h, t);
|
||||
print_otag(h, TAG_BODY, "");
|
||||
}
|
||||
|
||||
mdoc_root_pre(&mdoc->meta, h);
|
||||
mdoc_root_pre(mdoc, h);
|
||||
t = print_otag(h, TAG_DIV, "c", "manual-text");
|
||||
print_mdoc_nodelist(&mdoc->meta, n, h);
|
||||
print_mdoc_nodelist(mdoc, n, h);
|
||||
print_tagq(h, t);
|
||||
mdoc_root_post(&mdoc->meta, h);
|
||||
mdoc_root_post(mdoc, h);
|
||||
print_tagq(h, NULL);
|
||||
}
|
||||
|
||||
@ -346,18 +345,21 @@ print_mdoc_nodelist(MDOC_ARGS)
|
||||
static void
|
||||
print_mdoc_node(MDOC_ARGS)
|
||||
{
|
||||
int child;
|
||||
struct tag *t;
|
||||
int child;
|
||||
|
||||
if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
|
||||
return;
|
||||
|
||||
child = 1;
|
||||
t = h->tag;
|
||||
n->flags &= ~NODE_ENDED;
|
||||
html_fillmode(h, n->flags & NODE_NOFILL ? ROFF_nf : ROFF_fi);
|
||||
|
||||
child = 1;
|
||||
n->flags &= ~NODE_ENDED;
|
||||
switch (n->type) {
|
||||
case ROFFT_TEXT:
|
||||
t = h->tag;
|
||||
t->refcnt++;
|
||||
|
||||
/* No tables in this mode... */
|
||||
assert(NULL == h->tblt);
|
||||
|
||||
@ -366,15 +368,18 @@ print_mdoc_node(MDOC_ARGS)
|
||||
* (i.e., within a <PRE>) don't print the newline.
|
||||
*/
|
||||
if (*n->string == ' ' && n->flags & NODE_LINE &&
|
||||
(h->flags & (HTML_LITERAL | HTML_NONEWLINE)) == 0)
|
||||
(h->flags & HTML_NONEWLINE) == 0 &&
|
||||
(n->flags & NODE_NOFILL) == 0)
|
||||
print_otag(h, TAG_BR, "");
|
||||
if (NODE_DELIMC & n->flags)
|
||||
h->flags |= HTML_NOSPACE;
|
||||
print_text(h, n->string);
|
||||
if (NODE_DELIMO & n->flags)
|
||||
h->flags |= HTML_NOSPACE;
|
||||
return;
|
||||
break;
|
||||
case ROFFT_EQN:
|
||||
t = h->tag;
|
||||
t->refcnt++;
|
||||
print_eqn(h, n->eqn);
|
||||
break;
|
||||
case ROFFT_TBL:
|
||||
@ -391,20 +396,22 @@ print_mdoc_node(MDOC_ARGS)
|
||||
* the "meta" table state. This will be reopened on the
|
||||
* next table element.
|
||||
*/
|
||||
if (h->tblt != NULL) {
|
||||
if (h->tblt != NULL)
|
||||
print_tblclose(h);
|
||||
t = h->tag;
|
||||
}
|
||||
assert(h->tblt == NULL);
|
||||
t = h->tag;
|
||||
t->refcnt++;
|
||||
if (n->tok < ROFF_MAX) {
|
||||
roff_html_pre(h, n);
|
||||
child = 0;
|
||||
break;
|
||||
t->refcnt--;
|
||||
print_stagq(h, t);
|
||||
return;
|
||||
}
|
||||
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
|
||||
if (mdocs[n->tok].pre != NULL &&
|
||||
if (mdoc_html_acts[n->tok - MDOC_Dd].pre != NULL &&
|
||||
(n->end == ENDBODY_NOT || n->child != NULL))
|
||||
child = (*mdocs[n->tok].pre)(meta, n, h);
|
||||
child = (*mdoc_html_acts[n->tok - MDOC_Dd].pre)(meta,
|
||||
n, h);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -413,24 +420,31 @@ print_mdoc_node(MDOC_ARGS)
|
||||
h->flags |= HTML_PREKEEP;
|
||||
}
|
||||
|
||||
if (child && n->child)
|
||||
if (child && n->child != NULL)
|
||||
print_mdoc_nodelist(meta, n->child, h);
|
||||
|
||||
t->refcnt--;
|
||||
print_stagq(h, t);
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_TEXT:
|
||||
case ROFFT_EQN:
|
||||
break;
|
||||
default:
|
||||
if (n->tok < ROFF_MAX ||
|
||||
mdocs[n->tok].post == NULL ||
|
||||
if (mdoc_html_acts[n->tok - MDOC_Dd].post == NULL ||
|
||||
n->flags & NODE_ENDED)
|
||||
break;
|
||||
(*mdocs[n->tok].post)(meta, n, h);
|
||||
(*mdoc_html_acts[n->tok - MDOC_Dd].post)(meta, n, h);
|
||||
if (n->end != ENDBODY_NOT)
|
||||
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
|
||||
@ -507,12 +521,65 @@ cond_id(const struct roff_node *n)
|
||||
static int
|
||||
mdoc_sh_pre(MDOC_ARGS)
|
||||
{
|
||||
char *id;
|
||||
struct roff_node *sn, *subn;
|
||||
struct tag *t, *tsec, *tsub;
|
||||
char *id;
|
||||
int sc;
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
html_close_paragraph(h);
|
||||
if ((h->oflags & HTML_TOC) == 0 ||
|
||||
h->flags & HTML_TOCDONE ||
|
||||
n->sec <= SEC_SYNOPSIS) {
|
||||
print_otag(h, TAG_SECTION, "c", "Sh");
|
||||
break;
|
||||
}
|
||||
h->flags |= HTML_TOCDONE;
|
||||
sc = 0;
|
||||
for (sn = n->next; sn != NULL; sn = sn->next)
|
||||
if (sn->sec == SEC_CUSTOM)
|
||||
if (++sc == 2)
|
||||
break;
|
||||
if (sc < 2)
|
||||
break;
|
||||
t = print_otag(h, TAG_H1, "c", "Sh");
|
||||
print_text(h, "TABLE OF CONTENTS");
|
||||
print_tagq(h, t);
|
||||
t = print_otag(h, TAG_UL, "c", "Bl-compact");
|
||||
for (sn = n; sn != NULL; sn = sn->next) {
|
||||
tsec = print_otag(h, TAG_LI, "");
|
||||
id = html_make_id(sn->head, 0);
|
||||
tsub = print_otag(h, TAG_A, "hR", id);
|
||||
free(id);
|
||||
print_mdoc_nodelist(meta, sn->head->child, h);
|
||||
print_tagq(h, tsub);
|
||||
tsub = NULL;
|
||||
for (subn = sn->body->child; subn != NULL;
|
||||
subn = subn->next) {
|
||||
if (subn->tok != MDOC_Ss)
|
||||
continue;
|
||||
id = html_make_id(subn->head, 0);
|
||||
if (id == NULL)
|
||||
continue;
|
||||
if (tsub == NULL)
|
||||
print_otag(h, TAG_UL,
|
||||
"c", "Bl-compact");
|
||||
tsub = print_otag(h, TAG_LI, "");
|
||||
print_otag(h, TAG_A, "hR", id);
|
||||
free(id);
|
||||
print_mdoc_nodelist(meta,
|
||||
subn->head->child, h);
|
||||
print_tagq(h, tsub);
|
||||
}
|
||||
print_tagq(h, tsec);
|
||||
}
|
||||
print_tagq(h, t);
|
||||
print_otag(h, TAG_SECTION, "c", "Sh");
|
||||
break;
|
||||
case ROFFT_HEAD:
|
||||
id = html_make_id(n, 1);
|
||||
print_otag(h, TAG_H1, "cTi", "Sh", id);
|
||||
print_otag(h, TAG_H1, "ci", "Sh", id);
|
||||
if (id != NULL)
|
||||
print_otag(h, TAG_A, "chR", "permalink", id);
|
||||
break;
|
||||
@ -531,11 +598,21 @@ mdoc_ss_pre(MDOC_ARGS)
|
||||
{
|
||||
char *id;
|
||||
|
||||
if (n->type != ROFFT_HEAD)
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
html_close_paragraph(h);
|
||||
print_otag(h, TAG_SECTION, "c", "Ss");
|
||||
return 1;
|
||||
case ROFFT_HEAD:
|
||||
break;
|
||||
case ROFFT_BODY:
|
||||
return 1;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
id = html_make_id(n, 1);
|
||||
print_otag(h, TAG_H2, "cTi", "Ss", id);
|
||||
print_otag(h, TAG_H2, "ci", "Ss", id);
|
||||
if (id != NULL)
|
||||
print_otag(h, TAG_A, "chR", "permalink", id);
|
||||
return 1;
|
||||
@ -548,7 +625,7 @@ mdoc_fl_pre(MDOC_ARGS)
|
||||
|
||||
if ((id = cond_id(n)) != NULL)
|
||||
print_otag(h, TAG_A, "chR", "permalink", id);
|
||||
print_otag(h, TAG_CODE, "cTi", "Fl", id);
|
||||
print_otag(h, TAG_CODE, "ci", "Fl", id);
|
||||
|
||||
print_text(h, "\\-");
|
||||
if (!(n->child == NULL &&
|
||||
@ -567,19 +644,27 @@ mdoc_cm_pre(MDOC_ARGS)
|
||||
|
||||
if ((id = cond_id(n)) != NULL)
|
||||
print_otag(h, TAG_A, "chR", "permalink", id);
|
||||
print_otag(h, TAG_CODE, "cTi", "Cm", id);
|
||||
print_otag(h, TAG_CODE, "ci", "Cm", id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
mdoc_nd_pre(MDOC_ARGS)
|
||||
{
|
||||
if (n->type != ROFFT_BODY)
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
html_close_paragraph(h);
|
||||
return 1;
|
||||
|
||||
case ROFFT_HEAD:
|
||||
return 0;
|
||||
case ROFFT_BODY:
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
print_text(h, "\\(em");
|
||||
/* Cannot use TAG_SPAN because it may contain blocks. */
|
||||
print_otag(h, TAG_DIV, "cT", "Nd");
|
||||
print_otag(h, TAG_DIV, "c", "Nd");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -587,18 +672,21 @@ static int
|
||||
mdoc_nm_pre(MDOC_ARGS)
|
||||
{
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
break;
|
||||
case ROFFT_HEAD:
|
||||
print_otag(h, TAG_TD, "");
|
||||
/* FALLTHROUGH */
|
||||
case ROFFT_ELEM:
|
||||
print_otag(h, TAG_CODE, "cT", "Nm");
|
||||
print_otag(h, TAG_CODE, "c", "Nm");
|
||||
return 1;
|
||||
case ROFFT_BODY:
|
||||
print_otag(h, TAG_TD, "");
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
abort();
|
||||
}
|
||||
html_close_paragraph(h);
|
||||
synopsis_pre(h, n);
|
||||
print_otag(h, TAG_TABLE, "c", "Nm");
|
||||
print_otag(h, TAG_TR, "");
|
||||
@ -611,12 +699,12 @@ mdoc_xr_pre(MDOC_ARGS)
|
||||
if (NULL == n->child)
|
||||
return 0;
|
||||
|
||||
if (h->base_man)
|
||||
print_otag(h, TAG_A, "cThM", "Xr",
|
||||
if (h->base_man1)
|
||||
print_otag(h, TAG_A, "chM", "Xr",
|
||||
n->child->string, n->child->next == NULL ?
|
||||
NULL : n->child->next->string);
|
||||
else
|
||||
print_otag(h, TAG_A, "cT", "Xr");
|
||||
print_otag(h, TAG_A, "c", "Xr");
|
||||
|
||||
n = n->child;
|
||||
print_text(h, n->string);
|
||||
@ -645,7 +733,7 @@ mdoc_ns_pre(MDOC_ARGS)
|
||||
static int
|
||||
mdoc_ar_pre(MDOC_ARGS)
|
||||
{
|
||||
print_otag(h, TAG_VAR, "cT", "Ar");
|
||||
print_otag(h, TAG_VAR, "c", "Ar");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -660,7 +748,6 @@ static int
|
||||
mdoc_it_pre(MDOC_ARGS)
|
||||
{
|
||||
const struct roff_node *bl;
|
||||
struct tag *t;
|
||||
enum mdoc_list type;
|
||||
|
||||
bl = n->parent;
|
||||
@ -702,17 +789,6 @@ mdoc_it_pre(MDOC_ARGS)
|
||||
case LIST_tag:
|
||||
switch (n->type) {
|
||||
case ROFFT_HEAD:
|
||||
if (h->style != NULL && !bl->norm->Bl.comp &&
|
||||
(n->parent->prev == NULL ||
|
||||
n->parent->prev->body == NULL ||
|
||||
n->parent->prev->body->child != NULL)) {
|
||||
t = print_otag(h, TAG_DT, "");
|
||||
print_text(h, "\\ ");
|
||||
print_tagq(h, t);
|
||||
t = print_otag(h, TAG_DD, "");
|
||||
print_text(h, "\\ ");
|
||||
print_tagq(h, t);
|
||||
}
|
||||
print_otag(h, TAG_DT, "");
|
||||
break;
|
||||
case ROFFT_BODY:
|
||||
@ -746,17 +822,20 @@ mdoc_it_pre(MDOC_ARGS)
|
||||
static int
|
||||
mdoc_bl_pre(MDOC_ARGS)
|
||||
{
|
||||
char cattr[28];
|
||||
char cattr[32];
|
||||
struct mdoc_bl *bl;
|
||||
enum htmltag elemtype;
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_BODY:
|
||||
return 1;
|
||||
case ROFFT_BLOCK:
|
||||
html_close_paragraph(h);
|
||||
break;
|
||||
case ROFFT_HEAD:
|
||||
return 0;
|
||||
case ROFFT_BODY:
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
abort();
|
||||
}
|
||||
|
||||
bl = &n->norm->Bl;
|
||||
@ -826,28 +905,34 @@ mdoc_ex_pre(MDOC_ARGS)
|
||||
static int
|
||||
mdoc_st_pre(MDOC_ARGS)
|
||||
{
|
||||
print_otag(h, TAG_SPAN, "cT", "St");
|
||||
print_otag(h, TAG_SPAN, "c", "St");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
mdoc_em_pre(MDOC_ARGS)
|
||||
{
|
||||
print_otag(h, TAG_I, "cT", "Em");
|
||||
print_otag(h, TAG_I, "c", "Em");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
mdoc_d1_pre(MDOC_ARGS)
|
||||
{
|
||||
if (n->type != ROFFT_BLOCK)
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
html_close_paragraph(h);
|
||||
break;
|
||||
case ROFFT_HEAD:
|
||||
return 0;
|
||||
case ROFFT_BODY:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
print_otag(h, TAG_DIV, "c", "Bd Bd-indent");
|
||||
|
||||
if (n->tok == MDOC_Dl)
|
||||
print_otag(h, TAG_CODE, "c", "Li");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -857,7 +942,7 @@ mdoc_sx_pre(MDOC_ARGS)
|
||||
char *id;
|
||||
|
||||
id = html_make_id(n, 0);
|
||||
print_otag(h, TAG_A, "cThR", "Sx", id);
|
||||
print_otag(h, TAG_A, "chR", "Sx", id);
|
||||
free(id);
|
||||
return 1;
|
||||
}
|
||||
@ -865,86 +950,51 @@ mdoc_sx_pre(MDOC_ARGS)
|
||||
static int
|
||||
mdoc_bd_pre(MDOC_ARGS)
|
||||
{
|
||||
int comp, sv;
|
||||
char buf[16];
|
||||
struct roff_node *nn;
|
||||
int comp;
|
||||
|
||||
if (n->type == ROFFT_HEAD)
|
||||
return 0;
|
||||
|
||||
if (n->type == ROFFT_BLOCK) {
|
||||
comp = n->norm->Bd.comp;
|
||||
for (nn = n; nn && ! comp; nn = nn->parent) {
|
||||
if (nn->type != ROFFT_BLOCK)
|
||||
continue;
|
||||
if (MDOC_Ss == nn->tok || MDOC_Sh == nn->tok)
|
||||
comp = 1;
|
||||
if (nn->prev)
|
||||
break;
|
||||
}
|
||||
if ( ! comp)
|
||||
print_paragraph(h);
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
html_close_paragraph(h);
|
||||
return 1;
|
||||
case ROFFT_HEAD:
|
||||
return 0;
|
||||
case ROFFT_BODY:
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Handle preceding whitespace. */
|
||||
|
||||
comp = n->norm->Bd.comp;
|
||||
for (nn = n; nn != NULL && comp == 0; nn = nn->parent) {
|
||||
if (nn->type != ROFFT_BLOCK)
|
||||
continue;
|
||||
if (nn->tok == MDOC_Sh || nn->tok == MDOC_Ss)
|
||||
comp = 1;
|
||||
if (nn->prev != NULL)
|
||||
break;
|
||||
}
|
||||
(void)strlcpy(buf, "Bd", sizeof(buf));
|
||||
if (comp == 0)
|
||||
(void)strlcat(buf, " Pp", sizeof(buf));
|
||||
|
||||
/* Handle the -offset argument. */
|
||||
|
||||
if (n->norm->Bd.offs == NULL ||
|
||||
! strcmp(n->norm->Bd.offs, "left"))
|
||||
print_otag(h, TAG_DIV, "c", "Bd");
|
||||
else
|
||||
print_otag(h, TAG_DIV, "c", "Bd Bd-indent");
|
||||
if (n->norm->Bd.offs != NULL &&
|
||||
strcmp(n->norm->Bd.offs, "left") != 0)
|
||||
(void)strlcat(buf, " Bd-indent", sizeof(buf));
|
||||
|
||||
if (n->norm->Bd.type != DISP_unfilled &&
|
||||
n->norm->Bd.type != DISP_literal)
|
||||
return 1;
|
||||
|
||||
print_otag(h, TAG_PRE, "c", "Li");
|
||||
|
||||
/* This can be recursive: save & set our literal state. */
|
||||
|
||||
sv = h->flags & HTML_LITERAL;
|
||||
h->flags |= HTML_LITERAL;
|
||||
|
||||
for (nn = n->child; nn; nn = nn->next) {
|
||||
print_mdoc_node(meta, nn, h);
|
||||
/*
|
||||
* If the printed node flushes its own line, then we
|
||||
* needn't do it here as well. This is hacky, but the
|
||||
* notion of selective eoln whitespace is pretty dumb
|
||||
* anyway, so don't sweat it.
|
||||
*/
|
||||
switch (nn->tok) {
|
||||
case ROFF_br:
|
||||
case ROFF_sp:
|
||||
case MDOC_Sm:
|
||||
case MDOC_Bl:
|
||||
case MDOC_D1:
|
||||
case MDOC_Dl:
|
||||
case MDOC_Lp:
|
||||
case MDOC_Pp:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (h->flags & HTML_NONEWLINE ||
|
||||
(nn->next && ! (nn->next->flags & NODE_LINE)))
|
||||
continue;
|
||||
else if (nn->next)
|
||||
print_text(h, "\n");
|
||||
|
||||
h->flags |= HTML_NOSPACE;
|
||||
}
|
||||
|
||||
if (0 == sv)
|
||||
h->flags &= ~HTML_LITERAL;
|
||||
|
||||
return 0;
|
||||
print_otag(h, TAG_DIV, "c", buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
mdoc_pa_pre(MDOC_ARGS)
|
||||
{
|
||||
print_otag(h, TAG_SPAN, "cT", "Pa");
|
||||
print_otag(h, TAG_SPAN, "c", "Pa");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -975,7 +1025,7 @@ mdoc_an_pre(MDOC_ARGS)
|
||||
if (n->sec == SEC_AUTHORS && ! (h->flags & HTML_NOSPLIT))
|
||||
h->flags |= HTML_SPLIT;
|
||||
|
||||
print_otag(h, TAG_SPAN, "cT", "An");
|
||||
print_otag(h, TAG_SPAN, "c", "An");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -983,7 +1033,7 @@ static int
|
||||
mdoc_cd_pre(MDOC_ARGS)
|
||||
{
|
||||
synopsis_pre(h, n);
|
||||
print_otag(h, TAG_CODE, "cT", "Cd");
|
||||
print_otag(h, TAG_CODE, "c", "Cd");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -994,7 +1044,7 @@ mdoc_dv_pre(MDOC_ARGS)
|
||||
|
||||
if ((id = cond_id(n)) != NULL)
|
||||
print_otag(h, TAG_A, "chR", "permalink", id);
|
||||
print_otag(h, TAG_CODE, "cTi", "Dv", id);
|
||||
print_otag(h, TAG_CODE, "ci", "Dv", id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1005,7 +1055,7 @@ mdoc_ev_pre(MDOC_ARGS)
|
||||
|
||||
if ((id = cond_id(n)) != NULL)
|
||||
print_otag(h, TAG_A, "chR", "permalink", id);
|
||||
print_otag(h, TAG_CODE, "cTi", "Ev", id);
|
||||
print_otag(h, TAG_CODE, "ci", "Ev", id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1022,7 +1072,7 @@ mdoc_er_pre(MDOC_ARGS)
|
||||
|
||||
if (id != NULL)
|
||||
print_otag(h, TAG_A, "chR", "permalink", id);
|
||||
print_otag(h, TAG_CODE, "cTi", "Er", id);
|
||||
print_otag(h, TAG_CODE, "ci", "Er", id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1033,12 +1083,12 @@ mdoc_fa_pre(MDOC_ARGS)
|
||||
struct tag *t;
|
||||
|
||||
if (n->parent->tok != MDOC_Fo) {
|
||||
print_otag(h, TAG_VAR, "cT", "Fa");
|
||||
print_otag(h, TAG_VAR, "c", "Fa");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (nn = n->child; nn; nn = nn->next) {
|
||||
t = print_otag(h, TAG_VAR, "cT", "Fa");
|
||||
t = print_otag(h, TAG_VAR, "c", "Fa");
|
||||
print_text(h, nn->string);
|
||||
print_tagq(h, t);
|
||||
if (nn->next) {
|
||||
@ -1069,11 +1119,11 @@ mdoc_fd_pre(MDOC_ARGS)
|
||||
assert(n->type == ROFFT_TEXT);
|
||||
|
||||
if (strcmp(n->string, "#include")) {
|
||||
print_otag(h, TAG_CODE, "cT", "Fd");
|
||||
print_otag(h, TAG_CODE, "c", "Fd");
|
||||
return 1;
|
||||
}
|
||||
|
||||
print_otag(h, TAG_CODE, "cT", "In");
|
||||
print_otag(h, TAG_CODE, "c", "In");
|
||||
print_text(h, n->string);
|
||||
|
||||
if (NULL != (n = n->next)) {
|
||||
@ -1087,10 +1137,10 @@ mdoc_fd_pre(MDOC_ARGS)
|
||||
cp = strchr(buf, '\0') - 1;
|
||||
if (cp >= buf && (*cp == '>' || *cp == '"'))
|
||||
*cp = '\0';
|
||||
t = print_otag(h, TAG_A, "cThI", "In", buf);
|
||||
t = print_otag(h, TAG_A, "chI", "In", buf);
|
||||
free(buf);
|
||||
} else
|
||||
t = print_otag(h, TAG_A, "cT", "In");
|
||||
t = print_otag(h, TAG_A, "c", "In");
|
||||
|
||||
print_text(h, n->string);
|
||||
print_tagq(h, t);
|
||||
@ -1117,7 +1167,7 @@ mdoc_vt_pre(MDOC_ARGS)
|
||||
} else if (n->type == ROFFT_HEAD)
|
||||
return 0;
|
||||
|
||||
print_otag(h, TAG_VAR, "cT", "Vt");
|
||||
print_otag(h, TAG_VAR, "c", "Vt");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1125,7 +1175,7 @@ static int
|
||||
mdoc_ft_pre(MDOC_ARGS)
|
||||
{
|
||||
synopsis_pre(h, n);
|
||||
print_otag(h, TAG_VAR, "cT", "Ft");
|
||||
print_otag(h, TAG_VAR, "c", "Ft");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1146,7 +1196,7 @@ mdoc_fn_pre(MDOC_ARGS)
|
||||
|
||||
ep = strchr(sp, ' ');
|
||||
if (NULL != ep) {
|
||||
t = print_otag(h, TAG_VAR, "cT", "Ft");
|
||||
t = print_otag(h, TAG_VAR, "c", "Ft");
|
||||
|
||||
while (ep) {
|
||||
sz = MIN((int)(ep - sp), BUFSIZ - 1);
|
||||
@ -1159,7 +1209,7 @@ mdoc_fn_pre(MDOC_ARGS)
|
||||
print_tagq(h, t);
|
||||
}
|
||||
|
||||
t = print_otag(h, TAG_CODE, "cT", "Fn");
|
||||
t = print_otag(h, TAG_CODE, "c", "Fn");
|
||||
|
||||
if (sp)
|
||||
print_text(h, sp);
|
||||
@ -1172,10 +1222,10 @@ mdoc_fn_pre(MDOC_ARGS)
|
||||
|
||||
for (n = n->child->next; n; n = n->next) {
|
||||
if (NODE_SYNPRETTY & n->flags)
|
||||
t = print_otag(h, TAG_VAR, "cTs", "Fa",
|
||||
t = print_otag(h, TAG_VAR, "cs", "Fa",
|
||||
"white-space", "nowrap");
|
||||
else
|
||||
t = print_otag(h, TAG_VAR, "cT", "Fa");
|
||||
t = print_otag(h, TAG_VAR, "c", "Fa");
|
||||
print_text(h, n->string);
|
||||
print_tagq(h, t);
|
||||
if (n->next) {
|
||||
@ -1222,8 +1272,10 @@ mdoc_skip_pre(MDOC_ARGS)
|
||||
static int
|
||||
mdoc_pp_pre(MDOC_ARGS)
|
||||
{
|
||||
|
||||
print_paragraph(h);
|
||||
if ((n->flags & NODE_NOFILL) == 0) {
|
||||
html_close_paragraph(h);
|
||||
print_otag(h, TAG_P, "c", "Pp");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1246,7 +1298,7 @@ mdoc_lk_pre(MDOC_ARGS)
|
||||
descr = link->next;
|
||||
if (descr == punct)
|
||||
descr = link; /* no text */
|
||||
t = print_otag(h, TAG_A, "cTh", "Lk", link->string);
|
||||
t = print_otag(h, TAG_A, "ch", "Lk", link->string);
|
||||
do {
|
||||
if (descr->flags & (NODE_DELIMC | NODE_DELIMO))
|
||||
h->flags |= HTML_NOSPACE;
|
||||
@ -1274,7 +1326,7 @@ mdoc_mt_pre(MDOC_ARGS)
|
||||
assert(n->type == ROFFT_TEXT);
|
||||
|
||||
mandoc_asprintf(&cp, "mailto:%s", n->string);
|
||||
t = print_otag(h, TAG_A, "cTh", "Mt", cp);
|
||||
t = print_otag(h, TAG_A, "ch", "Mt", cp);
|
||||
print_text(h, n->string);
|
||||
print_tagq(h, t);
|
||||
free(cp);
|
||||
@ -1302,7 +1354,7 @@ mdoc_fo_pre(MDOC_ARGS)
|
||||
return 0;
|
||||
|
||||
assert(n->child->string);
|
||||
t = print_otag(h, TAG_CODE, "cT", "Fn");
|
||||
t = print_otag(h, TAG_CODE, "c", "Fn");
|
||||
print_text(h, n->child->string);
|
||||
print_tagq(h, t);
|
||||
return 0;
|
||||
@ -1326,7 +1378,7 @@ mdoc_in_pre(MDOC_ARGS)
|
||||
struct tag *t;
|
||||
|
||||
synopsis_pre(h, n);
|
||||
print_otag(h, TAG_CODE, "cT", "In");
|
||||
print_otag(h, TAG_CODE, "c", "In");
|
||||
|
||||
/*
|
||||
* The first argument of the `In' gets special treatment as
|
||||
@ -1345,9 +1397,9 @@ mdoc_in_pre(MDOC_ARGS)
|
||||
assert(n->type == ROFFT_TEXT);
|
||||
|
||||
if (h->base_includes)
|
||||
t = print_otag(h, TAG_A, "cThI", "In", n->string);
|
||||
t = print_otag(h, TAG_A, "chI", "In", n->string);
|
||||
else
|
||||
t = print_otag(h, TAG_A, "cT", "In");
|
||||
t = print_otag(h, TAG_A, "c", "In");
|
||||
print_text(h, n->string);
|
||||
print_tagq(h, t);
|
||||
|
||||
@ -1372,14 +1424,14 @@ mdoc_ic_pre(MDOC_ARGS)
|
||||
|
||||
if ((id = cond_id(n)) != NULL)
|
||||
print_otag(h, TAG_A, "chR", "permalink", id);
|
||||
print_otag(h, TAG_CODE, "cTi", "Ic", id);
|
||||
print_otag(h, TAG_CODE, "ci", "Ic", id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
mdoc_va_pre(MDOC_ARGS)
|
||||
{
|
||||
print_otag(h, TAG_VAR, "cT", "Va");
|
||||
print_otag(h, TAG_VAR, "c", "Va");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1398,10 +1450,17 @@ mdoc_bf_pre(MDOC_ARGS)
|
||||
{
|
||||
const char *cattr;
|
||||
|
||||
if (n->type == ROFFT_HEAD)
|
||||
return 0;
|
||||
else if (n->type != ROFFT_BODY)
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
html_close_paragraph(h);
|
||||
return 1;
|
||||
case ROFFT_HEAD:
|
||||
return 0;
|
||||
case ROFFT_BODY:
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
if (FONT_Em == n->norm->Bf.font)
|
||||
cattr = "Bf Em";
|
||||
@ -1424,7 +1483,7 @@ mdoc_ms_pre(MDOC_ARGS)
|
||||
|
||||
if ((id = cond_id(n)) != NULL)
|
||||
print_otag(h, TAG_A, "chR", "permalink", id);
|
||||
print_otag(h, TAG_SPAN, "cTi", "Ms", id);
|
||||
print_otag(h, TAG_SPAN, "ci", "Ms", id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1447,13 +1506,21 @@ mdoc_pf_post(MDOC_ARGS)
|
||||
static int
|
||||
mdoc_rs_pre(MDOC_ARGS)
|
||||
{
|
||||
if (n->type != ROFFT_BLOCK)
|
||||
return 1;
|
||||
|
||||
if (n->prev && SEC_SEE_ALSO == n->sec)
|
||||
print_paragraph(h);
|
||||
|
||||
print_otag(h, TAG_CITE, "cT", "Rs");
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
if (n->sec == SEC_SEE_ALSO)
|
||||
html_close_paragraph(h);
|
||||
break;
|
||||
case ROFFT_HEAD:
|
||||
return 0;
|
||||
case ROFFT_BODY:
|
||||
if (n->sec == SEC_SEE_ALSO)
|
||||
print_otag(h, TAG_P, "c", "Pp");
|
||||
print_otag(h, TAG_CITE, "c", "Rs");
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1482,7 +1549,7 @@ mdoc_li_pre(MDOC_ARGS)
|
||||
static int
|
||||
mdoc_sy_pre(MDOC_ARGS)
|
||||
{
|
||||
print_otag(h, TAG_B, "cT", "Sy");
|
||||
print_otag(h, TAG_B, "c", "Sy");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1492,7 +1559,7 @@ mdoc_lb_pre(MDOC_ARGS)
|
||||
if (SEC_LIBRARY == n->sec && NODE_LINE & n->flags && n->prev)
|
||||
print_otag(h, TAG_BR, "");
|
||||
|
||||
print_otag(h, TAG_SPAN, "cT", "Lb");
|
||||
print_otag(h, TAG_SPAN, "c", "Lb");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1630,9 +1697,15 @@ mdoc_quote_pre(MDOC_ARGS)
|
||||
case MDOC_Oo:
|
||||
case MDOC_Op:
|
||||
print_text(h, "\\(lB");
|
||||
h->flags |= HTML_NOSPACE;
|
||||
/* Cannot use TAG_SPAN because it may contain blocks. */
|
||||
print_otag(h, TAG_IDIV, "c", "Op");
|
||||
/*
|
||||
* 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
|
||||
* phrasing context (like .Dl or .Pp); we cannot
|
||||
* close out a .Pp at this point either because
|
||||
* that would break the line.
|
||||
*/
|
||||
/* XXX print_otag(h, TAG_???, "c", "Op"); */
|
||||
break;
|
||||
case MDOC_En:
|
||||
if (NULL == n->norm->Es ||
|
||||
@ -1760,3 +1833,9 @@ mdoc_eo_post(MDOC_ARGS)
|
||||
else if ( ! tail)
|
||||
h->flags &= ~HTML_NOSPACE;
|
||||
}
|
||||
|
||||
static int
|
||||
mdoc_abort_pre(MDOC_ARGS)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
272
mdoc_macro.c
272
mdoc_macro.c
@ -1,7 +1,7 @@
|
||||
/* $Id: mdoc_macro.c,v 1.224 2017/05/30 16:22:03 schwarze Exp $ */
|
||||
/* $Id: mdoc_macro.c,v 1.232 2019/01/07 07:26:29 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2010, 2012-2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2010, 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
|
||||
@ -49,7 +49,7 @@ static void dword(struct roff_man *, int, int, const char *,
|
||||
static int find_pending(struct roff_man *, enum roff_tok,
|
||||
int, int, struct roff_node *);
|
||||
static int lookup(struct roff_man *, int, int, int, const char *);
|
||||
static int macro_or_word(MACRO_PROT_ARGS, int);
|
||||
static int macro_or_word(MACRO_PROT_ARGS, char *, int);
|
||||
static void break_intermediate(struct roff_node *,
|
||||
struct roff_node *);
|
||||
static int parse_rest(struct roff_man *, enum roff_tok,
|
||||
@ -60,7 +60,7 @@ static void rew_last(struct roff_man *, const struct roff_node *);
|
||||
static void rew_pending(struct roff_man *,
|
||||
const struct roff_node *);
|
||||
|
||||
const struct mdoc_macro __mdoc_macros[MDOC_MAX - MDOC_Dd] = {
|
||||
static const struct mdoc_macro mdoc_macros[MDOC_MAX - MDOC_Dd] = {
|
||||
{ in_line_eoln, MDOC_PROLOGUE }, /* Dd */
|
||||
{ in_line_eoln, MDOC_PROLOGUE }, /* Dt */
|
||||
{ in_line_eoln, MDOC_PROLOGUE }, /* Os */
|
||||
@ -201,9 +201,15 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX - MDOC_Dd] = {
|
||||
{ in_line_eoln, 0 }, /* %U */
|
||||
{ phrase_ta, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ta */
|
||||
};
|
||||
const struct mdoc_macro *const mdoc_macros = __mdoc_macros - MDOC_Dd;
|
||||
|
||||
|
||||
const struct mdoc_macro *
|
||||
mdoc_macro(enum roff_tok tok)
|
||||
{
|
||||
assert(tok >= MDOC_Dd && tok < MDOC_MAX);
|
||||
return mdoc_macros + (tok - MDOC_Dd);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called at the end of parsing. It must traverse up the tree,
|
||||
* closing out open [implicit] scopes. Obviously, open explicit scopes
|
||||
@ -221,14 +227,13 @@ mdoc_endparse(struct roff_man *mdoc)
|
||||
|
||||
for ( ; n; n = n->parent)
|
||||
if (n->type == ROFFT_BLOCK &&
|
||||
mdoc_macros[n->tok].flags & MDOC_EXPLICIT)
|
||||
mandoc_msg(MANDOCERR_BLK_NOEND, mdoc->parse,
|
||||
n->line, n->pos, roff_name[n->tok]);
|
||||
mdoc_macro(n->tok)->flags & MDOC_EXPLICIT)
|
||||
mandoc_msg(MANDOCERR_BLK_NOEND,
|
||||
n->line, n->pos, "%s", roff_name[n->tok]);
|
||||
|
||||
/* Rewind to the first. */
|
||||
|
||||
rew_last(mdoc, mdoc->first);
|
||||
mdoc_state_reset(mdoc);
|
||||
rew_last(mdoc, mdoc->meta.first);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -244,13 +249,12 @@ lookup(struct roff_man *mdoc, int from, int line, int ppos, const char *p)
|
||||
mdoc->flags &= ~MDOC_PHRASEQF;
|
||||
return TOKEN_NONE;
|
||||
}
|
||||
if (from == TOKEN_NONE || mdoc_macros[from].flags & MDOC_PARSED) {
|
||||
if (from == TOKEN_NONE || mdoc_macro(from)->flags & MDOC_PARSED) {
|
||||
res = roffhash_find(mdoc->mdocmac, p, 0);
|
||||
if (res != TOKEN_NONE) {
|
||||
if (mdoc_macros[res].flags & MDOC_CALLABLE)
|
||||
if (mdoc_macro(res)->flags & MDOC_CALLABLE)
|
||||
return res;
|
||||
mandoc_msg(MANDOCERR_MACRO_CALL,
|
||||
mdoc->parse, line, ppos, p);
|
||||
mandoc_msg(MANDOCERR_MACRO_CALL, line, ppos, "%s", p);
|
||||
}
|
||||
}
|
||||
return TOKEN_NONE;
|
||||
@ -291,6 +295,8 @@ rew_pending(struct roff_man *mdoc, const struct roff_node *n)
|
||||
case ROFFT_HEAD:
|
||||
roff_body_alloc(mdoc, n->line, n->pos,
|
||||
n->tok);
|
||||
if (n->tok == MDOC_Ss)
|
||||
mdoc->flags &= ~ROFF_NONOFILL;
|
||||
break;
|
||||
case ROFFT_BLOCK:
|
||||
break;
|
||||
@ -409,16 +415,15 @@ find_pending(struct roff_man *mdoc, enum roff_tok tok, int line, int ppos,
|
||||
if (n->flags & NODE_ENDED)
|
||||
continue;
|
||||
if (n->type == ROFFT_BLOCK &&
|
||||
mdoc_macros[n->tok].flags & MDOC_EXPLICIT) {
|
||||
mdoc_macro(n->tok)->flags & MDOC_EXPLICIT) {
|
||||
irc = 1;
|
||||
break_intermediate(mdoc->last, target);
|
||||
if (target->type == ROFFT_HEAD)
|
||||
target->flags |= NODE_ENDED;
|
||||
else if ( ! (target->flags & NODE_ENDED)) {
|
||||
mandoc_vmsg(MANDOCERR_BLK_NEST,
|
||||
mdoc->parse, line, ppos,
|
||||
"%s breaks %s", roff_name[tok],
|
||||
roff_name[n->tok]);
|
||||
mandoc_msg(MANDOCERR_BLK_NEST,
|
||||
line, ppos, "%s breaks %s",
|
||||
roff_name[tok], roff_name[n->tok]);
|
||||
mdoc_endbody_alloc(mdoc, line, ppos,
|
||||
tok, target);
|
||||
}
|
||||
@ -470,14 +475,15 @@ append_delims(struct roff_man *mdoc, int line, int *pos, char *buf)
|
||||
{
|
||||
char *p;
|
||||
int la;
|
||||
enum margserr ac;
|
||||
|
||||
if (buf[*pos] == '\0')
|
||||
return;
|
||||
|
||||
for (;;) {
|
||||
la = *pos;
|
||||
if (mdoc_args(mdoc, line, pos, buf, TOKEN_NONE, &p) ==
|
||||
ARGS_EOLN)
|
||||
ac = mdoc_args(mdoc, line, pos, buf, TOKEN_NONE, &p);
|
||||
if (ac == ARGS_EOLN)
|
||||
break;
|
||||
dword(mdoc, line, la, p, DELIM_MAX, 1);
|
||||
|
||||
@ -495,6 +501,8 @@ append_delims(struct roff_man *mdoc, int line, int *pos, char *buf)
|
||||
|
||||
if (mandoc_eos(p, strlen(p)))
|
||||
mdoc->last->flags |= NODE_EOS;
|
||||
if (ac == ARGS_ALLOC)
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
@ -504,27 +512,23 @@ append_delims(struct roff_man *mdoc, int line, int *pos, char *buf)
|
||||
* Otherwise, allocate it and return 0.
|
||||
*/
|
||||
static int
|
||||
macro_or_word(MACRO_PROT_ARGS, int parsed)
|
||||
macro_or_word(MACRO_PROT_ARGS, char *p, int parsed)
|
||||
{
|
||||
char *p;
|
||||
int ntok;
|
||||
|
||||
p = buf + ppos;
|
||||
ntok = TOKEN_NONE;
|
||||
if (*p == '"')
|
||||
p++;
|
||||
else if (parsed && ! (mdoc->flags & MDOC_PHRASELIT))
|
||||
ntok = lookup(mdoc, tok, line, ppos, p);
|
||||
ntok = buf[ppos] == '"' || parsed == 0 ||
|
||||
mdoc->flags & MDOC_PHRASELIT ? TOKEN_NONE :
|
||||
lookup(mdoc, tok, line, ppos, p);
|
||||
|
||||
if (ntok == TOKEN_NONE) {
|
||||
dword(mdoc, line, ppos, p, DELIM_MAX, tok == TOKEN_NONE ||
|
||||
mdoc_macros[tok].flags & MDOC_JOIN);
|
||||
mdoc_macro(tok)->flags & MDOC_JOIN);
|
||||
return 0;
|
||||
} else {
|
||||
if (tok != TOKEN_NONE &&
|
||||
mdoc_macros[tok].fp == in_line_eoln)
|
||||
mdoc_macro(tok)->fp == in_line_eoln)
|
||||
rew_elem(mdoc, tok);
|
||||
mdoc_macro(mdoc, ntok, line, ppos, pos, buf);
|
||||
(*mdoc_macro(ntok)->fp)(mdoc, ntok, line, ppos, pos, buf);
|
||||
if (tok == TOKEN_NONE)
|
||||
append_delims(mdoc, line, pos, buf);
|
||||
return 1;
|
||||
@ -629,7 +633,7 @@ blk_exp_close(MACRO_PROT_ARGS)
|
||||
* the scope - of the current block ends.
|
||||
*/
|
||||
|
||||
mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse,
|
||||
mandoc_msg(MANDOCERR_BLK_NEST,
|
||||
line, ppos, "%s breaks %s",
|
||||
roff_name[atok], roff_name[later->tok]);
|
||||
|
||||
@ -672,8 +676,8 @@ blk_exp_close(MACRO_PROT_ARGS)
|
||||
}
|
||||
|
||||
if (body == NULL) {
|
||||
mandoc_msg(MANDOCERR_BLK_NOTOPEN, mdoc->parse,
|
||||
line, ppos, roff_name[tok]);
|
||||
mandoc_msg(MANDOCERR_BLK_NOTOPEN, line, ppos,
|
||||
"%s", roff_name[tok]);
|
||||
if (maxargs && endbody == NULL) {
|
||||
/*
|
||||
* Stray .Ec without previous .Eo:
|
||||
@ -688,14 +692,25 @@ blk_exp_close(MACRO_PROT_ARGS)
|
||||
mdoc_tail_alloc(mdoc, line, ppos, atok);
|
||||
}
|
||||
|
||||
if ( ! (mdoc_macros[tok].flags & MDOC_PARSED)) {
|
||||
if ((mdoc_macro(tok)->flags & MDOC_PARSED) == 0) {
|
||||
if (buf[*pos] != '\0')
|
||||
mandoc_vmsg(MANDOCERR_ARG_SKIP,
|
||||
mdoc->parse, line, ppos,
|
||||
"%s %s", roff_name[tok],
|
||||
buf + *pos);
|
||||
mandoc_msg(MANDOCERR_ARG_SKIP, line, ppos,
|
||||
"%s %s", roff_name[tok], buf + *pos);
|
||||
if (endbody == NULL && n != NULL)
|
||||
rew_pending(mdoc, n);
|
||||
|
||||
/*
|
||||
* Restore the fill mode that was set before the display.
|
||||
* This needs to be done here rather than during validation
|
||||
* such that subsequent nodes get the right flags.
|
||||
*/
|
||||
|
||||
if (tok == MDOC_Ed && body != NULL) {
|
||||
if (body->flags & NODE_NOFILL)
|
||||
mdoc->flags |= ROFF_NOFILL;
|
||||
else
|
||||
mdoc->flags &= ~ROFF_NOFILL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -717,14 +732,18 @@ blk_exp_close(MACRO_PROT_ARGS)
|
||||
|
||||
if (ntok == TOKEN_NONE) {
|
||||
dword(mdoc, line, lastarg, p, DELIM_MAX,
|
||||
MDOC_JOIN & mdoc_macros[tok].flags);
|
||||
mdoc_macro(tok)->flags & MDOC_JOIN);
|
||||
if (ac == ARGS_ALLOC)
|
||||
free(p);
|
||||
continue;
|
||||
}
|
||||
if (ac == ARGS_ALLOC)
|
||||
free(p);
|
||||
|
||||
if (n != NULL)
|
||||
rew_last(mdoc, n);
|
||||
mdoc->flags &= ~MDOC_NEWLINE;
|
||||
mdoc_macro(mdoc, ntok, line, lastarg, pos, buf);
|
||||
(*mdoc_macro(ntok)->fp)(mdoc, ntok, line, lastarg, pos, buf);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -828,12 +847,14 @@ in_line(MACRO_PROT_ARGS)
|
||||
} else if ( ! nc && ! cnt) {
|
||||
mdoc_argv_free(arg);
|
||||
mandoc_msg(MANDOCERR_MACRO_EMPTY,
|
||||
mdoc->parse, line, ppos,
|
||||
roff_name[tok]);
|
||||
line, ppos, "%s", roff_name[tok]);
|
||||
}
|
||||
mdoc_macro(mdoc, ntok, line, la, pos, buf);
|
||||
(*mdoc_macro(ntok)->fp)(mdoc, ntok,
|
||||
line, la, pos, buf);
|
||||
if (nl)
|
||||
append_delims(mdoc, line, pos, buf);
|
||||
if (ac == ARGS_ALLOC)
|
||||
free(p);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -875,7 +896,10 @@ in_line(MACRO_PROT_ARGS)
|
||||
}
|
||||
|
||||
dword(mdoc, line, la, p, d,
|
||||
mdoc_macros[tok].flags & MDOC_JOIN);
|
||||
mdoc_macro(tok)->flags & MDOC_JOIN);
|
||||
|
||||
if (ac == ARGS_ALLOC)
|
||||
free(p);
|
||||
|
||||
/*
|
||||
* If the first argument is a closing delimiter,
|
||||
@ -914,8 +938,8 @@ in_line(MACRO_PROT_ARGS)
|
||||
rew_last(mdoc, mdoc->last);
|
||||
} else {
|
||||
mdoc_argv_free(arg);
|
||||
mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
|
||||
line, ppos, roff_name[tok]);
|
||||
mandoc_msg(MANDOCERR_MACRO_EMPTY,
|
||||
line, ppos, "%s", roff_name[tok]);
|
||||
}
|
||||
}
|
||||
if (nl)
|
||||
@ -927,24 +951,25 @@ in_line(MACRO_PROT_ARGS)
|
||||
static void
|
||||
blk_full(MACRO_PROT_ARGS)
|
||||
{
|
||||
int la, nl, parsed;
|
||||
struct mdoc_arg *arg;
|
||||
struct roff_node *blk; /* Our own or a broken block. */
|
||||
struct roff_node *head; /* Our own head. */
|
||||
struct roff_node *body; /* Our own body. */
|
||||
struct roff_node *n;
|
||||
enum margserr ac, lac;
|
||||
char *p;
|
||||
size_t iarg;
|
||||
int done, la, nl, parsed;
|
||||
enum margserr ac, lac;
|
||||
|
||||
nl = MDOC_NEWLINE & mdoc->flags;
|
||||
|
||||
if (buf[*pos] == '\0' && (tok == MDOC_Sh || tok == MDOC_Ss)) {
|
||||
mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
|
||||
line, ppos, roff_name[tok]);
|
||||
mandoc_msg(MANDOCERR_MACRO_EMPTY,
|
||||
line, ppos, "%s", roff_name[tok]);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! (mdoc_macros[tok].flags & MDOC_EXPLICIT)) {
|
||||
if ((mdoc_macro(tok)->flags & MDOC_EXPLICIT) == 0) {
|
||||
|
||||
/* Here, tok is one of Sh Ss Nm Nd It. */
|
||||
|
||||
@ -960,21 +985,20 @@ blk_full(MACRO_PROT_ARGS)
|
||||
|
||||
if (tok == MDOC_It && n->tok == MDOC_Bl) {
|
||||
if (blk != NULL) {
|
||||
mandoc_vmsg(MANDOCERR_BLK_BROKEN,
|
||||
mdoc->parse, line, ppos,
|
||||
"It breaks %s",
|
||||
mandoc_msg(MANDOCERR_BLK_BROKEN,
|
||||
line, ppos, "It breaks %s",
|
||||
roff_name[blk->tok]);
|
||||
rew_pending(mdoc, blk);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (mdoc_macros[n->tok].flags & MDOC_EXPLICIT) {
|
||||
if (mdoc_macro(n->tok)->flags & MDOC_EXPLICIT) {
|
||||
switch (tok) {
|
||||
case MDOC_Sh:
|
||||
case MDOC_Ss:
|
||||
mandoc_vmsg(MANDOCERR_BLK_BROKEN,
|
||||
mdoc->parse, line, ppos,
|
||||
mandoc_msg(MANDOCERR_BLK_BROKEN,
|
||||
line, ppos,
|
||||
"%s breaks %s", roff_name[tok],
|
||||
roff_name[n->tok]);
|
||||
rew_pending(mdoc, n);
|
||||
@ -1000,8 +1024,7 @@ blk_full(MACRO_PROT_ARGS)
|
||||
/* Item breaking an explicit block. */
|
||||
|
||||
if (blk != NULL) {
|
||||
mandoc_vmsg(MANDOCERR_BLK_BROKEN,
|
||||
mdoc->parse, line, ppos,
|
||||
mandoc_msg(MANDOCERR_BLK_BROKEN, line, ppos,
|
||||
"It breaks %s", roff_name[blk->tok]);
|
||||
rew_pending(mdoc, blk);
|
||||
blk = NULL;
|
||||
@ -1015,7 +1038,7 @@ blk_full(MACRO_PROT_ARGS)
|
||||
/* Skip items outside lists. */
|
||||
|
||||
if (tok == MDOC_It && (n == NULL || n->tok != MDOC_Bl)) {
|
||||
mandoc_vmsg(MANDOCERR_IT_STRAY, mdoc->parse,
|
||||
mandoc_msg(MANDOCERR_IT_STRAY,
|
||||
line, ppos, "It %s", buf + *pos);
|
||||
roff_elem_alloc(mdoc, line, ppos, ROFF_br);
|
||||
rew_elem(mdoc, ROFF_br);
|
||||
@ -1032,6 +1055,16 @@ blk_full(MACRO_PROT_ARGS)
|
||||
* regular child nodes.
|
||||
*/
|
||||
|
||||
switch (tok) {
|
||||
case MDOC_Sh:
|
||||
mdoc->flags &= ~ROFF_NOFILL;
|
||||
break;
|
||||
case MDOC_Ss:
|
||||
mdoc->flags |= ROFF_NONOFILL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
mdoc_argv(mdoc, line, tok, &arg, pos, buf);
|
||||
blk = mdoc_block_alloc(mdoc, line, ppos, tok, arg);
|
||||
head = body = NULL;
|
||||
@ -1093,14 +1126,17 @@ blk_full(MACRO_PROT_ARGS)
|
||||
}
|
||||
|
||||
if (tok == MDOC_Bd || tok == MDOC_Bk) {
|
||||
mandoc_vmsg(MANDOCERR_ARG_EXCESS,
|
||||
mdoc->parse, line, la, "%s ... %s",
|
||||
roff_name[tok], buf + la);
|
||||
mandoc_msg(MANDOCERR_ARG_EXCESS, line, la,
|
||||
"%s ... %s", roff_name[tok], buf + la);
|
||||
if (ac == ARGS_ALLOC)
|
||||
free(p);
|
||||
break;
|
||||
}
|
||||
if (tok == MDOC_Rs) {
|
||||
mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse,
|
||||
mandoc_msg(MANDOCERR_ARG_SKIP,
|
||||
line, la, "Rs %s", buf + la);
|
||||
if (ac == ARGS_ALLOC)
|
||||
free(p);
|
||||
break;
|
||||
}
|
||||
if (ac == ARGS_PUNCT)
|
||||
@ -1115,6 +1151,8 @@ blk_full(MACRO_PROT_ARGS)
|
||||
ac != ARGS_PHRASE &&
|
||||
mdoc_isdelim(p) == DELIM_OPEN) {
|
||||
dword(mdoc, line, la, p, DELIM_OPEN, 0);
|
||||
if (ac == ARGS_ALLOC)
|
||||
free(p);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1146,7 +1184,10 @@ blk_full(MACRO_PROT_ARGS)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (macro_or_word(mdoc, tok, line, la, pos, buf, parsed))
|
||||
done = macro_or_word(mdoc, tok, line, la, pos, buf, p, parsed);
|
||||
if (ac == ARGS_ALLOC)
|
||||
free(p);
|
||||
if (done)
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1165,6 +1206,33 @@ blk_full(MACRO_PROT_ARGS)
|
||||
|
||||
rew_last(mdoc, head);
|
||||
body = roff_body_alloc(mdoc, line, ppos, tok);
|
||||
if (tok == MDOC_Ss)
|
||||
mdoc->flags &= ~ROFF_NONOFILL;
|
||||
|
||||
/*
|
||||
* Set up fill mode for display blocks.
|
||||
* This needs to be done here up front rather than during
|
||||
* validation such that child nodes get the right flags.
|
||||
*/
|
||||
|
||||
if (tok == MDOC_Bd && arg != NULL) {
|
||||
for (iarg = 0; iarg < arg->argc; iarg++) {
|
||||
switch (arg->argv[iarg].arg) {
|
||||
case MDOC_Unfilled:
|
||||
case MDOC_Literal:
|
||||
mdoc->flags |= ROFF_NOFILL;
|
||||
break;
|
||||
case MDOC_Filled:
|
||||
case MDOC_Ragged:
|
||||
case MDOC_Centred:
|
||||
mdoc->flags &= ~ROFF_NOFILL;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (mdoc->flags & MDOC_FREECOL) {
|
||||
rew_last(mdoc, body);
|
||||
@ -1176,7 +1244,7 @@ blk_full(MACRO_PROT_ARGS)
|
||||
static void
|
||||
blk_part_imp(MACRO_PROT_ARGS)
|
||||
{
|
||||
int la, nl;
|
||||
int done, la, nl;
|
||||
enum margserr ac;
|
||||
char *p;
|
||||
struct roff_node *blk; /* saved block context */
|
||||
@ -1211,13 +1279,18 @@ blk_part_imp(MACRO_PROT_ARGS)
|
||||
|
||||
if (body == NULL && mdoc_isdelim(p) == DELIM_OPEN) {
|
||||
dword(mdoc, line, la, p, DELIM_OPEN, 0);
|
||||
if (ac == ARGS_ALLOC)
|
||||
free(p);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (body == NULL)
|
||||
body = roff_body_alloc(mdoc, line, ppos, tok);
|
||||
|
||||
if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
|
||||
done = macro_or_word(mdoc, tok, line, la, pos, buf, p, 1);
|
||||
if (ac == ARGS_ALLOC)
|
||||
free(p);
|
||||
if (done)
|
||||
break;
|
||||
}
|
||||
if (body == NULL)
|
||||
@ -1236,13 +1309,13 @@ blk_part_imp(MACRO_PROT_ARGS)
|
||||
for (n = body->child; n && n->next; n = n->next)
|
||||
/* Do nothing. */ ;
|
||||
if (n && n->tok == MDOC_Ns)
|
||||
mdoc_node_relink(mdoc, n);
|
||||
roff_node_relink(mdoc, n);
|
||||
}
|
||||
|
||||
static void
|
||||
blk_part_exp(MACRO_PROT_ARGS)
|
||||
{
|
||||
int la, nl;
|
||||
int done, la, nl;
|
||||
enum margserr ac;
|
||||
struct roff_node *head; /* keep track of head */
|
||||
char *p;
|
||||
@ -1267,6 +1340,8 @@ blk_part_exp(MACRO_PROT_ARGS)
|
||||
|
||||
if (head == NULL && mdoc_isdelim(p) == DELIM_OPEN) {
|
||||
dword(mdoc, line, la, p, DELIM_OPEN, 0);
|
||||
if (ac == ARGS_ALLOC)
|
||||
free(p);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1276,11 +1351,17 @@ blk_part_exp(MACRO_PROT_ARGS)
|
||||
dword(mdoc, line, la, p, DELIM_MAX, 0);
|
||||
rew_last(mdoc, head);
|
||||
roff_body_alloc(mdoc, line, ppos, tok);
|
||||
if (tok == MDOC_Eo)
|
||||
if (tok == MDOC_Eo) {
|
||||
if (ac == ARGS_ALLOC)
|
||||
free(p);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
|
||||
done = macro_or_word(mdoc, tok, line, la, pos, buf, p, 1);
|
||||
if (ac == ARGS_ALLOC)
|
||||
free(p);
|
||||
if (done)
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1338,10 +1419,12 @@ in_line_argn(MACRO_PROT_ARGS)
|
||||
la = *pos;
|
||||
ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
|
||||
|
||||
if (ac == ARGS_WORD && state == -1 &&
|
||||
! (mdoc_macros[tok].flags & MDOC_IGNDELIM) &&
|
||||
if ((ac == ARGS_WORD || ac == ARGS_ALLOC) && state == -1 &&
|
||||
(mdoc_macro(tok)->flags & MDOC_IGNDELIM) == 0 &&
|
||||
mdoc_isdelim(p) == DELIM_OPEN) {
|
||||
dword(mdoc, line, la, p, DELIM_OPEN, 0);
|
||||
if (ac == ARGS_ALLOC)
|
||||
free(p);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1353,8 +1436,8 @@ in_line_argn(MACRO_PROT_ARGS)
|
||||
|
||||
if (ac == ARGS_PUNCT || ac == ARGS_EOLN) {
|
||||
if (abs(state) < 2 && tok == MDOC_Pf)
|
||||
mandoc_vmsg(MANDOCERR_PF_SKIP,
|
||||
mdoc->parse, line, ppos, "Pf %s",
|
||||
mandoc_msg(MANDOCERR_PF_SKIP,
|
||||
line, ppos, "Pf %s",
|
||||
p == NULL ? "at eol" : p);
|
||||
break;
|
||||
}
|
||||
@ -1372,11 +1455,14 @@ in_line_argn(MACRO_PROT_ARGS)
|
||||
rew_elem(mdoc, tok);
|
||||
state = -2;
|
||||
}
|
||||
mdoc_macro(mdoc, ntok, line, la, pos, buf);
|
||||
(*mdoc_macro(ntok)->fp)(mdoc, ntok,
|
||||
line, la, pos, buf);
|
||||
if (ac == ARGS_ALLOC)
|
||||
free(p);
|
||||
break;
|
||||
}
|
||||
|
||||
if (mdoc_macros[tok].flags & MDOC_IGNDELIM ||
|
||||
if (mdoc_macro(tok)->flags & MDOC_IGNDELIM ||
|
||||
mdoc_isdelim(p) == DELIM_NONE) {
|
||||
if (state == -1) {
|
||||
mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
|
||||
@ -1389,12 +1475,15 @@ in_line_argn(MACRO_PROT_ARGS)
|
||||
}
|
||||
|
||||
dword(mdoc, line, la, p, DELIM_MAX,
|
||||
mdoc_macros[tok].flags & MDOC_JOIN);
|
||||
mdoc_macro(tok)->flags & MDOC_JOIN);
|
||||
if (ac == ARGS_ALLOC)
|
||||
free(p);
|
||||
p = mdoc->last->string;
|
||||
}
|
||||
|
||||
if (state == -1) {
|
||||
mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
|
||||
line, ppos, roff_name[tok]);
|
||||
mandoc_msg(MANDOCERR_MACRO_EMPTY,
|
||||
line, ppos, "%s", roff_name[tok]);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1423,8 +1512,8 @@ in_line_eoln(MACRO_PROT_ARGS)
|
||||
|
||||
if (buf[*pos] == '\0' &&
|
||||
(tok == MDOC_Fd || *roff_name[tok] == '%')) {
|
||||
mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
|
||||
line, ppos, roff_name[tok]);
|
||||
mandoc_msg(MANDOCERR_MACRO_EMPTY,
|
||||
line, ppos, "%s", roff_name[tok]);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1444,13 +1533,19 @@ static int
|
||||
parse_rest(struct roff_man *mdoc, enum roff_tok tok,
|
||||
int line, int *pos, char *buf)
|
||||
{
|
||||
int la;
|
||||
char *p;
|
||||
int done, la;
|
||||
enum margserr ac;
|
||||
|
||||
for (;;) {
|
||||
la = *pos;
|
||||
if (mdoc_args(mdoc, line, pos, buf, tok, NULL) == ARGS_EOLN)
|
||||
ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
|
||||
if (ac == ARGS_EOLN)
|
||||
return 0;
|
||||
if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
|
||||
done = macro_or_word(mdoc, tok, line, la, pos, buf, p, 1);
|
||||
if (ac == ARGS_ALLOC)
|
||||
free(p);
|
||||
if (done)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -1492,8 +1587,7 @@ phrase_ta(MACRO_PROT_ARGS)
|
||||
}
|
||||
|
||||
if (n == NULL || n->norm->Bl.type != LIST_column) {
|
||||
mandoc_msg(MANDOCERR_TA_STRAY, mdoc->parse,
|
||||
line, ppos, "Ta");
|
||||
mandoc_msg(MANDOCERR_TA_STRAY, line, ppos, "Ta");
|
||||
return;
|
||||
}
|
||||
|
||||
|
111
mdoc_man.c
111
mdoc_man.c
@ -1,6 +1,6 @@
|
||||
/* $Id: mdoc_man.c,v 1.126 2018/04/11 17:11:13 schwarze Exp $ */
|
||||
/* $Id: mdoc_man.c,v 1.132 2019/01/04 03:17:36 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011-2018 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2011-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
|
||||
@ -36,7 +36,7 @@
|
||||
typedef int (*int_fp)(DECL_ARGS);
|
||||
typedef void (*void_fp)(DECL_ARGS);
|
||||
|
||||
struct manact {
|
||||
struct mdoc_man_act {
|
||||
int_fp cond; /* DON'T run actions */
|
||||
int_fp pre; /* pre-node action */
|
||||
void_fp post; /* post-node action */
|
||||
@ -75,6 +75,7 @@ static void post_pf(DECL_ARGS);
|
||||
static void post_sect(DECL_ARGS);
|
||||
static void post_vt(DECL_ARGS);
|
||||
static int pre__t(DECL_ARGS);
|
||||
static int pre_abort(DECL_ARGS);
|
||||
static int pre_an(DECL_ARGS);
|
||||
static int pre_ap(DECL_ARGS);
|
||||
static int pre_aq(DECL_ARGS);
|
||||
@ -103,6 +104,7 @@ static int pre_lk(DECL_ARGS);
|
||||
static int pre_li(DECL_ARGS);
|
||||
static int pre_nm(DECL_ARGS);
|
||||
static int pre_no(DECL_ARGS);
|
||||
static void pre_noarg(DECL_ARGS);
|
||||
static int pre_ns(DECL_ARGS);
|
||||
static void pre_onearg(DECL_ARGS);
|
||||
static int pre_pp(DECL_ARGS);
|
||||
@ -124,12 +126,14 @@ static void print_width(const struct mdoc_bl *,
|
||||
static void print_count(int *);
|
||||
static void print_node(DECL_ARGS);
|
||||
|
||||
static const void_fp roff_manacts[ROFF_MAX] = {
|
||||
static const void_fp roff_man_acts[ROFF_MAX] = {
|
||||
pre_br, /* br */
|
||||
pre_onearg, /* ce */
|
||||
pre_noarg, /* fi */
|
||||
pre_ft, /* ft */
|
||||
pre_onearg, /* ll */
|
||||
pre_onearg, /* mc */
|
||||
pre_noarg, /* nf */
|
||||
pre_onearg, /* po */
|
||||
pre_onearg, /* rj */
|
||||
pre_sp, /* sp */
|
||||
@ -137,7 +141,7 @@ static const void_fp roff_manacts[ROFF_MAX] = {
|
||||
pre_onearg, /* ti */
|
||||
};
|
||||
|
||||
static const struct manact __manacts[MDOC_MAX - MDOC_Dd] = {
|
||||
static const struct mdoc_man_act mdoc_man_acts[MDOC_MAX - MDOC_Dd] = {
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Dd */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Dt */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Os */
|
||||
@ -172,7 +176,7 @@ static const struct manact __manacts[MDOC_MAX - MDOC_Dd] = {
|
||||
{ cond_head, pre_enc, NULL, "\\- ", NULL }, /* Nd */
|
||||
{ NULL, pre_nm, post_nm, NULL, NULL }, /* Nm */
|
||||
{ cond_body, pre_enc, post_enc, "[", "]" }, /* Op */
|
||||
{ NULL, pre_Ft, post_font, NULL, NULL }, /* Ot */
|
||||
{ NULL, pre_abort, NULL, NULL, NULL }, /* Ot */
|
||||
{ NULL, pre_em, post_font, NULL, NULL }, /* Pa */
|
||||
{ NULL, pre_ex, NULL, NULL, NULL }, /* Rv */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* St */
|
||||
@ -245,7 +249,7 @@ static const struct manact __manacts[MDOC_MAX - MDOC_Dd] = {
|
||||
{ NULL, pre_em, post_font, NULL, NULL }, /* Fr */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Ud */
|
||||
{ NULL, NULL, post_lb, NULL, NULL }, /* Lb */
|
||||
{ NULL, pre_pp, NULL, NULL, NULL }, /* Lp */
|
||||
{ NULL, pre_abort, NULL, NULL, NULL }, /* Lp */
|
||||
{ NULL, pre_lk, NULL, NULL, NULL }, /* Lk */
|
||||
{ NULL, pre_em, post_font, NULL, NULL }, /* Mt */
|
||||
{ cond_body, pre_enc, post_enc, "{", "}" }, /* Brq */
|
||||
@ -259,7 +263,7 @@ static const struct manact __manacts[MDOC_MAX - MDOC_Dd] = {
|
||||
{ NULL, NULL, post_percent, NULL, NULL }, /* %U */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Ta */
|
||||
};
|
||||
static const struct manact *const manacts = __manacts - MDOC_Dd;
|
||||
static const struct mdoc_man_act *mdoc_man_act(enum roff_tok);
|
||||
|
||||
static int outflags;
|
||||
#define MMAN_spc (1 << 0) /* blank character before next word */
|
||||
@ -290,6 +294,13 @@ static struct {
|
||||
} fontqueue;
|
||||
|
||||
|
||||
static const struct mdoc_man_act *
|
||||
mdoc_man_act(enum roff_tok tok)
|
||||
{
|
||||
assert(tok >= MDOC_Dd && tok <= MDOC_MAX);
|
||||
return mdoc_man_acts + (tok - MDOC_Dd);
|
||||
}
|
||||
|
||||
static int
|
||||
man_strlen(const char *cp)
|
||||
{
|
||||
@ -317,6 +328,7 @@ man_strlen(const char *cp)
|
||||
case ESCAPE_UNICODE:
|
||||
case ESCAPE_NUMBERED:
|
||||
case ESCAPE_SPECIAL:
|
||||
case ESCAPE_UNDEF:
|
||||
case ESCAPE_OVERSTRIKE:
|
||||
if (skip)
|
||||
skip = 0;
|
||||
@ -593,20 +605,7 @@ print_count(int *count)
|
||||
}
|
||||
|
||||
void
|
||||
man_man(void *arg, const struct roff_man *man)
|
||||
{
|
||||
|
||||
/*
|
||||
* Dump the keep buffer.
|
||||
* We're guaranteed by now that this exists (is non-NULL).
|
||||
* Flush stdout afterward, just in case.
|
||||
*/
|
||||
fputs(mparse_getkeep(man_mparse(man)), stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void
|
||||
man_mdoc(void *arg, const struct roff_man *mdoc)
|
||||
man_mdoc(void *arg, const struct roff_meta *mdoc)
|
||||
{
|
||||
struct roff_node *n;
|
||||
|
||||
@ -619,9 +618,8 @@ man_mdoc(void *arg, const struct roff_man *mdoc)
|
||||
}
|
||||
|
||||
printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",
|
||||
mdoc->meta.title,
|
||||
(mdoc->meta.msec == NULL ? "" : mdoc->meta.msec),
|
||||
mdoc->meta.date, mdoc->meta.os, mdoc->meta.vol);
|
||||
mdoc->title, (mdoc->msec == NULL ? "" : mdoc->msec),
|
||||
mdoc->date, mdoc->os, mdoc->vol);
|
||||
|
||||
/* Disable hyphenation and if nroff, disable justification. */
|
||||
printf(".nh\n.if n .ad l");
|
||||
@ -633,16 +631,16 @@ man_mdoc(void *arg, const struct roff_man *mdoc)
|
||||
*fontqueue.tail = 'R';
|
||||
}
|
||||
for (; n != NULL; n = n->next)
|
||||
print_node(&mdoc->meta, n);
|
||||
print_node(mdoc, n);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
static void
|
||||
print_node(DECL_ARGS)
|
||||
{
|
||||
const struct manact *act;
|
||||
struct roff_node *sub;
|
||||
int cond, do_sub;
|
||||
const struct mdoc_man_act *act;
|
||||
struct roff_node *sub;
|
||||
int cond, do_sub;
|
||||
|
||||
if (n->flags & NODE_NOPRT)
|
||||
return;
|
||||
@ -680,15 +678,14 @@ print_node(DECL_ARGS)
|
||||
else if (outflags & MMAN_Sm)
|
||||
outflags |= MMAN_spc;
|
||||
} else if (n->tok < ROFF_MAX) {
|
||||
(*roff_manacts[n->tok])(meta, n);
|
||||
(*roff_man_acts[n->tok])(meta, n);
|
||||
return;
|
||||
} else {
|
||||
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
|
||||
/*
|
||||
* Conditionally run the pre-node action handler for a
|
||||
* node.
|
||||
*/
|
||||
act = manacts + n->tok;
|
||||
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))
|
||||
@ -731,12 +728,18 @@ cond_body(DECL_ARGS)
|
||||
return n->type == ROFFT_BODY;
|
||||
}
|
||||
|
||||
static int
|
||||
pre_abort(DECL_ARGS)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
static int
|
||||
pre_enc(DECL_ARGS)
|
||||
{
|
||||
const char *prefix;
|
||||
|
||||
prefix = manacts[n->tok].prefix;
|
||||
prefix = mdoc_man_act(n->tok)->prefix;
|
||||
if (NULL == prefix)
|
||||
return 1;
|
||||
print_word(prefix);
|
||||
@ -749,7 +752,7 @@ post_enc(DECL_ARGS)
|
||||
{
|
||||
const char *suffix;
|
||||
|
||||
suffix = manacts[n->tok].suffix;
|
||||
suffix = mdoc_man_act(n->tok)->suffix;
|
||||
if (NULL == suffix)
|
||||
return;
|
||||
outflags &= ~(MMAN_spc | MMAN_nl);
|
||||
@ -774,7 +777,7 @@ static void
|
||||
post_percent(DECL_ARGS)
|
||||
{
|
||||
|
||||
if (pre_em == manacts[n->tok].pre)
|
||||
if (mdoc_man_act(n->tok)->pre == pre_em)
|
||||
font_pop();
|
||||
if (n->next) {
|
||||
print_word(",");
|
||||
@ -820,7 +823,7 @@ pre_sect(DECL_ARGS)
|
||||
|
||||
if (n->type == ROFFT_HEAD) {
|
||||
outflags |= MMAN_sp;
|
||||
print_block(manacts[n->tok].prefix, 0);
|
||||
print_block(mdoc_man_act(n->tok)->prefix, 0);
|
||||
print_word("");
|
||||
putchar('\"');
|
||||
outflags &= ~MMAN_spc;
|
||||
@ -936,7 +939,6 @@ post_aq(DECL_ARGS)
|
||||
static int
|
||||
pre_bd(DECL_ARGS)
|
||||
{
|
||||
|
||||
outflags &= ~(MMAN_PP | MMAN_sp | MMAN_br);
|
||||
|
||||
if (DISP_unfilled == n->norm->Bd.type ||
|
||||
@ -951,12 +953,27 @@ pre_bd(DECL_ARGS)
|
||||
static void
|
||||
post_bd(DECL_ARGS)
|
||||
{
|
||||
enum roff_tok bef, now;
|
||||
|
||||
/* Close out this display. */
|
||||
print_line(".RE", MMAN_nl);
|
||||
if (DISP_unfilled == n->norm->Bd.type ||
|
||||
DISP_literal == n->norm->Bd.type)
|
||||
print_line(".fi", MMAN_nl);
|
||||
bef = n->flags & NODE_NOFILL ? ROFF_nf : ROFF_fi;
|
||||
if (n->last == NULL)
|
||||
now = n->norm->Bd.type == DISP_unfilled ||
|
||||
n->norm->Bd.type == DISP_literal ? ROFF_nf : ROFF_fi;
|
||||
else if (n->last->tok == ROFF_nf)
|
||||
now = ROFF_nf;
|
||||
else if (n->last->tok == ROFF_fi)
|
||||
now = ROFF_fi;
|
||||
else
|
||||
now = n->last->flags & NODE_NOFILL ? ROFF_nf : ROFF_fi;
|
||||
if (bef != now) {
|
||||
outflags |= MMAN_nl;
|
||||
print_word(".");
|
||||
outflags &= ~MMAN_spc;
|
||||
print_word(roff_name[bef]);
|
||||
outflags |= MMAN_nl;
|
||||
}
|
||||
|
||||
/* Maybe we are inside an enclosing list? */
|
||||
if (NULL != n->parent->next)
|
||||
@ -1607,7 +1624,6 @@ pre_onearg(DECL_ARGS)
|
||||
static int
|
||||
pre_li(DECL_ARGS)
|
||||
{
|
||||
|
||||
font_push('R');
|
||||
return 1;
|
||||
}
|
||||
@ -1640,7 +1656,6 @@ pre_nm(DECL_ARGS)
|
||||
static void
|
||||
post_nm(DECL_ARGS)
|
||||
{
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_BLOCK:
|
||||
outflags &= ~MMAN_Bk;
|
||||
@ -1658,15 +1673,23 @@ post_nm(DECL_ARGS)
|
||||
static int
|
||||
pre_no(DECL_ARGS)
|
||||
{
|
||||
|
||||
outflags |= MMAN_spc_force;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
pre_noarg(DECL_ARGS)
|
||||
{
|
||||
outflags |= MMAN_nl;
|
||||
print_word(".");
|
||||
outflags &= ~MMAN_spc;
|
||||
print_word(roff_name[n->tok]);
|
||||
outflags |= MMAN_nl;
|
||||
}
|
||||
|
||||
static int
|
||||
pre_ns(DECL_ARGS)
|
||||
{
|
||||
|
||||
outflags &= ~MMAN_spc;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* $Id: mdoc_markdown.c,v 1.24 2018/04/11 17:11:13 schwarze Exp $ */
|
||||
/* $Id: mdoc_markdown.c,v 1.30 2018/12/30 00:49:55 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 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
|
||||
@ -19,6 +19,7 @@
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc_aux.h"
|
||||
@ -48,6 +49,7 @@ static void md_uri(const char *);
|
||||
static int md_cond_head(struct roff_node *);
|
||||
static int md_cond_body(struct roff_node *);
|
||||
|
||||
static int md_pre_abort(struct roff_node *);
|
||||
static int md_pre_raw(struct roff_node *);
|
||||
static int md_pre_word(struct roff_node *);
|
||||
static int md_pre_skip(struct roff_node *);
|
||||
@ -103,7 +105,7 @@ static void md_post_Pf(struct roff_node *);
|
||||
static void md_post_Vt(struct roff_node *);
|
||||
static void md_post__T(struct roff_node *);
|
||||
|
||||
static const struct md_act __md_acts[MDOC_MAX - MDOC_Dd] = {
|
||||
static const struct md_act md_acts[MDOC_MAX - MDOC_Dd] = {
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Dd */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Dt */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Os */
|
||||
@ -138,7 +140,7 @@ static const struct md_act __md_acts[MDOC_MAX - MDOC_Dd] = {
|
||||
{ md_cond_head, md_pre_Nd, NULL, NULL, NULL }, /* Nd */
|
||||
{ NULL, md_pre_Nm, md_post_Nm, "**", "**" }, /* Nm */
|
||||
{ md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Op */
|
||||
{ NULL, md_pre_Fd, md_post_raw, "*", "*" }, /* Ot */
|
||||
{ NULL, md_pre_abort, NULL, NULL, NULL }, /* Ot */
|
||||
{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Pa */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Rv */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* St */
|
||||
@ -211,7 +213,7 @@ static const struct md_act __md_acts[MDOC_MAX - MDOC_Dd] = {
|
||||
{ NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Fr */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Ud */
|
||||
{ NULL, NULL, md_post_Lb, NULL, NULL }, /* Lb */
|
||||
{ NULL, md_pre_Pp, NULL, NULL, NULL }, /* Lp */
|
||||
{ NULL, md_pre_abort, NULL, NULL, NULL }, /* Lp */
|
||||
{ NULL, md_pre_Lk, NULL, NULL, NULL }, /* Lk */
|
||||
{ NULL, md_pre_Mt, NULL, NULL, NULL }, /* Mt */
|
||||
{ md_cond_body, md_pre_word, md_post_word, "{", "}" }, /* Brq */
|
||||
@ -225,7 +227,7 @@ static const struct md_act __md_acts[MDOC_MAX - MDOC_Dd] = {
|
||||
{ NULL, md_pre_Lk, md_post_pc, NULL, NULL }, /* %U */
|
||||
{ NULL, NULL, NULL, NULL, NULL }, /* Ta */
|
||||
};
|
||||
static const struct md_act *const md_acts = __md_acts - MDOC_Dd;
|
||||
static const struct md_act *md_act(enum roff_tok);
|
||||
|
||||
static int outflags;
|
||||
#define MD_spc (1 << 0) /* Blank character before next word. */
|
||||
@ -250,22 +252,30 @@ static int escflags; /* Escape in generated markdown code: */
|
||||
static int code_blocks, quote_blocks, list_blocks;
|
||||
static int outcount;
|
||||
|
||||
|
||||
static const struct md_act *
|
||||
md_act(enum roff_tok tok)
|
||||
{
|
||||
assert(tok >= MDOC_Dd && tok <= MDOC_MAX);
|
||||
return md_acts + (tok - MDOC_Dd);
|
||||
}
|
||||
|
||||
void
|
||||
markdown_mdoc(void *arg, const struct roff_man *mdoc)
|
||||
markdown_mdoc(void *arg, const struct roff_meta *mdoc)
|
||||
{
|
||||
outflags = MD_Sm;
|
||||
md_word(mdoc->meta.title);
|
||||
if (mdoc->meta.msec != NULL) {
|
||||
md_word(mdoc->title);
|
||||
if (mdoc->msec != NULL) {
|
||||
outflags &= ~MD_spc;
|
||||
md_word("(");
|
||||
md_word(mdoc->meta.msec);
|
||||
md_word(mdoc->msec);
|
||||
md_word(")");
|
||||
}
|
||||
md_word("-");
|
||||
md_word(mdoc->meta.vol);
|
||||
if (mdoc->meta.arch != NULL) {
|
||||
md_word(mdoc->vol);
|
||||
if (mdoc->arch != NULL) {
|
||||
md_word("(");
|
||||
md_word(mdoc->meta.arch);
|
||||
md_word(mdoc->arch);
|
||||
md_word(")");
|
||||
}
|
||||
outflags |= MD_sp;
|
||||
@ -273,9 +283,9 @@ markdown_mdoc(void *arg, const struct roff_man *mdoc)
|
||||
md_nodelist(mdoc->first->child);
|
||||
|
||||
outflags |= MD_sp;
|
||||
md_word(mdoc->meta.os);
|
||||
md_word(mdoc->os);
|
||||
md_word("-");
|
||||
md_word(mdoc->meta.date);
|
||||
md_word(mdoc->date);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
@ -330,8 +340,7 @@ md_node(struct roff_node *n)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
|
||||
act = md_acts + n->tok;
|
||||
act = md_act(n->tok);
|
||||
cond = act->cond == NULL || (*act->cond)(n);
|
||||
if (cond && act->pre != NULL &&
|
||||
(n->end == ENDBODY_NOT || n->child != NULL))
|
||||
@ -580,6 +589,12 @@ md_word(const char *s)
|
||||
case ESCAPE_SPECIAL:
|
||||
uc = mchars_spec2cp(seq, sz);
|
||||
break;
|
||||
case ESCAPE_UNDEF:
|
||||
uc = *seq;
|
||||
break;
|
||||
case ESCAPE_DEVICE:
|
||||
md_rawword("markdown");
|
||||
continue;
|
||||
case ESCAPE_FONTBOLD:
|
||||
nextfont = "**";
|
||||
break;
|
||||
@ -590,6 +605,7 @@ md_word(const char *s)
|
||||
nextfont = "***";
|
||||
break;
|
||||
case ESCAPE_FONT:
|
||||
case ESCAPE_FONTCW:
|
||||
case ESCAPE_FONTROMAN:
|
||||
nextfont = "";
|
||||
break;
|
||||
@ -711,12 +727,18 @@ md_cond_body(struct roff_node *n)
|
||||
return n->type == ROFFT_BODY;
|
||||
}
|
||||
|
||||
static int
|
||||
md_pre_abort(struct roff_node *n)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
static int
|
||||
md_pre_raw(struct roff_node *n)
|
||||
{
|
||||
const char *prefix;
|
||||
|
||||
if ((prefix = md_acts[n->tok].prefix) != NULL) {
|
||||
if ((prefix = md_act(n->tok)->prefix) != NULL) {
|
||||
md_rawword(prefix);
|
||||
outflags &= ~MD_spc;
|
||||
if (*prefix == '`')
|
||||
@ -730,7 +752,7 @@ md_post_raw(struct roff_node *n)
|
||||
{
|
||||
const char *suffix;
|
||||
|
||||
if ((suffix = md_acts[n->tok].suffix) != NULL) {
|
||||
if ((suffix = md_act(n->tok)->suffix) != NULL) {
|
||||
outflags &= ~(MD_spc | MD_nl);
|
||||
md_rawword(suffix);
|
||||
if (*suffix == '`')
|
||||
@ -743,7 +765,7 @@ md_pre_word(struct roff_node *n)
|
||||
{
|
||||
const char *prefix;
|
||||
|
||||
if ((prefix = md_acts[n->tok].prefix) != NULL) {
|
||||
if ((prefix = md_act(n->tok)->prefix) != NULL) {
|
||||
md_word(prefix);
|
||||
outflags &= ~MD_spc;
|
||||
}
|
||||
@ -755,7 +777,7 @@ md_post_word(struct roff_node *n)
|
||||
{
|
||||
const char *suffix;
|
||||
|
||||
if ((suffix = md_acts[n->tok].suffix) != NULL) {
|
||||
if ((suffix = md_act(n->tok)->suffix) != NULL) {
|
||||
outflags &= ~(MD_spc | MD_nl);
|
||||
md_word(suffix);
|
||||
}
|
||||
|
60
mdoc_state.c
60
mdoc_state.c
@ -1,4 +1,4 @@
|
||||
/* $Id: mdoc_state.c,v 1.9 2017/11/29 20:05:33 schwarze Exp $ */
|
||||
/* $Id: mdoc_state.c,v 1.15 2019/01/01 07:42:04 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
*
|
||||
@ -17,6 +17,7 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -24,19 +25,18 @@
|
||||
#include "roff.h"
|
||||
#include "mdoc.h"
|
||||
#include "libmandoc.h"
|
||||
#include "roff_int.h"
|
||||
#include "libmdoc.h"
|
||||
|
||||
#define STATE_ARGS struct roff_man *mdoc, struct roff_node *n
|
||||
|
||||
typedef void (*state_handler)(STATE_ARGS);
|
||||
|
||||
static void state_bd(STATE_ARGS);
|
||||
static void state_bl(STATE_ARGS);
|
||||
static void state_dl(STATE_ARGS);
|
||||
static void state_sh(STATE_ARGS);
|
||||
static void state_sm(STATE_ARGS);
|
||||
|
||||
static const state_handler __state_handlers[MDOC_MAX - MDOC_Dd] = {
|
||||
static const state_handler state_handlers[MDOC_MAX - MDOC_Dd] = {
|
||||
NULL, /* Dd */
|
||||
NULL, /* Dt */
|
||||
NULL, /* Os */
|
||||
@ -44,8 +44,8 @@ static const state_handler __state_handlers[MDOC_MAX - MDOC_Dd] = {
|
||||
NULL, /* Ss */
|
||||
NULL, /* Pp */
|
||||
NULL, /* D1 */
|
||||
state_dl, /* Dl */
|
||||
state_bd, /* Bd */
|
||||
NULL, /* Dl */
|
||||
NULL, /* Bd */
|
||||
NULL, /* Ed */
|
||||
state_bl, /* Bl */
|
||||
NULL, /* El */
|
||||
@ -158,7 +158,6 @@ static const state_handler __state_handlers[MDOC_MAX - MDOC_Dd] = {
|
||||
NULL, /* %U */
|
||||
NULL, /* Ta */
|
||||
};
|
||||
static const state_handler *const state_handlers = __state_handlers - MDOC_Dd;
|
||||
|
||||
|
||||
void
|
||||
@ -170,41 +169,14 @@ mdoc_state(struct roff_man *mdoc, struct roff_node *n)
|
||||
return;
|
||||
|
||||
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
|
||||
if ( ! (mdoc_macros[n->tok].flags & MDOC_PROLOGUE))
|
||||
if ((mdoc_macro(n->tok)->flags & MDOC_PROLOGUE) == 0)
|
||||
mdoc->flags |= MDOC_PBODY;
|
||||
|
||||
handler = state_handlers[n->tok];
|
||||
handler = state_handlers[n->tok - MDOC_Dd];
|
||||
if (*handler)
|
||||
(*handler)(mdoc, n);
|
||||
}
|
||||
|
||||
void
|
||||
mdoc_state_reset(struct roff_man *mdoc)
|
||||
{
|
||||
|
||||
roff_setreg(mdoc->roff, "nS", 0, '=');
|
||||
mdoc->flags = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
state_bd(STATE_ARGS)
|
||||
{
|
||||
enum mdocargt arg;
|
||||
|
||||
if (n->type != ROFFT_HEAD &&
|
||||
(n->type != ROFFT_BODY || n->end != ENDBODY_NOT))
|
||||
return;
|
||||
|
||||
if (n->parent->args == NULL)
|
||||
return;
|
||||
|
||||
arg = n->parent->args->argv[0].arg;
|
||||
if (arg != MDOC_Literal && arg != MDOC_Unfilled)
|
||||
return;
|
||||
|
||||
state_dl(mdoc, n);
|
||||
}
|
||||
|
||||
static void
|
||||
state_bl(STATE_ARGS)
|
||||
{
|
||||
@ -229,22 +201,6 @@ state_bl(STATE_ARGS)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
state_dl(STATE_ARGS)
|
||||
{
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_HEAD:
|
||||
mdoc->flags |= MDOC_LITERAL;
|
||||
break;
|
||||
case ROFFT_BODY:
|
||||
mdoc->flags &= ~MDOC_LITERAL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
state_sh(STATE_ARGS)
|
||||
{
|
||||
|
149
mdoc_term.c
149
mdoc_term.c
@ -1,7 +1,7 @@
|
||||
/* $Id: mdoc_term.c,v 1.367 2018/04/11 17:11:13 schwarze Exp $ */
|
||||
/* $Id: mdoc_term.c,v 1.372 2019/01/04 03:39:01 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2010, 2012-2018 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* 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
|
||||
@ -29,7 +29,6 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc_aux.h"
|
||||
#include "mandoc.h"
|
||||
#include "roff.h"
|
||||
#include "mdoc.h"
|
||||
#include "out.h"
|
||||
@ -47,7 +46,7 @@ struct termpair {
|
||||
const struct roff_meta *meta, \
|
||||
struct roff_node *n
|
||||
|
||||
struct termact {
|
||||
struct mdoc_term_act {
|
||||
int (*pre)(DECL_ARGS);
|
||||
void (*post)(DECL_ARGS);
|
||||
};
|
||||
@ -84,6 +83,7 @@ static void termp_xx_post(DECL_ARGS);
|
||||
|
||||
static int termp__a_pre(DECL_ARGS);
|
||||
static int termp__t_pre(DECL_ARGS);
|
||||
static int termp_abort_pre(DECL_ARGS);
|
||||
static int termp_an_pre(DECL_ARGS);
|
||||
static int termp_ap_pre(DECL_ARGS);
|
||||
static int termp_bd_pre(DECL_ARGS);
|
||||
@ -124,7 +124,7 @@ static int termp_vt_pre(DECL_ARGS);
|
||||
static int termp_xr_pre(DECL_ARGS);
|
||||
static int termp_xx_pre(DECL_ARGS);
|
||||
|
||||
static const struct termact __termacts[MDOC_MAX - MDOC_Dd] = {
|
||||
static const struct mdoc_term_act mdoc_term_acts[MDOC_MAX - MDOC_Dd] = {
|
||||
{ NULL, NULL }, /* Dd */
|
||||
{ NULL, NULL }, /* Dt */
|
||||
{ NULL, NULL }, /* Os */
|
||||
@ -159,7 +159,7 @@ static const struct termact __termacts[MDOC_MAX - MDOC_Dd] = {
|
||||
{ termp_nd_pre, NULL }, /* Nd */
|
||||
{ termp_nm_pre, termp_nm_post }, /* Nm */
|
||||
{ termp_quote_pre, termp_quote_post }, /* Op */
|
||||
{ termp_ft_pre, NULL }, /* Ot */
|
||||
{ termp_abort_pre, NULL }, /* Ot */
|
||||
{ termp_under_pre, NULL }, /* Pa */
|
||||
{ termp_ex_pre, NULL }, /* Rv */
|
||||
{ NULL, NULL }, /* St */
|
||||
@ -232,7 +232,7 @@ static const struct termact __termacts[MDOC_MAX - MDOC_Dd] = {
|
||||
{ termp_under_pre, NULL }, /* Fr */
|
||||
{ NULL, NULL }, /* Ud */
|
||||
{ NULL, termp_lb_post }, /* Lb */
|
||||
{ termp_pp_pre, NULL }, /* Lp */
|
||||
{ termp_abort_pre, NULL }, /* Lp */
|
||||
{ termp_lk_pre, NULL }, /* Lk */
|
||||
{ termp_under_pre, NULL }, /* Mt */
|
||||
{ termp_quote_pre, termp_quote_post }, /* Brq */
|
||||
@ -246,13 +246,12 @@ static const struct termact __termacts[MDOC_MAX - MDOC_Dd] = {
|
||||
{ NULL, termp____post }, /* %U */
|
||||
{ NULL, NULL }, /* Ta */
|
||||
};
|
||||
static const struct termact *const termacts = __termacts - MDOC_Dd;
|
||||
|
||||
static int fn_prio;
|
||||
|
||||
|
||||
void
|
||||
terminal_mdoc(void *arg, const struct roff_man *mdoc)
|
||||
terminal_mdoc(void *arg, const struct roff_meta *mdoc)
|
||||
{
|
||||
struct roff_node *n;
|
||||
struct termp *p;
|
||||
@ -270,8 +269,7 @@ terminal_mdoc(void *arg, const struct roff_man *mdoc)
|
||||
if (n->tok == MDOC_Sh && n->sec == SEC_SYNOPSIS) {
|
||||
if (n->child->next->child != NULL)
|
||||
print_mdoc_nodelist(p, NULL,
|
||||
&mdoc->meta,
|
||||
n->child->next->child);
|
||||
mdoc, n->child->next->child);
|
||||
term_newln(p);
|
||||
break;
|
||||
}
|
||||
@ -281,8 +279,7 @@ terminal_mdoc(void *arg, const struct roff_man *mdoc)
|
||||
save_defindent = p->defindent;
|
||||
if (p->defindent == 0)
|
||||
p->defindent = 5;
|
||||
term_begin(p, print_mdoc_head, print_mdoc_foot,
|
||||
&mdoc->meta);
|
||||
term_begin(p, print_mdoc_head, print_mdoc_foot, mdoc);
|
||||
while (n != NULL &&
|
||||
(n->type == ROFFT_COMMENT ||
|
||||
n->flags & NODE_NOPRT))
|
||||
@ -290,7 +287,7 @@ terminal_mdoc(void *arg, const struct roff_man *mdoc)
|
||||
if (n != NULL) {
|
||||
if (n->tok != MDOC_Sh)
|
||||
term_vspace(p);
|
||||
print_mdoc_nodelist(p, NULL, &mdoc->meta, n);
|
||||
print_mdoc_nodelist(p, NULL, mdoc, n);
|
||||
}
|
||||
term_end(p);
|
||||
p->defindent = save_defindent;
|
||||
@ -310,9 +307,23 @@ print_mdoc_nodelist(DECL_ARGS)
|
||||
static void
|
||||
print_mdoc_node(DECL_ARGS)
|
||||
{
|
||||
int chld;
|
||||
const struct mdoc_term_act *act;
|
||||
struct termpair npair;
|
||||
size_t offset, rmargin;
|
||||
int chld;
|
||||
|
||||
/*
|
||||
* In no-fill mode, break the output line at the beginning
|
||||
* of new input lines except after \c, and nowhere else.
|
||||
*/
|
||||
|
||||
if (n->flags & NODE_NOFILL) {
|
||||
if (n->flags & NODE_LINE &&
|
||||
(p->flags & TERMP_NONEWLINE) == 0)
|
||||
term_newln(p);
|
||||
p->flags |= TERMP_BRNEVER;
|
||||
} else
|
||||
p->flags &= ~TERMP_BRNEVER;
|
||||
|
||||
if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT)
|
||||
return;
|
||||
@ -343,9 +354,22 @@ print_mdoc_node(DECL_ARGS)
|
||||
|
||||
switch (n->type) {
|
||||
case ROFFT_TEXT:
|
||||
if (*n->string == ' ' && n->flags & NODE_LINE &&
|
||||
(p->flags & TERMP_NONEWLINE) == 0)
|
||||
term_newln(p);
|
||||
if (n->flags & NODE_LINE) {
|
||||
switch (*n->string) {
|
||||
case '\0':
|
||||
if (p->flags & TERMP_NONEWLINE)
|
||||
term_newln(p);
|
||||
else
|
||||
term_vspace(p);
|
||||
return;
|
||||
case ' ':
|
||||
if ((p->flags & TERMP_NONEWLINE) == 0)
|
||||
term_newln(p);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (NODE_DELIMC & n->flags)
|
||||
p->flags |= TERMP_NOSPACE;
|
||||
term_word(p, n->string);
|
||||
@ -370,10 +394,10 @@ print_mdoc_node(DECL_ARGS)
|
||||
return;
|
||||
}
|
||||
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
|
||||
if (termacts[n->tok].pre != NULL &&
|
||||
act = mdoc_term_acts + (n->tok - MDOC_Dd);
|
||||
if (act->pre != NULL &&
|
||||
(n->end == ENDBODY_NOT || n->child != NULL))
|
||||
chld = (*termacts[n->tok].pre)
|
||||
(p, &npair, meta, n);
|
||||
chld = (*act->pre)(p, &npair, meta, n);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -391,9 +415,9 @@ print_mdoc_node(DECL_ARGS)
|
||||
case ROFFT_EQN:
|
||||
break;
|
||||
default:
|
||||
if (termacts[n->tok].post == NULL || n->flags & NODE_ENDED)
|
||||
if (act->post == NULL || n->flags & NODE_ENDED)
|
||||
break;
|
||||
(void)(*termacts[n->tok].post)(p, &npair, meta, n);
|
||||
(void)(*act->post)(p, &npair, meta, n);
|
||||
|
||||
/*
|
||||
* Explicit end tokens not only call the post
|
||||
@ -1420,8 +1444,6 @@ termp_fa_pre(DECL_ARGS)
|
||||
static int
|
||||
termp_bd_pre(DECL_ARGS)
|
||||
{
|
||||
size_t lm, len;
|
||||
struct roff_node *nn;
|
||||
int offset;
|
||||
|
||||
if (n->type == ROFFT_BLOCK) {
|
||||
@ -1447,66 +1469,19 @@ termp_bd_pre(DECL_ARGS)
|
||||
p->tcol->offset += offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* If -ragged or -filled are specified, the block does nothing
|
||||
* but change the indentation. If -unfilled or -literal are
|
||||
* specified, text is printed exactly as entered in the display:
|
||||
* for macro lines, a newline is appended to the line. Blank
|
||||
* lines are allowed.
|
||||
*/
|
||||
|
||||
if (n->norm->Bd.type != DISP_literal &&
|
||||
n->norm->Bd.type != DISP_unfilled &&
|
||||
n->norm->Bd.type != DISP_centered)
|
||||
return 1;
|
||||
|
||||
if (n->norm->Bd.type == DISP_literal) {
|
||||
switch (n->norm->Bd.type) {
|
||||
case DISP_literal:
|
||||
term_tab_set(p, NULL);
|
||||
term_tab_set(p, "T");
|
||||
term_tab_set(p, "8n");
|
||||
break;
|
||||
case DISP_centered:
|
||||
p->flags |= TERMP_CENTER;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
lm = p->tcol->offset;
|
||||
p->flags |= TERMP_BRNEVER;
|
||||
for (nn = n->child; nn != NULL; nn = nn->next) {
|
||||
if (n->norm->Bd.type == DISP_centered) {
|
||||
if (nn->type == ROFFT_TEXT) {
|
||||
len = term_strlen(p, nn->string);
|
||||
p->tcol->offset = len >= p->tcol->rmargin ?
|
||||
0 : lm + len >= p->tcol->rmargin ?
|
||||
p->tcol->rmargin - len :
|
||||
(lm + p->tcol->rmargin - len) / 2;
|
||||
} else
|
||||
p->tcol->offset = lm;
|
||||
}
|
||||
print_mdoc_node(p, pair, meta, nn);
|
||||
/*
|
||||
* If the printed node flushes its own line, then we
|
||||
* needn't do it here as well. This is hacky, but the
|
||||
* notion of selective eoln whitespace is pretty dumb
|
||||
* anyway, so don't sweat it.
|
||||
*/
|
||||
if (nn->tok < ROFF_MAX)
|
||||
continue;
|
||||
switch (nn->tok) {
|
||||
case MDOC_Sm:
|
||||
case MDOC_Bl:
|
||||
case MDOC_D1:
|
||||
case MDOC_Dl:
|
||||
case MDOC_Lp:
|
||||
case MDOC_Pp:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (p->flags & TERMP_NONEWLINE ||
|
||||
(nn->next && ! (nn->next->flags & NODE_LINE)))
|
||||
continue;
|
||||
term_flushln(p);
|
||||
p->flags |= TERMP_NOSPACE;
|
||||
}
|
||||
p->flags &= ~TERMP_BRNEVER;
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1514,12 +1489,14 @@ termp_bd_post(DECL_ARGS)
|
||||
{
|
||||
if (n->type != ROFFT_BODY)
|
||||
return;
|
||||
if (DISP_literal == n->norm->Bd.type ||
|
||||
DISP_unfilled == n->norm->Bd.type)
|
||||
if (n->norm->Bd.type == DISP_unfilled ||
|
||||
n->norm->Bd.type == DISP_literal)
|
||||
p->flags |= TERMP_BRNEVER;
|
||||
p->flags |= TERMP_NOSPACE;
|
||||
term_newln(p);
|
||||
p->flags &= ~TERMP_BRNEVER;
|
||||
if (n->norm->Bd.type == DISP_centered)
|
||||
p->flags &= ~TERMP_CENTER;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -2098,3 +2075,9 @@ termp_tag_pre(DECL_ARGS)
|
||||
tag_put(n->child->string, 1, p->line);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
termp_abort_pre(DECL_ARGS)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
559
mdoc_validate.c
559
mdoc_validate.c
File diff suppressed because it is too large
Load Diff
3
msec.c
3
msec.c
@ -1,4 +1,4 @@
|
||||
/* $Id: msec.c,v 1.15 2015/10/06 18:32:19 schwarze Exp $ */
|
||||
/* $Id: msec.c,v 1.16 2018/12/14 01:18:26 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
*
|
||||
@ -18,6 +18,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
|
334
out.c
334
out.c
@ -1,7 +1,7 @@
|
||||
/* $Id: out.c,v 1.70 2017/06/27 18:25:02 schwarze Exp $ */
|
||||
/* $Id: out.c,v 1.77 2018/12/13 11:55:47 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2011,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
|
||||
@ -20,21 +20,29 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "mandoc_aux.h"
|
||||
#include "mandoc.h"
|
||||
#include "tbl.h"
|
||||
#include "out.h"
|
||||
|
||||
static void tblcalc_data(struct rofftbl *, struct roffcol *,
|
||||
struct tbl_colgroup {
|
||||
struct tbl_colgroup *next;
|
||||
size_t wanted;
|
||||
int startcol;
|
||||
int endcol;
|
||||
};
|
||||
|
||||
static size_t tblcalc_data(struct rofftbl *, struct roffcol *,
|
||||
const struct tbl_opts *, const struct tbl_dat *,
|
||||
size_t);
|
||||
static void tblcalc_literal(struct rofftbl *, struct roffcol *,
|
||||
static size_t tblcalc_literal(struct rofftbl *, struct roffcol *,
|
||||
const struct tbl_dat *, size_t);
|
||||
static void tblcalc_number(struct rofftbl *, struct roffcol *,
|
||||
static size_t tblcalc_number(struct rofftbl *, struct roffcol *,
|
||||
const struct tbl_opts *, const struct tbl_dat *);
|
||||
|
||||
|
||||
@ -103,16 +111,18 @@ a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
|
||||
* used for the actual width calculations.
|
||||
*/
|
||||
void
|
||||
tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
|
||||
tblcalc(struct rofftbl *tbl, const struct tbl_span *sp_first,
|
||||
size_t offset, size_t rmargin)
|
||||
{
|
||||
struct roffsu su;
|
||||
const struct tbl_opts *opts;
|
||||
const struct tbl_span *sp;
|
||||
const struct tbl_dat *dp;
|
||||
struct roffcol *col;
|
||||
size_t ewidth, xwidth;
|
||||
int spans;
|
||||
int icol, maxcol, necol, nxcol, quirkcol;
|
||||
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;
|
||||
|
||||
/*
|
||||
* Allocate the master column specifiers. These will hold the
|
||||
@ -120,33 +130,34 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
|
||||
* must be freed and nullified by the caller.
|
||||
*/
|
||||
|
||||
assert(NULL == tbl->cols);
|
||||
tbl->cols = mandoc_calloc((size_t)sp->opts->cols,
|
||||
assert(tbl->cols == NULL);
|
||||
tbl->cols = mandoc_calloc((size_t)sp_first->opts->cols,
|
||||
sizeof(struct roffcol));
|
||||
opts = sp->opts;
|
||||
opts = sp_first->opts;
|
||||
|
||||
for (maxcol = -1; sp; sp = sp->next) {
|
||||
if (TBL_SPAN_DATA != sp->pos)
|
||||
maxcol = -1;
|
||||
first_group = NULL;
|
||||
for (sp = sp_first; sp != NULL; sp = sp->next) {
|
||||
if (sp->pos != TBL_SPAN_DATA)
|
||||
continue;
|
||||
spans = 1;
|
||||
|
||||
/*
|
||||
* Account for the data cells in the layout, matching it
|
||||
* to data cells in the data section.
|
||||
*/
|
||||
for (dp = sp->first; dp; dp = dp->next) {
|
||||
/* Do not used spanned cells in the calculation. */
|
||||
if (0 < --spans)
|
||||
continue;
|
||||
spans = dp->spans;
|
||||
if (1 < spans)
|
||||
continue;
|
||||
|
||||
gp = &first_group;
|
||||
for (dp = sp->first; dp != NULL; dp = dp->next) {
|
||||
icol = dp->layout->col;
|
||||
while (maxcol < icol)
|
||||
while (icol > maxcol)
|
||||
tbl->cols[++maxcol].spacing = SIZE_MAX;
|
||||
col = tbl->cols + icol;
|
||||
col->flags |= dp->layout->flags;
|
||||
if (dp->layout->flags & TBL_CELL_WIGN)
|
||||
continue;
|
||||
|
||||
/* Handle explicit width specifications. */
|
||||
|
||||
if (dp->layout->wstr != NULL &&
|
||||
dp->layout->width == 0 &&
|
||||
a2roffsu(dp->layout->wstr, &su, SCALE_EN)
|
||||
@ -159,15 +170,165 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
|
||||
(col->spacing == SIZE_MAX ||
|
||||
col->spacing < dp->layout->spacing))
|
||||
col->spacing = dp->layout->spacing;
|
||||
tblcalc_data(tbl, col, opts, dp,
|
||||
|
||||
/*
|
||||
* Calculate an automatic width.
|
||||
* Except for spanning cells, apply it.
|
||||
*/
|
||||
|
||||
width = tblcalc_data(tbl,
|
||||
dp->hspans == 0 ? col : NULL,
|
||||
opts, dp,
|
||||
dp->block == 0 ? 0 :
|
||||
dp->layout->width ? dp->layout->width :
|
||||
rmargin ? (rmargin + sp->opts->cols / 2)
|
||||
/ (sp->opts->cols + 1) : 0);
|
||||
if (dp->hspans == 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Build an ordered, singly linked list
|
||||
* of all groups of columns joined by spans,
|
||||
* recording the minimum width for each group.
|
||||
*/
|
||||
|
||||
while (*gp != NULL && ((*gp)->startcol < icol ||
|
||||
(*gp)->endcol < icol + dp->hspans))
|
||||
gp = &(*gp)->next;
|
||||
if (*gp == NULL || (*gp)->startcol > icol ||
|
||||
(*gp)->endcol > icol + dp->hspans) {
|
||||
g = mandoc_malloc(sizeof(*g));
|
||||
g->next = *gp;
|
||||
g->wanted = width;
|
||||
g->startcol = icol;
|
||||
g->endcol = icol + dp->hspans;
|
||||
*gp = g;
|
||||
} else if ((*gp)->wanted < width)
|
||||
(*gp)->wanted = width;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Column spacings are needed for span width calculations,
|
||||
* so set the default values now.
|
||||
*/
|
||||
|
||||
for (icol = 0; icol <= maxcol; icol++)
|
||||
if (tbl->cols[icol].spacing == SIZE_MAX || icol == maxcol)
|
||||
tbl->cols[icol].spacing = 3;
|
||||
|
||||
/*
|
||||
* Replace the minimum widths with the missing widths,
|
||||
* and dismiss groups that are already wide enough.
|
||||
*/
|
||||
|
||||
gp = &first_group;
|
||||
while ((g = *gp) != NULL) {
|
||||
done = 0;
|
||||
for (icol = g->startcol; icol <= g->endcol; icol++) {
|
||||
width = tbl->cols[icol].width;
|
||||
if (icol < g->endcol)
|
||||
width += tbl->cols[icol].spacing;
|
||||
if (g->wanted <= width) {
|
||||
done = 1;
|
||||
break;
|
||||
} else
|
||||
(*gp)->wanted -= width;
|
||||
}
|
||||
if (done) {
|
||||
*gp = g->next;
|
||||
free(g);
|
||||
} else
|
||||
gp = &(*gp)->next;
|
||||
}
|
||||
|
||||
colwidth = mandoc_reallocarray(NULL, maxcol + 1, sizeof(*colwidth));
|
||||
while (first_group != NULL) {
|
||||
|
||||
/*
|
||||
* Rebuild the array of the widths of all columns
|
||||
* participating in spans that require expansion.
|
||||
*/
|
||||
|
||||
for (icol = 0; icol <= maxcol; icol++)
|
||||
colwidth[icol] = SIZE_MAX;
|
||||
for (g = first_group; g != NULL; g = g->next)
|
||||
for (icol = g->startcol; icol <= g->endcol; icol++)
|
||||
colwidth[icol] = tbl->cols[icol].width;
|
||||
|
||||
/*
|
||||
* Find the smallest and second smallest column width
|
||||
* among the columns which may need expamsion.
|
||||
*/
|
||||
|
||||
min1 = min2 = SIZE_MAX;
|
||||
for (icol = 0; icol <= maxcol; icol++) {
|
||||
if (min1 > colwidth[icol]) {
|
||||
min2 = min1;
|
||||
min1 = colwidth[icol];
|
||||
} else if (min1 < colwidth[icol] &&
|
||||
min2 > colwidth[icol])
|
||||
min2 = colwidth[icol];
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the minimum wanted width
|
||||
* for any one of the narrowest columns,
|
||||
* and mark the columns wanting that width.
|
||||
*/
|
||||
|
||||
wanted = min2;
|
||||
for (g = first_group; g != NULL; g = g->next) {
|
||||
necol = 0;
|
||||
for (icol = g->startcol; icol <= g->endcol; icol++)
|
||||
if (tbl->cols[icol].width == min1)
|
||||
necol++;
|
||||
if (necol == 0)
|
||||
continue;
|
||||
width = min1 + (g->wanted - 1) / necol + 1;
|
||||
if (width > min2)
|
||||
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. */
|
||||
|
||||
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)
|
||||
continue;
|
||||
if (g->wanted <= wanted - min1) {
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
g->wanted -= wanted - min1;
|
||||
}
|
||||
if (done) {
|
||||
*gp = g->next;
|
||||
free(g);
|
||||
} 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.
|
||||
* Count columns to equalize and columns to maximize.
|
||||
* Find maximum width of the columns to equalize.
|
||||
* Find total width of the columns *not* to maximize.
|
||||
@ -177,8 +338,10 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
|
||||
ewidth = xwidth = 0;
|
||||
for (icol = 0; icol <= maxcol; icol++) {
|
||||
col = tbl->cols + icol;
|
||||
if (col->spacing == SIZE_MAX || icol == maxcol)
|
||||
col->spacing = 3;
|
||||
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)
|
||||
@ -251,7 +414,7 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
static size_t
|
||||
tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
|
||||
const struct tbl_opts *opts, const struct tbl_dat *dp, size_t mw)
|
||||
{
|
||||
@ -263,26 +426,24 @@ tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
|
||||
case TBL_CELL_HORIZ:
|
||||
case TBL_CELL_DHORIZ:
|
||||
sz = (*tbl->len)(1, tbl->arg);
|
||||
if (col->width < sz)
|
||||
if (col != NULL && col->width < sz)
|
||||
col->width = sz;
|
||||
break;
|
||||
return sz;
|
||||
case TBL_CELL_LONG:
|
||||
case TBL_CELL_CENTRE:
|
||||
case TBL_CELL_LEFT:
|
||||
case TBL_CELL_RIGHT:
|
||||
tblcalc_literal(tbl, col, dp, mw);
|
||||
break;
|
||||
return tblcalc_literal(tbl, col, dp, mw);
|
||||
case TBL_CELL_NUMBER:
|
||||
tblcalc_number(tbl, col, opts, dp);
|
||||
break;
|
||||
return tblcalc_number(tbl, col, opts, dp);
|
||||
case TBL_CELL_DOWN:
|
||||
break;
|
||||
return 0;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
static size_t
|
||||
tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
|
||||
const struct tbl_dat *dp, size_t mw)
|
||||
{
|
||||
@ -291,11 +452,12 @@ tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
|
||||
char *end; /* End of the current line. */
|
||||
size_t lsz; /* Length of the current line. */
|
||||
size_t wsz; /* Length of the current word. */
|
||||
size_t msz; /* Length of the longest line. */
|
||||
|
||||
if (dp->string == NULL || *dp->string == '\0')
|
||||
return;
|
||||
return 0;
|
||||
str = mw ? mandoc_strdup(dp->string) : dp->string;
|
||||
lsz = 0;
|
||||
msz = lsz = 0;
|
||||
for (beg = str; beg != NULL && *beg != '\0'; beg = end) {
|
||||
end = mw ? strchr(beg, ' ') : NULL;
|
||||
if (end != NULL) {
|
||||
@ -308,62 +470,84 @@ tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
|
||||
lsz += 1 + wsz;
|
||||
else
|
||||
lsz = wsz;
|
||||
if (col->width < lsz)
|
||||
col->width = lsz;
|
||||
if (msz < lsz)
|
||||
msz = lsz;
|
||||
}
|
||||
if (mw)
|
||||
free((void *)str);
|
||||
if (col != NULL && col->width < msz)
|
||||
col->width = msz;
|
||||
return msz;
|
||||
}
|
||||
|
||||
static void
|
||||
static size_t
|
||||
tblcalc_number(struct rofftbl *tbl, struct roffcol *col,
|
||||
const struct tbl_opts *opts, const struct tbl_dat *dp)
|
||||
{
|
||||
int i;
|
||||
size_t sz, psz, ssz, d;
|
||||
const char *str;
|
||||
char *cp;
|
||||
const char *cp, *lastdigit, *lastpoint;
|
||||
size_t intsz, totsz;
|
||||
char buf[2];
|
||||
|
||||
if (dp->string == NULL || *dp->string == '\0')
|
||||
return 0;
|
||||
|
||||
totsz = (*tbl->slen)(dp->string, tbl->arg);
|
||||
if (col == NULL)
|
||||
return totsz;
|
||||
|
||||
/*
|
||||
* First calculate number width and decimal place (last + 1 for
|
||||
* non-decimal numbers). If the stored decimal is subsequent to
|
||||
* ours, make our size longer by that difference
|
||||
* (right-"shifting"); similarly, if ours is subsequent the
|
||||
* stored, then extend the stored size by the difference.
|
||||
* Finally, re-assign the stored values.
|
||||
* Find the last digit and
|
||||
* the last decimal point that is adjacent to a digit.
|
||||
* The alignment indicator "\&" overrides everything.
|
||||
*/
|
||||
|
||||
str = dp->string ? dp->string : "";
|
||||
sz = (*tbl->slen)(str, tbl->arg);
|
||||
lastdigit = lastpoint = NULL;
|
||||
for (cp = dp->string; cp[0] != '\0'; cp++) {
|
||||
if (cp[0] == '\\' && cp[1] == '&') {
|
||||
lastdigit = lastpoint = cp;
|
||||
break;
|
||||
} else if (cp[0] == opts->decimal &&
|
||||
(isdigit((unsigned char)cp[1]) ||
|
||||
(cp > dp->string && isdigit((unsigned char)cp[-1]))))
|
||||
lastpoint = cp;
|
||||
else if (isdigit((unsigned char)cp[0]))
|
||||
lastdigit = cp;
|
||||
}
|
||||
|
||||
/* FIXME: TBL_DATA_HORIZ et al.? */
|
||||
/* Not a number, treat as a literal string. */
|
||||
|
||||
buf[0] = opts->decimal;
|
||||
if (lastdigit == NULL) {
|
||||
if (col != NULL && col->width < totsz)
|
||||
col->width = totsz;
|
||||
return totsz;
|
||||
}
|
||||
|
||||
/* Measure the width of the integer part. */
|
||||
|
||||
if (lastpoint == NULL)
|
||||
lastpoint = lastdigit + 1;
|
||||
intsz = 0;
|
||||
buf[1] = '\0';
|
||||
for (cp = dp->string; cp < lastpoint; cp++) {
|
||||
buf[0] = cp[0];
|
||||
intsz += (*tbl->slen)(buf, tbl->arg);
|
||||
}
|
||||
|
||||
psz = (*tbl->slen)(buf, tbl->arg);
|
||||
/*
|
||||
* If this number has more integer digits than all numbers
|
||||
* seen on earlier lines, shift them all to the right.
|
||||
* If it has fewer, shift this number to the right.
|
||||
*/
|
||||
|
||||
if (NULL != (cp = strrchr(str, opts->decimal))) {
|
||||
buf[1] = '\0';
|
||||
for (ssz = 0, i = 0; cp != &str[i]; i++) {
|
||||
buf[0] = str[i];
|
||||
ssz += (*tbl->slen)(buf, tbl->arg);
|
||||
}
|
||||
d = ssz + psz;
|
||||
if (intsz > col->decimal) {
|
||||
col->nwidth += intsz - col->decimal;
|
||||
col->decimal = intsz;
|
||||
} else
|
||||
d = sz + psz;
|
||||
totsz += col->decimal - intsz;
|
||||
|
||||
/* Adjust the settings for this column. */
|
||||
/* Update the maximum total width seen so far. */
|
||||
|
||||
if (col->decimal > d) {
|
||||
sz += col->decimal - d;
|
||||
d = col->decimal;
|
||||
} else
|
||||
col->width += d - col->decimal;
|
||||
|
||||
if (sz > col->width)
|
||||
col->width = sz;
|
||||
if (d > col->decimal)
|
||||
col->decimal = d;
|
||||
if (totsz > col->nwidth)
|
||||
col->nwidth = totsz;
|
||||
return totsz;
|
||||
}
|
||||
|
5
out.h
5
out.h
@ -1,7 +1,7 @@
|
||||
/* $Id: out.h,v 1.32 2018/06/25 16:54:59 schwarze Exp $ */
|
||||
/* $Id: out.h,v 1.33 2018/08/18 20:18:14 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2014, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2014, 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
|
||||
@ -32,6 +32,7 @@ enum roffscale {
|
||||
|
||||
struct roffcol {
|
||||
size_t width; /* width of cell */
|
||||
size_t nwidth; /* max. width of number in cell */
|
||||
size_t decimal; /* decimal position in cell */
|
||||
size_t spacing; /* spacing after the column */
|
||||
int flags; /* layout flags, see tbl_cell */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: preconv.c,v 1.16 2017/02/18 13:43:52 schwarze Exp $ */
|
||||
/* $Id: preconv.c,v 1.17 2018/12/13 11:55:47 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
|
||||
@ -22,7 +22,10 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "roff.h"
|
||||
#include "mandoc_parse.h"
|
||||
#include "libmandoc.h"
|
||||
|
||||
int
|
||||
|
607
roff.7
607
roff.7
@ -1,7 +1,7 @@
|
||||
.\" $Id: roff.7,v 1.96 2018/04/10 00:52:30 schwarze Exp $
|
||||
.\" $Id: roff.7,v 1.111 2019/01/01 03:45:29 schwarze Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
.\" Copyright (c) 2010-2018 Ingo Schwarze <schwarze@openbsd.org>
|
||||
.\" Copyright (c) 2010-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: April 10 2018 $
|
||||
.Dd $Mdocdate: January 1 2019 $
|
||||
.Dt ROFF 7
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -39,17 +39,15 @@ or
|
||||
code.
|
||||
To properly format such manuals, the
|
||||
.Xr mandoc 1
|
||||
utility supports a tiny subset of
|
||||
utility supports a subset of
|
||||
.Nm
|
||||
requests and escapes.
|
||||
Only these requests and escapes supported by
|
||||
Even though this manual page lists all
|
||||
.Nm
|
||||
requests and escape sequences, it only contains partial information
|
||||
about requests not supported by
|
||||
.Xr mandoc 1
|
||||
are documented in the present manual,
|
||||
together with the basic language syntax shared by
|
||||
.Nm ,
|
||||
.Xr mdoc 7 ,
|
||||
and
|
||||
.Xr man 7 .
|
||||
and about language features that do not matter for manual pages.
|
||||
For complete
|
||||
.Nm
|
||||
manuals, consult the
|
||||
@ -86,14 +84,10 @@ character, and, in certain circumstances, the tab character.
|
||||
The backslash character
|
||||
.Sq \e
|
||||
indicates the start of an escape sequence, used for example for
|
||||
.Sx Comments ,
|
||||
.Sx Special Characters ,
|
||||
.Sx Predefined Strings ,
|
||||
.Sx Comments
|
||||
and
|
||||
user-defined strings defined using the
|
||||
.Sx ds
|
||||
request.
|
||||
For a listing of escape sequences, consult the
|
||||
.Sx Special Characters .
|
||||
For a complete listing of escape sequences, consult the
|
||||
.Sx ESCAPE SEQUENCE REFERENCE
|
||||
below.
|
||||
.Ss Comments
|
||||
@ -139,20 +133,73 @@ One-letter backslash escape.
|
||||
See
|
||||
.Xr mandoc_char 7
|
||||
for a complete list.
|
||||
.Ss Text Decoration
|
||||
Terms may be text-decorated using the
|
||||
.Sq \ef
|
||||
escape followed by an indicator: B (bold), I (italic), R (regular), or P
|
||||
(revert to previous mode).
|
||||
A numerical representation 3, 2, or 1 (bold, italic, and regular,
|
||||
respectively) may be used instead.
|
||||
The indicator or numerical representative may be preceded by C
|
||||
(constant-width), which is ignored.
|
||||
.Ss Font Selection
|
||||
In
|
||||
.Xr mdoc 7
|
||||
and
|
||||
.Xr man 7
|
||||
documents, fonts are usually selected with macros.
|
||||
The
|
||||
.Ic \ef
|
||||
escape sequence and the
|
||||
.Ic \&ft
|
||||
request can be used to manually change the font,
|
||||
but this is not recommended in
|
||||
.Xr mdoc 7
|
||||
documents.
|
||||
Such manual font changes are overridden by many subsequent macros.
|
||||
.Pp
|
||||
The two-character indicator
|
||||
.Sq BI
|
||||
requests a font that is both bold and italic.
|
||||
It may not be portable to old roff implementations.
|
||||
The following fonts are supported:
|
||||
.Pp
|
||||
.Bl -tag -width CW -offset indent -compact
|
||||
.It Cm B
|
||||
Bold font.
|
||||
.It Cm BI
|
||||
A font that is both bold and italic.
|
||||
.It Cm CB
|
||||
Bold constant width font.
|
||||
Same as
|
||||
.Cm B
|
||||
in terminal output.
|
||||
.It Cm CI
|
||||
Italic constant width font.
|
||||
Same as
|
||||
.Cm I
|
||||
in terminal output.
|
||||
.It Cm CR
|
||||
Regular constant width font.
|
||||
Same as
|
||||
.Cm R
|
||||
in terminal output.
|
||||
.It Cm CW
|
||||
An alias for
|
||||
.Cm CR .
|
||||
.It Cm I
|
||||
Italic font.
|
||||
.It Cm P
|
||||
Return to the previous font.
|
||||
If a macro caused a font change since the last
|
||||
.Ic \ef
|
||||
eascape sequence or
|
||||
.Ic \&ft
|
||||
request, this returns to the font before the last font change in
|
||||
the macro rather than to the font before the last manual font change.
|
||||
.It Cm R
|
||||
Roman font.
|
||||
This is the default font.
|
||||
.It Cm 1
|
||||
An alias for
|
||||
.Cm R .
|
||||
.It Cm 2
|
||||
An alias for
|
||||
.Cm I .
|
||||
.It Cm 3
|
||||
An alias for
|
||||
.Cm B .
|
||||
.It Cm 4
|
||||
An alias for
|
||||
.Cm BI .
|
||||
.El
|
||||
.Pp
|
||||
Examples:
|
||||
.Bl -tag -width Ds -offset indent -compact
|
||||
@ -163,40 +210,6 @@ Write in \fIitalic\fP, then return to previous font mode.
|
||||
.It Li \ef(BIbold italic\efP
|
||||
Write in \f(BIbold italic\fP, then return to previous font mode.
|
||||
.El
|
||||
.Pp
|
||||
Text decoration is
|
||||
.Em not
|
||||
recommended for
|
||||
.Xr mdoc 7 ,
|
||||
which encourages semantic annotation.
|
||||
.Ss Predefined Strings
|
||||
Predefined strings, like
|
||||
.Sx Special Characters ,
|
||||
mark special output glyphs.
|
||||
Predefined strings are escaped with the slash-asterisk,
|
||||
.Sq \e* :
|
||||
single-character
|
||||
.Sq \e*X ,
|
||||
two-character
|
||||
.Sq \e*(XX ,
|
||||
and N-character
|
||||
.Sq \e* Ns Bq N .
|
||||
.Pp
|
||||
Examples:
|
||||
.Bl -tag -width Ds -offset indent -compact
|
||||
.It Li \e*(Am
|
||||
Two-letter ampersand predefined string.
|
||||
.It Li \e*q
|
||||
One-letter double-quote predefined string.
|
||||
.El
|
||||
.Pp
|
||||
Predefined strings are not recommended for use,
|
||||
as they differ across implementations.
|
||||
Those supported by
|
||||
.Xr mandoc 1
|
||||
are listed in
|
||||
.Xr mandoc_char 7 .
|
||||
Manuals using these predefined strings are almost certainly not portable.
|
||||
.Ss Whitespace
|
||||
Whitespace consists of the space character.
|
||||
In text lines, whitespace is preserved within a line.
|
||||
@ -206,7 +219,7 @@ Unescaped trailing spaces are stripped from text line input unless in a
|
||||
literal context.
|
||||
In general, trailing whitespace on any input line is discouraged for
|
||||
reasons of portability.
|
||||
In the rare case that a blank character is needed at the end of an
|
||||
In the rare case that a space character is needed at the end of an
|
||||
input line, it may be forced by
|
||||
.Sq \e\ \e& .
|
||||
.Pp
|
||||
@ -225,7 +238,6 @@ Many requests and macros support scaled widths for their arguments.
|
||||
The syntax for a scaled width is
|
||||
.Sq Li [+-]?[0-9]*.[0-9]*[:unit:] ,
|
||||
where a decimal must be preceded or followed by at least one digit.
|
||||
Negative numbers, while accepted, are truncated to zero.
|
||||
.Pp
|
||||
The following scaling units are accepted:
|
||||
.Pp
|
||||
@ -235,9 +247,9 @@ centimetre
|
||||
.It i
|
||||
inch
|
||||
.It P
|
||||
pica (~1/6 inch)
|
||||
pica (1/6 inch)
|
||||
.It p
|
||||
point (~1/72 inch)
|
||||
point (1/72 inch)
|
||||
.It f
|
||||
scale
|
||||
.Sq u
|
||||
@ -257,7 +269,7 @@ character
|
||||
.It u
|
||||
default horizontal span for the terminal
|
||||
.It M
|
||||
mini-em (~1/100 em)
|
||||
mini-em (1/100 em)
|
||||
.El
|
||||
.Pp
|
||||
Using anything other than
|
||||
@ -341,7 +353,7 @@ Macros are provided by the
|
||||
and
|
||||
.Xr man 7
|
||||
languages and can be defined by the
|
||||
.Sx \&de
|
||||
.Ic \&de
|
||||
request.
|
||||
When called, they follow the same syntax as requests, except that
|
||||
macro arguments may optionally be quoted by enclosing them
|
||||
@ -447,7 +459,7 @@ compatibility mode at all, it handles this request as an alias for
|
||||
.It Ic \&as Ar stringname Op Ar string
|
||||
Append to a user-defined string.
|
||||
The syntax of this request is the same as that of
|
||||
.Sx \&ds .
|
||||
.Ic \&ds .
|
||||
If a user-defined string with the specified name does not yet exist,
|
||||
it is set to the empty string before appending.
|
||||
.It Ic \&as1 Ar stringname Op Ar string
|
||||
@ -539,9 +551,16 @@ This is a groff extension and currently ignored.
|
||||
.It Ic \&ch Ar macroname Op Ar dist
|
||||
Change a trap location.
|
||||
Currently ignored.
|
||||
.It Ic \&char Ar glyphname Op Ar string
|
||||
Define a new glyph.
|
||||
Currently unsupported.
|
||||
.It Ic \&char Ar glyph Op Ar string
|
||||
Define or redefine the ASCII character or character escape sequence
|
||||
.Ar glyph
|
||||
to be rendered as
|
||||
.Ar string ,
|
||||
which can be empty.
|
||||
Only partially supported in
|
||||
.Xr mandoc 1 ;
|
||||
may interact incorrectly with
|
||||
.Ic \&tr .
|
||||
.It Ic \&chop Ar stringname
|
||||
Remove the last character from a macro, string, or diversion.
|
||||
Currently unsupported.
|
||||
@ -622,7 +641,7 @@ macros, whichever applies to the document in question.
|
||||
.Pp
|
||||
Specifying a custom
|
||||
.Ar endmacro
|
||||
macro works in the same way as for
|
||||
works in the same way as for
|
||||
.Ic \&ig ;
|
||||
namely, the call to
|
||||
.Sq Pf . Ar endmacro
|
||||
@ -665,7 +684,9 @@ produces
|
||||
.Pp
|
||||
in the input stream, and thus in the output: \fI\^XtFree\^\fP.
|
||||
Each occurrence of \e\e$* is replaced with all the arguments,
|
||||
joined together with single blank characters.
|
||||
joined together with single space characters.
|
||||
The variant \e\e$@ is similar, except that each argument is
|
||||
individually quoted.
|
||||
.Pp
|
||||
Since macros and user-defined strings share a common string table,
|
||||
defining a macro
|
||||
@ -887,11 +908,23 @@ This is a Heirloom extension and currently ignored.
|
||||
Enable or disable an OpenType feature.
|
||||
This is a Heirloom extension and currently ignored.
|
||||
.It Ic \&fi
|
||||
Switch to fill mode.
|
||||
See
|
||||
.Xr man 7 .
|
||||
Ignored in
|
||||
.Xr mdoc 7 .
|
||||
Break the output line and switch to fill mode,
|
||||
which is active by default but can be ended with the
|
||||
.Ic \&nf
|
||||
request.
|
||||
In fill mode, input from subsequent input lines is added to
|
||||
the same output line until the next word no longer fits,
|
||||
at which point the output line is broken.
|
||||
This request is implied by the
|
||||
.Xr mdoc 7
|
||||
.Ic \&Sh
|
||||
macro and by the
|
||||
.Xr man 7
|
||||
.Ic \&SH ,
|
||||
.Ic \&SS ,
|
||||
and
|
||||
.Ic \&EE
|
||||
macros.
|
||||
.It Ic \&fkern Ar font minkern
|
||||
Control the use of kerning tables for a font.
|
||||
This is a Heirloom extension and currently ignored.
|
||||
@ -917,27 +950,12 @@ This is a Heirloom extension and currently ignored.
|
||||
Conditionally define a special font.
|
||||
This is a groff extension and currently ignored.
|
||||
.It Ic \&ft Op Ar font
|
||||
Change the font.
|
||||
The following
|
||||
Change the font; see
|
||||
.Sx Font Selection .
|
||||
The
|
||||
.Ar font
|
||||
arguments are supported:
|
||||
.Bl -tag -width 4n -offset indent
|
||||
.It Cm B , BI , 3 , 4
|
||||
switches to
|
||||
.Sy bold
|
||||
font
|
||||
.It Cm I , 2
|
||||
switches to
|
||||
.Em underlined
|
||||
font
|
||||
.It Cm R , CW , 1
|
||||
switches to normal font
|
||||
.It Cm P No "or no argument"
|
||||
switches back to the previous font
|
||||
.El
|
||||
.Pp
|
||||
This request takes effect only locally and may be overridden
|
||||
by macros and escape sequences.
|
||||
argument defaults to
|
||||
.Cm P .
|
||||
.It Ic \&ftr Ar newname Op Ar oldname
|
||||
Translate font name.
|
||||
This is a groff extension and currently ignored.
|
||||
@ -1037,13 +1055,13 @@ is
|
||||
or
|
||||
.Sq o
|
||||
.Pq odd page ,
|
||||
it evaluates to true.
|
||||
it evaluates to true, and the
|
||||
.Ar body
|
||||
starts with the next character.
|
||||
.It
|
||||
If the first character of
|
||||
.Ar condition
|
||||
is
|
||||
.Sq c
|
||||
.Pq character available ,
|
||||
.Sq e
|
||||
.Pq even page ,
|
||||
.Sq t
|
||||
@ -1051,7 +1069,20 @@ is
|
||||
or
|
||||
.Sq v
|
||||
.Pq vroff mode ,
|
||||
it evaluates to false.
|
||||
it evaluates to false, and the
|
||||
.Ar body
|
||||
starts with the next character.
|
||||
.It
|
||||
If the first character of
|
||||
.Ar condition
|
||||
is
|
||||
.Sq c
|
||||
.Pq character available ,
|
||||
it evaluates to true if the following character is an ASCII character
|
||||
or a valid character escape sequence, or to false otherwise.
|
||||
The
|
||||
.Ar body
|
||||
starts with the character following that next character.
|
||||
.It
|
||||
If the first character of
|
||||
.Ar condition
|
||||
@ -1219,7 +1250,7 @@ While evaluating the
|
||||
the unit suffixes described below
|
||||
.Sx Scaling Widths
|
||||
are ignored.
|
||||
.It Ic \&it Ar expression macro
|
||||
.It Ic \&itc Ar expression macro
|
||||
Set an input line trap, not counting lines ending with \ec.
|
||||
Currently unsupported.
|
||||
.It Ic \&IX Ar class keystring
|
||||
@ -1328,11 +1359,22 @@ Declare the need for the specified minimum vertical space
|
||||
before the next trap or the bottom of the page.
|
||||
Currently ignored.
|
||||
.It Ic \&nf
|
||||
Switch to no-fill mode.
|
||||
See
|
||||
.Xr man 7 .
|
||||
Ignored by
|
||||
.Xr mdoc 7 .
|
||||
Break the output line and switch to no-fill mode.
|
||||
Subsequent input lines are kept together on the same output line
|
||||
even when exceeding the right margin,
|
||||
and line breaks in subsequent input cause output line breaks.
|
||||
This request is implied by the
|
||||
.Xr mdoc 7
|
||||
.Ic \&Bd Fl unfilled
|
||||
and
|
||||
.Ic \&Bd Fl literal
|
||||
macros and by the
|
||||
.Xr man 7
|
||||
.Ic \&EX
|
||||
macro.
|
||||
The
|
||||
.Ic \&fi
|
||||
request switches back to the default fill mode.
|
||||
.It Ic \&nh
|
||||
Turn off automatic hyphenation mode.
|
||||
Currently ignored.
|
||||
@ -1346,8 +1388,11 @@ Currently unsupported.
|
||||
Temporarily turn off line numbering.
|
||||
Currently unsupported.
|
||||
.It Ic \&nop Ar body
|
||||
Execute the rest of the input line as a request or macro line.
|
||||
Currently unsupported.
|
||||
Execute the rest of the input line as a request, macro, or text line,
|
||||
skipping the
|
||||
.Ic \&nop
|
||||
request and any space characters immediately following it.
|
||||
This is mostly used to indent text lines inside macro definitions.
|
||||
.It Ic \&nr Ar register Oo Cm + Ns | Ns Cm - Oc Ns Ar expression Op Ar stepsize
|
||||
Define or change a register.
|
||||
A register is an arbitrary string value that defines some sort of state,
|
||||
@ -1486,8 +1531,8 @@ Currently ignored.
|
||||
Set the maximum stack depth for recursive macros.
|
||||
This is a Heirloom extension and currently ignored.
|
||||
.It Ic \&return Op Ar twice
|
||||
Exit a macro and return to the caller.
|
||||
Currently unsupported.
|
||||
Exit the presently executed macro and return to the caller.
|
||||
The argument is currently ignored.
|
||||
.It Ic \&rfschar Ar font glyph ...
|
||||
Remove font-specific fallback glyph definitions.
|
||||
Currently unsupported.
|
||||
@ -1536,8 +1581,11 @@ This is a Heirloom extension and currently ignored.
|
||||
Change the soft hyphen character.
|
||||
Currently ignored.
|
||||
.It Ic \&shift Op Ar number
|
||||
Shift macro arguments.
|
||||
Currently unsupported.
|
||||
Shift macro arguments
|
||||
.Ar number
|
||||
times, by default once: \e\e$i becomes what \e\e$i+number was.
|
||||
Also decrement \en(.$ by
|
||||
.Ar number .
|
||||
.It Ic \&sizes Ar size ...
|
||||
Define permissible point sizes.
|
||||
This is a groff extension and currently ignored.
|
||||
@ -1602,7 +1650,7 @@ Ignored because insecure.
|
||||
Re-start a table layout, retaining the options of the prior table
|
||||
invocation.
|
||||
See
|
||||
.Sx \&TS .
|
||||
.Ic \&TS .
|
||||
.It Ic \&ta Op Ar width ... Op Cm T Ar width ...
|
||||
Set tab stops.
|
||||
Each
|
||||
@ -1623,7 +1671,7 @@ Currently unsupported.
|
||||
.It Ic \&TE
|
||||
End a table context.
|
||||
See
|
||||
.Sx \&TS .
|
||||
.Ic \&TS .
|
||||
.It Ic \&ti Oo Cm + Ns | Ns Cm - Oc Ns Ar width
|
||||
Break the output line and indent the next output line by
|
||||
.Ar width .
|
||||
@ -1726,8 +1774,12 @@ This is a Heirloom extension and currently ignored.
|
||||
Set a page location trap.
|
||||
Currently unsupported.
|
||||
.It Ic \&while Ar condition body
|
||||
Repeated execution while a condition is true.
|
||||
Currently unsupported.
|
||||
Repeated execution while a
|
||||
.Ar condition
|
||||
is true, with syntax similar to
|
||||
.Ic \&if .
|
||||
Currently implemented with two restrictions: cannot nest,
|
||||
and each loop must start and end in the same scope.
|
||||
.It Ic \&write Oo \(dq Oc Ns Ar string
|
||||
Write to an open file.
|
||||
Ignored because insecure.
|
||||
@ -1743,10 +1795,10 @@ This is a Heirloom extension and currently ignored.
|
||||
.El
|
||||
.Ss Numerical expressions
|
||||
The
|
||||
.Sx \&nr ,
|
||||
.Sx \&if ,
|
||||
.Ic \&nr ,
|
||||
.Ic \&if ,
|
||||
and
|
||||
.Sx \&ie
|
||||
.Ic \&ie
|
||||
requests accept integer numerical expressions as arguments.
|
||||
These are always evaluated using the C
|
||||
.Vt int
|
||||
@ -1821,10 +1873,6 @@ The
|
||||
.Xr mandoc 1
|
||||
.Nm
|
||||
parser recognises the following escape sequences.
|
||||
Note that the
|
||||
.Nm
|
||||
language defines more escape sequences not implemented in
|
||||
.Xr mandoc 1 .
|
||||
In
|
||||
.Xr mdoc 7
|
||||
and
|
||||
@ -1836,228 +1884,315 @@ section above.
|
||||
.Pp
|
||||
A backslash followed by any character not listed here
|
||||
simply prints that character itself.
|
||||
.Ss \e<newline>
|
||||
.Bl -tag -width Ds
|
||||
.It Ic \e<newline>
|
||||
A backslash at the end of an input line can be used to continue the
|
||||
logical input line on the next physical input line, joining the text
|
||||
on both lines together as if it were on a single input line.
|
||||
.Ss \e<space>
|
||||
.It Ic \e<space>
|
||||
The escape sequence backslash-space
|
||||
.Pq Sq \e\ \&
|
||||
is an unpaddable space-sized non-breaking space character; see
|
||||
.Sx Whitespace .
|
||||
.Ss \e\(dq
|
||||
.Sx Whitespace
|
||||
and
|
||||
.Xr mandoc_char 7 .
|
||||
.It Ic \e!
|
||||
Embed text up to and including the end of the input line into the
|
||||
current diversion or into intermediate output without interpreting
|
||||
requests, macros, and escapes.
|
||||
Currently unsupported.
|
||||
.It Ic \e\(dq
|
||||
The rest of the input line is treated as
|
||||
.Sx Comments .
|
||||
.Ss \e%
|
||||
.It Ic \e#
|
||||
Line continuation with comment.
|
||||
Discard the rest of the physical input line and continue the logical
|
||||
input line on the next physical input line, joining the text on
|
||||
both lines together as if it were on a single input line.
|
||||
This is a groff extension.
|
||||
.It Ic \e$ Ns Ar arg
|
||||
Macro argument expansion, see
|
||||
.Ic \&de .
|
||||
.It Ic \e%
|
||||
Hyphenation allowed at this point of the word; ignored by
|
||||
.Xr mandoc 1 .
|
||||
.Ss \e&
|
||||
Non-printing zero-width character; see
|
||||
.Sx Whitespace .
|
||||
.Ss \e\(aq
|
||||
.It Ic \e&
|
||||
Non-printing zero-width character,
|
||||
often used for various kinds of escaping; see
|
||||
.Sx Whitespace ,
|
||||
.Xr mandoc_char 7 ,
|
||||
and the
|
||||
.Dq MACRO SYNTAX
|
||||
and
|
||||
.Dq Delimiters
|
||||
sections in
|
||||
.Xr mdoc 7 .
|
||||
.It Ic \e\(aq
|
||||
Acute accent special character; use
|
||||
.Sq \e(aa
|
||||
.Ic \e(aa
|
||||
instead.
|
||||
.Ss \e( Ns Ar cc
|
||||
.It Ic \e( Ns Ar cc
|
||||
.Sx Special Characters
|
||||
with two-letter names, see
|
||||
.Xr mandoc_char 7 .
|
||||
.Ss \e* Ns Bq Ar name
|
||||
.It Ic \e)
|
||||
Zero-width space transparent to end-of-sentence detection;
|
||||
ignored by
|
||||
.Xr mandoc 1 .
|
||||
.It Ic \e*[ Ns Ar name Ns Ic \&]
|
||||
Interpolate the string with the
|
||||
.Ar name ;
|
||||
see
|
||||
.Sx Predefined Strings
|
||||
and
|
||||
.Sx ds .
|
||||
.Ar name .
|
||||
For short names, there are variants
|
||||
.No \e* Ns Ar c
|
||||
.Ic \e* Ns Ar c
|
||||
and
|
||||
.No \e*( Ns Ar cc .
|
||||
.Ss \e,
|
||||
.Ic \e*( Ns Ar cc .
|
||||
.Pp
|
||||
One string is predefined on the
|
||||
.Nm
|
||||
language level:
|
||||
.Ic \e*(.T
|
||||
expands to the name of the output device,
|
||||
for example ascii, utf8, ps, pdf, html, or markdown.
|
||||
.Pp
|
||||
Macro sets traditionally predefine additional strings which are not
|
||||
portable and differ across implementations.
|
||||
Those supported by
|
||||
.Xr mandoc 1
|
||||
are listed in
|
||||
.Xr mandoc_char 7 .
|
||||
.Pp
|
||||
Strings can be defined, changed, and deleted with the
|
||||
.Ic \&ds ,
|
||||
.Ic \&as ,
|
||||
and
|
||||
.Ic \&rm
|
||||
requests.
|
||||
.It Ic \e,
|
||||
Left italic correction (groff extension); ignored by
|
||||
.Xr mandoc 1 .
|
||||
.Ss \e-
|
||||
.It Ic \e-
|
||||
Special character
|
||||
.Dq mathematical minus sign .
|
||||
.Ss \e/
|
||||
.Dq mathematical minus sign ;
|
||||
see
|
||||
.Xr mandoc_char 7
|
||||
for details.
|
||||
.It Ic \e/
|
||||
Right italic correction (groff extension); ignored by
|
||||
.Xr mandoc 1 .
|
||||
.Ss \e Ns Bq Ar name
|
||||
.It Ic \e:
|
||||
Breaking the line is allowed at this point of the word
|
||||
without inserting a hyphen.
|
||||
.It Ic \e?
|
||||
Embed the text up to the next
|
||||
.Ic \e?
|
||||
into the current diversion without interpreting requests, macros,
|
||||
and escapes.
|
||||
This is a groff extension and currently unsupported.
|
||||
.It Ic \e[ Ns Ar name Ns Ic \&]
|
||||
.Sx Special Characters
|
||||
with names of arbitrary length, see
|
||||
.Xr mandoc_char 7 .
|
||||
.Ss \e^
|
||||
.It Ic \e^
|
||||
One-twelfth em half-narrow space character, effectively zero-width in
|
||||
.Xr mandoc 1 .
|
||||
.Ss \e`
|
||||
Grave accent special character; use
|
||||
.Sq \e(ga
|
||||
.It Ic \e_
|
||||
Underline special character; use
|
||||
.Ic \e(ul
|
||||
instead.
|
||||
.Ss \e{
|
||||
.It Ic \e`
|
||||
Grave accent special character; use
|
||||
.Ic \e(ga
|
||||
instead.
|
||||
.It Ic \e{
|
||||
Begin conditional input; see
|
||||
.Sx if .
|
||||
.Ss \e\(ba
|
||||
.Ic \&if .
|
||||
.It Ic \e\(ba
|
||||
One-sixth em narrow space character, effectively zero-width in
|
||||
.Xr mandoc 1 .
|
||||
.Ss \e}
|
||||
.It Ic \e}
|
||||
End conditional input; see
|
||||
.Sx if .
|
||||
.Ss \e~
|
||||
.Ic \&if .
|
||||
.It Ic \e~
|
||||
Paddable non-breaking space character.
|
||||
.Ss \e0
|
||||
.It Ic \e0
|
||||
Digit width space character.
|
||||
.Ss \eA\(aq Ns Ar string Ns \(aq
|
||||
.It Ic \eA\(aq Ns Ar string Ns Ic \(aq
|
||||
Anchor definition; ignored by
|
||||
.Xr mandoc 1 .
|
||||
.Ss \eB\(aq Ns Ar string Ns \(aq
|
||||
.It Ic \ea
|
||||
Leader character; ignored by
|
||||
.Xr mandoc 1 .
|
||||
.It Ic \eB\(aq Ns Ar string Ns Ic \(aq
|
||||
Interpolate
|
||||
.Sq 1
|
||||
if
|
||||
.Ar string
|
||||
conforms to the syntax of
|
||||
.Sx Numerical expressions
|
||||
explained above and
|
||||
explained above or
|
||||
.Sq 0
|
||||
otherwise.
|
||||
.Ss \eb\(aq Ns Ar string Ns \(aq
|
||||
.It Ic \eb\(aq Ns Ar string Ns Ic \(aq
|
||||
Bracket building function; ignored by
|
||||
.Xr mandoc 1 .
|
||||
.Ss \eC\(aq Ns Ar name Ns \(aq
|
||||
.It Ic \eC\(aq Ns Ar name Ns Ic \(aq
|
||||
.Sx Special Characters
|
||||
with names of arbitrary length.
|
||||
.Ss \ec
|
||||
.It Ic \ec
|
||||
When encountered at the end of an input text line,
|
||||
the next input text line is considered to continue that line,
|
||||
even if there are request or macro lines in between.
|
||||
No whitespace is inserted.
|
||||
.Ss \eD\(aq Ns Ar string Ns \(aq
|
||||
.It Ic \eD\(aq Ns Ar string Ns Ic \(aq
|
||||
Draw graphics function; ignored by
|
||||
.Xr mandoc 1 .
|
||||
.Ss \ed
|
||||
.It Ic \ed
|
||||
Move down by half a line; ignored by
|
||||
.Xr mandoc 1 .
|
||||
.Ss \ee
|
||||
.It Ic \eE
|
||||
Escape character intended to not be interpreted in copy mode.
|
||||
In
|
||||
.Xr mandoc 1 ,
|
||||
it currently does the same as
|
||||
.Ic \e
|
||||
itself.
|
||||
.It Ic \ee
|
||||
Backslash special character.
|
||||
.Ss \eF Ns Bq Ar name
|
||||
.It Ic \eF[ Ns Ar name Ns Ic \&]
|
||||
Switch font family (groff extension); ignored by
|
||||
.Xr mandoc 1 .
|
||||
For short names, there are variants
|
||||
.No \eF Ns Ar c
|
||||
.Ic \eF Ns Ar c
|
||||
and
|
||||
.No \eF( Ns Ar cc .
|
||||
.Ss \ef Ns Bq Ar name
|
||||
.Ic \eF( Ns Ar cc .
|
||||
.It Ic \ef[ Ns Ar name Ns Ic \&]
|
||||
Switch to the font
|
||||
.Ar name ,
|
||||
see
|
||||
.Sx Text Decoration .
|
||||
.Sx Font Selection .
|
||||
For short names, there are variants
|
||||
.No \ef Ns Ar c
|
||||
.Ic \ef Ns Ar c
|
||||
and
|
||||
.No \ef( Ns Ar cc .
|
||||
.Ss \eg Ns Bq Ar name
|
||||
.Ic \ef( Ns Ar cc .
|
||||
An empty name
|
||||
.Ic \ef[]
|
||||
defaults to
|
||||
.Ic \efP .
|
||||
.It Ic \eg[ Ns Ar name Ns Ic \&]
|
||||
Interpolate the format of a number register; ignored by
|
||||
.Xr mandoc 1 .
|
||||
For short names, there are variants
|
||||
.No \eg Ns Ar c
|
||||
.Ic \eg Ns Ar c
|
||||
and
|
||||
.No \eg( Ns Ar cc .
|
||||
.Ss \eH\(aq Ns Oo +|- Oc Ns Ar number Ns \(aq
|
||||
.Ic \eg( Ns Ar cc .
|
||||
.It Ic \eH\(aq Ns Oo +|- Oc Ns Ar number Ns Ic \(aq
|
||||
Set the height of the current font; ignored by
|
||||
.Xr mandoc 1 .
|
||||
.Ss \eh\(aq Ns Oo Cm \&| Oc Ns Ar width Ns \(aq
|
||||
.It Ic \eh\(aq Ns Oo Cm \&| Oc Ns Ar width Ns Ic \(aq
|
||||
Horizontal motion.
|
||||
If the vertical bar is given, the motion is relative to the current
|
||||
indentation.
|
||||
Otherwise, it is relative to the current position.
|
||||
The default scaling unit is
|
||||
.Cm m .
|
||||
.Ss \ek Ns Bq Ar name
|
||||
.It Ic \ek[ Ns Ar name Ns Ic \&]
|
||||
Mark horizontal input place in register; ignored by
|
||||
.Xr mandoc 1 .
|
||||
For short names, there are variants
|
||||
.No \ek Ns Ar c
|
||||
.Ic \ek Ns Ar c
|
||||
and
|
||||
.No \ek( Ns Ar cc .
|
||||
.Ss \eL\(aq Ns Ar number Ns Oo Ar c Oc Ns \(aq
|
||||
.Ic \ek( Ns Ar cc .
|
||||
.It Ic \eL\(aq Ns Ar number Ns Oo Ar c Oc Ns Ic \(aq
|
||||
Vertical line drawing function; ignored by
|
||||
.Xr mandoc 1 .
|
||||
.Ss \el\(aq Ns Ar width Ns Oo Ar c Oc Ns \(aq
|
||||
.It Ic \el\(aq Ns Ar width Ns Oo Ar c Oc Ns Ic \(aq
|
||||
Draw a horizontal line of
|
||||
.Ar width
|
||||
using the glyph
|
||||
.Ar c .
|
||||
.Ss \eM Ns Bq Ar name
|
||||
.It Ic \eM[ Ns Ar name Ns Ic \&]
|
||||
Set fill (background) color (groff extension); ignored by
|
||||
.Xr mandoc 1 .
|
||||
For short names, there are variants
|
||||
.No \eM Ns Ar c
|
||||
.Ic \eM Ns Ar c
|
||||
and
|
||||
.No \eM( Ns Ar cc .
|
||||
.Ss \em Ns Bq Ar name
|
||||
.Ic \eM( Ns Ar cc .
|
||||
.It Ic \em[ Ns Ar name Ns Ic \&]
|
||||
Set glyph drawing color (groff extension); ignored by
|
||||
.Xr mandoc 1 .
|
||||
For short names, there are variants
|
||||
.No \em Ns Ar c
|
||||
.Ic \em Ns Ar c
|
||||
and
|
||||
.No \em( Ns Ar cc .
|
||||
.Ss \eN\(aq Ns Ar number Ns \(aq
|
||||
.Ic \em( Ns Ar cc .
|
||||
.It Ic \eN\(aq Ns Ar number Ns Ic \(aq
|
||||
Character
|
||||
.Ar number
|
||||
on the current font.
|
||||
.Ss \en Ns Oo +|- Oc Ns Bq Ar name
|
||||
.It Ic \en Ns Oo +|- Oc Ns Ic \&[ Ns Ar name Ns Ic \&]
|
||||
Interpolate the number register
|
||||
.Ar name .
|
||||
For short names, there are variants
|
||||
.No \en Ns Ar c
|
||||
.Ic \en Ns Ar c
|
||||
and
|
||||
.No \en( Ns Ar cc .
|
||||
.Ic \en( Ns Ar cc .
|
||||
If the optional sign is specified,
|
||||
the register is first incremented or decremented by the
|
||||
.Ar stepsize
|
||||
that was specified in the relevant
|
||||
.Ic \&nr
|
||||
request, and the changed value is interpolated.
|
||||
.Ss \eo\(aq Ns Ar string Ns \(aq
|
||||
.It Ic \eO Ns Ar digit , Ic \eO[5 Ns arguments Ns Ic \&]
|
||||
Suppress output.
|
||||
This is a groff extension and currently unsupported.
|
||||
With an argument of
|
||||
.Ic 1 , 2 , 3 ,
|
||||
or
|
||||
.Ic 4 ,
|
||||
it is ignored.
|
||||
.It Ic \eo\(aq Ns Ar string Ns Ic \(aq
|
||||
Overstrike, writing all the characters contained in the
|
||||
.Ar string
|
||||
to the same output position.
|
||||
In terminal and HTML output modes,
|
||||
only the last one of the characters is visible.
|
||||
.Ss \ep
|
||||
.It Ic \ep
|
||||
Break the output line at the end of the current word.
|
||||
.Ss \eR\(aq Ns Ar name Oo +|- Oc Ns Ar number Ns \(aq
|
||||
.It Ic \eR\(aq Ns Ar name Oo +|- Oc Ns Ar number Ns Ic \(aq
|
||||
Set number register; ignored by
|
||||
.Xr mandoc 1 .
|
||||
.Ss \eS\(aq Ns Ar number Ns \(aq
|
||||
.It Ic \er
|
||||
Move up by one line; ignored by
|
||||
.Xr mandoc 1 .
|
||||
.It Ic \eS\(aq Ns Ar number Ns Ic \(aq
|
||||
Slant output; ignored by
|
||||
.Xr mandoc 1 .
|
||||
.Ss \es\(aq Ns Oo +|- Oc Ns Ar number Ns \(aq
|
||||
.It Ic \es\(aq Ns Oo +|- Oc Ns Ar number Ns Ic \(aq
|
||||
Change point size; ignored by
|
||||
.Xr mandoc 1 .
|
||||
Alternative forms
|
||||
.No \es Ns Oo +|- Oc Ns Ar n ,
|
||||
.No \es Ns Oo +|- Oc Ns \(aq Ns Ar number Ns \(aq ,
|
||||
.No \es Ns Bq Oo +|- Oc Ns Ar number ,
|
||||
.Ic \es Ns Oo +|- Oc Ns Ar n ,
|
||||
.Ic \es Ns Oo +|- Oc Ns Ic \(aq Ns Ar number Ns Ic \(aq ,
|
||||
.Ic \es[ Ns Oo +|- Oc Ns Ar number Ns Ic \&] ,
|
||||
and
|
||||
.No \es Ns Oo +|- Oc Ns Bq Ar number
|
||||
.Ic \es Ns Oo +|- Oc Ns Ic \&[ Ns Ar number Ns Ic \&]
|
||||
are also parsed and ignored.
|
||||
.Ss \et
|
||||
.It Ic \et
|
||||
Horizontal tab; ignored by
|
||||
.Xr mandoc 1 .
|
||||
.Ss \eu
|
||||
.It Ic \eu
|
||||
Move up by half a line; ignored by
|
||||
.Xr mandoc 1 .
|
||||
.Ss \eV Ns Bq Ar name
|
||||
.It Ic \eV[ Ns Ar name Ns Ic \&]
|
||||
Interpolate an environment variable; ignored by
|
||||
.Xr mandoc 1 .
|
||||
For short names, there are variants
|
||||
.No \eV Ns Ar c
|
||||
.Ic \eV Ns Ar c
|
||||
and
|
||||
.No \eV( Ns Ar cc .
|
||||
.Ss \ev\(aq Ns Ar number Ns \(aq
|
||||
.Ic \eV( Ns Ar cc .
|
||||
.It Ic \ev\(aq Ns Ar number Ns Ic \(aq
|
||||
Vertical motion; ignored by
|
||||
.Xr mandoc 1 .
|
||||
.Ss \ew\(aq Ns Ar string Ns \(aq
|
||||
.It Ic \ew\(aq Ns Ar string Ns Ic \(aq
|
||||
Interpolate the width of the
|
||||
.Ar string .
|
||||
The
|
||||
@ -2066,49 +2201,49 @@ implementation assumes that after expansion of user-defined strings, the
|
||||
.Ar string
|
||||
only contains normal characters, no escape sequences, and that each
|
||||
character has a width of 24 basic units.
|
||||
.Ss \eX\(aq Ns Ar string Ns \(aq
|
||||
.It Ic \eX\(aq Ns Ar string Ns Ic \(aq
|
||||
Output
|
||||
.Ar string
|
||||
as device control function; ignored in nroff mode and by
|
||||
.Xr mandoc 1 .
|
||||
.Ss \ex\(aq Ns Ar number Ns \(aq
|
||||
.It Ic \ex\(aq Ns Ar number Ns Ic \(aq
|
||||
Extra line space function; ignored by
|
||||
.Xr mandoc 1 .
|
||||
.Ss \eY Ns Bq Ar name
|
||||
.It Ic \eY[ Ns Ar name Ns Ic \&]
|
||||
Output a string as a device control function; ignored in nroff mode and by
|
||||
.Xr mandoc 1 .
|
||||
For short names, there are variants
|
||||
.No \eY Ns Ar c
|
||||
.Ic \eY Ns Ar c
|
||||
and
|
||||
.No \eY( Ns Ar cc .
|
||||
.Ss \eZ\(aq Ns Ar string Ns \(aq
|
||||
.Ic \eY( Ns Ar cc .
|
||||
.It Ic \eZ\(aq Ns Ar string Ns Ic \(aq
|
||||
Print
|
||||
.Ar string
|
||||
with zero width and height; ignored by
|
||||
.Xr mandoc 1 .
|
||||
.Ss \ez
|
||||
.It Ic \ez
|
||||
Output the next character without advancing the cursor position.
|
||||
.El
|
||||
.Sh COMPATIBILITY
|
||||
The
|
||||
.Xr mandoc 1
|
||||
implementation of the
|
||||
.Nm
|
||||
language is intentionally incomplete.
|
||||
Unimplemented features include:
|
||||
language is incomplete.
|
||||
Major unimplemented features include:
|
||||
.Pp
|
||||
.Bl -dash -compact
|
||||
.It
|
||||
For security reasons,
|
||||
.Xr mandoc 1
|
||||
never reads or writes external files except via
|
||||
.Sx \&so
|
||||
.Ic \&so
|
||||
requests with safe relative paths.
|
||||
.It
|
||||
There is no automatic hyphenation, no adjustment to the right margin,
|
||||
and no centering; the output is always set flush-left.
|
||||
and very limited support for centering; the output is always set flush-left.
|
||||
.It
|
||||
Support for setting tabulator positions
|
||||
and tabulator and leader characters is missing,
|
||||
Support for setting tabulator and leader characters is missing,
|
||||
and support for manually changing indentation is limited.
|
||||
.It
|
||||
The
|
||||
@ -2119,14 +2254,14 @@ output media.
|
||||
.It
|
||||
Width measurements are implemented in a crude way
|
||||
and often yield wrong results.
|
||||
Explicit movement requests and escapes are ignored.
|
||||
Support for explicit movement requests and escapes is limited.
|
||||
.It
|
||||
There is no concept of output pages, no support for floats,
|
||||
graphics drawing, and picture inclusion;
|
||||
terminal output is always continuous.
|
||||
.It
|
||||
Requests regarding color, font families, and glyph manipulation
|
||||
are ignored.
|
||||
Requests regarding color, font families, font sizes,
|
||||
and glyph manipulation are ignored.
|
||||
Font support is very limited.
|
||||
Kerning is not implemented, and no ligatures are produced.
|
||||
.It
|
||||
@ -2134,12 +2269,12 @@ The
|
||||
.Qq \(aq
|
||||
macro control character does not suppress output line breaks.
|
||||
.It
|
||||
Diversions are not implemented,
|
||||
Diversions and environments are not implemented,
|
||||
and support for traps is very incomplete.
|
||||
.It
|
||||
While recursion is supported,
|
||||
.Sx \&while
|
||||
loops are not.
|
||||
Use of macros is not supported inside
|
||||
.Xr tbl 7
|
||||
code.
|
||||
.El
|
||||
.Pp
|
||||
The special semantics of the
|
||||
|
86
roff.h
86
roff.h
@ -1,7 +1,7 @@
|
||||
/* $Id: roff.h,v 1.59 2018/04/11 17:11:13 schwarze Exp $ */
|
||||
/* $Id: roff.h,v 1.69 2019/03/04 13:01:57 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* 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,11 +14,15 @@
|
||||
* 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 data types for all syntax trees and related functions.
|
||||
*/
|
||||
|
||||
struct ohash;
|
||||
struct mdoc_arg;
|
||||
union mdoc_data;
|
||||
struct tbl_span;
|
||||
struct eqn_box;
|
||||
|
||||
enum roff_macroset {
|
||||
MACROSET_NONE = 0,
|
||||
@ -69,9 +73,11 @@ enum roff_type {
|
||||
enum roff_tok {
|
||||
ROFF_br = 0,
|
||||
ROFF_ce,
|
||||
ROFF_fi,
|
||||
ROFF_ft,
|
||||
ROFF_ll,
|
||||
ROFF_mc,
|
||||
ROFF_nf,
|
||||
ROFF_po,
|
||||
ROFF_rj,
|
||||
ROFF_sp,
|
||||
@ -156,7 +162,6 @@ enum roff_tok {
|
||||
ROFF_fcolor,
|
||||
ROFF_fdeferlig,
|
||||
ROFF_feature,
|
||||
/* MAN_fi; ignored in mdoc(7) */
|
||||
ROFF_fkern,
|
||||
ROFF_fl,
|
||||
ROFF_flig,
|
||||
@ -216,7 +221,6 @@ enum roff_tok {
|
||||
ROFF_mso,
|
||||
ROFF_na,
|
||||
ROFF_ne,
|
||||
/* MAN_nf; ignored in mdoc(7) */
|
||||
ROFF_nh,
|
||||
ROFF_nhychar,
|
||||
ROFF_nm,
|
||||
@ -438,6 +442,7 @@ enum roff_tok {
|
||||
MAN_SH,
|
||||
MAN_SS,
|
||||
MAN_TP,
|
||||
MAN_TQ,
|
||||
MAN_LP,
|
||||
MAN_PP,
|
||||
MAN_P,
|
||||
@ -454,8 +459,6 @@ enum roff_tok {
|
||||
MAN_I,
|
||||
MAN_IR,
|
||||
MAN_RI,
|
||||
MAN_nf,
|
||||
MAN_fi,
|
||||
MAN_RE,
|
||||
MAN_RS,
|
||||
MAN_DT,
|
||||
@ -463,6 +466,8 @@ enum roff_tok {
|
||||
MAN_PD,
|
||||
MAN_AT,
|
||||
MAN_in,
|
||||
MAN_SY,
|
||||
MAN_YS,
|
||||
MAN_OP,
|
||||
MAN_EX,
|
||||
MAN_EE,
|
||||
@ -473,11 +478,6 @@ enum roff_tok {
|
||||
MAN_MAX
|
||||
};
|
||||
|
||||
enum roff_next {
|
||||
ROFF_NEXT_SIBLING = 0,
|
||||
ROFF_NEXT_CHILD
|
||||
};
|
||||
|
||||
/*
|
||||
* Indicates that a BODY's formatting has ended, but
|
||||
* the scope is still open. Used for badly nested blocks.
|
||||
@ -487,6 +487,12 @@ enum mdoc_endbody {
|
||||
ENDBODY_SPACE /* Is broken: append a space. */
|
||||
};
|
||||
|
||||
enum mandoc_os {
|
||||
MANDOC_OS_OTHER = 0,
|
||||
MANDOC_OS_NETBSD,
|
||||
MANDOC_OS_OPENBSD
|
||||
};
|
||||
|
||||
struct roff_node {
|
||||
struct roff_node *parent; /* Parent AST node. */
|
||||
struct roff_node *child; /* First child AST node. */
|
||||
@ -499,21 +505,22 @@ struct roff_node {
|
||||
struct mdoc_arg *args; /* BLOCK/ELEM */
|
||||
union mdoc_data *norm; /* Normalized arguments. */
|
||||
char *string; /* TEXT */
|
||||
const struct tbl_span *span; /* TBL */
|
||||
struct tbl_span *span; /* TBL */
|
||||
struct eqn_box *eqn; /* EQN */
|
||||
int line; /* Input file line number. */
|
||||
int pos; /* Input file column number. */
|
||||
int flags;
|
||||
#define NODE_VALID (1 << 0) /* Has been validated. */
|
||||
#define NODE_ENDED (1 << 1) /* Gone past body end mark. */
|
||||
#define NODE_EOS (1 << 2) /* At sentence boundary. */
|
||||
#define NODE_BROKEN (1 << 2) /* Must validate parent when ending. */
|
||||
#define NODE_LINE (1 << 3) /* First macro/text on line. */
|
||||
#define NODE_SYNPRETTY (1 << 4) /* SYNOPSIS-style formatting. */
|
||||
#define NODE_BROKEN (1 << 5) /* Must validate parent when ending. */
|
||||
#define NODE_DELIMO (1 << 6)
|
||||
#define NODE_DELIMC (1 << 7)
|
||||
#define NODE_NOSRC (1 << 8) /* Generated node, not in input file. */
|
||||
#define NODE_NOPRT (1 << 9) /* Shall not print anything. */
|
||||
#define NODE_DELIMO (1 << 4)
|
||||
#define NODE_DELIMC (1 << 5)
|
||||
#define NODE_EOS (1 << 6) /* At sentence boundary. */
|
||||
#define NODE_SYNPRETTY (1 << 7) /* SYNOPSIS-style formatting. */
|
||||
#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. */
|
||||
int prev_font; /* Before entering this node. */
|
||||
int aux; /* Decoded node data, type-dependent. */
|
||||
enum roff_tok tok; /* Request or macro ID. */
|
||||
@ -523,6 +530,7 @@ struct roff_node {
|
||||
};
|
||||
|
||||
struct roff_meta {
|
||||
struct roff_node *first; /* The first node parsed. */
|
||||
char *msec; /* Manual section, usually a digit. */
|
||||
char *vol; /* Manual volume title. */
|
||||
char *os; /* Operating system. */
|
||||
@ -530,51 +538,15 @@ struct roff_meta {
|
||||
char *title; /* Manual title, usually CAPS. */
|
||||
char *name; /* Leading manual name. */
|
||||
char *date; /* Normalized date. */
|
||||
char *sodest; /* .so target file name or NULL. */
|
||||
int hasbody; /* Document is not empty. */
|
||||
int rcsids; /* Bits indexed by enum mandoc_os. */
|
||||
enum mandoc_os os_e; /* Operating system. */
|
||||
};
|
||||
|
||||
struct roff_man {
|
||||
struct roff_meta meta; /* Document meta-data. */
|
||||
struct mparse *parse; /* Parse pointer. */
|
||||
struct roff *roff; /* Roff parser state data. */
|
||||
struct ohash *mdocmac; /* Mdoc macro lookup table. */
|
||||
struct ohash *manmac; /* Man macro lookup table. */
|
||||
const char *os_s; /* Default operating system. */
|
||||
struct roff_node *first; /* The first node parsed. */
|
||||
struct roff_node *last; /* The last node parsed. */
|
||||
struct roff_node *last_es; /* The most recent Es node. */
|
||||
int quick; /* Abort parse early. */
|
||||
int flags; /* Parse flags. */
|
||||
#define MDOC_LITERAL (1 << 1) /* In a literal scope. */
|
||||
#define MDOC_PBODY (1 << 2) /* In the document body. */
|
||||
#define MDOC_NEWLINE (1 << 3) /* First macro/text in a line. */
|
||||
#define MDOC_PHRASE (1 << 4) /* In a Bl -column phrase. */
|
||||
#define MDOC_PHRASELIT (1 << 5) /* Literal within a phrase. */
|
||||
#define MDOC_FREECOL (1 << 6) /* `It' invocation should close. */
|
||||
#define MDOC_SYNOPSIS (1 << 7) /* SYNOPSIS-style formatting. */
|
||||
#define MDOC_KEEP (1 << 8) /* In a word keep. */
|
||||
#define MDOC_SMOFF (1 << 9) /* Spacing is off. */
|
||||
#define MDOC_NODELIMC (1 << 10) /* Disable closing delimiter handling. */
|
||||
#define MAN_ELINE (1 << 11) /* Next-line element scope. */
|
||||
#define MAN_BLINE (1 << 12) /* Next-line block scope. */
|
||||
#define MDOC_PHRASEQF (1 << 13) /* Quote first word encountered. */
|
||||
#define MDOC_PHRASEQL (1 << 14) /* Quote last word of this phrase. */
|
||||
#define MDOC_PHRASEQN (1 << 15) /* Quote first word of the next phrase. */
|
||||
#define MAN_LITERAL MDOC_LITERAL
|
||||
#define MAN_NEWLINE MDOC_NEWLINE
|
||||
enum roff_macroset macroset; /* Kind of high-level macros used. */
|
||||
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. */
|
||||
};
|
||||
|
||||
extern const char *const *roff_name;
|
||||
|
||||
|
||||
int arch_valid(const char *, enum mandoc_os);
|
||||
void deroff(char **, const struct roff_node *);
|
||||
struct ohash *roffhash_alloc(enum roff_tok, enum roff_tok);
|
||||
enum roff_tok roffhash_find(struct ohash *, const char *, size_t);
|
||||
void roffhash_free(struct ohash *);
|
||||
void roff_validate(struct roff_man *);
|
||||
|
51
roff_html.c
51
roff_html.c
@ -1,7 +1,7 @@
|
||||
/* $Id: roff_html.c,v 1.12 2018/06/25 14:53:58 schwarze Exp $ */
|
||||
/* $Id: roff_html.c,v 1.19 2019/01/07 07:26:29 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2014, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2014, 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
|
||||
@ -18,7 +18,8 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "roff.h"
|
||||
@ -31,14 +32,19 @@ typedef void (*roff_html_pre_fp)(ROFF_HTML_ARGS);
|
||||
|
||||
static void roff_html_pre_br(ROFF_HTML_ARGS);
|
||||
static void roff_html_pre_ce(ROFF_HTML_ARGS);
|
||||
static void roff_html_pre_fi(ROFF_HTML_ARGS);
|
||||
static void roff_html_pre_ft(ROFF_HTML_ARGS);
|
||||
static void roff_html_pre_nf(ROFF_HTML_ARGS);
|
||||
static void roff_html_pre_sp(ROFF_HTML_ARGS);
|
||||
|
||||
static const roff_html_pre_fp roff_html_pre_acts[ROFF_MAX] = {
|
||||
roff_html_pre_br, /* br */
|
||||
roff_html_pre_ce, /* ce */
|
||||
NULL, /* ft */
|
||||
roff_html_pre_fi, /* fi */
|
||||
roff_html_pre_ft, /* ft */
|
||||
NULL, /* ll */
|
||||
NULL, /* mc */
|
||||
roff_html_pre_nf, /* nf */
|
||||
NULL, /* po */
|
||||
roff_html_pre_ce, /* rj */
|
||||
roff_html_pre_sp, /* sp */
|
||||
@ -58,11 +64,7 @@ roff_html_pre(struct html *h, const struct roff_node *n)
|
||||
static void
|
||||
roff_html_pre_br(ROFF_HTML_ARGS)
|
||||
{
|
||||
struct tag *t;
|
||||
|
||||
t = print_otag(h, TAG_DIV, "");
|
||||
print_text(h, "\\~"); /* So the div isn't empty. */
|
||||
print_tagq(h, t);
|
||||
print_otag(h, TAG_BR, "");
|
||||
}
|
||||
|
||||
static void
|
||||
@ -79,8 +81,37 @@ roff_html_pre_ce(ROFF_HTML_ARGS)
|
||||
roff_html_pre_br(h, n);
|
||||
}
|
||||
|
||||
static void
|
||||
roff_html_pre_fi(ROFF_HTML_ARGS)
|
||||
{
|
||||
if (html_fillmode(h, TOKEN_NONE) == ROFF_fi)
|
||||
print_otag(h, TAG_BR, "");
|
||||
}
|
||||
|
||||
static void
|
||||
roff_html_pre_ft(ROFF_HTML_ARGS)
|
||||
{
|
||||
const char *cp;
|
||||
|
||||
cp = n->child->string;
|
||||
print_metaf(h, mandoc_font(cp, (int)strlen(cp)));
|
||||
}
|
||||
|
||||
static void
|
||||
roff_html_pre_nf(ROFF_HTML_ARGS)
|
||||
{
|
||||
if (html_fillmode(h, TOKEN_NONE) == ROFF_nf)
|
||||
print_otag(h, TAG_BR, "");
|
||||
}
|
||||
|
||||
static void
|
||||
roff_html_pre_sp(ROFF_HTML_ARGS)
|
||||
{
|
||||
print_paragraph(h);
|
||||
if (html_fillmode(h, TOKEN_NONE) == ROFF_nf) {
|
||||
h->col++;
|
||||
print_endline(h);
|
||||
} else {
|
||||
html_close_paragraph(h);
|
||||
print_otag(h, TAG_P, "c", "Pp");
|
||||
}
|
||||
}
|
||||
|
58
roff_int.h
58
roff_int.h
@ -1,7 +1,7 @@
|
||||
/* $Id: roff_int.h,v 1.9 2017/07/08 17:52:50 schwarze Exp $ */
|
||||
/* $Id: roff_int.h,v 1.16 2019/01/05 00:36:50 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* 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,8 +14,54 @@
|
||||
* 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.
|
||||
*
|
||||
* Parser internals shared by multiple parsers.
|
||||
*/
|
||||
|
||||
struct ohash;
|
||||
struct roff_node;
|
||||
struct roff_meta;
|
||||
struct roff;
|
||||
struct mdoc_arg;
|
||||
|
||||
enum roff_next {
|
||||
ROFF_NEXT_SIBLING = 0,
|
||||
ROFF_NEXT_CHILD
|
||||
};
|
||||
|
||||
struct roff_man {
|
||||
struct roff_meta meta; /* Public parse results. */
|
||||
struct roff *roff; /* Roff parser state data. */
|
||||
struct ohash *mdocmac; /* Mdoc macro lookup table. */
|
||||
struct ohash *manmac; /* Man macro lookup table. */
|
||||
const char *os_s; /* Default operating system. */
|
||||
struct roff_node *last; /* The last node parsed. */
|
||||
struct roff_node *last_es; /* The most recent Es node. */
|
||||
int quick; /* Abort parse early. */
|
||||
int flags; /* Parse flags. */
|
||||
#define ROFF_NOFILL (1 << 1) /* Fill mode switched off. */
|
||||
#define MDOC_PBODY (1 << 2) /* In the document body. */
|
||||
#define MDOC_NEWLINE (1 << 3) /* First macro/text in a line. */
|
||||
#define MDOC_PHRASE (1 << 4) /* In a Bl -column phrase. */
|
||||
#define MDOC_PHRASELIT (1 << 5) /* Literal within a phrase. */
|
||||
#define MDOC_FREECOL (1 << 6) /* `It' invocation should close. */
|
||||
#define MDOC_SYNOPSIS (1 << 7) /* SYNOPSIS-style formatting. */
|
||||
#define MDOC_KEEP (1 << 8) /* In a word keep. */
|
||||
#define MDOC_SMOFF (1 << 9) /* Spacing is off. */
|
||||
#define MDOC_NODELIMC (1 << 10) /* Disable closing delimiter handling. */
|
||||
#define MAN_ELINE (1 << 11) /* Next-line element scope. */
|
||||
#define MAN_BLINE (1 << 12) /* Next-line block scope. */
|
||||
#define MDOC_PHRASEQF (1 << 13) /* Quote first word encountered. */
|
||||
#define MDOC_PHRASEQL (1 << 14) /* Quote last word of this phrase. */
|
||||
#define MDOC_PHRASEQN (1 << 15) /* Quote first word of the next phrase. */
|
||||
#define ROFF_NONOFILL (1 << 16) /* Temporarily suspend no-fill mode. */
|
||||
#define MAN_NEWLINE MDOC_NEWLINE
|
||||
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. */
|
||||
};
|
||||
|
||||
|
||||
struct roff_node *roff_node_alloc(struct roff_man *, int, int,
|
||||
enum roff_type, int);
|
||||
void roff_node_append(struct roff_man *, struct roff_node *);
|
||||
@ -26,9 +72,17 @@ struct roff_node *roff_block_alloc(struct roff_man *, int, int, int);
|
||||
struct roff_node *roff_head_alloc(struct roff_man *, int, int, int);
|
||||
struct roff_node *roff_body_alloc(struct roff_man *, int, int, int);
|
||||
void roff_node_unlink(struct roff_man *, struct roff_node *);
|
||||
void roff_node_relink(struct roff_man *, struct roff_node *);
|
||||
void roff_node_free(struct roff_node *);
|
||||
void roff_node_delete(struct roff_man *, struct roff_node *);
|
||||
|
||||
struct ohash *roffhash_alloc(enum roff_tok, enum roff_tok);
|
||||
enum roff_tok roffhash_find(struct ohash *, const char *, size_t);
|
||||
void roffhash_free(struct ohash *);
|
||||
|
||||
void roff_state_reset(struct roff_man *);
|
||||
void roff_validate(struct roff_man *);
|
||||
|
||||
/*
|
||||
* Functions called from roff.c need to be declared here,
|
||||
* not in libmdoc.h or libman.h, even if they are specific
|
||||
|
48
roff_term.c
48
roff_term.c
@ -1,6 +1,6 @@
|
||||
/* $Id: roff_term.c,v 1.14 2017/06/24 14:38:33 schwarze Exp $ */
|
||||
/* $Id: roff_term.c,v 1.19 2019/01/04 03:24:33 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2010, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2010,2014,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
|
||||
@ -17,7 +17,8 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "roff.h"
|
||||
@ -41,9 +42,11 @@ static void roff_term_pre_ti(ROFF_TERM_ARGS);
|
||||
static const roff_term_pre_fp roff_term_pre_acts[ROFF_MAX] = {
|
||||
roff_term_pre_br, /* br */
|
||||
roff_term_pre_ce, /* ce */
|
||||
roff_term_pre_br, /* fi */
|
||||
roff_term_pre_ft, /* ft */
|
||||
roff_term_pre_ll, /* ll */
|
||||
roff_term_pre_mc, /* mc */
|
||||
roff_term_pre_br, /* nf */
|
||||
roff_term_pre_po, /* po */
|
||||
roff_term_pre_ce, /* rj */
|
||||
roff_term_pre_sp, /* sp */
|
||||
@ -66,7 +69,9 @@ roff_term_pre_br(ROFF_TERM_ARGS)
|
||||
if (p->flags & TERMP_BRIND) {
|
||||
p->tcol->offset = p->tcol->rmargin;
|
||||
p->tcol->rmargin = p->maxrmargin;
|
||||
p->trailspace = 0;
|
||||
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
|
||||
p->flags |= TERMP_NOSPACE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,27 +79,16 @@ static void
|
||||
roff_term_pre_ce(ROFF_TERM_ARGS)
|
||||
{
|
||||
const struct roff_node *nc1, *nc2;
|
||||
size_t len, lm;
|
||||
|
||||
roff_term_pre_br(p, n);
|
||||
lm = p->tcol->offset;
|
||||
p->flags |= n->tok == ROFF_ce ? TERMP_CENTER : TERMP_RIGHT;
|
||||
nc1 = n->child->next;
|
||||
while (nc1 != NULL) {
|
||||
nc2 = nc1;
|
||||
len = 0;
|
||||
do {
|
||||
if (nc2->type == ROFFT_TEXT) {
|
||||
if (len)
|
||||
len++;
|
||||
len += term_strlen(p, nc2->string);
|
||||
}
|
||||
nc2 = nc2->next;
|
||||
} while (nc2 != NULL && (nc2->type != ROFFT_TEXT ||
|
||||
(nc2->flags & NODE_LINE) == 0));
|
||||
p->tcol->offset = len >= p->tcol->rmargin ? 0 :
|
||||
lm + len >= p->tcol->rmargin ? p->tcol->rmargin - len :
|
||||
n->tok == ROFF_rj ? p->tcol->rmargin - len :
|
||||
(lm + p->tcol->rmargin - len) / 2;
|
||||
while (nc1 != nc2) {
|
||||
if (nc1->type == ROFFT_TEXT)
|
||||
term_word(p, nc1->string);
|
||||
@ -105,28 +99,30 @@ roff_term_pre_ce(ROFF_TERM_ARGS)
|
||||
p->flags |= TERMP_NOSPACE;
|
||||
term_flushln(p);
|
||||
}
|
||||
p->tcol->offset = lm;
|
||||
p->flags &= ~(TERMP_CENTER | TERMP_RIGHT);
|
||||
}
|
||||
|
||||
static void
|
||||
roff_term_pre_ft(ROFF_TERM_ARGS)
|
||||
{
|
||||
switch (*n->child->string) {
|
||||
case '4':
|
||||
case '3':
|
||||
case 'B':
|
||||
const char *cp;
|
||||
|
||||
cp = n->child->string;
|
||||
switch (mandoc_font(cp, (int)strlen(cp))) {
|
||||
case ESCAPE_FONTBOLD:
|
||||
term_fontrepl(p, TERMFONT_BOLD);
|
||||
break;
|
||||
case '2':
|
||||
case 'I':
|
||||
case ESCAPE_FONTITALIC:
|
||||
term_fontrepl(p, TERMFONT_UNDER);
|
||||
break;
|
||||
case 'P':
|
||||
case ESCAPE_FONTBI:
|
||||
term_fontrepl(p, TERMFONT_BI);
|
||||
break;
|
||||
case ESCAPE_FONTPREV:
|
||||
term_fontlast(p);
|
||||
break;
|
||||
case '1':
|
||||
case 'C':
|
||||
case 'R':
|
||||
case ESCAPE_FONTROMAN:
|
||||
case ESCAPE_FONTCW:
|
||||
term_fontrepl(p, TERMFONT_NONE);
|
||||
break;
|
||||
default:
|
||||
|
106
roff_validate.c
106
roff_validate.c
@ -1,6 +1,6 @@
|
||||
/* $Id: roff_validate.c,v 1.9 2017/06/14 22:51:25 schwarze Exp $ */
|
||||
/* $Id: roff_validate.c,v 1.18 2018/12/31 09:02:37 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2010, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2010, 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
|
||||
@ -17,7 +17,8 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "roff.h"
|
||||
@ -28,17 +29,23 @@
|
||||
|
||||
typedef void (*roff_valid_fp)(ROFF_VALID_ARGS);
|
||||
|
||||
static void roff_valid_br(ROFF_VALID_ARGS);
|
||||
static void roff_valid_fi(ROFF_VALID_ARGS);
|
||||
static void roff_valid_ft(ROFF_VALID_ARGS);
|
||||
static void roff_valid_nf(ROFF_VALID_ARGS);
|
||||
static void roff_valid_sp(ROFF_VALID_ARGS);
|
||||
|
||||
static const roff_valid_fp roff_valids[ROFF_MAX] = {
|
||||
NULL, /* br */
|
||||
roff_valid_br, /* br */
|
||||
NULL, /* ce */
|
||||
roff_valid_fi, /* fi */
|
||||
roff_valid_ft, /* ft */
|
||||
NULL, /* ll */
|
||||
NULL, /* mc */
|
||||
roff_valid_nf, /* nf */
|
||||
NULL, /* po */
|
||||
NULL, /* rj */
|
||||
NULL, /* sp */
|
||||
roff_valid_sp, /* sp */
|
||||
NULL, /* ta */
|
||||
NULL, /* ti */
|
||||
};
|
||||
@ -55,10 +62,46 @@ roff_validate(struct roff_man *man)
|
||||
(*roff_valids[n->tok])(man, n);
|
||||
}
|
||||
|
||||
static void
|
||||
roff_valid_br(ROFF_VALID_ARGS)
|
||||
{
|
||||
struct roff_node *np;
|
||||
|
||||
if (n->next != NULL && n->next->type == ROFFT_TEXT &&
|
||||
*n->next->string == ' ') {
|
||||
mandoc_msg(MANDOCERR_PAR_SKIP, n->line, n->pos,
|
||||
"br before text line with leading blank");
|
||||
roff_node_delete(man, n);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((np = n->prev) == NULL)
|
||||
return;
|
||||
|
||||
switch (np->tok) {
|
||||
case ROFF_br:
|
||||
case ROFF_sp:
|
||||
case MDOC_Pp:
|
||||
mandoc_msg(MANDOCERR_PAR_SKIP,
|
||||
n->line, n->pos, "br after %s", roff_name[np->tok]);
|
||||
roff_node_delete(man, n);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
roff_valid_fi(ROFF_VALID_ARGS)
|
||||
{
|
||||
if ((n->flags & NODE_NOFILL) == 0)
|
||||
mandoc_msg(MANDOCERR_FI_SKIP, n->line, n->pos, "fi");
|
||||
}
|
||||
|
||||
static void
|
||||
roff_valid_ft(ROFF_VALID_ARGS)
|
||||
{
|
||||
char *cp;
|
||||
const char *cp;
|
||||
|
||||
if (n->child == NULL) {
|
||||
man->next = ROFF_NEXT_CHILD;
|
||||
@ -68,30 +111,39 @@ roff_valid_ft(ROFF_VALID_ARGS)
|
||||
}
|
||||
|
||||
cp = n->child->string;
|
||||
switch (*cp) {
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case 'I':
|
||||
case 'P':
|
||||
case 'R':
|
||||
if (cp[1] == '\0')
|
||||
return;
|
||||
if (mandoc_font(cp, (int)strlen(cp)) != ESCAPE_ERROR)
|
||||
return;
|
||||
mandoc_msg(MANDOCERR_FT_BAD, n->line, n->pos, "ft %s", cp);
|
||||
roff_node_delete(man, n);
|
||||
}
|
||||
|
||||
static void
|
||||
roff_valid_nf(ROFF_VALID_ARGS)
|
||||
{
|
||||
if (n->flags & NODE_NOFILL)
|
||||
mandoc_msg(MANDOCERR_NF_SKIP, n->line, n->pos, "nf");
|
||||
}
|
||||
|
||||
static void
|
||||
roff_valid_sp(ROFF_VALID_ARGS)
|
||||
{
|
||||
struct roff_node *np;
|
||||
|
||||
if ((np = n->prev) == NULL)
|
||||
return;
|
||||
|
||||
switch (np->tok) {
|
||||
case ROFF_br:
|
||||
mandoc_msg(MANDOCERR_PAR_SKIP,
|
||||
np->line, np->pos, "br before sp");
|
||||
roff_node_delete(man, np);
|
||||
break;
|
||||
case 'B':
|
||||
if (cp[1] == '\0' || (cp[1] == 'I' && cp[2] == '\0'))
|
||||
return;
|
||||
break;
|
||||
case 'C':
|
||||
if (cp[1] == 'W' && cp[2] == '\0')
|
||||
return;
|
||||
case MDOC_Pp:
|
||||
mandoc_msg(MANDOCERR_PAR_SKIP,
|
||||
n->line, n->pos, "sp after Pp");
|
||||
roff_node_delete(man, n);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
mandoc_vmsg(MANDOCERR_FT_BAD, man->parse,
|
||||
n->line, n->pos, "ft %s", cp);
|
||||
roff_node_delete(man, n);
|
||||
}
|
||||
|
54
st.c
54
st.c
@ -1,6 +1,6 @@
|
||||
/* $Id: st.c,v 1.14 2017/06/24 14:38:33 schwarze Exp $ */
|
||||
/* $Id: st.c,v 1.16 2018/12/14 01:18:26 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -18,11 +18,11 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "roff.h"
|
||||
#include "mdoc.h"
|
||||
#include "libmdoc.h"
|
||||
|
||||
#define LINE(x, y) \
|
||||
@ -31,8 +31,52 @@
|
||||
const char *
|
||||
mdoc_a2st(const char *p)
|
||||
{
|
||||
|
||||
#include "st.in"
|
||||
LINE("-p1003.1-88", "IEEE Std 1003.1-1988 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1-90", "IEEE Std 1003.1-1990 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1-96", "ISO/IEC 9945-1:1996 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1-2001", "IEEE Std 1003.1-2001 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1-2004", "IEEE Std 1003.1-2004 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1-2008", "IEEE Std 1003.1-2008 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1", "IEEE Std 1003.1 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1b", "IEEE Std 1003.1b (\\(lqPOSIX.1b\\(rq)")
|
||||
LINE("-p1003.1b-93", "IEEE Std 1003.1b-1993 (\\(lqPOSIX.1b\\(rq)")
|
||||
LINE("-p1003.1c-95", "IEEE Std 1003.1c-1995 (\\(lqPOSIX.1c\\(rq)")
|
||||
LINE("-p1003.1g-2000", "IEEE Std 1003.1g-2000 (\\(lqPOSIX.1g\\(rq)")
|
||||
LINE("-p1003.1i-95", "IEEE Std 1003.1i-1995 (\\(lqPOSIX.1i\\(rq)")
|
||||
LINE("-p1003.2", "IEEE Std 1003.2 (\\(lqPOSIX.2\\(rq)")
|
||||
LINE("-p1003.2-92", "IEEE Std 1003.2-1992 (\\(lqPOSIX.2\\(rq)")
|
||||
LINE("-p1003.2a-92", "IEEE Std 1003.2a-1992 (\\(lqPOSIX.2\\(rq)")
|
||||
LINE("-isoC", "ISO/IEC 9899:1990 (\\(lqISO\\~C90\\(rq)")
|
||||
LINE("-isoC-90", "ISO/IEC 9899:1990 (\\(lqISO\\~C90\\(rq)")
|
||||
LINE("-isoC-amd1", "ISO/IEC 9899/AMD1:1995 (\\(lqISO\\~C90, Amendment 1\\(rq)")
|
||||
LINE("-isoC-tcor1", "ISO/IEC 9899/TCOR1:1994 (\\(lqISO\\~C90, Technical Corrigendum 1\\(rq)")
|
||||
LINE("-isoC-tcor2", "ISO/IEC 9899/TCOR2:1995 (\\(lqISO\\~C90, Technical Corrigendum 2\\(rq)")
|
||||
LINE("-isoC-99", "ISO/IEC 9899:1999 (\\(lqISO\\~C99\\(rq)")
|
||||
LINE("-isoC-2011", "ISO/IEC 9899:2011 (\\(lqISO\\~C11\\(rq)")
|
||||
LINE("-iso9945-1-90", "ISO/IEC 9945-1:1990 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-iso9945-1-96", "ISO/IEC 9945-1:1996 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-iso9945-2-93", "ISO/IEC 9945-2:1993 (\\(lqPOSIX.2\\(rq)")
|
||||
LINE("-ansiC", "ANSI X3.159-1989 (\\(lqANSI\\~C89\\(rq)")
|
||||
LINE("-ansiC-89", "ANSI X3.159-1989 (\\(lqANSI\\~C89\\(rq)")
|
||||
LINE("-ieee754", "IEEE Std 754-1985")
|
||||
LINE("-iso8802-3", "ISO 8802-3: 1989")
|
||||
LINE("-iso8601", "ISO 8601")
|
||||
LINE("-ieee1275-94", "IEEE Std 1275-1994 (\\(lqOpen Firmware\\(rq)")
|
||||
LINE("-xpg3", "X/Open Portability Guide Issue\\~3 (\\(lqXPG3\\(rq)")
|
||||
LINE("-xpg4", "X/Open Portability Guide Issue\\~4 (\\(lqXPG4\\(rq)")
|
||||
LINE("-xpg4.2", "X/Open Portability Guide Issue\\~4, Version\\~2 (\\(lqXPG4.2\\(rq)")
|
||||
LINE("-xbd5", "X/Open Base Definitions Issue\\~5 (\\(lqXBD5\\(rq)")
|
||||
LINE("-xcu5", "X/Open Commands and Utilities Issue\\~5 (\\(lqXCU5\\(rq)")
|
||||
LINE("-xsh4.2", "X/Open System Interfaces and Headers Issue\\~4, Version\\~2 (\\(lqXSH4.2\\(rq)")
|
||||
LINE("-xsh5", "X/Open System Interfaces and Headers Issue\\~5 (\\(lqXSH5\\(rq)")
|
||||
LINE("-xns5", "X/Open Networking Services Issue\\~5 (\\(lqXNS5\\(rq)")
|
||||
LINE("-xns5.2", "X/Open Networking Services Issue\\~5.2 (\\(lqXNS5.2\\(rq)")
|
||||
LINE("-xcurses4.2", "X/Open Curses Issue\\~4, Version\\~2 (\\(lqXCURSES4.2\\(rq)")
|
||||
LINE("-susv1", "Version\\~1 of the Single UNIX Specification (\\(lqSUSv1\\(rq)")
|
||||
LINE("-susv2", "Version\\~2 of the Single UNIX Specification (\\(lqSUSv2\\(rq)")
|
||||
LINE("-susv3", "Version\\~3 of the Single UNIX Specification (\\(lqSUSv3\\(rq)")
|
||||
LINE("-susv4", "Version\\~4 of the Single UNIX Specification (\\(lqSUSv4\\(rq)")
|
||||
LINE("-svid4", "System\\~V Interface Definition, Fourth Edition (\\(lqSVID4\\(rq)")
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
76
st.in
76
st.in
@ -1,76 +0,0 @@
|
||||
/* $Id: st.in,v 1.30 2018/04/05 09:17:26 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file defines the .St macro arguments. If you add a new
|
||||
* standard, make sure that the left-and side corresponds to the .St
|
||||
* argument (like .St -p1003.1) and the right-hand side corresponds to
|
||||
* the formatted output string.
|
||||
*
|
||||
* Be sure to escape strings.
|
||||
* The non-breaking blanks prevent ending an output line right before
|
||||
* a number. Groff prevent line breaks at the same places.
|
||||
*
|
||||
* REMEMBER TO ADD NEW STANDARDS TO MDOC.7!
|
||||
*/
|
||||
|
||||
LINE("-p1003.1-88", "IEEE Std 1003.1-1988 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1-90", "IEEE Std 1003.1-1990 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1-96", "ISO/IEC 9945-1:1996 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1-2001", "IEEE Std 1003.1-2001 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1-2004", "IEEE Std 1003.1-2004 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1-2008", "IEEE Std 1003.1-2008 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1", "IEEE Std 1003.1 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-p1003.1b", "IEEE Std 1003.1b (\\(lqPOSIX.1b\\(rq)")
|
||||
LINE("-p1003.1b-93", "IEEE Std 1003.1b-1993 (\\(lqPOSIX.1b\\(rq)")
|
||||
LINE("-p1003.1c-95", "IEEE Std 1003.1c-1995 (\\(lqPOSIX.1c\\(rq)")
|
||||
LINE("-p1003.1g-2000", "IEEE Std 1003.1g-2000 (\\(lqPOSIX.1g\\(rq)")
|
||||
LINE("-p1003.1i-95", "IEEE Std 1003.1i-1995 (\\(lqPOSIX.1i\\(rq)")
|
||||
LINE("-p1003.2", "IEEE Std 1003.2 (\\(lqPOSIX.2\\(rq)")
|
||||
LINE("-p1003.2-92", "IEEE Std 1003.2-1992 (\\(lqPOSIX.2\\(rq)")
|
||||
LINE("-p1003.2a-92", "IEEE Std 1003.2a-1992 (\\(lqPOSIX.2\\(rq)")
|
||||
LINE("-isoC", "ISO/IEC 9899:1990 (\\(lqISO\\~C90\\(rq)")
|
||||
LINE("-isoC-90", "ISO/IEC 9899:1990 (\\(lqISO\\~C90\\(rq)")
|
||||
LINE("-isoC-amd1", "ISO/IEC 9899/AMD1:1995 (\\(lqISO\\~C90, Amendment 1\\(rq)")
|
||||
LINE("-isoC-tcor1", "ISO/IEC 9899/TCOR1:1994 (\\(lqISO\\~C90, Technical Corrigendum 1\\(rq)")
|
||||
LINE("-isoC-tcor2", "ISO/IEC 9899/TCOR2:1995 (\\(lqISO\\~C90, Technical Corrigendum 2\\(rq)")
|
||||
LINE("-isoC-99", "ISO/IEC 9899:1999 (\\(lqISO\\~C99\\(rq)")
|
||||
LINE("-isoC-2011", "ISO/IEC 9899:2011 (\\(lqISO\\~C11\\(rq)")
|
||||
LINE("-iso9945-1-90", "ISO/IEC 9945-1:1990 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-iso9945-1-96", "ISO/IEC 9945-1:1996 (\\(lqPOSIX.1\\(rq)")
|
||||
LINE("-iso9945-2-93", "ISO/IEC 9945-2:1993 (\\(lqPOSIX.2\\(rq)")
|
||||
LINE("-ansiC", "ANSI X3.159-1989 (\\(lqANSI\\~C89\\(rq)")
|
||||
LINE("-ansiC-89", "ANSI X3.159-1989 (\\(lqANSI\\~C89\\(rq)")
|
||||
LINE("-ieee754", "IEEE Std 754-1985")
|
||||
LINE("-iso8802-3", "ISO 8802-3: 1989")
|
||||
LINE("-iso8601", "ISO 8601")
|
||||
LINE("-ieee1275-94", "IEEE Std 1275-1994 (\\(lqOpen Firmware\\(rq)")
|
||||
LINE("-xpg3", "X/Open Portability Guide Issue\\~3 (\\(lqXPG3\\(rq)")
|
||||
LINE("-xpg4", "X/Open Portability Guide Issue\\~4 (\\(lqXPG4\\(rq)")
|
||||
LINE("-xpg4.2", "X/Open Portability Guide Issue\\~4, Version\\~2 (\\(lqXPG4.2\\(rq)")
|
||||
LINE("-xbd5", "X/Open Base Definitions Issue\\~5 (\\(lqXBD5\\(rq)")
|
||||
LINE("-xcu5", "X/Open Commands and Utilities Issue\\~5 (\\(lqXCU5\\(rq)")
|
||||
LINE("-xsh4.2", "X/Open System Interfaces and Headers Issue\\~4, Version\\~2 (\\(lqXSH4.2\\(rq)")
|
||||
LINE("-xsh5", "X/Open System Interfaces and Headers Issue\\~5 (\\(lqXSH5\\(rq)")
|
||||
LINE("-xns5", "X/Open Networking Services Issue\\~5 (\\(lqXNS5\\(rq)")
|
||||
LINE("-xns5.2", "X/Open Networking Services Issue\\~5.2 (\\(lqXNS5.2\\(rq)")
|
||||
LINE("-xcurses4.2", "X/Open Curses Issue\\~4, Version\\~2 (\\(lqXCURSES4.2\\(rq)")
|
||||
LINE("-susv1", "Version\\~1 of the Single UNIX Specification (\\(lqSUSv1\\(rq)")
|
||||
LINE("-susv2", "Version\\~2 of the Single UNIX Specification (\\(lqSUSv2\\(rq)")
|
||||
LINE("-susv3", "Version\\~3 of the Single UNIX Specification (\\(lqSUSv3\\(rq)")
|
||||
LINE("-susv4", "Version\\~4 of the Single UNIX Specification (\\(lqSUSv4\\(rq)")
|
||||
LINE("-svid4", "System\\~V Interface Definition, Fourth Edition (\\(lqSVID4\\(rq)")
|
45
tag.c
45
tag.c
@ -1,6 +1,6 @@
|
||||
/* $Id: tag.c,v 1.19 2018/02/23 16:47:10 schwarze Exp $ */
|
||||
/* $Id: tag.c,v 1.21 2018/11/22 11:30:23 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2015, 2016 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2015, 2016, 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
|
||||
@ -18,6 +18,10 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#if HAVE_ERR
|
||||
#include <err.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
@ -121,41 +125,57 @@ tag_init(void)
|
||||
|
||||
/*
|
||||
* Set the line number where a term is defined,
|
||||
* unless it is already defined at a higher priority.
|
||||
* unless it is already defined at a lower priority.
|
||||
*/
|
||||
void
|
||||
tag_put(const char *s, int prio, size_t line)
|
||||
{
|
||||
struct tag_entry *entry;
|
||||
const char *se;
|
||||
size_t len;
|
||||
unsigned int slot;
|
||||
|
||||
/* Sanity checks. */
|
||||
|
||||
if (tag_files.tfd <= 0)
|
||||
return;
|
||||
|
||||
if (s[0] == '\\' && (s[1] == '&' || s[1] == 'e'))
|
||||
s += 2;
|
||||
if (*s == '\0' || strchr(s, ' ') != NULL)
|
||||
|
||||
/*
|
||||
* Skip whitespace and whatever follows it,
|
||||
* and if there is any, downgrade the priority.
|
||||
*/
|
||||
|
||||
len = strcspn(s, " \t");
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
slot = ohash_qlookup(&tag_data, s);
|
||||
se = s + len;
|
||||
if (*se != '\0')
|
||||
prio = INT_MAX;
|
||||
|
||||
slot = ohash_qlookupi(&tag_data, s, &se);
|
||||
entry = ohash_find(&tag_data, slot);
|
||||
|
||||
if (entry == NULL) {
|
||||
|
||||
/* Build a new entry. */
|
||||
|
||||
len = strlen(s) + 1;
|
||||
entry = mandoc_malloc(sizeof(*entry) + len);
|
||||
entry = mandoc_malloc(sizeof(*entry) + len + 1);
|
||||
memcpy(entry->s, s, len);
|
||||
entry->s[len] = '\0';
|
||||
entry->lines = NULL;
|
||||
entry->maxlines = entry->nlines = 0;
|
||||
ohash_insert(&tag_data, slot, entry);
|
||||
|
||||
} else {
|
||||
|
||||
/* Handle priority 0 entries. */
|
||||
/*
|
||||
* Lower priority numbers take precedence,
|
||||
* but 0 is special.
|
||||
* A tag with priority 0 is only used
|
||||
* if the tag occurs exactly once.
|
||||
*/
|
||||
|
||||
if (prio == 0) {
|
||||
if (entry->prio == 0)
|
||||
@ -199,6 +219,11 @@ tag_write(void)
|
||||
|
||||
if (tag_files.tfd <= 0)
|
||||
return;
|
||||
if (tag_files.tagname != NULL && ohash_find(&tag_data,
|
||||
ohash_qlookup(&tag_data, tag_files.tagname)) == NULL) {
|
||||
warnx("%s: no such tag", tag_files.tagname);
|
||||
tag_files.tagname = NULL;
|
||||
}
|
||||
stream = fdopen(tag_files.tfd, "w");
|
||||
entry = ohash_first(&tag_data, &slot);
|
||||
while (entry != NULL) {
|
||||
|
3
tag.h
3
tag.h
@ -1,4 +1,4 @@
|
||||
/* $Id: tag.h,v 1.7 2015/11/20 21:59:54 schwarze Exp $ */
|
||||
/* $Id: tag.h,v 1.8 2018/11/22 11:30:23 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
|
||||
*
|
||||
@ -18,6 +18,7 @@
|
||||
struct tag_files {
|
||||
char ofn[20];
|
||||
char tfn[20];
|
||||
char *tagname;
|
||||
int ofd;
|
||||
int tfd;
|
||||
pid_t tcpgid;
|
||||
|
33
tbl.3
33
tbl.3
@ -1,6 +1,6 @@
|
||||
.\" $Id: tbl.3,v 1.2 2015/01/30 04:11:50 schwarze Exp $
|
||||
.\" $Id: tbl.3,v 1.6 2018/12/14 06:33:14 schwarze Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
|
||||
.\" Copyright (c) 2013, 2015, 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,7 +14,7 @@
|
||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd $Mdocdate: January 30 2015 $
|
||||
.Dd $Mdocdate: December 14 2018 $
|
||||
.Dt TBL 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -26,16 +26,15 @@
|
||||
.Nm tbl_free
|
||||
.Nd roff table parser library for mandoc
|
||||
.Sh SYNOPSIS
|
||||
.In mandoc.h
|
||||
.In libmandoc.h
|
||||
.In libroff.h
|
||||
.In sys/types.h
|
||||
.In tbl.h
|
||||
.In tbl_parse.h
|
||||
.Ft struct tbl_node *
|
||||
.Fo tbl_alloc
|
||||
.Fa "int pos"
|
||||
.Fa "int line"
|
||||
.Fa "struct mparse *parse"
|
||||
.Fc
|
||||
.Ft enum rofferr
|
||||
.Ft void
|
||||
.Fo tbl_read
|
||||
.Fa "struct tbl_node *tbl"
|
||||
.Fa "int ln"
|
||||
@ -67,15 +66,15 @@ utility and not designed for stand-alone use.
|
||||
The present manual is intended as a reference for developers working on
|
||||
.Xr mandoc 1 .
|
||||
.Ss Data structures
|
||||
Unless otherwise noted, all of the following data structures are defined in
|
||||
.In mandoc.h
|
||||
Unless otherwise noted, all of the following data structures are declared in
|
||||
.In tbl.h
|
||||
and are deleted in
|
||||
.Fn tbl_free .
|
||||
.Bl -tag -width Ds
|
||||
.It Vt struct tbl_node
|
||||
This structure describes a complete table.
|
||||
It is defined in
|
||||
.In libroff.h ,
|
||||
It is declared in
|
||||
.In tbl_int.h ,
|
||||
created in
|
||||
.Fn tbl_alloc ,
|
||||
and stored in the members
|
||||
@ -104,12 +103,6 @@ but if there is a span, the function
|
||||
.Fn tbl_layout
|
||||
guarantees that these pointers are not
|
||||
.Dv NULL .
|
||||
The function
|
||||
.Fn tbl_alloc
|
||||
guarantees that the
|
||||
.Fa parse
|
||||
member is not
|
||||
.Dv NULL .
|
||||
.It Vt struct tbl_opts
|
||||
This structure describes the options of one table.
|
||||
It is used as a substructure of
|
||||
@ -226,7 +219,7 @@ member is not
|
||||
.Ss Interface functions
|
||||
The following functions are implemented in
|
||||
.Pa tbl.c ,
|
||||
and all callers in
|
||||
and all callers are in
|
||||
.Pa roff.c .
|
||||
.Bl -tag -width Ds
|
||||
.It Fn tbl_alloc
|
||||
@ -279,6 +272,8 @@ and
|
||||
.Fn roff_reset .
|
||||
.El
|
||||
.Ss Private functions
|
||||
The following functions are declared in
|
||||
.In tbl_int.h .
|
||||
.Bl -tag -width Ds
|
||||
.It Ft int Fn tbl_options "struct tbl_node *tbl" "int ln" "const char *p"
|
||||
Parses the options line into
|
||||
|
44
tbl.7
44
tbl.7
@ -1,7 +1,7 @@
|
||||
.\" $Id: tbl.7,v 1.29 2017/10/17 23:19:12 schwarze Exp $
|
||||
.\" $Id: tbl.7,v 1.34 2019/03/02 21:03:02 schwarze Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
.\" Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
.\" Copyright (c) 2014,2015,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
|
||||
@ -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: October 17 2017 $
|
||||
.Dd $Mdocdate: March 2 2019 $
|
||||
.Dt TBL 7
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -147,9 +147,9 @@ The combined cell as a whole consumes only one cell
|
||||
of the corresponding data line.
|
||||
.It Cm a
|
||||
Left-justify a string and pad with one space.
|
||||
.It Cm ^
|
||||
.It Cm \(ha
|
||||
Vertically span rows from the last
|
||||
.Pf non- Cm ^
|
||||
.Pf non- Cm \(ha
|
||||
layout cell.
|
||||
It is an error to invoke a vertical span on the first layout line.
|
||||
Unlike a horizontal span, a vertical span consumes a data cell
|
||||
@ -231,13 +231,19 @@ Each data line consists of one or more data cells, delimited by
|
||||
.Cm tab
|
||||
characters.
|
||||
.Pp
|
||||
If a data cells contains only the single character
|
||||
If a data cell contains only the two bytes
|
||||
.Ql \e\(ha ,
|
||||
the cell above spans to this row, as if the layout specification
|
||||
of this cell were
|
||||
.Cm \(ha .
|
||||
.Pp
|
||||
If a data cell contains only the single character
|
||||
.Ql _
|
||||
or
|
||||
.Ql = ,
|
||||
a single or double horizontal line is drawn across the cell,
|
||||
joining its neighbours.
|
||||
If a data cells contains only the two character sequence
|
||||
If a data cell contains only the two character sequence
|
||||
.Ql \e_
|
||||
or
|
||||
.Ql \e= ,
|
||||
@ -323,7 +329,7 @@ _
|
||||
AFL:2.39b
|
||||
Mutt:1.8.0
|
||||
Ruby:1.8.7.374
|
||||
TeX Live:2015
|
||||
TeX Live:2015
|
||||
.TE
|
||||
.Ed
|
||||
.sp 2v
|
||||
@ -332,8 +338,8 @@ Spans and skipping width calculations:
|
||||
\&.TS
|
||||
box tab(:);
|
||||
lz s | rt
|
||||
lt| cb| ^
|
||||
^ | rz s.
|
||||
lt| cb| \(ha
|
||||
\(ha | rz s.
|
||||
left:r
|
||||
l:center:
|
||||
:right
|
||||
@ -388,8 +394,8 @@ T}::line 5
|
||||
These examples were constructed to demonstrate many
|
||||
.Nm
|
||||
features in a compact way.
|
||||
In real manual pages, keep tables as simple as possible:
|
||||
Like that, they usually look better, are less fragile, and more portable.
|
||||
In real manual pages, keep tables as simple as possible.
|
||||
They usually look better, are less fragile, and are more portable.
|
||||
.Sh COMPATIBILITY
|
||||
The
|
||||
.Xr mandoc 1
|
||||
@ -432,3 +438,17 @@ reference was written by
|
||||
.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
|
||||
and
|
||||
.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
|
||||
.Sh BUGS
|
||||
In
|
||||
.Fl T
|
||||
.Cm utf8
|
||||
output mode, heavy lines are drawn instead of double lines.
|
||||
This cannot be improved because the Unicode standard only provides
|
||||
an incomplete set of box drawing characters with double lines,
|
||||
whereas it provides a full set of box drawing characters
|
||||
with heavy lines.
|
||||
It is unlikely this can be improved in the future because the box
|
||||
drawing characters are already marked in Unicode as characters
|
||||
intended only for backward compatibility with legacy systems,
|
||||
and their use is not encouraged.
|
||||
So it seems unlikely that the missing ones might get added in the future.
|
||||
|
76
tbl.c
76
tbl.c
@ -1,4 +1,4 @@
|
||||
/* $Id: tbl.c,v 1.42 2017/07/08 17:52:50 schwarze Exp $ */
|
||||
/* $Id: tbl.c,v 1.46 2018/12/14 06:33:14 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2011, 2015 Ingo Schwarze <schwarze@openbsd.org>
|
||||
@ -25,10 +25,12 @@
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "mandoc_aux.h"
|
||||
#include "mandoc.h"
|
||||
#include "tbl.h"
|
||||
#include "libmandoc.h"
|
||||
#include "libroff.h"
|
||||
#include "tbl_parse.h"
|
||||
#include "tbl_int.h"
|
||||
|
||||
|
||||
void
|
||||
@ -86,14 +88,15 @@ tbl_read(struct tbl_node *tbl, int ln, const char *p, int pos)
|
||||
}
|
||||
|
||||
struct tbl_node *
|
||||
tbl_alloc(int pos, int line, struct mparse *parse)
|
||||
tbl_alloc(int pos, int line, struct tbl_node *last_tbl)
|
||||
{
|
||||
struct tbl_node *tbl;
|
||||
|
||||
tbl = mandoc_calloc(1, sizeof(*tbl));
|
||||
if (last_tbl != NULL)
|
||||
last_tbl->next = tbl;
|
||||
tbl->line = line;
|
||||
tbl->pos = pos;
|
||||
tbl->parse = parse;
|
||||
tbl->part = TBL_PART_OPTS;
|
||||
tbl->opts.tab = '\t';
|
||||
tbl->opts.decimal = '.';
|
||||
@ -103,76 +106,77 @@ tbl_alloc(int pos, int line, struct mparse *parse)
|
||||
void
|
||||
tbl_free(struct tbl_node *tbl)
|
||||
{
|
||||
struct tbl_node *old_tbl;
|
||||
struct tbl_row *rp;
|
||||
struct tbl_cell *cp;
|
||||
struct tbl_span *sp;
|
||||
struct tbl_dat *dp;
|
||||
|
||||
while ((rp = tbl->first_row) != NULL) {
|
||||
tbl->first_row = rp->next;
|
||||
while (rp->first != NULL) {
|
||||
cp = rp->first;
|
||||
rp->first = cp->next;
|
||||
free(cp->wstr);
|
||||
free(cp);
|
||||
while (tbl != NULL) {
|
||||
while ((rp = tbl->first_row) != NULL) {
|
||||
tbl->first_row = rp->next;
|
||||
while (rp->first != NULL) {
|
||||
cp = rp->first;
|
||||
rp->first = cp->next;
|
||||
free(cp->wstr);
|
||||
free(cp);
|
||||
}
|
||||
free(rp);
|
||||
}
|
||||
free(rp);
|
||||
}
|
||||
|
||||
while ((sp = tbl->first_span) != NULL) {
|
||||
tbl->first_span = sp->next;
|
||||
while (sp->first != NULL) {
|
||||
dp = sp->first;
|
||||
sp->first = dp->next;
|
||||
free(dp->string);
|
||||
free(dp);
|
||||
while ((sp = tbl->first_span) != NULL) {
|
||||
tbl->first_span = sp->next;
|
||||
while (sp->first != NULL) {
|
||||
dp = sp->first;
|
||||
sp->first = dp->next;
|
||||
free(dp->string);
|
||||
free(dp);
|
||||
}
|
||||
free(sp);
|
||||
}
|
||||
free(sp);
|
||||
old_tbl = tbl;
|
||||
tbl = tbl->next;
|
||||
free(old_tbl);
|
||||
}
|
||||
|
||||
free(tbl);
|
||||
}
|
||||
|
||||
void
|
||||
tbl_restart(int line, int pos, struct tbl_node *tbl)
|
||||
{
|
||||
if (tbl->part == TBL_PART_CDATA)
|
||||
mandoc_msg(MANDOCERR_TBLDATA_BLK, tbl->parse,
|
||||
line, pos, "T&");
|
||||
mandoc_msg(MANDOCERR_TBLDATA_BLK, line, pos, "T&");
|
||||
|
||||
tbl->part = TBL_PART_LAYOUT;
|
||||
tbl->line = line;
|
||||
tbl->pos = pos;
|
||||
}
|
||||
|
||||
const struct tbl_span *
|
||||
struct tbl_span *
|
||||
tbl_span(struct tbl_node *tbl)
|
||||
{
|
||||
struct tbl_span *span;
|
||||
|
||||
assert(tbl);
|
||||
span = tbl->current_span ? tbl->current_span->next
|
||||
: tbl->first_span;
|
||||
if (span)
|
||||
if (span != NULL)
|
||||
tbl->current_span = span;
|
||||
return span;
|
||||
}
|
||||
|
||||
int
|
||||
tbl_end(struct tbl_node *tbl)
|
||||
tbl_end(struct tbl_node *tbl, int still_open)
|
||||
{
|
||||
struct tbl_span *sp;
|
||||
|
||||
if (tbl->part == TBL_PART_CDATA)
|
||||
mandoc_msg(MANDOCERR_TBLDATA_BLK, tbl->parse,
|
||||
tbl->line, tbl->pos, "TE");
|
||||
if (still_open)
|
||||
mandoc_msg(MANDOCERR_BLK_NOEND, tbl->line, tbl->pos, "TS");
|
||||
else if (tbl->part == TBL_PART_CDATA)
|
||||
mandoc_msg(MANDOCERR_TBLDATA_BLK, tbl->line, tbl->pos, "TE");
|
||||
|
||||
sp = tbl->first_span;
|
||||
while (sp != NULL && sp->first == NULL)
|
||||
sp = sp->next;
|
||||
if (sp == NULL) {
|
||||
mandoc_msg(MANDOCERR_TBLDATA_NONE, tbl->parse,
|
||||
tbl->line, tbl->pos, NULL);
|
||||
mandoc_msg(MANDOCERR_TBLDATA_NONE, tbl->line, tbl->pos, NULL);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
122
tbl.h
Normal file
122
tbl.h
Normal file
@ -0,0 +1,122 @@
|
||||
/* $Id: tbl.h,v 1.1 2018/12/12 21:54:35 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 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
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
struct tbl_opts {
|
||||
int opts;
|
||||
#define TBL_OPT_ALLBOX (1 << 0) /* Option "allbox". */
|
||||
#define TBL_OPT_BOX (1 << 1) /* Option "box". */
|
||||
#define TBL_OPT_CENTRE (1 << 2) /* Option "center". */
|
||||
#define TBL_OPT_DBOX (1 << 3) /* Option "doublebox". */
|
||||
#define TBL_OPT_EXPAND (1 << 4) /* Option "expand". */
|
||||
#define TBL_OPT_NOKEEP (1 << 5) /* Option "nokeep". */
|
||||
#define TBL_OPT_NOSPACE (1 << 6) /* Option "nospaces". */
|
||||
#define TBL_OPT_NOWARN (1 << 7) /* Option "nowarn". */
|
||||
int cols; /* Number of columns. */
|
||||
int lvert; /* Width of left vertical line. */
|
||||
int rvert; /* Width of right vertical line. */
|
||||
char tab; /* Option "tab": cell separator. */
|
||||
char decimal; /* Option "decimalpoint". */
|
||||
};
|
||||
|
||||
enum tbl_cellt {
|
||||
TBL_CELL_CENTRE, /* c, C */
|
||||
TBL_CELL_RIGHT, /* r, R */
|
||||
TBL_CELL_LEFT, /* l, L */
|
||||
TBL_CELL_NUMBER, /* n, N */
|
||||
TBL_CELL_SPAN, /* s, S */
|
||||
TBL_CELL_LONG, /* a, A */
|
||||
TBL_CELL_DOWN, /* ^ */
|
||||
TBL_CELL_HORIZ, /* _, - */
|
||||
TBL_CELL_DHORIZ, /* = */
|
||||
TBL_CELL_MAX
|
||||
};
|
||||
|
||||
/*
|
||||
* A cell in a layout row.
|
||||
*/
|
||||
struct tbl_cell {
|
||||
struct tbl_cell *next; /* Layout cell to the right. */
|
||||
char *wstr; /* Min width represented as a string. */
|
||||
size_t width; /* Minimum column width. */
|
||||
size_t spacing; /* To the right of the column. */
|
||||
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 tbl_cellt pos;
|
||||
};
|
||||
|
||||
/*
|
||||
* A layout row.
|
||||
*/
|
||||
struct tbl_row {
|
||||
struct tbl_row *next; /* Layout row below. */
|
||||
struct tbl_cell *first; /* Leftmost layout cell. */
|
||||
struct tbl_cell *last; /* Rightmost layout cell. */
|
||||
int vert; /* Width of left vertical line. */
|
||||
};
|
||||
|
||||
enum tbl_datt {
|
||||
TBL_DATA_NONE, /* Uninitialized row. */
|
||||
TBL_DATA_DATA, /* Contains data rather than a line. */
|
||||
TBL_DATA_HORIZ, /* _: connecting horizontal line. */
|
||||
TBL_DATA_DHORIZ, /* =: connecting double horizontal line. */
|
||||
TBL_DATA_NHORIZ, /* \_: isolated horizontal line. */
|
||||
TBL_DATA_NDHORIZ /* \=: isolated double horizontal line. */
|
||||
};
|
||||
|
||||
/*
|
||||
* A cell within a row of data. The "string" field contains the
|
||||
* actual string value that's in the cell. The rest is layout.
|
||||
*/
|
||||
struct tbl_dat {
|
||||
struct tbl_dat *next; /* Data cell to the right. */
|
||||
struct tbl_cell *layout; /* Associated layout cell. */
|
||||
char *string; /* Data, or NULL if not TBL_DATA_DATA. */
|
||||
int hspans; /* How many horizontal spans follow. */
|
||||
int vspans; /* How many vertical spans follow. */
|
||||
int block; /* T{ text block T} */
|
||||
enum tbl_datt pos;
|
||||
};
|
||||
|
||||
enum tbl_spant {
|
||||
TBL_SPAN_DATA, /* Contains data rather than a line. */
|
||||
TBL_SPAN_HORIZ, /* _: horizontal line. */
|
||||
TBL_SPAN_DHORIZ /* =: double horizontal line. */
|
||||
};
|
||||
|
||||
/*
|
||||
* A row of data in a table.
|
||||
*/
|
||||
struct tbl_span {
|
||||
struct tbl_opts *opts; /* Options for the table as a whole. */
|
||||
struct tbl_span *prev; /* Data row above. */
|
||||
struct tbl_span *next; /* Data row below. */
|
||||
struct tbl_row *layout; /* Associated layout row. */
|
||||
struct tbl_dat *first; /* Leftmost data cell. */
|
||||
struct tbl_dat *last; /* Rightmost data cell. */
|
||||
int line; /* Input file line number. */
|
||||
enum tbl_spant pos;
|
||||
};
|
113
tbl_data.c
113
tbl_data.c
@ -1,7 +1,7 @@
|
||||
/* $Id: tbl_data.c,v 1.45 2017/07/08 17:52:50 schwarze Exp $ */
|
||||
/* $Id: tbl_data.c,v 1.52 2019/02/09 16:00:39 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2011, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2011,2015,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
|
||||
@ -21,14 +21,16 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "mandoc_aux.h"
|
||||
#include "mandoc.h"
|
||||
#include "tbl.h"
|
||||
#include "libmandoc.h"
|
||||
#include "libroff.h"
|
||||
#include "tbl_int.h"
|
||||
|
||||
static void getdata(struct tbl_node *, struct tbl_span *,
|
||||
int, const char *, int *);
|
||||
@ -40,10 +42,20 @@ static void
|
||||
getdata(struct tbl_node *tbl, struct tbl_span *dp,
|
||||
int ln, const char *p, int *pos)
|
||||
{
|
||||
struct tbl_dat *dat;
|
||||
struct tbl_dat *dat, *pdat;
|
||||
struct tbl_cell *cp;
|
||||
struct tbl_span *pdp;
|
||||
int sv;
|
||||
|
||||
/*
|
||||
* 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)++;
|
||||
|
||||
/* Advance to the next layout cell, skipping spanners. */
|
||||
|
||||
cp = dp->last == NULL ? dp->layout->first : dp->last->layout->next;
|
||||
@ -65,34 +77,68 @@ getdata(struct tbl_node *tbl, struct tbl_span *dp,
|
||||
cp->col = dp->layout->last->col + 1;
|
||||
dp->layout->last = cp;
|
||||
} else {
|
||||
mandoc_msg(MANDOCERR_TBLDATA_EXTRA, tbl->parse,
|
||||
ln, *pos, p + *pos);
|
||||
while (p[*pos])
|
||||
mandoc_msg(MANDOCERR_TBLDATA_EXTRA,
|
||||
ln, sv, "%s", p + sv);
|
||||
while (p[*pos] != '\0')
|
||||
(*pos)++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dat = mandoc_calloc(1, sizeof(*dat));
|
||||
dat = mandoc_malloc(sizeof(*dat));
|
||||
dat->layout = cp;
|
||||
dat->next = NULL;
|
||||
dat->string = NULL;
|
||||
dat->hspans = 0;
|
||||
dat->vspans = 0;
|
||||
dat->block = 0;
|
||||
dat->pos = TBL_DATA_NONE;
|
||||
dat->spans = 0;
|
||||
|
||||
/*
|
||||
* Increment the number of vertical spans in a data cell above,
|
||||
* if this cell vertically extends one or more cells above.
|
||||
* The iteration must be done over data rows,
|
||||
* not over layout rows, because one layout row
|
||||
* can be reused for more than one data row.
|
||||
*/
|
||||
|
||||
if (cp->pos == TBL_CELL_DOWN ||
|
||||
(*pos - sv == 2 && p[sv] == '\\' && p[sv + 1] == '^')) {
|
||||
pdp = dp;
|
||||
while ((pdp = pdp->prev) != NULL) {
|
||||
pdat = pdp->first;
|
||||
while (pdat != NULL &&
|
||||
pdat->layout->col < dat->layout->col)
|
||||
pdat = pdat->next;
|
||||
if (pdat == NULL)
|
||||
break;
|
||||
if (pdat->layout->pos != TBL_CELL_DOWN &&
|
||||
strcmp(pdat->string, "\\^") != 0) {
|
||||
pdat->vspans++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Count the number of horizontal spans to the right of this cell.
|
||||
* This is purely a matter of the layout, independent of the data.
|
||||
*/
|
||||
|
||||
for (cp = cp->next; cp != NULL; cp = cp->next)
|
||||
if (cp->pos == TBL_CELL_SPAN)
|
||||
dat->spans++;
|
||||
dat->hspans++;
|
||||
else
|
||||
break;
|
||||
|
||||
/* Append the new data cell to the data row. */
|
||||
|
||||
if (dp->last == NULL)
|
||||
dp->first = dat;
|
||||
else
|
||||
dp->last->next = dat;
|
||||
dp->last = dat;
|
||||
|
||||
sv = *pos;
|
||||
while (p[*pos] && p[*pos] != tbl->opts.tab)
|
||||
(*pos)++;
|
||||
|
||||
/*
|
||||
* Check for a continued-data scope opening. This consists of a
|
||||
* trailing `T{' at the end of the line. Subsequent lines,
|
||||
@ -106,7 +152,7 @@ getdata(struct tbl_node *tbl, struct tbl_span *dp,
|
||||
|
||||
dat->string = mandoc_strndup(p + sv, *pos - sv);
|
||||
|
||||
if (p[*pos])
|
||||
if (p[*pos] != '\0')
|
||||
(*pos)++;
|
||||
|
||||
if ( ! strcmp(dat->string, "_"))
|
||||
@ -125,7 +171,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,
|
||||
tbl->parse, ln, sv, dat->string);
|
||||
ln, sv, "%s", dat->string);
|
||||
}
|
||||
|
||||
void
|
||||
@ -164,8 +210,8 @@ tbl_cdata(struct tbl_node *tbl, int ln, const char *p, int pos)
|
||||
dat->string = mandoc_strdup(p + pos);
|
||||
|
||||
if (dat->layout->pos == TBL_CELL_DOWN)
|
||||
mandoc_msg(MANDOCERR_TBLDATA_SPAN, tbl->parse,
|
||||
ln, pos, dat->string);
|
||||
mandoc_msg(MANDOCERR_TBLDATA_SPAN,
|
||||
ln, pos, "%s", dat->string);
|
||||
}
|
||||
|
||||
static struct tbl_span *
|
||||
@ -202,14 +248,27 @@ tbl_data(struct tbl_node *tbl, int ln, const char *p, int pos)
|
||||
|
||||
assert(rp != NULL);
|
||||
|
||||
if ( ! strcmp(p, "_")) {
|
||||
sp = newspan(tbl, ln, rp);
|
||||
sp->pos = TBL_SPAN_HORIZ;
|
||||
return;
|
||||
} else if ( ! strcmp(p, "=")) {
|
||||
sp = newspan(tbl, ln, rp);
|
||||
sp->pos = TBL_SPAN_DHORIZ;
|
||||
return;
|
||||
if (p[1] == '\0') {
|
||||
switch (p[0]) {
|
||||
case '.':
|
||||
/*
|
||||
* Empty request lines must be handled here
|
||||
* and cannot be discarded in roff_parseln()
|
||||
* because in the layout section, they
|
||||
* are significant and end the layout.
|
||||
*/
|
||||
return;
|
||||
case '_':
|
||||
sp = newspan(tbl, ln, rp);
|
||||
sp->pos = TBL_SPAN_HORIZ;
|
||||
return;
|
||||
case '=':
|
||||
sp = newspan(tbl, ln, rp);
|
||||
sp->pos = TBL_SPAN_DHORIZ;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
158
tbl_html.c
158
tbl_html.c
@ -1,7 +1,7 @@
|
||||
/* $Id: tbl_html.c,v 1.24 2018/06/25 13:45:57 schwarze Exp $ */
|
||||
/* $Id: tbl_html.c,v 1.32 2019/01/06 04:55:09 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 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
|
||||
@ -25,6 +25,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "tbl.h"
|
||||
#include "out.h"
|
||||
#include "html.h"
|
||||
|
||||
@ -79,6 +80,7 @@ html_tbl_sulen(const struct roffsu *su, void *arg)
|
||||
static void
|
||||
html_tblopen(struct html *h, const struct tbl_span *sp)
|
||||
{
|
||||
html_close_paragraph(h);
|
||||
if (h->tbl.cols == NULL) {
|
||||
h->tbl.len = html_tbl_len;
|
||||
h->tbl.slen = html_tbl_strlen;
|
||||
@ -86,7 +88,15 @@ html_tblopen(struct html *h, const struct tbl_span *sp)
|
||||
tblcalc(&h->tbl, sp, 0, 0);
|
||||
}
|
||||
assert(NULL == h->tblt);
|
||||
h->tblt = print_otag(h, TAG_TABLE, "c", "tbl");
|
||||
h->tblt = print_otag(h, TAG_TABLE, "c?ss", "tbl",
|
||||
"border",
|
||||
sp->opts->opts & TBL_OPT_ALLBOX ? "1" : NULL,
|
||||
"border-style",
|
||||
sp->opts->opts & TBL_OPT_DBOX ? "double" :
|
||||
sp->opts->opts & TBL_OPT_BOX ? "solid" : NULL,
|
||||
"border-top-style",
|
||||
sp->pos == TBL_SPAN_DHORIZ ? "double" :
|
||||
sp->pos == TBL_SPAN_HORIZ ? "solid" : NULL);
|
||||
}
|
||||
|
||||
void
|
||||
@ -101,43 +111,138 @@ print_tblclose(struct html *h)
|
||||
void
|
||||
print_tbl(struct html *h, const struct tbl_span *sp)
|
||||
{
|
||||
const struct tbl_dat *dp;
|
||||
struct tag *tt;
|
||||
int ic;
|
||||
|
||||
/* Inhibit printing of spaces: we do padding ourselves. */
|
||||
const struct tbl_dat *dp;
|
||||
const struct tbl_cell *cp;
|
||||
const struct tbl_span *psp;
|
||||
struct tag *tt;
|
||||
const char *hspans, *vspans, *halign, *valign;
|
||||
const char *bborder, *lborder, *rborder;
|
||||
char hbuf[4], vbuf[4];
|
||||
int i;
|
||||
|
||||
if (h->tblt == NULL)
|
||||
html_tblopen(h, sp);
|
||||
|
||||
assert(h->tblt);
|
||||
/*
|
||||
* Horizontal lines spanning the whole table
|
||||
* are handled by previous or following table rows.
|
||||
*/
|
||||
|
||||
if (sp->pos != TBL_SPAN_DATA)
|
||||
return;
|
||||
|
||||
/* Inhibit printing of spaces: we do padding ourselves. */
|
||||
|
||||
h->flags |= HTML_NONOSPACE;
|
||||
h->flags |= HTML_NOSPACE;
|
||||
|
||||
tt = print_otag(h, TAG_TR, "");
|
||||
/* Draw a vertical line left of this row? */
|
||||
|
||||
switch (sp->pos) {
|
||||
case TBL_SPAN_HORIZ:
|
||||
case TBL_SPAN_DHORIZ:
|
||||
print_otag(h, TAG_TD, "?", "colspan", "0");
|
||||
switch (sp->layout->vert) {
|
||||
case 2:
|
||||
lborder = "double";
|
||||
break;
|
||||
case 1:
|
||||
lborder = "solid";
|
||||
break;
|
||||
default:
|
||||
dp = sp->first;
|
||||
for (ic = 0; ic < sp->opts->cols; ic++) {
|
||||
print_stagq(h, tt);
|
||||
print_otag(h, TAG_TD, "");
|
||||
|
||||
if (dp == NULL || dp->layout->col > ic)
|
||||
continue;
|
||||
if (dp->layout->pos != TBL_CELL_DOWN)
|
||||
if (dp->string != NULL)
|
||||
print_text(h, dp->string);
|
||||
dp = dp->next;
|
||||
}
|
||||
lborder = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Draw a horizontal line below this row? */
|
||||
|
||||
bborder = NULL;
|
||||
if ((psp = sp->next) != NULL) {
|
||||
switch (psp->pos) {
|
||||
case TBL_SPAN_DHORIZ:
|
||||
bborder = "double";
|
||||
break;
|
||||
case TBL_SPAN_HORIZ:
|
||||
bborder = "solid";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tt = print_otag(h, TAG_TR, "ss",
|
||||
"border-left-style", lborder,
|
||||
"border-bottom-style", bborder);
|
||||
|
||||
for (dp = sp->first; dp != NULL; dp = dp->next) {
|
||||
print_stagq(h, tt);
|
||||
|
||||
/*
|
||||
* Do not generate <td> elements for continuations
|
||||
* of spanned cells. Larger <td> elements covering
|
||||
* this space were already generated earlier.
|
||||
*/
|
||||
|
||||
cp = dp->layout;
|
||||
if (cp->pos == TBL_CELL_SPAN || cp->pos == TBL_CELL_DOWN ||
|
||||
(dp->string != NULL && strcmp(dp->string, "\\^") == 0))
|
||||
continue;
|
||||
|
||||
/* Determine the attribute values. */
|
||||
|
||||
if (dp->hspans > 0) {
|
||||
(void)snprintf(hbuf, sizeof(hbuf),
|
||||
"%d", dp->hspans + 1);
|
||||
hspans = hbuf;
|
||||
} else
|
||||
hspans = NULL;
|
||||
if (dp->vspans > 0) {
|
||||
(void)snprintf(vbuf, sizeof(vbuf),
|
||||
"%d", dp->vspans + 1);
|
||||
vspans = vbuf;
|
||||
} else
|
||||
vspans = NULL;
|
||||
|
||||
switch (cp->pos) {
|
||||
case TBL_CELL_CENTRE:
|
||||
halign = "center";
|
||||
break;
|
||||
case TBL_CELL_RIGHT:
|
||||
case TBL_CELL_NUMBER:
|
||||
halign = "right";
|
||||
break;
|
||||
default:
|
||||
halign = NULL;
|
||||
break;
|
||||
}
|
||||
if (cp->flags & TBL_CELL_TALIGN)
|
||||
valign = "top";
|
||||
else if (cp->flags & TBL_CELL_BALIGN)
|
||||
valign = "bottom";
|
||||
else
|
||||
valign = NULL;
|
||||
|
||||
for (i = dp->hspans; i > 0; i--)
|
||||
cp = cp->next;
|
||||
switch (cp->vert) {
|
||||
case 2:
|
||||
rborder = "double";
|
||||
break;
|
||||
case 1:
|
||||
rborder = "solid";
|
||||
break;
|
||||
default:
|
||||
rborder = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Print the element and the attributes. */
|
||||
|
||||
print_otag(h, TAG_TD, "??sss",
|
||||
"colspan", hspans, "rowspan", vspans,
|
||||
"vertical-align", valign,
|
||||
"text-align", halign,
|
||||
"border-right-style", rborder);
|
||||
if (dp->string != NULL)
|
||||
print_text(h, dp->string);
|
||||
}
|
||||
|
||||
print_tagq(h, tt);
|
||||
|
||||
h->flags &= ~HTML_NONOSPACE;
|
||||
@ -148,5 +253,4 @@ print_tbl(struct html *h, const struct tbl_span *sp)
|
||||
h->tbl.cols = NULL;
|
||||
print_tblclose(h);
|
||||
}
|
||||
|
||||
}
|
||||
|
47
tbl_int.h
Normal file
47
tbl_int.h
Normal file
@ -0,0 +1,47 @@
|
||||
/* $Id: tbl_int.h,v 1.2 2018/12/14 06:33:14 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2011,2013,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
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Internal interfaces of the tbl(7) parser.
|
||||
* For use inside the tbl(7) parser only.
|
||||
*/
|
||||
|
||||
enum tbl_part {
|
||||
TBL_PART_OPTS, /* In the first line, ends with semicolon. */
|
||||
TBL_PART_LAYOUT, /* In the layout section, ends with full stop. */
|
||||
TBL_PART_DATA, /* In the data section, ends with TE. */
|
||||
TBL_PART_CDATA /* In a T{ block, ends with T} */
|
||||
};
|
||||
|
||||
struct tbl_node {
|
||||
struct tbl_opts opts; /* Options for the whole table. */
|
||||
struct tbl_node *next; /* Next table. */
|
||||
struct tbl_row *first_row; /* First layout row. */
|
||||
struct tbl_row *last_row; /* Last layout row. */
|
||||
struct tbl_span *first_span; /* First data row. */
|
||||
struct tbl_span *current_span; /* Data row being parsed. */
|
||||
struct tbl_span *last_span; /* Last data row. */
|
||||
int line; /* Line number in input file. */
|
||||
int pos; /* Column number in input file. */
|
||||
enum tbl_part part; /* Table section being parsed. */
|
||||
};
|
||||
|
||||
|
||||
void tbl_option(struct tbl_node *, int, const char *, int *);
|
||||
void tbl_layout(struct tbl_node *, int, const char *, int);
|
||||
void tbl_data(struct tbl_node *, int, const char *, int);
|
||||
void tbl_cdata(struct tbl_node *, int, const char *, int);
|
||||
void tbl_reset(struct tbl_node *);
|
34
tbl_layout.c
34
tbl_layout.c
@ -1,4 +1,4 @@
|
||||
/* $Id: tbl_layout.c,v 1.44 2017/06/27 18:25:02 schwarze Exp $ */
|
||||
/* $Id: tbl_layout.c,v 1.48 2018/12/14 05:18:03 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2012, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
@ -21,14 +21,16 @@
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "mandoc_aux.h"
|
||||
#include "mandoc.h"
|
||||
#include "tbl.h"
|
||||
#include "libmandoc.h"
|
||||
#include "libroff.h"
|
||||
#include "tbl_int.h"
|
||||
|
||||
struct tbl_phrase {
|
||||
char name;
|
||||
@ -84,8 +86,7 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
|
||||
(*pos)++;
|
||||
goto mod;
|
||||
}
|
||||
mandoc_msg(MANDOCERR_TBLLAYOUT_PAR, tbl->parse,
|
||||
ln, *pos, NULL);
|
||||
mandoc_msg(MANDOCERR_TBLLAYOUT_PAR, ln, *pos, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -113,8 +114,7 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
|
||||
cp->flags |= TBL_CELL_ITALIC;
|
||||
goto mod;
|
||||
case 'm':
|
||||
mandoc_msg(MANDOCERR_TBLLAYOUT_MOD, tbl->parse,
|
||||
ln, *pos, "m");
|
||||
mandoc_msg(MANDOCERR_TBLLAYOUT_MOD, ln, *pos, "m");
|
||||
goto mod;
|
||||
case 'p':
|
||||
case 'v':
|
||||
@ -157,10 +157,10 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
|
||||
cp->vert++;
|
||||
else
|
||||
mandoc_msg(MANDOCERR_TBLLAYOUT_VERT,
|
||||
tbl->parse, ln, *pos - 1, NULL);
|
||||
ln, *pos - 1, NULL);
|
||||
goto mod;
|
||||
default:
|
||||
mandoc_vmsg(MANDOCERR_TBLLAYOUT_CHAR, tbl->parse,
|
||||
mandoc_msg(MANDOCERR_TBLLAYOUT_CHAR,
|
||||
ln, *pos - 1, "%c", p[*pos - 1]);
|
||||
goto mod;
|
||||
}
|
||||
@ -173,7 +173,7 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
|
||||
/* Support only one-character font-names for now. */
|
||||
|
||||
if (p[*pos] == '\0' || (p[*pos + 1] != ' ' && p[*pos + 1] != '.')) {
|
||||
mandoc_vmsg(MANDOCERR_FT_BAD, tbl->parse,
|
||||
mandoc_msg(MANDOCERR_FT_BAD,
|
||||
ln, *pos, "TS %s", p + *pos - 1);
|
||||
if (p[*pos] != '\0')
|
||||
(*pos)++;
|
||||
@ -195,7 +195,7 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
|
||||
case 'R':
|
||||
goto mod;
|
||||
default:
|
||||
mandoc_vmsg(MANDOCERR_FT_BAD, tbl->parse,
|
||||
mandoc_msg(MANDOCERR_FT_BAD,
|
||||
ln, *pos - 1, "TS f%c", p[*pos - 1]);
|
||||
goto mod;
|
||||
}
|
||||
@ -216,7 +216,7 @@ cell(struct tbl_node *tbl, struct tbl_row *rp,
|
||||
rp->vert++;
|
||||
else
|
||||
mandoc_msg(MANDOCERR_TBLLAYOUT_VERT,
|
||||
tbl->parse, ln, *pos, NULL);
|
||||
ln, *pos, NULL);
|
||||
}
|
||||
(*pos)++;
|
||||
}
|
||||
@ -235,7 +235,7 @@ cell(struct tbl_node *tbl, struct tbl_row *rp,
|
||||
break;
|
||||
|
||||
if (i == KEYS_MAX) {
|
||||
mandoc_vmsg(MANDOCERR_TBLLAYOUT_CHAR, tbl->parse,
|
||||
mandoc_msg(MANDOCERR_TBLLAYOUT_CHAR,
|
||||
ln, *pos, "%c", p[*pos]);
|
||||
(*pos)++;
|
||||
goto again;
|
||||
@ -246,14 +246,12 @@ cell(struct tbl_node *tbl, struct tbl_row *rp,
|
||||
|
||||
if (c == TBL_CELL_SPAN) {
|
||||
if (rp->last == NULL)
|
||||
mandoc_msg(MANDOCERR_TBLLAYOUT_SPAN,
|
||||
tbl->parse, ln, *pos, NULL);
|
||||
mandoc_msg(MANDOCERR_TBLLAYOUT_SPAN, ln, *pos, NULL);
|
||||
else if (rp->last->pos == TBL_CELL_HORIZ ||
|
||||
rp->last->pos == TBL_CELL_DHORIZ)
|
||||
c = rp->last->pos;
|
||||
} else if (c == TBL_CELL_DOWN && rp == tbl->first_row)
|
||||
mandoc_msg(MANDOCERR_TBLLAYOUT_DOWN,
|
||||
tbl->parse, ln, *pos, NULL);
|
||||
mandoc_msg(MANDOCERR_TBLLAYOUT_DOWN, ln, *pos, NULL);
|
||||
|
||||
(*pos)++;
|
||||
|
||||
@ -296,7 +294,7 @@ tbl_layout(struct tbl_node *tbl, int ln, const char *p, int pos)
|
||||
}
|
||||
if (tbl->first_row->first == NULL) {
|
||||
mandoc_msg(MANDOCERR_TBLLAYOUT_NONE,
|
||||
tbl->parse, ln, pos, NULL);
|
||||
ln, pos, NULL);
|
||||
cell_alloc(tbl, tbl->first_row,
|
||||
TBL_CELL_LEFT);
|
||||
if (tbl->opts.lvert < tbl->first_row->vert)
|
||||
|
22
tbl_opts.c
22
tbl_opts.c
@ -1,4 +1,4 @@
|
||||
/* $Id: tbl_opts.c,v 1.21 2015/09/26 00:54:04 schwarze Exp $ */
|
||||
/* $Id: tbl_opts.c,v 1.24 2018/12/14 05:18:03 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
|
||||
@ -25,8 +25,9 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "tbl.h"
|
||||
#include "libmandoc.h"
|
||||
#include "libroff.h"
|
||||
#include "tbl_int.h"
|
||||
|
||||
#define KEY_DPOINT 0
|
||||
#define KEY_DELIM 1
|
||||
@ -80,7 +81,7 @@ arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key)
|
||||
|
||||
switch (key) {
|
||||
case KEY_DELIM:
|
||||
mandoc_vmsg(MANDOCERR_TBLOPT_EQN, tbl->parse,
|
||||
mandoc_msg(MANDOCERR_TBLOPT_EQN,
|
||||
ln, *pos, "%.*s", len, p + *pos);
|
||||
want = 2;
|
||||
break;
|
||||
@ -102,12 +103,11 @@ arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key)
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
mandoc_msg(MANDOCERR_TBLOPT_NOARG,
|
||||
tbl->parse, ln, *pos, keys[key].name);
|
||||
mandoc_msg(MANDOCERR_TBLOPT_NOARG, ln, *pos,
|
||||
"%s", keys[key].name);
|
||||
else if (want && len != want)
|
||||
mandoc_vmsg(MANDOCERR_TBLOPT_ARGSZ,
|
||||
tbl->parse, ln, *pos, "%s want %d have %d",
|
||||
keys[key].name, want, len);
|
||||
mandoc_msg(MANDOCERR_TBLOPT_ARGSZ, ln, *pos,
|
||||
"%s want %d have %d", keys[key].name, want, len);
|
||||
|
||||
*pos += len;
|
||||
if (p[*pos] == ')')
|
||||
@ -141,8 +141,8 @@ tbl_option(struct tbl_node *tbl, int ln, const char *p, int *offs)
|
||||
len++;
|
||||
|
||||
if (len == 0) {
|
||||
mandoc_vmsg(MANDOCERR_TBLOPT_ALPHA,
|
||||
tbl->parse, ln, pos, "%c", p[pos]);
|
||||
mandoc_msg(MANDOCERR_TBLOPT_ALPHA,
|
||||
ln, pos, "%c", p[pos]);
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
@ -156,7 +156,7 @@ tbl_option(struct tbl_node *tbl, int ln, const char *p, int *offs)
|
||||
i++;
|
||||
|
||||
if (i == KEY_MAXKEYS) {
|
||||
mandoc_vmsg(MANDOCERR_TBLOPT_BAD, tbl->parse,
|
||||
mandoc_msg(MANDOCERR_TBLOPT_BAD,
|
||||
ln, pos, "%.*s", len, p + pos);
|
||||
pos += len;
|
||||
continue;
|
||||
|
30
tbl_parse.h
Normal file
30
tbl_parse.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* $Id: tbl_parse.h,v 1.2 2018/12/14 06:33:14 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2011, 2017 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 AUTHORS DISCLAIM ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* External interface of the tbl(7) parser.
|
||||
* For use in the roff(7) and tbl(7) parsers only.
|
||||
*/
|
||||
|
||||
struct tbl_node;
|
||||
struct tbl_span;
|
||||
|
||||
struct tbl_node *tbl_alloc(int, int, struct tbl_node *);
|
||||
int tbl_end(struct tbl_node *, int);
|
||||
void tbl_free(struct tbl_node *);
|
||||
void tbl_read(struct tbl_node *, int, const char *, int);
|
||||
void tbl_restart(int, int, struct tbl_node *);
|
||||
struct tbl_span *tbl_span(struct tbl_node *);
|
665
tbl_term.c
665
tbl_term.c
@ -1,7 +1,7 @@
|
||||
/* $Id: tbl_term.c,v 1.57 2017/07/31 16:14:10 schwarze Exp $ */
|
||||
/* $Id: tbl_term.c,v 1.68 2019/02/09 21:02:47 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2011,2012,2014,2015,2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2011-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
|
||||
@ -20,34 +20,121 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mandoc.h"
|
||||
#include "tbl.h"
|
||||
#include "out.h"
|
||||
#include "term.h"
|
||||
|
||||
#define IS_HORIZ(cp) ((cp)->pos == TBL_CELL_HORIZ || \
|
||||
(cp)->pos == TBL_CELL_DHORIZ)
|
||||
|
||||
|
||||
static size_t term_tbl_len(size_t, void *);
|
||||
static size_t term_tbl_strlen(const char *, void *);
|
||||
static size_t term_tbl_sulen(const struct roffsu *, void *);
|
||||
static void tbl_char(struct termp *, char, size_t);
|
||||
static void tbl_data(struct termp *, const struct tbl_opts *,
|
||||
const struct tbl_cell *,
|
||||
const struct tbl_dat *,
|
||||
const struct roffcol *);
|
||||
static void tbl_direct_border(struct termp *, int, size_t);
|
||||
static void tbl_fill_border(struct termp *, int, size_t);
|
||||
static void tbl_fill_char(struct termp *, char, size_t);
|
||||
static void tbl_fill_string(struct termp *, const char *, size_t);
|
||||
static void tbl_hrule(struct termp *, const struct tbl_span *,
|
||||
const struct tbl_span *, int);
|
||||
static void tbl_literal(struct termp *, const struct tbl_dat *,
|
||||
const struct roffcol *);
|
||||
static void tbl_number(struct termp *, const struct tbl_opts *,
|
||||
const struct tbl_dat *,
|
||||
const struct roffcol *);
|
||||
static void tbl_hrule(struct termp *, const struct tbl_span *, int);
|
||||
static void tbl_word(struct termp *, const struct tbl_dat *);
|
||||
|
||||
|
||||
/*
|
||||
* The following border-character tables are indexed
|
||||
* by ternary (3-based) numbers, as opposed to binary or decimal.
|
||||
* Each ternary digit describes the line width in one direction:
|
||||
* 0 means no line, 1 single or light line, 2 double or heavy line.
|
||||
*/
|
||||
|
||||
/* Positional values of the four directions. */
|
||||
#define BRIGHT 1
|
||||
#define BDOWN 3
|
||||
#define BLEFT (3 * 3)
|
||||
#define BUP (3 * 3 * 3)
|
||||
#define BHORIZ (BLEFT + BRIGHT)
|
||||
|
||||
/* Code points to use for each combination of widths. */
|
||||
static const int borders_utf8[81] = {
|
||||
0x0020, 0x2576, 0x257a, /* 000 right */
|
||||
0x2577, 0x250c, 0x250d, /* 001 down */
|
||||
0x257b, 0x250e, 0x250f, /* 002 */
|
||||
0x2574, 0x2500, 0x257c, /* 010 left */
|
||||
0x2510, 0x252c, 0x252e, /* 011 left down */
|
||||
0x2512, 0x2530, 0x2532, /* 012 */
|
||||
0x2578, 0x257e, 0x2501, /* 020 left */
|
||||
0x2511, 0x252d, 0x252f, /* 021 left down */
|
||||
0x2513, 0x2531, 0x2533, /* 022 */
|
||||
0x2575, 0x2514, 0x2515, /* 100 up */
|
||||
0x2502, 0x251c, 0x251d, /* 101 up down */
|
||||
0x257d, 0x251f, 0x2522, /* 102 */
|
||||
0x2518, 0x2534, 0x2536, /* 110 up left */
|
||||
0x2524, 0x253c, 0x253e, /* 111 all */
|
||||
0x2527, 0x2541, 0x2546, /* 112 */
|
||||
0x2519, 0x2535, 0x2537, /* 120 up left */
|
||||
0x2525, 0x253d, 0x253f, /* 121 all */
|
||||
0x252a, 0x2545, 0x2548, /* 122 */
|
||||
0x2579, 0x2516, 0x2517, /* 200 up */
|
||||
0x257f, 0x251e, 0x2521, /* 201 up down */
|
||||
0x2503, 0x2520, 0x2523, /* 202 */
|
||||
0x251a, 0x2538, 0x253a, /* 210 up left */
|
||||
0x2526, 0x2540, 0x2544, /* 211 all */
|
||||
0x2528, 0x2542, 0x254a, /* 212 */
|
||||
0x251b, 0x2539, 0x253b, /* 220 up left */
|
||||
0x2529, 0x2543, 0x2547, /* 221 all */
|
||||
0x252b, 0x2549, 0x254b, /* 222 */
|
||||
};
|
||||
|
||||
/* ASCII approximations for these code points, compatible with groff. */
|
||||
static const int borders_ascii[81] = {
|
||||
' ', '-', '=', /* 000 right */
|
||||
'|', '+', '+', /* 001 down */
|
||||
'|', '+', '+', /* 002 */
|
||||
'-', '-', '=', /* 010 left */
|
||||
'+', '+', '+', /* 011 left down */
|
||||
'+', '+', '+', /* 012 */
|
||||
'=', '=', '=', /* 020 left */
|
||||
'+', '+', '+', /* 021 left down */
|
||||
'+', '+', '+', /* 022 */
|
||||
'|', '+', '+', /* 100 up */
|
||||
'|', '+', '+', /* 101 up down */
|
||||
'|', '+', '+', /* 102 */
|
||||
'+', '+', '+', /* 110 up left */
|
||||
'+', '+', '+', /* 111 all */
|
||||
'+', '+', '+', /* 112 */
|
||||
'+', '+', '+', /* 120 up left */
|
||||
'+', '+', '+', /* 121 all */
|
||||
'+', '+', '+', /* 122 */
|
||||
'|', '+', '+', /* 200 up */
|
||||
'|', '+', '+', /* 201 up down */
|
||||
'|', '+', '+', /* 202 */
|
||||
'+', '+', '+', /* 210 up left */
|
||||
'+', '+', '+', /* 211 all */
|
||||
'+', '+', '+', /* 212 */
|
||||
'+', '+', '+', /* 220 up left */
|
||||
'+', '+', '+', /* 221 all */
|
||||
'+', '+', '+', /* 222 */
|
||||
};
|
||||
|
||||
/* Either of the above according to the selected output encoding. */
|
||||
static const int *borders_locale;
|
||||
|
||||
|
||||
static size_t
|
||||
term_tbl_sulen(const struct roffsu *su, void *arg)
|
||||
{
|
||||
@ -69,19 +156,22 @@ term_tbl_len(size_t sz, void *arg)
|
||||
return term_len((const struct termp *)arg, sz);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
term_tbl(struct termp *tp, const struct tbl_span *sp)
|
||||
{
|
||||
const struct tbl_cell *cp, *cpn, *cpp;
|
||||
const struct tbl_cell *cp, *cpn, *cpp, *cps;
|
||||
const struct tbl_dat *dp;
|
||||
static size_t offset;
|
||||
size_t save_offset;
|
||||
size_t coloff, tsz;
|
||||
int ic, horiz, spans, vert, more;
|
||||
char fc;
|
||||
int hspans, ic, more;
|
||||
int dvert, fc, horiz, lhori, rhori, uvert;
|
||||
|
||||
/* Inhibit printing of spaces: we do padding ourselves. */
|
||||
|
||||
tp->flags |= TERMP_NOSPACE | TERMP_NONOSPACE;
|
||||
save_offset = tp->tcol->offset;
|
||||
|
||||
/*
|
||||
* The first time we're invoked for a given table block,
|
||||
@ -89,6 +179,9 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
|
||||
*/
|
||||
|
||||
if (tp->tbl.cols == NULL) {
|
||||
borders_locale = tp->enc == TERMENC_UTF8 ?
|
||||
borders_utf8 : borders_ascii;
|
||||
|
||||
tp->tbl.len = term_tbl_len;
|
||||
tp->tbl.slen = term_tbl_strlen;
|
||||
tp->tbl.sulen = term_tbl_sulen;
|
||||
@ -120,21 +213,24 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
|
||||
tsz += tp->tbl.cols[sp->opts->cols - 1].width;
|
||||
if (offset + tsz > tp->tcol->rmargin)
|
||||
tsz -= 1;
|
||||
tp->tcol->offset = offset + tp->tcol->rmargin > tsz ?
|
||||
offset = offset + tp->tcol->rmargin > tsz ?
|
||||
(offset + tp->tcol->rmargin - tsz) / 2 : 0;
|
||||
tp->tcol->offset = offset;
|
||||
}
|
||||
|
||||
/* Horizontal frame at the start of boxed tables. */
|
||||
|
||||
if (sp->opts->opts & TBL_OPT_DBOX)
|
||||
tbl_hrule(tp, sp, 3);
|
||||
if (tp->enc == TERMENC_ASCII &&
|
||||
sp->opts->opts & TBL_OPT_DBOX)
|
||||
tbl_hrule(tp, NULL, sp, TBL_OPT_DBOX);
|
||||
if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX))
|
||||
tbl_hrule(tp, sp, 2);
|
||||
tbl_hrule(tp, NULL, sp, TBL_OPT_BOX);
|
||||
}
|
||||
|
||||
/* Set up the columns. */
|
||||
|
||||
tp->flags |= TERMP_MULTICOL;
|
||||
tp->tcol->offset = offset;
|
||||
horiz = 0;
|
||||
switch (sp->pos) {
|
||||
case TBL_SPAN_HORIZ:
|
||||
@ -156,9 +252,9 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
|
||||
/* Set up the data columns. */
|
||||
|
||||
dp = sp->first;
|
||||
spans = 0;
|
||||
hspans = 0;
|
||||
for (ic = 0; ic < sp->opts->cols; ic++) {
|
||||
if (spans == 0) {
|
||||
if (hspans == 0) {
|
||||
tp->tcol++;
|
||||
tp->tcol->offset = coloff;
|
||||
}
|
||||
@ -166,13 +262,13 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
|
||||
tp->tcol->rmargin = coloff;
|
||||
if (ic + 1 < sp->opts->cols)
|
||||
coloff += tp->tbl.cols[ic].spacing;
|
||||
if (spans) {
|
||||
spans--;
|
||||
if (hspans) {
|
||||
hspans--;
|
||||
continue;
|
||||
}
|
||||
if (dp == NULL)
|
||||
continue;
|
||||
spans = dp->spans;
|
||||
hspans = dp->hspans;
|
||||
if (ic || sp->layout->first->pos != TBL_CELL_SPAN)
|
||||
dp = dp->next;
|
||||
}
|
||||
@ -192,14 +288,14 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
|
||||
tp->tcol = tp->tcols;
|
||||
cp = cpn = sp->layout->first;
|
||||
dp = sp->first;
|
||||
spans = 0;
|
||||
hspans = 0;
|
||||
for (ic = 0; ic < sp->opts->cols; ic++) {
|
||||
if (cpn != NULL) {
|
||||
cp = cpn;
|
||||
cpn = cpn->next;
|
||||
}
|
||||
if (spans) {
|
||||
spans--;
|
||||
if (hspans) {
|
||||
hspans--;
|
||||
continue;
|
||||
}
|
||||
tp->tcol++;
|
||||
@ -207,7 +303,7 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
|
||||
tbl_data(tp, sp->opts, cp, dp, tp->tbl.cols + ic);
|
||||
if (dp == NULL)
|
||||
continue;
|
||||
spans = dp->spans;
|
||||
hspans = dp->hspans;
|
||||
if (cp->pos != TBL_CELL_SPAN)
|
||||
dp = dp->next;
|
||||
}
|
||||
@ -218,37 +314,43 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
|
||||
/* Print the vertical frame at the start of each row. */
|
||||
|
||||
tp->tcol = tp->tcols;
|
||||
fc = '\0';
|
||||
if (sp->layout->vert ||
|
||||
(sp->next != NULL && sp->next->layout->vert &&
|
||||
sp->next->pos == TBL_SPAN_DATA) ||
|
||||
(sp->prev != NULL && sp->prev->layout->vert &&
|
||||
(horiz || (IS_HORIZ(sp->layout->first) &&
|
||||
!IS_HORIZ(sp->prev->layout->first)))) ||
|
||||
sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX))
|
||||
fc = horiz || IS_HORIZ(sp->layout->first) ? '+' : '|';
|
||||
else if (horiz && sp->opts->lvert)
|
||||
fc = '-';
|
||||
if (fc != '\0') {
|
||||
uvert = dvert = sp->opts->opts & TBL_OPT_DBOX ? 2 :
|
||||
sp->opts->opts & TBL_OPT_BOX ? 1 : 0;
|
||||
if (sp->pos == TBL_SPAN_DATA && uvert < sp->layout->vert)
|
||||
uvert = dvert = sp->layout->vert;
|
||||
if (sp->next != NULL && sp->next->pos == TBL_SPAN_DATA &&
|
||||
dvert < sp->next->layout->vert)
|
||||
dvert = sp->next->layout->vert;
|
||||
if (sp->prev != NULL && uvert < sp->prev->layout->vert &&
|
||||
(horiz || (IS_HORIZ(sp->layout->first) &&
|
||||
!IS_HORIZ(sp->prev->layout->first))))
|
||||
uvert = sp->prev->layout->vert;
|
||||
rhori = sp->pos == TBL_SPAN_DHORIZ ||
|
||||
(sp->first != NULL && sp->first->pos == TBL_DATA_DHORIZ) ||
|
||||
sp->layout->first->pos == TBL_CELL_DHORIZ ? 2 :
|
||||
sp->pos == TBL_SPAN_HORIZ ||
|
||||
(sp->first != NULL && sp->first->pos == TBL_DATA_HORIZ) ||
|
||||
sp->layout->first->pos == TBL_CELL_HORIZ ? 1 : 0;
|
||||
fc = BUP * uvert + BDOWN * dvert + BRIGHT * rhori;
|
||||
if (uvert > 0 || dvert > 0 || (horiz && sp->opts->lvert)) {
|
||||
(*tp->advance)(tp, tp->tcols->offset);
|
||||
(*tp->letter)(tp, fc);
|
||||
tp->viscol = tp->tcol->offset + 1;
|
||||
tp->viscol = tp->tcol->offset;
|
||||
tbl_direct_border(tp, fc, 1);
|
||||
}
|
||||
|
||||
/* Print the data cells. */
|
||||
|
||||
more = 0;
|
||||
if (horiz) {
|
||||
tbl_hrule(tp, sp, 0);
|
||||
term_flushln(tp);
|
||||
} else {
|
||||
if (horiz)
|
||||
tbl_hrule(tp, sp->prev, sp, 0);
|
||||
else {
|
||||
cp = sp->layout->first;
|
||||
cpn = sp->next == NULL ? NULL :
|
||||
sp->next->layout->first;
|
||||
cpp = sp->prev == NULL ? NULL :
|
||||
sp->prev->layout->first;
|
||||
dp = sp->first;
|
||||
spans = 0;
|
||||
hspans = 0;
|
||||
for (ic = 0; ic < sp->opts->cols; ic++) {
|
||||
|
||||
/*
|
||||
@ -257,25 +359,27 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
|
||||
* and advance to next layout cell.
|
||||
*/
|
||||
|
||||
uvert = dvert = fc = 0;
|
||||
if (cp != NULL) {
|
||||
vert = cp->vert;
|
||||
cps = cp;
|
||||
while (cps->next != NULL &&
|
||||
cps->next->pos == TBL_CELL_SPAN)
|
||||
cps = cps->next;
|
||||
if (sp->pos == TBL_SPAN_DATA)
|
||||
uvert = dvert = cps->vert;
|
||||
switch (cp->pos) {
|
||||
case TBL_CELL_HORIZ:
|
||||
fc = '-';
|
||||
fc = BHORIZ;
|
||||
break;
|
||||
case TBL_CELL_DHORIZ:
|
||||
fc = '=';
|
||||
fc = BHORIZ * 2;
|
||||
break;
|
||||
default:
|
||||
fc = ' ';
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
vert = 0;
|
||||
fc = ' ';
|
||||
}
|
||||
if (cpp != NULL) {
|
||||
if (vert == 0 &&
|
||||
if (uvert < cpp->vert &&
|
||||
cp != NULL &&
|
||||
((IS_HORIZ(cp) &&
|
||||
!IS_HORIZ(cpp)) ||
|
||||
@ -283,19 +387,31 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
|
||||
cpp->next != NULL &&
|
||||
IS_HORIZ(cp->next) &&
|
||||
!IS_HORIZ(cpp->next))))
|
||||
vert = cpp->vert;
|
||||
uvert = cpp->vert;
|
||||
cpp = cpp->next;
|
||||
}
|
||||
if (vert == 0 &&
|
||||
sp->opts->opts & TBL_OPT_ALLBOX)
|
||||
vert = 1;
|
||||
if (sp->opts->opts & TBL_OPT_ALLBOX) {
|
||||
if (uvert == 0)
|
||||
uvert = 1;
|
||||
if (dvert == 0)
|
||||
dvert = 1;
|
||||
}
|
||||
if (cpn != NULL) {
|
||||
if (vert == 0)
|
||||
vert = cpn->vert;
|
||||
if (dvert == 0 ||
|
||||
(dvert < cpn->vert &&
|
||||
tp->enc == TERMENC_UTF8))
|
||||
dvert = cpn->vert;
|
||||
cpn = cpn->next;
|
||||
}
|
||||
if (cp != NULL)
|
||||
cp = cp->next;
|
||||
|
||||
lhori = (cp != NULL &&
|
||||
cp->pos == TBL_CELL_DHORIZ) ||
|
||||
(dp != NULL &&
|
||||
dp->pos == TBL_DATA_DHORIZ) ? 2 :
|
||||
(cp != NULL &&
|
||||
cp->pos == TBL_CELL_HORIZ) ||
|
||||
(dp != NULL &&
|
||||
dp->pos == TBL_DATA_HORIZ) ? 1 : 0;
|
||||
|
||||
/*
|
||||
* Skip later cells in a span,
|
||||
@ -303,12 +419,13 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
|
||||
* and advance to next data cell.
|
||||
*/
|
||||
|
||||
if (spans) {
|
||||
spans--;
|
||||
if (hspans) {
|
||||
hspans--;
|
||||
cp = cp->next;
|
||||
continue;
|
||||
}
|
||||
if (dp != NULL) {
|
||||
spans = dp->spans;
|
||||
hspans = dp->hspans;
|
||||
if (ic || sp->layout->first->pos
|
||||
!= TBL_CELL_SPAN)
|
||||
dp = dp->next;
|
||||
@ -330,10 +447,16 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
|
||||
* but not after the last column.
|
||||
*/
|
||||
|
||||
if (fc == ' ' && ((vert == 0 &&
|
||||
(cp == NULL || !IS_HORIZ(cp))) ||
|
||||
tp->tcol + 1 == tp->tcols + tp->lasttcol))
|
||||
if (fc == 0 &&
|
||||
((uvert == 0 && dvert == 0 &&
|
||||
cp != NULL && (cp->next == NULL ||
|
||||
!IS_HORIZ(cp->next))) ||
|
||||
tp->tcol + 1 ==
|
||||
tp->tcols + tp->lasttcol)) {
|
||||
if (cp != NULL)
|
||||
cp = cp->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tp->viscol < tp->tcol->rmargin) {
|
||||
(*tp->advance)(tp, tp->tcol->rmargin
|
||||
@ -341,77 +464,83 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
|
||||
tp->viscol = tp->tcol->rmargin;
|
||||
}
|
||||
while (tp->viscol < tp->tcol->rmargin +
|
||||
tp->tbl.cols[ic].spacing / 2) {
|
||||
(*tp->letter)(tp, fc);
|
||||
tp->viscol++;
|
||||
}
|
||||
tp->tbl.cols[ic].spacing / 2)
|
||||
tbl_direct_border(tp,
|
||||
BHORIZ * lhori, 1);
|
||||
|
||||
if (tp->tcol + 1 == tp->tcols + tp->lasttcol)
|
||||
continue;
|
||||
|
||||
if (fc == ' ' && cp != NULL) {
|
||||
switch (cp->pos) {
|
||||
case TBL_CELL_HORIZ:
|
||||
fc = '-';
|
||||
break;
|
||||
case TBL_CELL_DHORIZ:
|
||||
fc = '=';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tp->tbl.cols[ic].spacing) {
|
||||
(*tp->letter)(tp, fc == ' ' ? '|' :
|
||||
vert ? '+' : fc);
|
||||
tp->viscol++;
|
||||
}
|
||||
if (cp != NULL)
|
||||
cp = cp->next;
|
||||
|
||||
rhori = (cp != NULL &&
|
||||
cp->pos == TBL_CELL_DHORIZ) ||
|
||||
(dp != NULL &&
|
||||
dp->pos == TBL_DATA_DHORIZ) ? 2 :
|
||||
(cp != NULL &&
|
||||
cp->pos == TBL_CELL_HORIZ) ||
|
||||
(dp != NULL &&
|
||||
dp->pos == TBL_DATA_HORIZ) ? 1 : 0;
|
||||
|
||||
if (tp->tbl.cols[ic].spacing)
|
||||
tbl_direct_border(tp,
|
||||
BLEFT * lhori + BRIGHT * rhori +
|
||||
BUP * uvert + BDOWN * dvert, 1);
|
||||
|
||||
if (tp->enc == TERMENC_UTF8)
|
||||
uvert = dvert = 0;
|
||||
|
||||
if (fc != ' ') {
|
||||
if (cp != NULL &&
|
||||
cp->pos == TBL_CELL_HORIZ)
|
||||
fc = '-';
|
||||
else if (cp != NULL &&
|
||||
cp->pos == TBL_CELL_DHORIZ)
|
||||
fc = '=';
|
||||
else
|
||||
fc = ' ';
|
||||
}
|
||||
if (tp->tbl.cols[ic].spacing > 2 &&
|
||||
(vert > 1 || fc != ' ')) {
|
||||
(*tp->letter)(tp, fc == ' ' ? '|' :
|
||||
vert > 1 ? '+' : fc);
|
||||
tp->viscol++;
|
||||
}
|
||||
(uvert > 1 || dvert > 1 || rhori))
|
||||
tbl_direct_border(tp,
|
||||
BHORIZ * rhori +
|
||||
BUP * (uvert > 1) +
|
||||
BDOWN * (dvert > 1), 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print the vertical frame at the end of each row. */
|
||||
|
||||
fc = '\0';
|
||||
if ((sp->layout->last->vert &&
|
||||
sp->layout->last->col + 1 == sp->opts->cols) ||
|
||||
(sp->next != NULL &&
|
||||
sp->next->layout->last->vert &&
|
||||
sp->next->layout->last->col + 1 == sp->opts->cols) ||
|
||||
(sp->prev != NULL &&
|
||||
sp->prev->layout->last->vert &&
|
||||
sp->prev->layout->last->col + 1 == sp->opts->cols &&
|
||||
(horiz || (IS_HORIZ(sp->layout->last) &&
|
||||
!IS_HORIZ(sp->prev->layout->last)))) ||
|
||||
(sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)))
|
||||
fc = horiz || IS_HORIZ(sp->layout->last) ? '+' : '|';
|
||||
else if (horiz && sp->opts->rvert)
|
||||
fc = '-';
|
||||
if (fc != '\0') {
|
||||
uvert = dvert = sp->opts->opts & TBL_OPT_DBOX ? 2 :
|
||||
sp->opts->opts & TBL_OPT_BOX ? 1 : 0;
|
||||
if (sp->pos == TBL_SPAN_DATA &&
|
||||
uvert < sp->layout->last->vert &&
|
||||
sp->layout->last->col + 1 == sp->opts->cols)
|
||||
uvert = dvert = sp->layout->last->vert;
|
||||
if (sp->next != NULL &&
|
||||
dvert < sp->next->layout->last->vert &&
|
||||
sp->next->layout->last->col + 1 == sp->opts->cols)
|
||||
dvert = sp->next->layout->last->vert;
|
||||
if (sp->prev != NULL &&
|
||||
uvert < sp->prev->layout->last->vert &&
|
||||
sp->prev->layout->last->col + 1 == sp->opts->cols &&
|
||||
(horiz || (IS_HORIZ(sp->layout->last) &&
|
||||
!IS_HORIZ(sp->prev->layout->last))))
|
||||
uvert = sp->prev->layout->last->vert;
|
||||
lhori = sp->pos == TBL_SPAN_DHORIZ ||
|
||||
(sp->last != NULL &&
|
||||
sp->last->pos == TBL_DATA_DHORIZ &&
|
||||
sp->last->layout->col + 1 == sp->opts->cols) ||
|
||||
(sp->layout->last->pos == TBL_CELL_DHORIZ &&
|
||||
sp->layout->last->col + 1 == sp->opts->cols) ? 2 :
|
||||
sp->pos == TBL_SPAN_HORIZ ||
|
||||
(sp->last != NULL &&
|
||||
sp->last->pos == TBL_DATA_HORIZ &&
|
||||
sp->last->layout->col + 1 == sp->opts->cols) ||
|
||||
(sp->layout->last->pos == TBL_CELL_HORIZ &&
|
||||
sp->layout->last->col + 1 == sp->opts->cols) ? 1 : 0;
|
||||
fc = BUP * uvert + BDOWN * dvert + BLEFT * lhori;
|
||||
if (uvert > 0 || dvert > 0 || (horiz && sp->opts->rvert)) {
|
||||
if (horiz == 0 && (IS_HORIZ(sp->layout->last) == 0 ||
|
||||
sp->layout->last->col + 1 < sp->opts->cols)) {
|
||||
tp->tcol++;
|
||||
(*tp->advance)(tp,
|
||||
tp->tcol->offset > tp->viscol ?
|
||||
tp->tcol->offset - tp->viscol : 1);
|
||||
do {
|
||||
tbl_direct_border(tp,
|
||||
BHORIZ * lhori, 1);
|
||||
} while (tp->viscol < tp->tcol->offset);
|
||||
}
|
||||
(*tp->letter)(tp, fc);
|
||||
tbl_direct_border(tp, fc, 1);
|
||||
}
|
||||
(*tp->endline)(tp);
|
||||
tp->viscol = 0;
|
||||
@ -428,80 +557,156 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
|
||||
tp->tcol->rmargin = tp->maxrmargin;
|
||||
if (sp->next == NULL) {
|
||||
if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) {
|
||||
tbl_hrule(tp, sp, 2);
|
||||
tbl_hrule(tp, sp, NULL, TBL_OPT_BOX);
|
||||
tp->skipvsp = 1;
|
||||
}
|
||||
if (sp->opts->opts & TBL_OPT_DBOX) {
|
||||
tbl_hrule(tp, sp, 3);
|
||||
if (tp->enc == TERMENC_ASCII &&
|
||||
sp->opts->opts & TBL_OPT_DBOX) {
|
||||
tbl_hrule(tp, sp, NULL, TBL_OPT_DBOX);
|
||||
tp->skipvsp = 2;
|
||||
}
|
||||
assert(tp->tbl.cols);
|
||||
free(tp->tbl.cols);
|
||||
tp->tbl.cols = NULL;
|
||||
tp->tcol->offset = offset;
|
||||
} else if (horiz == 0 && sp->opts->opts & TBL_OPT_ALLBOX &&
|
||||
(sp->next == NULL || sp->next->pos == TBL_SPAN_DATA ||
|
||||
sp->next->next != NULL))
|
||||
tbl_hrule(tp, sp, 1);
|
||||
tbl_hrule(tp, sp, sp->next, TBL_OPT_ALLBOX);
|
||||
|
||||
tp->tcol->offset = save_offset;
|
||||
tp->flags &= ~TERMP_NONOSPACE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Kinds of horizontal rulers:
|
||||
* 0: inside the table (single or double line with crossings)
|
||||
* 1: inside the table (single or double line with crossings and ends)
|
||||
* 2: inner frame (single line with crossings and ends)
|
||||
* 3: outer frame (single line without crossings with ends)
|
||||
*/
|
||||
static void
|
||||
tbl_hrule(struct termp *tp, const struct tbl_span *sp, int kind)
|
||||
tbl_hrule(struct termp *tp, const struct tbl_span *spp,
|
||||
const struct tbl_span *spn, int flags)
|
||||
{
|
||||
const struct tbl_cell *cp, *cpn, *cpp;
|
||||
const struct roffcol *col;
|
||||
int vert;
|
||||
char line, cross;
|
||||
const struct tbl_cell *cpp; /* Layout cell above this line. */
|
||||
const struct tbl_cell *cpn; /* Layout cell below this line. */
|
||||
const struct tbl_dat *dpn; /* Data cell below this line. */
|
||||
const struct roffcol *col; /* Contains width and spacing. */
|
||||
int opts; /* For the table as a whole. */
|
||||
int bw; /* Box line width. */
|
||||
int hw; /* Horizontal line width. */
|
||||
int lw, rw; /* Left and right line widths. */
|
||||
int uw, dw; /* Vertical line widths. */
|
||||
|
||||
line = (kind < 2 && TBL_SPAN_DHORIZ == sp->pos) ? '=' : '-';
|
||||
cross = (kind < 3) ? '+' : '-';
|
||||
cpp = spp == NULL ? NULL : spp->layout->first;
|
||||
cpn = spn == NULL ? NULL : spn->layout->first;
|
||||
dpn = NULL;
|
||||
if (spn != NULL) {
|
||||
if (spn->pos == TBL_SPAN_DATA)
|
||||
dpn = spn->first;
|
||||
else if (spn->next != NULL)
|
||||
dpn = spn->next->first;
|
||||
}
|
||||
opts = spn == NULL ? spp->opts->opts : spn->opts->opts;
|
||||
bw = opts & TBL_OPT_DBOX ? (tp->enc == TERMENC_UTF8 ? 2 : 1) :
|
||||
opts & (TBL_OPT_BOX | TBL_OPT_ALLBOX) ? 1 : 0;
|
||||
hw = flags == TBL_OPT_DBOX || flags == TBL_OPT_BOX ? bw :
|
||||
spn->pos == TBL_SPAN_DHORIZ ? 2 : 1;
|
||||
|
||||
/* Print the left end of the line. */
|
||||
|
||||
if (tp->viscol == 0) {
|
||||
(*tp->advance)(tp, tp->tcols->offset);
|
||||
tp->viscol = tp->tcols->offset;
|
||||
}
|
||||
if (flags != 0)
|
||||
tbl_direct_border(tp,
|
||||
(spp == NULL ? 0 : BUP * bw) +
|
||||
(spn == NULL ? 0 : BDOWN * bw) +
|
||||
(spp == NULL || cpn == NULL ||
|
||||
cpn->pos != TBL_CELL_DOWN ? BRIGHT * hw : 0), 1);
|
||||
|
||||
if (kind)
|
||||
term_word(tp, "+");
|
||||
cp = sp->layout->first;
|
||||
cpp = kind || sp->prev == NULL ? NULL : sp->prev->layout->first;
|
||||
if (cpp == cp)
|
||||
cpp = NULL;
|
||||
cpn = kind > 1 || sp->next == NULL ? NULL : sp->next->layout->first;
|
||||
if (cpn == cp)
|
||||
cpn = NULL;
|
||||
for (;;) {
|
||||
col = tp->tbl.cols + cp->col;
|
||||
tbl_char(tp, line, col->width + col->spacing / 2);
|
||||
vert = cp->vert;
|
||||
if ((cp = cp->next) == NULL)
|
||||
break;
|
||||
col = tp->tbl.cols + (cpn == NULL ? cpp->col : cpn->col);
|
||||
|
||||
/* Print the horizontal line inside this column. */
|
||||
|
||||
lw = cpp == NULL || cpn == NULL ||
|
||||
(cpn->pos != TBL_CELL_DOWN &&
|
||||
(dpn == NULL || strcmp(dpn->string, "\\^") != 0))
|
||||
? hw : 0;
|
||||
tbl_direct_border(tp, BHORIZ * lw,
|
||||
col->width + col->spacing / 2);
|
||||
|
||||
/*
|
||||
* Figure out whether a vertical line is crossing
|
||||
* at the end of this column,
|
||||
* and advance to the next column.
|
||||
*/
|
||||
|
||||
uw = dw = 0;
|
||||
if (cpp != NULL) {
|
||||
if (vert < cpp->vert)
|
||||
vert = cpp->vert;
|
||||
if (flags != TBL_OPT_DBOX) {
|
||||
uw = cpp->vert;
|
||||
if (uw == 0 && opts & TBL_OPT_ALLBOX)
|
||||
uw = 1;
|
||||
}
|
||||
cpp = cpp->next;
|
||||
}
|
||||
if (cpn != NULL) {
|
||||
if (vert < cpn->vert)
|
||||
vert = cpn->vert;
|
||||
if (flags != TBL_OPT_DBOX) {
|
||||
dw = cpn->vert;
|
||||
if (dw == 0 && opts & TBL_OPT_ALLBOX)
|
||||
dw = 1;
|
||||
}
|
||||
cpn = cpn->next;
|
||||
while (dpn != NULL && dpn->layout != cpn)
|
||||
dpn = dpn->next;
|
||||
}
|
||||
if (sp->opts->opts & TBL_OPT_ALLBOX && !vert)
|
||||
vert = 1;
|
||||
if (cpp == NULL && cpn == NULL)
|
||||
break;
|
||||
|
||||
/* Vertical lines do not cross spanned cells. */
|
||||
|
||||
if (cpp != NULL && cpp->pos == TBL_CELL_SPAN)
|
||||
uw = 0;
|
||||
if (cpn != NULL && cpn->pos == TBL_CELL_SPAN)
|
||||
dw = 0;
|
||||
|
||||
/* The horizontal line inside the next column. */
|
||||
|
||||
rw = cpp == NULL || cpn == NULL ||
|
||||
(cpn->pos != TBL_CELL_DOWN &&
|
||||
(dpn == NULL || strcmp(dpn->string, "\\^") != 0))
|
||||
? hw : 0;
|
||||
|
||||
/* The line crossing at the end of this column. */
|
||||
|
||||
if (col->spacing)
|
||||
tbl_char(tp, vert ? cross : line, 1);
|
||||
tbl_direct_border(tp, BLEFT * lw +
|
||||
BRIGHT * rw + BUP * uw + BDOWN * dw, 1);
|
||||
|
||||
/*
|
||||
* In ASCII output, a crossing may print two characters.
|
||||
*/
|
||||
|
||||
if (tp->enc != TERMENC_ASCII || (uw < 2 && dw < 2))
|
||||
uw = dw = 0;
|
||||
if (col->spacing > 2)
|
||||
tbl_char(tp, vert > 1 ? cross : line, 1);
|
||||
tbl_direct_border(tp,
|
||||
BHORIZ * rw + BUP * uw + BDOWN * dw, 1);
|
||||
|
||||
/* Padding before the start of the next column. */
|
||||
|
||||
if (col->spacing > 4)
|
||||
tbl_char(tp, line, (col->spacing - 3) / 2);
|
||||
tbl_direct_border(tp,
|
||||
BHORIZ * rw, (col->spacing - 3) / 2);
|
||||
}
|
||||
if (kind) {
|
||||
term_word(tp, "+");
|
||||
term_flushln(tp);
|
||||
|
||||
/* Print the right end of the line. */
|
||||
|
||||
if (flags != 0) {
|
||||
tbl_direct_border(tp,
|
||||
(spp == NULL ? 0 : BUP * bw) +
|
||||
(spn == NULL ? 0 : BDOWN * bw) +
|
||||
(spp == NULL || spn == NULL ||
|
||||
spn->layout->last->pos != TBL_CELL_DOWN ?
|
||||
BLEFT * hw : 0), 1);
|
||||
(*tp->endline)(tp);
|
||||
tp->viscol = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -512,10 +717,10 @@ tbl_data(struct termp *tp, const struct tbl_opts *opts,
|
||||
{
|
||||
switch (cp->pos) {
|
||||
case TBL_CELL_HORIZ:
|
||||
tbl_char(tp, '-', col->width);
|
||||
tbl_fill_border(tp, BHORIZ, col->width);
|
||||
return;
|
||||
case TBL_CELL_DHORIZ:
|
||||
tbl_char(tp, '=', col->width);
|
||||
tbl_fill_border(tp, BHORIZ * 2, col->width);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
@ -529,11 +734,11 @@ tbl_data(struct termp *tp, const struct tbl_opts *opts,
|
||||
return;
|
||||
case TBL_DATA_HORIZ:
|
||||
case TBL_DATA_NHORIZ:
|
||||
tbl_char(tp, '-', col->width);
|
||||
tbl_fill_border(tp, BHORIZ, col->width);
|
||||
return;
|
||||
case TBL_DATA_NDHORIZ:
|
||||
case TBL_DATA_DHORIZ:
|
||||
tbl_char(tp, '=', col->width);
|
||||
tbl_fill_border(tp, BHORIZ * 2, col->width);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
@ -558,18 +763,48 @@ tbl_data(struct termp *tp, const struct tbl_opts *opts,
|
||||
}
|
||||
|
||||
static void
|
||||
tbl_char(struct termp *tp, char c, size_t len)
|
||||
tbl_fill_string(struct termp *tp, const char *cp, size_t len)
|
||||
{
|
||||
size_t i, sz;
|
||||
char cp[2];
|
||||
size_t i, sz;
|
||||
|
||||
sz = term_strlen(tp, cp);
|
||||
for (i = 0; i < len; i += sz)
|
||||
term_word(tp, cp);
|
||||
}
|
||||
|
||||
static void
|
||||
tbl_fill_char(struct termp *tp, char c, size_t len)
|
||||
{
|
||||
char cp[2];
|
||||
|
||||
cp[0] = c;
|
||||
cp[1] = '\0';
|
||||
tbl_fill_string(tp, cp, len);
|
||||
}
|
||||
|
||||
sz = term_strlen(tp, cp);
|
||||
static void
|
||||
tbl_fill_border(struct termp *tp, int c, size_t len)
|
||||
{
|
||||
char buf[12];
|
||||
|
||||
for (i = 0; i < len; i += sz)
|
||||
term_word(tp, cp);
|
||||
if ((c = borders_locale[c]) > 127) {
|
||||
(void)snprintf(buf, sizeof(buf), "\\[u%04x]", c);
|
||||
tbl_fill_string(tp, buf, len);
|
||||
} else
|
||||
tbl_fill_char(tp, c, len);
|
||||
}
|
||||
|
||||
static void
|
||||
tbl_direct_border(struct termp *tp, int c, size_t len)
|
||||
{
|
||||
size_t i, sz;
|
||||
|
||||
c = borders_locale[c];
|
||||
sz = (*tp->width)(tp, c);
|
||||
for (i = 0; i < len; i += sz) {
|
||||
(*tp->letter)(tp, c);
|
||||
tp->viscol += sz;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -577,14 +812,14 @@ tbl_literal(struct termp *tp, const struct tbl_dat *dp,
|
||||
const struct roffcol *col)
|
||||
{
|
||||
size_t len, padl, padr, width;
|
||||
int ic, spans;
|
||||
int ic, hspans;
|
||||
|
||||
assert(dp->string);
|
||||
len = term_strlen(tp, dp->string);
|
||||
width = col->width;
|
||||
ic = dp->layout->col;
|
||||
spans = dp->spans;
|
||||
while (spans--)
|
||||
hspans = dp->hspans;
|
||||
while (hspans--)
|
||||
width += tp->tbl.cols[++ic].width + 3;
|
||||
|
||||
padr = width > len ? width - len : 0;
|
||||
@ -609,9 +844,9 @@ tbl_literal(struct termp *tp, const struct tbl_dat *dp,
|
||||
break;
|
||||
}
|
||||
|
||||
tbl_char(tp, ASCII_NBRSP, padl);
|
||||
tbl_fill_char(tp, ASCII_NBRSP, padl);
|
||||
tbl_word(tp, dp);
|
||||
tbl_char(tp, ASCII_NBRSP, padr);
|
||||
tbl_fill_char(tp, ASCII_NBRSP, padr);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -619,44 +854,66 @@ tbl_number(struct termp *tp, const struct tbl_opts *opts,
|
||||
const struct tbl_dat *dp,
|
||||
const struct roffcol *col)
|
||||
{
|
||||
char *cp;
|
||||
const char *cp, *lastdigit, *lastpoint;
|
||||
size_t intsz, padl, totsz;
|
||||
char buf[2];
|
||||
size_t sz, psz, ssz, d, padl;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* See calc_data_number(). Left-pad by taking the offset of our
|
||||
* and the maximum decimal; right-pad by the remaining amount.
|
||||
* Almost the same code as in tblcalc_number():
|
||||
* First find the position of the decimal point.
|
||||
*/
|
||||
|
||||
assert(dp->string);
|
||||
lastdigit = lastpoint = NULL;
|
||||
for (cp = dp->string; cp[0] != '\0'; cp++) {
|
||||
if (cp[0] == '\\' && cp[1] == '&') {
|
||||
lastdigit = lastpoint = cp;
|
||||
break;
|
||||
} else if (cp[0] == opts->decimal &&
|
||||
(isdigit((unsigned char)cp[1]) ||
|
||||
(cp > dp->string && isdigit((unsigned char)cp[-1]))))
|
||||
lastpoint = cp;
|
||||
else if (isdigit((unsigned char)cp[0]))
|
||||
lastdigit = cp;
|
||||
}
|
||||
|
||||
sz = term_strlen(tp, dp->string);
|
||||
/* Then measure both widths. */
|
||||
|
||||
buf[0] = opts->decimal;
|
||||
buf[1] = '\0';
|
||||
|
||||
psz = term_strlen(tp, buf);
|
||||
|
||||
if ((cp = strrchr(dp->string, opts->decimal)) != NULL) {
|
||||
for (ssz = 0, i = 0; cp != &dp->string[i]; i++) {
|
||||
buf[0] = dp->string[i];
|
||||
ssz += term_strlen(tp, buf);
|
||||
padl = 0;
|
||||
totsz = term_strlen(tp, dp->string);
|
||||
if (lastdigit != NULL) {
|
||||
if (lastpoint == NULL)
|
||||
lastpoint = lastdigit + 1;
|
||||
intsz = 0;
|
||||
buf[1] = '\0';
|
||||
for (cp = dp->string; cp < lastpoint; cp++) {
|
||||
buf[0] = cp[0];
|
||||
intsz += term_strlen(tp, buf);
|
||||
}
|
||||
d = ssz + psz;
|
||||
} else
|
||||
d = sz + psz;
|
||||
|
||||
if (col->decimal > d && col->width > sz) {
|
||||
padl = col->decimal - d;
|
||||
if (padl + sz > col->width)
|
||||
padl = col->width - sz;
|
||||
tbl_char(tp, ASCII_NBRSP, padl);
|
||||
} else
|
||||
padl = 0;
|
||||
/*
|
||||
* Pad left to match the decimal position,
|
||||
* but avoid exceeding the total column width.
|
||||
*/
|
||||
|
||||
if (col->decimal > intsz && col->width > totsz) {
|
||||
padl = col->decimal - intsz;
|
||||
if (padl + totsz > col->width)
|
||||
padl = col->width - totsz;
|
||||
}
|
||||
|
||||
/* If it is not a number, simply center the string. */
|
||||
|
||||
} else if (col->width > totsz)
|
||||
padl = (col->width - totsz) / 2;
|
||||
|
||||
tbl_fill_char(tp, ASCII_NBRSP, padl);
|
||||
tbl_word(tp, dp);
|
||||
if (col->width > sz + padl)
|
||||
tbl_char(tp, ASCII_NBRSP, col->width - sz - padl);
|
||||
|
||||
/* Pad right to fill the column. */
|
||||
|
||||
if (col->width > padl + totsz)
|
||||
tbl_fill_char(tp, ASCII_NBRSP, col->width - padl - totsz);
|
||||
}
|
||||
|
||||
static void
|
||||
|
527
term.c
527
term.c
@ -1,7 +1,7 @@
|
||||
/* $Id: term.c,v 1.274 2017/07/28 14:25:48 schwarze Exp $ */
|
||||
/* $Id: term.c,v 1.280 2019/01/15 12:16:18 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2010-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
|
||||
@ -21,6 +21,7 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -37,6 +38,10 @@ 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_fill(struct termp *, size_t *, size_t *,
|
||||
size_t);
|
||||
|
||||
|
||||
void
|
||||
@ -83,223 +88,139 @@ term_end(struct termp *p)
|
||||
* Flush a chunk of text. By default, break the output line each time
|
||||
* the right margin is reached, and continue output on the next line
|
||||
* at the same offset as the chunk itself. By default, also break the
|
||||
* output line at the end of the chunk.
|
||||
* The following flags may be specified:
|
||||
*
|
||||
* - TERMP_NOBREAK: Do not break the output line at the right margin,
|
||||
* but only at the max right margin. Also, do not break the output
|
||||
* line at the end of the chunk, such that the next call can pad to
|
||||
* the next column. However, if less than p->trailspace blanks,
|
||||
* which can be 0, 1, or 2, remain to the right margin, the line
|
||||
* will be broken.
|
||||
* - TERMP_BRTRSP: Consider trailing whitespace significant
|
||||
* when deciding whether the chunk fits or not.
|
||||
* - TERMP_BRIND: If the chunk does not fit and the output line has
|
||||
* to be broken, start the next line at the right margin instead
|
||||
* of at the offset. Used together with TERMP_NOBREAK for the tags
|
||||
* in various kinds of tagged lists.
|
||||
* - TERMP_HANG: Do not break the output line at the right margin,
|
||||
* append the next chunk after it even if this one is too long.
|
||||
* To be used together with TERMP_NOBREAK.
|
||||
* - TERMP_NOPAD: Start writing at the current position,
|
||||
* do not pad with blank characters up to the offset.
|
||||
* output line at the end of the chunk. There are many flags modifying
|
||||
* this behaviour, see the comments in the body of the function.
|
||||
*/
|
||||
void
|
||||
term_flushln(struct termp *p)
|
||||
{
|
||||
size_t vis; /* current visual position on output */
|
||||
size_t vbl; /* number of blanks to prepend to output */
|
||||
size_t vend; /* end of word visual position on output */
|
||||
size_t bp; /* visual right border position */
|
||||
size_t dv; /* temporary for visual pos calculations */
|
||||
size_t j; /* temporary loop index for p->tcol->buf */
|
||||
size_t jhy; /* last hyph before overflow w/r/t j */
|
||||
size_t maxvis; /* output position of visible boundary */
|
||||
int ntab; /* number of tabs to prepend */
|
||||
int breakline; /* after this word */
|
||||
size_t vbl; /* Number of blanks to prepend to the output. */
|
||||
size_t vbr; /* Actual visual position of the end of field. */
|
||||
size_t vfield; /* Desired visual field width. */
|
||||
size_t vtarget; /* Desired visual position of the right margin. */
|
||||
size_t ic; /* Character position in the input buffer. */
|
||||
size_t nbr; /* Number of characters to print in this field. */
|
||||
|
||||
/*
|
||||
* Normally, start writing at the left margin, but with the
|
||||
* NOPAD flag, start writing at the current position instead.
|
||||
*/
|
||||
|
||||
vbl = (p->flags & TERMP_NOPAD) || p->tcol->offset < p->viscol ?
|
||||
0 : p->tcol->offset - p->viscol;
|
||||
if (p->minbl && vbl < p->minbl)
|
||||
vbl = p->minbl;
|
||||
maxvis = p->tcol->rmargin > p->viscol + vbl ?
|
||||
p->tcol->rmargin - p->viscol - vbl : 0;
|
||||
bp = !(p->flags & TERMP_NOBREAK) ? maxvis :
|
||||
p->maxrmargin > p->viscol + vbl ?
|
||||
p->maxrmargin - p->viscol - vbl : 0;
|
||||
vis = vend = 0;
|
||||
|
||||
if ((p->flags & TERMP_MULTICOL) == 0)
|
||||
p->tcol->col = 0;
|
||||
while (p->tcol->col < p->tcol->lastcol) {
|
||||
|
||||
/* Loop over output lines. */
|
||||
|
||||
for (;;) {
|
||||
vfield = p->tcol->rmargin > p->viscol + vbl ?
|
||||
p->tcol->rmargin - p->viscol - vbl : 0;
|
||||
|
||||
/*
|
||||
* Handle literal tab characters: collapse all
|
||||
* subsequent tabs into a single huge set of spaces.
|
||||
* Normally, break the line at the the right margin
|
||||
* of the field, but with the NOBREAK flag, only
|
||||
* break it at the max right margin of the screen,
|
||||
* and with the BRNEVER flag, never break it at all.
|
||||
*/
|
||||
|
||||
vtarget = p->flags & TERMP_BRNEVER ? SIZE_MAX :
|
||||
(p->flags & TERMP_NOBREAK) == 0 ? vfield :
|
||||
p->maxrmargin > p->viscol + vbl ?
|
||||
p->maxrmargin - p->viscol - vbl : 0;
|
||||
|
||||
/*
|
||||
* Figure out how much text will fit in the field.
|
||||
* If there is whitespace only, print nothing.
|
||||
*/
|
||||
|
||||
term_fill(p, &nbr, &vbr, vtarget);
|
||||
if (nbr == 0)
|
||||
break;
|
||||
|
||||
/*
|
||||
* With the CENTER or RIGHT flag, increase the indentation
|
||||
* to center the text between the left and right margins
|
||||
* or to adjust it to the right margin, respectively.
|
||||
*/
|
||||
|
||||
if (vbr < vtarget) {
|
||||
if (p->flags & TERMP_CENTER)
|
||||
vbl += (vtarget - vbr) / 2;
|
||||
else if (p->flags & TERMP_RIGHT)
|
||||
vbl += vtarget - vbr;
|
||||
}
|
||||
|
||||
/* Finally, print the field content. */
|
||||
|
||||
term_field(p, vbl, nbr, vbr, vtarget);
|
||||
|
||||
/*
|
||||
* If there is no text left in the field, exit the loop.
|
||||
* If the BRTRSP flag is set, consider trailing
|
||||
* whitespace significant when deciding whether
|
||||
* the field fits or not.
|
||||
*/
|
||||
|
||||
for (ic = p->tcol->col; ic < p->tcol->lastcol; ic++) {
|
||||
switch (p->tcol->buf[ic]) {
|
||||
case '\t':
|
||||
if (p->flags & TERMP_BRTRSP)
|
||||
vbr = term_tab_next(vbr);
|
||||
continue;
|
||||
case ' ':
|
||||
if (p->flags & TERMP_BRTRSP)
|
||||
vbr += (*p->width)(p, ' ');
|
||||
continue;
|
||||
case '\n':
|
||||
case ASCII_BREAK:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ic == p->tcol->lastcol)
|
||||
break;
|
||||
|
||||
/*
|
||||
* At the location of an automtic line break, input
|
||||
* space characters are consumed by the line break.
|
||||
*/
|
||||
|
||||
ntab = 0;
|
||||
while (p->tcol->col < p->tcol->lastcol &&
|
||||
p->tcol->buf[p->tcol->col] == '\t') {
|
||||
vend = term_tab_next(vis);
|
||||
vbl += vend - vis;
|
||||
vis = vend;
|
||||
ntab++;
|
||||
p->tcol->buf[p->tcol->col] == ' ')
|
||||
p->tcol->col++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Count up visible word characters. Control sequences
|
||||
* (starting with the CSI) aren't counted. A space
|
||||
* generates a non-printing word, which is valid (the
|
||||
* space is printed according to regular spacing rules).
|
||||
* In multi-column mode, leave the rest of the text
|
||||
* in the buffer to be handled by a subsequent
|
||||
* invocation, such that the other columns of the
|
||||
* table can be handled first.
|
||||
* In single-column mode, simply break the line.
|
||||
*/
|
||||
|
||||
jhy = 0;
|
||||
breakline = 0;
|
||||
for (j = p->tcol->col; j < p->tcol->lastcol; j++) {
|
||||
if (p->tcol->buf[j] == '\n') {
|
||||
if ((p->flags & TERMP_BRIND) == 0)
|
||||
breakline = 1;
|
||||
continue;
|
||||
}
|
||||
if (p->tcol->buf[j] == ' ' || p->tcol->buf[j] == '\t')
|
||||
break;
|
||||
|
||||
/* Back over the last printed character. */
|
||||
if (p->tcol->buf[j] == '\b') {
|
||||
assert(j);
|
||||
vend -= (*p->width)(p, p->tcol->buf[j - 1]);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Regular word. */
|
||||
/* Break at the hyphen point if we overrun. */
|
||||
if (vend > vis && vend < bp &&
|
||||
(p->tcol->buf[j] == ASCII_HYPH||
|
||||
p->tcol->buf[j] == ASCII_BREAK))
|
||||
jhy = j;
|
||||
|
||||
/*
|
||||
* Hyphenation now decided, put back a real
|
||||
* hyphen such that we get the correct width.
|
||||
*/
|
||||
if (p->tcol->buf[j] == ASCII_HYPH)
|
||||
p->tcol->buf[j] = '-';
|
||||
|
||||
vend += (*p->width)(p, p->tcol->buf[j]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find out whether we would exceed the right margin.
|
||||
* If so, break to the next line.
|
||||
*/
|
||||
|
||||
if (vend > bp && jhy == 0 && vis > 0 &&
|
||||
(p->flags & TERMP_BRNEVER) == 0) {
|
||||
if (p->flags & TERMP_MULTICOL)
|
||||
return;
|
||||
|
||||
endline(p);
|
||||
vend -= vis;
|
||||
|
||||
/* Use pending tabs on the new line. */
|
||||
|
||||
vbl = 0;
|
||||
while (ntab--)
|
||||
vbl = term_tab_next(vbl);
|
||||
|
||||
/* Re-establish indentation. */
|
||||
|
||||
if (p->flags & TERMP_BRIND)
|
||||
vbl += p->tcol->rmargin;
|
||||
else
|
||||
vbl += p->tcol->offset;
|
||||
maxvis = p->tcol->rmargin > vbl ?
|
||||
p->tcol->rmargin - vbl : 0;
|
||||
bp = !(p->flags & TERMP_NOBREAK) ? maxvis :
|
||||
p->maxrmargin > vbl ? p->maxrmargin - vbl : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out the rest of the word.
|
||||
*/
|
||||
|
||||
for ( ; p->tcol->col < p->tcol->lastcol; p->tcol->col++) {
|
||||
if (vend > bp && jhy > 0 && p->tcol->col > jhy)
|
||||
break;
|
||||
if (p->tcol->buf[p->tcol->col] == '\n')
|
||||
continue;
|
||||
if (p->tcol->buf[p->tcol->col] == '\t')
|
||||
break;
|
||||
if (p->tcol->buf[p->tcol->col] == ' ') {
|
||||
j = p->tcol->col;
|
||||
while (p->tcol->col < p->tcol->lastcol &&
|
||||
p->tcol->buf[p->tcol->col] == ' ')
|
||||
p->tcol->col++;
|
||||
dv = (p->tcol->col - j) * (*p->width)(p, ' ');
|
||||
vbl += dv;
|
||||
vend += dv;
|
||||
break;
|
||||
}
|
||||
if (p->tcol->buf[p->tcol->col] == ASCII_NBRSP) {
|
||||
vbl += (*p->width)(p, ' ');
|
||||
continue;
|
||||
}
|
||||
if (p->tcol->buf[p->tcol->col] == ASCII_BREAK)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Now we definitely know there will be
|
||||
* printable characters to output,
|
||||
* so write preceding white space now.
|
||||
*/
|
||||
if (vbl) {
|
||||
(*p->advance)(p, vbl);
|
||||
p->viscol += vbl;
|
||||
vbl = 0;
|
||||
}
|
||||
|
||||
(*p->letter)(p, p->tcol->buf[p->tcol->col]);
|
||||
if (p->tcol->buf[p->tcol->col] == '\b')
|
||||
p->viscol -= (*p->width)(p,
|
||||
p->tcol->buf[p->tcol->col - 1]);
|
||||
else
|
||||
p->viscol += (*p->width)(p,
|
||||
p->tcol->buf[p->tcol->col]);
|
||||
}
|
||||
vis = vend;
|
||||
|
||||
if (breakline == 0)
|
||||
continue;
|
||||
|
||||
/* Explicitly requested output line break. */
|
||||
|
||||
if (p->flags & TERMP_MULTICOL)
|
||||
return;
|
||||
|
||||
endline(p);
|
||||
breakline = 0;
|
||||
vis = vend = 0;
|
||||
p->viscol = 0;
|
||||
|
||||
/* Re-establish indentation. */
|
||||
/*
|
||||
* Normally, start the next line at the same indentation
|
||||
* as this one, but with the BRIND flag, start it at the
|
||||
* right margin instead. This is used together with
|
||||
* NOBREAK for the tags in various kinds of tagged lists.
|
||||
*/
|
||||
|
||||
vbl = p->tcol->offset;
|
||||
maxvis = p->tcol->rmargin > vbl ?
|
||||
p->tcol->rmargin - vbl : 0;
|
||||
bp = !(p->flags & TERMP_NOBREAK) ? maxvis :
|
||||
p->maxrmargin > vbl ? p->maxrmargin - vbl : 0;
|
||||
vbl = p->flags & TERMP_BRIND ?
|
||||
p->tcol->rmargin : p->tcol->offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there was trailing white space, it was not printed;
|
||||
* so reset the cursor position accordingly.
|
||||
*/
|
||||
|
||||
if (vis > vbl)
|
||||
vis -= vbl;
|
||||
else
|
||||
vis = 0;
|
||||
/* Reset output state in preparation for the next field. */
|
||||
|
||||
p->col = p->tcol->col = p->tcol->lastcol = 0;
|
||||
p->minbl = p->trailspace;
|
||||
@ -308,18 +229,186 @@ term_flushln(struct termp *p)
|
||||
if (p->flags & TERMP_MULTICOL)
|
||||
return;
|
||||
|
||||
/* Trailing whitespace is significant in some columns. */
|
||||
/*
|
||||
* The HANG flag means that the next field
|
||||
* always follows on the same line.
|
||||
* The NOBREAK flag means that the next field
|
||||
* follows on the same line unless the field was overrun.
|
||||
* Normally, break the line at the end of each field.
|
||||
*/
|
||||
|
||||
if (vis && vbl && (TERMP_BRTRSP & p->flags))
|
||||
vis += vbl;
|
||||
|
||||
/* If the column was overrun, break the line. */
|
||||
if ((p->flags & TERMP_NOBREAK) == 0 ||
|
||||
((p->flags & TERMP_HANG) == 0 &&
|
||||
vis + p->trailspace * (*p->width)(p, ' ') > maxvis))
|
||||
if ((p->flags & TERMP_HANG) == 0 &&
|
||||
((p->flags & TERMP_NOBREAK) == 0 ||
|
||||
vbr + term_len(p, p->trailspace) > vfield))
|
||||
endline(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Store the number of input characters to print in this field in *nbr
|
||||
* and their total visual width to print in *vbr.
|
||||
* If there is only whitespace in the field, both remain zero.
|
||||
* The desired visual width of the field is provided by vtarget.
|
||||
* If the first word is longer, the field will be overrun.
|
||||
*/
|
||||
static void
|
||||
term_fill(struct termp *p, size_t *nbr, size_t *vbr, size_t vtarget)
|
||||
{
|
||||
size_t ic; /* Character position in the input buffer. */
|
||||
size_t vis; /* Visual position of the current character. */
|
||||
size_t vn; /* Visual position of the next character. */
|
||||
int breakline; /* Break at the end of this word. */
|
||||
int graph; /* Last character was non-blank. */
|
||||
|
||||
*nbr = *vbr = vis = 0;
|
||||
breakline = graph = 0;
|
||||
for (ic = p->tcol->col; ic < p->tcol->lastcol; ic++) {
|
||||
switch (p->tcol->buf[ic]) {
|
||||
case '\b': /* Escape \o (overstrike) or backspace markup. */
|
||||
assert(ic > 0);
|
||||
vis -= (*p->width)(p, p->tcol->buf[ic - 1]);
|
||||
continue;
|
||||
|
||||
case '\t': /* Normal ASCII whitespace. */
|
||||
case ' ':
|
||||
case ASCII_BREAK: /* Escape \: (breakpoint). */
|
||||
switch (p->tcol->buf[ic]) {
|
||||
case '\t':
|
||||
vn = term_tab_next(vis);
|
||||
break;
|
||||
case ' ':
|
||||
vn = vis + (*p->width)(p, ' ');
|
||||
break;
|
||||
case ASCII_BREAK:
|
||||
vn = vis;
|
||||
break;
|
||||
}
|
||||
/* Can break at the end of a word. */
|
||||
if (breakline || vn > vtarget)
|
||||
break;
|
||||
if (graph) {
|
||||
*nbr = ic;
|
||||
*vbr = vis;
|
||||
graph = 0;
|
||||
}
|
||||
vis = vn;
|
||||
continue;
|
||||
|
||||
case '\n': /* Escape \p (break at the end of the word). */
|
||||
breakline = 1;
|
||||
continue;
|
||||
|
||||
case ASCII_HYPH: /* Breakable hyphen. */
|
||||
graph = 1;
|
||||
/*
|
||||
* We are about to decide whether to break the
|
||||
* line or not, so we no longer need this hyphen
|
||||
* to be marked as breakable. Put back a real
|
||||
* hyphen such that we get the correct width.
|
||||
*/
|
||||
p->tcol->buf[ic] = '-';
|
||||
vis += (*p->width)(p, '-');
|
||||
if (vis > vtarget) {
|
||||
ic++;
|
||||
break;
|
||||
}
|
||||
*nbr = ic + 1;
|
||||
*vbr = vis;
|
||||
continue;
|
||||
|
||||
case ASCII_NBRSP: /* Non-breakable space. */
|
||||
p->tcol->buf[ic] = ' ';
|
||||
/* FALLTHROUGH */
|
||||
default: /* Printable character. */
|
||||
graph = 1;
|
||||
vis += (*p->width)(p, p->tcol->buf[ic]);
|
||||
if (vis > vtarget && *nbr > 0)
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the last word extends to the end of the field without any
|
||||
* trailing whitespace, the loop could not check yet whether it
|
||||
* can remain on this line. So do the check now.
|
||||
*/
|
||||
|
||||
if (graph && (vis <= vtarget || *nbr == 0)) {
|
||||
*nbr = ic;
|
||||
*vbr = vis;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
static void
|
||||
term_field(struct termp *p, size_t vbl, size_t nbr, size_t vbr, size_t vtarget)
|
||||
{
|
||||
size_t ic; /* Character position in the input buffer. */
|
||||
size_t vis; /* Visual position of the current character. */
|
||||
size_t dv; /* Visual width of the current character. */
|
||||
size_t vn; /* Visual position of the next character. */
|
||||
|
||||
vis = 0;
|
||||
for (ic = p->tcol->col; ic < nbr; ic++) {
|
||||
|
||||
/*
|
||||
* To avoid the printing of trailing whitespace,
|
||||
* do not print whitespace right away, only count it.
|
||||
*/
|
||||
|
||||
switch (p->tcol->buf[ic]) {
|
||||
case '\n':
|
||||
case ASCII_BREAK:
|
||||
continue;
|
||||
case '\t':
|
||||
vn = term_tab_next(vis);
|
||||
vbl += vn - vis;
|
||||
vis = vn;
|
||||
continue;
|
||||
case ' ':
|
||||
case ASCII_NBRSP:
|
||||
dv = (*p->width)(p, ' ');
|
||||
vbl += dv;
|
||||
vis += dv;
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* We found a non-blank character to print,
|
||||
* so write preceding white space now.
|
||||
*/
|
||||
|
||||
if (vbl > 0) {
|
||||
(*p->advance)(p, vbl);
|
||||
p->viscol += vbl;
|
||||
vbl = 0;
|
||||
}
|
||||
|
||||
/* Print the character and adjust the visual position. */
|
||||
|
||||
(*p->letter)(p, p->tcol->buf[ic]);
|
||||
if (p->tcol->buf[ic] == '\b') {
|
||||
dv = (*p->width)(p, p->tcol->buf[ic - 1]);
|
||||
p->viscol -= dv;
|
||||
vis -= dv;
|
||||
} else {
|
||||
dv = (*p->width)(p, p->tcol->buf[ic]);
|
||||
p->viscol += dv;
|
||||
vis += dv;
|
||||
}
|
||||
}
|
||||
p->tcol->col = nbr;
|
||||
}
|
||||
|
||||
static void
|
||||
endline(struct termp *p)
|
||||
{
|
||||
@ -477,9 +566,6 @@ term_word(struct termp *p, const char *word)
|
||||
|
||||
word++;
|
||||
esc = mandoc_escape(&word, &seq, &sz);
|
||||
if (ESCAPE_ERROR == esc)
|
||||
continue;
|
||||
|
||||
switch (esc) {
|
||||
case ESCAPE_UNICODE:
|
||||
uc = mchars_num2uc(seq + 1, sz - 1);
|
||||
@ -500,6 +586,9 @@ term_word(struct termp *p, const char *word)
|
||||
encode1(p, uc);
|
||||
}
|
||||
continue;
|
||||
case ESCAPE_UNDEF:
|
||||
uc = *seq;
|
||||
break;
|
||||
case ESCAPE_FONTBOLD:
|
||||
term_fontrepl(p, TERMFONT_BOLD);
|
||||
continue;
|
||||
@ -510,6 +599,7 @@ term_word(struct termp *p, const char *word)
|
||||
term_fontrepl(p, TERMFONT_BI);
|
||||
continue;
|
||||
case ESCAPE_FONT:
|
||||
case ESCAPE_FONTCW:
|
||||
case ESCAPE_FONTROMAN:
|
||||
term_fontrepl(p, TERMFONT_NONE);
|
||||
continue;
|
||||
@ -525,6 +615,16 @@ term_word(struct termp *p, const char *word)
|
||||
else if (*word == '\0')
|
||||
p->flags |= (TERMP_NOSPACE | TERMP_NONEWLINE);
|
||||
continue;
|
||||
case ESCAPE_DEVICE:
|
||||
if (p->type == TERMTYPE_PDF)
|
||||
encode(p, "pdf", 3);
|
||||
else if (p->type == TERMTYPE_PS)
|
||||
encode(p, "ps", 2);
|
||||
else if (p->enc == TERMENC_ASCII)
|
||||
encode(p, "ascii", 5);
|
||||
else
|
||||
encode(p, "utf8", 4);
|
||||
continue;
|
||||
case ESCAPE_HORIZ:
|
||||
if (*seq == '|') {
|
||||
seq++;
|
||||
@ -576,6 +676,9 @@ term_word(struct termp *p, const char *word)
|
||||
case ESCAPE_SPECIAL:
|
||||
uc = mchars_spec2cp(cp, sz);
|
||||
break;
|
||||
case ESCAPE_UNDEF:
|
||||
uc = *seq;
|
||||
break;
|
||||
default:
|
||||
uc = -1;
|
||||
break;
|
||||
@ -834,12 +937,8 @@ term_strlen(const struct termp *p, const char *cp)
|
||||
switch (*cp) {
|
||||
case '\\':
|
||||
cp++;
|
||||
esc = mandoc_escape(&cp, &seq, &ssz);
|
||||
if (ESCAPE_ERROR == esc)
|
||||
continue;
|
||||
|
||||
rhs = NULL;
|
||||
|
||||
esc = mandoc_escape(&cp, &seq, &ssz);
|
||||
switch (esc) {
|
||||
case ESCAPE_UNICODE:
|
||||
uc = mchars_num2uc(seq + 1, ssz - 1);
|
||||
@ -860,6 +959,24 @@ term_strlen(const struct termp *p, const char *cp)
|
||||
sz += cond_width(p, uc, &skip);
|
||||
}
|
||||
continue;
|
||||
case ESCAPE_UNDEF:
|
||||
uc = *seq;
|
||||
break;
|
||||
case ESCAPE_DEVICE:
|
||||
if (p->type == TERMTYPE_PDF) {
|
||||
rhs = "pdf";
|
||||
rsz = 3;
|
||||
} else if (p->type == TERMTYPE_PS) {
|
||||
rhs = "ps";
|
||||
rsz = 2;
|
||||
} else if (p->enc == TERMENC_ASCII) {
|
||||
rhs = "ascii";
|
||||
rsz = 5;
|
||||
} else {
|
||||
rhs = "utf8";
|
||||
rsz = 4;
|
||||
}
|
||||
break;
|
||||
case ESCAPE_SKIPCHAR:
|
||||
skip = 1;
|
||||
continue;
|
||||
|
6
term.h
6
term.h
@ -1,7 +1,7 @@
|
||||
/* $Id: term.h,v 1.130 2017/07/08 14:51:05 schwarze Exp $ */
|
||||
/* $Id: term.h,v 1.131 2019/01/04 03:21:02 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2011-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
* Copyright (c) 2011-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
|
||||
@ -99,6 +99,8 @@ struct termp {
|
||||
#define TERMP_NEWMC (1 << 18) /* No .mc printed yet. */
|
||||
#define TERMP_ENDMC (1 << 19) /* Next break ends .mc mode. */
|
||||
#define TERMP_MULTICOL (1 << 20) /* Multiple column mode. */
|
||||
#define TERMP_CENTER (1 << 21) /* Center output lines. */
|
||||
#define TERMP_RIGHT (1 << 22) /* Adjust to the right margin. */
|
||||
enum termtype type; /* Terminal, PS, or PDF. */
|
||||
enum termenc enc; /* Type of encoding. */
|
||||
enum termfont fontl; /* Last font set. */
|
||||
|
13
term_ascii.c
13
term_ascii.c
@ -1,4 +1,4 @@
|
||||
/* $Id: term_ascii.c,v 1.61 2018/05/20 21:37:34 schwarze Exp $ */
|
||||
/* $Id: term_ascii.c,v 1.64 2018/11/28 14:23:06 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
* Copyright (c) 2014, 2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
|
||||
@ -90,7 +90,7 @@ ascii_init(enum termenc enc, const struct manoutput *outopts)
|
||||
p->width = ascii_width;
|
||||
|
||||
#if HAVE_WCHAR
|
||||
if (TERMENC_ASCII != enc) {
|
||||
if (enc != TERMENC_ASCII) {
|
||||
|
||||
/*
|
||||
* Do not change any of this to LC_ALL. It might break
|
||||
@ -99,7 +99,7 @@ ascii_init(enum termenc enc, const struct manoutput *outopts)
|
||||
* worst case, it might even cause buffer overflows.
|
||||
*/
|
||||
|
||||
v = TERMENC_LOCALE == enc ?
|
||||
v = enc == TERMENC_LOCALE ?
|
||||
setlocale(LC_CTYPE, "") :
|
||||
setlocale(LC_CTYPE, UTF8_LOCALE);
|
||||
|
||||
@ -113,7 +113,7 @@ ascii_init(enum termenc enc, const struct manoutput *outopts)
|
||||
v = setlocale(LC_CTYPE, "C");
|
||||
|
||||
if (v != NULL && MB_CUR_MAX > 1) {
|
||||
p->enc = enc;
|
||||
p->enc = TERMENC_UTF8;
|
||||
p->advance = locale_advance;
|
||||
p->endline = locale_endline;
|
||||
p->letter = locale_letter;
|
||||
@ -196,8 +196,7 @@ terminal_sepline(void *arg)
|
||||
static size_t
|
||||
ascii_width(const struct termp *p, int c)
|
||||
{
|
||||
|
||||
return 1;
|
||||
return c != ASCII_BREAK;
|
||||
}
|
||||
|
||||
void
|
||||
@ -311,7 +310,7 @@ ascii_uc2str(int uc)
|
||||
"<88>", "<89>", "<8A>", "<8B>", "<8C>", "<8D>", "<8E>", "<8F>",
|
||||
"<90>", "<91>", "<92>", "<93>", "<94>", "<95>", "<96>", "<97>",
|
||||
"<98>", "<99>", "<9A>", "<9B>", "<9C>", "<9D>", "<9E>", "<9F>",
|
||||
nbrsp, "!", "/\bc", "GBP", "o\bx", "=\bY", "|", "<section>",
|
||||
nbrsp, "!", "/\bc", "-\bL", "o\bx", "=\bY", "|", "<section>",
|
||||
"\"", "(C)", "_\ba", "<<", "~", "", "(R)", "-",
|
||||
"<degree>","+-","^2", "^3", "'","<micro>","<paragraph>",".",
|
||||
",", "^1", "_\bo", ">>", "1/4", "1/2", "3/4", "?",
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: term.c,v 1.119 2017/01/08 18:08:44 schwarze Exp $ */
|
||||
/* $Id: term_tab.c,v 1.5 2018/12/16 00:21:05 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
|
||||
*
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: test-getsubopt.c,v 1.4 2015/10/06 18:32:20 schwarze Exp $ */
|
||||
/* $Id: test-getsubopt.c,v 1.6 2018/08/15 14:37:41 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
*
|
||||
@ -15,12 +15,15 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#if defined(__linux__) || defined(__MINT__)
|
||||
#define _GNU_SOURCE /* getsubopt() */
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
* NetBSD declared this function in the wrong header before August 2018.
|
||||
* No harm is done by allowing that, too:
|
||||
* The only file using it, main.c, also includes unistd.h, anyway.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
|
@ -1,7 +1,3 @@
|
||||
#if defined(__linux__) || defined(__MINT__)
|
||||
# define _GNU_SOURCE /* strcasestr() */
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
int
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: test-stringlist.c,v 1.2 2015/10/06 18:32:20 schwarze Exp $ */
|
||||
/* $Id: test-stringlist.c,v 1.3 2018/08/15 02:48:51 schwarze Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
|
||||
*
|
||||
@ -15,6 +15,7 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stringlist.h>
|
||||
|
||||
int
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user