Import mandoc 2017-06-08

This commit is contained in:
Baptiste Daroussin 2017-06-08 19:29:07 +00:00
parent 6cae2c9f93
commit 7ad21139cd
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/mdocml/dist/; revision=319715
svn path=/vendor/mdocml/20170608/; revision=319716; tag=vendor/mandoc/20170608
81 changed files with 6231 additions and 3749 deletions

View File

@ -1,4 +1,4 @@
$Id: LICENSE,v 1.14 2017/02/08 12:24:10 schwarze Exp $ $Id: LICENSE,v 1.15 2017/02/21 00:37:03 schwarze Exp $
With the exceptions noted below, all code and documentation With the exceptions noted below, all code and documentation
contained in the mdocml toolkit is protected by the Copyright contained in the mdocml toolkit is protected by the Copyright

View File

@ -1,4 +1,4 @@
# $Id: Makefile,v 1.504 2017/02/18 15:29:39 schwarze Exp $ # $Id: Makefile,v 1.512 2017/05/07 17:31:45 schwarze Exp $
# #
# Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> # Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
# Copyright (c) 2011, 2013-2017 Ingo Schwarze <schwarze@openbsd.org> # Copyright (c) 2011, 2013-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -85,7 +85,6 @@ SRCS = att.c \
lib.c \ lib.c \
main.c \ main.c \
man.c \ man.c \
man_hash.c \
man_html.c \ man_html.c \
man_macro.c \ man_macro.c \
man_term.c \ man_term.c \
@ -95,15 +94,14 @@ SRCS = att.c \
mandoc_ohash.c \ mandoc_ohash.c \
mandocd.c \ mandocd.c \
mandocdb.c \ mandocdb.c \
manpage.c \
manpath.c \ manpath.c \
mansearch.c \ mansearch.c \
mdoc.c \ mdoc.c \
mdoc_argv.c \ mdoc_argv.c \
mdoc_hash.c \
mdoc_html.c \ mdoc_html.c \
mdoc_macro.c \ mdoc_macro.c \
mdoc_man.c \ mdoc_man.c \
mdoc_markdown.c \
mdoc_state.c \ mdoc_state.c \
mdoc_term.c \ mdoc_term.c \
mdoc_validate.c \ mdoc_validate.c \
@ -112,6 +110,9 @@ SRCS = att.c \
preconv.c \ preconv.c \
read.c \ read.c \
roff.c \ roff.c \
roff_html.c \
roff_term.c \
roff_validate.c \
soelim.c \ soelim.c \
st.c \ st.c \
tag.c \ tag.c \
@ -124,6 +125,7 @@ SRCS = att.c \
term.c \ term.c \
term_ascii.c \ term_ascii.c \
term_ps.c \ term_ps.c \
term_tab.c \
tree.c tree.c
DISTFILES = INSTALL \ DISTFILES = INSTALL \
@ -198,7 +200,6 @@ DISTFILES = INSTALL \
$(TESTSRCS) $(TESTSRCS)
LIBMAN_OBJS = man.o \ LIBMAN_OBJS = man.o \
man_hash.o \
man_macro.o \ man_macro.o \
man_validate.o man_validate.o
@ -206,7 +207,6 @@ LIBMDOC_OBJS = att.o \
lib.o \ lib.o \
mdoc.o \ mdoc.o \
mdoc_argv.o \ mdoc_argv.o \
mdoc_hash.o \
mdoc_macro.o \ mdoc_macro.o \
mdoc_state.o \ mdoc_state.o \
mdoc_validate.o \ mdoc_validate.o \
@ -214,6 +214,7 @@ LIBMDOC_OBJS = att.o \
LIBROFF_OBJS = eqn.o \ LIBROFF_OBJS = eqn.o \
roff.o \ roff.o \
roff_validate.o \
tbl.o \ tbl.o \
tbl_data.o \ tbl_data.o \
tbl_layout.o \ tbl_layout.o \
@ -250,16 +251,17 @@ MANDOC_HTML_OBJS = eqn_html.o \
html.o \ html.o \
man_html.o \ man_html.o \
mdoc_html.o \ mdoc_html.o \
roff_html.o \
tbl_html.o tbl_html.o
MANDOC_MAN_OBJS = mdoc_man.o
MANDOC_TERM_OBJS = eqn_term.o \ MANDOC_TERM_OBJS = eqn_term.o \
man_term.o \ man_term.o \
mdoc_term.o \ mdoc_term.o \
roff_term.o \
term.o \ term.o \
term_ascii.o \ term_ascii.o \
term_ps.o \ term_ps.o \
term_tab.o \
tbl_term.o tbl_term.o
DBM_OBJS = dbm.o \ DBM_OBJS = dbm.o \
@ -279,6 +281,8 @@ MAIN_OBJS = $(MANDOC_HTML_OBJS) \
$(DBA_OBJS) \ $(DBA_OBJS) \
main.o \ main.o \
manpath.o \ manpath.o \
mdoc_man.o \
mdoc_markdown.o \
out.o \ out.o \
tag.o \ tag.o \
tree.o tree.o
@ -294,10 +298,6 @@ MANDOCD_OBJS = $(MANDOC_HTML_OBJS) \
out.o \ out.o \
tag.o tag.o
MANPAGE_OBJS = $(DBM_OBJS) \
manpage.o \
manpath.o
DEMANDOC_OBJS = demandoc.o DEMANDOC_OBJS = demandoc.o
SOELIM_OBJS = soelim.o \ SOELIM_OBJS = soelim.o \
@ -373,7 +373,6 @@ clean:
rm -f mandoc $(MAIN_OBJS) rm -f mandoc $(MAIN_OBJS)
rm -f man.cgi $(CGI_OBJS) rm -f man.cgi $(CGI_OBJS)
rm -f mandocd catman $(MANDOCD_OBJS) rm -f mandocd catman $(MANDOCD_OBJS)
rm -f manpage $(MANPAGE_OBJS)
rm -f demandoc $(DEMANDOC_OBJS) rm -f demandoc $(DEMANDOC_OBJS)
rm -f soelim $(SOELIM_OBJS) rm -f soelim $(SOELIM_OBJS)
rm -f $(WWW_MANS) $(WWW_OBJS) rm -f $(WWW_MANS) $(WWW_OBJS)
@ -388,17 +387,16 @@ base-install: mandoc demandoc soelim
mkdir -p $(DESTDIR)$(MANDIR)/man8 mkdir -p $(DESTDIR)$(MANDIR)/man8
$(INSTALL_PROGRAM) mandoc demandoc $(DESTDIR)$(BINDIR) $(INSTALL_PROGRAM) mandoc demandoc $(DESTDIR)$(BINDIR)
$(INSTALL_PROGRAM) soelim $(DESTDIR)$(BINDIR)/$(BINM_SOELIM) $(INSTALL_PROGRAM) soelim $(DESTDIR)$(BINDIR)/$(BINM_SOELIM)
$(LN) $(DESTDIR)$(BINDIR)/mandoc $(DESTDIR)$(BINDIR)/$(BINM_MAN) cd $(DESTDIR)$(BINDIR) && $(LN) mandoc $(BINM_MAN)
$(LN) $(DESTDIR)$(BINDIR)/mandoc $(DESTDIR)$(BINDIR)/$(BINM_APROPOS) cd $(DESTDIR)$(BINDIR) && $(LN) mandoc $(BINM_APROPOS)
$(LN) $(DESTDIR)$(BINDIR)/mandoc $(DESTDIR)$(BINDIR)/$(BINM_WHATIS) cd $(DESTDIR)$(BINDIR) && $(LN) mandoc $(BINM_WHATIS)
$(LN) $(DESTDIR)$(BINDIR)/mandoc \ cd $(DESTDIR)$(SBINDIR) && \
$(DESTDIR)$(SBINDIR)/$(BINM_MAKEWHATIS) $(LN) ${BIN_FROM_SBIN}/mandoc $(BINM_MAKEWHATIS)
$(INSTALL_MAN) mandoc.1 demandoc.1 $(DESTDIR)$(MANDIR)/man1 $(INSTALL_MAN) mandoc.1 demandoc.1 $(DESTDIR)$(MANDIR)/man1
$(INSTALL_MAN) soelim.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_SOELIM).1 $(INSTALL_MAN) soelim.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_SOELIM).1
$(INSTALL_MAN) man.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_MAN).1 $(INSTALL_MAN) man.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_MAN).1
$(INSTALL_MAN) apropos.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_APROPOS).1 $(INSTALL_MAN) apropos.1 $(DESTDIR)$(MANDIR)/man1/$(BINM_APROPOS).1
$(LN) $(DESTDIR)$(MANDIR)/man1/$(BINM_APROPOS).1 \ cd $(DESTDIR)$(MANDIR)/man1 && $(LN) $(BINM_APROPOS).1 $(BINM_WHATIS).1
$(DESTDIR)$(MANDIR)/man1/$(BINM_WHATIS).1
$(INSTALL_MAN) man.conf.5 $(DESTDIR)$(MANDIR)/man5/$(MANM_MANCONF).5 $(INSTALL_MAN) man.conf.5 $(DESTDIR)$(MANDIR)/man5/$(MANM_MANCONF).5
$(INSTALL_MAN) mandoc.db.5 $(DESTDIR)$(MANDIR)/man5 $(INSTALL_MAN) mandoc.db.5 $(DESTDIR)$(MANDIR)/man5
$(INSTALL_MAN) man.7 $(DESTDIR)$(MANDIR)/man7/$(MANM_MAN).7 $(INSTALL_MAN) man.7 $(DESTDIR)$(MANDIR)/man7/$(MANM_MAN).7
@ -475,7 +473,7 @@ uninstall:
rm -f $(DESTDIR)$(INCLUDEDIR)/mandoc_aux.h rm -f $(DESTDIR)$(INCLUDEDIR)/mandoc_aux.h
rm -f $(DESTDIR)$(INCLUDEDIR)/mdoc.h rm -f $(DESTDIR)$(INCLUDEDIR)/mdoc.h
rm -f $(DESTDIR)$(INCLUDEDIR)/roff.h rm -f $(DESTDIR)$(INCLUDEDIR)/roff.h
rmdir $(DESTDIR)$(INCLUDEDIR) [ ! -e $(DESTDIR)$(INCLUDEDIR) ] || rmdir $(DESTDIR)$(INCLUDEDIR)
regress: all regress: all
cd regress && ./regress.pl cd regress && ./regress.pl
@ -493,9 +491,6 @@ libmandoc.a: $(COMPAT_OBJS) $(LIBMANDOC_OBJS)
mandoc: $(MAIN_OBJS) libmandoc.a mandoc: $(MAIN_OBJS) libmandoc.a
$(CC) -o $@ $(LDFLAGS) $(MAIN_OBJS) libmandoc.a $(LDADD) $(CC) -o $@ $(LDFLAGS) $(MAIN_OBJS) libmandoc.a $(LDADD)
manpage: $(MANPAGE_OBJS) libmandoc.a
$(CC) -o $@ $(LDFLAGS) $(MANPAGE_OBJS) libmandoc.a $(LDADD)
man.cgi: $(CGI_OBJS) libmandoc.a man.cgi: $(CGI_OBJS) libmandoc.a
$(CC) $(STATIC) -o $@ $(LDFLAGS) $(CGI_OBJS) libmandoc.a $(LDADD) $(CC) $(STATIC) -o $@ $(LDFLAGS) $(CGI_OBJS) libmandoc.a $(LDADD)

View File

@ -28,11 +28,10 @@ demandoc.o: demandoc.c config.h roff.h man.h mdoc.h mandoc.h
eqn.o: eqn.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h eqn.o: eqn.c config.h mandoc.h mandoc_aux.h libmandoc.h libroff.h
eqn_html.o: eqn_html.c config.h mandoc.h out.h html.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 eqn_term.o: eqn_term.c config.h mandoc.h out.h term.h
html.o: html.c config.h mandoc.h mandoc_aux.h out.h html.h manconf.h main.h html.o: html.c config.h mandoc_aux.h mandoc.h roff.h out.h html.h manconf.h main.h
lib.o: lib.c config.h roff.h mdoc.h libmdoc.h lib.in lib.o: lib.c config.h roff.h mdoc.h libmdoc.h lib.in
main.o: main.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h tag.h main.h manconf.h mansearch.h main.o: main.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.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.o: man.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h
man_hash.o: man_hash.c config.h mandoc.h roff.h man.h libmandoc.h libman.h
man_html.o: man_html.c config.h mandoc_aux.h roff.h man.h out.h html.h main.h man_html.o: man_html.c config.h mandoc_aux.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_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 mandoc.h roff.h man.h out.h term.h main.h
@ -42,15 +41,14 @@ mandoc_aux.o: mandoc_aux.c config.h mandoc.h mandoc_aux.h
mandoc_ohash.o: mandoc_ohash.c mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc_ohash.o: mandoc_ohash.c mandoc_aux.h mandoc_ohash.h compat_ohash.h
mandocd.o: mandocd.c config.h mandoc.h roff.h mdoc.h man.h main.h manconf.h 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 mandocdb.o: mandocdb.c config.h compat_fts.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h mdoc.h man.h manconf.h mansearch.h dba_array.h dba.h
manpage.o: manpage.c config.h manconf.h mansearch.h
manpath.o: manpath.c config.h mandoc_aux.h manconf.h 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.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.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_argv.o: mdoc_argv.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h
mdoc_hash.o: mdoc_hash.c config.h mandoc.h roff.h mdoc.h libmandoc.h libmdoc.h
mdoc_html.o: mdoc_html.c config.h mandoc_aux.h roff.h mdoc.h out.h html.h main.h mdoc_html.o: mdoc_html.c config.h mandoc_aux.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_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_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_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_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_validate.o: mdoc_validate.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h mdoc_validate.o: mdoc_validate.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h
@ -58,7 +56,10 @@ 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 out.o: out.c config.h mandoc_aux.h mandoc.h out.h
preconv.o: preconv.c config.h mandoc.h libmandoc.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_int.h read.o: read.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h libmandoc.h roff_int.h
roff.o: roff.c config.h mandoc.h mandoc_aux.h roff.h libmandoc.h roff_int.h libroff.h predefs.in 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
roff_html.o: roff_html.c roff.h out.h html.h
roff_term.o: roff_term.c 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 soelim.o: soelim.c config.h compat_stringlist.h
st.o: st.c config.h roff.h mdoc.h libmdoc.h st.in st.o: st.c config.h roff.h mdoc.h libmdoc.h st.in
tag.o: tag.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h tag.h tag.o: tag.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h tag.h
@ -71,4 +72,5 @@ tbl_term.o: tbl_term.c config.h mandoc.h out.h term.h
term.o: term.c config.h mandoc.h mandoc_aux.h out.h term.h main.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_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_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 main.h

2
NEWS
View File

@ -1,4 +1,4 @@
$Id: NEWS,v 1.20 2017/02/16 14:38:12 schwarze Exp $ $Id: NEWS,v 1.21 2017/02/21 00:37:03 schwarze Exp $
This file lists the most important changes in the mdocml.bsd.lv distribution. This file lists the most important changes in the mdocml.bsd.lv distribution.

29
TODO
View File

@ -1,6 +1,6 @@
************************************************************************ ************************************************************************
* Official mandoc TODO. * Official mandoc TODO.
* $Id: TODO,v 1.234 2017/02/18 11:53:33 schwarze Exp $ * $Id: TODO,v 1.237 2017/05/16 19:06:30 schwarze Exp $
************************************************************************ ************************************************************************
Many issues are annotated for difficulty as follows: Many issues are annotated for difficulty as follows:
@ -61,18 +61,6 @@ are mere guesses, and some may be wrong.
reported by brad@ Sat, 15 Jan 2011 15:45:23 -0500 reported by brad@ Sat, 15 Jan 2011 15:45:23 -0500
loc *** exist *** algo *** size ** imp * loc *** exist *** algo *** size ** imp *
- .ta (tab settings)
#1 most important issue naddy@ Mon, 16 Feb 2015 20:59:17 +0100
ircbug(1) gnats(1) reported by brad@ Sat, 15 Jan 2011 15:50:51 -0500
also Tcl_NewStringObj(3) via wiz@ Wed, 5 Mar 2014 22:27:43 +0100
also posix2time(3) Carsten Kunze Mon, 1 Dec 2014 13:03:10 +0100
loc ** exist *** algo ** size ** imp ***
- .ti (temporary indent)
found by naddy@ in xloadimage(1) [devel/libvstr] vstr(3)
found by bentley@ in nmh(1) Mon, 23 Apr 2012 13:38:28 -0600
loc ** exist ** algo ** size * imp ** (parser reorg helps a lot)
- .while and .shift - .while and .shift
found by jca@ in ratpoison(1) Sun, 30 Jun 2013 12:01:09 +0200 found by jca@ in ratpoison(1) Sun, 30 Jun 2013 12:01:09 +0200
loc * exist ** algo ** size ** imp ** loc * exist ** algo ** size ** imp **
@ -273,12 +261,6 @@ are mere guesses, and some may be wrong.
- kettenis wants base roff, ms, and me Fri, 1 Jan 2010 22:13:15 +0100 (CET) - kettenis wants base roff, ms, and me Fri, 1 Jan 2010 22:13:15 +0100 (CET)
loc ** exist ** algo ** size *** imp * loc ** exist ** algo ** size *** imp *
- Vsevolod Stakhov (FreeBSD) needs either a markdown output formatter
for mandoc -mdoc or a markdown to mdoc converter because they
have to maintain manuals needed both in markdown and mdoc format.
Look at the libsoldout (markdown -> whatever)
loc * exist * algo * size ** imp **
--- compatibility checks ----------------------------------------------- --- compatibility checks -----------------------------------------------
- is .Bk implemented correctly in modern groff? - is .Bk implemented correctly in modern groff?
@ -566,8 +548,6 @@ are mere guesses, and some may be wrong.
Several areas can be cleaned up to make mandoc even faster. These are Several areas can be cleaned up to make mandoc even faster. These are
- improve hashing mechanism for macros (quite important: performance)
- the PDF file is HUGE: this can be reduced by using relative offsets - the PDF file is HUGE: this can be reduced by using relative offsets
************************************************************************ ************************************************************************
@ -613,3 +593,10 @@ Several areas can be cleaned up to make mandoc even faster. These are
- use uname(1) to set doc-default-operating-system at install time - use uname(1) to set doc-default-operating-system at install time
tobimensch Mon, 1 Dec 2014 00:25:07 +0100 tobimensch Mon, 1 Dec 2014 00:25:07 +0100
- apostrophe (39), circumflex (94), grave (96), tilde (126)
in manuals: \(aq, \(ha, \`, \(ti
Re: [Groff] ASCII Minus Sign in man Pages.
bentley@ 26 Apr 2017 10:02:06 -0600
Do we need to fix existing manuals?
Do we need to fix the definition of the mdoc(7) language?

117
apropos.1
View File

@ -1,7 +1,7 @@
.\" $Id: apropos.1,v 1.40 2017/01/31 19:44:04 schwarze Exp $ .\" $Id: apropos.1,v 1.45 2017/03/27 18:51:36 schwarze Exp $
.\" .\"
.\" Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> .\" Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2011, 2012, 2014 Ingo Schwarze <schwarze@openbsd.org> .\" Copyright (c) 2011, 2012, 2014, 2017 Ingo Schwarze <schwarze@openbsd.org>
.\" .\"
.\" Permission to use, copy, modify, and distribute this software for any .\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above .\" 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 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: January 31 2017 $ .Dd $Mdocdate: March 27 2017 $
.Dt APROPOS 1 .Dt APROPOS 1
.Os .Os
.Sh NAME .Sh NAME
@ -24,7 +24,7 @@
.Nd search manual page databases .Nd search manual page databases
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm .Nm
.Op Fl acfhklw .Op Fl afk
.Op Fl C Ar file .Op Fl C Ar file
.Op Fl M Ar path .Op Fl M Ar path
.Op Fl m Ar path .Op Fl m Ar path
@ -89,12 +89,6 @@ Specify an alternative configuration
in in
.Xr man.conf 5 .Xr man.conf 5
format. format.
.It Fl c
In
.Fl a
mode, copy the formatted manual pages to the standard output without using
.Xr more 1
to paginate them.
.It Fl f .It Fl f
Search for all words in Search for all words in
.Ar expression .Ar expression
@ -102,37 +96,12 @@ 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 In this mode, macro keys, comparison operators, and logical operators
are not available. are not available.
This overrides any earlier
.Fl k
and
.Fl l
options.
.It Fl h
Instead of showing the title lines, show the SYNOPSIS sections, just like
.Xr man 1
.Fl h
would.
.It Fl k .It Fl k
Support the full Support the full
.Ar expression .Ar expression
syntax. syntax.
This overrides any earlier
.Fl f
and
.Fl l
options.
It is the default for It is the default for
.Nm . .Nm .
.It Fl l
An alias for
.Xr mandoc 1
.Fl a .
This overrides any earlier
.Fl f ,
.Fl k ,
and
.Fl w
options.
.It Fl M Ar path .It Fl M Ar path
Use the colon-separated path instead of the default list of paths Use the colon-separated path instead of the default list of paths
searched for searched for
@ -162,14 +131,16 @@ By default, pages from all sections are shown.
See See
.Xr man 1 .Xr man 1
for a listing of sections. for a listing of sections.
.It Fl w
Instead of showing title lines, show the pathnames of the matching
manual pages, just like
.Xr man 1
.Fl w
would.
.El .El
.Pp .Pp
The options
.Fl chlw
are also supported and are documented in
.Xr man 1 .
The options
.Fl fkl
are mutually exclusive and override each other.
.Pp
An An
.Ar expression .Ar expression
consists of search terms joined by logical operators consists of search terms joined by logical operators
@ -237,7 +208,28 @@ is evaluated case-insensitively.
Has no effect on substring terms. Has no effect on substring terms.
.El .El
.Pp .Pp
Results are sorted by manual sections and names, with output formatted as 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
.Xr ascii 7
alphabetical order, case-insensitive.
.El
.Pp
Each output line is formatted as
.Pp .Pp
.D1 name[, name...](sec) \- description .D1 name[, name...](sec) \- description
.Pp .Pp
@ -341,25 +333,25 @@ Text production:
.It Ev MANPAGER .It Ev MANPAGER
Any non-empty value of the environment variable Any non-empty value of the environment variable
.Ev MANPAGER .Ev MANPAGER
will be used instead of the standard pagination program, is used instead of the standard pagination program,
.Xr more 1 . .Xr more 1 ;
.It Ev MANPATH see
The standard search path used by
.Xr man 1 .Xr man 1
may be changed by specifying a path in the for details.
.Ev MANPATH Only used if
environment variable. .Fl a
Invalid paths, or paths without manual databases, are ignored. or
.Fl l
is specified.
.It Ev MANPATH
A colon-separated list of directories to search for manual pages; see
.Xr man 1
for details.
Overridden by Overridden by
.Fl M . .Fl M ,
If ignored if
.Ev MANPATH .Fl l
begins with a colon, it is appended to the default list; is specified.
if it ends with a colon, it is prepended to the default list;
or if it contains two adjacent colons,
the standard search path is inserted between the colons.
If none of these conditions are met, it overrides the
standard search path.
.It Ev PAGER .It Ev PAGER
Specifies the pagination program to use when Specifies the pagination program to use when
.Ev MANPAGER .Ev MANPAGER
@ -367,7 +359,12 @@ is not defined.
If neither PAGER nor MANPAGER is defined, If neither PAGER nor MANPAGER is defined,
.Xr more 1 .Xr more 1
.Fl s .Fl s
will be used. is used.
Only used if
.Fl a
or
.Fl l
is specified.
.El .El
.Sh FILES .Sh FILES
.Bl -tag -width "/etc/man.conf" -compact .Bl -tag -width "/etc/man.conf" -compact

View File

@ -1,4 +1,4 @@
.\" $Id: catman.8,v 1.7 2017/02/06 19:04:21 schwarze Exp $ .\" $Id: catman.8,v 1.8 2017/03/18 19:56:01 schwarze Exp $
.\" .\"
.\" Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org> .\" Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
.\" .\"
@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: February 6 2017 $ .Dd $Mdocdate: March 18 2017 $
.Dt CATMAN 8 .Dt CATMAN 8
.Os .Os
.Sh NAME .Sh NAME
@ -49,7 +49,7 @@ Override the default operating system
.Ar name .Ar name
for the for the
.Xr mdoc 7 .Xr mdoc 7
.Ic Os .Ic \&Os
and for the and for the
.Xr man 7 .Xr man 7
.Ic TH .Ic TH

151
cgi.c
View File

@ -1,4 +1,4 @@
/* $Id: cgi.c,v 1.147 2017/02/08 13:34:27 schwarze Exp $ */ /* $Id: cgi.c,v 1.154 2017/04/19 01:00:03 schwarze Exp $ */
/* /*
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> * 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 Ingo Schwarze <schwarze@usta.de>
@ -76,11 +76,12 @@ static void pg_error_badrequest(const char *);
static void pg_error_internal(void); static void pg_error_internal(void);
static void pg_index(const struct req *); static void pg_index(const struct req *);
static void pg_noresult(const struct req *, const char *); static void pg_noresult(const struct req *, const char *);
static void pg_redirect(const struct req *, const char *);
static void pg_search(const struct req *); static void pg_search(const struct req *);
static void pg_searchres(const struct req *, static void pg_searchres(const struct req *,
struct manpage *, size_t); struct manpage *, size_t);
static void pg_show(struct req *, const char *); static void pg_show(struct req *, const char *);
static void resp_begin_html(int, const char *); static void resp_begin_html(int, const char *, const char *);
static void resp_begin_http(int, const char *); static void resp_begin_http(int, const char *);
static void resp_catman(const struct req *, const char *); static void resp_catman(const struct req *, const char *);
static void resp_copy(const char *); static void resp_copy(const char *);
@ -345,8 +346,9 @@ resp_copy(const char *filename)
} }
static void static void
resp_begin_html(int code, const char *msg) resp_begin_html(int code, const char *msg, const char *file)
{ {
char *cp;
resp_begin_http(code, msg); resp_begin_http(code, msg);
@ -356,10 +358,20 @@ resp_begin_html(int code, const char *msg)
" <meta charset=\"UTF-8\"/>\n" " <meta charset=\"UTF-8\"/>\n"
" <link rel=\"stylesheet\" href=\"%s/mandoc.css\"" " <link rel=\"stylesheet\" href=\"%s/mandoc.css\""
" type=\"text/css\" media=\"all\">\n" " type=\"text/css\" media=\"all\">\n"
" <title>%s</title>\n" " <title>",
CSS_DIR);
if (file != NULL) {
if ((cp = strrchr(file, '/')) != NULL)
file = cp + 1;
if ((cp = strrchr(file, '.')) != NULL) {
printf("%.*s(%s) - ", (int)(cp - file), file, cp + 1);
} else
printf("%s - ", file);
}
printf("%s</title>\n"
"</head>\n" "</head>\n"
"<body>\n", "<body>\n",
CSS_DIR, CUSTOMIZE_TITLE); CUSTOMIZE_TITLE);
resp_copy(MAN_DIR "/header.html"); resp_copy(MAN_DIR "/header.html");
} }
@ -492,7 +504,7 @@ static void
pg_index(const struct req *req) pg_index(const struct req *req)
{ {
resp_begin_html(200, NULL); resp_begin_html(200, NULL, NULL);
resp_searchform(req, FOCUS_QUERY); resp_searchform(req, FOCUS_QUERY);
printf("<p>\n" printf("<p>\n"
"This web interface is documented in the\n" "This web interface is documented in the\n"
@ -509,7 +521,7 @@ pg_index(const struct req *req)
static void static void
pg_noresult(const struct req *req, const char *msg) pg_noresult(const struct req *req, const char *msg)
{ {
resp_begin_html(200, NULL); resp_begin_html(200, NULL, NULL);
resp_searchform(req, FOCUS_QUERY); resp_searchform(req, FOCUS_QUERY);
puts("<p>"); puts("<p>");
puts(msg); puts(msg);
@ -521,7 +533,7 @@ static void
pg_error_badrequest(const char *msg) pg_error_badrequest(const char *msg)
{ {
resp_begin_html(400, "Bad Request"); resp_begin_html(400, "Bad Request", NULL);
puts("<h1>Bad Request</h1>\n" puts("<h1>Bad Request</h1>\n"
"<p>\n"); "<p>\n");
puts(msg); puts(msg);
@ -534,11 +546,28 @@ pg_error_badrequest(const char *msg)
static void static void
pg_error_internal(void) pg_error_internal(void)
{ {
resp_begin_html(500, "Internal Server Error"); resp_begin_html(500, "Internal Server Error", NULL);
puts("<p>Internal Server Error</p>"); puts("<p>Internal Server Error</p>");
resp_end_html(); resp_end_html();
} }
static void
pg_redirect(const struct req *req, const char *name)
{
printf("Status: 303 See Other\r\n"
"Location: /");
if (*scriptname != '\0')
printf("%s/", scriptname);
if (strcmp(req->q.manpath, req->p[0]))
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);
printf("\r\nContent-Type: text/html; charset=utf-8\r\n\r\n");
}
static void static void
pg_searchres(const struct req *req, struct manpage *r, size_t sz) pg_searchres(const struct req *req, struct manpage *r, size_t sz)
{ {
@ -562,47 +591,25 @@ pg_searchres(const struct req *req, struct manpage *r, size_t sz)
* If we have just one result, then jump there now * If we have just one result, then jump there now
* without any delay. * without any delay.
*/ */
printf("Status: 303 See Other\r\n"); printf("Status: 303 See Other\r\n"
printf("Location: http://%s/%s%s%s/%s", "Location: /");
HTTP_HOST, scriptname, if (*scriptname != '\0')
*scriptname == '\0' ? "" : "/", printf("%s/", scriptname);
req->q.manpath, r[0].file); if (strcmp(req->q.manpath, req->p[0]))
printf("\r\n" printf("%s/", req->q.manpath);
"Content-Type: text/html; charset=utf-8\r\n" printf("%s\r\n"
"\r\n"); "Content-Type: text/html; charset=utf-8\r\n\r\n",
r[0].file);
return; return;
} }
resp_begin_html(200, NULL);
resp_searchform(req,
req->q.equal || sz == 1 ? FOCUS_NONE : FOCUS_QUERY);
if (sz > 1) {
puts("<table class=\"results\">");
for (i = 0; i < sz; i++) {
printf(" <tr>\n"
" <td>"
"<a class=\"Xr\" href=\"/%s%s%s/%s\">",
scriptname, *scriptname == '\0' ? "" : "/",
req->q.manpath, r[i].file);
html_print(r[i].names);
printf("</a></td>\n"
" <td><span class=\"Nd\">");
html_print(r[i].output);
puts("</span></td>\n"
" </tr>");
}
puts("</table>");
}
/* /*
* In man(1) mode, show one of the pages * In man(1) mode, show one of the pages
* even if more than one is found. * even if more than one is found.
*/ */
iuse = 0;
if (req->q.equal || sz == 1) { if (req->q.equal || sz == 1) {
puts("<hr>");
iuse = 0;
priouse = 20; priouse = 20;
archpriouse = 3; archpriouse = 3;
for (i = 0; i < sz; i++) { for (i = 0; i < sz; i++) {
@ -635,6 +642,36 @@ pg_searchres(const struct req *req, struct manpage *r, size_t sz)
priouse = prio; priouse = prio;
iuse = i; iuse = i;
} }
resp_begin_html(200, NULL, r[iuse].file);
} else
resp_begin_html(200, NULL, NULL);
resp_searchform(req,
req->q.equal || sz == 1 ? FOCUS_NONE : FOCUS_QUERY);
if (sz > 1) {
puts("<table class=\"results\">");
for (i = 0; i < sz; i++) {
printf(" <tr>\n"
" <td>"
"<a class=\"Xr\" href=\"/");
if (*scriptname != '\0')
printf("%s/", scriptname);
if (strcmp(req->q.manpath, req->p[0]))
printf("%s/", req->q.manpath);
printf("%s\">", r[i].file);
html_print(r[i].names);
printf("</a></td>\n"
" <td><span class=\"Nd\">");
html_print(r[i].output);
puts("</span></td>\n"
" </tr>");
}
puts("</table>");
}
if (req->q.equal || sz == 1) {
puts("<hr>");
resp_show(req, r[iuse].file); resp_show(req, r[iuse].file);
} }
@ -803,7 +840,8 @@ resp_format(const struct req *req, const char *file)
conf.fragment = 1; conf.fragment = 1;
conf.style = mandoc_strdup(CSS_DIR "/mandoc.css"); conf.style = mandoc_strdup(CSS_DIR "/mandoc.css");
usepath = strcmp(req->q.manpath, req->p[0]); usepath = strcmp(req->q.manpath, req->p[0]);
mandoc_asprintf(&conf.man, "/%s%s%%N.%%S", mandoc_asprintf(&conf.man, "/%s%s%s%s%%N.%%S",
scriptname, *scriptname == '\0' ? "" : "/",
usepath ? req->q.manpath : "", usepath ? "/" : ""); usepath ? req->q.manpath : "", usepath ? "/" : "");
mparse_result(mp, &man, NULL); mparse_result(mp, &man, NULL);
@ -886,7 +924,7 @@ pg_show(struct req *req, const char *fullpath)
return; return;
} }
resp_begin_html(200, NULL); resp_begin_html(200, NULL, file);
resp_searchform(req, FOCUS_NONE); resp_searchform(req, FOCUS_NONE);
resp_show(req, file); resp_show(req, file);
resp_end_html(); resp_end_html();
@ -956,9 +994,13 @@ pg_search(const struct req *req)
} }
} }
if (0 == mansearch(&search, &paths, argc, argv, &res, &ressz)) res = NULL;
ressz = 0;
if (req->isquery && req->q.equal && argc == 1)
pg_redirect(req, argv[0]);
else if (mansearch(&search, &paths, argc, argv, &res, &ressz) == 0)
pg_noresult(req, "You entered an invalid query."); pg_noresult(req, "You entered an invalid query.");
else if (0 == ressz) else if (ressz == 0)
pg_noresult(req, "No results found."); pg_noresult(req, "No results found.");
else else
pg_searchres(req, res, ressz); pg_searchres(req, res, ressz);
@ -978,6 +1020,22 @@ main(void)
const char *querystring; const char *querystring;
int i; int i;
#if HAVE_PLEDGE
/*
* The "rpath" pledge could be revoked after mparse_readfd()
* if the file desciptor to "/footer.html" would be opened
* up front, but it's probably not worth the complication
* of the code it would cause: it would require scattering
* pledge() calls in multiple low-level resp_*() functions.
*/
if (pledge("stdio rpath", NULL) == -1) {
warn("pledge");
pg_error_internal();
return EXIT_FAILURE;
}
#endif
/* Poor man's ReDoS mitigation. */ /* Poor man's ReDoS mitigation. */
itimer.it_value.tv_sec = 2; itimer.it_value.tv_sec = 2;
@ -1015,7 +1073,8 @@ main(void)
if (*path != '\0') { if (*path != '\0') {
parse_path_info(&req, path); parse_path_info(&req, path);
if (req.q.manpath == NULL || access(path, F_OK) == -1) if (req.q.manpath == NULL || req.q.sec == NULL ||
*req.q.query == '\0' || access(path, F_OK) == -1)
path = ""; path = "";
} else if ((querystring = getenv("QUERY_STRING")) != NULL) } else if ((querystring = getenv("QUERY_STRING")) != NULL)
parse_query_string(&req, querystring); parse_query_string(&req, querystring);

View File

@ -1,6 +1,5 @@
/* Example compile-time configuration file for man.cgi(8). */ /* Example compile-time configuration file for man.cgi(8). */
#define HTTP_HOST "mdocml.bsd.lv"
#define SCRIPT_NAME "cgi-bin/man.cgi" #define SCRIPT_NAME "cgi-bin/man.cgi"
#define MAN_DIR "/man" #define MAN_DIR "/man"
#define CSS_DIR "" #define CSS_DIR ""

20
chars.c
View File

@ -1,7 +1,7 @@
/* $Id: chars.c,v 1.69 2017/02/17 18:28:06 schwarze Exp $ */ /* $Id: chars.c,v 1.70 2017/06/02 12:43:52 schwarze Exp $ */
/* /*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -81,6 +81,10 @@ static struct ln lines[] = {
{ "sh", "#", 0x0023 }, { "sh", "#", 0x0023 },
{ "CR", "_|", 0x21b5 }, { "CR", "_|", 0x21b5 },
{ "OK", "\\/", 0x2713 }, { "OK", "\\/", 0x2713 },
{ "CL", "<club>", 0x2663 },
{ "SP", "<spade>", 0x2660 },
{ "HE", "<heart>", 0x2665 },
{ "DI", "<diamond>", 0x2666 },
/* Legal symbols. */ /* Legal symbols. */
{ "co", "(C)", 0x00a9 }, { "co", "(C)", 0x00a9 },
@ -161,6 +165,7 @@ static struct ln lines[] = {
{ "uA", "=\b^", 0x21d1 }, { "uA", "=\b^", 0x21d1 },
{ "dA", "=\bv", 0x21d3 }, { "dA", "=\bv", 0x21d3 },
{ "vA", "^=v", 0x21d5 }, { "vA", "^=v", 0x21d5 },
{ "an", "-", 0x23af },
/* Logic. */ /* Logic. */
{ "AN", "^", 0x2227 }, { "AN", "^", 0x2227 },
@ -234,11 +239,20 @@ static struct ln lines[] = {
{ "Ah", "N", 0x2135 }, { "Ah", "N", 0x2135 },
{ "Im", "I", 0x2111 }, { "Im", "I", 0x2111 },
{ "Re", "R", 0x211c }, { "Re", "R", 0x211c },
{ "wp", "P", 0x2118 },
{ "pd", "a", 0x2202 }, { "pd", "a", 0x2202 },
{ "-h", "/h", 0x210f }, { "-h", "/h", 0x210f },
{ "hbar", "/h", 0x210f },
{ "12", "1/2", 0x00bd }, { "12", "1/2", 0x00bd },
{ "14", "1/4", 0x00bc }, { "14", "1/4", 0x00bc },
{ "34", "3/4", 0x00be }, { "34", "3/4", 0x00be },
{ "18", "1/8", 0x215B },
{ "38", "3/8", 0x215C },
{ "58", "5/8", 0x215D },
{ "78", "7/8", 0x215E },
{ "S1", "1", 0x00B9 },
{ "S2", "2", 0x00B2 },
{ "S3", "3", 0x00B3 },
/* Ligatures. */ /* Ligatures. */
{ "ff", "ff", 0xfb00 }, { "ff", "ff", 0xfb00 },
@ -354,6 +368,8 @@ static struct ln lines[] = {
{ "fm", "\'", 0x2032 }, { "fm", "\'", 0x2032 },
{ "sd", "''", 0x2033 }, { "sd", "''", 0x2033 },
{ "mc", ",\bu", 0x00b5 }, { "mc", ",\bu", 0x00b5 },
{ "Of", "_\ba", 0x00aa },
{ "Om", "_\bo", 0x00ba },
/* Greek characters. */ /* Greek characters. */
{ "*A", "A", 0x0391 }, { "*A", "A", 0x0391 },

19
configure vendored
View File

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
# #
# $Id: configure,v 1.61 2017/02/18 12:24:24 schwarze Exp $ # $Id: configure,v 1.62 2017/03/04 16:36:29 schwarze Exp $
# #
# Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org> # Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
# #
@ -91,6 +91,7 @@ HAVE_WCHAR=
PREFIX="/usr/local" PREFIX="/usr/local"
BINDIR= BINDIR=
SBINDIR= SBINDIR=
BIN_FROM_SBIN=
INCLUDEDIR= INCLUDEDIR=
LIBDIR= LIBDIR=
MANDIR= MANDIR=
@ -458,14 +459,15 @@ echo "config.h: written" 1>&3
exec > Makefile.local exec > Makefile.local
[ -z "${BINDIR}" ] && BINDIR="${PREFIX}/bin" [ -z "${BINDIR}" ] && BINDIR="${PREFIX}/bin"
[ -z "${SBINDIR}" ] && SBINDIR="${PREFIX}/sbin" [ -z "${SBINDIR}" ] && SBINDIR="${PREFIX}/sbin"
[ -z "${INCLUDEDIR}" ] && INCLUDEDIR="${PREFIX}/include/mandoc" [ -z "${BIN_FROM_SBIN}" ] && BIN_FROM_SBIN="../bin"
[ -z "${LIBDIR}" ] && LIBDIR="${PREFIX}/lib/mandoc" [ -z "${INCLUDEDIR}" ] && INCLUDEDIR="${PREFIX}/include/mandoc"
[ -z "${MANDIR}" ] && MANDIR="${PREFIX}/man" [ -z "${LIBDIR}" ] && LIBDIR="${PREFIX}/lib/mandoc"
[ -z "${MANDIR}" ] && MANDIR="${PREFIX}/man"
[ -z "${HTDOCDIR}" ] && HTDOCDIR="${WWWPREFIX}/htdocs" [ -z "${HTDOCDIR}" ] && HTDOCDIR="${WWWPREFIX}/htdocs"
[ -z "${CGIBINDIR}" ] && CGIBINDIR="${WWWPREFIX}/cgi-bin" [ -z "${CGIBINDIR}" ] && CGIBINDIR="${WWWPREFIX}/cgi-bin"
[ -z "${INSTALL_PROGRAM}" ] && INSTALL_PROGRAM="${INSTALL} -m 0555" [ -z "${INSTALL_PROGRAM}" ] && INSTALL_PROGRAM="${INSTALL} -m 0555"
[ -z "${INSTALL_LIB}" ] && INSTALL_LIB="${INSTALL} -m 0444" [ -z "${INSTALL_LIB}" ] && INSTALL_LIB="${INSTALL} -m 0444"
@ -493,6 +495,7 @@ STATIC = ${STATIC}
PREFIX = ${PREFIX} PREFIX = ${PREFIX}
BINDIR = ${BINDIR} BINDIR = ${BINDIR}
SBINDIR = ${SBINDIR} SBINDIR = ${SBINDIR}
BIN_FROM_SBIN = ${BIN_FROM_SBIN}
INCLUDEDIR = ${INCLUDEDIR} INCLUDEDIR = ${INCLUDEDIR}
LIBDIR = ${LIBDIR} LIBDIR = ${LIBDIR}
MANDIR = ${MANDIR} MANDIR = ${MANDIR}

View File

@ -1,4 +1,4 @@
# $Id: configure.local.example,v 1.29 2017/02/18 12:24:24 schwarze Exp $ # $Id: configure.local.example,v 1.30 2017/03/04 16:36:29 schwarze Exp $
# #
# Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org> # Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
# #
@ -85,6 +85,13 @@ BINDIR="${PREFIX}/bin"
SBINDIR="${PREFIX}/sbin" SBINDIR="${PREFIX}/sbin"
MANDIR="${PREFIX}/man" MANDIR="${PREFIX}/man"
# If BINDIR and SBINDIR are not subdirectories of the same parent
# directory or if the basename(1) of BINDIR differs from "bin",
# the relative path from SBINDIR to BINDIR is also needed.
# The default is:
BIN_FROM_SBIN="../bin"
# Some distributions may want to avoid naming conflicts # Some distributions may want to avoid naming conflicts
# with the configuration files of other man(1) implementations. # with the configuration files of other man(1) implementations.
# This changes the name of the installed section 5 manual page as well. # This changes the name of the installed section 5 manual page as well.

11
eqn.c
View File

@ -1,4 +1,4 @@
/* $Id: eqn.c,v 1.61 2016/01/08 00:50:45 schwarze Exp $ */ /* $Id: eqn.c,v 1.62 2017/03/11 15:43:04 schwarze Exp $ */
/* /*
* Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -366,15 +366,19 @@ eqn_def_find(struct eqn_node *ep, const char *key, size_t sz)
static const char * static const char *
eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl) eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
{ {
static size_t last_len;
static int lim;
char *start, *next; char *start, *next;
int q, diff, lim; int q, diff;
size_t ssz, dummy; size_t ssz, dummy;
struct eqn_def *def; struct eqn_def *def;
if (NULL == sz) if (NULL == sz)
sz = &dummy; sz = &dummy;
lim = 0; if (ep->cur >= last_len)
lim = 0;
ep->rew = ep->cur; ep->rew = ep->cur;
again: again:
/* Prevent self-definitions. */ /* Prevent self-definitions. */
@ -448,6 +452,7 @@ eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
memmove(start + *sz + diff, start + *sz, memmove(start + *sz + diff, start + *sz,
(strlen(start) - *sz) + 1); (strlen(start) - *sz) + 1);
memcpy(start, def->val, def->valsz); memcpy(start, def->val, def->valsz);
last_len = start - ep->data + def->valsz;
lim++; lim++;
goto again; goto again;
} }

13
gmdiff
View File

@ -29,21 +29,24 @@ if [ "X$1" = "X-h" ]; then
EQN="neqn" EQN="neqn"
ROFF="nroff" ROFF="nroff"
MOPT="-Omdoc $MOPT" MOPT="-Omdoc $MOPT"
elif [ "X$1" = "X-u" ]; then
shift
ROFF="groff -ket -ww -Tutf8 -P -c"
MOPT="-Werror -Tutf8 $MOPT"
else else
EQN="eqn -Tascii" ROFF="groff -et -ww -Tascii -P -c"
ROFF="groff -ww -Tascii -P -c" MOPT="-Werror -Tascii $MOPT"
fi fi
MOPT="-Werror -Tascii $MOPT"
while [ -n "$1" ]; do while [ -n "$1" ]; do
file=$1 file=$1
shift shift
echo " ========== $file ========== " echo " ========== $file ========== "
tbl $file | $EQN | $ROFF -mandoc 2> /tmp/roff.err > /tmp/roff.out $ROFF -mandoc $file 2> /tmp/roff.err > /tmp/roff.out
${MANDOC:=mandoc} -Ios='OpenBSD ports' $MOPT $file \ ${MANDOC:=mandoc} -Ios='OpenBSD ports' $MOPT $file \
2> /tmp/mandoc.err > /tmp/mandoc.out 2> /tmp/mandoc.err > /tmp/mandoc.out
for i in roff mandoc; do for i in roff mandoc; do
[[ -s /tmp/$i.err ]] && echo "$i errors:" && cat /tmp/$i.err [ -s /tmp/$i.err ] && echo "$i errors:" && cat /tmp/$i.err
done done
diff -au /tmp/roff.out /tmp/mandoc.out 2>&1 diff -au /tmp/roff.out /tmp/mandoc.out 2>&1
done done

61
html.c
View File

@ -1,4 +1,4 @@
/* $Id: html.c,v 1.207 2017/02/05 20:22:04 schwarze Exp $ */ /* $Id: html.c,v 1.213 2017/06/08 12:54:58 schwarze Exp $ */
/* /*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011-2015, 2017 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2011-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -28,8 +28,9 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include "mandoc.h"
#include "mandoc_aux.h" #include "mandoc_aux.h"
#include "mandoc.h"
#include "roff.h"
#include "out.h" #include "out.h"
#include "html.h" #include "html.h"
#include "manconf.h" #include "manconf.h"
@ -236,6 +237,28 @@ print_metaf(struct html *h, enum mandoc_esc deco)
} }
} }
char *
html_make_id(const struct roff_node *n)
{
const struct roff_node *nch;
char *buf, *cp;
for (nch = n->child; nch != NULL; nch = nch->next)
if (nch->type != ROFFT_TEXT)
return NULL;
buf = NULL;
deroff(&buf, n);
/* http://www.w3.org/TR/html5/dom.html#the-id-attribute */
for (cp = buf; *cp != '\0'; cp++)
if (*cp == ' ')
*cp = '_';
return buf;
}
int int
html_strlen(const char *cp) html_strlen(const char *cp)
{ {
@ -534,18 +557,25 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
print_byte(h, '='); print_byte(h, '=');
print_byte(h, '"'); print_byte(h, '"');
switch (*fmt) { switch (*fmt) {
case 'M':
print_href(h, arg1, arg2, 1);
fmt++;
break;
case 'I': case 'I':
print_href(h, arg1, NULL, 0); print_href(h, arg1, NULL, 0);
fmt++; fmt++;
break; break;
case 'M':
print_href(h, arg1, arg2, 1);
fmt++;
break;
case 'R': case 'R':
print_byte(h, '#'); print_byte(h, '#');
print_encode(h, arg1, NULL, 1);
fmt++; fmt++;
/* FALLTHROUGH */ break;
case 'T':
print_encode(h, arg1, NULL, 1);
print_word(h, "\" title=\"");
print_encode(h, arg1, NULL, 1);
fmt++;
break;
default: default:
print_encode(h, arg1, NULL, 1); print_encode(h, arg1, NULL, 1);
break; break;
@ -579,13 +609,21 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
SCALE_VS_INIT(su, i); SCALE_VS_INIT(su, i);
break; break;
case 'w': case 'w':
case 'W':
if ((arg2 = va_arg(ap, char *)) == NULL) if ((arg2 = va_arg(ap, char *)) == NULL)
break; break;
su = &mysu; su = &mysu;
a2width(arg2, su); a2width(arg2, su);
if (fmt[-1] == 'W') if (*fmt == '+') {
/* Increase to make even bold text fit. */
su->scale *= 1.2;
/* Add padding. */
su->scale += 3.0;
fmt++;
}
if (*fmt == '-') {
su->scale *= -1.0; su->scale *= -1.0;
fmt++;
}
break; break;
default: default:
abort(); abort();
@ -912,7 +950,10 @@ print_word(struct html *h, const char *cp)
static void static void
a2width(const char *p, struct roffsu *su) a2width(const char *p, struct roffsu *su)
{ {
if (a2roffsu(p, su, SCALE_MAX) < 2) { const char *end;
end = a2roffsu(p, su, SCALE_MAX);
if (end == NULL || *end != '\0') {
su->unit = SCALE_EN; su->unit = SCALE_EN;
su->scale = html_strlen(p); su->scale = html_strlen(p);
} else if (su->scale < 0.0) } else if (su->scale < 0.0)

6
html.h
View File

@ -1,4 +1,4 @@
/* $Id: html.h,v 1.83 2017/02/05 20:22:04 schwarze Exp $ */ /* $Id: html.h,v 1.85 2017/05/04 22:16:09 schwarze Exp $ */
/* /*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -112,9 +112,12 @@ struct html {
}; };
struct roff_node;
struct tbl_span; struct tbl_span;
struct eqn; struct eqn;
void roff_html_pre(struct html *, const struct roff_node *);
void print_gen_decls(struct html *); void print_gen_decls(struct html *);
void print_gen_head(struct html *); void print_gen_head(struct html *);
struct tag *print_otag(struct html *, enum htmltag, const char *, ...); struct tag *print_otag(struct html *, enum htmltag, const char *, ...);
@ -127,4 +130,5 @@ void print_eqn(struct html *, const struct eqn *);
void print_paragraph(struct html *); void print_paragraph(struct html *);
void print_endline(struct html *); void print_endline(struct html *);
char *html_make_id(const struct roff_node *);
int html_strlen(const char *); int html_strlen(const char *);

View File

@ -1,4 +1,4 @@
/* $Id: libman.h,v 1.79 2015/11/07 14:01:16 schwarze Exp $ */ /* $Id: libman.h,v 1.81 2017/04/29 12:45:41 schwarze Exp $ */
/* /*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -17,7 +17,7 @@
*/ */
#define MACRO_PROT_ARGS struct roff_man *man, \ #define MACRO_PROT_ARGS struct roff_man *man, \
int tok, \ enum roff_tok tok, \
int line, \ int line, \
int ppos, \ int ppos, \
int *pos, \ int *pos, \
@ -35,7 +35,6 @@ struct man_macro {
extern const struct man_macro *const man_macros; extern const struct man_macro *const man_macros;
int man_hash_find(const char *);
void man_node_validate(struct roff_man *); void man_node_validate(struct roff_man *);
void man_state(struct roff_man *, struct roff_node *); void man_state(struct roff_man *, struct roff_node *);
void man_unscope(struct roff_man *, const struct roff_node *); void man_unscope(struct roff_man *, const struct roff_node *);

View File

@ -1,4 +1,4 @@
/* $Id: libmandoc.h,v 1.66 2017/02/18 13:43:52 schwarze Exp $ */ /* $Id: libmandoc.h,v 1.67 2017/04/29 12:45:41 schwarze Exp $ */
/* /*
* Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -50,11 +50,9 @@ int mandoc_eos(const char *, size_t);
int mandoc_strntoi(const char *, size_t, int); int mandoc_strntoi(const char *, size_t, int);
const char *mandoc_a2msec(const char*); const char *mandoc_a2msec(const char*);
void mdoc_hash_init(void);
int mdoc_parseln(struct roff_man *, int, char *, int); int mdoc_parseln(struct roff_man *, int, char *, int);
void mdoc_endparse(struct roff_man *); void mdoc_endparse(struct roff_man *);
void man_hash_init(void);
int man_parseln(struct roff_man *, int, char *, int); int man_parseln(struct roff_man *, int, char *, int);
void man_endparse(struct roff_man *); void man_endparse(struct roff_man *);

View File

@ -1,7 +1,7 @@
/* $Id: libmdoc.h,v 1.109 2017/02/16 03:00:23 schwarze Exp $ */ /* $Id: libmdoc.h,v 1.112 2017/05/30 16:22:03 schwarze Exp $ */
/* /*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -17,7 +17,7 @@
*/ */
#define MACRO_PROT_ARGS struct roff_man *mdoc, \ #define MACRO_PROT_ARGS struct roff_man *mdoc, \
int tok, \ enum roff_tok tok, \
int line, \ int line, \
int ppos, \ int ppos, \
int *pos, \ int *pos, \
@ -39,7 +39,6 @@ enum margserr {
ARGS_EOLN, /* end-of-line */ ARGS_EOLN, /* end-of-line */
ARGS_WORD, /* normal word */ ARGS_WORD, /* normal word */
ARGS_PUNCT, /* series of punctuation */ ARGS_PUNCT, /* series of punctuation */
ARGS_QWORD, /* quoted word */
ARGS_PHRASE /* Bl -column phrase */ ARGS_PHRASE /* Bl -column phrase */
}; };
@ -65,24 +64,24 @@ extern const struct mdoc_macro *const mdoc_macros;
void mdoc_macro(MACRO_PROT_ARGS); void mdoc_macro(MACRO_PROT_ARGS);
void mdoc_elem_alloc(struct roff_man *, int, int, void mdoc_elem_alloc(struct roff_man *, int, int,
int, struct mdoc_arg *); enum roff_tok, struct mdoc_arg *);
struct roff_node *mdoc_block_alloc(struct roff_man *, int, int, struct roff_node *mdoc_block_alloc(struct roff_man *, int, int,
int, struct mdoc_arg *); enum roff_tok, struct mdoc_arg *);
void mdoc_tail_alloc(struct roff_man *, int, int, int); void mdoc_tail_alloc(struct roff_man *, int, int,
struct roff_node *mdoc_endbody_alloc(struct roff_man *, int, int, int, enum roff_tok);
struct roff_node *); 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_relink(struct roff_man *, struct roff_node *);
void mdoc_node_validate(struct roff_man *); void mdoc_node_validate(struct roff_man *);
void mdoc_state(struct roff_man *, struct roff_node *); void mdoc_state(struct roff_man *, struct roff_node *);
void mdoc_state_reset(struct roff_man *); void mdoc_state_reset(struct roff_man *);
int mdoc_hash_find(const char *);
const char *mdoc_a2arch(const char *); const char *mdoc_a2arch(const char *);
const char *mdoc_a2att(const char *); const char *mdoc_a2att(const char *);
const char *mdoc_a2lib(const char *); const char *mdoc_a2lib(const char *);
enum roff_sec mdoc_a2sec(const char *); enum roff_sec mdoc_a2sec(const char *);
const char *mdoc_a2st(const char *); const char *mdoc_a2st(const char *);
void mdoc_argv(struct roff_man *, int, int, void mdoc_argv(struct roff_man *, int, enum roff_tok,
struct mdoc_arg **, int *, char *); struct mdoc_arg **, int *, char *);
enum margserr mdoc_args(struct roff_man *, int, enum margserr mdoc_args(struct roff_man *, int,
int *, char *, int, char **); int *, char *, enum roff_tok, char **);
enum mdelim mdoc_isdelim(const char *); enum mdelim mdoc_isdelim(const char *);

89
main.c
View File

@ -1,4 +1,4 @@
/* $Id: main.c,v 1.283 2017/02/17 14:31:52 schwarze Exp $ */ /* $Id: main.c,v 1.292 2017/06/03 12:17:25 schwarze Exp $ */
/* /*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2012, 2014-2017 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2010-2012, 2014-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -56,7 +56,6 @@ enum outmode {
OUTMODE_FLN, OUTMODE_FLN,
OUTMODE_LST, OUTMODE_LST,
OUTMODE_ALL, OUTMODE_ALL,
OUTMODE_INT,
OUTMODE_ONE OUTMODE_ONE
}; };
@ -67,6 +66,7 @@ enum outt {
OUTT_TREE, /* -Ttree */ OUTT_TREE, /* -Ttree */
OUTT_MAN, /* -Tman */ OUTT_MAN, /* -Tman */
OUTT_HTML, /* -Thtml */ OUTT_HTML, /* -Thtml */
OUTT_MARKDOWN, /* -Tmarkdown */
OUTT_LINT, /* -Tlint */ OUTT_LINT, /* -Tlint */
OUTT_PS, /* -Tps */ OUTT_PS, /* -Tps */
OUTT_PDF /* -Tpdf */ OUTT_PDF /* -Tpdf */
@ -92,7 +92,7 @@ static void fs_search(const struct mansearch *,
const struct manpaths *, int, char**, const struct manpaths *, int, char**,
struct manpage **, size_t *); struct manpage **, size_t *);
static int koptions(int *, char *); static int koptions(int *, char *);
static int moptions(int *, char *); static void moptions(int *, char *);
static void mmsg(enum mandocerr, enum mandoclevel, static void mmsg(enum mandocerr, enum mandoclevel,
const char *, int, int, const char *); const char *, int, int, const char *);
static void outdata_alloc(struct curparse *); static void outdata_alloc(struct curparse *);
@ -149,7 +149,7 @@ main(int argc, char *argv[])
return mandocdb(argc, argv); return mandocdb(argc, argv);
#if HAVE_PLEDGE #if HAVE_PLEDGE
if (pledge("stdio rpath tmppath tty proc exec flock", NULL) == -1) if (pledge("stdio rpath tmppath tty proc exec", NULL) == -1)
err((int)MANDOCLEVEL_SYSERR, "pledge"); err((int)MANDOCLEVEL_SYSERR, "pledge");
#endif #endif
@ -193,8 +193,12 @@ main(int argc, char *argv[])
show_usage = 0; show_usage = 0;
outmode = OUTMODE_DEF; outmode = OUTMODE_DEF;
while (-1 != (c = getopt(argc, argv, while ((c = getopt(argc, argv,
"aC:cfhI:iK:klM:m:O:S:s:T:VW:w"))) { "aC:cfhI:iK:klM:m:O:S:s:T:VW:w")) != -1) {
if (c == 'i' && search.argmode == ARG_EXPR) {
optind--;
break;
}
switch (c) { switch (c) {
case 'a': case 'a':
outmode = OUTMODE_ALL; outmode = OUTMODE_ALL;
@ -224,9 +228,6 @@ main(int argc, char *argv[])
} }
defos = mandoc_strdup(optarg + 3); defos = mandoc_strdup(optarg + 3);
break; break;
case 'i':
outmode = OUTMODE_INT;
break;
case 'K': case 'K':
if ( ! koptions(&options, optarg)) if ( ! koptions(&options, optarg))
return (int)MANDOCLEVEL_BADARG; return (int)MANDOCLEVEL_BADARG;
@ -312,7 +313,7 @@ main(int argc, char *argv[])
#if HAVE_PLEDGE #if HAVE_PLEDGE
if (!use_pager) if (!use_pager)
if (pledge("stdio rpath flock", NULL) == -1) if (pledge("stdio rpath", NULL) == -1)
err((int)MANDOCLEVEL_SYSERR, "pledge"); err((int)MANDOCLEVEL_SYSERR, "pledge");
#endif #endif
@ -441,8 +442,8 @@ main(int argc, char *argv[])
} }
#endif #endif
if (search.argmode == ARG_FILE && ! moptions(&options, auxpaths)) if (search.argmode == ARG_FILE)
return (int)MANDOCLEVEL_BADARG; moptions(&options, auxpaths);
mchars_alloc(); mchars_alloc();
curp.mp = mparse_alloc(options, curp.wlevel, mmsg, defos); curp.mp = mparse_alloc(options, curp.wlevel, mmsg, defos);
@ -591,24 +592,22 @@ usage(enum argmode argmode)
switch (argmode) { switch (argmode) {
case ARG_FILE: case ARG_FILE:
fputs("usage: mandoc [-acfhkl] [-I os=name] " fputs("usage: mandoc [-ac] [-I os=name] "
"[-K encoding] [-mformat] [-O option]\n" "[-K encoding] [-mdoc | -man] [-O options]\n"
"\t [-T output] [-W level] [file ...]\n", stderr); "\t [-T output] [-W level] [file ...]\n", stderr);
break; break;
case ARG_NAME: case ARG_NAME:
fputs("usage: man [-acfhklw] [-C file] [-I os=name] " fputs("usage: man [-acfhklw] [-C file] [-M path] "
"[-K encoding] [-M path] [-m path]\n" "[-m path] [-S subsection]\n"
"\t [-O option=value] [-S subsection] [-s section] " "\t [[-s] section] name ...\n", stderr);
"[-T output] [-W level]\n"
"\t [section] name ...\n", stderr);
break; break;
case ARG_WORD: case ARG_WORD:
fputs("usage: whatis [-acfhklw] [-C file] " fputs("usage: whatis [-afk] [-C file] "
"[-M path] [-m path] [-O outkey] [-S arch]\n" "[-M path] [-m path] [-O outkey] [-S arch]\n"
"\t [-s section] name ...\n", stderr); "\t [-s section] name ...\n", stderr);
break; break;
case ARG_EXPR: case ARG_EXPR:
fputs("usage: apropos [-acfhklw] [-C file] " fputs("usage: apropos [-afk] [-C file] "
"[-M path] [-m path] [-O outkey] [-S arch]\n" "[-M path] [-m path] [-O outkey] [-S arch]\n"
"\t [-s section] expression ...\n", stderr); "\t [-s section] expression ...\n", stderr);
break; break;
@ -766,6 +765,9 @@ parse(struct curparse *curp, int fd, const char *file)
case OUTT_PS: case OUTT_PS:
terminal_mdoc(curp->outdata, man); terminal_mdoc(curp->outdata, man);
break; break;
case OUTT_MARKDOWN:
markdown_mdoc(curp->outdata, man);
break;
default: default:
break; break;
} }
@ -915,24 +917,16 @@ koptions(int *options, char *arg)
return 1; return 1;
} }
static int static void
moptions(int *options, char *arg) moptions(int *options, char *arg)
{ {
if (arg == NULL) if (arg == NULL)
/* nothing to do */; return;
else if (0 == strcmp(arg, "doc")) if (strcmp(arg, "doc") == 0)
*options |= MPARSE_MDOC; *options |= MPARSE_MDOC;
else if (0 == strcmp(arg, "andoc")) else if (strcmp(arg, "an") == 0)
/* nothing to do */;
else if (0 == strcmp(arg, "an"))
*options |= MPARSE_MAN; *options |= MPARSE_MAN;
else {
warnx("-m %s: Bad argument", arg);
return 0;
}
return 1;
} }
static int static int
@ -943,19 +937,19 @@ toptions(struct curparse *curp, char *arg)
curp->outtype = OUTT_ASCII; curp->outtype = OUTT_ASCII;
else if (0 == strcmp(arg, "lint")) { else if (0 == strcmp(arg, "lint")) {
curp->outtype = OUTT_LINT; curp->outtype = OUTT_LINT;
curp->wlevel = MANDOCLEVEL_WARNING; curp->wlevel = MANDOCLEVEL_STYLE;
} else if (0 == strcmp(arg, "tree")) } else if (0 == strcmp(arg, "tree"))
curp->outtype = OUTT_TREE; curp->outtype = OUTT_TREE;
else if (0 == strcmp(arg, "man")) else if (0 == strcmp(arg, "man"))
curp->outtype = OUTT_MAN; curp->outtype = OUTT_MAN;
else if (0 == strcmp(arg, "html")) else if (0 == strcmp(arg, "html"))
curp->outtype = OUTT_HTML; curp->outtype = OUTT_HTML;
else if (0 == strcmp(arg, "markdown"))
curp->outtype = OUTT_MARKDOWN;
else if (0 == strcmp(arg, "utf8")) else if (0 == strcmp(arg, "utf8"))
curp->outtype = OUTT_UTF8; curp->outtype = OUTT_UTF8;
else if (0 == strcmp(arg, "locale")) else if (0 == strcmp(arg, "locale"))
curp->outtype = OUTT_LOCALE; curp->outtype = OUTT_LOCALE;
else if (0 == strcmp(arg, "xhtml"))
curp->outtype = OUTT_HTML;
else if (0 == strcmp(arg, "ps")) else if (0 == strcmp(arg, "ps"))
curp->outtype = OUTT_PS; curp->outtype = OUTT_PS;
else if (0 == strcmp(arg, "pdf")) else if (0 == strcmp(arg, "pdf"))
@ -972,15 +966,16 @@ static int
woptions(struct curparse *curp, char *arg) woptions(struct curparse *curp, char *arg)
{ {
char *v, *o; char *v, *o;
const char *toks[7]; const char *toks[8];
toks[0] = "stop"; toks[0] = "stop";
toks[1] = "all"; toks[1] = "all";
toks[2] = "warning"; toks[2] = "style";
toks[3] = "error"; toks[3] = "warning";
toks[4] = "unsupp"; toks[4] = "error";
toks[5] = "fatal"; toks[5] = "unsupp";
toks[6] = NULL; toks[6] = "fatal";
toks[7] = NULL;
while (*arg) { while (*arg) {
o = arg; o = arg;
@ -990,15 +985,18 @@ woptions(struct curparse *curp, char *arg)
break; break;
case 1: case 1:
case 2: case 2:
curp->wlevel = MANDOCLEVEL_WARNING; curp->wlevel = MANDOCLEVEL_STYLE;
break; break;
case 3: case 3:
curp->wlevel = MANDOCLEVEL_ERROR; curp->wlevel = MANDOCLEVEL_WARNING;
break; break;
case 4: case 4:
curp->wlevel = MANDOCLEVEL_UNSUPP; curp->wlevel = MANDOCLEVEL_ERROR;
break; break;
case 5: case 5:
curp->wlevel = MANDOCLEVEL_UNSUPP;
break;
case 6:
curp->wlevel = MANDOCLEVEL_BADARG; curp->wlevel = MANDOCLEVEL_BADARG;
break; break;
default: default:
@ -1006,7 +1004,6 @@ woptions(struct curparse *curp, char *arg)
return 0; return 0;
} }
} }
return 1; return 1;
} }

4
main.h
View File

@ -1,4 +1,4 @@
/* $Id: main.h,v 1.26 2016/07/15 19:33:01 schwarze Exp $ */ /* $Id: main.h,v 1.27 2017/03/03 14:23:23 schwarze Exp $ */
/* /*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -49,3 +49,5 @@ void pspdf_free(void *);
void terminal_mdoc(void *, const struct roff_man *); void terminal_mdoc(void *, const struct roff_man *);
void terminal_man(void *, const struct roff_man *); void terminal_man(void *, const struct roff_man *);
void terminal_sepline(void *); void terminal_sepline(void *);
void markdown_mdoc(void *, const struct roff_man *);

View File

@ -1,7 +1,7 @@
.\" $Id: makewhatis.8,v 1.4 2016/07/19 22:40:33 schwarze Exp $ .\" $Id: makewhatis.8,v 1.6 2017/05/17 22:27:12 schwarze Exp $
.\" .\"
.\" Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> .\" Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2011, 2012 Ingo Schwarze <schwarze@openbsd.org> .\" Copyright (c) 2011, 2012, 2014, 2017 Ingo Schwarze <schwarze@openbsd.org>
.\" .\"
.\" Permission to use, copy, modify, and distribute this software for any .\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above .\" 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 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: July 19 2016 $ .Dd $Mdocdate: May 17 2017 $
.Dt MAKEWHATIS 8 .Dt MAKEWHATIS 8
.Os .Os
.Sh NAME .Sh NAME
@ -74,6 +74,8 @@ and
.Sm on .Sm on
in that directory. in that directory.
Existing databases are replaced. Existing databases are replaced.
If a directory contains no manual pages, no database is created in that
directory.
If If
.Ar dir .Ar dir
is not provided, is not provided,
@ -130,11 +132,22 @@ Remove
.Ar .Ar
from the database in from the database in
.Ar dir . .Ar dir .
If that causes the database to become empty, also delete the database file.
.El .El
.Pp .Pp
If fatal parse errors are encountered while parsing, the offending file If fatal parse errors are encountered while parsing, the offending file
is printed to stderr, omitted from the index, and the parse continues is printed to stderr, omitted from the index, and the parse continues
with the next input file. with the next input file.
.Sh ENVIRONMENT
.Bl -tag -width MANPATH
.It Ev MANPATH
A colon-separated list of directories to create databases in.
Ignored if a
.Ar dir
argument or the
.Fl t
option is specified.
.El
.Sh FILES .Sh FILES
.Bl -tag -width Ds .Bl -tag -width Ds
.It Pa mandoc.db .It Pa mandoc.db

163
man.1
View File

@ -1,9 +1,9 @@
.\" $Id: man.1,v 1.21 2017/01/31 19:44:04 schwarze Exp $ .\" $Id: man.1,v 1.29 2017/05/17 23:23:00 schwarze Exp $
.\" .\"
.\" Copyright (c) 1989, 1990, 1993 .\" Copyright (c) 1989, 1990, 1993
.\" The Regents of the University of California. All rights reserved. .\" The Regents of the University of California. All rights reserved.
.\" Copyright (c) 2003, 2007, 2008, 2014 Jason McIntyre <jmc@openbsd.org> .\" Copyright (c) 2003, 2007, 2008, 2014 Jason McIntyre <jmc@openbsd.org>
.\" Copyright (c) 2010, 2011, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> .\" Copyright (c) 2010, 2011, 2014-2017 Ingo Schwarze <schwarze@openbsd.org>
.\" .\"
.\" Redistribution and use in source and binary forms, with or without .\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions .\" modification, are permitted provided that the following conditions
@ -31,7 +31,7 @@
.\" .\"
.\" @(#)man.1 8.2 (Berkeley) 1/2/94 .\" @(#)man.1 8.2 (Berkeley) 1/2/94
.\" .\"
.Dd $Mdocdate: January 31 2017 $ .Dd $Mdocdate: May 17 2017 $
.Dt MAN 1 .Dt MAN 1
.Os .Os
.Sh NAME .Sh NAME
@ -41,16 +41,10 @@
.Nm man .Nm man
.Op Fl acfhklw .Op Fl acfhklw
.Op Fl C Ar file .Op Fl C Ar file
.Op Fl I Cm os Ns = Ns Ar name
.Op Fl K Ar encoding
.Op Fl M Ar path .Op Fl M Ar path
.Op Fl m Ar path .Op Fl m Ar path
.Op Fl O Ar option Ns = Ns Ar value
.Op Fl S Ar subsection .Op Fl S Ar subsection
.Op Fl s Ar section .Op Oo Fl s Oc Ar section
.Op Fl T Ar output
.Op Fl W Ar level
.Op Ar section
.Ar name ... .Ar name ...
.Sh DESCRIPTION .Sh DESCRIPTION
The The
@ -91,39 +85,12 @@ It searches for
.Ar name .Ar name
in manual page names and displays the header lines from all matching pages. in manual page names and displays the header lines from all matching pages.
The search is case insensitive and matches whole words only. The search is case insensitive and matches whole words only.
This overrides any earlier
.Fl k
and
.Fl l
options.
.It Fl h .It Fl h
Display only the SYNOPSIS lines of the requested manual pages. Display only the SYNOPSIS lines of the requested manual pages.
Implies Implies
.Fl a .Fl a
and and
.Fl c . .Fl c .
.It Fl I Cm os Ns = Ns Ar name
Override the default operating system
.Ar name
for the
.Xr mdoc 7
.Ic \&Os
and for the
.Xr man 7
.Ic \&TH
macro.
.It Fl K Ar encoding
Specify the input encoding.
The supported
.Ar encoding
arguments are
.Cm us-ascii ,
.Cm iso-8859-1 ,
and
.Cm utf-8 .
By default, the encoding is automatically detected as described in the
.Xr mandoc 1
manual.
.It Fl k .It Fl k
A synonym for A synonym for
.Xr apropos 1 . .Xr apropos 1 .
@ -133,11 +100,6 @@ an expression can be provided using the syntax described in the
.Xr apropos 1 .Xr apropos 1
manual. manual.
By default, it displays the header lines of all matching pages. By default, it displays the header lines of all matching pages.
This overrides any earlier
.Fl f
and
.Fl l
options.
.It Fl l .It Fl l
A synonym for A synonym for
.Xr mandoc 1 .Xr mandoc 1
@ -149,15 +111,10 @@ No search is done and
.Ar file , .Ar file ,
.Ar path , .Ar path ,
.Ar section , .Ar section ,
and .Ar subsection ,
.Ar subsection
are ignored.
This overrides any earlier
.Fl f ,
.Fl k ,
and and
.Fl w .Fl w
options. are ignored.
.It Fl M Ar path .It Fl M Ar path
Override the list of standard directories which Override the list of standard directories which
.Nm .Nm
@ -184,15 +141,8 @@ the directories specified using the
option or the option or the
.Ev MANPATH .Ev MANPATH
environment variable. environment variable.
.It Fl O Ar option Ns = Ns Ar value
Comma-separated output options.
For each output format, the available options are described in the
.Xr mandoc 1
manual.
.It Fl S Ar subsection .It Fl S Ar subsection
Restricts the directories that Only show pages for the specified
.Nm
will search to those of a specific
.Xr machine 1 .Xr machine 1
architecture. architecture.
.Ar subsection .Ar subsection
@ -234,53 +184,23 @@ System maintenance and operation commands.
.It 9 .It 9
Kernel internals. Kernel internals.
.El .El
.It Fl T Ar output .Pp
Select the output format. If not specified and a match is found in more than one section,
The default is the first match is selected from the following list:
.Cm locale . 1, 8, 6, 2, 3, 5, 7, 4, 9, 3p.
The other output modes
.Cm ascii ,
.Cm html ,
.Cm lint ,
.Cm man ,
.Cm pdf ,
.Cm ps ,
.Cm tree ,
and
.Cm utf8
are described in the
.Xr mandoc 1
manual.
.It Fl W Ar level
Specify the minimum message
.Ar level
to be reported on the standard error output and to affect the exit status.
The
.Ar level
can be
.Cm warning ,
.Cm error ,
or
.Cm unsupp ;
.Cm all
is an alias for
.Cm warning .
By default,
.Nm
is silent.
See the
.Xr mandoc 1
manual for details.
.It Fl w .It Fl w
List the pathnames of the manual pages which List the pathnames of all matching manual pages instead of displaying
.Nm any of them.
would display for the specified
.Ar section
and
.Ar name
combination.
.El .El
.Pp .Pp
The options
.Fl IKOTW
are also supported and are documented in
.Xr mandoc 1 .
The options
.Fl fkl
are mutually exclusive and override each other.
.Pp
Guidelines for writing Guidelines for writing
man pages can be found in man pages can be found in
.Xr mdoc 7 . .Xr mdoc 7 .
@ -290,13 +210,7 @@ for example
.Pa cat1/foo.0 .Pa cat1/foo.0
and and
.Pa man1/foo.1 , .Pa man1/foo.1 ,
exist in the same directory, and at least one of them is selected, exist in the same directory, only the unformatted version is used.
only the newer one is used.
However, if both the
.Fl a
and the
.Fl w
options are specified, both file names are printed.
.Sh ENVIRONMENT .Sh ENVIRONMENT
.Bl -tag -width MANPATHX .Bl -tag -width MANPATHX
.It Ev MACHINE .It Ev MACHINE
@ -318,7 +232,7 @@ is case insensitive.
.It Ev MANPAGER .It Ev MANPAGER
Any non-empty value of the environment variable Any non-empty value of the environment variable
.Ev MANPAGER .Ev MANPAGER
will be used instead of the standard pagination program, is used instead of the standard pagination program,
.Xr more 1 . .Xr more 1 .
If If
.Xr less 1 .Xr less 1
@ -342,13 +256,27 @@ information about the term last searched for with
.It Ev MANPATH .It Ev MANPATH
The standard search path used by The standard search path used by
.Nm .Nm
may be overridden by specifying a path in the may be changed by specifying a path in the
.Ev MANPATH .Ev MANPATH
environment environment variable.
variable.
The format of the path is a colon The format of the path is a colon
.Pq Ql \&: .Pq Ql \&:
separated list of directories. separated list of directories.
Invalid paths are ignored.
Overridden by
.Fl M ,
ignored if
.Fl l
is specified.
.Pp
If
.Ev MANPATH
begins with a colon, it is appended to the default list;
if it ends with a colon, it is prepended to the default list;
or if it contains two adjacent colons,
the standard search path is inserted between the colons.
If none of these conditions are met, it overrides the
standard search path.
.It Ev PAGER .It Ev PAGER
Specifies the pagination program to use when Specifies the pagination program to use when
.Ev MANPAGER .Ev MANPAGER
@ -356,7 +284,12 @@ is not defined.
If neither PAGER nor MANPAGER is defined, If neither PAGER nor MANPAGER is defined,
.Xr more 1 .Xr more 1
.Fl s .Fl s
will be used. is used.
Only used if
.Fl a
or
.Fl l
is specified.
.El .El
.Sh FILES .Sh FILES
.Bl -tag -width /etc/man.conf -compact .Bl -tag -width /etc/man.conf -compact
@ -365,10 +298,12 @@ default man configuration file
.El .El
.Sh EXIT STATUS .Sh EXIT STATUS
.Ex -std man .Ex -std man
See
.Xr mandoc 1
for details.
.Sh SEE ALSO .Sh SEE ALSO
.Xr apropos 1 , .Xr apropos 1 ,
.Xr intro 1 , .Xr intro 1 ,
.Xr whatis 1 ,
.Xr whereis 1 , .Xr whereis 1 ,
.Xr intro 2 , .Xr intro 2 ,
.Xr intro 3 , .Xr intro 3 ,

45
man.7
View File

@ -1,4 +1,4 @@
.\" $Id: man.7,v 1.132 2015/01/29 00:33:57 schwarze Exp $ .\" $Id: man.7,v 1.135 2017/05/07 21:44:49 schwarze Exp $
.\" .\"
.\" Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> .\" Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2011-2015 Ingo Schwarze <schwarze@openbsd.org> .\" Copyright (c) 2011-2015 Ingo Schwarze <schwarze@openbsd.org>
@ -16,7 +16,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: January 29 2015 $ .Dd $Mdocdate: May 7 2017 $
.Dt MAN 7 .Dt MAN 7
.Os .Os
.Sh NAME .Sh NAME
@ -266,8 +266,6 @@ in the alphabetical reference below.
.It Sx TP Ta tagged paragraph: Op Ar width .It Sx TP Ta tagged paragraph: Op Ar width
.It Sx HP Ta hanged paragraph: Op Ar width .It Sx HP Ta hanged paragraph: Op Ar width
.It Sx PD Ta set vertical paragraph distance: Op Ar height .It Sx PD Ta set vertical paragraph distance: Op Ar height
.It Sx \&br Ta force output line break in text mode (no arguments)
.It Sx \&sp Ta force vertical space: Op Ar height
.It Sx fi , nf Ta fill mode and no-fill mode (no arguments) .It Sx fi , nf Ta fill mode and no-fill mode (no arguments)
.It Sx in Ta additional indent: Op Ar width .It Sx in Ta additional indent: Op Ar width
.El .El
@ -350,8 +348,12 @@ See also
and and
.Sx \&IR . .Sx \&IR .
.Ss \&DT .Ss \&DT
Has no effect. Restore the default tabulator positions.
Included for compatibility. They are at intervals of 0.5 inches.
This has no effect unless the tabulator positions were changed with the
.Xr roff 7
.Ic \&ta
request.
.Ss \&EE .Ss \&EE
This is a non-standard GNU extension, included only for compatibility. This is a non-standard GNU extension, included only for compatibility.
In In
@ -708,12 +710,6 @@ It has the following syntax:
link description to be shown link description to be shown
.Pf \. Sx UE .Pf \. Sx UE
.Ed .Ed
.Ss \&br
Breaks the current line.
Consecutive invocations have no further effect.
.Pp
See also
.Sx \&sp .
.Ss \&fi .Ss \&fi
End literal mode begun by End literal mode begun by
.Sx \&nf . .Sx \&nf .
@ -736,24 +732,6 @@ Literal mode is implicitly ended by
.Sx \&SH .Sx \&SH
or or
.Sx \&SS . .Sx \&SS .
.Ss \&sp
Insert vertical spaces into output with the following syntax:
.Bd -filled -offset indent
.Pf \. Sx \&sp
.Op Ar height
.Ed
.Pp
The
.Ar height
argument is a scaling width as described in
.Xr roff 7 .
If 0, this is equivalent to the
.Sx \&br
macro.
Defaults to 1, if unspecified.
.Pp
See also
.Sx \&br .
.Sh MACRO SYNTAX .Sh MACRO SYNTAX
The The
.Nm .Nm
@ -777,10 +755,7 @@ is equivalent to
.Sq \&.I foo . .Sq \&.I foo .
If next-line macros are invoked consecutively, only the last is used. If next-line macros are invoked consecutively, only the last is used.
If a next-line macro is followed by a non-next-line macro, an error is If a next-line macro is followed by a non-next-line macro, an error is
raised, except for raised.
.Sx \&br
and
.Sx \&sp .
.Pp .Pp
The syntax is as follows: The syntax is as follows:
.Bd -literal -offset indent .Bd -literal -offset indent
@ -808,11 +783,9 @@ The syntax is as follows:
.It Sx \&SM Ta n Ta next-line Ta \& .It Sx \&SM Ta n Ta next-line Ta \&
.It Sx \&TH Ta >1, <6 Ta current Ta \& .It Sx \&TH Ta >1, <6 Ta current Ta \&
.It Sx \&UC Ta <=1 Ta current Ta \& .It Sx \&UC Ta <=1 Ta current Ta \&
.It Sx \&br Ta 0 Ta current Ta compat
.It Sx \&fi Ta 0 Ta current Ta compat .It Sx \&fi Ta 0 Ta current Ta compat
.It Sx \&in Ta 1 Ta current Ta compat .It Sx \&in Ta 1 Ta current Ta compat
.It Sx \&nf Ta 0 Ta current Ta compat .It Sx \&nf Ta 0 Ta current Ta compat
.It Sx \&sp Ta 1 Ta current Ta compat
.El .El
.Pp .Pp
Macros marked as Macros marked as

84
man.c
View File

@ -1,7 +1,7 @@
/* $Id: man.c,v 1.167 2017/01/10 13:47:00 schwarze Exp $ */ /* $Id: man.c,v 1.174 2017/06/03 15:55:24 schwarze Exp $ */
/* /*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011 Joerg Sonnenberger <joerg@netbsd.org> * Copyright (c) 2011 Joerg Sonnenberger <joerg@netbsd.org>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
@ -35,21 +35,6 @@
#include "roff_int.h" #include "roff_int.h"
#include "libman.h" #include "libman.h"
const char *const __man_macronames[MAN_MAX] = {
"br", "TH", "SH", "SS",
"TP", "LP", "PP", "P",
"IP", "HP", "SM", "SB",
"BI", "IB", "BR", "RB",
"R", "B", "I", "IR",
"RI", "sp", "nf",
"fi", "RE", "RS", "DT",
"UC", "PD", "AT", "in",
"ft", "OP", "EX", "EE",
"UR", "UE", "ll"
};
const char * const *man_macronames = __man_macronames;
static void man_descope(struct roff_man *, int, int); static void man_descope(struct roff_man *, int, int);
static int man_ptext(struct roff_man *, int, char *, int); static int man_ptext(struct roff_man *, int, char *, int);
static int man_pmacro(struct roff_man *, int, char *, int); static int man_pmacro(struct roff_man *, int, char *, int);
@ -104,15 +89,17 @@ man_ptext(struct roff_man *man, int line, char *buf, int offs)
/* Skip leading whitespace. */ ; /* Skip leading whitespace. */ ;
/* /*
* Blank lines are ignored right after headings * Blank lines are ignored in next line scope and right
* but add a single vertical space elsewhere. * after headings but add a single vertical space elsewhere.
*/ */
if (buf[i] == '\0') { if (buf[i] == '\0') {
/* Allocate a blank entry. */ if (man->flags & (MAN_ELINE | MAN_BLINE))
if (man->last->tok != MAN_SH && mandoc_msg(MANDOCERR_BLK_BLANK, man->parse,
line, 0, NULL);
else if (man->last->tok != MAN_SH &&
man->last->tok != MAN_SS) { man->last->tok != MAN_SS) {
roff_elem_alloc(man, line, offs, MAN_sp); roff_elem_alloc(man, line, offs, ROFF_sp);
man->next = ROFF_NEXT_SIBLING; man->next = ROFF_NEXT_SIBLING;
} }
return 1; return 1;
@ -160,26 +147,19 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
{ {
struct roff_node *n; struct roff_node *n;
const char *cp; const char *cp;
int tok; size_t sz;
int i, ppos; enum roff_tok tok;
int ppos;
int bline; int bline;
char mac[5];
/* Determine the line macro. */
ppos = offs; ppos = offs;
tok = TOKEN_NONE;
/* for (sz = 0; sz < 4 && strchr(" \t\\", buf[offs]) == NULL; sz++)
* Copy the first word into a nil-terminated buffer. offs++;
* Stop when a space, tab, escape, or eoln is encountered. if (sz > 0 && sz < 4)
*/ tok = roffhash_find(man->manmac, buf + ppos, sz);
i = 0;
while (i < 4 && strchr(" \t\\", buf[offs]) == NULL)
mac[i++] = buf[offs++];
mac[i] = '\0';
tok = (i > 0 && i < 4) ? man_hash_find(mac) : TOKEN_NONE;
if (tok == TOKEN_NONE) { if (tok == TOKEN_NONE) {
mandoc_msg(MANDOCERR_MACRO, man->parse, mandoc_msg(MANDOCERR_MACRO, man->parse,
ln, ppos, buf + ppos - 1); ln, ppos, buf + ppos - 1);
@ -203,7 +183,7 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
/* Jump to the next non-whitespace word. */ /* Jump to the next non-whitespace word. */
while (buf[offs] && buf[offs] == ' ') while (buf[offs] == ' ')
offs++; offs++;
/* /*
@ -223,6 +203,20 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
man_breakscope(man, tok); man_breakscope(man, tok);
bline = man->flags & MAN_BLINE; bline = man->flags & MAN_BLINE;
/*
* If the line in next-line scope ends with \c, keep the
* next-line scope open for the subsequent input line.
* That is not at all portable, only groff >= 1.22.4
* does it, but *if* this weird idiom occurs in a manual
* 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;
}
/* Call to handler... */ /* Call to handler... */
assert(man_macros[tok].fp); assert(man_macros[tok].fp);
@ -266,7 +260,7 @@ man_breakscope(struct roff_man *man, int tok)
* Delete the element that is being broken. * Delete the element that is being broken.
*/ */
if (man->flags & MAN_ELINE && (tok == TOKEN_NONE || if (man->flags & MAN_ELINE && (tok < MAN_TH ||
! (man_macros[tok].flags & MAN_NSCOPED))) { ! (man_macros[tok].flags & MAN_NSCOPED))) {
n = man->last; n = man->last;
assert(n->type != ROFFT_TEXT); assert(n->type != ROFFT_TEXT);
@ -275,8 +269,7 @@ man_breakscope(struct roff_man *man, int tok)
mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse, mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
n->line, n->pos, "%s breaks %s", n->line, n->pos, "%s breaks %s",
tok == TOKEN_NONE ? "TS" : man_macronames[tok], roff_name[tok], roff_name[n->tok]);
man_macronames[n->tok]);
roff_node_delete(man, n); roff_node_delete(man, n);
man->flags &= ~MAN_ELINE; man->flags &= ~MAN_ELINE;
@ -302,7 +295,7 @@ man_breakscope(struct roff_man *man, int tok)
* Delete the block that is being broken. * Delete the block that is being broken.
*/ */
if (man->flags & MAN_BLINE && (tok == TOKEN_NONE || if (man->flags & MAN_BLINE && (tok < MAN_TH ||
man_macros[tok].flags & MAN_BSCOPE)) { man_macros[tok].flags & MAN_BSCOPE)) {
n = man->last; n = man->last;
if (n->type == ROFFT_TEXT) if (n->type == ROFFT_TEXT)
@ -317,8 +310,7 @@ man_breakscope(struct roff_man *man, int tok)
mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse, mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
n->line, n->pos, "%s breaks %s", n->line, n->pos, "%s breaks %s",
tok == TOKEN_NONE ? "TS" : man_macronames[tok], roff_name[tok], roff_name[n->tok]);
man_macronames[n->tok]);
roff_node_delete(man, n); roff_node_delete(man, n);
man->flags &= ~MAN_BLINE; man->flags &= ~MAN_BLINE;

View File

@ -1,6 +1,6 @@
.\" $Id: man.cgi.3,v 1.2 2016/07/07 19:19:01 schwarze Exp $ .\" $Id: man.cgi.3,v 1.4 2017/03/15 13:18:53 schwarze Exp $
.\" .\"
.\" Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org> .\" Copyright (c) 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
.\" .\"
.\" Permission to use, copy, modify, and distribute this software for any .\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above .\" 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 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: July 7 2016 $ .Dd $Mdocdate: March 15 2017 $
.Dt MAN.CGI 3 .Dt MAN.CGI 3
.Os .Os
.Sh NAME .Sh NAME
@ -126,12 +126,30 @@ contains a search query in short format or when
is empty and a is empty and a
.Ev QUERY_STRING .Ev QUERY_STRING
is provided. is provided.
It changes into the manpath and calls If possible, requests using
.Ev QUERY_STRING
are redirected to URIs using
.Ev PATH_INFO
by calling
.Fn pg_redirect .
Otherwise, it changes into the manpath and calls
.Xr mansearch 3 . .Xr mansearch 3 .
Depending on the result, it calls either Depending on the result, it calls either
.Fn pg_noresult .Fn pg_noresult
or or
.Fn pg_searchres . .Fn pg_searchres .
.It Ft void Fn pg_redirect "const struct req *req" "const char *name"
This function is special in so far as it does not print an HTML page,
but only an HTTP 303 response with a Location: of the form:
.Sm off
.No http://
.Ar host Ns /
.Op Ar scriptname Ns /
.Op Ar manpath Ns /
.Op Ar arch Ns /
.Fa name
.Op Pf . Ar sec
.Sm on
.It Ft void Fn pg_noresult "const struct req *req" "const char *msg" .It Ft void Fn pg_noresult "const struct req *req" "const char *msg"
This function calls This function calls
.Fn resp_begin_html , .Fn resp_begin_html ,
@ -219,13 +237,18 @@ and
are used. are used.
The highest level result generators are: The highest level result generators are:
.Bl -tag -width 1n .Bl -tag -width 1n
.It Ft void Fn resp_begin_html "int code" "const char *msg" .It Ft void Fn resp_begin_html "int code" "const char *msg" "const char *file"
This generator calls This generator calls
.Fn resp_begin_http .Fn resp_begin_http
to print the HTTP headers, then prints the HTML header up to the to print the HTTP headers, then prints the HTML header up to the
opening tag of the <body> element, then copies the file opening tag of the <body> element, then copies the file
.Pa header.html .Pa header.html
to the output, if it exists and is readable. to the output, if it exists and is readable.
If
.Fa file
is not
.Dv NULL ,
it is used for the <title> element.
.It Ft void Fn resp_searchform "const struct req *req" "enum focus focus" .It Ft void Fn resp_searchform "const struct req *req" "enum focus focus"
This generator prints a search form, filling it with data This generator prints a search form, filling it with data
from the provided request object. from the provided request object.

View File

@ -1,4 +1,4 @@
.\" $Id: man.cgi.8,v 1.20 2016/07/11 22:48:37 schwarze Exp $ .\" $Id: man.cgi.8,v 1.22 2017/03/18 16:48:24 schwarze Exp $
.\" .\"
.\" Copyright (c) 2014, 2015, 2016 Ingo Schwarze <schwarze@openbsd.org> .\" Copyright (c) 2014, 2015, 2016 Ingo Schwarze <schwarze@openbsd.org>
.\" .\"
@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: July 11 2016 $ .Dd $Mdocdate: March 18 2017 $
.Dt MAN.CGI 8 .Dt MAN.CGI 8
.Os .Os
.Sh NAME .Sh NAME
@ -186,11 +186,6 @@ Otherwise, a leading slash is needed.
This is used in generated HTML code. This is used in generated HTML code.
.It Dv CUSTOMIZE_TITLE .It Dv CUSTOMIZE_TITLE
An ASCII string to be used for the HTML <TITLE> element. An ASCII string to be used for the HTML <TITLE> element.
.It Dv HTTP_HOST
The FQDN of the (possibly virtual) host the HTTP server is running on.
This is used for
.Ic Location:
headers in HTTP 303 responses.
.It Dv MAN_DIR .It Dv MAN_DIR
A file system path to the A file system path to the
.Nm .Nm
@ -411,15 +406,16 @@ A version of
based on based on
.Xr mandoc 1 .Xr mandoc 1
first appeared in mdocml-1.12.1 (March 2012). first appeared in mdocml-1.12.1 (March 2012).
The current SQLite3-based version first appeared in The current
.Ox 5.6 . .Xr mandoc.db 5
database format first appeared in
.Ox 6.1 .
.Sh AUTHORS .Sh AUTHORS
.An -nosplit .An -nosplit
The The
.Nm .Nm
program was written by program was written by
.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
and ported to the SQLite3-based and is maintained by
.Xr mandoc.db 5 .An Ingo Schwarze Aq Mt schwarze@openbsd.org ,
backend by who also designed and implemented the database format.
.An Ingo Schwarze Aq Mt schwarze@openbsd.org .

46
man.h
View File

@ -1,4 +1,4 @@
/* $Id: man.h,v 1.77 2015/11/07 14:01:16 schwarze Exp $ */ /* $Id: man.h,v 1.78 2017/04/24 23:06:18 schwarze Exp $ */
/* /*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -16,50 +16,6 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#define MAN_br 0
#define MAN_TH 1
#define MAN_SH 2
#define MAN_SS 3
#define MAN_TP 4
#define MAN_LP 5
#define MAN_PP 6
#define MAN_P 7
#define MAN_IP 8
#define MAN_HP 9
#define MAN_SM 10
#define MAN_SB 11
#define MAN_BI 12
#define MAN_IB 13
#define MAN_BR 14
#define MAN_RB 15
#define MAN_R 16
#define MAN_B 17
#define MAN_I 18
#define MAN_IR 19
#define MAN_RI 20
#define MAN_sp 21
#define MAN_nf 22
#define MAN_fi 23
#define MAN_RE 24
#define MAN_RS 25
#define MAN_DT 26
#define MAN_UC 27
#define MAN_PD 28
#define MAN_AT 29
#define MAN_in 30
#define MAN_ft 31
#define MAN_OP 32
#define MAN_EX 33
#define MAN_EE 34
#define MAN_UR 35
#define MAN_UE 36
#define MAN_ll 37
#define MAN_MAX 38
/* Names of macros. */
extern const char *const *man_macronames;
struct roff_man; struct roff_man;
const struct mparse *man_mparse(const struct roff_man *); const struct mparse *man_mparse(const struct roff_man *);

View File

@ -1,103 +0,0 @@
/* $Id: man_hash.c,v 1.35 2016/07/15 18:03:45 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2015 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 <sys/types.h>
#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <string.h>
#include "mandoc.h"
#include "roff.h"
#include "man.h"
#include "libmandoc.h"
#include "libman.h"
#define HASH_DEPTH 6
#define HASH_ROW(x) do { \
if (isupper((unsigned char)(x))) \
(x) -= 65; \
else \
(x) -= 97; \
(x) *= HASH_DEPTH; \
} while (/* CONSTCOND */ 0)
/*
* Lookup table is indexed first by lower-case first letter (plus one
* for the period, which is stored in the last row), then by lower or
* uppercase second letter. Buckets correspond to the index of the
* macro (the integer value of the enum stored as a char to save a bit
* of space).
*/
static unsigned char table[26 * HASH_DEPTH];
void
man_hash_init(void)
{
int i, j, x;
if (*table != '\0')
return;
memset(table, UCHAR_MAX, sizeof(table));
for (i = 0; i < (int)MAN_MAX; i++) {
x = man_macronames[i][0];
assert(isalpha((unsigned char)x));
HASH_ROW(x);
for (j = 0; j < HASH_DEPTH; j++)
if (UCHAR_MAX == table[x + j]) {
table[x + j] = (unsigned char)i;
break;
}
assert(j < HASH_DEPTH);
}
}
int
man_hash_find(const char *tmp)
{
int x, y, i;
int tok;
if ('\0' == (x = tmp[0]))
return TOKEN_NONE;
if ( ! (isalpha((unsigned char)x)))
return TOKEN_NONE;
HASH_ROW(x);
for (i = 0; i < HASH_DEPTH; i++) {
if (UCHAR_MAX == (y = table[x + i]))
return TOKEN_NONE;
tok = y;
if (0 == strcmp(tmp, man_macronames[tok]))
return tok;
}
return TOKEN_NONE;
}

View File

@ -1,4 +1,4 @@
/* $Id: man_html.c,v 1.133 2017/02/05 18:15:39 schwarze Exp $ */ /* $Id: man_html.c,v 1.143 2017/06/08 12:54:58 schwarze Exp $ */
/* /*
* Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -65,14 +65,12 @@ static int man_SM_pre(MAN_ARGS);
static int man_SS_pre(MAN_ARGS); static int man_SS_pre(MAN_ARGS);
static int man_UR_pre(MAN_ARGS); static int man_UR_pre(MAN_ARGS);
static int man_alt_pre(MAN_ARGS); static int man_alt_pre(MAN_ARGS);
static int man_br_pre(MAN_ARGS);
static int man_ign_pre(MAN_ARGS); static int man_ign_pre(MAN_ARGS);
static int man_in_pre(MAN_ARGS); static int man_in_pre(MAN_ARGS);
static void man_root_post(MAN_ARGS); static void man_root_post(MAN_ARGS);
static void man_root_pre(MAN_ARGS); static void man_root_pre(MAN_ARGS);
static const struct htmlman mans[MAN_MAX] = { static const struct htmlman __mans[MAN_MAX - MAN_TH] = {
{ man_br_pre, NULL }, /* br */
{ NULL, NULL }, /* TH */ { NULL, NULL }, /* TH */
{ man_SH_pre, NULL }, /* SH */ { man_SH_pre, NULL }, /* SH */
{ man_SS_pre, NULL }, /* SS */ { man_SS_pre, NULL }, /* SS */
@ -93,7 +91,6 @@ static const struct htmlman mans[MAN_MAX] = {
{ man_I_pre, NULL }, /* I */ { man_I_pre, NULL }, /* I */
{ man_alt_pre, NULL }, /* IR */ { man_alt_pre, NULL }, /* IR */
{ man_alt_pre, NULL }, /* RI */ { man_alt_pre, NULL }, /* RI */
{ man_br_pre, NULL }, /* sp */
{ NULL, NULL }, /* nf */ { NULL, NULL }, /* nf */
{ NULL, NULL }, /* fi */ { NULL, NULL }, /* fi */
{ NULL, NULL }, /* RE */ { NULL, NULL }, /* RE */
@ -103,14 +100,13 @@ static const struct htmlman mans[MAN_MAX] = {
{ man_ign_pre, NULL }, /* PD */ { man_ign_pre, NULL }, /* PD */
{ man_ign_pre, NULL }, /* AT */ { man_ign_pre, NULL }, /* AT */
{ man_in_pre, NULL }, /* in */ { man_in_pre, NULL }, /* in */
{ man_ign_pre, NULL }, /* ft */
{ man_OP_pre, NULL }, /* OP */ { man_OP_pre, NULL }, /* OP */
{ NULL, NULL }, /* EX */ { NULL, NULL }, /* EX */
{ NULL, NULL }, /* EE */ { NULL, NULL }, /* EE */
{ man_UR_pre, NULL }, /* UR */ { man_UR_pre, NULL }, /* UR */
{ NULL, NULL }, /* UE */ { NULL, NULL }, /* UE */
{ man_ign_pre, NULL }, /* ll */
}; };
static const struct htmlman *const mans = __mans - MAN_TH;
/* /*
@ -255,7 +251,8 @@ print_man_node(MAN_ARGS)
case ROFFT_TEXT: case ROFFT_TEXT:
if (fillmode(h, want_fillmode) == MAN_fi && if (fillmode(h, want_fillmode) == MAN_fi &&
want_fillmode == MAN_fi && want_fillmode == MAN_fi &&
n->flags & NODE_LINE && *n->string == ' ') n->flags & NODE_LINE && *n->string == ' ' &&
(h->flags & HTML_NONEWLINE) == 0)
print_otag(h, TAG_BR, ""); print_otag(h, TAG_BR, "");
if (*n->string != '\0') if (*n->string != '\0')
break; break;
@ -304,6 +301,13 @@ print_man_node(MAN_ARGS)
print_tblclose(h); print_tblclose(h);
t = h->tag; t = h->tag;
if (n->tok < ROFF_MAX) {
roff_html_pre(h, n);
child = 0;
break;
}
assert(n->tok >= MAN_TH && n->tok < MAN_MAX);
if (mans[n->tok].pre) if (mans[n->tok].pre)
child = (*mans[n->tok].pre)(man, n, h); child = (*mans[n->tok].pre)(man, n, h);
@ -354,13 +358,9 @@ fillmode(struct html *h, int want)
static int static int
a2width(const struct roff_node *n, struct roffsu *su) a2width(const struct roff_node *n, struct roffsu *su)
{ {
if (n->type != ROFFT_TEXT) if (n->type != ROFFT_TEXT)
return 0; return 0;
if (a2roffsu(n->string, su, SCALE_EN)) return a2roffsu(n->string, su, SCALE_EN) != NULL;
return 1;
return 0;
} }
static void static void
@ -409,34 +409,18 @@ man_root_post(MAN_ARGS)
print_tagq(h, t); print_tagq(h, t);
} }
static int
man_br_pre(MAN_ARGS)
{
struct roffsu su;
SCALE_VS_INIT(&su, 1);
if (MAN_sp == n->tok) {
if (NULL != (n = n->child))
if ( ! a2roffsu(n->string, &su, SCALE_VS))
su.scale = 1.0;
} else
su.scale = 0.0;
print_otag(h, TAG_DIV, "suh", &su);
/* So the div isn't empty: */
print_text(h, "\\~");
return 0;
}
static int static int
man_SH_pre(MAN_ARGS) man_SH_pre(MAN_ARGS)
{ {
if (n->type == ROFFT_HEAD) char *id;
print_otag(h, TAG_H1, "c", "Sh");
if (n->type == ROFFT_HEAD) {
id = html_make_id(n);
print_otag(h, TAG_H1, "cTi", "Sh", id);
if (id != NULL)
print_otag(h, TAG_A, "chR", "selflink", id);
free(id);
}
return 1; return 1;
} }
@ -498,8 +482,15 @@ man_SM_pre(MAN_ARGS)
static int static int
man_SS_pre(MAN_ARGS) man_SS_pre(MAN_ARGS)
{ {
if (n->type == ROFFT_HEAD) char *id;
print_otag(h, TAG_H2, "c", "Ss");
if (n->type == ROFFT_HEAD) {
id = html_make_id(n);
print_otag(h, TAG_H2, "cTi", "Ss", id);
if (id != NULL)
print_otag(h, TAG_A, "chR", "selflink", id);
free(id);
}
return 1; return 1;
} }
@ -656,7 +647,7 @@ man_UR_pre(MAN_ARGS)
assert(n->type == ROFFT_HEAD); assert(n->type == ROFFT_HEAD);
if (n->child != NULL) { if (n->child != NULL) {
assert(n->child->type == ROFFT_TEXT); assert(n->child->type == ROFFT_TEXT);
print_otag(h, TAG_A, "ch", "Lk", n->child->string); print_otag(h, TAG_A, "cTh", "Lk", n->child->string);
} }
assert(n->next->type == ROFFT_BODY); assert(n->next->type == ROFFT_BODY);

View File

@ -1,7 +1,7 @@
/* $Id: man_macro.c,v 1.115 2017/01/10 13:47:00 schwarze Exp $ */ /* $Id: man_macro.c,v 1.120 2017/05/05 15:17:32 schwarze Exp $ */
/* /*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2012, 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2012-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de> * Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
@ -38,10 +38,9 @@ static void blk_imp(MACRO_PROT_ARGS);
static void in_line_eoln(MACRO_PROT_ARGS); static void in_line_eoln(MACRO_PROT_ARGS);
static int man_args(struct roff_man *, int, static int man_args(struct roff_man *, int,
int *, char *, char **); int *, char *, char **);
static void rew_scope(struct roff_man *, int); static void rew_scope(struct roff_man *, enum roff_tok);
const struct man_macro __man_macros[MAN_MAX] = { const struct man_macro __man_macros[MAN_MAX - MAN_TH] = {
{ in_line_eoln, MAN_NSCOPED }, /* br */
{ in_line_eoln, MAN_BSCOPE }, /* TH */ { in_line_eoln, MAN_BSCOPE }, /* TH */
{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SH */ { blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SH */
{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SS */ { blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SS */
@ -62,7 +61,6 @@ const struct man_macro __man_macros[MAN_MAX] = {
{ in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* I */ { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* I */
{ in_line_eoln, 0 }, /* IR */ { in_line_eoln, 0 }, /* IR */
{ in_line_eoln, 0 }, /* RI */ { in_line_eoln, 0 }, /* RI */
{ in_line_eoln, MAN_NSCOPED }, /* sp */
{ in_line_eoln, MAN_NSCOPED }, /* nf */ { in_line_eoln, MAN_NSCOPED }, /* nf */
{ in_line_eoln, MAN_NSCOPED }, /* fi */ { in_line_eoln, MAN_NSCOPED }, /* fi */
{ blk_close, MAN_BSCOPE }, /* RE */ { blk_close, MAN_BSCOPE }, /* RE */
@ -72,16 +70,13 @@ const struct man_macro __man_macros[MAN_MAX] = {
{ in_line_eoln, MAN_NSCOPED }, /* PD */ { in_line_eoln, MAN_NSCOPED }, /* PD */
{ in_line_eoln, 0 }, /* AT */ { in_line_eoln, 0 }, /* AT */
{ in_line_eoln, 0 }, /* in */ { in_line_eoln, 0 }, /* in */
{ in_line_eoln, 0 }, /* ft */
{ in_line_eoln, 0 }, /* OP */ { in_line_eoln, 0 }, /* OP */
{ in_line_eoln, MAN_BSCOPE }, /* EX */ { in_line_eoln, MAN_BSCOPE }, /* EX */
{ in_line_eoln, MAN_BSCOPE }, /* EE */ { in_line_eoln, MAN_BSCOPE }, /* EE */
{ blk_exp, MAN_BSCOPE }, /* UR */ { blk_exp, MAN_BSCOPE }, /* UR */
{ blk_close, MAN_BSCOPE }, /* UE */ { blk_close, MAN_BSCOPE }, /* UE */
{ in_line_eoln, 0 }, /* ll */
}; };
const struct man_macro *const man_macros = __man_macros - MAN_TH;
const struct man_macro * const man_macros = __man_macros;
void void
@ -100,8 +95,7 @@ man_unscope(struct roff_man *man, const struct roff_node *to)
man_macros[n->tok].flags & MAN_SCOPED) { man_macros[n->tok].flags & MAN_SCOPED) {
mandoc_vmsg(MANDOCERR_BLK_LINE, mandoc_vmsg(MANDOCERR_BLK_LINE,
man->parse, n->line, n->pos, man->parse, n->line, n->pos,
"EOF breaks %s", "EOF breaks %s", roff_name[n->tok]);
man_macronames[n->tok]);
if (man->flags & MAN_ELINE) if (man->flags & MAN_ELINE)
man->flags &= ~MAN_ELINE; man->flags &= ~MAN_ELINE;
else { else {
@ -118,7 +112,7 @@ man_unscope(struct roff_man *man, const struct roff_node *to)
man_macros[n->tok].fp == blk_exp) man_macros[n->tok].fp == blk_exp)
mandoc_msg(MANDOCERR_BLK_NOEND, mandoc_msg(MANDOCERR_BLK_NOEND,
man->parse, n->line, n->pos, man->parse, n->line, n->pos,
man_macronames[n->tok]); roff_name[n->tok]);
} }
/* /*
@ -150,7 +144,7 @@ man_unscope(struct roff_man *man, const struct roff_node *to)
* scopes. When a scope is closed, it must be validated and actioned. * scopes. When a scope is closed, it must be validated and actioned.
*/ */
static void static void
rew_scope(struct roff_man *man, int tok) rew_scope(struct roff_man *man, enum roff_tok tok)
{ {
struct roff_node *n; struct roff_node *n;
@ -193,7 +187,7 @@ rew_scope(struct roff_man *man, int tok)
void void
blk_close(MACRO_PROT_ARGS) blk_close(MACRO_PROT_ARGS)
{ {
int ntok; enum roff_tok ntok;
const struct roff_node *nn; const struct roff_node *nn;
char *p; char *p;
int nrew, target; int nrew, target;
@ -233,7 +227,7 @@ blk_close(MACRO_PROT_ARGS)
if (nn == NULL) { if (nn == NULL) {
mandoc_msg(MANDOCERR_BLK_NOTOPEN, man->parse, mandoc_msg(MANDOCERR_BLK_NOTOPEN, man->parse,
line, ppos, man_macronames[tok]); line, ppos, roff_name[tok]);
rew_scope(man, MAN_PP); rew_scope(man, MAN_PP);
} else { } else {
line = man->last->line; line = man->last->line;
@ -266,9 +260,8 @@ blk_exp(MACRO_PROT_ARGS)
roff_word_alloc(man, line, la, p); roff_word_alloc(man, line, la, p);
if (buf[*pos] != '\0') if (buf[*pos] != '\0')
mandoc_vmsg(MANDOCERR_ARG_EXCESS, mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse, line,
man->parse, line, *pos, "%s ... %s", *pos, "%s ... %s", roff_name[tok], buf + *pos);
man_macronames[tok], buf + *pos);
man_unscope(man, head); man_unscope(man, head);
roff_body_alloc(man, line, ppos, tok); roff_body_alloc(man, line, ppos, tok);
@ -331,18 +324,16 @@ in_line_eoln(MACRO_PROT_ARGS)
n = man->last; n = man->last;
for (;;) { for (;;) {
if (buf[*pos] != '\0' && (tok == MAN_br || if (buf[*pos] != '\0' && (tok == MAN_fi || tok == MAN_nf)) {
tok == MAN_fi || tok == MAN_nf)) {
mandoc_vmsg(MANDOCERR_ARG_SKIP, mandoc_vmsg(MANDOCERR_ARG_SKIP,
man->parse, line, *pos, "%s %s", man->parse, line, *pos, "%s %s",
man_macronames[tok], buf + *pos); roff_name[tok], buf + *pos);
break; break;
} }
if (buf[*pos] != '\0' && man->last != n && if (buf[*pos] != '\0' && man->last != n && tok == MAN_PD) {
(tok == MAN_PD || tok == MAN_ft || tok == MAN_sp)) {
mandoc_vmsg(MANDOCERR_ARG_EXCESS, mandoc_vmsg(MANDOCERR_ARG_EXCESS,
man->parse, line, *pos, "%s ... %s", man->parse, line, *pos, "%s ... %s",
man_macronames[tok], buf + *pos); roff_name[tok], buf + *pos);
break; break;
} }
la = *pos; la = *pos;

View File

@ -1,4 +1,4 @@
/* $Id: man_term.c,v 1.191 2017/02/15 14:10:08 schwarze Exp $ */ /* $Id: man_term.c,v 1.204 2017/06/08 12:54:58 schwarze Exp $ */
/* /*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2015, 2017 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2010-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -68,6 +68,7 @@ static void print_bvspace(struct termp *,
const struct roff_node *, int); const struct roff_node *, int);
static int pre_B(DECL_ARGS); static int pre_B(DECL_ARGS);
static int pre_DT(DECL_ARGS);
static int pre_HP(DECL_ARGS); static int pre_HP(DECL_ARGS);
static int pre_I(DECL_ARGS); static int pre_I(DECL_ARGS);
static int pre_IP(DECL_ARGS); static int pre_IP(DECL_ARGS);
@ -80,12 +81,9 @@ static int pre_SS(DECL_ARGS);
static int pre_TP(DECL_ARGS); static int pre_TP(DECL_ARGS);
static int pre_UR(DECL_ARGS); static int pre_UR(DECL_ARGS);
static int pre_alternate(DECL_ARGS); static int pre_alternate(DECL_ARGS);
static int pre_ft(DECL_ARGS);
static int pre_ign(DECL_ARGS); static int pre_ign(DECL_ARGS);
static int pre_in(DECL_ARGS); static int pre_in(DECL_ARGS);
static int pre_literal(DECL_ARGS); static int pre_literal(DECL_ARGS);
static int pre_ll(DECL_ARGS);
static int pre_sp(DECL_ARGS);
static void post_IP(DECL_ARGS); static void post_IP(DECL_ARGS);
static void post_HP(DECL_ARGS); static void post_HP(DECL_ARGS);
@ -95,8 +93,7 @@ static void post_SS(DECL_ARGS);
static void post_TP(DECL_ARGS); static void post_TP(DECL_ARGS);
static void post_UR(DECL_ARGS); static void post_UR(DECL_ARGS);
static const struct termact termacts[MAN_MAX] = { static const struct termact __termacts[MAN_MAX - MAN_TH] = {
{ pre_sp, NULL, MAN_NOTEXT }, /* br */
{ NULL, NULL, 0 }, /* TH */ { NULL, NULL, 0 }, /* TH */
{ pre_SH, post_SH, 0 }, /* SH */ { pre_SH, post_SH, 0 }, /* SH */
{ pre_SS, post_SS, 0 }, /* SS */ { pre_SS, post_SS, 0 }, /* SS */
@ -117,24 +114,22 @@ static const struct termact termacts[MAN_MAX] = {
{ pre_I, NULL, 0 }, /* I */ { pre_I, NULL, 0 }, /* I */
{ pre_alternate, NULL, 0 }, /* IR */ { pre_alternate, NULL, 0 }, /* IR */
{ pre_alternate, NULL, 0 }, /* RI */ { pre_alternate, NULL, 0 }, /* RI */
{ pre_sp, NULL, MAN_NOTEXT }, /* sp */
{ pre_literal, NULL, 0 }, /* nf */ { pre_literal, NULL, 0 }, /* nf */
{ pre_literal, NULL, 0 }, /* fi */ { pre_literal, NULL, 0 }, /* fi */
{ NULL, NULL, 0 }, /* RE */ { NULL, NULL, 0 }, /* RE */
{ pre_RS, post_RS, 0 }, /* RS */ { pre_RS, post_RS, 0 }, /* RS */
{ pre_ign, NULL, 0 }, /* DT */ { pre_DT, NULL, 0 }, /* DT */
{ pre_ign, NULL, MAN_NOTEXT }, /* UC */ { pre_ign, NULL, MAN_NOTEXT }, /* UC */
{ pre_PD, NULL, MAN_NOTEXT }, /* PD */ { pre_PD, NULL, MAN_NOTEXT }, /* PD */
{ pre_ign, NULL, 0 }, /* AT */ { pre_ign, NULL, 0 }, /* AT */
{ pre_in, NULL, MAN_NOTEXT }, /* in */ { pre_in, NULL, MAN_NOTEXT }, /* in */
{ pre_ft, NULL, MAN_NOTEXT }, /* ft */
{ pre_OP, NULL, 0 }, /* OP */ { pre_OP, NULL, 0 }, /* OP */
{ pre_literal, NULL, 0 }, /* EX */ { pre_literal, NULL, 0 }, /* EX */
{ pre_literal, NULL, 0 }, /* EE */ { pre_literal, NULL, 0 }, /* EE */
{ pre_UR, post_UR, 0 }, /* UR */ { pre_UR, post_UR, 0 }, /* UR */
{ NULL, NULL, 0 }, /* UE */ { NULL, NULL, 0 }, /* UE */
{ pre_ll, NULL, MAN_NOTEXT }, /* ll */
}; };
static const struct termact *termacts = __termacts - MAN_TH;
void void
@ -146,9 +141,10 @@ terminal_man(void *arg, const struct roff_man *man)
size_t save_defindent; size_t save_defindent;
p = (struct termp *)arg; p = (struct termp *)arg;
p->overstep = 0; p->tcol->rmargin = p->maxrmargin = p->defrmargin;
p->rmargin = p->maxrmargin = p->defrmargin; term_tab_set(p, NULL);
p->tabwidth = term_len(p, 5); term_tab_set(p, "T");
term_tab_set(p, ".5i");
memset(&mt, 0, sizeof(struct mtermp)); memset(&mt, 0, sizeof(struct mtermp));
mt.lmargin[mt.lmargincur] = term_len(p, p->defindent); mt.lmargin[mt.lmargincur] = term_len(p, p->defindent);
@ -218,14 +214,6 @@ pre_ign(DECL_ARGS)
return 0; return 0;
} }
static int
pre_ll(DECL_ARGS)
{
term_setwidth(p, n->child != NULL ? n->child->string : NULL);
return 0;
}
static int static int
pre_I(DECL_ARGS) pre_I(DECL_ARGS)
{ {
@ -240,7 +228,7 @@ pre_literal(DECL_ARGS)
term_newln(p); term_newln(p);
if (MAN_nf == n->tok || MAN_EX == n->tok) if (n->tok == MAN_nf || n->tok == MAN_EX)
mt->fl |= MANT_LITERAL; mt->fl |= MANT_LITERAL;
else else
mt->fl &= ~MANT_LITERAL; mt->fl &= ~MANT_LITERAL;
@ -250,9 +238,9 @@ pre_literal(DECL_ARGS)
* So in case a second call to term_flushln() is needed, * So in case a second call to term_flushln() is needed,
* indentation has to be set up explicitly. * indentation has to be set up explicitly.
*/ */
if (MAN_HP == n->parent->tok && p->rmargin < p->maxrmargin) { if (n->parent->tok == MAN_HP && p->tcol->rmargin < p->maxrmargin) {
p->offset = p->rmargin; p->tcol->offset = p->tcol->rmargin;
p->rmargin = p->maxrmargin; p->tcol->rmargin = p->maxrmargin;
p->trailspace = 0; p->trailspace = 0;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
p->flags |= TERMP_NOSPACE; p->flags |= TERMP_NOSPACE;
@ -272,7 +260,7 @@ pre_PD(DECL_ARGS)
return 0; return 0;
} }
assert(n->type == ROFFT_TEXT); assert(n->type == ROFFT_TEXT);
if (a2roffsu(n->string, &su, SCALE_VS)) if (a2roffsu(n->string, &su, SCALE_VS) != NULL)
mt->pardist = term_vspan(p, &su); mt->pardist = term_vspan(p, &su);
return 0; return 0;
} }
@ -361,41 +349,6 @@ pre_OP(DECL_ARGS)
return 0; return 0;
} }
static int
pre_ft(DECL_ARGS)
{
const char *cp;
if (NULL == n->child) {
term_fontlast(p);
return 0;
}
cp = n->child->string;
switch (*cp) {
case '4':
case '3':
case 'B':
term_fontrepl(p, TERMFONT_BOLD);
break;
case '2':
case 'I':
term_fontrepl(p, TERMFONT_UNDER);
break;
case 'P':
term_fontlast(p);
break;
case '1':
case 'C':
case 'R':
term_fontrepl(p, TERMFONT_NONE);
break;
default:
break;
}
return 0;
}
static int static int
pre_in(DECL_ARGS) pre_in(DECL_ARGS)
{ {
@ -406,8 +359,8 @@ pre_in(DECL_ARGS)
term_newln(p); term_newln(p);
if (NULL == n->child) { if (n->child == NULL) {
p->offset = mt->offset; p->tcol->offset = mt->offset;
return 0; return 0;
} }
@ -421,71 +374,29 @@ pre_in(DECL_ARGS)
else else
cp--; cp--;
if ( ! a2roffsu(++cp, &su, SCALE_EN)) if (a2roffsu(++cp, &su, SCALE_EN) == NULL)
return 0; return 0;
v = (term_hspan(p, &su) + 11) / 24; v = (term_hspan(p, &su) + 11) / 24;
if (less < 0) if (less < 0)
p->offset -= p->offset > v ? v : p->offset; p->tcol->offset -= p->tcol->offset > v ? v : p->tcol->offset;
else if (less > 0) else if (less > 0)
p->offset += v; p->tcol->offset += v;
else else
p->offset = v; p->tcol->offset = v;
if (p->offset > SHRT_MAX) if (p->tcol->offset > SHRT_MAX)
p->offset = term_len(p, p->defindent); p->tcol->offset = term_len(p, p->defindent);
return 0; return 0;
} }
static int static int
pre_sp(DECL_ARGS) pre_DT(DECL_ARGS)
{ {
struct roffsu su; term_tab_set(p, NULL);
int i, len; term_tab_set(p, "T");
term_tab_set(p, ".5i");
if ((NULL == n->prev && n->parent)) {
switch (n->parent->tok) {
case MAN_SH:
case MAN_SS:
case MAN_PP:
case MAN_LP:
case MAN_P:
return 0;
default:
break;
}
}
if (n->tok == MAN_br)
len = 0;
else if (n->child == NULL)
len = 1;
else {
if ( ! a2roffsu(n->child->string, &su, SCALE_VS))
su.scale = 1.0;
len = term_vspan(p, &su);
}
if (len == 0)
term_newln(p);
else if (len < 0)
p->skipvsp -= len;
else
for (i = 0; i < len; i++)
term_vspace(p);
/*
* Handle an explicit break request in the same way
* as an overflowing line.
*/
if (p->flags & TERMP_BRIND) {
p->offset = p->rmargin;
p->rmargin = p->maxrmargin;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
}
return 0; return 0;
} }
@ -514,7 +425,7 @@ pre_HP(DECL_ARGS)
/* Calculate offset. */ /* Calculate offset. */
if ((nn = n->parent->head->child) != NULL && if ((nn = n->parent->head->child) != NULL &&
a2roffsu(nn->string, &su, SCALE_EN)) { a2roffsu(nn->string, &su, SCALE_EN) != NULL) {
len = term_hspan(p, &su) / 24; len = term_hspan(p, &su) / 24;
if (len < 0 && (size_t)(-len) > mt->offset) if (len < 0 && (size_t)(-len) > mt->offset)
len = -mt->offset; len = -mt->offset;
@ -524,8 +435,8 @@ pre_HP(DECL_ARGS)
} else } else
len = mt->lmargin[mt->lmargincur]; len = mt->lmargin[mt->lmargincur];
p->offset = mt->offset; p->tcol->offset = mt->offset;
p->rmargin = mt->offset + len; p->tcol->rmargin = mt->offset + len;
return 1; return 1;
} }
@ -549,8 +460,8 @@ post_HP(DECL_ARGS)
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
p->trailspace = 0; p->trailspace = 0;
p->offset = mt->offset; p->tcol->offset = mt->offset;
p->rmargin = p->maxrmargin; p->tcol->rmargin = p->maxrmargin;
break; break;
default: default:
break; break;
@ -567,7 +478,7 @@ pre_PP(DECL_ARGS)
print_bvspace(p, n, mt->pardist); print_bvspace(p, n, mt->pardist);
break; break;
default: default:
p->offset = mt->offset; p->tcol->offset = mt->offset;
break; break;
} }
@ -599,7 +510,7 @@ pre_IP(DECL_ARGS)
/* Calculate the offset from the optional second argument. */ /* Calculate the offset from the optional second argument. */
if ((nn = n->parent->head->child) != NULL && if ((nn = n->parent->head->child) != NULL &&
(nn = nn->next) != NULL && (nn = nn->next) != NULL &&
a2roffsu(nn->string, &su, SCALE_EN)) { a2roffsu(nn->string, &su, SCALE_EN) != NULL) {
len = term_hspan(p, &su) / 24; len = term_hspan(p, &su) / 24;
if (len < 0 && (size_t)(-len) > mt->offset) if (len < 0 && (size_t)(-len) > mt->offset)
len = -mt->offset; len = -mt->offset;
@ -611,8 +522,8 @@ pre_IP(DECL_ARGS)
switch (n->type) { switch (n->type) {
case ROFFT_HEAD: case ROFFT_HEAD:
p->offset = mt->offset; p->tcol->offset = mt->offset;
p->rmargin = mt->offset + len; p->tcol->rmargin = mt->offset + len;
savelit = MANT_LITERAL & mt->fl; savelit = MANT_LITERAL & mt->fl;
mt->fl &= ~MANT_LITERAL; mt->fl &= ~MANT_LITERAL;
@ -625,8 +536,8 @@ pre_IP(DECL_ARGS)
return 0; return 0;
case ROFFT_BODY: case ROFFT_BODY:
p->offset = mt->offset + len; p->tcol->offset = mt->offset + len;
p->rmargin = p->maxrmargin; p->tcol->rmargin = p->maxrmargin;
break; break;
default: default:
break; break;
@ -644,11 +555,11 @@ post_IP(DECL_ARGS)
term_flushln(p); term_flushln(p);
p->flags &= ~TERMP_NOBREAK; p->flags &= ~TERMP_NOBREAK;
p->trailspace = 0; p->trailspace = 0;
p->rmargin = p->maxrmargin; p->tcol->rmargin = p->maxrmargin;
break; break;
case ROFFT_BODY: case ROFFT_BODY:
term_newln(p); term_newln(p);
p->offset = mt->offset; p->tcol->offset = mt->offset;
break; break;
default: default:
break; break;
@ -681,7 +592,7 @@ pre_TP(DECL_ARGS)
if ((nn = n->parent->head->child) != NULL && if ((nn = n->parent->head->child) != NULL &&
nn->string != NULL && ! (NODE_LINE & nn->flags) && nn->string != NULL && ! (NODE_LINE & nn->flags) &&
a2roffsu(nn->string, &su, SCALE_EN)) { a2roffsu(nn->string, &su, SCALE_EN) != NULL) {
len = term_hspan(p, &su) / 24; len = term_hspan(p, &su) / 24;
if (len < 0 && (size_t)(-len) > mt->offset) if (len < 0 && (size_t)(-len) > mt->offset)
len = -mt->offset; len = -mt->offset;
@ -693,8 +604,8 @@ pre_TP(DECL_ARGS)
switch (n->type) { switch (n->type) {
case ROFFT_HEAD: case ROFFT_HEAD:
p->offset = mt->offset; p->tcol->offset = mt->offset;
p->rmargin = mt->offset + len; p->tcol->rmargin = mt->offset + len;
savelit = MANT_LITERAL & mt->fl; savelit = MANT_LITERAL & mt->fl;
mt->fl &= ~MANT_LITERAL; mt->fl &= ~MANT_LITERAL;
@ -713,8 +624,8 @@ pre_TP(DECL_ARGS)
mt->fl |= MANT_LITERAL; mt->fl |= MANT_LITERAL;
return 0; return 0;
case ROFFT_BODY: case ROFFT_BODY:
p->offset = mt->offset + len; p->tcol->offset = mt->offset + len;
p->rmargin = p->maxrmargin; p->tcol->rmargin = p->maxrmargin;
p->trailspace = 0; p->trailspace = 0;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP); p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP);
break; break;
@ -735,7 +646,7 @@ post_TP(DECL_ARGS)
break; break;
case ROFFT_BODY: case ROFFT_BODY:
term_newln(p); term_newln(p);
p->offset = mt->offset; p->tcol->offset = mt->offset;
break; break;
default: default:
break; break;
@ -770,14 +681,14 @@ pre_SS(DECL_ARGS)
break; break;
case ROFFT_HEAD: case ROFFT_HEAD:
term_fontrepl(p, TERMFONT_BOLD); term_fontrepl(p, TERMFONT_BOLD);
p->offset = term_len(p, 3); p->tcol->offset = term_len(p, 3);
p->rmargin = mt->offset; p->tcol->rmargin = mt->offset;
p->trailspace = mt->offset; p->trailspace = mt->offset;
p->flags |= TERMP_NOBREAK | TERMP_BRIND; p->flags |= TERMP_NOBREAK | TERMP_BRIND;
break; break;
case ROFFT_BODY: case ROFFT_BODY:
p->offset = mt->offset; p->tcol->offset = mt->offset;
p->rmargin = p->maxrmargin; p->tcol->rmargin = p->maxrmargin;
p->trailspace = 0; p->trailspace = 0;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
break; break;
@ -832,14 +743,14 @@ pre_SH(DECL_ARGS)
break; break;
case ROFFT_HEAD: case ROFFT_HEAD:
term_fontrepl(p, TERMFONT_BOLD); term_fontrepl(p, TERMFONT_BOLD);
p->offset = 0; p->tcol->offset = 0;
p->rmargin = mt->offset; p->tcol->rmargin = mt->offset;
p->trailspace = mt->offset; p->trailspace = mt->offset;
p->flags |= TERMP_NOBREAK | TERMP_BRIND; p->flags |= TERMP_NOBREAK | TERMP_BRIND;
break; break;
case ROFFT_BODY: case ROFFT_BODY:
p->offset = mt->offset; p->tcol->offset = mt->offset;
p->rmargin = p->maxrmargin; p->tcol->rmargin = p->maxrmargin;
p->trailspace = 0; p->trailspace = 0;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND); p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
break; break;
@ -885,7 +796,7 @@ pre_RS(DECL_ARGS)
n->aux = SHRT_MAX + 1; n->aux = SHRT_MAX + 1;
if (n->child == NULL) if (n->child == NULL)
n->aux = mt->lmargin[mt->lmargincur]; n->aux = mt->lmargin[mt->lmargincur];
else if (a2roffsu(n->child->string, &su, SCALE_EN)) else if (a2roffsu(n->child->string, &su, SCALE_EN) != NULL)
n->aux = term_hspan(p, &su) / 24; n->aux = term_hspan(p, &su) / 24;
if (n->aux < 0 && (size_t)(-n->aux) > mt->offset) if (n->aux < 0 && (size_t)(-n->aux) > mt->offset)
n->aux = -mt->offset; n->aux = -mt->offset;
@ -893,8 +804,8 @@ pre_RS(DECL_ARGS)
n->aux = term_len(p, p->defindent); n->aux = term_len(p, p->defindent);
mt->offset += n->aux; mt->offset += n->aux;
p->offset = mt->offset; p->tcol->offset = mt->offset;
p->rmargin = p->maxrmargin; p->tcol->rmargin = p->maxrmargin;
if (++mt->lmarginsz < MAXMARGINS) if (++mt->lmarginsz < MAXMARGINS)
mt->lmargincur = mt->lmarginsz; mt->lmargincur = mt->lmarginsz;
@ -918,7 +829,7 @@ post_RS(DECL_ARGS)
} }
mt->offset -= n->parent->head->aux; mt->offset -= n->parent->head->aux;
p->offset = mt->offset; p->tcol->offset = mt->offset;
if (--mt->lmarginsz < MAXMARGINS) if (--mt->lmarginsz < MAXMARGINS)
mt->lmargincur = mt->lmarginsz; mt->lmargincur = mt->lmarginsz;
@ -951,7 +862,6 @@ post_UR(DECL_ARGS)
static void static void
print_man_node(DECL_ARGS) print_man_node(DECL_ARGS)
{ {
size_t rm, rmax;
int c; int c;
switch (n->type) { switch (n->type) {
@ -961,10 +871,11 @@ print_man_node(DECL_ARGS)
* If we have a space as the first character, break * If we have a space as the first character, break
* before printing the line's data. * before printing the line's data.
*/ */
if ('\0' == *n->string) { if (*n->string == '\0') {
term_vspace(p); term_vspace(p);
return; return;
} else if (' ' == *n->string && NODE_LINE & n->flags) } else if (*n->string == ' ' && n->flags & NODE_LINE &&
(p->flags & TERMP_NONEWLINE) == 0)
term_newln(p); term_newln(p);
term_word(p, n->string); term_word(p, n->string);
@ -986,6 +897,12 @@ print_man_node(DECL_ARGS)
break; break;
} }
if (n->tok < ROFF_MAX) {
roff_term_pre(p, n);
return;
}
assert(n->tok >= MAN_TH && n->tok <= MAN_MAX);
if ( ! (MAN_NOTEXT & termacts[n->tok].flags)) if ( ! (MAN_NOTEXT & termacts[n->tok].flags))
term_fontrepl(p, TERMFONT_NONE); term_fontrepl(p, TERMFONT_NONE);
@ -1012,20 +929,17 @@ print_man_node(DECL_ARGS)
if (mt->fl & MANT_LITERAL && if (mt->fl & MANT_LITERAL &&
! (p->flags & (TERMP_NOBREAK | TERMP_NONEWLINE)) && ! (p->flags & (TERMP_NOBREAK | TERMP_NONEWLINE)) &&
(n->next == NULL || n->next->flags & NODE_LINE)) { (n->next == NULL || n->next->flags & NODE_LINE)) {
rm = p->rmargin; p->flags |= TERMP_BRNEVER | TERMP_NOSPACE;
rmax = p->maxrmargin;
p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
p->flags |= TERMP_NOSPACE;
if (n->string != NULL && *n->string != '\0') if (n->string != NULL && *n->string != '\0')
term_flushln(p); term_flushln(p);
else else
term_newln(p); term_newln(p);
if (rm < rmax && n->parent->tok == MAN_HP) { p->flags &= ~TERMP_BRNEVER;
p->offset = rm; if (p->tcol->rmargin < p->maxrmargin &&
p->rmargin = rmax; n->parent->tok == MAN_HP) {
} else p->tcol->offset = p->tcol->rmargin;
p->rmargin = rm; p->tcol->rmargin = p->maxrmargin;
p->maxrmargin = rmax; }
} }
if (NODE_EOS & n->flags) if (NODE_EOS & n->flags)
p->flags |= TERMP_SENTENCE; p->flags |= TERMP_SENTENCE;
@ -1081,8 +995,8 @@ print_man_foot(struct termp *p, const struct roff_meta *meta)
p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
p->trailspace = 1; p->trailspace = 1;
p->offset = 0; p->tcol->offset = 0;
p->rmargin = p->maxrmargin > datelen ? p->tcol->rmargin = p->maxrmargin > datelen ?
(p->maxrmargin + term_len(p, 1) - datelen) / 2 : 0; (p->maxrmargin + term_len(p, 1) - datelen) / 2 : 0;
if (meta->os) if (meta->os)
@ -1091,9 +1005,10 @@ print_man_foot(struct termp *p, const struct roff_meta *meta)
/* At the bottom in the middle: manual date. */ /* At the bottom in the middle: manual date. */
p->offset = p->rmargin; p->tcol->offset = p->tcol->rmargin;
titlen = term_strlen(p, title); titlen = term_strlen(p, title);
p->rmargin = p->maxrmargin > titlen ? p->maxrmargin - titlen : 0; p->tcol->rmargin = p->maxrmargin > titlen ?
p->maxrmargin - titlen : 0;
p->flags |= TERMP_NOSPACE; p->flags |= TERMP_NOSPACE;
term_word(p, meta->date); term_word(p, meta->date);
@ -1104,8 +1019,8 @@ print_man_foot(struct termp *p, const struct roff_meta *meta)
p->flags &= ~TERMP_NOBREAK; p->flags &= ~TERMP_NOBREAK;
p->flags |= TERMP_NOSPACE; p->flags |= TERMP_NOSPACE;
p->trailspace = 0; p->trailspace = 0;
p->offset = p->rmargin; p->tcol->offset = p->tcol->rmargin;
p->rmargin = p->maxrmargin; p->tcol->rmargin = p->maxrmargin;
term_word(p, title); term_word(p, title);
term_flushln(p); term_flushln(p);
@ -1132,8 +1047,8 @@ print_man_head(struct termp *p, const struct roff_meta *meta)
p->flags |= TERMP_NOBREAK | TERMP_NOSPACE; p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
p->trailspace = 1; p->trailspace = 1;
p->offset = 0; p->tcol->offset = 0;
p->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ? p->tcol->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
(p->maxrmargin - vollen + term_len(p, 1)) / 2 : (p->maxrmargin - vollen + term_len(p, 1)) / 2 :
vollen < p->maxrmargin ? p->maxrmargin - vollen : 0; vollen < p->maxrmargin ? p->maxrmargin - vollen : 0;
@ -1143,9 +1058,9 @@ print_man_head(struct termp *p, const struct roff_meta *meta)
/* At the top in the middle: manual volume. */ /* At the top in the middle: manual volume. */
p->flags |= TERMP_NOSPACE; p->flags |= TERMP_NOSPACE;
p->offset = p->rmargin; p->tcol->offset = p->tcol->rmargin;
p->rmargin = p->offset + vollen + titlen < p->maxrmargin ? p->tcol->rmargin = p->tcol->offset + vollen + titlen <
p->maxrmargin - titlen : p->maxrmargin; p->maxrmargin ? p->maxrmargin - titlen : p->maxrmargin;
term_word(p, volume); term_word(p, volume);
term_flushln(p); term_flushln(p);
@ -1154,17 +1069,17 @@ print_man_head(struct termp *p, const struct roff_meta *meta)
p->flags &= ~TERMP_NOBREAK; p->flags &= ~TERMP_NOBREAK;
p->trailspace = 0; p->trailspace = 0;
if (p->rmargin + titlen <= p->maxrmargin) { if (p->tcol->rmargin + titlen <= p->maxrmargin) {
p->flags |= TERMP_NOSPACE; p->flags |= TERMP_NOSPACE;
p->offset = p->rmargin; p->tcol->offset = p->tcol->rmargin;
p->rmargin = p->maxrmargin; p->tcol->rmargin = p->maxrmargin;
term_word(p, title); term_word(p, title);
term_flushln(p); term_flushln(p);
} }
p->flags &= ~TERMP_NOSPACE; p->flags &= ~TERMP_NOSPACE;
p->offset = 0; p->tcol->offset = 0;
p->rmargin = p->maxrmargin; p->tcol->rmargin = p->maxrmargin;
/* /*
* Groff prints three blank lines before the content. * Groff prints three blank lines before the content.

View File

@ -1,7 +1,7 @@
/* $OpenBSD$ */ /* $OpenBSD$ */
/* /*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2012-2016 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2010, 2012-2017 Ingo Schwarze <schwarze@openbsd.org>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -48,14 +48,12 @@ static void check_text(CHKARGS);
static void post_AT(CHKARGS); static void post_AT(CHKARGS);
static void post_IP(CHKARGS); static void post_IP(CHKARGS);
static void post_vs(CHKARGS); static void post_vs(CHKARGS);
static void post_ft(CHKARGS);
static void post_OP(CHKARGS); static void post_OP(CHKARGS);
static void post_TH(CHKARGS); static void post_TH(CHKARGS);
static void post_UC(CHKARGS); static void post_UC(CHKARGS);
static void post_UR(CHKARGS); static void post_UR(CHKARGS);
static v_check man_valids[MAN_MAX] = { static const v_check __man_valids[MAN_MAX - MAN_TH] = {
post_vs, /* br */
post_TH, /* TH */ post_TH, /* TH */
NULL, /* SH */ NULL, /* SH */
NULL, /* SS */ NULL, /* SS */
@ -76,7 +74,6 @@ static v_check man_valids[MAN_MAX] = {
NULL, /* I */ NULL, /* I */
NULL, /* IR */ NULL, /* IR */
NULL, /* RI */ NULL, /* RI */
post_vs, /* sp */
NULL, /* nf */ NULL, /* nf */
NULL, /* fi */ NULL, /* fi */
NULL, /* RE */ NULL, /* RE */
@ -86,21 +83,20 @@ static v_check man_valids[MAN_MAX] = {
NULL, /* PD */ NULL, /* PD */
post_AT, /* AT */ post_AT, /* AT */
NULL, /* in */ NULL, /* in */
post_ft, /* ft */
post_OP, /* OP */ post_OP, /* OP */
NULL, /* EX */ NULL, /* EX */
NULL, /* EE */ NULL, /* EE */
post_UR, /* UR */ post_UR, /* UR */
NULL, /* UE */ NULL, /* UE */
NULL, /* ll */
}; };
static const v_check *man_valids = __man_valids - MAN_TH;
void void
man_node_validate(struct roff_man *man) man_node_validate(struct roff_man *man)
{ {
struct roff_node *n; struct roff_node *n;
v_check *cp; const v_check *cp;
n = man->last; n = man->last;
man->last = man->last->child; man->last = man->last->child;
@ -125,6 +121,19 @@ man_node_validate(struct roff_man *man)
case ROFFT_TBL: case ROFFT_TBL:
break; break;
default: 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;
}
break;
}
assert(n->tok >= MAN_TH && n->tok < MAN_MAX);
cp = man_valids + n->tok; cp = man_valids + n->tok;
if (*cp) if (*cp)
(*cp)(man, n); (*cp)(man, n);
@ -200,54 +209,13 @@ post_UR(CHKARGS)
check_part(man, n); check_part(man, n);
} }
static void
post_ft(CHKARGS)
{
char *cp;
int ok;
if (n->child == NULL)
return;
ok = 0;
cp = n->child->string;
switch (*cp) {
case '1':
case '2':
case '3':
case '4':
case 'I':
case 'P':
case 'R':
if ('\0' == cp[1])
ok = 1;
break;
case 'B':
if ('\0' == cp[1] || ('I' == cp[1] && '\0' == cp[2]))
ok = 1;
break;
case 'C':
if ('W' == cp[1] && '\0' == cp[2])
ok = 1;
break;
default:
break;
}
if (0 == ok) {
mandoc_vmsg(MANDOCERR_FT_BAD, man->parse,
n->line, n->pos, "ft %s", cp);
*cp = '\0';
}
}
static void static void
check_part(CHKARGS) check_part(CHKARGS)
{ {
if (n->type == ROFFT_BODY && n->child == NULL) if (n->type == ROFFT_BODY && n->child == NULL)
mandoc_msg(MANDOCERR_BLK_EMPTY, man->parse, mandoc_msg(MANDOCERR_BLK_EMPTY, man->parse,
n->line, n->pos, man_macronames[n->tok]); n->line, n->pos, roff_name[n->tok]);
} }
static void static void
@ -263,14 +231,13 @@ check_par(CHKARGS)
if (n->child == NULL) if (n->child == NULL)
mandoc_vmsg(MANDOCERR_PAR_SKIP, mandoc_vmsg(MANDOCERR_PAR_SKIP,
man->parse, n->line, n->pos, man->parse, n->line, n->pos,
"%s empty", man_macronames[n->tok]); "%s empty", roff_name[n->tok]);
break; break;
case ROFFT_HEAD: case ROFFT_HEAD:
if (n->child != NULL) if (n->child != NULL)
mandoc_vmsg(MANDOCERR_ARG_SKIP, mandoc_vmsg(MANDOCERR_ARG_SKIP,
man->parse, n->line, n->pos, man->parse, n->line, n->pos, "%s %s%s",
"%s %s%s", man_macronames[n->tok], roff_name[n->tok], n->child->string,
n->child->string,
n->child->next != NULL ? " ..." : ""); n->child->next != NULL ? " ..." : "");
break; break;
default: default:
@ -291,7 +258,7 @@ post_IP(CHKARGS)
if (n->parent->head->child == NULL && n->child == NULL) if (n->parent->head->child == NULL && n->child == NULL)
mandoc_vmsg(MANDOCERR_PAR_SKIP, mandoc_vmsg(MANDOCERR_PAR_SKIP,
man->parse, n->line, n->pos, man->parse, n->line, n->pos,
"%s empty", man_macronames[n->tok]); "%s empty", roff_name[n->tok]);
break; break;
default: default:
break; break;
@ -478,9 +445,12 @@ post_vs(CHKARGS)
switch (n->parent->tok) { switch (n->parent->tok) {
case MAN_SH: case MAN_SH:
case MAN_SS: case MAN_SS:
case MAN_PP:
case MAN_LP:
case MAN_P:
mandoc_vmsg(MANDOCERR_PAR_SKIP, man->parse, n->line, n->pos, mandoc_vmsg(MANDOCERR_PAR_SKIP, man->parse, n->line, n->pos,
"%s after %s", man_macronames[n->tok], "%s after %s", roff_name[n->tok],
man_macronames[n->parent->tok]); roff_name[n->parent->tok]);
/* FALLTHROUGH */ /* FALLTHROUGH */
case TOKEN_NONE: case TOKEN_NONE:
/* /*

356
mandoc.1
View File

@ -1,4 +1,4 @@
.\" $Id: mandoc.1,v 1.174 2017/02/10 15:45:28 schwarze Exp $ .\" $Id: mandoc.1,v 1.196 2017/06/08 00:23:30 schwarze Exp $
.\" .\"
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2012, 2014-2017 Ingo Schwarze <schwarze@openbsd.org> .\" Copyright (c) 2012, 2014-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -15,19 +15,19 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: February 10 2017 $ .Dd $Mdocdate: June 8 2017 $
.Dt MANDOC 1 .Dt MANDOC 1
.Os .Os
.Sh NAME .Sh NAME
.Nm mandoc .Nm mandoc
.Nd format and display UNIX manuals .Nd format manual pages
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm mandoc .Nm mandoc
.Op Fl acfhkl .Op Fl ac
.Op Fl I Cm os Ns = Ns Ar name .Op Fl I Cm os Ns = Ns Ar name
.Op Fl K Ar encoding .Op Fl K Ar encoding
.Op Fl m Ns Ar format .Op Fl mdoc | man
.Op Fl O Ar option .Op Fl O Ar options
.Op Fl T Ar output .Op Fl T Ar output
.Op Fl W Ar level .Op Fl W Ar level
.Op Ar .Op Ar
@ -44,9 +44,7 @@ reads
.Xr mdoc 7 .Xr mdoc 7
or or
.Xr man 7 .Xr man 7
text from stdin, implying text from stdin and produces
.Fl m Ns Cm andoc ,
and produces
.Fl T Cm locale .Fl T Cm locale
output. output.
.Pp .Pp
@ -67,28 +65,21 @@ to paginate them.
This is the default. This is the default.
It can be specified to override It can be specified to override
.Fl a . .Fl a .
.It Fl f
A synonym for
.Xr whatis 1 .
This overrides any earlier
.Fl k
and
.Fl l
options.
.It Fl h
Display only the SYNOPSIS lines.
Implies
.Fl c .
.It Fl I Cm os Ns = Ns Ar name .It Fl I Cm os Ns = Ns Ar name
Override the default operating system Override the default operating system
.Ar name .Ar name
for the for the
.Xr mdoc 7 .Xr mdoc 7
.Sq \&Os .Ic \&Os
and for the and for the
.Xr man 7 .Xr man 7
.Sq \&TH .Ic \&TH
macro. macro.
This can also be used to perform style checks according to the
conventions of one operating system while running on a different
operating system; see
.Sx Style messages
for details.
.It Fl K Ar encoding .It Fl K Ar encoding
Specify the input encoding. Specify the input encoding.
The supported The supported
@ -98,46 +89,53 @@ arguments are
.Cm iso-8859-1 , .Cm iso-8859-1 ,
and and
.Cm utf-8 . .Cm utf-8 .
If not specified, autodetection uses the first match: If not specified, autodetection uses the first match in the following
.Bl -tag -width iso-8859-1 list:
.It Cm utf-8 .Bl -enum
if the first three bytes of the input file .It
are the UTF-8 byte order mark (BOM, 0xefbbbf) If the first three bytes of the input file are the UTF-8 byte order
.It Ar encoding mark (BOM, 0xefbbbf), input is interpreted as
if the first or second line of the input file matches the .Cm utf-8 .
.It
If the first or second line of the input file matches the
.Sy emacs .Sy emacs
mode line format mode line format
.Pp .Pp
.D1 .\e" -*- Oo ...; Oc coding: Ar encoding ; No -*- .D1 .\e" -*- Oo ...; Oc coding: Ar encoding ; No -*-
.It Cm utf-8 .Pp
if the first non-ASCII byte in the file introduces a valid UTF-8 sequence then input is interpreted according to
.It Cm iso-8859-1 .Ar encoding .
otherwise .It
If the first non-ASCII byte in the file introduces a valid UTF-8
sequence, input is interpreted as
.Cm utf-8 .
.It
Otherwise, input is interpreted as
.Cm iso-8859-1 .
.El .El
.It Fl k .It Fl mdoc | man
A synonym for With
.Xr apropos 1 . .Fl mdoc ,
This overrides any earlier all input files are interpreted as
.Fl f .Xr mdoc 7 .
and With
.Fl l .Fl man ,
options. all input files are interpreted as
.It Fl l .Xr man 7 .
A synonym for By default, the input language is automatically detected for each file:
.Fl a . if the the first macro is
Also reverts any earlier .Ic \&Dd
.Fl f or
and .Ic \&Dt ,
.Fl k the
options. .Xr mdoc 7
.It Fl m Ns Ar format parser is used; otherwise, the
Input format. .Xr man 7
See parser is used.
.Sx Input Formats With other arguments,
for available formats. .Fl m
Defaults to is silently ignored.
.Fl m Ns Cm andoc . .It Fl O Ar options
.It Fl O Ar option
Comma-separated output options. Comma-separated output options.
.It Fl T Ar output .It Fl T Ar output
Output format. Output format.
@ -153,13 +151,14 @@ to be reported on the standard error output and to affect the exit status.
The The
.Ar level .Ar level
can be can be
.Cm style ,
.Cm warning , .Cm warning ,
.Cm error , .Cm error ,
or or
.Cm unsupp ; .Cm unsupp ;
.Cm all .Cm all
is an alias for is an alias for
.Cm warning . .Cm style .
By default, By default,
.Nm .Nm
is silent. is silent.
@ -190,6 +189,9 @@ If multiple files are specified,
will halt with the first failed parse. will halt with the first failed parse.
.El .El
.Pp .Pp
The options
.Fl fhklw
are also supported and are documented in man(1).
In In
.Fl f .Fl f
and and
@ -197,60 +199,20 @@ and
mode, mode,
.Nm .Nm
also supports the options also supports the options
.Fl CMmOSsw .Fl CMmOSs
described in the described in the
.Xr apropos 1 .Xr apropos 1
manual. manual.
.Ss Input Formats The options
The .Fl fkl
.Nm are mutually exclusive and override each other.
utility accepts
.Xr mdoc 7
and
.Xr man 7
input with
.Fl m Ns Cm doc
and
.Fl m Ns Cm an ,
respectively.
The
.Xr mdoc 7
format is
.Em strongly
recommended;
.Xr man 7
should only be used for legacy manuals.
.Pp
A third option,
.Fl m Ns Cm andoc ,
which is also the default, determines encoding on-the-fly: if the first
non-comment macro is
.Sq \&Dd
or
.Sq \&Dt ,
the
.Xr mdoc 7
parser is used; otherwise, the
.Xr man 7
parser is used.
.Pp
If multiple
files are specified with
.Fl m Ns Cm andoc ,
each has its file-type determined this way.
If multiple files are
specified and
.Fl m Ns Cm doc
or
.Fl m Ns Cm an
is specified, then this format is used exclusively.
.Ss Output Formats .Ss Output Formats
The The
.Nm .Nm
utility accepts the following utility accepts the following
.Fl T .Fl T
arguments, which correspond to output modes: arguments, which correspond to output modes:
.Bl -tag -width "-T locale" .Bl -tag -width "-T markdown"
.It Fl T Cm ascii .It Fl T Cm ascii
Produce 7-bit ASCII output. Produce 7-bit ASCII output.
See See
@ -262,7 +224,7 @@ See
.It Fl T Cm lint .It Fl T Cm lint
Parse only: produce no output. Parse only: produce no output.
Implies Implies
.Fl W Cm warning . .Fl W Cm style .
.It Fl T Cm locale .It Fl T Cm locale
Encode output using the current locale. Encode output using the current locale.
This is the default. This is the default.
@ -274,6 +236,12 @@ Produce
format output. format output.
See See
.Sx Man Output . .Sx Man Output .
.It Fl T Cm markdown
Produce output in
.Sy markdown
format.
See
.Sx Markdown Output .
.It Fl T Cm pdf .It Fl T Cm pdf
Produce PDF output. Produce PDF output.
See See
@ -290,9 +258,6 @@ See
Encode output in the UTF\-8 multi-byte format. Encode output in the UTF\-8 multi-byte format.
See See
.Sx UTF\-8 Output . .Sx UTF\-8 Output .
.It Fl T Cm xhtml
This is a synonym for
.Fl T Cm html .
.El .El
.Pp .Pp
If multiple input files are specified, these will be processed by the If multiple input files are specified, these will be processed by the
@ -377,7 +342,7 @@ The string
for example, for example,
.Ar ../src/%I.html , .Ar ../src/%I.html ,
is used as a template for linked header files (usually via the is used as a template for linked header files (usually via the
.Sq \&In .Ic \&In
macro). macro).
Instances of Instances of
.Sq \&%I .Sq \&%I
@ -390,7 +355,7 @@ The string
for example, for example,
.Ar ../html%S/%N.%S.html , .Ar ../html%S/%N.%S.html ,
is used as a template for linked manuals (usually via the is used as a template for linked manuals (usually via the
.Sq \&Xr .Ic \&Xr
macro). macro).
Instances of Instances of
.Sq \&%N .Sq \&%N
@ -436,13 +401,47 @@ If the input format is
.Xr man 7 , .Xr man 7 ,
the input is copied to the output, expanding any the input is copied to the output, expanding any
.Xr roff 7 .Xr roff 7
.Sq so .Ic so
requests. requests.
The parser is also run, and as usual, the The parser is also run, and as usual, the
.Fl W .Fl W
level controls which level controls which
.Sx DIAGNOSTICS .Sx DIAGNOSTICS
are displayed before copying the input to the output. are displayed before copying the input to the output.
.Ss Markdown Output
Translate
.Xr mdoc 7
input to the
.Sy markdown
format conforming to
.Lk http://daringfireball.net/projects/markdown/syntax.text\
"John Gruber's 2004 specification" .
The output also almost conforms to the
.Lk http://commonmark.org/ CommonMark
specification.
.Pp
The character set used for the markdown output is ASCII.
Non-ASCII characters are encoded as HTML entities.
Since that is not possible in literal font contexts, because these
are rendered as code spans and code blocks in the markdown output,
non-ASCII characters are transliterated to ASCII approximations in
these contexts.
.Pp
Markdown is a very weak markup language, so all semantic markup is
lost, and even part of the presentational markup may be lost.
Do not use this as an intermediate step in converting to HTML;
instead, use
.Fl T Cm html
directly.
.Pp
The
.Xr man 7 ,
.Xr tbl 7 ,
and
.Xr eqn 7
input languages are not supported by
.Fl T Cm markdown
output mode.
.Ss PDF Output .Ss PDF Output
PDF-1.1 output may be generated by PDF-1.1 output may be generated by
.Fl T Cm pdf . .Fl T Cm pdf .
@ -563,8 +562,16 @@ Meta data is not available in this case.
.It Ev MANPAGER .It Ev MANPAGER
Any non-empty value of the environment variable Any non-empty value of the environment variable
.Ev MANPAGER .Ev MANPAGER
will be used instead of the standard pagination program, is used instead of the standard pagination program,
.Xr more 1 . .Xr more 1 ;
see
.Xr man 1
for details.
Only used if
.Fl a
or
.Fl l
is specified.
.It Ev PAGER .It Ev PAGER
Specifies the pagination program to use when Specifies the pagination program to use when
.Ev MANPAGER .Ev MANPAGER
@ -572,7 +579,12 @@ is not defined.
If neither PAGER nor MANPAGER is defined, If neither PAGER nor MANPAGER is defined,
.Xr more 1 .Xr more 1
.Fl s .Fl s
will be used. is used.
Only used if
.Fl a
or
.Fl l
is specified.
.El .El
.Sh EXIT STATUS .Sh EXIT STATUS
The The
@ -585,27 +597,32 @@ option:
.Pp .Pp
.Bl -tag -width Ds -compact .Bl -tag -width Ds -compact
.It 0 .It 0
No warnings or errors occurred, or those that did were ignored because No style suggestions, warnings or errors occurred, or those that
they were lower than the requested did were ignored because they were lower than the requested
.Ar level . .Ar level .
.It 1
At least one style suggestion occurred, but no warning or error, and
.Fl W Cm style
was specified.
.It 2 .It 2
At least one warning occurred, but no error, and At least one warning occurred, but no error, and
.Fl W Cm warning .Fl W Cm warning
or
.Fl W Cm style
was specified. was specified.
.It 3 .It 3
At least one parsing error occurred, At least one parsing error occurred,
but no unsupported feature was encountered, and but no unsupported feature was encountered, and
.Fl W Cm error .Fl W Cm error
or or a lower
.Fl W Cm warning .Ar level
was specified. was requested.
.It 4 .It 4
At least one unsupported feature was encountered, and At least one unsupported feature was encountered, and
.Fl W Cm unsupp , .Fl W Cm unsupp
.Fl W Cm error or a lower
or .Ar level
.Fl W Cm warning was requested.
was specified.
.It 5 .It 5
Invalid command line arguments were specified. Invalid command line arguments were specified.
No input files have been read. No input files have been read.
@ -620,12 +637,11 @@ to exit at once, possibly in the middle of parsing or formatting a file.
Note that selecting Note that selecting
.Fl T Cm lint .Fl T Cm lint
output mode implies output mode implies
.Fl W Cm warning . .Fl W Cm style .
.Sh EXAMPLES .Sh EXAMPLES
To page manuals to the terminal: To page manuals to the terminal:
.Pp .Pp
.Dl $ mandoc \-W all,stop mandoc.1 2\*(Gt&1 | less .Dl $ mandoc -l mandoc.1 man.1 apropos.1 makewhatis.8
.Dl $ mandoc mandoc.1 mdoc.3 mdoc.7 | less
.Pp .Pp
To produce HTML manuals with To produce HTML manuals with
.Pa mandoc.css .Pa mandoc.css
@ -705,9 +721,22 @@ rendering can be produced.
Documents causing warnings may render poorly when using other Documents causing warnings may render poorly when using other
formatting tools instead of formatting tools instead of
.Nm . .Nm .
.It Cm style
An input file uses dubious or discouraged style.
This is not a complaint about the syntax, and probably neither
formatting nor portability are in danger.
While great care is taken to avoid false positives on the higher
message levels, the
.Cm style
level tries to reduce the probability that issues go unnoticed,
so it may occasionally issue bogus suggestions.
Please use your good judgement to decide whether any particular
.Cm style
suggestion really justifies a change to the input file.
.El .El
.Pp .Pp
Messages of the Messages of the
.Cm style ,
.Cm warning , .Cm warning ,
.Cm error , .Cm error ,
and and
@ -718,6 +747,58 @@ are hidden unless their level, or a lower level, is requested using a
option or option or
.Fl T Cm lint .Fl T Cm lint
output mode. output mode.
.Ss Style messages
As indicated below, some style checks are only performed if a
specific operating system name occurs in the arguments of the
.Ic \&Os
macro, of the
.Fl Ios
command line option, or, if neither are present, in the return value
of the
.Xr uname 3
function.
.Bl -ohang
.It Sy "useless macro"
.Pq mdoc
A
.Ic \&Bt ,
.Ic \&Tn ,
or
.Ic \&Ud
macro was found.
Simply delete it: it serves no useful purpose.
.It Sy "consider using OS macro"
.Pq mdoc
A string was found in plain text or in a
.Ic \&Bx
macro that could be represented using
.Ic \&Ox ,
.Ic \&Nx ,
.Ic \&Fx ,
or
.Ic \&Dx .
.It Sy "errnos out of order"
.Pq mdoc, Nx
The
.Ic \&Er
items in a
.Ic \&Bl
list are not in alphabetical order.
.It Sy "duplicate errno"
.Pq mdoc, Nx
A
.Ic \&Bl
list contains two consecutive
.Ic \&It
entries describing the same
.Ic \&Er
number.
.It Sy "description line ends with a full stop"
.Pq mdoc
Do not use punctuation at the end of an
.Ic \&Nd
block.
.El
.Ss Warnings related to the document prologue .Ss Warnings related to the document prologue
.Bl -ohang .Bl -ohang
.It Sy "missing manual title, using UNTITLED" .It Sy "missing manual title, using UNTITLED"
@ -870,6 +951,14 @@ The
.Ic \&Nd .Ic \&Nd
macro lacks the required argument. macro lacks the required argument.
The title line of the manual will end after the dash. The title line of the manual will end after the dash.
.It Sy "description line outside NAME section"
.Pq mdoc
An
.Ic \&Nd
macro appears outside the NAME section.
The arguments are printed anyway and the following text is used for
.Xr apropos 1 ,
but none of that behaviour is portable.
.It Sy "sections out of conventional order" .It Sy "sections out of conventional order"
.Pq mdoc .Pq mdoc
A standard section occurs after another section it usually precedes. A standard section occurs after another section it usually precedes.
@ -1088,7 +1177,7 @@ or
.Ic \&Bl .Ic \&Bl
.Fl offset .Fl offset
or or
.Fl width. .Fl width .
.It Sy "missing display type, using -ragged" .It Sy "missing display type, using -ragged"
.Pq mdoc .Pq mdoc
The The
@ -1310,6 +1399,12 @@ or
.Ic \&Fn .Ic \&Fn
macro contains an opening or closing parenthesis; that's probably wrong, macro contains an opening or closing parenthesis; that's probably wrong,
parentheses are added automatically. parentheses are added automatically.
.It Sy "unknown library name"
.Pq mdoc, not on Ox
An
.Ic \&Lb
macro has an unknown name argument and will be rendered as
.Qq library Dq Ar name .
.It Sy "invalid content in Rs block" .It Sy "invalid content in Rs block"
.Pq mdoc .Pq mdoc
An An
@ -1657,6 +1752,11 @@ whatever mode was active before the block.
A A
.Ic \&Bl .Ic \&Bl
macro fails to specify the list type. macro fails to specify the list type.
.It Sy "argument is not numeric, using 1"
.Pq roff
The argument of a
.Ic \&ce
request is not a number.
.It Sy "missing manual name, using \(dq\(dq" .It Sy "missing manual name, using \(dq\(dq"
.Pq mdoc .Pq mdoc
The first call to The first call to

View File

@ -1,4 +1,4 @@
.\" $Id: mandoc.3,v 1.38 2017/01/09 01:37:03 schwarze Exp $ .\" $Id: mandoc.3,v 1.39 2017/05/17 23:39:31 schwarze Exp $
.\" .\"
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org> .\" Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: January 9 2017 $ .Dd $Mdocdate: May 17 2017 $
.Dt MANDOC 3 .Dt MANDOC 3
.Os .Os
.Sh NAME .Sh NAME
@ -669,11 +669,9 @@ Using badly-nested blocks is
.Em strongly discouraged ; .Em strongly discouraged ;
for example, the for example, the
.Fl T Ns Cm html .Fl T Ns Cm html
and front-end to
.Fl T Ns Cm xhtml
front-ends to
.Xr mandoc 1 .Xr mandoc 1
are unable to render them in any meaningful way. is unable to render them in any meaningful way.
Furthermore, behaviour when encountering badly-nested blocks is not Furthermore, behaviour when encountering badly-nested blocks is not
consistent across troff implementations, especially when using multiple consistent across troff implementations, especially when using multiple
levels of badly-nested blocks. levels of badly-nested blocks.

View File

@ -1,7 +1,7 @@
/* $Id: mandoc.c,v 1.98 2015/11/12 22:44:27 schwarze Exp $ */ /* $Id: mandoc.c,v 1.100 2017/06/02 19:21:23 schwarze Exp $ */
/* /*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011-2015 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2011-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -175,7 +175,17 @@ mandoc_escape(const char **end, const char **start, int *sz)
++*end; ++*end;
return ESCAPE_ERROR; return ESCAPE_ERROR;
} }
gly = ESCAPE_IGNORE; switch ((*start)[-1]) {
case 'h':
gly = ESCAPE_HORIZ;
break;
case 'l':
gly = ESCAPE_HLINE;
break;
default:
gly = ESCAPE_IGNORE;
break;
}
term = **start; term = **start;
*start = ++*end; *start = ++*end;
break; break;

View File

@ -1,4 +1,4 @@
/* $Id: mandoc.css,v 1.17 2017/02/05 21:00:43 schwarze Exp $ */ /* $Id: mandoc.css,v 1.18 2017/03/13 20:22:18 schwarze Exp $ */
/* /*
* Standard style sheet for mandoc(1) -Thtml and man.cgi(8). * Standard style sheet for mandoc(1) -Thtml and man.cgi(8).
*/ */
@ -14,6 +14,11 @@ ul, ol, dl { margin-top: 0em;
margin-bottom: 0em; } margin-bottom: 0em; }
li, dt { margin-top: 1em; } li, dt { margin-top: 1em; }
a.selflink { border-bottom: thin dotted;
color: inherit;
font: inherit;
text-decoration: inherit; }
/* Search form and search results. */ /* Search form and search results. */
fieldset { border: thin solid silver; fieldset { border: thin solid silver;

View File

@ -1,4 +1,4 @@
/* $Id: mandoc.h,v 1.214 2017/01/28 23:30:08 schwarze Exp $ */ /* $Id: mandoc.h,v 1.226 2017/06/08 18:11:22 schwarze Exp $ */
/* /*
* Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -28,7 +28,7 @@
*/ */
enum mandoclevel { enum mandoclevel {
MANDOCLEVEL_OK = 0, MANDOCLEVEL_OK = 0,
MANDOCLEVEL_RESERVED, MANDOCLEVEL_STYLE, /* style suggestions */
MANDOCLEVEL_WARNING, /* warnings: syntax, whitespace, etc. */ MANDOCLEVEL_WARNING, /* warnings: syntax, whitespace, etc. */
MANDOCLEVEL_ERROR, /* input has been thrown away */ MANDOCLEVEL_ERROR, /* input has been thrown away */
MANDOCLEVEL_UNSUPP, /* input needs unimplemented features */ MANDOCLEVEL_UNSUPP, /* input needs unimplemented features */
@ -44,6 +44,14 @@ enum mandoclevel {
enum mandocerr { enum mandocerr {
MANDOCERR_OK, MANDOCERR_OK,
MANDOCERR_STYLE, /* ===== start of style suggestions ===== */
MANDOCERR_MACRO_USELESS, /* useless macro: macro */
MANDOCERR_BX, /* consider using OS macro: macro */
MANDOCERR_ER_ORDER, /* errnos out of order: Er ... */
MANDOCERR_ER_REP, /* duplicate errno: Er ... */
MANDOCERR_ND_DOT, /* description line ends with a full stop */
MANDOCERR_WARNING, /* ===== start of warnings ===== */ MANDOCERR_WARNING, /* ===== start of warnings ===== */
/* related to the prologue */ /* related to the prologue */
@ -71,6 +79,7 @@ enum mandocerr {
MANDOCERR_NAMESEC_BAD, /* bad NAME section content: macro */ MANDOCERR_NAMESEC_BAD, /* bad NAME section content: macro */
MANDOCERR_NAMESEC_PUNCT, /* missing comma before name: Nm name */ MANDOCERR_NAMESEC_PUNCT, /* missing comma before name: Nm name */
MANDOCERR_ND_EMPTY, /* missing description line, using "" */ MANDOCERR_ND_EMPTY, /* missing description line, using "" */
MANDOCERR_ND_LATE, /* description line outside NAME section */
MANDOCERR_SEC_ORDER, /* sections out of conventional order: Sh title */ MANDOCERR_SEC_ORDER, /* sections out of conventional order: Sh title */
MANDOCERR_SEC_REP, /* duplicate section title: Sh title */ MANDOCERR_SEC_REP, /* duplicate section title: Sh title */
MANDOCERR_SEC_MSEC, /* unexpected section: Sh title for ... only */ MANDOCERR_SEC_MSEC, /* unexpected section: Sh title for ... only */
@ -90,6 +99,7 @@ enum mandocerr {
MANDOCERR_FI_SKIP, /* fill mode already enabled, skipping: fi */ MANDOCERR_FI_SKIP, /* fill mode already enabled, skipping: fi */
MANDOCERR_NF_SKIP, /* fill mode already disabled, skipping: nf */ MANDOCERR_NF_SKIP, /* fill mode already disabled, skipping: nf */
MANDOCERR_BLK_LINE, /* line scope broken: macro breaks macro */ MANDOCERR_BLK_LINE, /* line scope broken: macro breaks macro */
MANDOCERR_BLK_BLANK, /* skipping blank line in line scope */
/* related to missing arguments */ /* related to missing arguments */
MANDOCERR_REQ_EMPTY, /* skipping empty request: request */ MANDOCERR_REQ_EMPTY, /* skipping empty request: request */
@ -125,6 +135,7 @@ enum mandocerr {
MANDOCERR_AT_BAD, /* unknown AT&T UNIX version: At version */ MANDOCERR_AT_BAD, /* unknown AT&T UNIX version: At version */
MANDOCERR_FA_COMMA, /* comma in function argument: arg */ MANDOCERR_FA_COMMA, /* comma in function argument: arg */
MANDOCERR_FN_PAREN, /* parenthesis in function name: arg */ MANDOCERR_FN_PAREN, /* parenthesis in function name: arg */
MANDOCERR_LB_BAD, /* unknown library name: Lb ... */
MANDOCERR_RS_BAD, /* invalid content in Rs block: macro */ MANDOCERR_RS_BAD, /* invalid content in Rs block: macro */
MANDOCERR_SM_BAD, /* invalid Boolean argument: macro arg */ MANDOCERR_SM_BAD, /* invalid Boolean argument: macro arg */
MANDOCERR_FT_BAD, /* unknown font, skipping request: ft font */ MANDOCERR_FT_BAD, /* unknown font, skipping request: ft font */
@ -177,6 +188,7 @@ enum mandocerr {
MANDOCERR_BD_FILE, /* NOT IMPLEMENTED: Bd -file */ MANDOCERR_BD_FILE, /* NOT IMPLEMENTED: Bd -file */
MANDOCERR_BD_NOARG, /* skipping display without arguments: Bd */ MANDOCERR_BD_NOARG, /* skipping display without arguments: Bd */
MANDOCERR_BL_NOTYPE, /* missing list type, using -item: Bl */ MANDOCERR_BL_NOTYPE, /* missing list type, using -item: Bl */
MANDOCERR_CE_NONUM, /* argument is not numeric, using 1: ce ... */
MANDOCERR_NM_NONAME, /* missing manual name, using "": Nm */ MANDOCERR_NM_NONAME, /* missing manual name, using "": Nm */
MANDOCERR_OS_UNAME, /* uname(3) system call failed, using UNKNOWN */ MANDOCERR_OS_UNAME, /* uname(3) system call failed, using UNKNOWN */
MANDOCERR_ST_BAD, /* unknown standard specifier: St standard */ MANDOCERR_ST_BAD, /* unknown standard specifier: St standard */
@ -234,9 +246,10 @@ enum tbl_cellt {
*/ */
struct tbl_cell { struct tbl_cell {
struct tbl_cell *next; 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 vert; /* width of subsequent vertical line */
enum tbl_cellt pos;
size_t spacing;
int col; /* column number, starting from 0 */ int col; /* column number, starting from 0 */
int flags; int flags;
#define TBL_CELL_TALIGN (1 << 0) /* t, T */ #define TBL_CELL_TALIGN (1 << 0) /* t, T */
@ -247,6 +260,7 @@ struct tbl_cell {
#define TBL_CELL_UP (1 << 5) /* u, U */ #define TBL_CELL_UP (1 << 5) /* u, U */
#define TBL_CELL_WIGN (1 << 6) /* z, Z */ #define TBL_CELL_WIGN (1 << 6) /* z, Z */
#define TBL_CELL_WMAX (1 << 7) /* x, X */ #define TBL_CELL_WMAX (1 << 7) /* x, X */
enum tbl_cellt pos;
}; };
/* /*
@ -274,9 +288,10 @@ enum tbl_datt {
*/ */
struct tbl_dat { struct tbl_dat {
struct tbl_cell *layout; /* layout cell */ struct tbl_cell *layout; /* layout cell */
int spans; /* how many spans follow */
struct tbl_dat *next; struct tbl_dat *next;
char *string; /* data (NULL if not TBL_DATA_DATA) */ 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_datt pos;
}; };
@ -404,6 +419,8 @@ enum mandoc_esc {
ESCAPE_NUMBERED, /* a numbered glyph */ ESCAPE_NUMBERED, /* a numbered glyph */
ESCAPE_UNICODE, /* a unicode codepoint */ ESCAPE_UNICODE, /* a unicode codepoint */
ESCAPE_NOSPACE, /* suppress space if the last on a line */ ESCAPE_NOSPACE, /* suppress space if the last on a line */
ESCAPE_HORIZ, /* horizontal movement */
ESCAPE_HLINE, /* horizontal line drawing */
ESCAPE_SKIPCHAR, /* skip the next character */ ESCAPE_SKIPCHAR, /* skip the next character */
ESCAPE_OVERSTRIKE /* overstrike all chars in the argument */ ESCAPE_OVERSTRIKE /* overstrike all chars in the argument */
}; };

View File

@ -1,8 +1,8 @@
.\" $Id: mandoc_char.7,v 1.64 2017/02/05 21:41:21 schwarze Exp $ .\" $Id: mandoc_char.7,v 1.66 2017/06/02 12:43:52 schwarze Exp $
.\" .\"
.\" Copyright (c) 2003 Jason McIntyre <jmc@openbsd.org> .\" Copyright (c) 2003 Jason McIntyre <jmc@openbsd.org>
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2011, 2013, 2015 Ingo Schwarze <schwarze@openbsd.org> .\" Copyright (c) 2011, 2013, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
.\" .\"
.\" Permission to use, copy, modify, and distribute this software for any .\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above .\" 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 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: February 5 2017 $ .Dd $Mdocdate: June 2 2017 $
.Dt MANDOC_CHAR 7 .Dt MANDOC_CHAR 7
.Os .Os
.Sh NAME .Sh NAME
@ -169,6 +169,8 @@ even on request and macro lines.
.Ss Accents .Ss Accents
In output modes supporting such special output characters, for example In output modes supporting such special output characters, for example
.Fl T Cm pdf , .Fl T Cm pdf ,
and sometimes less consistently in
.Fl T Cm utf8 ,
some some
.Xr roff 7 .Xr roff 7
formatters convert the following ASCII input characters to the formatters convert the following ASCII input characters to the
@ -177,6 +179,7 @@ following Unicode special output characters:
.It \(ga Ta U+2018 Ta left single quotation mark .It \(ga Ta U+2018 Ta left single quotation mark
.It \(aq Ta U+2019 Ta right single quotation mark .It \(aq Ta U+2019 Ta right single quotation mark
.It \(ti Ta U+02DC Ta small tilde .It \(ti Ta U+02DC Ta small tilde
.It \(ha Ta U+02C6 Ta modifier letter circumflex
.El .El
.Pp .Pp
In prose, this automatic substitution is often desirable; In prose, this automatic substitution is often desirable;
@ -187,6 +190,7 @@ escaping to render as follows:
.It \e(ga Ta U+0060 Ta grave accent .It \e(ga Ta U+0060 Ta grave accent
.It \e(aq Ta U+0027 Ta apostrophe .It \e(aq Ta U+0027 Ta apostrophe
.It \e(ti Ta U+007E Ta tilde .It \e(ti Ta U+007E Ta tilde
.It \e(ha Ta U+005E Ta circumflex accent
.El .El
.Ss Periods .Ss Periods
The period The period
@ -279,6 +283,10 @@ Text markers:
.It \e(sh Ta \(sh Ta hash (pound) .It \e(sh Ta \(sh Ta hash (pound)
.It \e(CR Ta \(CR Ta carriage return .It \e(CR Ta \(CR Ta carriage return
.It \e(OK Ta \(OK Ta check mark .It \e(OK Ta \(OK Ta check mark
.It \e(CL Ta \(CL Ta club suit
.It \e(SP Ta \(SP Ta spade suit
.It \e(HE Ta \(HE Ta heart suit
.It \e(DI Ta \(DI Ta diamond suit
.El .El
.Pp .Pp
Legal symbols: Legal symbols:
@ -372,6 +380,7 @@ Arrows:
.It \e(uA Ta \(uA Ta up double-arrow .It \e(uA Ta \(uA Ta up double-arrow
.It \e(dA Ta \(dA Ta down double-arrow .It \e(dA Ta \(dA Ta down double-arrow
.It \e(vA Ta \(vA Ta up-down double-arrow .It \e(vA Ta \(vA Ta up-down double-arrow
.It \e(an Ta \(an Ta horizontal arrow extension
.El .El
.Pp .Pp
Logical: Logical:
@ -450,11 +459,20 @@ Mathematical:
.It \e(Ah Ta \(Ah Ta aleph .It \e(Ah Ta \(Ah Ta aleph
.It \e(Im Ta \(Im Ta imaginary .It \e(Im Ta \(Im Ta imaginary
.It \e(Re Ta \(Re Ta real .It \e(Re Ta \(Re Ta real
.It \e(wp Ta \(wp Ta Weierstrass p
.It \e(pd Ta \(pd Ta partial differential .It \e(pd Ta \(pd Ta partial differential
.It \e(-h Ta \(-h Ta Planck constant over 2\(*p .It \e(-h Ta \(-h Ta Planck constant over 2\(*p
.It \e[12] Ta \[12] Ta one-half .It \e[hbar] Ta \[hbar] Ta Planck constant over 2\(*p
.It \e[14] Ta \[14] Ta one-fourth .It \e(12 Ta \(12 Ta one-half
.It \e[34] Ta \[34] Ta three-fourths .It \e(14 Ta \(14 Ta one-fourth
.It \e(34 Ta \(34 Ta three-fourths
.It \e(18 Ta \(18 Ta one-eighth
.It \e(38 Ta \(38 Ta three-eighths
.It \e(58 Ta \(58 Ta five-eighths
.It \e(78 Ta \(78 Ta seven-eighths
.It \e(S1 Ta \(S1 Ta superscript 1
.It \e(S2 Ta \(S2 Ta superscript 2
.It \e(S3 Ta \(S3 Ta superscript 3
.El .El
.Pp .Pp
Ligatures: Ligatures:
@ -588,6 +606,8 @@ Units:
.It \e(fm Ta \(fm Ta minute .It \e(fm Ta \(fm Ta minute
.It \e(sd Ta \(sd Ta second .It \e(sd Ta \(sd Ta second
.It \e(mc Ta \(mc Ta micro .It \e(mc Ta \(mc Ta micro
.It \e(Of Ta \(Of Ta Spanish female ordinal
.It \e(Om Ta \(Om Ta Spanish masculine ordinal
.El .El
.Pp .Pp
Greek letters: Greek letters:
@ -748,9 +768,7 @@ the
differently between mandoc and groff. differently between mandoc and groff.
.It .It
In In
.Fl T Ns Cm html .Fl T Ns Cm html ,
and
.Fl T Ns Cm xhtml ,
the \e(\(ti=, \e(nb, and \e(nc special characters render differently the \e(\(ti=, \e(nb, and \e(nc special characters render differently
between mandoc and groff. between mandoc and groff.
.It .It

View File

@ -60,9 +60,19 @@ Requires
.In sys/types.h .In sys/types.h
for for
.Vt size_t . .Vt size_t .
.Pp
Provides the utility functions documented in Provides the utility functions documented in
.Xr mandoc_malloc 3 . .Xr mandoc_malloc 3 .
.It Qq Pa mandoc_ohash.h .It Qq Pa mandoc_ohash.h
Requires
.In stddef.h
for
.Vt ptrdiff_t
and
.In stdint.h
for
.Vt uint32_t .
.Pp
Includes Includes
.In ohash.h .In ohash.h
and provides and provides
@ -113,17 +123,30 @@ from
.Pa roff.h .Pa roff.h
as an opaque type for function prototypes. as an opaque type for function prototypes.
.It Qq Pa roff.h .It Qq Pa roff.h
Requires
.Qq Pa mandoc_ohash.h
for
.Vt struct ohash .
.Pp
Provides Provides
.Vt enum mdoc_endbody , .Vt enum mdoc_endbody ,
.Vt enum roff_macroset , .Vt enum roff_macroset ,
.Vt enum roff_next , .Vt enum roff_next ,
.Vt enum roff_sec , .Vt enum roff_sec ,
.Vt enum roff_tok ,
.Vt enum roff_type , .Vt enum roff_type ,
.Vt struct roff_man , .Vt struct roff_man ,
.Vt struct roff_meta , .Vt struct roff_meta ,
.Vt struct roff_node , .Vt struct roff_node ,
and the function the constant array
.Fn deroff . .Va roff_name
and the functions
.Fn deroff ,
.Fn roffhash_alloc ,
.Fn roffhash_find ,
.Fn roffhash_free ,
and
.Fn roff_validate .
.Pp .Pp
Uses pointers to the types Uses pointers to the types
.Vt struct mdoc_arg .Vt struct mdoc_arg
@ -198,9 +221,10 @@ or
.El .El
.Ss Parser internals .Ss Parser internals
The following headers require inclusion of a parser interface header The following headers require inclusion of a parser interface header
before they can be included. All parser interface headers should before they can be included.
precede all parser internal headers. When any parser internal headers All parser interface headers should precede all parser internal headers.
are included, the same file should not include any formatter headers. When any parser internal headers are included, the same file should
not include any formatter headers.
.Bl -tag -width Ds .Bl -tag -width Ds
.It Qq Pa libmandoc.h .It Qq Pa libmandoc.h
Requires Requires
@ -271,6 +295,10 @@ from
as opaque types for function prototypes. as opaque types for function prototypes.
.It Qq Pa libmdoc.h .It Qq Pa libmdoc.h
Requires Requires
.Qq Pa roff.h
for
.Vt enum roff_tok
and
.Qq Pa mdoc.h .Qq Pa mdoc.h
for for
.Vt enum mdoc_* .Vt enum mdoc_*
@ -303,6 +331,11 @@ When this header is included, the same file should not include
or or
.Pa libroff.h . .Pa libroff.h .
.It Qq Pa libman.h .It Qq Pa libman.h
Requires
.Qq Pa roff.h
for
.Vt enum roff_tok .
.Pp
Provides Provides
.Vt struct man_macro .Vt struct man_macro
and some functions internal to the and some functions internal to the
@ -405,6 +438,7 @@ Provides
.Vt enum termtype , .Vt enum termtype ,
.Vt struct termp_tbl , .Vt struct termp_tbl ,
.Vt struct termp , .Vt struct termp ,
.Fn roff_term_pre ,
and many terminal formatting functions. and many terminal formatting functions.
.Pp .Pp
Uses the opaque type Uses the opaque type
@ -419,6 +453,8 @@ from
.Pa mandoc.h .Pa mandoc.h
and and
.Vt struct roff_meta .Vt struct roff_meta
and
.Vt struct roff_node
from from
.Pa roff.h .Pa roff.h
as opaque types for function prototypes. as opaque types for function prototypes.
@ -431,10 +467,7 @@ or
Requires Requires
.In sys/types.h .In sys/types.h
for for
.Vt size_t , .Vt size_t
.In stdio.h
for
.Dv BUFSIZ ,
and and
.Qq Pa out.h .Qq Pa out.h
for for
@ -450,8 +483,21 @@ Provides
.Vt struct tagq , .Vt struct tagq ,
.Vt struct htmlpair , .Vt struct htmlpair ,
.Vt struct html , .Vt struct html ,
.Fn roff_html_pre ,
and many HTML formatting functions. and many HTML formatting functions.
.Pp .Pp
Uses
.Vt struct tbl_span
and
.Vt struct eqn
from
.Pa mandoc.h
and
.Vt struct roff_node
from
.Pa roff.h
as opaque types for function prototypes.
.Pp
When this header is included, the same file should not include When this header is included, the same file should not include
.Pa term.h .Pa term.h
or or
@ -506,8 +552,7 @@ Provides
.Vt struct manpage , .Vt struct manpage ,
.Vt struct mansearch , .Vt struct mansearch ,
and the functions and the functions
.Fn mansearch_setup , .Fn mansearch
.Fn mansearch ,
and and
.Fn mansearch_free . .Fn mansearch_free .
.Pp .Pp

View File

@ -1,4 +1,4 @@
.\" $Id: mandoc_html.3,v 1.5 2017/01/28 22:36:38 schwarze Exp $ .\" $Id: mandoc_html.3,v 1.8 2017/05/12 17:58:21 schwarze Exp $
.\" .\"
.\" Copyright (c) 2014, 2017 Ingo Schwarze <schwarze@openbsd.org> .\" Copyright (c) 2014, 2017 Ingo Schwarze <schwarze@openbsd.org>
.\" .\"
@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: January 28 2017 $ .Dd $Mdocdate: May 12 2017 $
.Dt MANDOC_HTML 3 .Dt MANDOC_HTML 3
.Os .Os
.Sh NAME .Sh NAME
@ -48,6 +48,14 @@
.Fa "struct html *h" .Fa "struct html *h"
.Fa "const char *word" .Fa "const char *word"
.Fc .Fc
.Ft char *
.Fo html_make_id
.Fa "const struct roff_node *n"
.Fc
.Ft int
.Fo html_strlen
.Fa "const char *cp"
.Fc
.Sh DESCRIPTION .Sh DESCRIPTION
The mandoc HTML formatter is not a formal library. The mandoc HTML formatter is not a formal library.
However, as it is compiled into more than one program, in particular However, as it is compiled into more than one program, in particular
@ -145,6 +153,11 @@ the respective attribute is not written.
Print a Print a
.Cm class .Cm class
attribute. 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 .It Cm h
Print a Print a
.Cm href .Cm href
@ -191,7 +204,7 @@ Instead, the rest of the format string consists of pairs of
argument type letters and style name letters. argument type letters and style name letters.
.El .El
.Pp .Pp
Argument type letters each require on argument as follows: Argument type letters each require one argument as follows:
.Bl -tag -width 1n -offset indent .Bl -tag -width 1n -offset indent
.It Cm h .It Cm h
Requires one Requires one
@ -220,10 +233,18 @@ width specifier.
If the argument is If the argument is
.Dv NULL , .Dv NULL ,
nothing is printed for this pair. nothing is printed for this pair.
.It Cm W .Pp
Similar to The
.Cm w , .Cm w
but makes the width negative by multiplying it with \(mi1. argument type letter can optionally be followed by one or two
modifier letters.
The modifier
.Cm +
increases the width by 10% to make even bold text fit
and adds two units for padding between columns.
The modifier
.Cm \-
makes the width negative by multiplying it with \-1.
.El .El
.Pp .Pp
Style name letters decide what to do with the preceding argument: Style name letters decide what to do with the preceding argument:
@ -301,8 +322,27 @@ and
.Fn print_tagq .Fn print_tagq
functions. functions.
.Pp .Pp
The function
.Fn html_make_id
takes a node containing one or more text children
and returns a newly allocated string containing the concatenation
of the child strings, with blanks replaced by underscores.
If the node
.Fa n
contains any non-text child node,
.Fn html_make_id
returns
.Dv NULL
instead.
The caller is responsible for freeing the returned string.
.Pp
The function
.Fn html_strlen
counts the number of characters in
.Fa cp .
It is used as a crude estimate of the width needed to display a string.
.Pp
The functions The functions
.Fn html_strlen ,
.Fn print_eqn , .Fn print_eqn ,
.Fn print_tbl , .Fn print_tbl ,
and and

View File

@ -1,4 +1,4 @@
.\" $Id: mandocd.8,v 1.1 2017/02/06 19:04:21 schwarze Exp $ .\" $Id: mandocd.8,v 1.2 2017/03/18 19:56:01 schwarze Exp $
.\" .\"
.\" Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org> .\" Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
.\" .\"
@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: February 6 2017 $ .Dd $Mdocdate: March 18 2017 $
.Dt MANDOCD 8 .Dt MANDOCD 8
.Os .Os
.Sh NAME .Sh NAME
@ -85,7 +85,7 @@ Override the default operating system
.Ar name .Ar name
for the for the
.Xr mdoc 7 .Xr mdoc 7
.Ic Os .Ic \&Os
and for the and for the
.Xr man 7 .Xr man 7
.Ic TH .Ic TH

View File

@ -1,4 +1,4 @@
/* $Id: mandocdb.c,v 1.244 2017/02/17 14:45:55 schwarze Exp $ */ /* $Id: mandocdb.c,v 1.250 2017/05/17 22:27:12 schwarze Exp $ */
/* /*
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011-2017 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2011-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -183,8 +183,7 @@ static struct ohash names; /* table of all names */
static struct ohash strings; /* table of all strings */ static struct ohash strings; /* table of all strings */
static uint64_t name_mask; static uint64_t name_mask;
static const struct mdoc_handler mdocs[MDOC_MAX] = { static const struct mdoc_handler __mdocs[MDOC_MAX - MDOC_Dd] = {
{ NULL, 0, 0 }, /* Ap */
{ NULL, 0, NODE_NOPRT }, /* Dd */ { NULL, 0, NODE_NOPRT }, /* Dd */
{ NULL, 0, NODE_NOPRT }, /* Dt */ { NULL, 0, NODE_NOPRT }, /* Dt */
{ NULL, 0, NODE_NOPRT }, /* Os */ { NULL, 0, NODE_NOPRT }, /* Os */
@ -200,6 +199,7 @@ static const struct mdoc_handler mdocs[MDOC_MAX] = {
{ NULL, 0, 0 }, /* It */ { NULL, 0, 0 }, /* It */
{ NULL, 0, 0 }, /* Ad */ { NULL, 0, 0 }, /* Ad */
{ NULL, TYPE_An, 0 }, /* An */ { NULL, TYPE_An, 0 }, /* An */
{ NULL, 0, 0 }, /* Ap */
{ NULL, TYPE_Ar, 0 }, /* Ar */ { NULL, TYPE_Ar, 0 }, /* Ar */
{ NULL, TYPE_Cd, 0 }, /* Cd */ { NULL, TYPE_Cd, 0 }, /* Cd */
{ NULL, TYPE_Cm, 0 }, /* Cm */ { NULL, TYPE_Cm, 0 }, /* Cm */
@ -302,12 +302,10 @@ static const struct mdoc_handler mdocs[MDOC_MAX] = {
{ NULL, 0, 0 }, /* En */ { NULL, 0, 0 }, /* En */
{ NULL, TYPE_Dx, NODE_NOSRC }, /* Dx */ { NULL, TYPE_Dx, NODE_NOSRC }, /* Dx */
{ NULL, 0, 0 }, /* %Q */ { NULL, 0, 0 }, /* %Q */
{ NULL, 0, 0 }, /* br */
{ NULL, 0, 0 }, /* sp */
{ NULL, 0, 0 }, /* %U */ { NULL, 0, 0 }, /* %U */
{ NULL, 0, 0 }, /* Ta */ { NULL, 0, 0 }, /* Ta */
{ NULL, 0, 0 }, /* ll */
}; };
static const struct mdoc_handler *const mdocs = __mdocs - MDOC_Dd;
int int
@ -1211,7 +1209,7 @@ mpages_merge(struct dba *dba, struct mparse *mp)
} else if (man != NULL && man->macroset == MACROSET_MAN) { } else if (man != NULL && man->macroset == MACROSET_MAN) {
man_validate(man); man_validate(man);
if (*man->meta.msec != '\0' || if (*man->meta.msec != '\0' ||
*man->meta.msec != '\0') { *man->meta.title != '\0') {
mpage->form = FORM_SRC; mpage->form = FORM_SRC;
mpage->sec = mandoc_strdup(man->meta.msec); mpage->sec = mandoc_strdup(man->meta.msec);
mpage->arch = mandoc_strdup(mlink->arch); mpage->arch = mandoc_strdup(mlink->arch);
@ -1545,25 +1543,26 @@ parse_mdoc(struct mpage *mpage, const struct roff_meta *meta,
const struct roff_node *n) const struct roff_node *n)
{ {
assert(NULL != n); for (n = n->child; n != NULL; n = n->next) {
for (n = n->child; NULL != n; n = n->next) { if (n->tok == TOKEN_NONE ||
if (n->flags & mdocs[n->tok].taboo) n->tok < ROFF_MAX ||
n->flags & mdocs[n->tok].taboo)
continue; continue;
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
switch (n->type) { switch (n->type) {
case ROFFT_ELEM: case ROFFT_ELEM:
case ROFFT_BLOCK: case ROFFT_BLOCK:
case ROFFT_HEAD: case ROFFT_HEAD:
case ROFFT_BODY: case ROFFT_BODY:
case ROFFT_TAIL: case ROFFT_TAIL:
if (NULL != mdocs[n->tok].fp) if (mdocs[n->tok].fp != NULL &&
if (0 == (*mdocs[n->tok].fp)(mpage, meta, n)) (*mdocs[n->tok].fp)(mpage, meta, n) == 0)
break; break;
if (mdocs[n->tok].mask) if (mdocs[n->tok].mask)
putmdockey(mpage, n->child, putmdockey(mpage, n->child,
mdocs[n->tok].mask, mdocs[n->tok].taboo); mdocs[n->tok].mask, mdocs[n->tok].taboo);
break; break;
default: default:
assert(n->type != ROFFT_ROOT);
continue; continue;
} }
if (NULL != n->child) if (NULL != n->child)
@ -2123,6 +2122,23 @@ dbwrite(struct dba *dba)
int status; int status;
pid_t child; pid_t child;
/*
* Do not write empty databases, and delete existing ones
* when makewhatis -u causes them to become empty.
*/
dba_array_start(dba->pages);
if (dba_array_next(dba->pages) == NULL) {
if (unlink(MANDOC_DB) == -1)
say(MANDOC_DB, "&unlink");
return;
}
/*
* Build the database in a temporary file,
* then atomically move it into place.
*/
if (dba_write(MANDOC_DB "~", dba) != -1) { if (dba_write(MANDOC_DB "~", dba) != -1) {
if (rename(MANDOC_DB "~", MANDOC_DB) == -1) { if (rename(MANDOC_DB "~", MANDOC_DB) == -1) {
exitcode = (int)MANDOCLEVEL_SYSERR; exitcode = (int)MANDOCLEVEL_SYSERR;
@ -2132,6 +2148,11 @@ dbwrite(struct dba *dba)
return; return;
} }
/*
* We lack write permission and cannot replace the database
* file, but let's at least check whether the data changed.
*/
(void)strlcpy(tfn, "/tmp/mandocdb.XXXXXXXX", sizeof(tfn)); (void)strlcpy(tfn, "/tmp/mandocdb.XXXXXXXX", sizeof(tfn));
if (mkdtemp(tfn) == NULL) { if (mkdtemp(tfn) == NULL) {
exitcode = (int)MANDOCLEVEL_SYSERR; exitcode = (int)MANDOCLEVEL_SYSERR;

195
manpage.c
View File

@ -1,195 +0,0 @@
/* $Id: manpage.c,v 1.14 2016/07/09 15:24:19 schwarze Exp $ */
/*
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013 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 <sys/types.h>
#include <assert.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "manconf.h"
#include "mansearch.h"
static void show(const char *, const char *);
int
main(int argc, char *argv[])
{
int ch, term;
size_t i, sz, linesz;
ssize_t len;
struct mansearch search;
struct manpage *res;
char *conf_file, *defpaths, *auxpaths, *line;
char buf[PATH_MAX];
const char *cmd;
struct manconf conf;
char *progname;
extern char *optarg;
extern int optind;
term = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO);
progname = strrchr(argv[0], '/');
if (progname == NULL)
progname = argv[0];
else
++progname;
auxpaths = defpaths = conf_file = NULL;
memset(&conf, 0, sizeof(conf));
memset(&search, 0, sizeof(struct mansearch));
while (-1 != (ch = getopt(argc, argv, "C:M:m:S:s:")))
switch (ch) {
case ('C'):
conf_file = optarg;
break;
case ('M'):
defpaths = optarg;
break;
case ('m'):
auxpaths = optarg;
break;
case ('S'):
search.arch = optarg;
break;
case ('s'):
search.sec = optarg;
break;
default:
goto usage;
}
argc -= optind;
argv += optind;
if (0 == argc)
goto usage;
search.outkey = "Nd";
search.argmode = ARG_EXPR;
manconf_parse(&conf, conf_file, defpaths, auxpaths);
ch = mansearch(&search, &conf.manpath, argc, argv, &res, &sz);
manconf_free(&conf);
if (0 == ch)
goto usage;
if (0 == sz) {
free(res);
return EXIT_FAILURE;
} else if (1 == sz && term) {
i = 1;
goto show;
} else if (NULL == res)
return EXIT_FAILURE;
for (i = 0; i < sz; i++) {
printf("%6zu %s: %s\n",
i + 1, res[i].names, res[i].output);
free(res[i].names);
free(res[i].output);
}
if (0 == term) {
for (i = 0; i < sz; i++)
free(res[i].file);
free(res);
return EXIT_SUCCESS;
}
i = 1;
printf("Enter a choice [1]: ");
fflush(stdout);
line = NULL;
linesz = 0;
if ((len = getline(&line, &linesz, stdin)) != -1) {
if ('\n' == line[--len] && len > 0) {
line[len] = '\0';
if ((i = atoi(line)) < 1 || i > sz)
i = 0;
}
}
free(line);
if (0 == i) {
for (i = 0; i < sz; i++)
free(res[i].file);
free(res);
return EXIT_SUCCESS;
}
show:
cmd = res[i - 1].form ? "mandoc" : "cat";
strlcpy(buf, res[i - 1].file, PATH_MAX);
for (i = 0; i < sz; i++)
free(res[i].file);
free(res);
show(cmd, buf);
/* NOTREACHED */
usage:
fprintf(stderr, "usage: %s [-C conf] "
"[-M paths] "
"[-m paths] "
"[-S arch] "
"[-s section] "
"expr ...\n",
progname);
return EXIT_FAILURE;
}
static void
show(const char *cmd, const char *file)
{
int fds[2];
pid_t pid;
if (-1 == pipe(fds)) {
perror(NULL);
exit(EXIT_FAILURE);
}
if (-1 == (pid = fork())) {
perror(NULL);
exit(EXIT_FAILURE);
} else if (pid > 0) {
dup2(fds[0], STDIN_FILENO);
close(fds[1]);
cmd = NULL != getenv("MANPAGER") ?
getenv("MANPAGER") :
(NULL != getenv("PAGER") ?
getenv("PAGER") : "more");
execlp(cmd, cmd, (char *)NULL);
perror(cmd);
exit(EXIT_FAILURE);
}
dup2(fds[1], STDOUT_FILENO);
close(fds[0]);
execlp(cmd, cmd, file, (char *)NULL);
perror(cmd);
exit(EXIT_FAILURE);
}

View File

@ -1,4 +1,4 @@
.\" $Id: mansearch.3,v 1.4 2015/03/27 17:37:25 schwarze Exp $ .\" $Id: mansearch.3,v 1.5 2017/03/30 22:22:05 schwarze Exp $
.\" .\"
.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org> .\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
.\" .\"
@ -14,28 +14,22 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: March 27 2015 $ .Dd $Mdocdate: March 30 2017 $
.Dt MANSEARCH 3 .Dt MANSEARCH 3
.Os .Os
.Sh NAME .Sh NAME
.Nm mansearch , .Nm mansearch
.Nm mansearch_setup
.Nd search manual page databases .Nd search manual page databases
.Sh SYNOPSIS .Sh SYNOPSIS
.In stdint.h .In stdint.h
.In manconf.h .In manconf.h
.In mansearch.h .In mansearch.h
.Ft int .Ft int
.Fo mansearch_setup
.Fa "int start"
.Fc
.Ft int
.Fo mansearch .Fo mansearch
.Fa "const struct mansearch *search" .Fa "const struct mansearch *search"
.Fa "const struct manpaths *paths" .Fa "const struct manpaths *paths"
.Fa "int argc" .Fa "int argc"
.Fa "char *argv[]" .Fa "char *argv[]"
.Fa "const char *outkey"
.Fa "struct manpage **res" .Fa "struct manpage **res"
.Fa "size_t *sz" .Fa "size_t *sz"
.Fc .Fc
@ -44,7 +38,7 @@ The
.Fn mansearch .Fn mansearch
function returns information about manuals matching a search query from a function returns information about manuals matching a search query from a
.Xr mandoc.db 5 .Xr mandoc.db 5
SQLite3 database. database.
.Pp .Pp
The query arguments are as follows: The query arguments are as follows:
.Bl -tag -width Ds .Bl -tag -width Ds
@ -58,18 +52,6 @@ Directories to be searched, defined in
Search criteria, usually taken from the command line. Search criteria, usually taken from the command line.
.El .El
.Pp .Pp
The
.Fa "const char *outkey"
selects which data to return in the
.Va output
field of the
.Fa res
structures.
It takes any of the macro keys defined in
.Pa mansearch_const.c
and described in
.Xr apropos 1 .
.Pp
The output arguments are as follows: The output arguments are as follows:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Fa "struct manpage **res" .It Fa "struct manpage **res"
@ -89,19 +71,6 @@ array itself.
Returns the number of result structures contained in Returns the number of result structures contained in
.Fa res . .Fa res .
.El .El
.Pp
To speed up searches, the
.Fn mansearch_setup
function can optionally be called with a
.Fa start
argument of 1 before
.Fn mansearch
to set up an SQLite3 pagecache.
If it was called, it has to be called again with a
.Fa start
argument of 0 after the last call to
.Fn mansearch
to release the memory used for the pagecache.
.Sh IMPLEMENTATION NOTES .Sh IMPLEMENTATION NOTES
For each manual page tree, the search is done in two steps. For each manual page tree, the search is done in two steps.
In the first step, a list of pages matching the search criteria is built. In the first step, a list of pages matching the search criteria is built.
@ -112,103 +81,26 @@ array.
.Pp .Pp
All function mentioned here are defined in the file All function mentioned here are defined in the file
.Pa mansearch.c . .Pa mansearch.c .
No functions except
.Fn mansearch
and
.Fn sql_statement
build any SQL code, and no functions except
.Fn mansearch ,
.Fn buildnames ,
and
.Fn buildoutput
execute it.
.Ss Finding matches .Ss Finding matches
The query is built using the following grammar:
.Bd -literal -offset indent
<query> ::= "SELECT * FROM mpages WHERE" <condition>
<condition> ::= "(" <condition> ")" |
<condition> "OR" <condition> |
<condition> "AND" <condition> |
"desc" <operator> "?" |
"id IN (SELECT pageid FROM" <subquery> ")"
<subquery> ::= "names WHERE name" <operator> "?" |
"keys WHERE key" <operator> "? AND bits & ?"
<operator> ::= "MATCH" | "REGEXP"
.Ed
.Pp
The MATCH and REGEXP operators are implemented by the functions
.Fn sql_match
and
.Fn sql_regexp ,
respectively.
This is required because SQLite3 natively neither supports
case-insensitive substring matching nor regular expression matching,
but only string identity, shell globbing, and the weird home-brewed
LIKE operator.
.Pp
Command line parsing is done by the function Command line parsing is done by the function
.Fn exprcomp .Fn exprcomp
building a singly linked list of building a singly linked list of
.Vt expr .Vt expr
structures, using the helper functions structures, using the helper functions
.Fn exprterm .Fn expr_and
and and
.Fn exprspec . .Fn exprterm .
The resulting SQL statement is assembled by the function
.Fn sql_statement
and evaluated in the main loop of the
.Fn mansearch
function.
.Ss Assembling the results .Ss Assembling the results
The names, sections, and architectures of the manuals found The names, sections, and architectures of the manuals found
are assembled into the are assembled into the
.Va names .Va names
field of the result structure by the function field of the result structure by the function
.Fn buildnames , .Fn buildnames .
using the following query:
.Pp
.Dl "SELECT * FROM mlinks WHERE pageid=? ORDER BY sec, arch, name"
.Pp
If the
.Fa outkey
differs from
.Qq Ic \&Nd ,
the requested output data is assembled into the
.Va output
field of the result structure by the function
.Fn buildoutput ,
using the following query:
.Pp
.Dl "SELECT * FROM keys WHERE pageid=? AND bits & ?"
.Sh FILES .Sh FILES
.Bl -tag -width mandoc.db -compact .Bl -tag -width mandoc.db -compact
.It Pa mandoc.db .It Pa mandoc.db
The manual page database. The manual page database.
.El .El
.Sh EXAMPLES
The simplest invocation
.Pp
.Dl apropos keyword
.Pp
results in the following SQL query:
.Bd -literal
SELECT * FROM mpages WHERE (
id IN (SELECT pageid FROM names WHERE name MATCH 'keyword') OR
desc MATCH 'keyword'
);
.Ed
.Pp
A more complicated request like
.Pp
.Dl apropos -s 2 Nm,Xr=getuid
.Pp
results in:
.Bd -literal
SELECT * FROM mpages WHERE (
id IN (SELECT pageid FROM names WHERE name MATCH 'getuid') OR
id IN (SELECT pageid FROM keys WHERE key MATCH 'getuid' AND bits & 4)
) AND id IN (SELECT pageid FROM keys WHERE key REGEXP '^2$' AND bits & 2);
.Ed
.Sh SEE ALSO .Sh SEE ALSO
.Xr apropos 1 , .Xr apropos 1 ,
.Xr mandoc.db 5 , .Xr mandoc.db 5 ,
@ -223,6 +115,6 @@ subsystem first appeared in
A module to search manual page databases was first written by A module to search manual page databases was first written by
.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
in 2011, at first using the Berkeley DB; in 2011, at first using the Berkeley DB;
he rewrote it for SQLite3 in 2012. he rewrote it for SQLite3 in 2012, and
The current version received major changes from .An Ingo Schwarze Aq Mt schwarze@openbsd.org
.An Ingo Schwarze Aq Mt schwarze@openbsd.org . removed the dependency on SQLite3 in 2016.

View File

@ -1,7 +1,7 @@
/* $OpenBSD: mansearch.c,v 1.50 2016/07/09 15:23:36 schwarze Exp $ */ /* $OpenBSD: mansearch.c,v 1.50 2016/07/09 15:23:36 schwarze Exp $ */
/* /*
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015, 2016 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2013-2017 Ingo Schwarze <schwarze@openbsd.org>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -67,9 +67,9 @@ static struct ohash *manmerge_term(struct expr *, struct ohash *);
static struct ohash *manmerge_or(struct expr *, struct ohash *); static struct ohash *manmerge_or(struct expr *, struct ohash *);
static struct ohash *manmerge_and(struct expr *, struct ohash *); static struct ohash *manmerge_and(struct expr *, struct ohash *);
static char *buildnames(const struct dbm_page *); static char *buildnames(const struct dbm_page *);
static char *buildoutput(size_t, int32_t); static char *buildoutput(size_t, struct dbm_page *);
static size_t lstlen(const char *); static size_t lstlen(const char *, size_t);
static void lstcat(char *, size_t *, const char *); static void lstcat(char *, size_t *, const char *, const char *);
static int lstmatch(const char *, const char *); static int lstmatch(const char *, const char *);
static struct expr *exprcomp(const struct mansearch *, static struct expr *exprcomp(const struct mansearch *,
int, char *[], int *); int, char *[], int *);
@ -155,7 +155,8 @@ mansearch(const struct mansearch *search,
chdir_status = 1; chdir_status = 1;
if (dbm_open(MANDOC_DB) == -1) { if (dbm_open(MANDOC_DB) == -1) {
warn("%s/%s", paths->paths[i], MANDOC_DB); if (errno != ENOENT)
warn("%s/%s", paths->paths[i], MANDOC_DB);
continue; continue;
} }
@ -181,9 +182,7 @@ mansearch(const struct mansearch *search,
mandoc_asprintf(&mpage->file, "%s/%s", mandoc_asprintf(&mpage->file, "%s/%s",
paths->paths[i], page->file + 1); paths->paths[i], page->file + 1);
mpage->names = buildnames(page); mpage->names = buildnames(page);
mpage->output = (int)outkey == KEY_Nd ? mpage->output = buildoutput(outkey, page);
mandoc_strdup(page->desc) :
buildoutput(outkey, page->addr);
mpage->ipath = i; mpage->ipath = i;
mpage->bits = rp->bits; mpage->bits = rp->bits;
mpage->sec = *page->sect - '0'; mpage->sec = *page->sect - '0';
@ -404,16 +403,16 @@ buildnames(const struct dbm_page *page)
char *buf; char *buf;
size_t i, sz; size_t i, sz;
sz = lstlen(page->name) + 1 + lstlen(page->sect) + sz = lstlen(page->name, 2) + 1 + lstlen(page->sect, 2) +
(page->arch == NULL ? 0 : 1 + lstlen(page->arch)) + 2; (page->arch == NULL ? 0 : 1 + lstlen(page->arch, 2)) + 2;
buf = mandoc_malloc(sz); buf = mandoc_malloc(sz);
i = 0; i = 0;
lstcat(buf, &i, page->name); lstcat(buf, &i, page->name, ", ");
buf[i++] = '('; buf[i++] = '(';
lstcat(buf, &i, page->sect); lstcat(buf, &i, page->sect, ", ");
if (page->arch != NULL) { if (page->arch != NULL) {
buf[i++] = '/'; buf[i++] = '/';
lstcat(buf, &i, page->arch); lstcat(buf, &i, page->arch, ", ");
} }
buf[i++] = ')'; buf[i++] = ')';
buf[i++] = '\0'; buf[i++] = '\0';
@ -423,11 +422,11 @@ buildnames(const struct dbm_page *page)
/* /*
* Count the buffer space needed to print the NUL-terminated * Count the buffer space needed to print the NUL-terminated
* list of NUL-terminated strings, when printing two separator * list of NUL-terminated strings, when printing sep separator
* characters between strings. * characters between strings.
*/ */
static size_t static size_t
lstlen(const char *cp) lstlen(const char *cp, size_t sep)
{ {
size_t sz; size_t sz;
@ -435,7 +434,7 @@ lstlen(const char *cp)
if (cp[0] == '\0') { if (cp[0] == '\0') {
if (cp[1] == '\0') if (cp[1] == '\0')
break; break;
sz++; sz += sep - 1;
} else if (cp[0] < ' ') } else if (cp[0] < ' ')
sz--; sz--;
cp++; cp++;
@ -445,17 +444,20 @@ lstlen(const char *cp)
/* /*
* Print the NUL-terminated list of NUL-terminated strings * Print the NUL-terminated list of NUL-terminated strings
* into the buffer, seperating strings with a comma and a blank. * into the buffer, seperating strings with sep.
*/ */
static void static void
lstcat(char *buf, size_t *i, const char *cp) lstcat(char *buf, size_t *i, const char *cp, const char *sep)
{ {
const char *s;
for (;;) { for (;;) {
if (cp[0] == '\0') { if (cp[0] == '\0') {
if (cp[1] == '\0') if (cp[1] == '\0')
break; break;
buf[(*i)++] = ','; s = sep;
buf[(*i)++] = ' '; while (*s != '\0')
buf[(*i)++] = *s++;
} else if (cp[0] >= ' ') } else if (cp[0] >= ' ')
buf[(*i)++] = cp[0]; buf[(*i)++] = cp[0];
cp++; cp++;
@ -482,17 +484,46 @@ lstmatch(const char *want, const char *have)
} }
/* /*
* Build a list of values taken by the macro im * Build a list of values taken by the macro im in the manual page.
* in the manual page with big-endian address addr.
*/ */
static char * static char *
buildoutput(size_t im, int32_t addr) buildoutput(size_t im, struct dbm_page *page)
{ {
const char *oldoutput, *sep; const char *oldoutput, *sep, *input;
char *output, *newoutput, *value; char *output, *newoutput, *value;
size_t sz, i;
switch (im) {
case KEY_Nd:
return mandoc_strdup(page->desc);
case KEY_Nm:
input = page->name;
break;
case KEY_sec:
input = page->sect;
break;
case KEY_arch:
input = page->arch;
if (input == NULL)
input = "all\0";
break;
default:
input = NULL;
break;
}
if (input != NULL) {
sz = lstlen(input, 3) + 1;
output = mandoc_malloc(sz);
i = 0;
lstcat(output, &i, input, " # ");
output[i++] = '\0';
assert(i == sz);
return output;
}
output = NULL; output = NULL;
dbm_macro_bypage(im - 2, addr); dbm_macro_bypage(im - 2, page->addr);
while ((value = dbm_macro_next()) != NULL) { while ((value = dbm_macro_next()) != NULL) {
if (output == NULL) { if (output == NULL) {
oldoutput = ""; oldoutput = "";
@ -642,6 +673,12 @@ exprterm(const struct mansearch *search, int argc, char *argv[], int *argi)
return e; return e;
} }
if (strcmp("-i", argv[*argi]) == 0 && *argi + 1 < argc) {
cs = 0;
++*argi;
} else
cs = 1;
e = mandoc_calloc(1, sizeof(*e)); e = mandoc_calloc(1, sizeof(*e));
e->type = EXPR_TERM; e->type = EXPR_TERM;
e->bits = 0; e->bits = 0;

View File

@ -1,7 +1,7 @@
/* $Id: mansearch.h,v 1.27 2016/08/01 12:31:00 schwarze Exp $ */ /* $Id: mansearch.h,v 1.28 2017/04/17 20:05:08 schwarze Exp $ */
/* /*
* Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2016 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2013, 2014, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -21,6 +21,9 @@
#define MANDOCDB_VERSION 1 #define MANDOCDB_VERSION 1
#define MACRO_MAX 36 #define MACRO_MAX 36
#define KEY_arch 0
#define KEY_sec 1
#define KEY_Nm 38
#define KEY_Nd 39 #define KEY_Nd 39
#define KEY_MAX 40 #define KEY_MAX 40

31
mdoc.7
View File

@ -1,4 +1,4 @@
.\" $Id: mdoc.7,v 1.262 2017/02/16 14:38:12 schwarze Exp $ .\" $Id: mdoc.7,v 1.264 2017/05/05 15:54:59 schwarze Exp $
.\" .\"
.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2010, 2011, 2013-2017 Ingo Schwarze <schwarze@openbsd.org> .\" Copyright (c) 2010, 2011, 2013-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: February 16 2017 $ .Dd $Mdocdate: May 5 2017 $
.Dt MDOC 7 .Dt MDOC 7
.Os .Os
.Sh NAME .Sh NAME
@ -476,8 +476,6 @@ in the alphabetical
.It Sx \&Ap Ta apostrophe without surrounding whitespace (no arguments) .It Sx \&Ap Ta apostrophe without surrounding whitespace (no arguments)
.It Sx \&Sm Ta switch horizontal spacing mode: Op Cm on | off .It Sx \&Sm Ta switch horizontal spacing mode: Op Cm on | off
.It Sx \&Bk , \&Ek Ta keep block: Fl words .It Sx \&Bk , \&Ek Ta keep block: Fl words
.It Sx \&br Ta force output line break in text mode (no arguments)
.It Sx \&sp Ta force vertical space: Op Ar height
.El .El
.Ss Semantic markup for command line utilities: .Ss Semantic markup for command line utilities:
.Bl -column "Brq, Bro, Brc" description .Bl -column "Brq, Bro, Brc" description
@ -2736,29 +2734,6 @@ Examples:
.Dl \&.Xr mandoc 1 .Dl \&.Xr mandoc 1
.Dl \&.Xr mandoc 1 \&; .Dl \&.Xr mandoc 1 \&;
.Dl \&.Xr mandoc 1 \&Ns s behaviour .Dl \&.Xr mandoc 1 \&Ns s behaviour
.Ss \&br
Emits a line-break.
This macro should not be used; it is implemented for compatibility with
historical manuals.
.Pp
Consider using
.Sx \&Pp
in the event of natural paragraph breaks.
.Ss \&sp
Emits vertical space.
This macro should not be used; it is implemented for compatibility with
historical manuals.
Its syntax is as follows:
.Pp
.D1 Pf \. Sx \&sp Op Ar height
.Pp
The
.Ar height
argument is a scaling width as described in
.Xr roff 7 .
If unspecified,
.Sx \&sp
asserts a single vertical space.
.Sh MACRO SYNTAX .Sh MACRO SYNTAX
The syntax of a macro depends on its classification. The syntax of a macro depends on its classification.
In this section, In this section,
@ -3043,8 +3018,6 @@ then the macro accepts an arbitrary number of arguments.
.It Sx \&Va Ta Yes Ta Yes Ta n .It Sx \&Va Ta Yes Ta Yes Ta n
.It Sx \&Vt Ta Yes Ta Yes Ta >0 .It Sx \&Vt Ta Yes Ta Yes Ta >0
.It Sx \&Xr Ta Yes Ta Yes Ta 2 .It Sx \&Xr Ta Yes Ta Yes Ta 2
.It Sx \&br Ta \&No Ta \&No Ta 0
.It Sx \&sp Ta \&No Ta \&No Ta 1
.El .El
.Ss Delimiters .Ss Delimiters
When a macro argument consists of one single input character When a macro argument consists of one single input character

105
mdoc.c
View File

@ -1,4 +1,4 @@
/* $Id: mdoc.c,v 1.260 2017/02/16 03:00:23 schwarze Exp $ */ /* $Id: mdoc.c,v 1.266 2017/06/07 20:58:49 schwarze Exp $ */
/* /*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * 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-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -35,41 +35,6 @@
#include "roff_int.h" #include "roff_int.h"
#include "libmdoc.h" #include "libmdoc.h"
const char *const __mdoc_macronames[MDOC_MAX + 1] = {
"text",
"Ap", "Dd", "Dt", "Os",
"Sh", "Ss", "Pp", "D1",
"Dl", "Bd", "Ed", "Bl",
"El", "It", "Ad", "An",
"Ar", "Cd", "Cm", "Dv",
"Er", "Ev", "Ex", "Fa",
"Fd", "Fl", "Fn", "Ft",
"Ic", "In", "Li", "Nd",
"Nm", "Op", "Ot", "Pa",
"Rv", "St", "Va", "Vt",
"Xr", "%A", "%B", "%D",
"%I", "%J", "%N", "%O",
"%P", "%R", "%T", "%V",
"Ac", "Ao", "Aq", "At",
"Bc", "Bf", "Bo", "Bq",
"Bsx", "Bx", "Db", "Dc",
"Do", "Dq", "Ec", "Ef",
"Em", "Eo", "Fx", "Ms",
"No", "Ns", "Nx", "Ox",
"Pc", "Pf", "Po", "Pq",
"Qc", "Ql", "Qo", "Qq",
"Re", "Rs", "Sc", "So",
"Sq", "Sm", "Sx", "Sy",
"Tn", "Ux", "Xc", "Xo",
"Fo", "Fc", "Oo", "Oc",
"Bk", "Ek", "Bt", "Hf",
"Fr", "Ud", "Lb", "Lp",
"Lk", "Mt", "Brq", "Bro",
"Brc", "%C", "Es", "En",
"Dx", "%Q", "br", "sp",
"%U", "Ta", "ll",
};
const char *const __mdoc_argnames[MDOC_ARG_MAX] = { const char *const __mdoc_argnames[MDOC_ARG_MAX] = {
"split", "nosplit", "ragged", "split", "nosplit", "ragged",
"unfilled", "literal", "file", "unfilled", "literal", "file",
@ -80,9 +45,7 @@ const char *const __mdoc_argnames[MDOC_ARG_MAX] = {
"width", "compact", "std", "width", "compact", "std",
"filled", "words", "emphasis", "filled", "words", "emphasis",
"symbolic", "nested", "centered" "symbolic", "nested", "centered"
}; };
const char * const *mdoc_macronames = __mdoc_macronames + 1;
const char * const *mdoc_argnames = __mdoc_argnames; const char * const *mdoc_argnames = __mdoc_argnames;
static int mdoc_ptext(struct roff_man *, int, char *, int); static int mdoc_ptext(struct roff_man *, int, char *, int);
@ -119,13 +82,12 @@ mdoc_parseln(struct roff_man *mdoc, int ln, char *buf, int offs)
void void
mdoc_macro(MACRO_PROT_ARGS) mdoc_macro(MACRO_PROT_ARGS)
{ {
assert(tok > TOKEN_NONE && tok < MDOC_MAX); assert(tok >= MDOC_Dd && tok < MDOC_MAX);
(*mdoc_macros[tok].fp)(mdoc, tok, line, ppos, pos, buf); (*mdoc_macros[tok].fp)(mdoc, tok, line, ppos, pos, buf);
} }
void void
mdoc_tail_alloc(struct roff_man *mdoc, int line, int pos, int tok) mdoc_tail_alloc(struct roff_man *mdoc, int line, int pos, enum roff_tok tok)
{ {
struct roff_node *p; struct roff_node *p;
@ -135,8 +97,8 @@ mdoc_tail_alloc(struct roff_man *mdoc, int line, int pos, int tok)
} }
struct roff_node * struct roff_node *
mdoc_endbody_alloc(struct roff_man *mdoc, int line, int pos, int tok, mdoc_endbody_alloc(struct roff_man *mdoc, int line, int pos,
struct roff_node *body) enum roff_tok tok, struct roff_node *body)
{ {
struct roff_node *p; struct roff_node *p;
@ -153,7 +115,7 @@ mdoc_endbody_alloc(struct roff_man *mdoc, int line, int pos, int tok,
struct roff_node * struct roff_node *
mdoc_block_alloc(struct roff_man *mdoc, int line, int pos, mdoc_block_alloc(struct roff_man *mdoc, int line, int pos,
int tok, struct mdoc_arg *args) enum roff_tok tok, struct mdoc_arg *args)
{ {
struct roff_node *p; struct roff_node *p;
@ -180,7 +142,7 @@ mdoc_block_alloc(struct roff_man *mdoc, int line, int pos,
void void
mdoc_elem_alloc(struct roff_man *mdoc, int line, int pos, mdoc_elem_alloc(struct roff_man *mdoc, int line, int pos,
int tok, struct mdoc_arg *args) enum roff_tok tok, struct mdoc_arg *args)
{ {
struct roff_node *p; struct roff_node *p;
@ -291,7 +253,7 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
* blank lines aren't allowed, but enough manuals assume this * blank lines aren't allowed, but enough manuals assume this
* behaviour that we want to work around it. * behaviour that we want to work around it.
*/ */
roff_elem_alloc(mdoc, line, offs, MDOC_sp); roff_elem_alloc(mdoc, line, offs, ROFF_sp);
mdoc->last->flags |= NODE_VALID | NODE_ENDED; mdoc->last->flags |= NODE_VALID | NODE_ENDED;
mdoc->next = ROFF_NEXT_SIBLING; mdoc->next = ROFF_NEXT_SIBLING;
return 1; return 1;
@ -316,14 +278,20 @@ mdoc_ptext(struct roff_man *mdoc, int line, char *buf, int offs)
for (c = buf + offs; c != NULL; c = strchr(c + 1, '.')) { for (c = buf + offs; c != NULL; c = strchr(c + 1, '.')) {
if (c - buf < offs + 2) if (c - buf < offs + 2)
continue; continue;
if (end - c < 4) if (end - c < 3)
break; break;
if (isalpha((unsigned char)c[-2]) && if (c[1] != ' ' ||
isalpha((unsigned char)c[-1]) && isalpha((unsigned char)c[-2]) == 0 ||
c[1] == ' ' && isalpha((unsigned char)c[-1]) == 0 ||
isupper((unsigned char)(c[2] == ' ' ? c[3] : c[2])) && (c[-2] == 'n' && c[-1] == 'c') ||
(c[-2] != 'n' || c[-1] != 'c') && (c[-2] == 'v' && c[-1] == 's'))
(c[-2] != 'v' || c[-1] != 's')) continue;
c += 2;
if (*c == ' ')
c++;
if (*c == ' ')
c++;
if (isupper((unsigned char)(*c)))
mandoc_msg(MANDOCERR_EOS, mdoc->parse, mandoc_msg(MANDOCERR_EOS, mdoc->parse,
line, (int)(c - buf), NULL); line, (int)(c - buf), NULL);
} }
@ -340,25 +308,18 @@ mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs)
{ {
struct roff_node *n; struct roff_node *n;
const char *cp; const char *cp;
int tok; size_t sz;
int i, sv; enum roff_tok tok;
char mac[5]; int sv;
/* Determine the line macro. */
sv = offs; sv = offs;
tok = TOKEN_NONE;
/* for (sz = 0; sz < 4 && strchr(" \t\\", buf[offs]) == NULL; sz++)
* Copy the first word into a nil-terminated buffer. offs++;
* Stop when a space, tab, escape, or eoln is encountered. if (sz == 2 || sz == 3)
*/ tok = roffhash_find(mdoc->mdocmac, buf + sv, sz);
i = 0;
while (i < 4 && strchr(" \t\\", buf[offs]) == NULL)
mac[i++] = buf[offs++];
mac[i] = '\0';
tok = (i > 1 && i < 4) ? mdoc_hash_find(mac) : TOKEN_NONE;
if (tok == TOKEN_NONE) { if (tok == TOKEN_NONE) {
mandoc_msg(MANDOCERR_MACRO, mdoc->parse, mandoc_msg(MANDOCERR_MACRO, mdoc->parse,
ln, sv, buf + sv - 1); ln, sv, buf + sv - 1);
@ -382,7 +343,7 @@ mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs)
/* Jump to the next non-whitespace word. */ /* Jump to the next non-whitespace word. */
while (buf[offs] && ' ' == buf[offs]) while (buf[offs] == ' ')
offs++; offs++;
/* /*

131
mdoc.h
View File

@ -1,4 +1,4 @@
/* $Id: mdoc.h,v 1.144 2015/11/07 14:01:16 schwarze Exp $ */ /* $Id: mdoc.h,v 1.145 2017/04/24 23:06:18 schwarze Exp $ */
/* /*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -16,131 +16,6 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#define MDOC_Ap 0
#define MDOC_Dd 1
#define MDOC_Dt 2
#define MDOC_Os 3
#define MDOC_Sh 4
#define MDOC_Ss 5
#define MDOC_Pp 6
#define MDOC_D1 7
#define MDOC_Dl 8
#define MDOC_Bd 9
#define MDOC_Ed 10
#define MDOC_Bl 11
#define MDOC_El 12
#define MDOC_It 13
#define MDOC_Ad 14
#define MDOC_An 15
#define MDOC_Ar 16
#define MDOC_Cd 17
#define MDOC_Cm 18
#define MDOC_Dv 19
#define MDOC_Er 20
#define MDOC_Ev 21
#define MDOC_Ex 22
#define MDOC_Fa 23
#define MDOC_Fd 24
#define MDOC_Fl 25
#define MDOC_Fn 26
#define MDOC_Ft 27
#define MDOC_Ic 28
#define MDOC_In 29
#define MDOC_Li 30
#define MDOC_Nd 31
#define MDOC_Nm 32
#define MDOC_Op 33
#define MDOC_Ot 34
#define MDOC_Pa 35
#define MDOC_Rv 36
#define MDOC_St 37
#define MDOC_Va 38
#define MDOC_Vt 39
#define MDOC_Xr 40
#define MDOC__A 41
#define MDOC__B 42
#define MDOC__D 43
#define MDOC__I 44
#define MDOC__J 45
#define MDOC__N 46
#define MDOC__O 47
#define MDOC__P 48
#define MDOC__R 49
#define MDOC__T 50
#define MDOC__V 51
#define MDOC_Ac 52
#define MDOC_Ao 53
#define MDOC_Aq 54
#define MDOC_At 55
#define MDOC_Bc 56
#define MDOC_Bf 57
#define MDOC_Bo 58
#define MDOC_Bq 59
#define MDOC_Bsx 60
#define MDOC_Bx 61
#define MDOC_Db 62
#define MDOC_Dc 63
#define MDOC_Do 64
#define MDOC_Dq 65
#define MDOC_Ec 66
#define MDOC_Ef 67
#define MDOC_Em 68
#define MDOC_Eo 69
#define MDOC_Fx 70
#define MDOC_Ms 71
#define MDOC_No 72
#define MDOC_Ns 73
#define MDOC_Nx 74
#define MDOC_Ox 75
#define MDOC_Pc 76
#define MDOC_Pf 77
#define MDOC_Po 78
#define MDOC_Pq 79
#define MDOC_Qc 80
#define MDOC_Ql 81
#define MDOC_Qo 82
#define MDOC_Qq 83
#define MDOC_Re 84
#define MDOC_Rs 85
#define MDOC_Sc 86
#define MDOC_So 87
#define MDOC_Sq 88
#define MDOC_Sm 89
#define MDOC_Sx 90
#define MDOC_Sy 91
#define MDOC_Tn 92
#define MDOC_Ux 93
#define MDOC_Xc 94
#define MDOC_Xo 95
#define MDOC_Fo 96
#define MDOC_Fc 97
#define MDOC_Oo 98
#define MDOC_Oc 99
#define MDOC_Bk 100
#define MDOC_Ek 101
#define MDOC_Bt 102
#define MDOC_Hf 103
#define MDOC_Fr 104
#define MDOC_Ud 105
#define MDOC_Lb 106
#define MDOC_Lp 107
#define MDOC_Lk 108
#define MDOC_Mt 109
#define MDOC_Brq 110
#define MDOC_Bro 111
#define MDOC_Brc 112
#define MDOC__C 113
#define MDOC_Es 114
#define MDOC_En 115
#define MDOC_Dx 116
#define MDOC__Q 117
#define MDOC_br 118
#define MDOC_sp 119
#define MDOC__U 120
#define MDOC_Ta 121
#define MDOC_ll 122
#define MDOC_MAX 123
enum mdocargt { enum mdocargt {
MDOC_Split, /* -split */ MDOC_Split, /* -split */
MDOC_Nosplit, /* -nospli */ MDOC_Nosplit, /* -nospli */
@ -274,11 +149,7 @@ union mdoc_data {
struct mdoc_rs Rs; struct mdoc_rs Rs;
}; };
/* Names of macros. */
extern const char *const *mdoc_macronames;
/* Names of macro args. Index is enum mdocargt. */ /* Names of macro args. Index is enum mdocargt. */
extern const char *const *mdoc_argnames; extern const char *const *mdoc_argnames;
void mdoc_validate(struct roff_man *); void mdoc_validate(struct roff_man *);

View File

@ -1,7 +1,7 @@
/* $Id: mdoc_argv.c,v 1.109 2016/08/28 16:15:12 schwarze Exp $ */ /* $Id: mdoc_argv.c,v 1.115 2017/05/30 16:22:03 schwarze Exp $ */
/* /*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2012, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2012, 2014-2017 Ingo Schwarze <schwarze@openbsd.org>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -144,8 +144,7 @@ static const enum mdocargt args_Bl[] = {
MDOC_ARG_MAX MDOC_ARG_MAX
}; };
static const struct mdocarg mdocargs[MDOC_MAX] = { static const struct mdocarg __mdocargs[MDOC_MAX - MDOC_Dd] = {
{ ARGSFL_DELIM, NULL }, /* Ap */
{ ARGSFL_NONE, NULL }, /* Dd */ { ARGSFL_NONE, NULL }, /* Dd */
{ ARGSFL_NONE, NULL }, /* Dt */ { ARGSFL_NONE, NULL }, /* Dt */
{ ARGSFL_NONE, NULL }, /* Os */ { ARGSFL_NONE, NULL }, /* Os */
@ -161,6 +160,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_NONE, NULL }, /* It */ { ARGSFL_NONE, NULL }, /* It */
{ ARGSFL_DELIM, NULL }, /* Ad */ { ARGSFL_DELIM, NULL }, /* Ad */
{ ARGSFL_DELIM, args_An }, /* An */ { ARGSFL_DELIM, args_An }, /* An */
{ ARGSFL_DELIM, NULL }, /* Ap */
{ ARGSFL_DELIM, NULL }, /* Ar */ { ARGSFL_DELIM, NULL }, /* Ar */
{ ARGSFL_DELIM, NULL }, /* Cd */ { ARGSFL_DELIM, NULL }, /* Cd */
{ ARGSFL_DELIM, NULL }, /* Cm */ { ARGSFL_DELIM, NULL }, /* Cm */
@ -263,12 +263,10 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_DELIM, NULL }, /* En */ { ARGSFL_DELIM, NULL }, /* En */
{ ARGSFL_DELIM, NULL }, /* Dx */ { ARGSFL_DELIM, NULL }, /* Dx */
{ ARGSFL_NONE, NULL }, /* %Q */ { ARGSFL_NONE, NULL }, /* %Q */
{ ARGSFL_NONE, NULL }, /* br */
{ ARGSFL_NONE, NULL }, /* sp */
{ ARGSFL_NONE, NULL }, /* %U */ { ARGSFL_NONE, NULL }, /* %U */
{ ARGSFL_NONE, NULL }, /* Ta */ { ARGSFL_NONE, NULL }, /* Ta */
{ ARGSFL_NONE, NULL }, /* ll */
}; };
static const struct mdocarg *const mdocargs = __mdocargs - MDOC_Dd;
/* /*
@ -277,7 +275,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
* Some flags take no argument, some one, some multiple. * Some flags take no argument, some one, some multiple.
*/ */
void void
mdoc_argv(struct roff_man *mdoc, int line, int tok, mdoc_argv(struct roff_man *mdoc, int line, enum roff_tok tok,
struct mdoc_arg **reta, int *pos, char *buf) struct mdoc_arg **reta, int *pos, char *buf)
{ {
struct mdoc_argv tmpv; struct mdoc_argv tmpv;
@ -291,6 +289,7 @@ mdoc_argv(struct roff_man *mdoc, int line, int tok,
/* Which flags does this macro support? */ /* Which flags does this macro support? */
assert(tok >= MDOC_Dd && tok < MDOC_MAX);
argtable = mdocargs[tok].argvs; argtable = mdocargs[tok].argvs;
if (argtable == NULL) if (argtable == NULL)
return; return;
@ -415,7 +414,7 @@ argn_free(struct mdoc_arg *p, int iarg)
enum margserr enum margserr
mdoc_args(struct roff_man *mdoc, int line, int *pos, mdoc_args(struct roff_man *mdoc, int line, int *pos,
char *buf, int tok, char **v) char *buf, enum roff_tok tok, char **v)
{ {
struct roff_node *n; struct roff_node *n;
char *v_local; char *v_local;
@ -424,8 +423,6 @@ mdoc_args(struct roff_man *mdoc, int line, int *pos,
if (v == NULL) if (v == NULL)
v = &v_local; v = &v_local;
fl = tok == TOKEN_NONE ? ARGSFL_NONE : mdocargs[tok].flags; fl = tok == TOKEN_NONE ? ARGSFL_NONE : mdocargs[tok].flags;
if (tok != MDOC_It)
return args(mdoc, line, pos, buf, fl, v);
/* /*
* We know that we're in an `It', so it's reasonable to expect * We know that we're in an `It', so it's reasonable to expect
@ -434,12 +431,15 @@ mdoc_args(struct roff_man *mdoc, int line, int *pos,
* safe fall-back into the default behaviour. * safe fall-back into the default behaviour.
*/ */
for (n = mdoc->last; n; n = n->parent) if (tok == MDOC_It) {
if (MDOC_Bl == n->tok) for (n = mdoc->last; n != NULL; n = n->parent) {
if (LIST_column == n->norm->Bl.type) { if (n->tok != MDOC_Bl)
continue;
if (n->norm->Bl.type == LIST_column)
fl = ARGSFL_TABSEP; fl = ARGSFL_TABSEP;
break; break;
} }
}
return args(mdoc, line, pos, buf, fl, v); return args(mdoc, line, pos, buf, fl, v);
} }
@ -555,14 +555,14 @@ args(struct roff_man *mdoc, int line, int *pos,
if ( ! (mdoc->flags & MDOC_PHRASE)) if ( ! (mdoc->flags & MDOC_PHRASE))
mandoc_msg(MANDOCERR_ARG_QUOTE, mandoc_msg(MANDOCERR_ARG_QUOTE,
mdoc->parse, line, *pos, NULL); mdoc->parse, line, *pos, NULL);
return ARGS_QWORD; return ARGS_WORD;
} }
mdoc->flags &= ~MDOC_PHRASELIT; mdoc->flags &= ~MDOC_PHRASELIT;
buf[(*pos)++] = '\0'; buf[(*pos)++] = '\0';
if ('\0' == buf[*pos]) if ('\0' == buf[*pos])
return ARGS_QWORD; return ARGS_WORD;
while (' ' == buf[*pos]) while (' ' == buf[*pos])
(*pos)++; (*pos)++;
@ -571,7 +571,7 @@ args(struct roff_man *mdoc, int line, int *pos,
mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse, mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
line, *pos, NULL); line, *pos, NULL);
return ARGS_QWORD; return ARGS_WORD;
} }
p = &buf[*pos]; p = &buf[*pos];

View File

@ -1,95 +0,0 @@
/* $Id: mdoc_hash.c,v 1.27 2016/07/15 18:03:45 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2015 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 <sys/types.h>
#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "mandoc.h"
#include "roff.h"
#include "mdoc.h"
#include "libmandoc.h"
#include "libmdoc.h"
static unsigned char table[27 * 12];
void
mdoc_hash_init(void)
{
int i, j, major;
const char *p;
if (*table != '\0')
return;
memset(table, UCHAR_MAX, sizeof(table));
for (i = 0; i < (int)MDOC_MAX; i++) {
p = mdoc_macronames[i];
if (isalpha((unsigned char)p[1]))
major = 12 * (tolower((unsigned char)p[1]) - 97);
else
major = 12 * 26;
for (j = 0; j < 12; j++)
if (UCHAR_MAX == table[major + j]) {
table[major + j] = (unsigned char)i;
break;
}
assert(j < 12);
}
}
int
mdoc_hash_find(const char *p)
{
int major, i, j;
if (0 == p[0])
return TOKEN_NONE;
if ( ! isalpha((unsigned char)p[0]) && '%' != p[0])
return TOKEN_NONE;
if (isalpha((unsigned char)p[1]))
major = 12 * (tolower((unsigned char)p[1]) - 97);
else if ('1' == p[1])
major = 12 * 26;
else
return TOKEN_NONE;
if (p[2] && p[3])
return TOKEN_NONE;
for (j = 0; j < 12; j++) {
if (UCHAR_MAX == (i = table[major + j]))
break;
if (0 == strcmp(p, mdoc_macronames[i]))
return i;
}
return TOKEN_NONE;
}

View File

@ -1,4 +1,4 @@
/* $Id: mdoc_html.c,v 1.271 2017/02/16 03:00:23 schwarze Exp $ */ /* $Id: mdoc_html.c,v 1.289 2017/05/30 16:31:29 schwarze Exp $ */
/* /*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -48,7 +48,7 @@ struct htmlmdoc {
void (*post)(MDOC_ARGS); void (*post)(MDOC_ARGS);
}; };
static char *make_id(const struct roff_node *); static char *cond_id(const struct roff_node *);
static void print_mdoc_head(MDOC_ARGS); static void print_mdoc_head(MDOC_ARGS);
static void print_mdoc_node(MDOC_ARGS); static void print_mdoc_node(MDOC_ARGS);
static void print_mdoc_nodelist(MDOC_ARGS); static void print_mdoc_nodelist(MDOC_ARGS);
@ -108,7 +108,6 @@ static int mdoc_rs_pre(MDOC_ARGS);
static int mdoc_sh_pre(MDOC_ARGS); static int mdoc_sh_pre(MDOC_ARGS);
static int mdoc_skip_pre(MDOC_ARGS); static int mdoc_skip_pre(MDOC_ARGS);
static int mdoc_sm_pre(MDOC_ARGS); static int mdoc_sm_pre(MDOC_ARGS);
static int mdoc_sp_pre(MDOC_ARGS);
static int mdoc_ss_pre(MDOC_ARGS); static int mdoc_ss_pre(MDOC_ARGS);
static int mdoc_st_pre(MDOC_ARGS); static int mdoc_st_pre(MDOC_ARGS);
static int mdoc_sx_pre(MDOC_ARGS); static int mdoc_sx_pre(MDOC_ARGS);
@ -118,8 +117,7 @@ static int mdoc_vt_pre(MDOC_ARGS);
static int mdoc_xr_pre(MDOC_ARGS); static int mdoc_xr_pre(MDOC_ARGS);
static int mdoc_xx_pre(MDOC_ARGS); static int mdoc_xx_pre(MDOC_ARGS);
static const struct htmlmdoc mdocs[MDOC_MAX] = { static const struct htmlmdoc __mdocs[MDOC_MAX - MDOC_Dd] = {
{mdoc_ap_pre, NULL}, /* Ap */
{NULL, NULL}, /* Dd */ {NULL, NULL}, /* Dd */
{NULL, NULL}, /* Dt */ {NULL, NULL}, /* Dt */
{NULL, NULL}, /* Os */ {NULL, NULL}, /* Os */
@ -135,6 +133,7 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = {
{mdoc_it_pre, NULL}, /* It */ {mdoc_it_pre, NULL}, /* It */
{mdoc_ad_pre, NULL}, /* Ad */ {mdoc_ad_pre, NULL}, /* Ad */
{mdoc_an_pre, NULL}, /* An */ {mdoc_an_pre, NULL}, /* An */
{mdoc_ap_pre, NULL}, /* Ap */
{mdoc_ar_pre, NULL}, /* Ar */ {mdoc_ar_pre, NULL}, /* Ar */
{mdoc_cd_pre, NULL}, /* Cd */ {mdoc_cd_pre, NULL}, /* Cd */
{mdoc_cm_pre, NULL}, /* Cm */ {mdoc_cm_pre, NULL}, /* Cm */
@ -237,12 +236,10 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = {
{mdoc_quote_pre, mdoc_quote_post}, /* En */ {mdoc_quote_pre, mdoc_quote_post}, /* En */
{mdoc_xx_pre, NULL}, /* Dx */ {mdoc_xx_pre, NULL}, /* Dx */
{mdoc__x_pre, mdoc__x_post}, /* %Q */ {mdoc__x_pre, mdoc__x_post}, /* %Q */
{mdoc_sp_pre, NULL}, /* br */
{mdoc_sp_pre, NULL}, /* sp */
{mdoc__x_pre, mdoc__x_post}, /* %U */ {mdoc__x_pre, mdoc__x_post}, /* %U */
{NULL, NULL}, /* Ta */ {NULL, NULL}, /* Ta */
{mdoc_skip_pre, NULL}, /* ll */
}; };
static const struct htmlmdoc *const mdocs = __mdocs - MDOC_Dd;
/* /*
@ -362,9 +359,9 @@ print_mdoc_node(MDOC_ARGS)
* Make sure that if we're in a literal mode already * Make sure that if we're in a literal mode already
* (i.e., within a <PRE>) don't print the newline. * (i.e., within a <PRE>) don't print the newline.
*/ */
if (' ' == *n->string && NODE_LINE & n->flags) if (*n->string == ' ' && n->flags & NODE_LINE &&
if ( ! (HTML_LITERAL & h->flags)) (h->flags & (HTML_LITERAL | HTML_NONEWLINE)) == 0)
print_otag(h, TAG_BR, ""); print_otag(h, TAG_BR, "");
if (NODE_DELIMC & n->flags) if (NODE_DELIMC & n->flags)
h->flags |= HTML_NOSPACE; h->flags |= HTML_NOSPACE;
print_text(h, n->string); print_text(h, n->string);
@ -393,7 +390,14 @@ print_mdoc_node(MDOC_ARGS)
t = h->tag; t = h->tag;
} }
assert(h->tblt == NULL); assert(h->tblt == NULL);
if (mdocs[n->tok].pre && (n->end == ENDBODY_NOT || n->child)) if (n->tok < ROFF_MAX) {
roff_html_pre(h, n);
child = 0;
break;
}
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
if (mdocs[n->tok].pre != NULL &&
(n->end == ENDBODY_NOT || n->child != NULL))
child = (*mdocs[n->tok].pre)(meta, n, h); child = (*mdocs[n->tok].pre)(meta, n, h);
break; break;
} }
@ -412,7 +416,9 @@ print_mdoc_node(MDOC_ARGS)
case ROFFT_EQN: case ROFFT_EQN:
break; break;
default: default:
if ( ! mdocs[n->tok].post || n->flags & NODE_ENDED) if (n->tok < ROFF_MAX ||
mdocs[n->tok].post == NULL ||
n->flags & NODE_ENDED)
break; break;
(*mdocs[n->tok].post)(meta, n, h); (*mdocs[n->tok].post)(meta, n, h);
if (n->end != ENDBODY_NOT) if (n->end != ENDBODY_NOT)
@ -477,25 +483,19 @@ mdoc_root_pre(MDOC_ARGS)
} }
static char * static char *
make_id(const struct roff_node *n) cond_id(const struct roff_node *n)
{ {
const struct roff_node *nch; if (n->child != NULL &&
char *buf, *cp; n->child->type == ROFFT_TEXT &&
(n->prev == NULL ||
for (nch = n->child; nch != NULL; nch = nch->next) (n->prev->type == ROFFT_TEXT &&
if (nch->type != ROFFT_TEXT) strcmp(n->prev->string, "|") == 0)) &&
return NULL; (n->parent->tok == MDOC_It ||
(n->parent->tok == MDOC_Xo &&
buf = NULL; n->parent->parent->prev == NULL &&
deroff(&buf, n); n->parent->parent->parent->tok == MDOC_It)))
return html_make_id(n);
/* http://www.w3.org/TR/html5/dom.html#the-id-attribute */ return NULL;
for (cp = buf; *cp != '\0'; cp++)
if (*cp == ' ')
*cp = '_';
return buf;
} }
static int static int
@ -505,8 +505,10 @@ mdoc_sh_pre(MDOC_ARGS)
switch (n->type) { switch (n->type) {
case ROFFT_HEAD: case ROFFT_HEAD:
id = make_id(n); id = html_make_id(n);
print_otag(h, TAG_H1, "ci", "Sh", id); print_otag(h, TAG_H1, "cTi", "Sh", id);
if (id != NULL)
print_otag(h, TAG_A, "chR", "selflink", id);
free(id); free(id);
break; break;
case ROFFT_BODY: case ROFFT_BODY:
@ -527,8 +529,10 @@ mdoc_ss_pre(MDOC_ARGS)
if (n->type != ROFFT_HEAD) if (n->type != ROFFT_HEAD)
return 1; return 1;
id = make_id(n); id = html_make_id(n);
print_otag(h, TAG_H2, "ci", "Ss", id); print_otag(h, TAG_H2, "cTi", "Ss", id);
if (id != NULL)
print_otag(h, TAG_A, "chR", "selflink", id);
free(id); free(id);
return 1; return 1;
} }
@ -536,9 +540,14 @@ mdoc_ss_pre(MDOC_ARGS)
static int static int
mdoc_fl_pre(MDOC_ARGS) mdoc_fl_pre(MDOC_ARGS)
{ {
print_otag(h, TAG_B, "c", "Fl"); char *id;
print_text(h, "\\-");
if ((id = cond_id(n)) != NULL)
print_otag(h, TAG_A, "chR", "selflink", id);
print_otag(h, TAG_B, "cTi", "Fl", id);
free(id);
print_text(h, "\\-");
if (!(n->child == NULL && if (!(n->child == NULL &&
(n->next == NULL || (n->next == NULL ||
n->next->type == ROFFT_TEXT || n->next->type == ROFFT_TEXT ||
@ -551,7 +560,12 @@ mdoc_fl_pre(MDOC_ARGS)
static int static int
mdoc_cm_pre(MDOC_ARGS) mdoc_cm_pre(MDOC_ARGS)
{ {
print_otag(h, TAG_B, "c", "Cm"); char *id;
if ((id = cond_id(n)) != NULL)
print_otag(h, TAG_A, "chR", "selflink", id);
print_otag(h, TAG_B, "cTi", "Cm", id);
free(id);
return 1; return 1;
} }
@ -564,22 +578,19 @@ mdoc_nd_pre(MDOC_ARGS)
/* XXX: this tag in theory can contain block elements. */ /* XXX: this tag in theory can contain block elements. */
print_text(h, "\\(em"); print_text(h, "\\(em");
print_otag(h, TAG_SPAN, "c", "Nd"); print_otag(h, TAG_SPAN, "cT", "Nd");
return 1; return 1;
} }
static int static int
mdoc_nm_pre(MDOC_ARGS) mdoc_nm_pre(MDOC_ARGS)
{ {
struct tag *t;
int len;
switch (n->type) { switch (n->type) {
case ROFFT_HEAD: case ROFFT_HEAD:
print_otag(h, TAG_TD, ""); print_otag(h, TAG_TD, "");
/* FALLTHROUGH */ /* FALLTHROUGH */
case ROFFT_ELEM: case ROFFT_ELEM:
print_otag(h, TAG_B, "c", "Nm"); print_otag(h, TAG_B, "cT", "Nm");
return 1; return 1;
case ROFFT_BODY: case ROFFT_BODY:
print_otag(h, TAG_TD, ""); print_otag(h, TAG_TD, "");
@ -587,21 +598,8 @@ mdoc_nm_pre(MDOC_ARGS)
default: default:
break; break;
} }
synopsis_pre(h, n); synopsis_pre(h, n);
print_otag(h, TAG_TABLE, "c", "Nm"); print_otag(h, TAG_TABLE, "c", "Nm");
for (len = 0, n = n->head->child; n; n = n->next)
if (n->type == ROFFT_TEXT)
len += html_strlen(n->string);
if (len == 0 && meta->name != NULL)
len = html_strlen(meta->name);
t = print_otag(h, TAG_COLGROUP, "");
print_otag(h, TAG_COL, "shw", len);
print_otag(h, TAG_COL, "");
print_tagq(h, t);
print_otag(h, TAG_TR, ""); print_otag(h, TAG_TR, "");
return 1; return 1;
} }
@ -613,11 +611,11 @@ mdoc_xr_pre(MDOC_ARGS)
return 0; return 0;
if (h->base_man) if (h->base_man)
print_otag(h, TAG_A, "chM", "Xr", print_otag(h, TAG_A, "cThM", "Xr",
n->child->string, n->child->next == NULL ? n->child->string, n->child->next == NULL ?
NULL : n->child->next->string); NULL : n->child->next->string);
else else
print_otag(h, TAG_A, "c", "Xr"); print_otag(h, TAG_A, "cT", "Xr");
n = n->child; n = n->child;
print_text(h, n->string); print_text(h, n->string);
@ -646,7 +644,7 @@ mdoc_ns_pre(MDOC_ARGS)
static int static int
mdoc_ar_pre(MDOC_ARGS) mdoc_ar_pre(MDOC_ARGS)
{ {
print_otag(h, TAG_VAR, "c", "Ar"); print_otag(h, TAG_VAR, "cT", "Ar");
return 1; return 1;
} }
@ -666,7 +664,7 @@ mdoc_it_pre(MDOC_ARGS)
enum mdoc_list type; enum mdoc_list type;
bl = n->parent; bl = n->parent;
while (bl != NULL && bl->tok != MDOC_Bl) while (bl->tok != MDOC_Bl)
bl = bl->parent; bl = bl->parent;
type = bl->norm->Bl.type; type = bl->norm->Bl.type;
@ -751,8 +749,9 @@ mdoc_it_pre(MDOC_ARGS)
case ROFFT_HEAD: case ROFFT_HEAD:
if (h->style != NULL && !bl->norm->Bl.comp && if (h->style != NULL && !bl->norm->Bl.comp &&
(n->parent->prev == NULL || (n->parent->prev == NULL ||
n->parent->prev->body == NULL ||
n->parent->prev->body->child != NULL)) { n->parent->prev->body->child != NULL)) {
t = print_otag(h, TAG_DT, "csWl", t = print_otag(h, TAG_DT, "csw+-l",
cattr, bl->norm->Bl.width); cattr, bl->norm->Bl.width);
print_text(h, "\\ "); print_text(h, "\\ ");
print_tagq(h, t); print_tagq(h, t);
@ -760,7 +759,7 @@ mdoc_it_pre(MDOC_ARGS)
print_text(h, "\\ "); print_text(h, "\\ ");
print_tagq(h, t); print_tagq(h, t);
} }
print_otag(h, TAG_DT, "csWl", cattr, print_otag(h, TAG_DT, "csw+-l", cattr,
bl->norm->Bl.width); bl->norm->Bl.width);
break; break;
case ROFFT_BODY: case ROFFT_BODY:
@ -823,7 +822,7 @@ mdoc_bl_pre(MDOC_ARGS)
t = print_otag(h, TAG_COLGROUP, ""); t = print_otag(h, TAG_COLGROUP, "");
for (i = 0; i < bl->ncols - 1; i++) for (i = 0; i < bl->ncols - 1; i++)
print_otag(h, TAG_COL, "sww", bl->cols[i]); print_otag(h, TAG_COL, "sw+w", bl->cols[i]);
print_otag(h, TAG_COL, "swW", bl->cols[i]); print_otag(h, TAG_COL, "swW", bl->cols[i]);
print_tagq(h, t); print_tagq(h, t);
return 0; return 0;
@ -870,7 +869,7 @@ mdoc_bl_pre(MDOC_ARGS)
cattr = "Bl-tag"; cattr = "Bl-tag";
if (bl->offs) if (bl->offs)
print_otag(h, TAG_DIV, "cswl", cattr, bl->offs); print_otag(h, TAG_DIV, "cswl", cattr, bl->offs);
print_otag(h, TAG_DL, "cswl", cattr, bl->width); print_otag(h, TAG_DL, "csw+l", cattr, bl->width);
return 1; return 1;
case LIST_column: case LIST_column:
elemtype = TAG_TABLE; elemtype = TAG_TABLE;
@ -894,14 +893,14 @@ mdoc_ex_pre(MDOC_ARGS)
static int static int
mdoc_st_pre(MDOC_ARGS) mdoc_st_pre(MDOC_ARGS)
{ {
print_otag(h, TAG_SPAN, "c", "St"); print_otag(h, TAG_SPAN, "cT", "St");
return 1; return 1;
} }
static int static int
mdoc_em_pre(MDOC_ARGS) mdoc_em_pre(MDOC_ARGS)
{ {
print_otag(h, TAG_I, "c", "Em"); print_otag(h, TAG_I, "cT", "Em");
return 1; return 1;
} }
@ -924,8 +923,8 @@ mdoc_sx_pre(MDOC_ARGS)
{ {
char *id; char *id;
id = make_id(n); id = html_make_id(n);
print_otag(h, TAG_A, "chR", "Sx", id); print_otag(h, TAG_A, "cThR", "Sx", id);
free(id); free(id);
return 1; return 1;
} }
@ -991,9 +990,9 @@ mdoc_bd_pre(MDOC_ARGS)
* anyway, so don't sweat it. * anyway, so don't sweat it.
*/ */
switch (nn->tok) { switch (nn->tok) {
case ROFF_br:
case ROFF_sp:
case MDOC_Sm: case MDOC_Sm:
case MDOC_br:
case MDOC_sp:
case MDOC_Bl: case MDOC_Bl:
case MDOC_D1: case MDOC_D1:
case MDOC_Dl: case MDOC_Dl:
@ -1021,7 +1020,7 @@ mdoc_bd_pre(MDOC_ARGS)
static int static int
mdoc_pa_pre(MDOC_ARGS) mdoc_pa_pre(MDOC_ARGS)
{ {
print_otag(h, TAG_I, "c", "Pa"); print_otag(h, TAG_I, "cT", "Pa");
return 1; return 1;
} }
@ -1052,7 +1051,7 @@ mdoc_an_pre(MDOC_ARGS)
if (n->sec == SEC_AUTHORS && ! (h->flags & HTML_NOSPLIT)) if (n->sec == SEC_AUTHORS && ! (h->flags & HTML_NOSPLIT))
h->flags |= HTML_SPLIT; h->flags |= HTML_SPLIT;
print_otag(h, TAG_SPAN, "c", "An"); print_otag(h, TAG_SPAN, "cT", "An");
return 1; return 1;
} }
@ -1060,28 +1059,49 @@ static int
mdoc_cd_pre(MDOC_ARGS) mdoc_cd_pre(MDOC_ARGS)
{ {
synopsis_pre(h, n); synopsis_pre(h, n);
print_otag(h, TAG_B, "c", "Cd"); print_otag(h, TAG_B, "cT", "Cd");
return 1; return 1;
} }
static int static int
mdoc_dv_pre(MDOC_ARGS) mdoc_dv_pre(MDOC_ARGS)
{ {
print_otag(h, TAG_CODE, "c", "Dv"); char *id;
if ((id = cond_id(n)) != NULL)
print_otag(h, TAG_A, "chR", "selflink", id);
print_otag(h, TAG_CODE, "cTi", "Dv", id);
free(id);
return 1; return 1;
} }
static int static int
mdoc_ev_pre(MDOC_ARGS) mdoc_ev_pre(MDOC_ARGS)
{ {
print_otag(h, TAG_CODE, "c", "Ev"); char *id;
if ((id = cond_id(n)) != NULL)
print_otag(h, TAG_A, "chR", "selflink", id);
print_otag(h, TAG_CODE, "cTi", "Ev", id);
free(id);
return 1; return 1;
} }
static int static int
mdoc_er_pre(MDOC_ARGS) mdoc_er_pre(MDOC_ARGS)
{ {
print_otag(h, TAG_CODE, "c", "Er"); char *id;
id = n->sec == SEC_ERRORS &&
(n->parent->tok == MDOC_It ||
(n->parent->tok == MDOC_Bq &&
n->parent->parent->parent->tok == MDOC_It)) ?
html_make_id(n) : NULL;
if (id != NULL)
print_otag(h, TAG_A, "chR", "selflink", id);
print_otag(h, TAG_CODE, "cTi", "Er", id);
free(id);
return 1; return 1;
} }
@ -1092,12 +1112,12 @@ mdoc_fa_pre(MDOC_ARGS)
struct tag *t; struct tag *t;
if (n->parent->tok != MDOC_Fo) { if (n->parent->tok != MDOC_Fo) {
print_otag(h, TAG_VAR, "c", "Fa"); print_otag(h, TAG_VAR, "cT", "Fa");
return 1; return 1;
} }
for (nn = n->child; nn; nn = nn->next) { for (nn = n->child; nn; nn = nn->next) {
t = print_otag(h, TAG_VAR, "c", "Fa"); t = print_otag(h, TAG_VAR, "cT", "Fa");
print_text(h, nn->string); print_text(h, nn->string);
print_tagq(h, t); print_tagq(h, t);
if (nn->next) { if (nn->next) {
@ -1128,11 +1148,11 @@ mdoc_fd_pre(MDOC_ARGS)
assert(n->type == ROFFT_TEXT); assert(n->type == ROFFT_TEXT);
if (strcmp(n->string, "#include")) { if (strcmp(n->string, "#include")) {
print_otag(h, TAG_B, "c", "Fd"); print_otag(h, TAG_B, "cT", "Fd");
return 1; return 1;
} }
print_otag(h, TAG_B, "c", "In"); print_otag(h, TAG_B, "cT", "In");
print_text(h, n->string); print_text(h, n->string);
if (NULL != (n = n->next)) { if (NULL != (n = n->next)) {
@ -1146,10 +1166,10 @@ mdoc_fd_pre(MDOC_ARGS)
cp = strchr(buf, '\0') - 1; cp = strchr(buf, '\0') - 1;
if (cp >= buf && (*cp == '>' || *cp == '"')) if (cp >= buf && (*cp == '>' || *cp == '"'))
*cp = '\0'; *cp = '\0';
t = print_otag(h, TAG_A, "chI", "In", buf); t = print_otag(h, TAG_A, "cThI", "In", buf);
free(buf); free(buf);
} else } else
t = print_otag(h, TAG_A, "c", "In"); t = print_otag(h, TAG_A, "cT", "In");
print_text(h, n->string); print_text(h, n->string);
print_tagq(h, t); print_tagq(h, t);
@ -1176,7 +1196,7 @@ mdoc_vt_pre(MDOC_ARGS)
} else if (n->type == ROFFT_HEAD) } else if (n->type == ROFFT_HEAD)
return 0; return 0;
print_otag(h, TAG_VAR, "c", "Vt"); print_otag(h, TAG_VAR, "cT", "Vt");
return 1; return 1;
} }
@ -1184,7 +1204,7 @@ static int
mdoc_ft_pre(MDOC_ARGS) mdoc_ft_pre(MDOC_ARGS)
{ {
synopsis_pre(h, n); synopsis_pre(h, n);
print_otag(h, TAG_VAR, "c", "Ft"); print_otag(h, TAG_VAR, "cT", "Ft");
return 1; return 1;
} }
@ -1205,7 +1225,7 @@ mdoc_fn_pre(MDOC_ARGS)
ep = strchr(sp, ' '); ep = strchr(sp, ' ');
if (NULL != ep) { if (NULL != ep) {
t = print_otag(h, TAG_VAR, "c", "Ft"); t = print_otag(h, TAG_VAR, "cT", "Ft");
while (ep) { while (ep) {
sz = MIN((int)(ep - sp), BUFSIZ - 1); sz = MIN((int)(ep - sp), BUFSIZ - 1);
@ -1218,7 +1238,7 @@ mdoc_fn_pre(MDOC_ARGS)
print_tagq(h, t); print_tagq(h, t);
} }
t = print_otag(h, TAG_B, "c", "Fn"); t = print_otag(h, TAG_B, "cT", "Fn");
if (sp) if (sp)
print_text(h, sp); print_text(h, sp);
@ -1231,10 +1251,10 @@ mdoc_fn_pre(MDOC_ARGS)
for (n = n->child->next; n; n = n->next) { for (n = n->child->next; n; n = n->next) {
if (NODE_SYNPRETTY & n->flags) if (NODE_SYNPRETTY & n->flags)
t = print_otag(h, TAG_VAR, "css?", "Fa", t = print_otag(h, TAG_VAR, "cTss?", "Fa",
"white-space", "nowrap"); "white-space", "nowrap");
else else
t = print_otag(h, TAG_VAR, "c", "Fa"); t = print_otag(h, TAG_VAR, "cT", "Fa");
print_text(h, n->string); print_text(h, n->string);
print_tagq(h, t); print_tagq(h, t);
if (n->next) { if (n->next) {
@ -1286,48 +1306,36 @@ mdoc_pp_pre(MDOC_ARGS)
return 0; return 0;
} }
static int
mdoc_sp_pre(MDOC_ARGS)
{
struct roffsu su;
SCALE_VS_INIT(&su, 1);
if (MDOC_sp == n->tok) {
if (NULL != (n = n->child)) {
if ( ! a2roffsu(n->string, &su, SCALE_VS))
su.scale = 1.0;
else if (su.scale < 0.0)
su.scale = 0.0;
}
} else
su.scale = 0.0;
print_otag(h, TAG_DIV, "suh", &su);
/* So the div isn't empty: */
print_text(h, "\\~");
return 0;
}
static int static int
mdoc_lk_pre(MDOC_ARGS) mdoc_lk_pre(MDOC_ARGS)
{ {
if (NULL == (n = n->child)) const struct roff_node *link, *descr, *punct;
struct tag *t;
if ((link = n->child) == NULL)
return 0; return 0;
assert(n->type == ROFFT_TEXT); /* Find beginning of trailing punctuation. */
punct = n->last;
while (punct != link && punct->flags & NODE_DELIMC)
punct = punct->prev;
punct = punct->next;
print_otag(h, TAG_A, "ch", "Lk", n->string); /* Link target and link text. */
t = print_otag(h, TAG_A, "cTh", "Lk", link->string);
if (NULL == n->next) for (descr = link->next; descr != punct; descr = descr->next) {
print_text(h, n->string); if (descr->flags & (NODE_DELIMC | NODE_DELIMO))
h->flags |= HTML_NOSPACE;
for (n = n->next; n; n = n->next) print_text(h, descr->string);
print_text(h, n->string); }
print_tagq(h, t);
/* Trailing punctuation. */
while (punct != NULL) {
h->flags |= HTML_NOSPACE;
print_text(h, punct->string);
punct = punct->next;
}
return 0; return 0;
} }
@ -1341,7 +1349,7 @@ mdoc_mt_pre(MDOC_ARGS)
assert(n->type == ROFFT_TEXT); assert(n->type == ROFFT_TEXT);
mandoc_asprintf(&cp, "mailto:%s", n->string); mandoc_asprintf(&cp, "mailto:%s", n->string);
t = print_otag(h, TAG_A, "ch", "Mt", cp); t = print_otag(h, TAG_A, "cTh", "Mt", cp);
print_text(h, n->string); print_text(h, n->string);
print_tagq(h, t); print_tagq(h, t);
free(cp); free(cp);
@ -1369,7 +1377,7 @@ mdoc_fo_pre(MDOC_ARGS)
return 0; return 0;
assert(n->child->string); assert(n->child->string);
t = print_otag(h, TAG_B, "c", "Fn"); t = print_otag(h, TAG_B, "cT", "Fn");
print_text(h, n->child->string); print_text(h, n->child->string);
print_tagq(h, t); print_tagq(h, t);
return 0; return 0;
@ -1393,7 +1401,7 @@ mdoc_in_pre(MDOC_ARGS)
struct tag *t; struct tag *t;
synopsis_pre(h, n); synopsis_pre(h, n);
print_otag(h, TAG_B, "c", "In"); print_otag(h, TAG_B, "cT", "In");
/* /*
* The first argument of the `In' gets special treatment as * The first argument of the `In' gets special treatment as
@ -1412,9 +1420,9 @@ mdoc_in_pre(MDOC_ARGS)
assert(n->type == ROFFT_TEXT); assert(n->type == ROFFT_TEXT);
if (h->base_includes) if (h->base_includes)
t = print_otag(h, TAG_A, "chI", "In", n->string); t = print_otag(h, TAG_A, "cThI", "In", n->string);
else else
t = print_otag(h, TAG_A, "c", "In"); t = print_otag(h, TAG_A, "cT", "In");
print_text(h, n->string); print_text(h, n->string);
print_tagq(h, t); print_tagq(h, t);
@ -1435,14 +1443,19 @@ mdoc_in_pre(MDOC_ARGS)
static int static int
mdoc_ic_pre(MDOC_ARGS) mdoc_ic_pre(MDOC_ARGS)
{ {
print_otag(h, TAG_B, "c", "Ic"); char *id;
if ((id = cond_id(n)) != NULL)
print_otag(h, TAG_A, "chR", "selflink", id);
print_otag(h, TAG_B, "cTi", "Ic", id);
free(id);
return 1; return 1;
} }
static int static int
mdoc_va_pre(MDOC_ARGS) mdoc_va_pre(MDOC_ARGS)
{ {
print_otag(h, TAG_VAR, "c", "Va"); print_otag(h, TAG_VAR, "cT", "Va");
return 1; return 1;
} }
@ -1487,7 +1500,12 @@ mdoc_bf_pre(MDOC_ARGS)
static int static int
mdoc_ms_pre(MDOC_ARGS) mdoc_ms_pre(MDOC_ARGS)
{ {
print_otag(h, TAG_B, "c", "Ms"); char *id;
if ((id = cond_id(n)) != NULL)
print_otag(h, TAG_A, "chR", "selflink", id);
print_otag(h, TAG_B, "cTi", "Ms", id);
free(id);
return 1; return 1;
} }
@ -1516,28 +1534,38 @@ mdoc_rs_pre(MDOC_ARGS)
if (n->prev && SEC_SEE_ALSO == n->sec) if (n->prev && SEC_SEE_ALSO == n->sec)
print_paragraph(h); print_paragraph(h);
print_otag(h, TAG_CITE, "c", "Rs"); print_otag(h, TAG_CITE, "cT", "Rs");
return 1; return 1;
} }
static int static int
mdoc_no_pre(MDOC_ARGS) mdoc_no_pre(MDOC_ARGS)
{ {
print_otag(h, TAG_SPAN, "c", "No"); char *id;
if ((id = cond_id(n)) != NULL)
print_otag(h, TAG_A, "chR", "selflink", id);
print_otag(h, TAG_SPAN, "ci", "No", id);
free(id);
return 1; return 1;
} }
static int static int
mdoc_li_pre(MDOC_ARGS) mdoc_li_pre(MDOC_ARGS)
{ {
print_otag(h, TAG_CODE, "c", "Li"); char *id;
if ((id = cond_id(n)) != NULL)
print_otag(h, TAG_A, "chR", "selflink", id);
print_otag(h, TAG_CODE, "ci", "Li", id);
free(id);
return 1; return 1;
} }
static int static int
mdoc_sy_pre(MDOC_ARGS) mdoc_sy_pre(MDOC_ARGS)
{ {
print_otag(h, TAG_B, "c", "Sy"); print_otag(h, TAG_B, "cT", "Sy");
return 1; return 1;
} }
@ -1547,7 +1575,7 @@ mdoc_lb_pre(MDOC_ARGS)
if (SEC_LIBRARY == n->sec && NODE_LINE & n->flags && n->prev) if (SEC_LIBRARY == n->sec && NODE_LINE & n->flags && n->prev)
print_otag(h, TAG_BR, ""); print_otag(h, TAG_BR, "");
print_otag(h, TAG_SPAN, "c", "Lb"); print_otag(h, TAG_SPAN, "cT", "Lb");
return 1; return 1;
} }

View File

@ -1,4 +1,4 @@
/* $Id: mdoc_macro.c,v 1.217 2017/02/16 09:47:31 schwarze Exp $ */ /* $Id: mdoc_macro.c,v 1.224 2017/05/30 16:22:03 schwarze Exp $ */
/* /*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010, 2012-2017 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2010, 2012-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -46,21 +46,21 @@ static void phrase_ta(MACRO_PROT_ARGS);
static void append_delims(struct roff_man *, int, int *, char *); static void append_delims(struct roff_man *, int, int *, char *);
static void dword(struct roff_man *, int, int, const char *, static void dword(struct roff_man *, int, int, const char *,
enum mdelim, int); enum mdelim, int);
static int find_pending(struct roff_man *, int, int, int, static int find_pending(struct roff_man *, enum roff_tok,
struct roff_node *); int, int, struct roff_node *);
static int lookup(struct roff_man *, int, int, int, const char *); 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, int);
static void break_intermediate(struct roff_node *, static void break_intermediate(struct roff_node *,
struct roff_node *); struct roff_node *);
static int parse_rest(struct roff_man *, int, int, int *, char *); static int parse_rest(struct roff_man *, enum roff_tok,
static int rew_alt(int); int, int *, char *);
static void rew_elem(struct roff_man *, int); static enum roff_tok rew_alt(enum roff_tok);
static void rew_elem(struct roff_man *, enum roff_tok);
static void rew_last(struct roff_man *, const struct roff_node *); static void rew_last(struct roff_man *, const struct roff_node *);
static void rew_pending(struct roff_man *, static void rew_pending(struct roff_man *,
const struct roff_node *); const struct roff_node *);
const struct mdoc_macro __mdoc_macros[MDOC_MAX] = { const struct mdoc_macro __mdoc_macros[MDOC_MAX - MDOC_Dd] = {
{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ap */
{ in_line_eoln, MDOC_PROLOGUE }, /* Dd */ { in_line_eoln, MDOC_PROLOGUE }, /* Dd */
{ in_line_eoln, MDOC_PROLOGUE }, /* Dt */ { in_line_eoln, MDOC_PROLOGUE }, /* Dt */
{ in_line_eoln, MDOC_PROLOGUE }, /* Os */ { in_line_eoln, MDOC_PROLOGUE }, /* Os */
@ -76,6 +76,8 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
{ blk_full, MDOC_PARSED | MDOC_JOIN }, /* It */ { blk_full, MDOC_PARSED | MDOC_JOIN }, /* It */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */
{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* An */ { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* An */
{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED |
MDOC_IGNDELIM | MDOC_JOIN }, /* Ap */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */
{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Cd */ { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Cd */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */
@ -196,14 +198,10 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* En */ { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* En */
{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Dx */ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Dx */
{ in_line_eoln, MDOC_JOIN }, /* %Q */ { in_line_eoln, MDOC_JOIN }, /* %Q */
{ in_line_eoln, 0 }, /* br */
{ in_line_eoln, 0 }, /* sp */
{ in_line_eoln, 0 }, /* %U */ { in_line_eoln, 0 }, /* %U */
{ phrase_ta, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ta */ { phrase_ta, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ta */
{ in_line_eoln, MDOC_PROLOGUE }, /* ll */
}; };
const struct mdoc_macro *const mdoc_macros = __mdoc_macros - MDOC_Dd;
const struct mdoc_macro * const mdoc_macros = __mdoc_macros;
/* /*
@ -225,7 +223,7 @@ mdoc_endparse(struct roff_man *mdoc)
if (n->type == ROFFT_BLOCK && if (n->type == ROFFT_BLOCK &&
mdoc_macros[n->tok].flags & MDOC_EXPLICIT) mdoc_macros[n->tok].flags & MDOC_EXPLICIT)
mandoc_msg(MANDOCERR_BLK_NOEND, mdoc->parse, mandoc_msg(MANDOCERR_BLK_NOEND, mdoc->parse,
n->line, n->pos, mdoc_macronames[n->tok]); n->line, n->pos, roff_name[n->tok]);
/* Rewind to the first. */ /* Rewind to the first. */
@ -240,20 +238,19 @@ mdoc_endparse(struct roff_man *mdoc)
static int static int
lookup(struct roff_man *mdoc, int from, int line, int ppos, const char *p) lookup(struct roff_man *mdoc, int from, int line, int ppos, const char *p)
{ {
int res; enum roff_tok res;
if (mdoc->flags & MDOC_PHRASEQF) { if (mdoc->flags & MDOC_PHRASEQF) {
mdoc->flags &= ~MDOC_PHRASEQF; mdoc->flags &= ~MDOC_PHRASEQF;
return TOKEN_NONE; return TOKEN_NONE;
} }
if (from == TOKEN_NONE || mdoc_macros[from].flags & MDOC_PARSED) { if (from == TOKEN_NONE || mdoc_macros[from].flags & MDOC_PARSED) {
res = mdoc_hash_find(p); res = roffhash_find(mdoc->mdocmac, p, 0);
if (res != TOKEN_NONE) { if (res != TOKEN_NONE) {
if (mdoc_macros[res].flags & MDOC_CALLABLE) if (mdoc_macros[res].flags & MDOC_CALLABLE)
return res; return res;
if (res != MDOC_br && res != MDOC_sp && res != MDOC_ll) mandoc_msg(MANDOCERR_MACRO_CALL,
mandoc_msg(MANDOCERR_MACRO_CALL, mdoc->parse, line, ppos, p);
mdoc->parse, line, ppos, p);
} }
} }
return TOKEN_NONE; return TOKEN_NONE;
@ -324,8 +321,8 @@ rew_pending(struct roff_man *mdoc, const struct roff_node *n)
* For a block closing macro, return the corresponding opening one. * For a block closing macro, return the corresponding opening one.
* Otherwise, return the macro itself. * Otherwise, return the macro itself.
*/ */
static int static enum roff_tok
rew_alt(int tok) rew_alt(enum roff_tok tok)
{ {
switch (tok) { switch (tok) {
case MDOC_Ac: case MDOC_Ac:
@ -366,7 +363,7 @@ rew_alt(int tok)
} }
static void static void
rew_elem(struct roff_man *mdoc, int tok) rew_elem(struct roff_man *mdoc, enum roff_tok tok)
{ {
struct roff_node *n; struct roff_node *n;
@ -398,7 +395,7 @@ break_intermediate(struct roff_node *n, struct roff_node *breaker)
* the rew_pending() call closing out the sub-block. * the rew_pending() call closing out the sub-block.
*/ */
static int static int
find_pending(struct roff_man *mdoc, int tok, int line, int ppos, find_pending(struct roff_man *mdoc, enum roff_tok tok, int line, int ppos,
struct roff_node *target) struct roff_node *target)
{ {
struct roff_node *n; struct roff_node *n;
@ -420,8 +417,8 @@ find_pending(struct roff_man *mdoc, int tok, int line, int ppos,
else if ( ! (target->flags & NODE_ENDED)) { else if ( ! (target->flags & NODE_ENDED)) {
mandoc_vmsg(MANDOCERR_BLK_NEST, mandoc_vmsg(MANDOCERR_BLK_NEST,
mdoc->parse, line, ppos, mdoc->parse, line, ppos,
"%s breaks %s", mdoc_macronames[tok], "%s breaks %s", roff_name[tok],
mdoc_macronames[n->tok]); roff_name[n->tok]);
mdoc_endbody_alloc(mdoc, line, ppos, mdoc_endbody_alloc(mdoc, line, ppos,
tok, target); tok, target);
} }
@ -524,7 +521,8 @@ macro_or_word(MACRO_PROT_ARGS, int parsed)
mdoc_macros[tok].flags & MDOC_JOIN); mdoc_macros[tok].flags & MDOC_JOIN);
return 0; return 0;
} else { } else {
if (mdoc_macros[tok].fp == in_line_eoln) if (tok != TOKEN_NONE &&
mdoc_macros[tok].fp == in_line_eoln)
rew_elem(mdoc, tok); rew_elem(mdoc, tok);
mdoc_macro(mdoc, ntok, line, ppos, pos, buf); mdoc_macro(mdoc, ntok, line, ppos, pos, buf);
if (tok == TOKEN_NONE) if (tok == TOKEN_NONE)
@ -548,7 +546,7 @@ blk_exp_close(MACRO_PROT_ARGS)
int j, lastarg, maxargs, nl, pending; int j, lastarg, maxargs, nl, pending;
enum margserr ac; enum margserr ac;
int atok, ntok; enum roff_tok atok, ntok;
char *p; char *p;
nl = MDOC_NEWLINE & mdoc->flags; nl = MDOC_NEWLINE & mdoc->flags;
@ -633,8 +631,7 @@ blk_exp_close(MACRO_PROT_ARGS)
mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse, mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse,
line, ppos, "%s breaks %s", line, ppos, "%s breaks %s",
mdoc_macronames[atok], roff_name[atok], roff_name[later->tok]);
mdoc_macronames[later->tok]);
endbody = mdoc_endbody_alloc(mdoc, line, ppos, endbody = mdoc_endbody_alloc(mdoc, line, ppos,
atok, body); atok, body);
@ -676,14 +673,14 @@ blk_exp_close(MACRO_PROT_ARGS)
if (body == NULL) { if (body == NULL) {
mandoc_msg(MANDOCERR_BLK_NOTOPEN, mdoc->parse, mandoc_msg(MANDOCERR_BLK_NOTOPEN, mdoc->parse,
line, ppos, mdoc_macronames[tok]); line, ppos, roff_name[tok]);
if (maxargs && endbody == NULL) { if (maxargs && endbody == NULL) {
/* /*
* Stray .Ec without previous .Eo: * Stray .Ec without previous .Eo:
* Break the output line, keep the arguments. * Break the output line, keep the arguments.
*/ */
roff_elem_alloc(mdoc, line, ppos, MDOC_br); roff_elem_alloc(mdoc, line, ppos, ROFF_br);
rew_elem(mdoc, MDOC_br); rew_elem(mdoc, ROFF_br);
} }
} else if (endbody == NULL) { } else if (endbody == NULL) {
rew_last(mdoc, body); rew_last(mdoc, body);
@ -695,7 +692,7 @@ blk_exp_close(MACRO_PROT_ARGS)
if (buf[*pos] != '\0') if (buf[*pos] != '\0')
mandoc_vmsg(MANDOCERR_ARG_SKIP, mandoc_vmsg(MANDOCERR_ARG_SKIP,
mdoc->parse, line, ppos, mdoc->parse, line, ppos,
"%s %s", mdoc_macronames[tok], "%s %s", roff_name[tok],
buf + *pos); buf + *pos);
if (endbody == NULL && n != NULL) if (endbody == NULL && n != NULL)
rew_pending(mdoc, n); rew_pending(mdoc, n);
@ -716,8 +713,7 @@ blk_exp_close(MACRO_PROT_ARGS)
if (ac == ARGS_PUNCT || ac == ARGS_EOLN) if (ac == ARGS_PUNCT || ac == ARGS_EOLN)
break; break;
ntok = ac == ARGS_QWORD ? TOKEN_NONE : ntok = lookup(mdoc, tok, line, lastarg, p);
lookup(mdoc, tok, line, lastarg, p);
if (ntok == TOKEN_NONE) { if (ntok == TOKEN_NONE) {
dword(mdoc, line, lastarg, p, DELIM_MAX, dword(mdoc, line, lastarg, p, DELIM_MAX,
@ -752,7 +748,7 @@ static void
in_line(MACRO_PROT_ARGS) in_line(MACRO_PROT_ARGS)
{ {
int la, scope, cnt, firstarg, mayopen, nc, nl; int la, scope, cnt, firstarg, mayopen, nc, nl;
int ntok; enum roff_tok ntok;
enum margserr ac; enum margserr ac;
enum mdelim d; enum mdelim d;
struct mdoc_arg *arg; struct mdoc_arg *arg;
@ -813,7 +809,7 @@ in_line(MACRO_PROT_ARGS)
break; break;
} }
ntok = (ac == ARGS_QWORD || (tok == MDOC_Fn && !cnt)) ? ntok = (tok == MDOC_Fn && !cnt) ?
TOKEN_NONE : lookup(mdoc, tok, line, la, p); TOKEN_NONE : lookup(mdoc, tok, line, la, p);
/* /*
@ -833,7 +829,7 @@ in_line(MACRO_PROT_ARGS)
mdoc_argv_free(arg); mdoc_argv_free(arg);
mandoc_msg(MANDOCERR_MACRO_EMPTY, mandoc_msg(MANDOCERR_MACRO_EMPTY,
mdoc->parse, line, ppos, mdoc->parse, line, ppos,
mdoc_macronames[tok]); roff_name[tok]);
} }
mdoc_macro(mdoc, ntok, line, la, pos, buf); mdoc_macro(mdoc, ntok, line, la, pos, buf);
if (nl) if (nl)
@ -842,14 +838,11 @@ in_line(MACRO_PROT_ARGS)
} }
/* /*
* Non-quote-enclosed punctuation. Set up our scope, if * Handle punctuation. Set up our scope, if a word;
* a word; rewind the scope, if a delimiter; then append * rewind the scope, if a delimiter; then append the word.
* the word.
*/ */
d = ac == ARGS_QWORD ? DELIM_NONE : mdoc_isdelim(p); if ((d = mdoc_isdelim(p)) != DELIM_NONE) {
if (DELIM_NONE != d) {
/* /*
* If we encounter closing punctuation, no word * If we encounter closing punctuation, no word
* has been emitted, no scope is open, and we're * has been emitted, no scope is open, and we're
@ -869,11 +862,12 @@ in_line(MACRO_PROT_ARGS)
* Close out our scope, if one is open, before * Close out our scope, if one is open, before
* any punctuation. * any punctuation.
*/ */
if (scope) if (scope && tok != MDOC_Lk) {
rew_elem(mdoc, tok); rew_elem(mdoc, tok);
scope = 0; scope = 0;
if (tok == MDOC_Fn) if (tok == MDOC_Fn)
mayopen = 0; mayopen = 0;
}
} else if (mayopen && !scope) { } else if (mayopen && !scope) {
mdoc_elem_alloc(mdoc, line, ppos, tok, arg); mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
scope = 1; scope = 1;
@ -881,7 +875,7 @@ in_line(MACRO_PROT_ARGS)
} }
dword(mdoc, line, la, p, d, dword(mdoc, line, la, p, d,
MDOC_JOIN & mdoc_macros[tok].flags); mdoc_macros[tok].flags & MDOC_JOIN);
/* /*
* If the first argument is a closing delimiter, * If the first argument is a closing delimiter,
@ -903,8 +897,10 @@ in_line(MACRO_PROT_ARGS)
} }
} }
if (scope) if (scope && tok != MDOC_Lk) {
rew_elem(mdoc, tok); rew_elem(mdoc, tok);
scope = 0;
}
/* /*
* If no elements have been collected and we're allowed to have * If no elements have been collected and we're allowed to have
@ -919,11 +915,13 @@ in_line(MACRO_PROT_ARGS)
} else { } else {
mdoc_argv_free(arg); mdoc_argv_free(arg);
mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
line, ppos, mdoc_macronames[tok]); line, ppos, roff_name[tok]);
} }
} }
if (nl) if (nl)
append_delims(mdoc, line, pos, buf); append_delims(mdoc, line, pos, buf);
if (scope)
rew_elem(mdoc, tok);
} }
static void static void
@ -942,7 +940,7 @@ blk_full(MACRO_PROT_ARGS)
if (buf[*pos] == '\0' && (tok == MDOC_Sh || tok == MDOC_Ss)) { if (buf[*pos] == '\0' && (tok == MDOC_Sh || tok == MDOC_Ss)) {
mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
line, ppos, mdoc_macronames[tok]); line, ppos, roff_name[tok]);
return; return;
} }
@ -965,7 +963,7 @@ blk_full(MACRO_PROT_ARGS)
mandoc_vmsg(MANDOCERR_BLK_BROKEN, mandoc_vmsg(MANDOCERR_BLK_BROKEN,
mdoc->parse, line, ppos, mdoc->parse, line, ppos,
"It breaks %s", "It breaks %s",
mdoc_macronames[blk->tok]); roff_name[blk->tok]);
rew_pending(mdoc, blk); rew_pending(mdoc, blk);
} }
break; break;
@ -977,9 +975,8 @@ blk_full(MACRO_PROT_ARGS)
case MDOC_Ss: case MDOC_Ss:
mandoc_vmsg(MANDOCERR_BLK_BROKEN, mandoc_vmsg(MANDOCERR_BLK_BROKEN,
mdoc->parse, line, ppos, mdoc->parse, line, ppos,
"%s breaks %s", "%s breaks %s", roff_name[tok],
mdoc_macronames[tok], roff_name[n->tok]);
mdoc_macronames[n->tok]);
rew_pending(mdoc, n); rew_pending(mdoc, n);
n = mdoc->last; n = mdoc->last;
continue; continue;
@ -1005,8 +1002,7 @@ blk_full(MACRO_PROT_ARGS)
if (blk != NULL) { if (blk != NULL) {
mandoc_vmsg(MANDOCERR_BLK_BROKEN, mandoc_vmsg(MANDOCERR_BLK_BROKEN,
mdoc->parse, line, ppos, mdoc->parse, line, ppos,
"It breaks %s", "It breaks %s", roff_name[blk->tok]);
mdoc_macronames[blk->tok]);
rew_pending(mdoc, blk); rew_pending(mdoc, blk);
blk = NULL; blk = NULL;
} }
@ -1021,8 +1017,8 @@ blk_full(MACRO_PROT_ARGS)
if (tok == MDOC_It && (n == NULL || n->tok != MDOC_Bl)) { if (tok == MDOC_It && (n == NULL || n->tok != MDOC_Bl)) {
mandoc_vmsg(MANDOCERR_IT_STRAY, mdoc->parse, mandoc_vmsg(MANDOCERR_IT_STRAY, mdoc->parse,
line, ppos, "It %s", buf + *pos); line, ppos, "It %s", buf + *pos);
roff_elem_alloc(mdoc, line, ppos, MDOC_br); roff_elem_alloc(mdoc, line, ppos, ROFF_br);
rew_elem(mdoc, MDOC_br); rew_elem(mdoc, ROFF_br);
return; return;
} }
} }
@ -1099,7 +1095,7 @@ blk_full(MACRO_PROT_ARGS)
if (tok == MDOC_Bd || tok == MDOC_Bk) { if (tok == MDOC_Bd || tok == MDOC_Bk) {
mandoc_vmsg(MANDOCERR_ARG_EXCESS, mandoc_vmsg(MANDOCERR_ARG_EXCESS,
mdoc->parse, line, la, "%s ... %s", mdoc->parse, line, la, "%s ... %s",
mdoc_macronames[tok], buf + la); roff_name[tok], buf + la);
break; break;
} }
if (tok == MDOC_Rs) { if (tok == MDOC_Rs) {
@ -1117,7 +1113,6 @@ blk_full(MACRO_PROT_ARGS)
if (head == NULL && if (head == NULL &&
ac != ARGS_PHRASE && ac != ARGS_PHRASE &&
ac != ARGS_QWORD &&
mdoc_isdelim(p) == DELIM_OPEN) { mdoc_isdelim(p) == DELIM_OPEN) {
dword(mdoc, line, la, p, DELIM_OPEN, 0); dword(mdoc, line, la, p, DELIM_OPEN, 0);
continue; continue;
@ -1214,8 +1209,7 @@ blk_part_imp(MACRO_PROT_ARGS)
if (ac == ARGS_EOLN || ac == ARGS_PUNCT) if (ac == ARGS_EOLN || ac == ARGS_PUNCT)
break; break;
if (body == NULL && ac != ARGS_QWORD && if (body == NULL && mdoc_isdelim(p) == DELIM_OPEN) {
mdoc_isdelim(p) == DELIM_OPEN) {
dword(mdoc, line, la, p, DELIM_OPEN, 0); dword(mdoc, line, la, p, DELIM_OPEN, 0);
continue; continue;
} }
@ -1271,8 +1265,7 @@ blk_part_exp(MACRO_PROT_ARGS)
/* Flush out leading punctuation. */ /* Flush out leading punctuation. */
if (head == NULL && ac != ARGS_QWORD && if (head == NULL && mdoc_isdelim(p) == DELIM_OPEN) {
mdoc_isdelim(p) == DELIM_OPEN) {
dword(mdoc, line, la, p, DELIM_OPEN, 0); dword(mdoc, line, la, p, DELIM_OPEN, 0);
continue; continue;
} }
@ -1307,7 +1300,7 @@ in_line_argn(MACRO_PROT_ARGS)
struct mdoc_arg *arg; struct mdoc_arg *arg;
char *p; char *p;
enum margserr ac; enum margserr ac;
int ntok; enum roff_tok ntok;
int state; /* arg#; -1: not yet open; -2: closed */ int state; /* arg#; -1: not yet open; -2: closed */
int la, maxargs, nl; int la, maxargs, nl;
@ -1371,7 +1364,7 @@ in_line_argn(MACRO_PROT_ARGS)
state = -2; state = -2;
} }
ntok = (ac == ARGS_QWORD || (tok == MDOC_Pf && state == 0)) ? ntok = (tok == MDOC_Pf && state == 0) ?
TOKEN_NONE : lookup(mdoc, tok, line, la, p); TOKEN_NONE : lookup(mdoc, tok, line, la, p);
if (ntok != TOKEN_NONE) { if (ntok != TOKEN_NONE) {
@ -1383,8 +1376,7 @@ in_line_argn(MACRO_PROT_ARGS)
break; break;
} }
if (ac == ARGS_QWORD || if (mdoc_macros[tok].flags & MDOC_IGNDELIM ||
mdoc_macros[tok].flags & MDOC_IGNDELIM ||
mdoc_isdelim(p) == DELIM_NONE) { mdoc_isdelim(p) == DELIM_NONE) {
if (state == -1) { if (state == -1) {
mdoc_elem_alloc(mdoc, line, ppos, tok, arg); mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
@ -1397,12 +1389,12 @@ in_line_argn(MACRO_PROT_ARGS)
} }
dword(mdoc, line, la, p, DELIM_MAX, dword(mdoc, line, la, p, DELIM_MAX,
MDOC_JOIN & mdoc_macros[tok].flags); mdoc_macros[tok].flags & MDOC_JOIN);
} }
if (state == -1) { if (state == -1) {
mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
line, ppos, mdoc_macronames[tok]); line, ppos, roff_name[tok]);
return; return;
} }
@ -1430,9 +1422,9 @@ in_line_eoln(MACRO_PROT_ARGS)
} }
if (buf[*pos] == '\0' && if (buf[*pos] == '\0' &&
(tok == MDOC_Fd || mdoc_macronames[tok][0] == '%')) { (tok == MDOC_Fd || *roff_name[tok] == '%')) {
mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
line, ppos, mdoc_macronames[tok]); line, ppos, roff_name[tok]);
return; return;
} }
@ -1449,7 +1441,8 @@ in_line_eoln(MACRO_PROT_ARGS)
* or until the next macro, call that macro, and return 1. * or until the next macro, call that macro, and return 1.
*/ */
static int static int
parse_rest(struct roff_man *mdoc, int tok, int line, int *pos, char *buf) parse_rest(struct roff_man *mdoc, enum roff_tok tok,
int line, int *pos, char *buf)
{ {
int la; int la;

View File

@ -1,4 +1,4 @@
/* $Id: mdoc_man.c,v 1.104 2017/02/17 19:15:41 schwarze Exp $ */ /* $Id: mdoc_man.c,v 1.119 2017/06/08 12:54:58 schwarze Exp $ */
/* /*
* Copyright (c) 2011-2017 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2011-2017 Ingo Schwarze <schwarze@openbsd.org>
* *
@ -20,6 +20,7 @@
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "mandoc_aux.h" #include "mandoc_aux.h"
@ -32,10 +33,13 @@
#define DECL_ARGS const struct roff_meta *meta, struct roff_node *n #define DECL_ARGS const struct roff_meta *meta, struct roff_node *n
typedef int (*int_fp)(DECL_ARGS);
typedef void (*void_fp)(DECL_ARGS);
struct manact { struct manact {
int (*cond)(DECL_ARGS); /* DON'T run actions */ int_fp cond; /* DON'T run actions */
int (*pre)(DECL_ARGS); /* pre-node action */ int_fp pre; /* pre-node action */
void (*post)(DECL_ARGS); /* post-node action */ void_fp post; /* post-node action */
const char *prefix; /* pre-node string constant */ const char *prefix; /* pre-node string constant */
const char *suffix; /* post-node string constant */ const char *suffix; /* post-node string constant */
}; };
@ -44,6 +48,7 @@ static int cond_body(DECL_ARGS);
static int cond_head(DECL_ARGS); static int cond_head(DECL_ARGS);
static void font_push(char); static void font_push(char);
static void font_pop(void); static void font_pop(void);
static int man_strlen(const char *);
static void mid_it(void); static void mid_it(void);
static void post__t(DECL_ARGS); static void post__t(DECL_ARGS);
static void post_aq(DECL_ARGS); static void post_aq(DECL_ARGS);
@ -68,7 +73,6 @@ static void post_nm(DECL_ARGS);
static void post_percent(DECL_ARGS); static void post_percent(DECL_ARGS);
static void post_pf(DECL_ARGS); static void post_pf(DECL_ARGS);
static void post_sect(DECL_ARGS); static void post_sect(DECL_ARGS);
static void post_sp(DECL_ARGS);
static void post_vt(DECL_ARGS); static void post_vt(DECL_ARGS);
static int pre__t(DECL_ARGS); static int pre__t(DECL_ARGS);
static int pre_an(DECL_ARGS); static int pre_an(DECL_ARGS);
@ -78,7 +82,7 @@ static int pre_bd(DECL_ARGS);
static int pre_bf(DECL_ARGS); static int pre_bf(DECL_ARGS);
static int pre_bk(DECL_ARGS); static int pre_bk(DECL_ARGS);
static int pre_bl(DECL_ARGS); static int pre_bl(DECL_ARGS);
static int pre_br(DECL_ARGS); static void pre_br(DECL_ARGS);
static int pre_dl(DECL_ARGS); static int pre_dl(DECL_ARGS);
static int pre_en(DECL_ARGS); static int pre_en(DECL_ARGS);
static int pre_enc(DECL_ARGS); static int pre_enc(DECL_ARGS);
@ -91,22 +95,24 @@ static int pre_fd(DECL_ARGS);
static int pre_fl(DECL_ARGS); static int pre_fl(DECL_ARGS);
static int pre_fn(DECL_ARGS); static int pre_fn(DECL_ARGS);
static int pre_fo(DECL_ARGS); static int pre_fo(DECL_ARGS);
static int pre_ft(DECL_ARGS); static void pre_ft(DECL_ARGS);
static int pre_Ft(DECL_ARGS);
static int pre_in(DECL_ARGS); static int pre_in(DECL_ARGS);
static int pre_it(DECL_ARGS); static int pre_it(DECL_ARGS);
static int pre_lk(DECL_ARGS); static int pre_lk(DECL_ARGS);
static int pre_li(DECL_ARGS); static int pre_li(DECL_ARGS);
static int pre_ll(DECL_ARGS);
static int pre_nm(DECL_ARGS); static int pre_nm(DECL_ARGS);
static int pre_no(DECL_ARGS); static int pre_no(DECL_ARGS);
static int pre_ns(DECL_ARGS); static int pre_ns(DECL_ARGS);
static void pre_onearg(DECL_ARGS);
static int pre_pp(DECL_ARGS); static int pre_pp(DECL_ARGS);
static int pre_rs(DECL_ARGS); static int pre_rs(DECL_ARGS);
static int pre_sm(DECL_ARGS); static int pre_sm(DECL_ARGS);
static int pre_sp(DECL_ARGS); static void pre_sp(DECL_ARGS);
static int pre_sect(DECL_ARGS); static int pre_sect(DECL_ARGS);
static int pre_sy(DECL_ARGS); static int pre_sy(DECL_ARGS);
static void pre_syn(const struct roff_node *); static void pre_syn(const struct roff_node *);
static void pre_ta(DECL_ARGS);
static int pre_vt(DECL_ARGS); static int pre_vt(DECL_ARGS);
static int pre_xr(DECL_ARGS); static int pre_xr(DECL_ARGS);
static void print_word(const char *); static void print_word(const char *);
@ -118,8 +124,18 @@ static void print_width(const struct mdoc_bl *,
static void print_count(int *); static void print_count(int *);
static void print_node(DECL_ARGS); static void print_node(DECL_ARGS);
static const struct manact manacts[MDOC_MAX + 1] = { static const void_fp roff_manacts[ROFF_MAX] = {
{ NULL, pre_ap, NULL, NULL, NULL }, /* Ap */ pre_br,
pre_onearg,
pre_ft,
pre_onearg,
pre_onearg,
pre_sp,
pre_ta,
pre_onearg,
};
static const struct manact __manacts[MDOC_MAX - MDOC_Dd] = {
{ NULL, NULL, NULL, NULL, NULL }, /* Dd */ { NULL, NULL, NULL, NULL, NULL }, /* Dd */
{ NULL, NULL, NULL, NULL, NULL }, /* Dt */ { NULL, NULL, NULL, NULL, NULL }, /* Dt */
{ NULL, NULL, NULL, NULL, NULL }, /* Os */ { NULL, NULL, NULL, NULL, NULL }, /* Os */
@ -135,6 +151,7 @@ static const struct manact manacts[MDOC_MAX + 1] = {
{ NULL, pre_it, post_it, NULL, NULL }, /* It */ { NULL, pre_it, post_it, NULL, NULL }, /* It */
{ NULL, pre_em, post_font, NULL, NULL }, /* Ad */ { NULL, pre_em, post_font, NULL, NULL }, /* Ad */
{ NULL, pre_an, NULL, NULL, NULL }, /* An */ { NULL, pre_an, NULL, NULL, NULL }, /* An */
{ NULL, pre_ap, NULL, NULL, NULL }, /* Ap */
{ NULL, pre_em, post_font, NULL, NULL }, /* Ar */ { NULL, pre_em, post_font, NULL, NULL }, /* Ar */
{ NULL, pre_sy, post_font, NULL, NULL }, /* Cd */ { NULL, pre_sy, post_font, NULL, NULL }, /* Cd */
{ NULL, pre_sy, post_font, NULL, NULL }, /* Cm */ { NULL, pre_sy, post_font, NULL, NULL }, /* Cm */
@ -146,14 +163,14 @@ static const struct manact manacts[MDOC_MAX + 1] = {
{ NULL, pre_fd, post_fd, NULL, NULL }, /* Fd */ { NULL, pre_fd, post_fd, NULL, NULL }, /* Fd */
{ NULL, pre_fl, post_fl, NULL, NULL }, /* Fl */ { NULL, pre_fl, post_fl, NULL, NULL }, /* Fl */
{ NULL, pre_fn, post_fn, NULL, NULL }, /* Fn */ { NULL, pre_fn, post_fn, NULL, NULL }, /* Fn */
{ NULL, pre_ft, post_font, NULL, NULL }, /* Ft */ { NULL, pre_Ft, post_font, NULL, NULL }, /* Ft */
{ NULL, pre_sy, post_font, NULL, NULL }, /* Ic */ { NULL, pre_sy, post_font, NULL, NULL }, /* Ic */
{ NULL, pre_in, post_in, NULL, NULL }, /* In */ { NULL, pre_in, post_in, NULL, NULL }, /* In */
{ NULL, pre_li, post_font, NULL, NULL }, /* Li */ { NULL, pre_li, post_font, NULL, NULL }, /* Li */
{ cond_head, pre_enc, NULL, "\\- ", NULL }, /* Nd */ { cond_head, pre_enc, NULL, "\\- ", NULL }, /* Nd */
{ NULL, pre_nm, post_nm, NULL, NULL }, /* Nm */ { NULL, pre_nm, post_nm, NULL, NULL }, /* Nm */
{ cond_body, pre_enc, post_enc, "[", "]" }, /* Op */ { cond_body, pre_enc, post_enc, "[", "]" }, /* Op */
{ NULL, pre_ft, post_font, NULL, NULL }, /* Ot */ { NULL, pre_Ft, post_font, NULL, NULL }, /* Ot */
{ NULL, pre_em, post_font, NULL, NULL }, /* Pa */ { NULL, pre_em, post_font, NULL, NULL }, /* Pa */
{ NULL, pre_ex, NULL, NULL, NULL }, /* Rv */ { NULL, pre_ex, NULL, NULL, NULL }, /* Rv */
{ NULL, NULL, NULL, NULL, NULL }, /* St */ { NULL, NULL, NULL, NULL, NULL }, /* St */
@ -237,13 +254,10 @@ static const struct manact manacts[MDOC_MAX + 1] = {
{ cond_body, pre_en, post_en, NULL, NULL }, /* En */ { cond_body, pre_en, post_en, NULL, NULL }, /* En */
{ NULL, NULL, NULL, NULL, NULL }, /* Dx */ { NULL, NULL, NULL, NULL, NULL }, /* Dx */
{ NULL, NULL, post_percent, NULL, NULL }, /* %Q */ { NULL, NULL, post_percent, NULL, NULL }, /* %Q */
{ NULL, pre_br, NULL, NULL, NULL }, /* br */
{ NULL, pre_sp, post_sp, NULL, NULL }, /* sp */
{ NULL, NULL, post_percent, NULL, NULL }, /* %U */ { NULL, NULL, post_percent, NULL, NULL }, /* %U */
{ NULL, NULL, NULL, NULL, NULL }, /* Ta */ { NULL, NULL, NULL, NULL, NULL }, /* Ta */
{ NULL, pre_ll, post_sp, NULL, NULL }, /* ll */
{ NULL, NULL, NULL, NULL, NULL }, /* ROOT */
}; };
static const struct manact *const manacts = __manacts - MDOC_Dd;
static int outflags; static int outflags;
#define MMAN_spc (1 << 0) /* blank character before next word */ #define MMAN_spc (1 << 0) /* blank character before next word */
@ -274,6 +288,49 @@ static struct {
} fontqueue; } fontqueue;
static int
man_strlen(const char *cp)
{
size_t rsz;
int skip, sz;
sz = 0;
skip = 0;
for (;;) {
rsz = strcspn(cp, "\\");
if (rsz) {
cp += rsz;
if (skip) {
skip = 0;
rsz--;
}
sz += rsz;
}
if ('\0' == *cp)
break;
cp++;
switch (mandoc_escape(&cp, NULL, NULL)) {
case ESCAPE_ERROR:
return sz;
case ESCAPE_UNICODE:
case ESCAPE_NUMBERED:
case ESCAPE_SPECIAL:
case ESCAPE_OVERSTRIKE:
if (skip)
skip = 0;
else
sz++;
break;
case ESCAPE_SKIPCHAR:
skip = 1;
break;
default:
break;
}
}
return sz;
}
static void static void
font_push(char newfont) font_push(char newfont)
{ {
@ -391,7 +448,6 @@ static void
print_line(const char *s, int newflags) print_line(const char *s, int newflags)
{ {
outflags &= ~MMAN_br;
outflags |= MMAN_nl; outflags |= MMAN_nl;
print_word(s); print_word(s);
outflags |= newflags; outflags |= newflags;
@ -420,6 +476,7 @@ print_offs(const char *v, int keywords)
{ {
char buf[24]; char buf[24];
struct roffsu su; struct roffsu su;
const char *end;
int sz; int sz;
print_line(".RS", MMAN_Bk_susp); print_line(".RS", MMAN_Bk_susp);
@ -431,8 +488,11 @@ print_offs(const char *v, int keywords)
sz = 6; sz = 6;
else if (keywords && !strcmp(v, "indent-two")) else if (keywords && !strcmp(v, "indent-two"))
sz = 12; sz = 12;
else if (a2roffsu(v, &su, SCALE_EN) > 1) { else {
if (SCALE_EN == su.unit) end = a2roffsu(v, &su, SCALE_EN);
if (end == NULL || *end != '\0')
sz = man_strlen(v);
else if (SCALE_EN == su.unit)
sz = su.scale; sz = su.scale;
else { else {
/* /*
@ -446,8 +506,7 @@ print_offs(const char *v, int keywords)
outflags |= MMAN_nl; outflags |= MMAN_nl;
return; return;
} }
} else }
sz = strlen(v);
/* /*
* We are inside an enclosing list. * We are inside an enclosing list.
@ -469,6 +528,7 @@ print_width(const struct mdoc_bl *bl, const struct roff_node *child)
{ {
char buf[24]; char buf[24];
struct roffsu su; struct roffsu su;
const char *end;
int numeric, remain, sz, chsz; int numeric, remain, sz, chsz;
numeric = 1; numeric = 1;
@ -477,21 +537,23 @@ print_width(const struct mdoc_bl *bl, const struct roff_node *child)
/* Convert the width into a number (of characters). */ /* Convert the width into a number (of characters). */
if (bl->width == NULL) if (bl->width == NULL)
sz = (bl->type == LIST_hang) ? 6 : 0; sz = (bl->type == LIST_hang) ? 6 : 0;
else if (a2roffsu(bl->width, &su, SCALE_MAX) > 1) { else {
if (SCALE_EN == su.unit) end = a2roffsu(bl->width, &su, SCALE_MAX);
if (end == NULL || *end != '\0')
sz = man_strlen(bl->width);
else if (SCALE_EN == su.unit)
sz = su.scale; sz = su.scale;
else { else {
sz = 0; sz = 0;
numeric = 0; numeric = 0;
} }
} else }
sz = strlen(bl->width);
/* XXX Rough estimation, might have multiple parts. */ /* XXX Rough estimation, might have multiple parts. */
if (bl->type == LIST_enum) if (bl->type == LIST_enum)
chsz = (bl->count > 8) + 1; chsz = (bl->count > 8) + 1;
else if (child != NULL && child->type == ROFFT_TEXT) else if (child != NULL && child->type == ROFFT_TEXT)
chsz = strlen(child->string); chsz = man_strlen(child->string);
else else
chsz = 0; chsz = 0;
@ -607,7 +669,11 @@ print_node(DECL_ARGS)
outflags &= ~(MMAN_spc | MMAN_spc_force); outflags &= ~(MMAN_spc | MMAN_spc_force);
else if (outflags & MMAN_Sm) else if (outflags & MMAN_Sm)
outflags |= MMAN_spc; outflags |= MMAN_spc;
} else if (n->tok < ROFF_MAX) {
(*roff_manacts[n->tok])(meta, n);
return;
} else { } else {
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
/* /*
* Conditionally run the pre-node action handler for a * Conditionally run the pre-node action handler for a
* node. * node.
@ -715,8 +781,7 @@ static int
pre__t(DECL_ARGS) pre__t(DECL_ARGS)
{ {
if (n->parent && MDOC_Rs == n->parent->tok && if (n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T) {
n->parent->norm->Rs.quote_T) {
print_word("\\(lq"); print_word("\\(lq");
outflags &= ~MMAN_spc; outflags &= ~MMAN_spc;
} else } else
@ -728,8 +793,7 @@ static void
post__t(DECL_ARGS) post__t(DECL_ARGS)
{ {
if (n->parent && MDOC_Rs == n->parent->tok && if (n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T) {
n->parent->norm->Rs.quote_T) {
outflags &= ~MMAN_spc; outflags &= ~MMAN_spc;
print_word("\\(rq"); print_word("\\(rq");
} else } else
@ -1013,12 +1077,10 @@ post_bl(DECL_ARGS)
} }
static int static void
pre_br(DECL_ARGS) pre_br(DECL_ARGS)
{ {
outflags |= MMAN_br; outflags |= MMAN_br;
return 0;
} }
static int static int
@ -1263,7 +1325,7 @@ post_fo(DECL_ARGS)
} }
static int static int
pre_ft(DECL_ARGS) pre_Ft(DECL_ARGS)
{ {
pre_syn(n); pre_syn(n);
@ -1271,6 +1333,14 @@ pre_ft(DECL_ARGS)
return 1; return 1;
} }
static void
pre_ft(DECL_ARGS)
{
print_line(".ft", 0);
print_word(n->child->string);
outflags |= MMAN_nl;
}
static int static int
pre_in(DECL_ARGS) pre_in(DECL_ARGS)
{ {
@ -1465,33 +1535,63 @@ post_lb(DECL_ARGS)
static int static int
pre_lk(DECL_ARGS) pre_lk(DECL_ARGS)
{ {
const struct roff_node *link, *descr; const struct roff_node *link, *descr, *punct;
int display;
if (NULL == (link = n->child)) if ((link = n->child) == NULL)
return 0; return 0;
if (NULL != (descr = link->next)) { /* Find beginning of trailing punctuation. */
punct = n->last;
while (punct != link && punct->flags & NODE_DELIMC)
punct = punct->prev;
punct = punct->next;
/* Link text. */
if ((descr = link->next) != NULL && descr != punct) {
font_push('I'); font_push('I');
while (NULL != descr) { while (descr != punct) {
print_word(descr->string); print_word(descr->string);
descr = descr->next; descr = descr->next;
} }
print_word(":");
font_pop(); font_pop();
print_word(":");
} }
/* Link target. */
display = man_strlen(link->string) >= 26;
if (display) {
print_line(".RS", MMAN_Bk_susp);
print_word("6n");
outflags |= MMAN_nl;
}
font_push('B'); font_push('B');
print_word(link->string); print_word(link->string);
font_pop(); font_pop();
/* Trailing punctuation. */
while (punct != NULL) {
print_word(punct->string);
punct = punct->next;
}
if (display)
print_line(".RE", MMAN_nl);
return 0; return 0;
} }
static int static void
pre_ll(DECL_ARGS) pre_onearg(DECL_ARGS)
{ {
outflags |= MMAN_nl;
print_line(".ll", 0); print_word(".");
return 1; outflags &= ~MMAN_spc;
print_word(roff_name[n->tok]);
if (n->child != NULL)
print_word(n->child->string);
outflags |= MMAN_nl;
if (n->tok == ROFF_ce)
for (n = n->child->next; n != NULL; n = n->next)
print_node(meta, n);
} }
static int static int
@ -1520,7 +1620,7 @@ pre_nm(DECL_ARGS)
if (NULL == n->parent->prev) if (NULL == n->parent->prev)
outflags |= MMAN_sp; outflags |= MMAN_sp;
print_block(".HP", 0); print_block(".HP", 0);
printf(" %zun", strlen(name) + 1); printf(" %dn", man_strlen(name) + 1);
outflags |= MMAN_nl; outflags |= MMAN_nl;
} }
font_push('B'); font_push('B');
@ -1615,22 +1715,17 @@ pre_sm(DECL_ARGS)
return 0; return 0;
} }
static int static void
pre_sp(DECL_ARGS) pre_sp(DECL_ARGS)
{ {
if (outflags & MMAN_PP) {
if (MMAN_PP & outflags) {
outflags &= ~MMAN_PP; outflags &= ~MMAN_PP;
print_line(".PP", 0); print_line(".PP", 0);
} else } else {
print_line(".sp", 0); print_line(".sp", 0);
return 1; if (n->child != NULL)
} print_word(n->child->string);
}
static void
post_sp(DECL_ARGS)
{
outflags |= MMAN_nl; outflags |= MMAN_nl;
} }
@ -1642,6 +1737,15 @@ pre_sy(DECL_ARGS)
return 1; return 1;
} }
static void
pre_ta(DECL_ARGS)
{
print_line(".ta", 0);
for (n = n->child; n != NULL; n = n->next)
print_word(n->string);
outflags |= MMAN_nl;
}
static int static int
pre_vt(DECL_ARGS) pre_vt(DECL_ARGS)
{ {

1558
mdoc_markdown.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/* $Id: mdoc_state.c,v 1.4 2017/01/10 13:47:00 schwarze Exp $ */ /* $Id: mdoc_state.c,v 1.8 2017/05/05 15:17:32 schwarze Exp $ */
/* /*
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -16,6 +16,7 @@
*/ */
#include <sys/types.h> #include <sys/types.h>
#include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -35,8 +36,7 @@ static void state_dl(STATE_ARGS);
static void state_sh(STATE_ARGS); static void state_sh(STATE_ARGS);
static void state_sm(STATE_ARGS); static void state_sm(STATE_ARGS);
static const state_handler state_handlers[MDOC_MAX] = { static const state_handler __state_handlers[MDOC_MAX - MDOC_Dd] = {
NULL, /* Ap */
NULL, /* Dd */ NULL, /* Dd */
NULL, /* Dt */ NULL, /* Dt */
NULL, /* Os */ NULL, /* Os */
@ -52,6 +52,7 @@ static const state_handler state_handlers[MDOC_MAX] = {
NULL, /* It */ NULL, /* It */
NULL, /* Ad */ NULL, /* Ad */
NULL, /* An */ NULL, /* An */
NULL, /* Ap */
NULL, /* Ar */ NULL, /* Ar */
NULL, /* Cd */ NULL, /* Cd */
NULL, /* Cm */ NULL, /* Cm */
@ -154,12 +155,10 @@ static const state_handler state_handlers[MDOC_MAX] = {
NULL, /* En */ NULL, /* En */
NULL, /* Dx */ NULL, /* Dx */
NULL, /* %Q */ NULL, /* %Q */
NULL, /* br */
NULL, /* sp */
NULL, /* %U */ NULL, /* %U */
NULL, /* Ta */ NULL, /* Ta */
NULL, /* ll */
}; };
static const state_handler *const state_handlers = __state_handlers - MDOC_Dd;
void void
@ -167,9 +166,10 @@ mdoc_state(struct roff_man *mdoc, struct roff_node *n)
{ {
state_handler handler; state_handler handler;
if (n->tok == TOKEN_NONE) if (n->tok == TOKEN_NONE || n->tok < ROFF_MAX)
return; return;
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
if ( ! (mdoc_macros[n->tok].flags & MDOC_PROLOGUE)) if ( ! (mdoc_macros[n->tok].flags & MDOC_PROLOGUE))
mdoc->flags |= MDOC_PBODY; mdoc->flags |= MDOC_PBODY;

View File

@ -1,4 +1,4 @@
/* $Id: mdoc_term.c,v 1.346 2017/02/17 19:15:41 schwarze Exp $ */ /* $Id: mdoc_term.c,v 1.363 2017/06/08 12:54:58 schwarze Exp $ */
/* /*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * 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-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -106,7 +106,6 @@ static int termp_ft_pre(DECL_ARGS);
static int termp_in_pre(DECL_ARGS); static int termp_in_pre(DECL_ARGS);
static int termp_it_pre(DECL_ARGS); static int termp_it_pre(DECL_ARGS);
static int termp_li_pre(DECL_ARGS); static int termp_li_pre(DECL_ARGS);
static int termp_ll_pre(DECL_ARGS);
static int termp_lk_pre(DECL_ARGS); static int termp_lk_pre(DECL_ARGS);
static int termp_nd_pre(DECL_ARGS); static int termp_nd_pre(DECL_ARGS);
static int termp_nm_pre(DECL_ARGS); static int termp_nm_pre(DECL_ARGS);
@ -116,7 +115,7 @@ static int termp_rs_pre(DECL_ARGS);
static int termp_sh_pre(DECL_ARGS); static int termp_sh_pre(DECL_ARGS);
static int termp_skip_pre(DECL_ARGS); static int termp_skip_pre(DECL_ARGS);
static int termp_sm_pre(DECL_ARGS); static int termp_sm_pre(DECL_ARGS);
static int termp_sp_pre(DECL_ARGS); static int termp_pp_pre(DECL_ARGS);
static int termp_ss_pre(DECL_ARGS); static int termp_ss_pre(DECL_ARGS);
static int termp_sy_pre(DECL_ARGS); static int termp_sy_pre(DECL_ARGS);
static int termp_tag_pre(DECL_ARGS); static int termp_tag_pre(DECL_ARGS);
@ -125,14 +124,13 @@ static int termp_vt_pre(DECL_ARGS);
static int termp_xr_pre(DECL_ARGS); static int termp_xr_pre(DECL_ARGS);
static int termp_xx_pre(DECL_ARGS); static int termp_xx_pre(DECL_ARGS);
static const struct termact termacts[MDOC_MAX] = { static const struct termact __termacts[MDOC_MAX - MDOC_Dd] = {
{ termp_ap_pre, NULL }, /* Ap */
{ NULL, NULL }, /* Dd */ { NULL, NULL }, /* Dd */
{ NULL, NULL }, /* Dt */ { NULL, NULL }, /* Dt */
{ NULL, NULL }, /* Os */ { NULL, NULL }, /* Os */
{ termp_sh_pre, termp_sh_post }, /* Sh */ { termp_sh_pre, termp_sh_post }, /* Sh */
{ termp_ss_pre, termp_ss_post }, /* Ss */ { termp_ss_pre, termp_ss_post }, /* Ss */
{ termp_sp_pre, NULL }, /* Pp */ { termp_pp_pre, NULL }, /* Pp */
{ termp_d1_pre, termp_bl_post }, /* D1 */ { termp_d1_pre, termp_bl_post }, /* D1 */
{ termp_d1_pre, termp_bl_post }, /* Dl */ { termp_d1_pre, termp_bl_post }, /* Dl */
{ termp_bd_pre, termp_bd_post }, /* Bd */ { termp_bd_pre, termp_bd_post }, /* Bd */
@ -142,6 +140,7 @@ static const struct termact termacts[MDOC_MAX] = {
{ termp_it_pre, termp_it_post }, /* It */ { termp_it_pre, termp_it_post }, /* It */
{ termp_under_pre, NULL }, /* Ad */ { termp_under_pre, NULL }, /* Ad */
{ termp_an_pre, NULL }, /* An */ { termp_an_pre, NULL }, /* An */
{ termp_ap_pre, NULL }, /* Ap */
{ termp_under_pre, NULL }, /* Ar */ { termp_under_pre, NULL }, /* Ar */
{ termp_cd_pre, NULL }, /* Cd */ { termp_cd_pre, NULL }, /* Cd */
{ termp_bold_pre, NULL }, /* Cm */ { termp_bold_pre, NULL }, /* Cm */
@ -233,7 +232,7 @@ static const struct termact termacts[MDOC_MAX] = {
{ termp_under_pre, NULL }, /* Fr */ { termp_under_pre, NULL }, /* Fr */
{ NULL, NULL }, /* Ud */ { NULL, NULL }, /* Ud */
{ NULL, termp_lb_post }, /* Lb */ { NULL, termp_lb_post }, /* Lb */
{ termp_sp_pre, NULL }, /* Lp */ { termp_pp_pre, NULL }, /* Lp */
{ termp_lk_pre, NULL }, /* Lk */ { termp_lk_pre, NULL }, /* Lk */
{ termp_under_pre, NULL }, /* Mt */ { termp_under_pre, NULL }, /* Mt */
{ termp_quote_pre, termp_quote_post }, /* Brq */ { termp_quote_pre, termp_quote_post }, /* Brq */
@ -244,15 +243,14 @@ static const struct termact termacts[MDOC_MAX] = {
{ termp_quote_pre, termp_quote_post }, /* En */ { termp_quote_pre, termp_quote_post }, /* En */
{ termp_xx_pre, termp_xx_post }, /* Dx */ { termp_xx_pre, termp_xx_post }, /* Dx */
{ NULL, termp____post }, /* %Q */ { NULL, termp____post }, /* %Q */
{ termp_sp_pre, NULL }, /* br */
{ termp_sp_pre, NULL }, /* sp */
{ NULL, termp____post }, /* %U */ { NULL, termp____post }, /* %U */
{ NULL, NULL }, /* Ta */ { NULL, NULL }, /* Ta */
{ termp_ll_pre, NULL }, /* ll */
}; };
static const struct termact *const termacts = __termacts - MDOC_Dd;
static int fn_prio; static int fn_prio;
void void
terminal_mdoc(void *arg, const struct roff_man *mdoc) terminal_mdoc(void *arg, const struct roff_man *mdoc)
{ {
@ -261,9 +259,10 @@ terminal_mdoc(void *arg, const struct roff_man *mdoc)
size_t save_defindent; size_t save_defindent;
p = (struct termp *)arg; p = (struct termp *)arg;
p->overstep = 0; p->tcol->rmargin = p->maxrmargin = p->defrmargin;
p->rmargin = p->maxrmargin = p->defrmargin; term_tab_set(p, NULL);
p->tabwidth = term_len(p, 5); term_tab_set(p, "T");
term_tab_set(p, ".5i");
n = mdoc->first->child; n = mdoc->first->child;
if (p->synopsisonly) { if (p->synopsisonly) {
@ -317,8 +316,8 @@ print_mdoc_node(DECL_ARGS)
return; return;
chld = 1; chld = 1;
offset = p->offset; offset = p->tcol->offset;
rmargin = p->rmargin; rmargin = p->tcol->rmargin;
n->flags &= ~NODE_ENDED; n->flags &= ~NODE_ENDED;
n->prev_font = p->fonti; n->prev_font = p->fonti;
@ -342,7 +341,8 @@ print_mdoc_node(DECL_ARGS)
switch (n->type) { switch (n->type) {
case ROFFT_TEXT: case ROFFT_TEXT:
if (' ' == *n->string && NODE_LINE & n->flags) if (*n->string == ' ' && n->flags & NODE_LINE &&
(p->flags & TERMP_NONEWLINE) == 0)
term_newln(p); term_newln(p);
if (NODE_DELIMC & n->flags) if (NODE_DELIMC & n->flags)
p->flags |= TERMP_NOSPACE; p->flags |= TERMP_NOSPACE;
@ -363,7 +363,12 @@ print_mdoc_node(DECL_ARGS)
term_tbl(p, n->span); term_tbl(p, n->span);
break; break;
default: default:
if (termacts[n->tok].pre && if (n->tok < ROFF_MAX) {
roff_term_pre(p, n);
return;
}
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
if (termacts[n->tok].pre != NULL &&
(n->end == ENDBODY_NOT || n->child != NULL)) (n->end == ENDBODY_NOT || n->child != NULL))
chld = (*termacts[n->tok].pre) chld = (*termacts[n->tok].pre)
(p, &npair, meta, n); (p, &npair, meta, n);
@ -384,7 +389,7 @@ print_mdoc_node(DECL_ARGS)
case ROFFT_EQN: case ROFFT_EQN:
break; break;
default: default:
if ( ! termacts[n->tok].post || NODE_ENDED & n->flags) if (termacts[n->tok].post == NULL || n->flags & NODE_ENDED)
break; break;
(void)(*termacts[n->tok].post)(p, &npair, meta, n); (void)(*termacts[n->tok].post)(p, &npair, meta, n);
@ -401,10 +406,9 @@ print_mdoc_node(DECL_ARGS)
if (NODE_EOS & n->flags) if (NODE_EOS & n->flags)
p->flags |= TERMP_SENTENCE; p->flags |= TERMP_SENTENCE;
if (MDOC_ll != n->tok) { if (n->type != ROFFT_TEXT)
p->offset = offset; p->tcol->offset = offset;
p->rmargin = rmargin; p->tcol->rmargin = rmargin;
}
} }
static void static void
@ -424,9 +428,9 @@ print_mdoc_foot(struct termp *p, const struct roff_meta *meta)
term_vspace(p); term_vspace(p);
p->offset = 0; p->tcol->offset = 0;
sz = term_strlen(p, meta->date); sz = term_strlen(p, meta->date);
p->rmargin = p->maxrmargin > sz ? p->tcol->rmargin = p->maxrmargin > sz ?
(p->maxrmargin + term_len(p, 1) - sz) / 2 : 0; (p->maxrmargin + term_len(p, 1) - sz) / 2 : 0;
p->trailspace = 1; p->trailspace = 1;
p->flags |= TERMP_NOSPACE | TERMP_NOBREAK; p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
@ -434,16 +438,16 @@ print_mdoc_foot(struct termp *p, const struct roff_meta *meta)
term_word(p, meta->os); term_word(p, meta->os);
term_flushln(p); term_flushln(p);
p->offset = p->rmargin; p->tcol->offset = p->tcol->rmargin;
sz = term_strlen(p, meta->os); sz = term_strlen(p, meta->os);
p->rmargin = p->maxrmargin > sz ? p->maxrmargin - sz : 0; p->tcol->rmargin = p->maxrmargin > sz ? p->maxrmargin - sz : 0;
p->flags |= TERMP_NOSPACE; p->flags |= TERMP_NOSPACE;
term_word(p, meta->date); term_word(p, meta->date);
term_flushln(p); term_flushln(p);
p->offset = p->rmargin; p->tcol->offset = p->tcol->rmargin;
p->rmargin = p->maxrmargin; p->tcol->rmargin = p->maxrmargin;
p->trailspace = 0; p->trailspace = 0;
p->flags &= ~TERMP_NOBREAK; p->flags &= ~TERMP_NOBREAK;
p->flags |= TERMP_NOSPACE; p->flags |= TERMP_NOSPACE;
@ -451,8 +455,8 @@ print_mdoc_foot(struct termp *p, const struct roff_meta *meta)
term_word(p, meta->os); term_word(p, meta->os);
term_flushln(p); term_flushln(p);
p->offset = 0; p->tcol->offset = 0;
p->rmargin = p->maxrmargin; p->tcol->rmargin = p->maxrmargin;
p->flags = 0; p->flags = 0;
} }
@ -492,8 +496,8 @@ print_mdoc_head(struct termp *p, const struct roff_meta *meta)
p->flags |= TERMP_NOBREAK | TERMP_NOSPACE; p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
p->trailspace = 1; p->trailspace = 1;
p->offset = 0; p->tcol->offset = 0;
p->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ? p->tcol->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
(p->maxrmargin - vollen + term_len(p, 1)) / 2 : (p->maxrmargin - vollen + term_len(p, 1)) / 2 :
vollen < p->maxrmargin ? p->maxrmargin - vollen : 0; vollen < p->maxrmargin ? p->maxrmargin - vollen : 0;
@ -501,26 +505,26 @@ print_mdoc_head(struct termp *p, const struct roff_meta *meta)
term_flushln(p); term_flushln(p);
p->flags |= TERMP_NOSPACE; p->flags |= TERMP_NOSPACE;
p->offset = p->rmargin; p->tcol->offset = p->tcol->rmargin;
p->rmargin = p->offset + vollen + titlen < p->maxrmargin ? p->tcol->rmargin = p->tcol->offset + vollen + titlen <
p->maxrmargin - titlen : p->maxrmargin; p->maxrmargin ? p->maxrmargin - titlen : p->maxrmargin;
term_word(p, volume); term_word(p, volume);
term_flushln(p); term_flushln(p);
p->flags &= ~TERMP_NOBREAK; p->flags &= ~TERMP_NOBREAK;
p->trailspace = 0; p->trailspace = 0;
if (p->rmargin + titlen <= p->maxrmargin) { if (p->tcol->rmargin + titlen <= p->maxrmargin) {
p->flags |= TERMP_NOSPACE; p->flags |= TERMP_NOSPACE;
p->offset = p->rmargin; p->tcol->offset = p->tcol->rmargin;
p->rmargin = p->maxrmargin; p->tcol->rmargin = p->maxrmargin;
term_word(p, title); term_word(p, title);
term_flushln(p); term_flushln(p);
} }
p->flags &= ~TERMP_NOSPACE; p->flags &= ~TERMP_NOSPACE;
p->offset = 0; p->tcol->offset = 0;
p->rmargin = p->maxrmargin; p->tcol->rmargin = p->maxrmargin;
free(title); free(title);
free(volume); free(volume);
} }
@ -529,8 +533,10 @@ static int
a2width(const struct termp *p, const char *v) a2width(const struct termp *p, const char *v)
{ {
struct roffsu su; struct roffsu su;
const char *end;
if (a2roffsu(v, &su, SCALE_MAX) < 2) { end = a2roffsu(v, &su, SCALE_MAX);
if (end == NULL || *end != '\0') {
SCALE_HS_INIT(&su, term_strlen(p, v)); SCALE_HS_INIT(&su, term_strlen(p, v));
su.scale /= term_strlen(p, "0"); su.scale /= term_strlen(p, "0");
} }
@ -595,14 +601,6 @@ print_bvspace(struct termp *p,
} }
static int
termp_ll_pre(DECL_ARGS)
{
term_setwidth(p, n->child != NULL ? n->child->string : NULL);
return 0;
}
static int static int
termp_it_pre(DECL_ARGS) termp_it_pre(DECL_ARGS)
{ {
@ -653,8 +651,8 @@ termp_it_pre(DECL_ARGS)
if (bl->norm->Bl.offs != NULL) { if (bl->norm->Bl.offs != NULL) {
offset = a2width(p, bl->norm->Bl.offs); offset = a2width(p, bl->norm->Bl.offs);
if (offset < 0 && (size_t)(-offset) > p->offset) if (offset < 0 && (size_t)(-offset) > p->tcol->offset)
offset = -p->offset; offset = -p->tcol->offset;
else if (offset > SHRT_MAX) else if (offset > SHRT_MAX)
offset = 0; offset = 0;
} }
@ -718,8 +716,8 @@ termp_it_pre(DECL_ARGS)
* handling for column for how this changes. * handling for column for how this changes.
*/ */
width = a2width(p, bl->norm->Bl.width) + term_len(p, 2); width = a2width(p, bl->norm->Bl.width) + term_len(p, 2);
if (width < 0 && (size_t)(-width) > p->offset) if (width < 0 && (size_t)(-width) > p->tcol->offset)
width = -p->offset; width = -p->tcol->offset;
else if (width > SHRT_MAX) else if (width > SHRT_MAX)
width = 0; width = 0;
break; break;
@ -768,33 +766,15 @@ termp_it_pre(DECL_ARGS)
case LIST_bullet: case LIST_bullet:
case LIST_dash: case LIST_dash:
case LIST_hyphen: case LIST_hyphen:
/* if (n->type == ROFFT_HEAD) {
* Weird special case. p->flags |= TERMP_NOBREAK | TERMP_HANG;
* Some very narrow lists actually hang. p->trailspace = 1;
*/ } else if (width <= (int)term_len(p, 2))
if (width <= (int)term_len(p, 2)) p->flags |= TERMP_NOPAD;
p->flags |= TERMP_HANG;
if (n->type != ROFFT_HEAD)
break;
p->flags |= TERMP_NOBREAK;
p->trailspace = 1;
break; break;
case LIST_hang: case LIST_hang:
if (n->type != ROFFT_HEAD) if (n->type != ROFFT_HEAD)
break; break;
/*
* This is ugly. If `-hang' is specified and the body
* is a `Bl' or `Bd', then we want basically to nullify
* the "overstep" effect in term_flushln() and treat
* this as a `-ohang' list instead.
*/
if (NULL != n->next &&
NULL != n->next->child &&
(MDOC_Bl == n->next->child->tok ||
MDOC_Bd == n->next->child->tok))
break;
p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG; p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG;
p->trailspace = 1; p->trailspace = 1;
break; break;
@ -806,7 +786,7 @@ termp_it_pre(DECL_ARGS)
p->trailspace = 2; p->trailspace = 2;
if (NULL == n->next || NULL == n->next->child) if (NULL == n->next || NULL == n->next->child)
p->flags |= TERMP_DANGLE; p->flags |= TERMP_HANG;
break; break;
case LIST_column: case LIST_column:
if (n->type == ROFFT_HEAD) if (n->type == ROFFT_HEAD)
@ -837,43 +817,31 @@ termp_it_pre(DECL_ARGS)
* necessarily lengthened. Everybody gets the offset. * necessarily lengthened. Everybody gets the offset.
*/ */
p->offset += offset; p->tcol->offset += offset;
switch (type) { switch (type) {
case LIST_hang:
/*
* Same stipulation as above, regarding `-hang'. We
* don't want to recalculate rmargin and offsets when
* using `Bd' or `Bl' within `-hang' overstep lists.
*/
if (n->type == ROFFT_HEAD &&
NULL != n->next &&
NULL != n->next->child &&
(MDOC_Bl == n->next->child->tok ||
MDOC_Bd == n->next->child->tok))
break;
/* FALLTHROUGH */
case LIST_bullet: case LIST_bullet:
case LIST_dash: case LIST_dash:
case LIST_enum: case LIST_enum:
case LIST_hyphen: case LIST_hyphen:
case LIST_hang:
case LIST_tag: case LIST_tag:
if (n->type == ROFFT_HEAD) if (n->type == ROFFT_HEAD)
p->rmargin = p->offset + width; p->tcol->rmargin = p->tcol->offset + width;
else else
p->offset += width; p->tcol->offset += width;
break; break;
case LIST_column: case LIST_column:
assert(width); assert(width);
p->rmargin = p->offset + width; p->tcol->rmargin = p->tcol->offset + width;
/* /*
* XXX - this behaviour is not documented: the * XXX - this behaviour is not documented: the
* right-most column is filled to the right margin. * right-most column is filled to the right margin.
*/ */
if (n->type == ROFFT_HEAD) if (n->type == ROFFT_HEAD)
break; break;
if (NULL == n->next && p->rmargin < p->maxrmargin) if (n->next == NULL && p->tcol->rmargin < p->maxrmargin)
p->rmargin = p->maxrmargin; p->tcol->rmargin = p->maxrmargin;
break; break;
default: default:
break; break;
@ -923,6 +891,7 @@ termp_it_pre(DECL_ARGS)
case LIST_column: case LIST_column:
if (n->type == ROFFT_HEAD) if (n->type == ROFFT_HEAD)
return 0; return 0;
p->minbl = 0;
break; break;
default: default:
break; break;
@ -963,8 +932,7 @@ termp_it_post(DECL_ARGS)
* has munged them in the meanwhile. * has munged them in the meanwhile.
*/ */
p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP | TERMP_BRIND | p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP | TERMP_BRIND | TERMP_HANG);
TERMP_DANGLE | TERMP_HANG);
p->trailspace = 0; p->trailspace = 0;
} }
@ -979,7 +947,7 @@ termp_nm_pre(DECL_ARGS)
} }
if (n->type == ROFFT_BODY) { if (n->type == ROFFT_BODY) {
if (NULL == n->child) if (n->child == NULL)
return 0; return 0;
p->flags |= TERMP_NOSPACE; p->flags |= TERMP_NOSPACE;
cp = NULL; cp = NULL;
@ -988,9 +956,10 @@ termp_nm_pre(DECL_ARGS)
if (cp == NULL) if (cp == NULL)
cp = meta->name; cp = meta->name;
if (cp == NULL) if (cp == NULL)
p->offset += term_len(p, 6); p->tcol->offset += term_len(p, 6);
else else
p->offset += term_len(p, 1) + term_strlen(p, cp); p->tcol->offset += term_len(p, 1) +
term_strlen(p, cp);
return 1; return 1;
} }
@ -1001,18 +970,18 @@ termp_nm_pre(DECL_ARGS)
synopsis_pre(p, n->parent); synopsis_pre(p, n->parent);
if (n->type == ROFFT_HEAD && if (n->type == ROFFT_HEAD &&
NULL != n->next && NULL != n->next->child) { n->next != NULL && n->next->child != NULL) {
p->flags |= TERMP_NOSPACE | TERMP_NOBREAK | TERMP_BRIND; p->flags |= TERMP_NOSPACE | TERMP_NOBREAK | TERMP_BRIND;
p->trailspace = 1; p->trailspace = 1;
p->rmargin = p->offset + term_len(p, 1); p->tcol->rmargin = p->tcol->offset + term_len(p, 1);
if (NULL == n->child) { if (n->child == NULL)
p->rmargin += term_strlen(p, meta->name); p->tcol->rmargin += term_strlen(p, meta->name);
} else if (n->child->type == ROFFT_TEXT) { else if (n->child->type == ROFFT_TEXT) {
p->rmargin += term_strlen(p, n->child->string); p->tcol->rmargin += term_strlen(p, n->child->string);
if (n->child->next) if (n->child->next != NULL)
p->flags |= TERMP_HANG; p->flags |= TERMP_HANG;
} else { } else {
p->rmargin += term_len(p, 5); p->tcol->rmargin += term_len(p, 5);
p->flags |= TERMP_HANG; p->flags |= TERMP_HANG;
} }
} }
@ -1135,8 +1104,14 @@ static void
termp_bl_post(DECL_ARGS) termp_bl_post(DECL_ARGS)
{ {
if (n->type == ROFFT_BLOCK) if (n->type != ROFFT_BLOCK)
term_newln(p); return;
term_newln(p);
if (n->tok != MDOC_Bl || n->norm->Bl.type != LIST_column)
return;
term_tab_set(p, NULL);
term_tab_set(p, "T");
term_tab_set(p, ".5i");
} }
static int static int
@ -1278,7 +1253,10 @@ termp_sh_pre(DECL_ARGS)
term_fontpush(p, TERMFONT_BOLD); term_fontpush(p, TERMFONT_BOLD);
break; break;
case ROFFT_BODY: case ROFFT_BODY:
p->offset = term_len(p, p->defindent); p->tcol->offset = term_len(p, p->defindent);
term_tab_set(p, NULL);
term_tab_set(p, "T");
term_tab_set(p, ".5i");
switch (n->sec) { switch (n->sec) {
case SEC_DESCRIPTION: case SEC_DESCRIPTION:
fn_prio = 0; fn_prio = 0;
@ -1306,7 +1284,7 @@ termp_sh_post(DECL_ARGS)
break; break;
case ROFFT_BODY: case ROFFT_BODY:
term_newln(p); term_newln(p);
p->offset = 0; p->tcol->offset = 0;
break; break;
default: default:
break; break;
@ -1328,7 +1306,10 @@ termp_d1_pre(DECL_ARGS)
if (n->type != ROFFT_BLOCK) if (n->type != ROFFT_BLOCK)
return 1; return 1;
term_newln(p); term_newln(p);
p->offset += term_len(p, p->defindent + 1); p->tcol->offset += term_len(p, p->defindent + 1);
term_tab_set(p, NULL);
term_tab_set(p, "T");
term_tab_set(p, ".5i");
return 1; return 1;
} }
@ -1356,8 +1337,8 @@ termp_fn_pre(DECL_ARGS)
return 0; return 0;
if (pretty) { if (pretty) {
rmargin = p->rmargin; rmargin = p->tcol->rmargin;
p->rmargin = p->offset + term_len(p, 4); p->tcol->rmargin = p->tcol->offset + term_len(p, 4);
p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG; p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG;
} }
@ -1372,8 +1353,9 @@ termp_fn_pre(DECL_ARGS)
if (pretty) { if (pretty) {
term_flushln(p); term_flushln(p);
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG); p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
p->offset = p->rmargin; p->flags |= TERMP_NOPAD;
p->rmargin = rmargin; p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = rmargin;
} }
p->flags |= TERMP_NOSPACE; p->flags |= TERMP_NOSPACE;
@ -1434,7 +1416,7 @@ termp_fa_pre(DECL_ARGS)
static int static int
termp_bd_pre(DECL_ARGS) termp_bd_pre(DECL_ARGS)
{ {
size_t tabwidth, lm, len, rm, rmax; size_t lm, len;
struct roff_node *nn; struct roff_node *nn;
int offset; int offset;
@ -1450,15 +1432,15 @@ termp_bd_pre(DECL_ARGS)
! strcmp(n->norm->Bd.offs, "left")) ! strcmp(n->norm->Bd.offs, "left"))
/* nothing */; /* nothing */;
else if ( ! strcmp(n->norm->Bd.offs, "indent")) else if ( ! strcmp(n->norm->Bd.offs, "indent"))
p->offset += term_len(p, p->defindent + 1); p->tcol->offset += term_len(p, p->defindent + 1);
else if ( ! strcmp(n->norm->Bd.offs, "indent-two")) else if ( ! strcmp(n->norm->Bd.offs, "indent-two"))
p->offset += term_len(p, (p->defindent + 1) * 2); p->tcol->offset += term_len(p, (p->defindent + 1) * 2);
else { else {
offset = a2width(p, n->norm->Bd.offs); offset = a2width(p, n->norm->Bd.offs);
if (offset < 0 && (size_t)(-offset) > p->offset) if (offset < 0 && (size_t)(-offset) > p->tcol->offset)
p->offset = 0; p->tcol->offset = 0;
else if (offset < SHRT_MAX) else if (offset < SHRT_MAX)
p->offset += offset; p->tcol->offset += offset;
} }
/* /*
@ -1469,29 +1451,29 @@ termp_bd_pre(DECL_ARGS)
* lines are allowed. * lines are allowed.
*/ */
if (DISP_literal != n->norm->Bd.type && if (n->norm->Bd.type != DISP_literal &&
DISP_unfilled != n->norm->Bd.type && n->norm->Bd.type != DISP_unfilled &&
DISP_centered != n->norm->Bd.type) n->norm->Bd.type != DISP_centered)
return 1; return 1;
tabwidth = p->tabwidth; if (n->norm->Bd.type == DISP_literal) {
if (DISP_literal == n->norm->Bd.type) term_tab_set(p, NULL);
p->tabwidth = term_len(p, 8); term_tab_set(p, "T");
term_tab_set(p, "8n");
}
lm = p->offset; lm = p->tcol->offset;
rm = p->rmargin; p->flags |= TERMP_BRNEVER;
rmax = p->maxrmargin; for (nn = n->child; nn != NULL; nn = nn->next) {
p->rmargin = p->maxrmargin = TERM_MAXMARGIN; if (n->norm->Bd.type == DISP_centered) {
for (nn = n->child; nn; nn = nn->next) {
if (DISP_centered == n->norm->Bd.type) {
if (nn->type == ROFFT_TEXT) { if (nn->type == ROFFT_TEXT) {
len = term_strlen(p, nn->string); len = term_strlen(p, nn->string);
p->offset = len >= rm ? 0 : p->tcol->offset = len >= p->tcol->rmargin ?
lm + len >= rm ? rm - len : 0 : lm + len >= p->tcol->rmargin ?
(lm + rm - len) / 2; p->tcol->rmargin - len :
(lm + p->tcol->rmargin - len) / 2;
} else } else
p->offset = lm; p->tcol->offset = lm;
} }
print_mdoc_node(p, pair, meta, nn); print_mdoc_node(p, pair, meta, nn);
/* /*
@ -1500,10 +1482,10 @@ termp_bd_pre(DECL_ARGS)
* notion of selective eoln whitespace is pretty dumb * notion of selective eoln whitespace is pretty dumb
* anyway, so don't sweat it. * anyway, so don't sweat it.
*/ */
if (nn->tok < ROFF_MAX)
continue;
switch (nn->tok) { switch (nn->tok) {
case MDOC_Sm: case MDOC_Sm:
case MDOC_br:
case MDOC_sp:
case MDOC_Bl: case MDOC_Bl:
case MDOC_D1: case MDOC_D1:
case MDOC_Dl: case MDOC_Dl:
@ -1519,33 +1501,21 @@ termp_bd_pre(DECL_ARGS)
term_flushln(p); term_flushln(p);
p->flags |= TERMP_NOSPACE; p->flags |= TERMP_NOSPACE;
} }
p->flags &= ~TERMP_BRNEVER;
p->tabwidth = tabwidth;
p->rmargin = rm;
p->maxrmargin = rmax;
return 0; return 0;
} }
static void static void
termp_bd_post(DECL_ARGS) termp_bd_post(DECL_ARGS)
{ {
size_t rm, rmax;
if (n->type != ROFFT_BODY) if (n->type != ROFFT_BODY)
return; return;
rm = p->rmargin;
rmax = p->maxrmargin;
if (DISP_literal == n->norm->Bd.type || if (DISP_literal == n->norm->Bd.type ||
DISP_unfilled == n->norm->Bd.type) DISP_unfilled == n->norm->Bd.type)
p->rmargin = p->maxrmargin = TERM_MAXMARGIN; p->flags |= TERMP_BRNEVER;
p->flags |= TERMP_NOSPACE; p->flags |= TERMP_NOSPACE;
term_newln(p); term_newln(p);
p->flags &= ~TERMP_BRNEVER;
p->rmargin = rm;
p->maxrmargin = rmax;
} }
static int static int
@ -1587,10 +1557,13 @@ termp_ss_pre(DECL_ARGS)
break; break;
case ROFFT_HEAD: case ROFFT_HEAD:
term_fontpush(p, TERMFONT_BOLD); term_fontpush(p, TERMFONT_BOLD);
p->offset = term_len(p, (p->defindent+1)/2); p->tcol->offset = term_len(p, (p->defindent+1)/2);
break; break;
case ROFFT_BODY: case ROFFT_BODY:
p->offset = term_len(p, p->defindent); p->tcol->offset = term_len(p, p->defindent);
term_tab_set(p, NULL);
term_tab_set(p, "T");
term_tab_set(p, ".5i");
break; break;
default: default:
break; break;
@ -1650,37 +1623,10 @@ termp_in_post(DECL_ARGS)
} }
static int static int
termp_sp_pre(DECL_ARGS) termp_pp_pre(DECL_ARGS)
{ {
struct roffsu su; fn_prio = 0;
int i, len; term_vspace(p);
switch (n->tok) {
case MDOC_sp:
if (n->child) {
if ( ! a2roffsu(n->child->string, &su, SCALE_VS))
su.scale = 1.0;
len = term_vspan(p, &su);
} else
len = 1;
break;
case MDOC_br:
len = 0;
break;
default:
len = 1;
fn_prio = 0;
break;
}
if (0 == len)
term_newln(p);
else if (len < 0)
p->skipvsp -= len;
else
for (i = 0; i < len; i++)
term_vspace(p);
return 0; return 0;
} }
@ -1861,8 +1807,8 @@ termp_fo_pre(DECL_ARGS)
return 1; return 1;
} else if (n->type == ROFFT_BODY) { } else if (n->type == ROFFT_BODY) {
if (pretty) { if (pretty) {
rmargin = p->rmargin; rmargin = p->tcol->rmargin;
p->rmargin = p->offset + term_len(p, 4); p->tcol->rmargin = p->tcol->offset + term_len(p, 4);
p->flags |= TERMP_NOBREAK | TERMP_BRIND | p->flags |= TERMP_NOBREAK | TERMP_BRIND |
TERMP_HANG; TERMP_HANG;
} }
@ -1873,8 +1819,9 @@ termp_fo_pre(DECL_ARGS)
term_flushln(p); term_flushln(p);
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND |
TERMP_HANG); TERMP_HANG);
p->offset = p->rmargin; p->flags |= TERMP_NOPAD;
p->rmargin = rmargin; p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = rmargin;
} }
return 1; return 1;
} }
@ -1992,26 +1939,50 @@ termp_li_pre(DECL_ARGS)
static int static int
termp_lk_pre(DECL_ARGS) termp_lk_pre(DECL_ARGS)
{ {
const struct roff_node *link, *descr; const struct roff_node *link, *descr, *punct;
int display;
if (NULL == (link = n->child)) if ((link = n->child) == NULL)
return 0; return 0;
if (NULL != (descr = link->next)) { /* Find beginning of trailing punctuation. */
punct = n->last;
while (punct != link && punct->flags & NODE_DELIMC)
punct = punct->prev;
punct = punct->next;
/* Link text. */
if ((descr = link->next) != NULL && descr != punct) {
term_fontpush(p, TERMFONT_UNDER); term_fontpush(p, TERMFONT_UNDER);
while (NULL != descr) { while (descr != punct) {
if (descr->flags & (NODE_DELIMC | NODE_DELIMO))
p->flags |= TERMP_NOSPACE;
term_word(p, descr->string); term_word(p, descr->string);
descr = descr->next; descr = descr->next;
} }
term_fontpop(p);
p->flags |= TERMP_NOSPACE; p->flags |= TERMP_NOSPACE;
term_word(p, ":"); term_word(p, ":");
term_fontpop(p);
} }
/* Link target. */
display = term_strlen(p, link->string) >= 26;
if (display) {
term_newln(p);
p->tcol->offset += term_len(p, p->defindent + 1);
}
term_fontpush(p, TERMFONT_BOLD); term_fontpush(p, TERMFONT_BOLD);
term_word(p, link->string); term_word(p, link->string);
term_fontpop(p); term_fontpop(p);
/* Trailing punctuation. */
while (punct != NULL) {
p->flags |= TERMP_NOSPACE;
term_word(p, punct->string);
punct = punct->next;
}
if (display)
term_newln(p);
return 0; return 0;
} }

View File

@ -1,4 +1,4 @@
/* $Id: mdoc_validate.c,v 1.318 2017/02/06 03:44:58 schwarze Exp $ */ /* $Id: mdoc_validate.c,v 1.332 2017/06/08 00:23:30 schwarze Exp $ */
/* /*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -53,12 +53,13 @@ typedef void (*v_post)(POST_ARGS);
static int build_list(struct roff_man *, int); static int build_list(struct roff_man *, int);
static void check_text(struct roff_man *, int, int, char *); static void check_text(struct roff_man *, int, int, char *);
static void check_bsd(struct roff_man *, int, int, char *);
static void check_argv(struct roff_man *, static void check_argv(struct roff_man *,
struct roff_node *, struct mdoc_argv *); struct roff_node *, struct mdoc_argv *);
static void check_args(struct roff_man *, struct roff_node *); static void check_args(struct roff_man *, struct roff_node *);
static int child_an(const struct roff_node *); static int child_an(const struct roff_node *);
static size_t macro2len(int); static size_t macro2len(enum roff_tok);
static void rewrite_macro2len(char **); static void rewrite_macro2len(struct roff_man *, char **);
static void post_an(POST_ARGS); static void post_an(POST_ARGS);
static void post_an_norm(POST_ARGS); static void post_an_norm(POST_ARGS);
@ -105,11 +106,11 @@ static void post_sh_authors(POST_ARGS);
static void post_sm(POST_ARGS); static void post_sm(POST_ARGS);
static void post_st(POST_ARGS); static void post_st(POST_ARGS);
static void post_std(POST_ARGS); static void post_std(POST_ARGS);
static void post_useless(POST_ARGS);
static void post_xr(POST_ARGS); static void post_xr(POST_ARGS);
static void post_xx(POST_ARGS); static void post_xx(POST_ARGS);
static v_post mdoc_valids[MDOC_MAX] = { static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] = {
NULL, /* Ap */
post_dd, /* Dd */ post_dd, /* Dd */
post_dt, /* Dt */ post_dt, /* Dt */
post_os, /* Os */ post_os, /* Os */
@ -125,6 +126,7 @@ static v_post mdoc_valids[MDOC_MAX] = {
post_it, /* It */ post_it, /* It */
NULL, /* Ad */ NULL, /* Ad */
post_an, /* An */ post_an, /* An */
NULL, /* Ap */
post_defaults, /* Ar */ post_defaults, /* Ar */
NULL, /* Cd */ NULL, /* Cd */
NULL, /* Cm */ NULL, /* Cm */
@ -201,7 +203,7 @@ static v_post mdoc_valids[MDOC_MAX] = {
post_sm, /* Sm */ post_sm, /* Sm */
post_hyph, /* Sx */ post_hyph, /* Sx */
NULL, /* Sy */ NULL, /* Sy */
NULL, /* Tn */ post_useless, /* Tn */
post_xx, /* Ux */ post_xx, /* Ux */
NULL, /* Xc */ NULL, /* Xc */
NULL, /* Xo */ NULL, /* Xo */
@ -227,16 +229,14 @@ static v_post mdoc_valids[MDOC_MAX] = {
post_en, /* En */ post_en, /* En */
post_xx, /* Dx */ post_xx, /* Dx */
NULL, /* %Q */ NULL, /* %Q */
post_par, /* br */
post_par, /* sp */
NULL, /* %U */ NULL, /* %U */
NULL, /* Ta */ NULL, /* Ta */
NULL, /* ll */
}; };
static const v_post *const mdoc_valids = __mdoc_valids - MDOC_Dd;
#define RSORD_MAX 14 /* Number of `Rs' blocks. */ #define RSORD_MAX 14 /* Number of `Rs' blocks. */
static const int rsord[RSORD_MAX] = { static const enum roff_tok rsord[RSORD_MAX] = {
MDOC__A, MDOC__A,
MDOC__T, MDOC__T,
MDOC__B, MDOC__B,
@ -284,7 +284,7 @@ void
mdoc_node_validate(struct roff_man *mdoc) mdoc_node_validate(struct roff_man *mdoc)
{ {
struct roff_node *n; struct roff_node *n;
v_post *p; const v_post *p;
n = mdoc->last; n = mdoc->last;
mdoc->last = mdoc->last->child; mdoc->last = mdoc->last->child;
@ -303,6 +303,10 @@ mdoc_node_validate(struct roff_man *mdoc)
if (n->sec != SEC_SYNOPSIS || if (n->sec != SEC_SYNOPSIS ||
(n->parent->tok != MDOC_Cd && n->parent->tok != MDOC_Fd)) (n->parent->tok != MDOC_Cd && n->parent->tok != MDOC_Fd))
check_text(mdoc, n->line, n->pos, n->string); check_text(mdoc, n->line, n->pos, n->string);
if (n->parent->tok == MDOC_Sh ||
n->parent->tok == MDOC_Ss ||
n->parent->tok == MDOC_It)
check_bsd(mdoc, n->line, n->pos, n->string);
break; break;
case ROFFT_EQN: case ROFFT_EQN:
case ROFFT_TBL: case ROFFT_TBL:
@ -326,6 +330,20 @@ mdoc_node_validate(struct roff_man *mdoc)
/* Call the macro's postprocessor. */ /* Call the macro's postprocessor. */
if (n->tok < ROFF_MAX) {
switch(n->tok) {
case ROFF_br:
case ROFF_sp:
post_par(mdoc);
break;
default:
roff_validate(mdoc);
break;
}
break;
}
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
p = mdoc_valids + n->tok; p = mdoc_valids + n->tok;
if (*p) if (*p)
(*p)(mdoc); (*p)(mdoc);
@ -370,6 +388,25 @@ check_text(struct roff_man *mdoc, int ln, int pos, char *p)
ln, pos + (int)(p - cp), NULL); ln, pos + (int)(p - cp), NULL);
} }
static void
check_bsd(struct roff_man *mdoc, int ln, int pos, char *p)
{
const char *cp;
if ((cp = strstr(p, "OpenBSD")) != NULL)
mandoc_msg(MANDOCERR_BX, mdoc->parse,
ln, pos + (cp - p), "Ox");
if ((cp = strstr(p, "NetBSD")) != NULL)
mandoc_msg(MANDOCERR_BX, mdoc->parse,
ln, pos + (cp - p), "Nx");
if ((cp = strstr(p, "FreeBSD")) != NULL)
mandoc_msg(MANDOCERR_BX, mdoc->parse,
ln, pos + (cp - p), "Fx");
if ((cp = strstr(p, "DragonFly")) != NULL)
mandoc_msg(MANDOCERR_BX, mdoc->parse,
ln, pos + (cp - p), "Dx");
}
static void static void
post_bl_norm(POST_ARGS) post_bl_norm(POST_ARGS)
{ {
@ -450,7 +487,7 @@ post_bl_norm(POST_ARGS)
mdoc->parse, argv->line, mdoc->parse, argv->line,
argv->pos, "Bl -width %s", argv->pos, "Bl -width %s",
argv->value[0]); argv->value[0]);
rewrite_macro2len(argv->value); rewrite_macro2len(mdoc, argv->value);
n->norm->Bl.width = argv->value[0]; n->norm->Bl.width = argv->value[0];
break; break;
case MDOC_Offset: case MDOC_Offset:
@ -465,7 +502,7 @@ post_bl_norm(POST_ARGS)
mdoc->parse, argv->line, mdoc->parse, argv->line,
argv->pos, "Bl -offset %s", argv->pos, "Bl -offset %s",
argv->value[0]); argv->value[0]);
rewrite_macro2len(argv->value); rewrite_macro2len(mdoc, argv->value);
n->norm->Bl.offs = argv->value[0]; n->norm->Bl.offs = argv->value[0];
break; break;
default: default:
@ -592,7 +629,7 @@ post_bd(POST_ARGS)
mdoc->parse, argv->line, mdoc->parse, argv->line,
argv->pos, "Bd -offset %s", argv->pos, "Bd -offset %s",
argv->value[0]); argv->value[0]);
rewrite_macro2len(argv->value); rewrite_macro2len(mdoc, argv->value);
n->norm->Bd.offs = argv->value[0]; n->norm->Bd.offs = argv->value[0];
break; break;
case MDOC_Compact: case MDOC_Compact:
@ -659,11 +696,11 @@ post_eoln(POST_ARGS)
{ {
struct roff_node *n; struct roff_node *n;
post_useless(mdoc);
n = mdoc->last; n = mdoc->last;
if (n->child != NULL) if (n->child != NULL)
mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse, mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse, n->line,
n->line, n->pos, "%s %s", n->pos, "%s %s", roff_name[n->tok], n->child->string);
mdoc_macronames[n->tok], n->child->string);
while (n->child != NULL) while (n->child != NULL)
roff_node_delete(mdoc, n->child); roff_node_delete(mdoc, n->child);
@ -757,6 +794,9 @@ post_lb(POST_ARGS)
return; return;
} }
mandoc_vmsg(MANDOCERR_LB_BAD, mdoc->parse, n->child->line,
n->child->pos, "Lb %s", n->child->string);
roff_word_alloc(mdoc, n->line, n->pos, "library"); roff_word_alloc(mdoc, n->line, n->pos, "library");
mdoc->last->flags = NODE_NOSRC; mdoc->last->flags = NODE_NOSRC;
roff_word_alloc(mdoc, n->line, n->pos, "\\(Lq"); roff_word_alloc(mdoc, n->line, n->pos, "\\(Lq");
@ -817,7 +857,7 @@ post_std(POST_ARGS)
return; return;
mandoc_msg(MANDOCERR_ARG_STD, mdoc->parse, mandoc_msg(MANDOCERR_ARG_STD, mdoc->parse,
n->line, n->pos, mdoc_macronames[n->tok]); n->line, n->pos, roff_name[n->tok]);
} }
static void static void
@ -852,7 +892,17 @@ post_obsolete(POST_ARGS)
n = mdoc->last; n = mdoc->last;
if (n->type == ROFFT_ELEM || n->type == ROFFT_BLOCK) if (n->type == ROFFT_ELEM || n->type == ROFFT_BLOCK)
mandoc_msg(MANDOCERR_MACRO_OBS, mdoc->parse, mandoc_msg(MANDOCERR_MACRO_OBS, mdoc->parse,
n->line, n->pos, mdoc_macronames[n->tok]); n->line, n->pos, roff_name[n->tok]);
}
static void
post_useless(POST_ARGS)
{
struct roff_node *n;
n = mdoc->last;
mandoc_msg(MANDOCERR_MACRO_USELESS, mdoc->parse,
n->line, n->pos, roff_name[n->tok]);
} }
/* /*
@ -1029,15 +1079,25 @@ static void
post_nd(POST_ARGS) post_nd(POST_ARGS)
{ {
struct roff_node *n; struct roff_node *n;
size_t sz;
n = mdoc->last; n = mdoc->last;
if (n->type != ROFFT_BODY) if (n->type != ROFFT_BODY)
return; return;
if (n->sec != SEC_NAME)
mandoc_msg(MANDOCERR_ND_LATE, mdoc->parse,
n->line, n->pos, "Nd");
if (n->child == NULL) if (n->child == NULL)
mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse, mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse,
n->line, n->pos, "Nd"); n->line, n->pos, "Nd");
else if (n->last->type == ROFFT_TEXT &&
(sz = strlen(n->last->string)) != 0 &&
n->last->string[sz - 1] == '.')
mandoc_msg(MANDOCERR_ND_DOT, mdoc->parse,
n->last->line, n->last->pos + sz - 1, NULL);
post_hyph(mdoc); post_hyph(mdoc);
} }
@ -1056,7 +1116,7 @@ post_display(POST_ARGS)
roff_node_delete(mdoc, n); roff_node_delete(mdoc, n);
} else if (n->child == NULL) } else if (n->child == NULL)
mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse, mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
n->line, n->pos, mdoc_macronames[n->tok]); n->line, n->pos, roff_name[n->tok]);
else if (n->tok == MDOC_D1) else if (n->tok == MDOC_D1)
post_hyph(mdoc); post_hyph(mdoc);
break; break;
@ -1079,7 +1139,7 @@ post_display(POST_ARGS)
if (np->type == ROFFT_BLOCK && np->tok == MDOC_Bd) { if (np->type == ROFFT_BLOCK && np->tok == MDOC_Bd) {
mandoc_vmsg(MANDOCERR_BD_NEST, mandoc_vmsg(MANDOCERR_BD_NEST,
mdoc->parse, n->line, n->pos, mdoc->parse, n->line, n->pos,
"%s in Bd", mdoc_macronames[n->tok]); "%s in Bd", roff_name[n->tok]);
break; break;
} }
} }
@ -1265,10 +1325,10 @@ post_it(POST_ARGS)
/* FALLTHROUGH */ /* FALLTHROUGH */
case LIST_item: case LIST_item:
if ((nch = nit->head->child) != NULL) if ((nch = nit->head->child) != NULL)
mandoc_vmsg(MANDOCERR_ARG_SKIP, mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse,
mdoc->parse, nit->line, nit->pos, nit->line, nit->pos, "It %s",
"It %s", nch->string == NULL ? nch->string == NULL ? roff_name[nch->tok] :
mdoc_macronames[nch->tok] : nch->string); nch->string);
break; break;
case LIST_column: case LIST_column:
cols = (int)nbl->norm->Bl.ncols; cols = (int)nbl->norm->Bl.ncols;
@ -1306,7 +1366,7 @@ post_bl_block(POST_ARGS)
switch (nc->tok) { switch (nc->tok) {
case MDOC_Pp: case MDOC_Pp:
case MDOC_Lp: case MDOC_Lp:
case MDOC_br: case ROFF_br:
break; break;
default: default:
nc = NULL; nc = NULL;
@ -1315,14 +1375,13 @@ post_bl_block(POST_ARGS)
if (ni->next == NULL) { if (ni->next == NULL) {
mandoc_msg(MANDOCERR_PAR_MOVE, mandoc_msg(MANDOCERR_PAR_MOVE,
mdoc->parse, nc->line, nc->pos, mdoc->parse, nc->line, nc->pos,
mdoc_macronames[nc->tok]); roff_name[nc->tok]);
mdoc_node_relink(mdoc, nc); mdoc_node_relink(mdoc, nc);
} else if (n->norm->Bl.comp == 0 && } else if (n->norm->Bl.comp == 0 &&
n->norm->Bl.type != LIST_column) { n->norm->Bl.type != LIST_column) {
mandoc_vmsg(MANDOCERR_PAR_SKIP, mandoc_vmsg(MANDOCERR_PAR_SKIP,
mdoc->parse, nc->line, nc->pos, mdoc->parse, nc->line, nc->pos,
"%s before It", "%s before It", roff_name[nc->tok]);
mdoc_macronames[nc->tok]);
roff_node_delete(mdoc, nc); roff_node_delete(mdoc, nc);
} else } else
break; break;
@ -1335,17 +1394,17 @@ post_bl_block(POST_ARGS)
* If the argument of -offset or -width is a macro, * If the argument of -offset or -width is a macro,
* replace it with the associated default width. * replace it with the associated default width.
*/ */
void static void
rewrite_macro2len(char **arg) rewrite_macro2len(struct roff_man *mdoc, char **arg)
{ {
size_t width; size_t width;
int tok; enum roff_tok tok;
if (*arg == NULL) if (*arg == NULL)
return; return;
else if ( ! strcmp(*arg, "Ds")) else if ( ! strcmp(*arg, "Ds"))
width = 6; width = 6;
else if ((tok = mdoc_hash_find(*arg)) == TOKEN_NONE) else if ((tok = roffhash_find(mdoc->mdocmac, *arg, 0)) == TOKEN_NONE)
return; return;
else else
width = macro2len(tok); width = macro2len(tok);
@ -1423,6 +1482,8 @@ post_bl(POST_ARGS)
struct roff_node *nparent, *nprev; /* of the Bl block */ struct roff_node *nparent, *nprev; /* of the Bl block */
struct roff_node *nblock, *nbody; /* of the Bl */ struct roff_node *nblock, *nbody; /* of the Bl */
struct roff_node *nchild, *nnext; /* of the Bl body */ struct roff_node *nchild, *nnext; /* of the Bl body */
const char *prev_Er;
int order;
nbody = mdoc->last; nbody = mdoc->last;
switch (nbody->type) { switch (nbody->type) {
@ -1486,8 +1547,7 @@ post_bl(POST_ARGS)
} }
mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse, mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse,
nchild->line, nchild->pos, nchild->line, nchild->pos, roff_name[nchild->tok]);
mdoc_macronames[nchild->tok]);
/* /*
* Move the node out of the Bl block. * Move the node out of the Bl block.
@ -1524,6 +1584,34 @@ post_bl(POST_ARGS)
nchild = nnext; nchild = nnext;
} }
if (mdoc->meta.os_e != MDOC_OS_NETBSD)
return;
prev_Er = NULL;
for (nchild = nbody->child; nchild != NULL; nchild = nchild->next) {
if (nchild->tok != MDOC_It)
continue;
if ((nnext = nchild->head->child) == NULL)
continue;
if (nnext->type == ROFFT_BLOCK)
nnext = nnext->body->child;
if (nnext == NULL || nnext->tok != MDOC_Er)
continue;
nnext = nnext->child;
if (prev_Er != NULL) {
order = strcmp(prev_Er, nnext->string);
if (order > 0)
mandoc_vmsg(MANDOCERR_ER_ORDER,
mdoc->parse, nnext->line, nnext->pos,
"Er %s %s", prev_Er, nnext->string);
else if (order == 0)
mandoc_vmsg(MANDOCERR_ER_REP,
mdoc->parse, nnext->line, nnext->pos,
"Er %s", prev_Er);
}
prev_Er = nnext->string;
}
} }
static void static void
@ -1565,7 +1653,7 @@ post_sm(POST_ARGS)
mandoc_vmsg(MANDOCERR_SM_BAD, mandoc_vmsg(MANDOCERR_SM_BAD,
mdoc->parse, nch->line, nch->pos, mdoc->parse, nch->line, nch->pos,
"%s %s", mdoc_macronames[mdoc->last->tok], nch->string); "%s %s", roff_name[mdoc->last->tok], nch->string);
mdoc_node_relink(mdoc, nch); mdoc_node_relink(mdoc, nch);
return; return;
} }
@ -1608,7 +1696,7 @@ post_root(POST_ARGS)
mandoc_msg(MANDOCERR_DOC_EMPTY, mdoc->parse, 0, 0, NULL); mandoc_msg(MANDOCERR_DOC_EMPTY, mdoc->parse, 0, 0, NULL);
else if (n->tok != MDOC_Sh) else if (n->tok != MDOC_Sh)
mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse, mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse,
n->line, n->pos, mdoc_macronames[n->tok]); n->line, n->pos, roff_name[n->tok]);
} }
static void static void
@ -1642,9 +1730,8 @@ post_rs(POST_ARGS)
break; break;
if (i == RSORD_MAX) { if (i == RSORD_MAX) {
mandoc_msg(MANDOCERR_RS_BAD, mandoc_msg(MANDOCERR_RS_BAD, mdoc->parse,
mdoc->parse, nch->line, nch->pos, nch->line, nch->pos, roff_name[nch->tok]);
mdoc_macronames[nch->tok]);
i = -1; i = -1;
} else if (nch->tok == MDOC__J || nch->tok == MDOC__B) } else if (nch->tok == MDOC__J || nch->tok == MDOC__B)
np->norm->Rs.quote_T++; np->norm->Rs.quote_T++;
@ -1797,7 +1884,7 @@ post_sh_name(POST_ARGS)
/* FALLTHROUGH */ /* FALLTHROUGH */
default: default:
mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse, mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
n->line, n->pos, mdoc_macronames[n->tok]); n->line, n->pos, roff_name[n->tok]);
continue; continue;
} }
break; break;
@ -1867,7 +1954,7 @@ post_sh_see_also(POST_ARGS)
if (isalpha((const unsigned char)*name)) if (isalpha((const unsigned char)*name))
return; return;
lastpunct = n->string; lastpunct = n->string;
if (n->next == NULL) if (n->next == NULL || n->next->tok == MDOC_Rs)
mandoc_vmsg(MANDOCERR_XR_PUNCT, mdoc->parse, mandoc_vmsg(MANDOCERR_XR_PUNCT, mdoc->parse,
n->line, n->pos, "%s after %s(%s)", n->line, n->pos, "%s after %s(%s)",
lastpunct, lastname, lastsec); lastpunct, lastname, lastsec);
@ -1918,7 +2005,7 @@ post_sh_head(POST_ARGS)
sec != SEC_CUSTOM ? secnames[sec] : sec != SEC_CUSTOM ? secnames[sec] :
(nch = mdoc->last->child) == NULL ? "" : (nch = mdoc->last->child) == NULL ? "" :
nch->type == ROFFT_TEXT ? nch->string : nch->type == ROFFT_TEXT ? nch->string :
mdoc_macronames[nch->tok]); roff_name[nch->tok]);
/* The SYNOPSIS gets special attention in other areas. */ /* The SYNOPSIS gets special attention in other areas. */
@ -2014,6 +2101,9 @@ post_ignpar(POST_ARGS)
struct roff_node *np; struct roff_node *np;
switch (mdoc->last->type) { switch (mdoc->last->type) {
case ROFFT_BLOCK:
post_prevpar(mdoc);
return;
case ROFFT_HEAD: case ROFFT_HEAD:
post_hyph(mdoc); post_hyph(mdoc);
return; return;
@ -2027,8 +2117,8 @@ post_ignpar(POST_ARGS)
if (np->tok == MDOC_Pp || np->tok == MDOC_Lp) { if (np->tok == MDOC_Pp || np->tok == MDOC_Lp) {
mandoc_vmsg(MANDOCERR_PAR_SKIP, mandoc_vmsg(MANDOCERR_PAR_SKIP,
mdoc->parse, np->line, np->pos, mdoc->parse, np->line, np->pos,
"%s after %s", mdoc_macronames[np->tok], "%s after %s", roff_name[np->tok],
mdoc_macronames[mdoc->last->tok]); roff_name[mdoc->last->tok]);
roff_node_delete(mdoc, np); roff_node_delete(mdoc, np);
} }
@ -2036,8 +2126,8 @@ post_ignpar(POST_ARGS)
if (np->tok == MDOC_Pp || np->tok == MDOC_Lp) { if (np->tok == MDOC_Pp || np->tok == MDOC_Lp) {
mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
np->line, np->pos, "%s at the end of %s", np->line, np->pos, "%s at the end of %s",
mdoc_macronames[np->tok], roff_name[np->tok],
mdoc_macronames[mdoc->last->tok]); roff_name[mdoc->last->tok]);
roff_node_delete(mdoc, np); roff_node_delete(mdoc, np);
} }
} }
@ -2060,7 +2150,7 @@ post_prevpar(POST_ARGS)
if (n->prev->tok != MDOC_Pp && if (n->prev->tok != MDOC_Pp &&
n->prev->tok != MDOC_Lp && n->prev->tok != MDOC_Lp &&
n->prev->tok != MDOC_br) n->prev->tok != ROFF_br)
return; return;
if (n->tok == MDOC_Bl && n->norm->Bl.comp) if (n->tok == MDOC_Bl && n->norm->Bl.comp)
return; return;
@ -2070,9 +2160,8 @@ post_prevpar(POST_ARGS)
return; return;
mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
n->prev->line, n->prev->pos, n->prev->line, n->prev->pos, "%s before %s",
"%s before %s", mdoc_macronames[n->prev->tok], roff_name[n->prev->tok], roff_name[n->tok]);
mdoc_macronames[n->tok]);
roff_node_delete(mdoc, n->prev); roff_node_delete(mdoc, n->prev);
} }
@ -2082,10 +2171,10 @@ post_par(POST_ARGS)
struct roff_node *np; struct roff_node *np;
np = mdoc->last; np = mdoc->last;
if (np->tok != MDOC_br && np->tok != MDOC_sp) if (np->tok != ROFF_br && np->tok != ROFF_sp)
post_prevpar(mdoc); post_prevpar(mdoc);
if (np->tok == MDOC_sp) { if (np->tok == ROFF_sp) {
if (np->child != NULL && np->child->next != NULL) if (np->child != NULL && np->child->next != NULL)
mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
np->child->next->line, np->child->next->pos, np->child->next->line, np->child->next->pos,
@ -2093,21 +2182,20 @@ post_par(POST_ARGS)
} else if (np->child != NULL) } else if (np->child != NULL)
mandoc_vmsg(MANDOCERR_ARG_SKIP, mandoc_vmsg(MANDOCERR_ARG_SKIP,
mdoc->parse, np->line, np->pos, "%s %s", mdoc->parse, np->line, np->pos, "%s %s",
mdoc_macronames[np->tok], np->child->string); roff_name[np->tok], np->child->string);
if ((np = mdoc->last->prev) == NULL) { if ((np = mdoc->last->prev) == NULL) {
np = mdoc->last->parent; np = mdoc->last->parent;
if (np->tok != MDOC_Sh && np->tok != MDOC_Ss) if (np->tok != MDOC_Sh && np->tok != MDOC_Ss)
return; return;
} else if (np->tok != MDOC_Pp && np->tok != MDOC_Lp && } else if (np->tok != MDOC_Pp && np->tok != MDOC_Lp &&
(mdoc->last->tok != MDOC_br || (mdoc->last->tok != ROFF_br ||
(np->tok != MDOC_sp && np->tok != MDOC_br))) (np->tok != ROFF_sp && np->tok != ROFF_br)))
return; return;
mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
mdoc->last->line, mdoc->last->pos, mdoc->last->line, mdoc->last->pos, "%s after %s",
"%s after %s", mdoc_macronames[mdoc->last->tok], roff_name[mdoc->last->tok], roff_name[np->tok]);
mdoc_macronames[np->tok]);
roff_node_delete(mdoc, mdoc->last); roff_node_delete(mdoc, mdoc->last);
} }
@ -2251,11 +2339,19 @@ static void
post_bx(POST_ARGS) post_bx(POST_ARGS)
{ {
struct roff_node *n, *nch; struct roff_node *n, *nch;
const char *macro;
n = mdoc->last; n = mdoc->last;
nch = n->child; nch = n->child;
if (nch != NULL) { if (nch != NULL) {
macro = !strcmp(nch->string, "Open") ? "Ox" :
!strcmp(nch->string, "Net") ? "Nx" :
!strcmp(nch->string, "Free") ? "Fx" :
!strcmp(nch->string, "DragonFly") ? "Dx" : NULL;
if (macro != NULL)
mandoc_msg(MANDOCERR_BX, mdoc->parse,
n->line, n->pos, macro);
mdoc->last = nch; mdoc->last = nch;
nch = nch->next; nch = nch->next;
mdoc->next = ROFF_NEXT_SIBLING; mdoc->next = ROFF_NEXT_SIBLING;
@ -2322,11 +2418,11 @@ post_os(POST_ARGS)
mdoc->meta.os = NULL; mdoc->meta.os = NULL;
deroff(&mdoc->meta.os, n); deroff(&mdoc->meta.os, n);
if (mdoc->meta.os) if (mdoc->meta.os)
return; goto out;
if (mdoc->defos) { if (mdoc->defos) {
mdoc->meta.os = mandoc_strdup(mdoc->defos); mdoc->meta.os = mandoc_strdup(mdoc->defos);
return; goto out;
} }
#ifdef OSNAME #ifdef OSNAME
@ -2343,6 +2439,10 @@ post_os(POST_ARGS)
} }
mdoc->meta.os = mandoc_strdup(defbuf); mdoc->meta.os = mandoc_strdup(defbuf);
#endif /*!OSNAME*/ #endif /*!OSNAME*/
out: mdoc->meta.os_e = strstr(mdoc->meta.os, "OpenBSD") != NULL ?
MDOC_OS_OPENBSD : strstr(mdoc->meta.os, "NetBSD") != NULL ?
MDOC_OS_NETBSD : MDOC_OS_OTHER;
} }
enum roff_sec enum roff_sec
@ -2358,7 +2458,7 @@ mdoc_a2sec(const char *p)
} }
static size_t static size_t
macro2len(int macro) macro2len(enum roff_tok macro)
{ {
switch (macro) { switch (macro) {

72
out.c
View File

@ -1,7 +1,7 @@
/* $Id: out.c,v 1.62 2015/10/12 00:08:16 schwarze Exp $ */ /* $Id: out.c,v 1.65 2017/06/08 18:11:22 schwarze Exp $ */
/* /*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2011, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -29,9 +29,10 @@
#include "out.h" #include "out.h"
static void tblcalc_data(struct rofftbl *, struct roffcol *, static void tblcalc_data(struct rofftbl *, struct roffcol *,
const struct tbl_opts *, const struct tbl_dat *); const struct tbl_opts *, const struct tbl_dat *,
size_t);
static void tblcalc_literal(struct rofftbl *, struct roffcol *, static void tblcalc_literal(struct rofftbl *, struct roffcol *,
const struct tbl_dat *); const struct tbl_dat *, size_t);
static void tblcalc_number(struct rofftbl *, struct roffcol *, static void tblcalc_number(struct rofftbl *, struct roffcol *,
const struct tbl_opts *, const struct tbl_dat *); const struct tbl_opts *, const struct tbl_dat *);
@ -40,10 +41,10 @@ static void tblcalc_number(struct rofftbl *, struct roffcol *,
* Parse the *src string and store a scaling unit into *dst. * Parse the *src string and store a scaling unit into *dst.
* If the string doesn't specify the unit, use the default. * If the string doesn't specify the unit, use the default.
* If no default is specified, fail. * If no default is specified, fail.
* Return 2 on complete success, 1 when a conversion was done, * Return a pointer to the byte after the last byte used,
* but there was trailing garbage, and 0 on total failure. * or NULL on total failure.
*/ */
int const char *
a2roffsu(const char *src, struct roffsu *dst, enum roffscale def) a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
{ {
char *endptr; char *endptr;
@ -51,7 +52,7 @@ a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
dst->unit = def == SCALE_MAX ? SCALE_BU : def; dst->unit = def == SCALE_MAX ? SCALE_BU : def;
dst->scale = strtod(src, &endptr); dst->scale = strtod(src, &endptr);
if (endptr == src) if (endptr == src)
return 0; return NULL;
switch (*endptr++) { switch (*endptr++) {
case 'c': case 'c':
@ -89,12 +90,11 @@ a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
/* FALLTHROUGH */ /* FALLTHROUGH */
default: default:
if (SCALE_MAX == def) if (SCALE_MAX == def)
return 0; return NULL;
dst->unit = def; dst->unit = def;
break; break;
} }
return endptr;
return *endptr == '\0' ? 2 : 1;
} }
/* /*
@ -107,6 +107,7 @@ void
tblcalc(struct rofftbl *tbl, const struct tbl_span *sp, tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
size_t totalwidth) size_t totalwidth)
{ {
struct roffsu su;
const struct tbl_opts *opts; const struct tbl_opts *opts;
const struct tbl_dat *dp; const struct tbl_dat *dp;
struct roffcol *col; struct roffcol *col;
@ -147,7 +148,16 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
col->flags |= dp->layout->flags; col->flags |= dp->layout->flags;
if (dp->layout->flags & TBL_CELL_WIGN) if (dp->layout->flags & TBL_CELL_WIGN)
continue; continue;
tblcalc_data(tbl, col, opts, dp); if (dp->layout->wstr != NULL &&
dp->layout->width == 0 &&
a2roffsu(dp->layout->wstr, &su, SCALE_EN)
!= NULL)
dp->layout->width =
(*tbl->sulen)(&su, tbl->arg);
if (col->width < dp->layout->width)
col->width = dp->layout->width;
tblcalc_data(tbl, col, opts, dp, dp->block ?
totalwidth / (sp->opts->cols + 1) : 0);
} }
} }
@ -197,9 +207,12 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
*/ */
if (nxcol && totalwidth) { if (nxcol && totalwidth) {
xwidth = totalwidth - xwidth - 3*maxcol - xwidth += 3*maxcol +
(opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) ? (opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) ?
2 : !!opts->lvert + !!opts->rvert); 2 : !!opts->lvert + !!opts->rvert);
if (xwidth >= totalwidth)
return;
xwidth = totalwidth - xwidth;
/* /*
* Emulate a bug in GNU tbl width calculation that * Emulate a bug in GNU tbl width calculation that
@ -232,7 +245,7 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
static void static void
tblcalc_data(struct rofftbl *tbl, struct roffcol *col, tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
const struct tbl_opts *opts, const struct tbl_dat *dp) const struct tbl_opts *opts, const struct tbl_dat *dp, size_t mw)
{ {
size_t sz; size_t sz;
@ -249,7 +262,7 @@ tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
case TBL_CELL_CENTRE: case TBL_CELL_CENTRE:
case TBL_CELL_LEFT: case TBL_CELL_LEFT:
case TBL_CELL_RIGHT: case TBL_CELL_RIGHT:
tblcalc_literal(tbl, col, dp); tblcalc_literal(tbl, col, dp, mw);
break; break;
case TBL_CELL_NUMBER: case TBL_CELL_NUMBER:
tblcalc_number(tbl, col, opts, dp); tblcalc_number(tbl, col, opts, dp);
@ -263,16 +276,29 @@ tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
static void static void
tblcalc_literal(struct rofftbl *tbl, struct roffcol *col, tblcalc_literal(struct rofftbl *tbl, struct roffcol *col,
const struct tbl_dat *dp) const struct tbl_dat *dp, size_t mw)
{ {
size_t sz; const char *str; /* Beginning of the first line. */
const char *str; const char *beg; /* Beginning of the current line. */
char *end; /* End of the current line. */
size_t sz; /* Length of the current line. */
str = dp->string ? dp->string : ""; if (dp->string == NULL || *dp->string == '\0')
sz = (*tbl->slen)(str, tbl->arg); return;
str = mw ? mandoc_strdup(dp->string) : dp->string;
if (col->width < sz) for (beg = str; beg != NULL && *beg != '\0'; beg = end) {
col->width = sz; end = mw ? strchr(beg, ' ') : NULL;
if (end != NULL) {
*end++ = '\0';
while (*end == ' ')
end++;
}
sz = (*tbl->slen)(beg, tbl->arg);
if (col->width < sz)
col->width = sz;
}
if (mw)
free((void *)str);
} }
static void static void

9
out.h
View File

@ -1,6 +1,7 @@
/* $Id: out.h,v 1.27 2015/11/07 14:01:16 schwarze Exp $ */ /* $Id: out.h,v 1.29 2017/06/08 18:11:22 schwarze Exp $ */
/* /*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2017 Ingo Schwarze <schwarze@openbsd.org>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -40,14 +41,16 @@ struct roffsu {
double scale; double scale;
}; };
typedef size_t (*tbl_sulen)(const struct roffsu *, void *);
typedef size_t (*tbl_strlen)(const char *, void *); typedef size_t (*tbl_strlen)(const char *, void *);
typedef size_t (*tbl_len)(size_t, void *); typedef size_t (*tbl_len)(size_t, void *);
struct rofftbl { struct rofftbl {
tbl_sulen sulen; /* calculate scaling unit length */
tbl_strlen slen; /* calculate string length */ tbl_strlen slen; /* calculate string length */
tbl_len len; /* produce width of empty space */ tbl_len len; /* produce width of empty space */
struct roffcol *cols; /* master column specifiers */ struct roffcol *cols; /* master column specifiers */
void *arg; /* passed to slen and len */ void *arg; /* passed to sulen, slen, and len */
}; };
#define SCALE_VS_INIT(p, v) \ #define SCALE_VS_INIT(p, v) \
@ -63,6 +66,6 @@ struct rofftbl {
struct tbl_span; struct tbl_span;
int a2roffsu(const char *, struct roffsu *, enum roffscale); const char *a2roffsu(const char *, struct roffsu *, enum roffscale);
void tblcalc(struct rofftbl *tbl, void tblcalc(struct rofftbl *tbl,
const struct tbl_span *, size_t); const struct tbl_span *, size_t);

127
read.c
View File

@ -1,4 +1,4 @@
/* $Id: read.c,v 1.161 2017/02/18 17:29:28 schwarze Exp $ */ /* $Id: read.c,v 1.173 2017/06/08 00:23:30 schwarze Exp $ */
/* /*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -66,7 +66,7 @@ struct mparse {
static void choose_parser(struct mparse *); static void choose_parser(struct mparse *);
static void resize_buf(struct buf *, size_t); static void resize_buf(struct buf *, size_t);
static void mparse_buf_r(struct mparse *, struct buf, size_t, int); static int mparse_buf_r(struct mparse *, struct buf, size_t, int);
static int read_whole_file(struct mparse *, const char *, int, static int read_whole_file(struct mparse *, const char *, int,
struct buf *, int *); struct buf *, int *);
static void mparse_end(struct mparse *); static void mparse_end(struct mparse *);
@ -75,7 +75,7 @@ static void mparse_parse_buffer(struct mparse *, struct buf,
static const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = { static const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = {
MANDOCERR_OK, MANDOCERR_OK,
MANDOCERR_WARNING, MANDOCERR_STYLE,
MANDOCERR_WARNING, MANDOCERR_WARNING,
MANDOCERR_ERROR, MANDOCERR_ERROR,
MANDOCERR_UNSUPP, MANDOCERR_UNSUPP,
@ -86,6 +86,14 @@ static const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = {
static const char * const mandocerrs[MANDOCERR_MAX] = { static const char * const mandocerrs[MANDOCERR_MAX] = {
"ok", "ok",
"generic style suggestion",
"useless macro",
"consider using OS macro",
"errnos out of order",
"duplicate errno",
"description line ends with a full stop",
"generic warning", "generic warning",
/* related to the prologue */ /* related to the prologue */
@ -113,6 +121,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"bad NAME section content", "bad NAME section content",
"missing comma before name", "missing comma before name",
"missing description line, using \"\"", "missing description line, using \"\"",
"description line outside NAME section",
"sections out of conventional order", "sections out of conventional order",
"duplicate section title", "duplicate section title",
"unexpected section", "unexpected section",
@ -132,6 +141,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"fill mode already enabled, skipping", "fill mode already enabled, skipping",
"fill mode already disabled, skipping", "fill mode already disabled, skipping",
"line scope broken", "line scope broken",
"skipping blank line in line scope",
/* related to missing macro arguments */ /* related to missing macro arguments */
"skipping empty request", "skipping empty request",
@ -167,6 +177,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"unknown AT&T UNIX version", "unknown AT&T UNIX version",
"comma in function argument", "comma in function argument",
"parenthesis in function name", "parenthesis in function name",
"unknown library name",
"invalid content in Rs block", "invalid content in Rs block",
"invalid Boolean argument", "invalid Boolean argument",
"unknown font, skipping request", "unknown font, skipping request",
@ -219,6 +230,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"NOT IMPLEMENTED: Bd -file", "NOT IMPLEMENTED: Bd -file",
"skipping display without arguments", "skipping display without arguments",
"missing list type, using -item", "missing list type, using -item",
"argument is not numeric, using 1",
"missing manual name, using \"\"", "missing manual name, using \"\"",
"uname(3) system call failed, using UNKNOWN", "uname(3) system call failed, using UNKNOWN",
"unknown standard specifier", "unknown standard specifier",
@ -240,7 +252,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
static const char * const mandoclevels[MANDOCLEVEL_MAX] = { static const char * const mandoclevels[MANDOCLEVEL_MAX] = {
"SUCCESS", "SUCCESS",
"RESERVED", "STYLE",
"WARNING", "WARNING",
"ERROR", "ERROR",
"UNSUPP", "UNSUPP",
@ -292,14 +304,15 @@ choose_parser(struct mparse *curp)
} }
if (format == MPARSE_MDOC) { if (format == MPARSE_MDOC) {
mdoc_hash_init();
curp->man->macroset = MACROSET_MDOC; curp->man->macroset = MACROSET_MDOC;
curp->man->first->tok = TOKEN_NONE; if (curp->man->mdocmac == NULL)
curp->man->mdocmac = roffhash_alloc(MDOC_Dd, MDOC_MAX);
} else { } else {
man_hash_init();
curp->man->macroset = MACROSET_MAN; curp->man->macroset = MACROSET_MAN;
curp->man->first->tok = TOKEN_NONE; if (curp->man->manmac == NULL)
curp->man->manmac = roffhash_alloc(MAN_TH, MAN_MAX);
} }
curp->man->first->tok = TOKEN_NONE;
} }
/* /*
@ -309,7 +322,7 @@ choose_parser(struct mparse *curp)
* macros, inline equations, and input line traps) * macros, inline equations, and input line traps)
* and indirectly (for .so file inclusion). * and indirectly (for .so file inclusion).
*/ */
static void static int
mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start) mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
{ {
const struct tbl_span *span; const struct tbl_span *span;
@ -317,7 +330,6 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
const char *save_file; const char *save_file;
char *cp; char *cp;
size_t pos; /* byte number in the ln buffer */ size_t pos; /* byte number in the ln buffer */
size_t j; /* auxiliary byte number in the blk buffer */
enum rofferr rr; enum rofferr rr;
int of; int of;
int lnn; /* line number in the real file */ int lnn; /* line number in the real file */
@ -399,79 +411,14 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
continue; continue;
} }
/* Trailing backslash = a plain char. */
if (blk.buf[i] != '\\' || i + 1 == blk.sz) {
ln.buf[pos++] = blk.buf[i++];
continue;
}
/*
* Found escape and at least one other character.
* When it's a newline character, skip it.
* When there is a carriage return in between,
* skip that one as well.
*/
if ('\r' == blk.buf[i + 1] && i + 2 < blk.sz &&
'\n' == blk.buf[i + 2])
++i;
if ('\n' == blk.buf[i + 1]) {
i += 2;
++lnn;
continue;
}
if ('"' == blk.buf[i + 1] || '#' == blk.buf[i + 1]) {
j = i;
i += 2;
/* Comment, skip to end of line */
for (; i < blk.sz; ++i) {
if (blk.buf[i] != '\n')
continue;
if (blk.buf[i - 1] == ' ' ||
blk.buf[i - 1] == '\t')
mandoc_msg(
MANDOCERR_SPACE_EOL,
curp, curp->line,
pos + i-1 - j, NULL);
++i;
++lnn;
break;
}
/* Backout trailing whitespaces */
for (; pos > 0; --pos) {
if (ln.buf[pos - 1] != ' ')
break;
if (pos > 2 && ln.buf[pos - 2] == '\\')
break;
}
break;
}
/* Catch escaped bogus characters. */
c = (unsigned char) blk.buf[i+1];
if ( ! (isascii(c) &&
(isgraph(c) || isblank(c)))) {
mandoc_vmsg(MANDOCERR_CHAR_BAD, curp,
curp->line, pos, "0x%x", c);
i += 2;
ln.buf[pos++] = '?';
continue;
}
/* Some other escape sequence, copy & cont. */
ln.buf[pos++] = blk.buf[i++];
ln.buf[pos++] = blk.buf[i++]; ln.buf[pos++] = blk.buf[i++];
} }
if (pos >= ln.sz) if (pos + 1 >= ln.sz)
resize_buf(&ln, 256); resize_buf(&ln, 256);
if (i == blk.sz || blk.buf[i] == '\0')
ln.buf[pos++] = '\n';
ln.buf[pos] = '\0'; ln.buf[pos] = '\0';
/* /*
@ -510,13 +457,16 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
switch (rr) { switch (rr) {
case ROFF_REPARSE: case ROFF_REPARSE:
if (REPARSE_LIMIT >= ++curp->reparse_count) if (++curp->reparse_count > REPARSE_LIMIT)
mparse_buf_r(curp, ln, of, 0);
else
mandoc_msg(MANDOCERR_ROFFLOOP, curp, mandoc_msg(MANDOCERR_ROFFLOOP, curp,
curp->line, pos, NULL); curp->line, pos, NULL);
pos = 0; else if (mparse_buf_r(curp, ln, of, 0) == 1 ||
continue; start == 1) {
pos = 0;
continue;
}
free(ln.buf);
return 0;
case ROFF_APPEND: case ROFF_APPEND:
pos = strlen(ln.buf); pos = strlen(ln.buf);
continue; continue;
@ -530,7 +480,7 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
(i >= blk.sz || blk.buf[i] == '\0')) { (i >= blk.sz || blk.buf[i] == '\0')) {
curp->sodest = mandoc_strdup(ln.buf + of); curp->sodest = mandoc_strdup(ln.buf + of);
free(ln.buf); free(ln.buf);
return; return 1;
} }
/* /*
* We remove `so' clauses from our lookaside * We remove `so' clauses from our lookaside
@ -596,6 +546,7 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
} }
free(ln.buf); free(ln.buf);
return 1;
} }
static int static int
@ -813,11 +764,13 @@ mparse_alloc(int options, enum mandoclevel wlevel, mandocmsg mmsg,
curp->man = roff_man_alloc( curp->roff, curp, curp->defos, curp->man = roff_man_alloc( curp->roff, curp, curp->defos,
curp->options & MPARSE_QUICK ? 1 : 0); curp->options & MPARSE_QUICK ? 1 : 0);
if (curp->options & MPARSE_MDOC) { if (curp->options & MPARSE_MDOC) {
mdoc_hash_init();
curp->man->macroset = MACROSET_MDOC; curp->man->macroset = MACROSET_MDOC;
if (curp->man->mdocmac == NULL)
curp->man->mdocmac = roffhash_alloc(MDOC_Dd, MDOC_MAX);
} else if (curp->options & MPARSE_MAN) { } else if (curp->options & MPARSE_MAN) {
man_hash_init();
curp->man->macroset = MACROSET_MAN; curp->man->macroset = MACROSET_MAN;
if (curp->man->manmac == NULL)
curp->man->manmac = roffhash_alloc(MAN_TH, MAN_MAX);
} }
curp->man->first->tok = TOKEN_NONE; curp->man->first->tok = TOKEN_NONE;
return curp; return curp;
@ -843,6 +796,8 @@ void
mparse_free(struct mparse *curp) mparse_free(struct mparse *curp)
{ {
roffhash_free(curp->man->mdocmac);
roffhash_free(curp->man->manmac);
roff_man_free(curp->man); roff_man_free(curp->man);
roff_free(curp->roff); roff_free(curp->roff);
if (curp->secondary) if (curp->secondary)

912
roff.7

File diff suppressed because it is too large Load Diff

1369
roff.c

File diff suppressed because it is too large Load Diff

426
roff.h
View File

@ -1,4 +1,4 @@
/* $Id: roff.h,v 1.40 2017/02/16 03:00:23 schwarze Exp $ */ /* $Id: roff.h,v 1.52 2017/06/07 23:29:49 schwarze Exp $ */
/* /*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * 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 Ingo Schwarze <schwarze@openbsd.org>
@ -16,6 +16,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
struct ohash;
struct mdoc_arg; struct mdoc_arg;
union mdoc_data; union mdoc_data;
@ -25,6 +26,12 @@ enum roff_macroset {
MACROSET_MAN MACROSET_MAN
}; };
enum mdoc_os {
MDOC_OS_OTHER = 0,
MDOC_OS_NETBSD,
MDOC_OS_OPENBSD
};
enum roff_sec { enum roff_sec {
SEC_NONE = 0, SEC_NONE = 0,
SEC_NAME, SEC_NAME,
@ -64,6 +71,411 @@ enum roff_type {
ROFFT_EQN ROFFT_EQN
}; };
enum roff_tok {
ROFF_br = 0,
ROFF_ce,
ROFF_ft,
ROFF_ll,
ROFF_mc,
ROFF_sp,
ROFF_ta,
ROFF_ti,
ROFF_MAX,
ROFF_ab,
ROFF_ad,
ROFF_af,
ROFF_aln,
ROFF_als,
ROFF_am,
ROFF_am1,
ROFF_ami,
ROFF_ami1,
ROFF_as,
ROFF_as1,
ROFF_asciify,
ROFF_backtrace,
ROFF_bd,
ROFF_bleedat,
ROFF_blm,
ROFF_box,
ROFF_boxa,
ROFF_bp,
ROFF_BP,
ROFF_break,
ROFF_breakchar,
ROFF_brnl,
ROFF_brp,
ROFF_brpnl,
ROFF_c2,
ROFF_cc,
ROFF_cf,
ROFF_cflags,
ROFF_ch,
ROFF_char,
ROFF_chop,
ROFF_class,
ROFF_close,
ROFF_CL,
ROFF_color,
ROFF_composite,
ROFF_continue,
ROFF_cp,
ROFF_cropat,
ROFF_cs,
ROFF_cu,
ROFF_da,
ROFF_dch,
ROFF_Dd,
ROFF_de,
ROFF_de1,
ROFF_defcolor,
ROFF_dei,
ROFF_dei1,
ROFF_device,
ROFF_devicem,
ROFF_di,
ROFF_do,
ROFF_ds,
ROFF_ds1,
ROFF_dwh,
ROFF_dt,
ROFF_ec,
ROFF_ecr,
ROFF_ecs,
ROFF_el,
ROFF_em,
ROFF_EN,
ROFF_eo,
ROFF_EP,
ROFF_EQ,
ROFF_errprint,
ROFF_ev,
ROFF_evc,
ROFF_ex,
ROFF_fallback,
ROFF_fam,
ROFF_fc,
ROFF_fchar,
ROFF_fcolor,
ROFF_fdeferlig,
ROFF_feature,
/* MAN_fi; ignored in mdoc(7) */
ROFF_fkern,
ROFF_fl,
ROFF_flig,
ROFF_fp,
ROFF_fps,
ROFF_fschar,
ROFF_fspacewidth,
ROFF_fspecial,
ROFF_ftr,
ROFF_fzoom,
ROFF_gcolor,
ROFF_hc,
ROFF_hcode,
ROFF_hidechar,
ROFF_hla,
ROFF_hlm,
ROFF_hpf,
ROFF_hpfa,
ROFF_hpfcode,
ROFF_hw,
ROFF_hy,
ROFF_hylang,
ROFF_hylen,
ROFF_hym,
ROFF_hypp,
ROFF_hys,
ROFF_ie,
ROFF_if,
ROFF_ig,
/* MAN_in; ignored in mdoc(7) */
ROFF_index,
ROFF_it,
ROFF_itc,
ROFF_IX,
ROFF_kern,
ROFF_kernafter,
ROFF_kernbefore,
ROFF_kernpair,
ROFF_lc,
ROFF_lc_ctype,
ROFF_lds,
ROFF_length,
ROFF_letadj,
ROFF_lf,
ROFF_lg,
ROFF_lhang,
ROFF_linetabs,
ROFF_lnr,
ROFF_lnrf,
ROFF_lpfx,
ROFF_ls,
ROFF_lsm,
ROFF_lt,
ROFF_mediasize,
ROFF_minss,
ROFF_mk,
ROFF_mso,
ROFF_na,
ROFF_ne,
/* MAN_nf; ignored in mdoc(7) */
ROFF_nh,
ROFF_nhychar,
ROFF_nm,
ROFF_nn,
ROFF_nop,
ROFF_nr,
ROFF_nrf,
ROFF_nroff,
ROFF_ns,
ROFF_nx,
ROFF_open,
ROFF_opena,
ROFF_os,
ROFF_output,
ROFF_padj,
ROFF_papersize,
ROFF_pc,
ROFF_pev,
ROFF_pi,
ROFF_PI,
ROFF_pl,
ROFF_pm,
ROFF_pn,
ROFF_pnr,
ROFF_po,
ROFF_ps,
ROFF_psbb,
ROFF_pshape,
ROFF_pso,
ROFF_ptr,
ROFF_pvs,
ROFF_rchar,
ROFF_rd,
ROFF_recursionlimit,
ROFF_return,
ROFF_rfschar,
ROFF_rhang,
ROFF_rj,
ROFF_rm,
ROFF_rn,
ROFF_rnn,
ROFF_rr,
ROFF_rs,
ROFF_rt,
ROFF_schar,
ROFF_sentchar,
ROFF_shc,
ROFF_shift,
ROFF_sizes,
ROFF_so,
ROFF_spacewidth,
ROFF_special,
ROFF_spreadwarn,
ROFF_ss,
ROFF_sty,
ROFF_substring,
ROFF_sv,
ROFF_sy,
ROFF_T_,
ROFF_tc,
ROFF_TE,
ROFF_TH,
ROFF_tkf,
ROFF_tl,
ROFF_tm,
ROFF_tm1,
ROFF_tmc,
ROFF_tr,
ROFF_track,
ROFF_transchar,
ROFF_trf,
ROFF_trimat,
ROFF_trin,
ROFF_trnt,
ROFF_troff,
ROFF_TS,
ROFF_uf,
ROFF_ul,
ROFF_unformat,
ROFF_unwatch,
ROFF_unwatchn,
ROFF_vpt,
ROFF_vs,
ROFF_warn,
ROFF_warnscale,
ROFF_watch,
ROFF_watchlength,
ROFF_watchn,
ROFF_wh,
ROFF_while,
ROFF_write,
ROFF_writec,
ROFF_writem,
ROFF_xflag,
ROFF_cblock,
ROFF_RENAMED,
ROFF_USERDEF,
TOKEN_NONE,
MDOC_Dd,
MDOC_Dt,
MDOC_Os,
MDOC_Sh,
MDOC_Ss,
MDOC_Pp,
MDOC_D1,
MDOC_Dl,
MDOC_Bd,
MDOC_Ed,
MDOC_Bl,
MDOC_El,
MDOC_It,
MDOC_Ad,
MDOC_An,
MDOC_Ap,
MDOC_Ar,
MDOC_Cd,
MDOC_Cm,
MDOC_Dv,
MDOC_Er,
MDOC_Ev,
MDOC_Ex,
MDOC_Fa,
MDOC_Fd,
MDOC_Fl,
MDOC_Fn,
MDOC_Ft,
MDOC_Ic,
MDOC_In,
MDOC_Li,
MDOC_Nd,
MDOC_Nm,
MDOC_Op,
MDOC_Ot,
MDOC_Pa,
MDOC_Rv,
MDOC_St,
MDOC_Va,
MDOC_Vt,
MDOC_Xr,
MDOC__A,
MDOC__B,
MDOC__D,
MDOC__I,
MDOC__J,
MDOC__N,
MDOC__O,
MDOC__P,
MDOC__R,
MDOC__T,
MDOC__V,
MDOC_Ac,
MDOC_Ao,
MDOC_Aq,
MDOC_At,
MDOC_Bc,
MDOC_Bf,
MDOC_Bo,
MDOC_Bq,
MDOC_Bsx,
MDOC_Bx,
MDOC_Db,
MDOC_Dc,
MDOC_Do,
MDOC_Dq,
MDOC_Ec,
MDOC_Ef,
MDOC_Em,
MDOC_Eo,
MDOC_Fx,
MDOC_Ms,
MDOC_No,
MDOC_Ns,
MDOC_Nx,
MDOC_Ox,
MDOC_Pc,
MDOC_Pf,
MDOC_Po,
MDOC_Pq,
MDOC_Qc,
MDOC_Ql,
MDOC_Qo,
MDOC_Qq,
MDOC_Re,
MDOC_Rs,
MDOC_Sc,
MDOC_So,
MDOC_Sq,
MDOC_Sm,
MDOC_Sx,
MDOC_Sy,
MDOC_Tn,
MDOC_Ux,
MDOC_Xc,
MDOC_Xo,
MDOC_Fo,
MDOC_Fc,
MDOC_Oo,
MDOC_Oc,
MDOC_Bk,
MDOC_Ek,
MDOC_Bt,
MDOC_Hf,
MDOC_Fr,
MDOC_Ud,
MDOC_Lb,
MDOC_Lp,
MDOC_Lk,
MDOC_Mt,
MDOC_Brq,
MDOC_Bro,
MDOC_Brc,
MDOC__C,
MDOC_Es,
MDOC_En,
MDOC_Dx,
MDOC__Q,
MDOC__U,
MDOC_Ta,
MDOC_MAX,
MAN_TH,
MAN_SH,
MAN_SS,
MAN_TP,
MAN_LP,
MAN_PP,
MAN_P,
MAN_IP,
MAN_HP,
MAN_SM,
MAN_SB,
MAN_BI,
MAN_IB,
MAN_BR,
MAN_RB,
MAN_R,
MAN_B,
MAN_I,
MAN_IR,
MAN_RI,
MAN_nf,
MAN_fi,
MAN_RE,
MAN_RS,
MAN_DT,
MAN_UC,
MAN_PD,
MAN_AT,
MAN_in,
MAN_OP,
MAN_EX,
MAN_EE,
MAN_UR,
MAN_UE,
MAN_MAX
};
enum roff_next { enum roff_next {
ROFF_NEXT_SIBLING = 0, ROFF_NEXT_SIBLING = 0,
ROFF_NEXT_CHILD ROFF_NEXT_CHILD
@ -94,8 +506,6 @@ struct roff_node {
const struct eqn *eqn; /* EQN */ const struct eqn *eqn; /* EQN */
int line; /* Input file line number. */ int line; /* Input file line number. */
int pos; /* Input file column number. */ int pos; /* Input file column number. */
int tok; /* Request or macro ID. */
#define TOKEN_NONE (-1) /* No request or macro. */
int flags; int flags;
#define NODE_VALID (1 << 0) /* Has been validated. */ #define NODE_VALID (1 << 0) /* Has been validated. */
#define NODE_ENDED (1 << 1) /* Gone past body end mark. */ #define NODE_ENDED (1 << 1) /* Gone past body end mark. */
@ -109,6 +519,7 @@ struct roff_node {
#define NODE_NOPRT (1 << 9) /* Shall not print anything. */ #define NODE_NOPRT (1 << 9) /* Shall not print anything. */
int prev_font; /* Before entering this node. */ int prev_font; /* Before entering this node. */
int aux; /* Decoded node data, type-dependent. */ int aux; /* Decoded node data, type-dependent. */
enum roff_tok tok; /* Request or macro ID. */
enum roff_type type; /* AST node type. */ enum roff_type type; /* AST node type. */
enum roff_sec sec; /* Current named section. */ enum roff_sec sec; /* Current named section. */
enum mdoc_endbody end; /* BODY */ enum mdoc_endbody end; /* BODY */
@ -123,12 +534,15 @@ struct roff_meta {
char *name; /* Leading manual name. */ char *name; /* Leading manual name. */
char *date; /* Normalized date. */ char *date; /* Normalized date. */
int hasbody; /* Document is not empty. */ int hasbody; /* Document is not empty. */
enum mdoc_os os_e; /* Operating system. */
}; };
struct roff_man { struct roff_man {
struct roff_meta meta; /* Document meta-data. */ struct roff_meta meta; /* Document meta-data. */
struct mparse *parse; /* Parse pointer. */ struct mparse *parse; /* Parse pointer. */
struct roff *roff; /* Roff parser state data. */ struct roff *roff; /* Roff parser state data. */
struct ohash *mdocmac; /* Mdoc macro lookup table. */
struct ohash *manmac; /* Man macro lookup table. */
const char *defos; /* Default operating system. */ const char *defos; /* Default operating system. */
struct roff_node *first; /* The first node parsed. */ struct roff_node *first; /* The first node parsed. */
struct roff_node *last; /* The last node parsed. */ struct roff_node *last; /* The last node parsed. */
@ -158,5 +572,11 @@ struct roff_man {
enum roff_next next; /* Where to put the next node. */ enum roff_next next; /* Where to put the next node. */
}; };
extern const char *const *roff_name;
void deroff(char **, const struct roff_node *); 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 *);

93
roff_html.c Normal file
View File

@ -0,0 +1,93 @@
/* $Id: roff_html.c,v 1.8 2017/06/08 12:54:58 schwarze Exp $ */
/*
* Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 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 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 <sys/types.h>
#include <assert.h>
#include <stddef.h>
#include "roff.h"
#include "out.h"
#include "html.h"
#define ROFF_HTML_ARGS struct html *h, const struct roff_node *n
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_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 */
NULL, /* ll */
NULL, /* mc */
roff_html_pre_sp, /* sp */
NULL, /* ta */
NULL, /* ti */
};
void
roff_html_pre(struct html *h, const struct roff_node *n)
{
assert(n->tok < ROFF_MAX);
if (roff_html_pre_acts[n->tok] != NULL)
(*roff_html_pre_acts[n->tok])(h, 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);
}
static void
roff_html_pre_ce(ROFF_HTML_ARGS)
{
for (n = n->child->next; n != NULL; n = n->next) {
if (n->type == ROFFT_TEXT) {
if (n->flags & NODE_LINE)
roff_html_pre_br(h, n);
print_text(h, n->string);
} else
roff_html_pre(h, n);
}
roff_html_pre_br(h, n);
}
static void
roff_html_pre_sp(ROFF_HTML_ARGS)
{
struct roffsu su;
SCALE_VS_INIT(&su, 1);
if ((n = n->child) != NULL) {
if (a2roffsu(n->string, &su, SCALE_VS) == NULL)
su.scale = 1.0;
else if (su.scale < 0.0)
su.scale = 0.0;
}
print_otag(h, TAG_DIV, "suh", &su);
print_text(h, "\\~"); /* So the div isn't empty. */
}

221
roff_term.c Normal file
View File

@ -0,0 +1,221 @@
/* $Id: roff_term.c,v 1.10 2017/06/08 12:54:58 schwarze Exp $ */
/*
* Copyright (c) 2010, 2014, 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
* 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 <sys/types.h>
#include <assert.h>
#include <stddef.h>
#include "roff.h"
#include "out.h"
#include "term.h"
#define ROFF_TERM_ARGS struct termp *p, const struct roff_node *n
typedef void (*roff_term_pre_fp)(ROFF_TERM_ARGS);
static void roff_term_pre_br(ROFF_TERM_ARGS);
static void roff_term_pre_ce(ROFF_TERM_ARGS);
static void roff_term_pre_ft(ROFF_TERM_ARGS);
static void roff_term_pre_ll(ROFF_TERM_ARGS);
static void roff_term_pre_mc(ROFF_TERM_ARGS);
static void roff_term_pre_sp(ROFF_TERM_ARGS);
static void roff_term_pre_ta(ROFF_TERM_ARGS);
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_ft, /* ft */
roff_term_pre_ll, /* ll */
roff_term_pre_mc, /* mc */
roff_term_pre_sp, /* sp */
roff_term_pre_ta, /* ta */
roff_term_pre_ti, /* ti */
};
void
roff_term_pre(struct termp *p, const struct roff_node *n)
{
assert(n->tok < ROFF_MAX);
(*roff_term_pre_acts[n->tok])(p, n);
}
static void
roff_term_pre_br(ROFF_TERM_ARGS)
{
term_newln(p);
if (p->flags & TERMP_BRIND) {
p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = p->maxrmargin;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
}
}
static void
roff_term_pre_ce(ROFF_TERM_ARGS)
{
const struct roff_node *nch;
size_t len, lm;
roff_term_pre_br(p, n);
lm = p->tcol->offset;
n = n->child->next;
while (n != NULL) {
nch = n;
len = 0;
do {
if (n->type == ROFFT_TEXT) {
if (len)
len++;
len += term_strlen(p, nch->string);
}
nch = nch->next;
} while (nch != NULL && (n->type != ROFFT_TEXT ||
(n->flags & NODE_LINE) == 0));
p->tcol->offset = len >= p->tcol->rmargin ? 0 :
lm + len >= p->tcol->rmargin ? p->tcol->rmargin - len :
(lm + p->tcol->rmargin - len) / 2;
while (n != nch) {
if (n->type == ROFFT_TEXT)
term_word(p, n->string);
else
roff_term_pre(p, n);
n = n->next;
}
p->flags |= TERMP_NOSPACE;
term_flushln(p);
}
p->tcol->offset = lm;
}
static void
roff_term_pre_ft(ROFF_TERM_ARGS)
{
switch (*n->child->string) {
case '4':
case '3':
case 'B':
term_fontrepl(p, TERMFONT_BOLD);
break;
case '2':
case 'I':
term_fontrepl(p, TERMFONT_UNDER);
break;
case 'P':
term_fontlast(p);
break;
case '1':
case 'C':
case 'R':
term_fontrepl(p, TERMFONT_NONE);
break;
default:
break;
}
}
static void
roff_term_pre_ll(ROFF_TERM_ARGS)
{
term_setwidth(p, n->child != NULL ? n->child->string : NULL);
}
static void
roff_term_pre_mc(ROFF_TERM_ARGS)
{
if (p->col) {
p->flags |= TERMP_NOBREAK;
term_flushln(p);
p->flags &= ~(TERMP_NOBREAK | TERMP_NOSPACE);
}
if (n->child != NULL) {
p->mc = n->child->string;
p->flags |= TERMP_NEWMC;
} else
p->flags |= TERMP_ENDMC;
}
static void
roff_term_pre_sp(ROFF_TERM_ARGS)
{
struct roffsu su;
int len;
if (n->child != NULL) {
if (a2roffsu(n->child->string, &su, SCALE_VS) == NULL)
su.scale = 1.0;
len = term_vspan(p, &su);
} else
len = 1;
if (len < 0)
p->skipvsp -= len;
else
while (len--)
term_vspace(p);
roff_term_pre_br(p, n);
}
static void
roff_term_pre_ta(ROFF_TERM_ARGS)
{
term_tab_set(p, NULL);
for (n = n->child; n != NULL; n = n->next)
term_tab_set(p, n->string);
}
static void
roff_term_pre_ti(ROFF_TERM_ARGS)
{
struct roffsu su;
const char *cp;
int len, sign;
roff_term_pre_br(p, n);
if (n->child == NULL)
return;
cp = n->child->string;
if (*cp == '+') {
sign = 1;
cp++;
} else if (*cp == '-') {
sign = -1;
cp++;
} else
sign = 0;
if (a2roffsu(cp, &su, SCALE_EM) == NULL)
return;
len = term_hspan(p, &su) / 24;
if (sign == 0) {
p->ti = len - p->tcol->offset;
p->tcol->offset = len;
} else if (sign == 1) {
p->ti = len;
p->tcol->offset += len;
} else if ((size_t)len < p->tcol->offset) {
p->ti = -len;
p->tcol->offset -= len;
} else {
p->ti = -p->tcol->offset;
p->tcol->offset = 0;
}
}

95
roff_validate.c Normal file
View File

@ -0,0 +1,95 @@
/* $Id: roff_validate.c,v 1.7 2017/06/06 15:01:04 schwarze Exp $ */
/*
* Copyright (c) 2010, 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 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 <sys/types.h>
#include <assert.h>
#include <stddef.h>
#include "mandoc.h"
#include "roff.h"
#include "libmandoc.h"
#include "roff_int.h"
#define ROFF_VALID_ARGS struct roff_man *man, struct roff_node *n
typedef void (*roff_valid_fp)(ROFF_VALID_ARGS);
static void roff_valid_ft(ROFF_VALID_ARGS);
static const roff_valid_fp roff_valids[ROFF_MAX] = {
NULL, /* br */
NULL, /* ce */
roff_valid_ft, /* ft */
NULL, /* ll */
NULL, /* mc */
NULL, /* sp */
NULL, /* ta */
NULL, /* ti */
};
void
roff_validate(struct roff_man *man)
{
struct roff_node *n;
n = man->last;
assert(n->tok < ROFF_MAX);
if (roff_valids[n->tok] != NULL)
(*roff_valids[n->tok])(man, n);
}
static void
roff_valid_ft(ROFF_VALID_ARGS)
{
char *cp;
if (n->child == NULL) {
man->next = ROFF_NEXT_CHILD;
roff_word_alloc(man, n->line, n->pos, "P");
man->last = n;
return;
}
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;
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;
break;
default:
break;
}
mandoc_vmsg(MANDOCERR_FT_BAD, man->parse,
n->line, n->pos, "ft %s", cp);
roff_node_delete(man, n);
}

View File

@ -1,4 +1,4 @@
.\" $Id: soelim.1,v 1.3 2015/05/20 22:59:12 schwarze Exp $ .\" $Id: soelim.1,v 1.4 2017/03/18 19:56:01 schwarze Exp $
.\" .\"
.\" Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org> .\" Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org>
.\" All rights reserved. .\" All rights reserved.
@ -24,7 +24,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE. .\" SUCH DAMAGE.
.\" .\"
.Dd $Mdocdate: May 20 2015 $ .Dd $Mdocdate: March 18 2017 $
.Dt SOELIM 1 .Dt SOELIM 1
.Os .Os
.Sh NAME .Sh NAME
@ -69,8 +69,8 @@ This option specify directories where
searches for files (both those on the command line and those named in searches for files (both those on the command line and those named in
.Dq .so .Dq .so
directive.) directive.)
This options may be specified multiple times. The directories will be searched This options may be specified multiple times.
in the order specified. The directories will be searched in the order specified.
.El .El
.Pp .Pp
The files are always searched first in the current directory. The files are always searched first in the current directory.

13
tbl.7
View File

@ -1,7 +1,7 @@
.\" $Id: tbl.7,v 1.26 2015/01/29 00:33:57 schwarze Exp $ .\" $Id: tbl.7,v 1.27 2017/06/08 18:11:22 schwarze Exp $
.\" .\"
.\" Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> .\" Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
.\" Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> .\" Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
.\" .\"
.\" Permission to use, copy, modify, and distribute this software for any .\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above .\" 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 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: January 29 2015 $ .Dd $Mdocdate: June 8 2017 $
.Dt TBL 7 .Dt TBL 7
.Os .Os
.Sh NAME .Sh NAME
@ -245,7 +245,7 @@ Emit a double-vertical bar instead of data.
.Pp .Pp
Keys may be followed by a set of modifiers. Keys may be followed by a set of modifiers.
A modifier is either a modifier key or a natural number for specifying A modifier is either a modifier key or a natural number for specifying
the minimum width of a column. the spacing to the right of the column.
The following case-insensitive modifier keys are available: The following case-insensitive modifier keys are available:
.Bl -tag -width 2n .Bl -tag -width 2n
.It Cm b .It Cm b
@ -284,8 +284,7 @@ Currently ignored.
Move cell content up by half a table line. Move cell content up by half a table line.
Currently ignored. Currently ignored.
.It Cm w .It Cm w
Specify minimum column width. Specify the minimum column width.
Currently ignored.
.It Cm x .It Cm x
After determining the width of all other columns, distribute the After determining the width of all other columns, distribute the
rest of the line length among all columns having the rest of the line length among all columns having the
@ -300,7 +299,7 @@ minimum width 10, followed by vertical bar, followed by a left-justified
column of minimum width 10, another vertical bar, then a column using column of minimum width 10, another vertical bar, then a column using
bold font justified about the decimal point in numbers: bold font justified about the decimal point in numbers:
.Pp .Pp
.Dl c10 | l10 | nfB .Dl cw10 | lw10 | nfB
.Ss Data .Ss Data
The data section follows the last layout row. The data section follows the last layout row.
By default, cells in a data section are delimited by a tab. By default, cells in a data section are delimited by a tab.

3
tbl.c
View File

@ -1,4 +1,4 @@
/* $Id: tbl.c,v 1.40 2015/10/06 18:32:20 schwarze Exp $ */ /* $Id: tbl.c,v 1.41 2017/06/08 18:11:22 schwarze Exp $ */
/* /*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2015 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2011, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -114,6 +114,7 @@ tbl_free(struct tbl_node *tbl)
while (rp->first != NULL) { while (rp->first != NULL) {
cp = rp->first; cp = rp->first;
rp->first = cp->next; rp->first = cp->next;
free(cp->wstr);
free(cp); free(cp);
} }
free(rp); free(rp);

View File

@ -1,7 +1,7 @@
/* $Id: tbl_data.c,v 1.41 2015/10/06 18:32:20 schwarze Exp $ */ /* $Id: tbl_data.c,v 1.42 2017/06/08 18:11:22 schwarze Exp $ */
/* /*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2015 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2011, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -144,6 +144,7 @@ tbl_cdata(struct tbl_node *tbl, int ln, const char *p, int pos)
} }
dat->pos = TBL_DATA_DATA; dat->pos = TBL_DATA_DATA;
dat->block = 1;
if (dat->string != NULL) { if (dat->string != NULL) {
sz = strlen(p + pos) + strlen(dat->string) + 2; sz = strlen(p + pos) + strlen(dat->string) + 2;

View File

@ -1,4 +1,4 @@
/* $Id: tbl_html.c,v 1.20 2017/02/05 18:15:39 schwarze Exp $ */ /* $Id: tbl_html.c,v 1.21 2017/06/08 18:11:22 schwarze Exp $ */
/* /*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -31,22 +31,48 @@
static void html_tblopen(struct html *, const struct tbl_span *); static void html_tblopen(struct html *, const struct tbl_span *);
static size_t html_tbl_len(size_t, void *); static size_t html_tbl_len(size_t, void *);
static size_t html_tbl_strlen(const char *, void *); static size_t html_tbl_strlen(const char *, void *);
static size_t html_tbl_sulen(const struct roffsu *, void *);
static size_t static size_t
html_tbl_len(size_t sz, void *arg) html_tbl_len(size_t sz, void *arg)
{ {
return sz; return sz;
} }
static size_t static size_t
html_tbl_strlen(const char *p, void *arg) html_tbl_strlen(const char *p, void *arg)
{ {
return strlen(p); return strlen(p);
} }
static size_t
html_tbl_sulen(const struct roffsu *su, void *arg)
{
switch (su->unit) {
case SCALE_FS: /* 2^16 basic units */
return su->scale * 65536.0 / 24.0;
case SCALE_IN: /* 10 characters per inch */
return su->scale * 10.0;
case SCALE_CM: /* 2.54 cm per inch */
return su->scale * 10.0 / 2.54;
case SCALE_PC: /* 6 pica per inch */
case SCALE_VS:
return su->scale * 10.0 / 6.0;
case SCALE_EN:
case SCALE_EM:
return su->scale;
case SCALE_PT: /* 12 points per pica */
return su->scale * 10.0 / 6.0 / 12.0;
case SCALE_BU: /* 24 basic units per character */
return su->scale / 24.0;
case SCALE_MM: /* 1/1000 inch */
return su->scale / 100.0;
default:
abort();
}
}
static void static void
html_tblopen(struct html *h, const struct tbl_span *sp) html_tblopen(struct html *h, const struct tbl_span *sp)
{ {
@ -56,6 +82,7 @@ html_tblopen(struct html *h, const struct tbl_span *sp)
if (h->tbl.cols == NULL) { if (h->tbl.cols == NULL) {
h->tbl.len = html_tbl_len; h->tbl.len = html_tbl_len;
h->tbl.slen = html_tbl_strlen; h->tbl.slen = html_tbl_strlen;
h->tbl.sulen = html_tbl_sulen;
tblcalc(&h->tbl, sp, 0); tblcalc(&h->tbl, sp, 0);
} }

View File

@ -1,7 +1,7 @@
/* $Id: tbl_layout.c,v 1.41 2015/10/12 00:08:16 schwarze Exp $ */ /* $Id: tbl_layout.c,v 1.42 2017/06/08 18:11:22 schwarze Exp $ */
/* /*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2012, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2012, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -62,6 +62,7 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
int ln, const char *p, int *pos) int ln, const char *p, int *pos)
{ {
char *endptr; char *endptr;
size_t sz;
mod: mod:
while (p[*pos] == ' ' || p[*pos] == '\t') while (p[*pos] == ' ' || p[*pos] == '\t')
@ -127,7 +128,22 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
case 'u': case 'u':
cp->flags |= TBL_CELL_UP; cp->flags |= TBL_CELL_UP;
goto mod; goto mod;
case 'w': /* XXX for now, ignore minimal column width */ case 'w':
sz = 0;
if (p[*pos] == '(') {
(*pos)++;
while (p[*pos + sz] != '\0' && p[*pos + sz] != ')')
sz++;
} else
while (isdigit((unsigned char)p[*pos + sz]))
sz++;
if (sz) {
free(cp->wstr);
cp->wstr = mandoc_strndup(p + *pos, sz);
*pos += sz;
if (p[*pos] == ')')
(*pos)++;
}
goto mod; goto mod;
case 'x': case 'x':
cp->flags |= TBL_CELL_WMAX; cp->flags |= TBL_CELL_WMAX;

View File

@ -1,7 +1,7 @@
/* $Id: tbl_term.c,v 1.43 2015/10/12 00:08:16 schwarze Exp $ */ /* $Id: tbl_term.c,v 1.46 2017/06/08 18:11:22 schwarze Exp $ */
/* /*
* Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011, 2012, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2011,2012,2014,2015,2017 Ingo Schwarze <schwarze@openbsd.org>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -30,6 +30,7 @@
static size_t term_tbl_len(size_t, void *); static size_t term_tbl_len(size_t, void *);
static size_t term_tbl_strlen(const char *, 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_char(struct termp *, char, size_t);
static void tbl_data(struct termp *, const struct tbl_opts *, static void tbl_data(struct termp *, const struct tbl_opts *,
const struct tbl_dat *, const struct tbl_dat *,
@ -43,17 +44,21 @@ static void tbl_hrule(struct termp *, const struct tbl_span *, int);
static void tbl_word(struct termp *, const struct tbl_dat *); static void tbl_word(struct termp *, const struct tbl_dat *);
static size_t
term_tbl_sulen(const struct roffsu *su, void *arg)
{
return term_hspan((const struct termp *)arg, su) / 24;
}
static size_t static size_t
term_tbl_strlen(const char *p, void *arg) term_tbl_strlen(const char *p, void *arg)
{ {
return term_strlen((const struct termp *)arg, p); return term_strlen((const struct termp *)arg, p);
} }
static size_t static size_t
term_tbl_len(size_t sz, void *arg) term_tbl_len(size_t sz, void *arg)
{ {
return term_len((const struct termp *)arg, sz); return term_len((const struct termp *)arg, sz);
} }
@ -63,18 +68,12 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
const struct tbl_cell *cp; const struct tbl_cell *cp;
const struct tbl_dat *dp; const struct tbl_dat *dp;
static size_t offset; static size_t offset;
size_t rmargin, maxrmargin, tsz; size_t tsz;
int ic, horiz, spans, vert; int ic, horiz, spans, vert;
rmargin = tp->rmargin;
maxrmargin = tp->maxrmargin;
tp->rmargin = tp->maxrmargin = TERM_MAXMARGIN;
/* Inhibit printing of spaces: we do padding ourselves. */ /* Inhibit printing of spaces: we do padding ourselves. */
tp->flags |= TERMP_NONOSPACE; tp->flags |= TERMP_NOSPACE | TERMP_NONOSPACE | TERMP_BRNEVER;
tp->flags |= TERMP_NOSPACE;
/* /*
* The first time we're invoked for a given table block, * The first time we're invoked for a given table block,
@ -84,23 +83,24 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
if (tp->tbl.cols == NULL) { if (tp->tbl.cols == NULL) {
tp->tbl.len = term_tbl_len; tp->tbl.len = term_tbl_len;
tp->tbl.slen = term_tbl_strlen; tp->tbl.slen = term_tbl_strlen;
tp->tbl.sulen = term_tbl_sulen;
tp->tbl.arg = tp; tp->tbl.arg = tp;
tblcalc(&tp->tbl, sp, rmargin - tp->offset); tblcalc(&tp->tbl, sp, tp->tcol->rmargin - tp->tcol->offset);
/* Center the table as a whole. */ /* Center the table as a whole. */
offset = tp->offset; offset = tp->tcol->offset;
if (sp->opts->opts & TBL_OPT_CENTRE) { if (sp->opts->opts & TBL_OPT_CENTRE) {
tsz = sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) tsz = sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)
? 2 : !!sp->opts->lvert + !!sp->opts->rvert; ? 2 : !!sp->opts->lvert + !!sp->opts->rvert;
for (ic = 0; ic < sp->opts->cols; ic++) for (ic = 0; ic < sp->opts->cols; ic++)
tsz += tp->tbl.cols[ic].width + 3; tsz += tp->tbl.cols[ic].width + 3;
tsz -= 3; tsz -= 3;
if (offset + tsz > rmargin) if (offset + tsz > tp->tcol->rmargin)
tsz -= 1; tsz -= 1;
tp->offset = (offset + rmargin > tsz) ? tp->tcol->offset = offset + tp->tcol->rmargin > tsz ?
(offset + rmargin - tsz) / 2 : 0; (offset + tp->tcol->rmargin - tsz) / 2 : 0;
} }
/* Horizontal frame at the start of boxed tables. */ /* Horizontal frame at the start of boxed tables. */
@ -199,12 +199,9 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
assert(tp->tbl.cols); assert(tp->tbl.cols);
free(tp->tbl.cols); free(tp->tbl.cols);
tp->tbl.cols = NULL; tp->tbl.cols = NULL;
tp->offset = offset; tp->tcol->offset = offset;
} }
tp->flags &= ~(TERMP_NONOSPACE | TERMP_BRNEVER);
tp->flags &= ~TERMP_NONOSPACE;
tp->rmargin = rmargin;
tp->maxrmargin = maxrmargin;
} }
/* /*

422
term.c
View File

@ -1,4 +1,4 @@
/* $Id: term.c,v 1.259 2017/01/08 18:16:58 schwarze Exp $ */ /* $Id: term.c,v 1.268 2017/06/08 12:54:58 schwarze Exp $ */
/* /*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -32,17 +32,19 @@
#include "main.h" #include "main.h"
static size_t cond_width(const struct termp *, int, int *); static size_t cond_width(const struct termp *, int, int *);
static void adjbuf(struct termp *p, size_t); static void adjbuf(struct termp_col *, size_t);
static void bufferc(struct termp *, char); static void bufferc(struct termp *, char);
static void encode(struct termp *, const char *, size_t); static void encode(struct termp *, const char *, size_t);
static void encode1(struct termp *, int); static void encode1(struct termp *, int);
static void endline(struct termp *);
void void
term_free(struct termp *p) term_free(struct termp *p)
{ {
for (p->tcol = p->tcols; p->tcol < p->tcols + p->maxtcol; p->tcol++)
free(p->buf); free(p->tcol->buf);
free(p->tcols);
free(p->fontq); free(p->fontq);
free(p); free(p);
} }
@ -84,69 +86,53 @@ term_end(struct termp *p)
* to be broken, start the next line at the right margin instead * to be broken, start the next line at the right margin instead
* of at the offset. Used together with TERMP_NOBREAK for the tags * of at the offset. Used together with TERMP_NOBREAK for the tags
* in various kinds of tagged lists. * in various kinds of tagged lists.
* - TERMP_DANGLE: Do not break the output line at the right margin, * - 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. * append the next chunk after it even if this one is too long.
* To be used together with TERMP_NOBREAK. * To be used together with TERMP_NOBREAK.
* - TERMP_HANG: Like TERMP_DANGLE, and also suppress padding before * - TERMP_NOPAD: Start writing at the current position,
* the next chunk if this column is not full. * do not pad with blank characters up to the offset.
*/ */
void void
term_flushln(struct termp *p) term_flushln(struct termp *p)
{ {
size_t i; /* current input position in p->buf */
int ntab; /* number of tabs to prepend */
size_t vis; /* current visual position on output */ size_t vis; /* current visual position on output */
size_t vbl; /* number of blanks to prepend to output */ size_t vbl; /* number of blanks to prepend to output */
size_t vend; /* end of word visual position on output */ size_t vend; /* end of word visual position on output */
size_t bp; /* visual right border position */ size_t bp; /* visual right border position */
size_t dv; /* temporary for visual pos calculations */ size_t dv; /* temporary for visual pos calculations */
size_t j; /* temporary loop index for p->buf */ size_t j; /* temporary loop index for p->tcol->buf */
size_t jhy; /* last hyph before overflow w/r/t j */ size_t jhy; /* last hyph before overflow w/r/t j */
size_t maxvis; /* output position of visible boundary */ size_t maxvis; /* output position of visible boundary */
int ntab; /* number of tabs to prepend */
/* vbl = (p->flags & TERMP_NOPAD) || p->tcol->offset < p->viscol ?
* First, establish the maximum columns of "visible" content. 0 : p->tcol->offset - p->viscol;
* This is usually the difference between the right-margin and if (p->minbl && vbl < p->minbl)
* an indentation, but can be, for tagged lists or columns, a vbl = p->minbl;
* small set of values. maxvis = p->tcol->rmargin > p->viscol + vbl ?
* p->tcol->rmargin - p->viscol - vbl : 0;
* The following unsigned-signed subtractions look strange, bp = !(p->flags & TERMP_NOBREAK) ? maxvis :
* but they are actually correct. If the int p->overstep p->maxrmargin > p->viscol + vbl ?
* is negative, it gets sign extended. Subtracting that p->maxrmargin - p->viscol - vbl : 0;
* very large size_t effectively adds a small number to dv.
*/
dv = p->rmargin > p->offset ? p->rmargin - p->offset : 0;
maxvis = (int)dv > p->overstep ? dv - (size_t)p->overstep : 0;
if (p->flags & TERMP_NOBREAK) {
dv = p->maxrmargin > p->offset ?
p->maxrmargin - p->offset : 0;
bp = (int)dv > p->overstep ?
dv - (size_t)p->overstep : 0;
} else
bp = maxvis;
/*
* Calculate the required amount of padding.
*/
vbl = p->offset + p->overstep > p->viscol ?
p->offset + p->overstep - p->viscol : 0;
vis = vend = 0; vis = vend = 0;
i = 0;
while (i < p->col) { if (p->lasttcol == 0)
p->tcol->col = 0;
while (p->tcol->col < p->lastcol) {
/* /*
* Handle literal tab characters: collapse all * Handle literal tab characters: collapse all
* subsequent tabs into a single huge set of spaces. * subsequent tabs into a single huge set of spaces.
*/ */
ntab = 0; ntab = 0;
while (i < p->col && '\t' == p->buf[i]) { while (p->tcol->col < p->lastcol &&
vend = (vis / p->tabwidth + 1) * p->tabwidth; p->tcol->buf[p->tcol->col] == '\t') {
vend = term_tab_next(vis);
vbl += vend - vis; vbl += vend - vis;
vis = vend; vis = vend;
ntab++; ntab++;
i++; p->tcol->col++;
} }
/* /*
@ -156,84 +142,90 @@ term_flushln(struct termp *p)
* space is printed according to regular spacing rules). * space is printed according to regular spacing rules).
*/ */
for (j = i, jhy = 0; j < p->col; j++) { jhy = 0;
if (' ' == p->buf[j] || '\t' == p->buf[j]) for (j = p->tcol->col; j < p->lastcol; j++) {
if (p->tcol->buf[j] == ' ' || p->tcol->buf[j] == '\t')
break; break;
/* Back over the last printed character. */ /* Back over the last printed character. */
if (8 == p->buf[j]) { if (p->tcol->buf[j] == '\b') {
assert(j); assert(j);
vend -= (*p->width)(p, p->buf[j - 1]); vend -= (*p->width)(p, p->tcol->buf[j - 1]);
continue; continue;
} }
/* Regular word. */ /* Regular word. */
/* Break at the hyphen point if we overrun. */ /* Break at the hyphen point if we overrun. */
if (vend > vis && vend < bp && if (vend > vis && vend < bp &&
(ASCII_HYPH == p->buf[j] || (p->tcol->buf[j] == ASCII_HYPH||
ASCII_BREAK == p->buf[j])) p->tcol->buf[j] == ASCII_BREAK))
jhy = j; jhy = j;
/* /*
* Hyphenation now decided, put back a real * Hyphenation now decided, put back a real
* hyphen such that we get the correct width. * hyphen such that we get the correct width.
*/ */
if (ASCII_HYPH == p->buf[j]) if (p->tcol->buf[j] == ASCII_HYPH)
p->buf[j] = '-'; p->tcol->buf[j] = '-';
vend += (*p->width)(p, p->buf[j]); vend += (*p->width)(p, p->tcol->buf[j]);
} }
/* /*
* Find out whether we would exceed the right margin. * Find out whether we would exceed the right margin.
* If so, break to the next line. * If so, break to the next line.
*/ */
if (vend > bp && 0 == jhy && vis > 0) {
if (vend > bp && jhy == 0 && vis > 0 &&
(p->flags & TERMP_BRNEVER) == 0) {
if (p->lasttcol)
return;
endline(p);
vend -= vis; vend -= vis;
(*p->endline)(p);
p->viscol = 0;
if (TERMP_BRIND & p->flags) {
vbl = p->rmargin;
vend += p->rmargin;
vend -= p->offset;
} else
vbl = p->offset;
/* use pending tabs on the new line */ /* Use pending tabs on the new line. */
if (0 < ntab) vbl = 0;
vbl += ntab * p->tabwidth; while (ntab--)
vbl = term_tab_next(vbl);
/* /* Re-establish indentation. */
* Remove the p->overstep width.
* Again, if p->overstep is negative,
* sign extension does the right thing.
*/
bp += (size_t)p->overstep; if (p->flags & TERMP_BRIND)
p->overstep = 0; 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 [remaining] word. */ /*
for ( ; i < p->col; i++) { * Write out the rest of the word.
if (vend > bp && jhy > 0 && i > jhy) */
for ( ; p->tcol->col < p->lastcol; p->tcol->col++) {
if (vend > bp && jhy > 0 && p->tcol->col > jhy)
break; break;
if ('\t' == p->buf[i]) if (p->tcol->buf[p->tcol->col] == '\t')
break; break;
if (' ' == p->buf[i]) { if (p->tcol->buf[p->tcol->col] == ' ') {
j = i; j = p->tcol->col;
while (i < p->col && ' ' == p->buf[i]) while (p->tcol->col < p->lastcol &&
i++; p->tcol->buf[p->tcol->col] == ' ')
dv = (i - j) * (*p->width)(p, ' '); p->tcol->col++;
dv = (p->tcol->col - j) * (*p->width)(p, ' ');
vbl += dv; vbl += dv;
vend += dv; vend += dv;
break; break;
} }
if (ASCII_NBRSP == p->buf[i]) { if (p->tcol->buf[p->tcol->col] == ASCII_NBRSP) {
vbl += (*p->width)(p, ' '); vbl += (*p->width)(p, ' ');
continue; continue;
} }
if (ASCII_BREAK == p->buf[i]) if (p->tcol->buf[p->tcol->col] == ASCII_BREAK)
continue; continue;
/* /*
@ -247,11 +239,13 @@ term_flushln(struct termp *p)
vbl = 0; vbl = 0;
} }
(*p->letter)(p, p->buf[i]); (*p->letter)(p, p->tcol->buf[p->tcol->col]);
if (8 == p->buf[i]) if (p->tcol->buf[p->tcol->col] == '\b')
p->viscol -= (*p->width)(p, p->buf[i-1]); p->viscol -= (*p->width)(p,
p->tcol->buf[p->tcol->col - 1]);
else else
p->viscol += (*p->width)(p, p->buf[i]); p->viscol += (*p->width)(p,
p->tcol->buf[p->tcol->col]);
} }
vis = vend; vis = vend;
} }
@ -260,48 +254,45 @@ term_flushln(struct termp *p)
* If there was trailing white space, it was not printed; * If there was trailing white space, it was not printed;
* so reset the cursor position accordingly. * so reset the cursor position accordingly.
*/ */
if (vis > vbl) if (vis > vbl)
vis -= vbl; vis -= vbl;
else else
vis = 0; vis = 0;
p->col = 0; p->col = p->lastcol = 0;
p->overstep = 0; p->minbl = p->trailspace;
p->flags &= ~(TERMP_BACKAFTER | TERMP_BACKBEFORE); p->flags &= ~(TERMP_BACKAFTER | TERMP_BACKBEFORE | TERMP_NOPAD);
if ( ! (TERMP_NOBREAK & p->flags)) {
p->viscol = 0;
(*p->endline)(p);
return;
}
if (TERMP_HANG & p->flags) {
p->overstep += (int)(p->offset + vis - p->rmargin +
p->trailspace * (*p->width)(p, ' '));
/*
* If we have overstepped the margin, temporarily move
* it to the right and flag the rest of the line to be
* shorter.
* If there is a request to keep the columns together,
* allow negative overstep when the column is not full.
*/
if (p->trailspace && p->overstep < 0)
p->overstep = 0;
return;
} else if (TERMP_DANGLE & p->flags)
return;
/* Trailing whitespace is significant in some columns. */ /* Trailing whitespace is significant in some columns. */
if (vis && vbl && (TERMP_BRTRSP & p->flags)) if (vis && vbl && (TERMP_BRTRSP & p->flags))
vis += vbl; vis += vbl;
/* If the column was overrun, break the line. */ /* If the column was overrun, break the line. */
if (maxvis < vis + p->trailspace * (*p->width)(p, ' ')) { if ((p->flags & TERMP_NOBREAK) == 0 ||
(*p->endline)(p); ((p->flags & TERMP_HANG) == 0 &&
p->viscol = 0; vis + p->trailspace * (*p->width)(p, ' ') > maxvis))
endline(p);
}
static void
endline(struct termp *p)
{
if ((p->flags & (TERMP_NEWMC | TERMP_ENDMC)) == TERMP_ENDMC) {
p->mc = NULL;
p->flags &= ~TERMP_ENDMC;
} }
if (p->mc != NULL) {
if (p->viscol && p->maxrmargin >= p->viscol)
(*p->advance)(p, p->maxrmargin - p->viscol + 1);
p->flags |= TERMP_NOBUF | TERMP_NOSPACE;
term_word(p, p->mc);
p->flags &= ~(TERMP_NOBUF | TERMP_NEWMC);
}
p->viscol = 0;
p->minbl = 0;
(*p->endline)(p);
} }
/* /*
@ -314,7 +305,7 @@ term_newln(struct termp *p)
{ {
p->flags |= TERMP_NOSPACE; p->flags |= TERMP_NOSPACE;
if (p->col || p->viscol) if (p->lastcol || p->viscol)
term_flushln(p); term_flushln(p);
} }
@ -330,6 +321,7 @@ term_vspace(struct termp *p)
term_newln(p); term_newln(p);
p->viscol = 0; p->viscol = 0;
p->minbl = 0;
if (0 < p->skipvsp) if (0 < p->skipvsp)
p->skipvsp--; p->skipvsp--;
else else
@ -397,30 +389,31 @@ term_fontpop(struct termp *p)
void void
term_word(struct termp *p, const char *word) term_word(struct termp *p, const char *word)
{ {
struct roffsu su;
const char nbrsp[2] = { ASCII_NBRSP, 0 }; const char nbrsp[2] = { ASCII_NBRSP, 0 };
const char *seq, *cp; const char *seq, *cp;
int sz, uc; int sz, uc;
size_t ssz; size_t csz, lsz, ssz;
enum mandoc_esc esc; enum mandoc_esc esc;
if ( ! (TERMP_NOSPACE & p->flags)) { if ((p->flags & TERMP_NOBUF) == 0) {
if ( ! (TERMP_KEEP & p->flags)) { if ((p->flags & TERMP_NOSPACE) == 0) {
bufferc(p, ' '); if ((p->flags & TERMP_KEEP) == 0) {
if (TERMP_SENTENCE & p->flags)
bufferc(p, ' '); bufferc(p, ' ');
} else if (p->flags & TERMP_SENTENCE)
bufferc(p, ASCII_NBRSP); bufferc(p, ' ');
} else
bufferc(p, ASCII_NBRSP);
}
if (p->flags & TERMP_PREKEEP)
p->flags |= TERMP_KEEP;
if (p->flags & TERMP_NONOSPACE)
p->flags |= TERMP_NOSPACE;
else
p->flags &= ~TERMP_NOSPACE;
p->flags &= ~(TERMP_SENTENCE | TERMP_NONEWLINE);
p->skipvsp = 0;
} }
if (TERMP_PREKEEP & p->flags)
p->flags |= TERMP_KEEP;
if ( ! (p->flags & TERMP_NONOSPACE))
p->flags &= ~TERMP_NOSPACE;
else
p->flags |= TERMP_NOSPACE;
p->flags &= ~(TERMP_SENTENCE | TERMP_NONEWLINE);
p->skipvsp = 0;
while ('\0' != *word) { while ('\0' != *word) {
if ('\\' != *word) { if ('\\' != *word) {
@ -485,6 +478,74 @@ term_word(struct termp *p, const char *word)
else if (*word == '\0') else if (*word == '\0')
p->flags |= (TERMP_NOSPACE | TERMP_NONEWLINE); p->flags |= (TERMP_NOSPACE | TERMP_NONEWLINE);
continue; continue;
case ESCAPE_HORIZ:
if (a2roffsu(seq, &su, SCALE_EM) == NULL)
continue;
uc = term_hspan(p, &su) / 24;
if (uc > 0)
while (uc-- > 0)
bufferc(p, ASCII_NBRSP);
else if (p->col > (size_t)(-uc))
p->col += uc;
else {
uc += p->col;
p->col = 0;
if (p->tcol->offset > (size_t)(-uc)) {
p->ti += uc;
p->tcol->offset += uc;
} else {
p->ti -= p->tcol->offset;
p->tcol->offset = 0;
}
}
continue;
case ESCAPE_HLINE:
if ((seq = a2roffsu(seq, &su, SCALE_EM)) == NULL)
continue;
uc = term_hspan(p, &su) / 24;
if (uc <= 0) {
if (p->tcol->rmargin <= p->tcol->offset)
continue;
lsz = p->tcol->rmargin - p->tcol->offset;
} else
lsz = uc;
if (*seq == '\0')
uc = -1;
else if (*seq == '\\') {
seq++;
esc = mandoc_escape(&seq, &cp, &sz);
switch (esc) {
case ESCAPE_UNICODE:
uc = mchars_num2uc(cp + 1, sz - 1);
break;
case ESCAPE_NUMBERED:
uc = mchars_num2char(cp, sz);
break;
case ESCAPE_SPECIAL:
uc = mchars_spec2cp(cp, sz);
break;
default:
uc = -1;
break;
}
} else
uc = *seq;
if (uc < 0x20 || (uc > 0x7E && uc < 0xA0))
uc = '_';
if (p->enc == TERMENC_ASCII) {
cp = ascii_uc2str(uc);
csz = term_strlen(p, cp);
ssz = strlen(cp);
} else
csz = (*p->width)(p, uc);
while (lsz >= csz) {
if (p->enc == TERMENC_ASCII)
encode(p, cp, ssz);
else
encode1(p, uc);
lsz -= csz;
}
continue;
case ESCAPE_SKIPCHAR: case ESCAPE_SKIPCHAR:
p->flags |= TERMP_BACKAFTER; p->flags |= TERMP_BACKAFTER;
continue; continue;
@ -504,10 +565,12 @@ term_word(struct termp *p, const char *word)
} }
} }
/* Trim trailing backspace/blank pair. */ /* Trim trailing backspace/blank pair. */
if (p->col > 2 && if (p->lastcol > 2 &&
(p->buf[p->col - 1] == ' ' || (p->tcol->buf[p->lastcol - 1] == ' ' ||
p->buf[p->col - 1] == '\t')) p->tcol->buf[p->lastcol - 1] == '\t'))
p->col -= 2; p->lastcol -= 2;
if (p->col > p->lastcol)
p->col = p->lastcol;
continue; continue;
default: default:
continue; continue;
@ -532,25 +595,28 @@ term_word(struct termp *p, const char *word)
} }
static void static void
adjbuf(struct termp *p, size_t sz) adjbuf(struct termp_col *c, size_t sz)
{ {
if (c->maxcols == 0)
if (0 == p->maxcols) c->maxcols = 1024;
p->maxcols = 1024; while (c->maxcols <= sz)
while (sz >= p->maxcols) c->maxcols <<= 2;
p->maxcols <<= 2; c->buf = mandoc_reallocarray(c->buf, c->maxcols, sizeof(*c->buf));
p->buf = mandoc_reallocarray(p->buf, p->maxcols, sizeof(int));
} }
static void static void
bufferc(struct termp *p, char c) bufferc(struct termp *p, char c)
{ {
if (p->flags & TERMP_NOBUF) {
if (p->col + 1 >= p->maxcols) (*p->letter)(p, c);
adjbuf(p, p->col + 1); return;
}
p->buf[p->col++] = c; if (p->col + 1 >= p->tcol->maxcols)
adjbuf(p->tcol, p->col + 1);
if (p->lastcol <= p->col || (c != ' ' && c != ASCII_NBRSP))
p->tcol->buf[p->col] = c;
if (p->lastcol < ++p->col)
p->lastcol = p->col;
} }
/* /*
@ -563,31 +629,40 @@ encode1(struct termp *p, int c)
{ {
enum termfont f; enum termfont f;
if (p->col + 7 >= p->maxcols) if (p->flags & TERMP_NOBUF) {
adjbuf(p, p->col + 7); (*p->letter)(p, c);
return;
}
if (p->col + 7 >= p->tcol->maxcols)
adjbuf(p->tcol, p->col + 7);
f = (c == ASCII_HYPH || c > 127 || isgraph(c)) ? f = (c == ASCII_HYPH || c > 127 || isgraph(c)) ?
p->fontq[p->fonti] : TERMFONT_NONE; p->fontq[p->fonti] : TERMFONT_NONE;
if (p->flags & TERMP_BACKBEFORE) { if (p->flags & TERMP_BACKBEFORE) {
if (p->buf[p->col - 1] == ' ' || p->buf[p->col - 1] == '\t') if (p->tcol->buf[p->col - 1] == ' ' ||
p->tcol->buf[p->col - 1] == '\t')
p->col--; p->col--;
else else
p->buf[p->col++] = 8; p->tcol->buf[p->col++] = '\b';
p->flags &= ~TERMP_BACKBEFORE; p->flags &= ~TERMP_BACKBEFORE;
} }
if (TERMFONT_UNDER == f || TERMFONT_BI == f) { if (f == TERMFONT_UNDER || f == TERMFONT_BI) {
p->buf[p->col++] = '_'; p->tcol->buf[p->col++] = '_';
p->buf[p->col++] = 8; p->tcol->buf[p->col++] = '\b';
} }
if (TERMFONT_BOLD == f || TERMFONT_BI == f) { if (f == TERMFONT_BOLD || f == TERMFONT_BI) {
if (ASCII_HYPH == c) if (c == ASCII_HYPH)
p->buf[p->col++] = '-'; p->tcol->buf[p->col++] = '-';
else else
p->buf[p->col++] = c; p->tcol->buf[p->col++] = c;
p->buf[p->col++] = 8; p->tcol->buf[p->col++] = '\b';
} }
p->buf[p->col++] = c; if (p->lastcol <= p->col || (c != ' ' && c != ASCII_NBRSP))
p->tcol->buf[p->col] = c;
if (p->lastcol < ++p->col)
p->lastcol = p->col;
if (p->flags & TERMP_BACKAFTER) { if (p->flags & TERMP_BACKAFTER) {
p->flags |= TERMP_BACKBEFORE; p->flags |= TERMP_BACKBEFORE;
p->flags &= ~TERMP_BACKAFTER; p->flags &= ~TERMP_BACKAFTER;
@ -599,15 +674,24 @@ encode(struct termp *p, const char *word, size_t sz)
{ {
size_t i; size_t i;
if (p->col + 2 + (sz * 5) >= p->maxcols) if (p->flags & TERMP_NOBUF) {
adjbuf(p, p->col + 2 + (sz * 5)); for (i = 0; i < sz; i++)
(*p->letter)(p, word[i]);
return;
}
if (p->col + 2 + (sz * 5) >= p->tcol->maxcols)
adjbuf(p->tcol, p->col + 2 + (sz * 5));
for (i = 0; i < sz; i++) { for (i = 0; i < sz; i++) {
if (ASCII_HYPH == word[i] || if (ASCII_HYPH == word[i] ||
isgraph((unsigned char)word[i])) isgraph((unsigned char)word[i]))
encode1(p, word[i]); encode1(p, word[i]);
else { else {
p->buf[p->col++] = word[i]; if (p->lastcol <= p->col ||
(word[i] != ' ' && word[i] != ASCII_NBRSP))
p->tcol->buf[p->col] = word[i];
p->col++;
/* /*
* Postpone the effect of \z while handling * Postpone the effect of \z while handling
@ -621,6 +705,8 @@ encode(struct termp *p, const char *word, size_t sz)
} }
} }
} }
if (p->lastcol < p->col)
p->lastcol = p->col;
} }
void void
@ -644,7 +730,7 @@ term_setwidth(struct termp *p, const char *wstr)
default: default:
break; break;
} }
if (a2roffsu(wstr, &su, SCALE_MAX)) if (a2roffsu(wstr, &su, SCALE_MAX) != NULL)
width = term_hspan(p, &su); width = term_hspan(p, &su);
else else
iop = 0; iop = 0;

59
term.h
View File

@ -1,7 +1,7 @@
/* $Id: term.h,v 1.118 2015/11/07 14:01:16 schwarze Exp $ */ /* $Id: term.h,v 1.126 2017/06/07 20:01:19 schwarze Exp $ */
/* /*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011-2015 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2011-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -36,9 +36,10 @@ enum termfont {
TERMFONT__MAX TERMFONT__MAX
}; };
#define TERM_MAXMARGIN 100000 /* FIXME */ struct eqn;
struct roff_meta; struct roff_meta;
struct roff_node;
struct tbl_span;
struct termp; struct termp;
typedef void (*term_margin)(struct termp *, const struct roff_meta *); typedef void (*term_margin)(struct termp *, const struct roff_meta *);
@ -48,24 +49,33 @@ struct termp_tbl {
int decimal; /* decimal point position */ int decimal; /* decimal point position */
}; };
struct termp_col {
int *buf; /* Output buffer. */
size_t maxcols; /* Allocated bytes in buf. */
size_t col; /* Byte in buf to be written. */
size_t rmargin; /* Current right margin. */
size_t offset; /* Current left margin. */
};
struct termp { struct termp {
enum termtype type; struct rofftbl tbl; /* Table configuration. */
struct rofftbl tbl; /* table configuration */ struct termp_col *tcols; /* Array of table columns. */
int synopsisonly; /* print the synopsis only */ struct termp_col *tcol; /* Current table column. */
int mdocstyle; /* imitate mdoc(7) output */ size_t maxtcol; /* Allocated table columns. */
size_t lasttcol; /* Last column currently used. */
size_t line; /* Current output line number. */ size_t line; /* Current output line number. */
size_t defindent; /* Default indent for text. */ size_t defindent; /* Default indent for text. */
size_t defrmargin; /* Right margin of the device. */ size_t defrmargin; /* Right margin of the device. */
size_t lastrmargin; /* Right margin before the last ll. */ size_t lastrmargin; /* Right margin before the last ll. */
size_t rmargin; /* Current right margin. */
size_t maxrmargin; /* Max right margin. */ size_t maxrmargin; /* Max right margin. */
size_t maxcols; /* Max size of buf. */ size_t col; /* Byte position in buf. */
size_t offset; /* Margin offest. */ size_t lastcol; /* Bytes in buf. */
size_t tabwidth; /* Distance of tab positions. */
size_t col; /* Bytes in buf. */
size_t viscol; /* Chars on current line. */ size_t viscol; /* Chars on current line. */
size_t trailspace; /* See termp_flushln(). */ size_t trailspace; /* See term_flushln(). */
int overstep; /* See termp_flushln(). */ size_t minbl; /* Minimum blanks before next field. */
int synopsisonly; /* Print the synopsis only. */
int mdocstyle; /* Imitate mdoc(7) output. */
int ti; /* Temporary indent for one line. */
int skipvsp; /* Vertical space to skip. */ int skipvsp; /* Vertical space to skip. */
int flags; int flags;
#define TERMP_SENTENCE (1 << 0) /* Space before a sentence. */ #define TERMP_SENTENCE (1 << 0) /* Space before a sentence. */
@ -79,12 +89,16 @@ struct termp {
#define TERMP_NOBREAK (1 << 8) /* See term_flushln(). */ #define TERMP_NOBREAK (1 << 8) /* See term_flushln(). */
#define TERMP_BRTRSP (1 << 9) /* See term_flushln(). */ #define TERMP_BRTRSP (1 << 9) /* See term_flushln(). */
#define TERMP_BRIND (1 << 10) /* See term_flushln(). */ #define TERMP_BRIND (1 << 10) /* See term_flushln(). */
#define TERMP_DANGLE (1 << 11) /* See term_flushln(). */ #define TERMP_HANG (1 << 11) /* See term_flushln(). */
#define TERMP_HANG (1 << 12) /* See term_flushln(). */ #define TERMP_NOPAD (1 << 12) /* See term_flushln(). */
#define TERMP_NOSPLIT (1 << 13) /* Do not break line before .An. */ #define TERMP_NOSPLIT (1 << 13) /* Do not break line before .An. */
#define TERMP_SPLIT (1 << 14) /* Break line before .An. */ #define TERMP_SPLIT (1 << 14) /* Break line before .An. */
#define TERMP_NONEWLINE (1 << 15) /* No line break in nofill mode. */ #define TERMP_NONEWLINE (1 << 15) /* No line break in nofill mode. */
int *buf; /* Output buffer. */ #define TERMP_BRNEVER (1 << 16) /* Don't even break at maxrmargin. */
#define TERMP_NOBUF (1 << 17) /* Bypass output buffer. */
#define TERMP_NEWMC (1 << 18) /* No .mc printed yet. */
#define TERMP_ENDMC (1 << 19) /* Next break ends .mc mode. */
enum termtype type; /* Terminal, PS, or PDF. */
enum termenc enc; /* Type of encoding. */ enum termenc enc; /* Type of encoding. */
enum termfont fontl; /* Last font set. */ enum termfont fontl; /* Last font set. */
enum termfont *fontq; /* Symmetric fonts. */ enum termfont *fontq; /* Symmetric fonts. */
@ -102,15 +116,15 @@ struct termp {
int (*hspan)(const struct termp *, int (*hspan)(const struct termp *,
const struct roffsu *); const struct roffsu *);
const void *argf; /* arg for headf/footf */ const void *argf; /* arg for headf/footf */
const char *mc; /* Margin character. */
struct termp_ps *ps; struct termp_ps *ps;
}; };
struct tbl_span;
struct eqn;
const char *ascii_uc2str(int); const char *ascii_uc2str(int);
void roff_term_pre(struct termp *, const struct roff_node *);
void term_eqn(struct termp *, const struct eqn *); void term_eqn(struct termp *, const struct eqn *);
void term_tbl(struct termp *, const struct tbl_span *); void term_tbl(struct termp *, const struct tbl_span *);
void term_free(struct termp *); void term_free(struct termp *);
@ -128,6 +142,9 @@ int term_vspan(const struct termp *, const struct roffsu *);
size_t term_strlen(const struct termp *, const char *); size_t term_strlen(const struct termp *, const char *);
size_t term_len(const struct termp *, size_t); size_t term_len(const struct termp *, size_t);
void term_tab_set(const struct termp *, const char *);
size_t term_tab_next(size_t);
void term_fontpush(struct termp *, enum termfont); void term_fontpush(struct termp *, enum termfont);
void term_fontpop(struct termp *); void term_fontpop(struct termp *);
void term_fontpopq(struct termp *, int); void term_fontpopq(struct termp *, int);

View File

@ -1,7 +1,7 @@
/* $Id: term_ascii.c,v 1.54 2016/07/31 09:29:13 schwarze Exp $ */ /* $Id: term_ascii.c,v 1.57 2017/06/07 17:38:26 schwarze Exp $ */
/* /*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -65,13 +65,14 @@ ascii_init(enum termenc enc, const struct manoutput *outopts)
#endif #endif
struct termp *p; struct termp *p;
p = mandoc_calloc(1, sizeof(struct termp)); p = mandoc_calloc(1, sizeof(*p));
p->tcol = p->tcols = mandoc_calloc(1, sizeof(*p->tcol));
p->maxtcol = 1;
p->line = 1; p->line = 1;
p->tabwidth = 5;
p->defrmargin = p->lastrmargin = 78; p->defrmargin = p->lastrmargin = 78;
p->fontq = mandoc_reallocarray(NULL, p->fontq = mandoc_reallocarray(NULL,
(p->fontsz = 8), sizeof(enum termfont)); (p->fontsz = 8), sizeof(*p->fontq));
p->fontq[0] = p->fontl = TERMFONT_NONE; p->fontq[0] = p->fontl = TERMFONT_NONE;
p->begin = ascii_begin; p->begin = ascii_begin;
@ -149,7 +150,7 @@ ascii_setwidth(struct termp *p, int iop, int width)
{ {
width /= 24; width /= 24;
p->rmargin = p->defrmargin; p->tcol->rmargin = p->defrmargin;
if (iop > 0) if (iop > 0)
p->defrmargin += width; p->defrmargin += width;
else if (iop == 0) else if (iop == 0)
@ -158,8 +159,8 @@ ascii_setwidth(struct termp *p, int iop, int width)
p->defrmargin -= width; p->defrmargin -= width;
else else
p->defrmargin = 0; p->defrmargin = 0;
p->lastrmargin = p->rmargin; p->lastrmargin = p->tcol->rmargin;
p->rmargin = p->maxrmargin = p->defrmargin; p->tcol->rmargin = p->maxrmargin = p->defrmargin;
} }
void void
@ -216,6 +217,8 @@ ascii_endline(struct termp *p)
{ {
p->line++; p->line++;
p->tcol->offset -= p->ti;
p->ti = 0;
putchar('\n'); putchar('\n');
} }
@ -370,6 +373,8 @@ locale_endline(struct termp *p)
{ {
p->line++; p->line++;
p->tcol->offset -= p->ti;
p->ti = 0;
putwchar(L'\n'); putwchar(L'\n');
} }

View File

@ -1,7 +1,7 @@
/* $Id: term_ps.c,v 1.83 2017/02/17 14:31:52 schwarze Exp $ */ /* $Id: term_ps.c,v 1.85 2017/06/07 17:38:26 schwarze Exp $ */
/* /*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2014, 2015, 2016 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -538,12 +538,15 @@ pspdf_alloc(const struct manoutput *outopts)
size_t marginx, marginy, lineheight; size_t marginx, marginy, lineheight;
const char *pp; const char *pp;
p = mandoc_calloc(1, sizeof(struct termp)); p = mandoc_calloc(1, sizeof(*p));
p->tcol = p->tcols = mandoc_calloc(1, sizeof(*p->tcol));
p->maxtcol = 1;
p->enc = TERMENC_ASCII; p->enc = TERMENC_ASCII;
p->fontq = mandoc_reallocarray(NULL, p->fontq = mandoc_reallocarray(NULL,
(p->fontsz = 8), sizeof(enum termfont)); (p->fontsz = 8), sizeof(*p->fontq));
p->fontq[0] = p->fontl = TERMFONT_NONE; p->fontq[0] = p->fontl = TERMFONT_NONE;
p->ps = mandoc_calloc(1, sizeof(struct termp_ps)); p->ps = mandoc_calloc(1, sizeof(*p->ps));
p->advance = ps_advance; p->advance = ps_advance;
p->begin = ps_begin; p->begin = ps_begin;
@ -1219,6 +1222,9 @@ ps_endline(struct termp *p)
} }
ps_closepage(p); ps_closepage(p);
p->tcol->offset -= p->ti;
p->ti = 0;
} }
static void static void

117
term_tab.c Normal file
View File

@ -0,0 +1,117 @@
/* $OpenBSD: term.c,v 1.119 2017/01/08 18:08:44 schwarze Exp $ */
/*
* Copyright (c) 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 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 <sys/types.h>
#include <stddef.h>
#include "mandoc_aux.h"
#include "out.h"
#include "term.h"
struct tablist {
size_t *t; /* Allocated array of tab positions. */
size_t s; /* Allocated number of positions. */
size_t n; /* Currently used number of positions. */
};
static struct {
struct tablist a; /* All tab positions for lookup. */
struct tablist p; /* Periodic tab positions to add. */
size_t d; /* Default tab width in units of n. */
} tabs;
void
term_tab_set(const struct termp *p, const char *arg)
{
static int recording_period;
struct roffsu su;
struct tablist *tl;
size_t pos;
int add;
/* Special arguments: clear all tabs or switch lists. */
if (arg == NULL) {
tabs.a.n = tabs.p.n = 0;
recording_period = 0;
if (tabs.d == 0) {
a2roffsu(".8i", &su, SCALE_IN);
tabs.d = term_hspan(p, &su) / 24;
}
return;
}
if (arg[0] == 'T' && arg[1] == '\0') {
recording_period = 1;
return;
}
/* Parse the sign, the number, and the unit. */
if (*arg == '+') {
add = 1;
arg++;
} else
add = 0;
if (a2roffsu(arg, &su, SCALE_EM) == NULL)
return;
/* Select the list, and extend it if it is full. */
tl = recording_period ? &tabs.p : &tabs.a;
if (tl->n >= tl->s) {
tl->s += 8;
tl->t = mandoc_reallocarray(tl->t, tl->s, sizeof(*tl->t));
}
/* Append the new position. */
pos = term_hspan(p, &su);
tl->t[tl->n] = pos;
if (add && tl->n)
tl->t[tl->n] += tl->t[tl->n - 1];
tl->n++;
}
size_t
term_tab_next(size_t prev)
{
size_t i, j;
for (i = 0;; i++) {
if (i == tabs.a.n) {
if (tabs.p.n == 0)
return prev;
/*
return i ? prev :
(prev / tabs.d + 1) * tabs.d;
*/
tabs.a.n += tabs.p.n;
if (tabs.a.s < tabs.a.n) {
tabs.a.s = tabs.a.n;
tabs.a.t = mandoc_reallocarray(tabs.a.t,
tabs.a.s, sizeof(*tabs.a.t));
}
for (j = 0; j < tabs.p.n; j++)
tabs.a.t[i + j] = tabs.p.t[j] +
(i ? tabs.a.t[i - 1] : 0);
}
if (prev < tabs.a.t[i] / 24)
return tabs.a.t[i] / 24;
}
}

14
tree.c
View File

@ -1,4 +1,4 @@
/* $Id: tree.c,v 1.73 2017/02/10 15:45:28 schwarze Exp $ */ /* $Id: tree.c,v 1.74 2017/04/24 23:06:18 schwarze Exp $ */
/* /*
* Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -129,23 +129,23 @@ print_mdoc(const struct roff_node *n, int indent)
p = n->string; p = n->string;
break; break;
case ROFFT_BODY: case ROFFT_BODY:
p = mdoc_macronames[n->tok]; p = roff_name[n->tok];
break; break;
case ROFFT_HEAD: case ROFFT_HEAD:
p = mdoc_macronames[n->tok]; p = roff_name[n->tok];
break; break;
case ROFFT_TAIL: case ROFFT_TAIL:
p = mdoc_macronames[n->tok]; p = roff_name[n->tok];
break; break;
case ROFFT_ELEM: case ROFFT_ELEM:
p = mdoc_macronames[n->tok]; p = roff_name[n->tok];
if (n->args) { if (n->args) {
argv = n->args->argv; argv = n->args->argv;
argc = n->args->argc; argc = n->args->argc;
} }
break; break;
case ROFFT_BLOCK: case ROFFT_BLOCK:
p = mdoc_macronames[n->tok]; p = roff_name[n->tok];
if (n->args) { if (n->args) {
argv = n->args->argv; argv = n->args->argv;
argc = n->args->argc; argc = n->args->argc;
@ -257,7 +257,7 @@ print_man(const struct roff_node *n, int indent)
case ROFFT_BLOCK: case ROFFT_BLOCK:
case ROFFT_HEAD: case ROFFT_HEAD:
case ROFFT_BODY: case ROFFT_BODY:
p = man_macronames[n->tok]; p = roff_name[n->tok];
break; break;
case ROFFT_ROOT: case ROFFT_ROOT:
p = "root"; p = "root";