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

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.

29
TODO
View File

@ -1,6 +1,6 @@
************************************************************************
* 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:
@ -61,18 +61,6 @@ are mere guesses, and some may be wrong.
reported by brad@ Sat, 15 Jan 2011 15:45:23 -0500
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
found by jca@ in ratpoison(1) Sun, 30 Jun 2013 12:01:09 +0200
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)
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 -----------------------------------------------
- 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
- improve hashing mechanism for macros (quite important: performance)
- 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
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, 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
.\" purpose with or without fee is hereby granted, provided that the above
@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: January 31 2017 $
.Dd $Mdocdate: March 27 2017 $
.Dt APROPOS 1
.Os
.Sh NAME
@ -24,7 +24,7 @@
.Nd search manual page databases
.Sh SYNOPSIS
.Nm
.Op Fl acfhklw
.Op Fl afk
.Op Fl C Ar file
.Op Fl M Ar path
.Op Fl m Ar path
@ -89,12 +89,6 @@ Specify an alternative configuration
in
.Xr man.conf 5
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
Search for all words in
.Ar expression
@ -102,37 +96,12 @@ in manual page names only.
The search is case insensitive and matches whole words only.
In this mode, macro keys, comparison operators, and logical operators
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
Support the full
.Ar expression
syntax.
This overrides any earlier
.Fl f
and
.Fl l
options.
It is the default for
.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
Use the colon-separated path instead of the default list of paths
searched for
@ -162,14 +131,16 @@ By default, pages from all sections are shown.
See
.Xr man 1
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
.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
.Ar expression
consists of search terms joined by logical operators
@ -237,7 +208,28 @@ is evaluated case-insensitively.
Has no effect on substring terms.
.El
.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
.D1 name[, name...](sec) \- description
.Pp
@ -341,25 +333,25 @@ Text production:
.It Ev MANPAGER
Any non-empty value of the environment variable
.Ev MANPAGER
will be used instead of the standard pagination program,
.Xr more 1 .
.It Ev MANPATH
The standard search path used by
is used instead of the standard pagination program,
.Xr more 1 ;
see
.Xr man 1
may be changed by specifying a path in the
.Ev MANPATH
environment variable.
Invalid paths, or paths without manual databases, are ignored.
for details.
Only used if
.Fl a
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
.Fl M .
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.
.Fl M ,
ignored if
.Fl l
is specified.
.It Ev PAGER
Specifies the pagination program to use when
.Ev MANPAGER
@ -367,7 +359,12 @@ is not defined.
If neither PAGER nor MANPAGER is defined,
.Xr more 1
.Fl s
will be used.
is used.
Only used if
.Fl a
or
.Fl l
is specified.
.El
.Sh FILES
.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>
.\"
@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: February 6 2017 $
.Dd $Mdocdate: March 18 2017 $
.Dt CATMAN 8
.Os
.Sh NAME
@ -49,7 +49,7 @@ Override the default operating system
.Ar name
for the
.Xr mdoc 7
.Ic Os
.Ic \&Os
and for the
.Xr man 7
.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) 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_index(const struct req *);
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_searchres(const struct req *,
struct manpage *, size_t);
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_catman(const struct req *, const char *);
static void resp_copy(const char *);
@ -345,8 +346,9 @@ resp_copy(const char *filename)
}
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);
@ -356,10 +358,20 @@ resp_begin_html(int code, const char *msg)
" <meta charset=\"UTF-8\"/>\n"
" <link rel=\"stylesheet\" href=\"%s/mandoc.css\""
" 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"
"<body>\n",
CSS_DIR, CUSTOMIZE_TITLE);
CUSTOMIZE_TITLE);
resp_copy(MAN_DIR "/header.html");
}
@ -492,7 +504,7 @@ static void
pg_index(const struct req *req)
{
resp_begin_html(200, NULL);
resp_begin_html(200, NULL, NULL);
resp_searchform(req, FOCUS_QUERY);
printf("<p>\n"
"This web interface is documented in the\n"
@ -509,7 +521,7 @@ pg_index(const struct req *req)
static void
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);
puts("<p>");
puts(msg);
@ -521,7 +533,7 @@ static void
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"
"<p>\n");
puts(msg);
@ -534,11 +546,28 @@ pg_error_badrequest(const char *msg)
static 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>");
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
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
* without any delay.
*/
printf("Status: 303 See Other\r\n");
printf("Location: http://%s/%s%s%s/%s",
HTTP_HOST, scriptname,
*scriptname == '\0' ? "" : "/",
req->q.manpath, r[0].file);
printf("\r\n"
"Content-Type: text/html; charset=utf-8\r\n"
"\r\n");
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);
printf("%s\r\n"
"Content-Type: text/html; charset=utf-8\r\n\r\n",
r[0].file);
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
* even if more than one is found.
*/
iuse = 0;
if (req->q.equal || sz == 1) {
puts("<hr>");
iuse = 0;
priouse = 20;
archpriouse = 3;
for (i = 0; i < sz; i++) {
@ -635,6 +642,36 @@ pg_searchres(const struct req *req, struct manpage *r, size_t sz)
priouse = prio;
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);
}
@ -803,7 +840,8 @@ resp_format(const struct req *req, const char *file)
conf.fragment = 1;
conf.style = mandoc_strdup(CSS_DIR "/mandoc.css");
usepath = strcmp(req->q.manpath, req->p[0]);
mandoc_asprintf(&conf.man, "/%s%s%%N.%%S",
mandoc_asprintf(&conf.man, "/%s%s%s%s%%N.%%S",
scriptname, *scriptname == '\0' ? "" : "/",
usepath ? req->q.manpath : "", usepath ? "/" : "");
mparse_result(mp, &man, NULL);
@ -886,7 +924,7 @@ pg_show(struct req *req, const char *fullpath)
return;
}
resp_begin_html(200, NULL);
resp_begin_html(200, NULL, file);
resp_searchform(req, FOCUS_NONE);
resp_show(req, file);
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.");
else if (0 == ressz)
else if (ressz == 0)
pg_noresult(req, "No results found.");
else
pg_searchres(req, res, ressz);
@ -978,6 +1020,22 @@ main(void)
const char *querystring;
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. */
itimer.it_value.tv_sec = 2;
@ -1015,7 +1073,8 @@ main(void)
if (*path != '\0') {
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 = "";
} else if ((querystring = getenv("QUERY_STRING")) != NULL)
parse_query_string(&req, querystring);

View File

@ -1,6 +1,5 @@
/* Example compile-time configuration file for man.cgi(8). */
#define HTTP_HOST "mdocml.bsd.lv"
#define SCRIPT_NAME "cgi-bin/man.cgi"
#define MAN_DIR "/man"
#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) 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
* purpose with or without fee is hereby granted, provided that the above
@ -81,6 +81,10 @@ static struct ln lines[] = {
{ "sh", "#", 0x0023 },
{ "CR", "_|", 0x21b5 },
{ "OK", "\\/", 0x2713 },
{ "CL", "<club>", 0x2663 },
{ "SP", "<spade>", 0x2660 },
{ "HE", "<heart>", 0x2665 },
{ "DI", "<diamond>", 0x2666 },
/* Legal symbols. */
{ "co", "(C)", 0x00a9 },
@ -161,6 +165,7 @@ static struct ln lines[] = {
{ "uA", "=\b^", 0x21d1 },
{ "dA", "=\bv", 0x21d3 },
{ "vA", "^=v", 0x21d5 },
{ "an", "-", 0x23af },
/* Logic. */
{ "AN", "^", 0x2227 },
@ -234,11 +239,20 @@ static struct ln lines[] = {
{ "Ah", "N", 0x2135 },
{ "Im", "I", 0x2111 },
{ "Re", "R", 0x211c },
{ "wp", "P", 0x2118 },
{ "pd", "a", 0x2202 },
{ "-h", "/h", 0x210f },
{ "hbar", "/h", 0x210f },
{ "12", "1/2", 0x00bd },
{ "14", "1/4", 0x00bc },
{ "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. */
{ "ff", "ff", 0xfb00 },
@ -354,6 +368,8 @@ static struct ln lines[] = {
{ "fm", "\'", 0x2032 },
{ "sd", "''", 0x2033 },
{ "mc", ",\bu", 0x00b5 },
{ "Of", "_\ba", 0x00aa },
{ "Om", "_\bo", 0x00ba },
/* Greek characters. */
{ "*A", "A", 0x0391 },

19
configure vendored
View File

@ -1,6 +1,6 @@
#!/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>
#
@ -91,6 +91,7 @@ HAVE_WCHAR=
PREFIX="/usr/local"
BINDIR=
SBINDIR=
BIN_FROM_SBIN=
INCLUDEDIR=
LIBDIR=
MANDIR=
@ -458,14 +459,15 @@ echo "config.h: written" 1>&3
exec > Makefile.local
[ -z "${BINDIR}" ] && BINDIR="${PREFIX}/bin"
[ -z "${SBINDIR}" ] && SBINDIR="${PREFIX}/sbin"
[ -z "${INCLUDEDIR}" ] && INCLUDEDIR="${PREFIX}/include/mandoc"
[ -z "${LIBDIR}" ] && LIBDIR="${PREFIX}/lib/mandoc"
[ -z "${MANDIR}" ] && MANDIR="${PREFIX}/man"
[ -z "${BINDIR}" ] && BINDIR="${PREFIX}/bin"
[ -z "${SBINDIR}" ] && SBINDIR="${PREFIX}/sbin"
[ -z "${BIN_FROM_SBIN}" ] && BIN_FROM_SBIN="../bin"
[ -z "${INCLUDEDIR}" ] && INCLUDEDIR="${PREFIX}/include/mandoc"
[ -z "${LIBDIR}" ] && LIBDIR="${PREFIX}/lib/mandoc"
[ -z "${MANDIR}" ] && MANDIR="${PREFIX}/man"
[ -z "${HTDOCDIR}" ] && HTDOCDIR="${WWWPREFIX}/htdocs"
[ -z "${CGIBINDIR}" ] && CGIBINDIR="${WWWPREFIX}/cgi-bin"
[ -z "${HTDOCDIR}" ] && HTDOCDIR="${WWWPREFIX}/htdocs"
[ -z "${CGIBINDIR}" ] && CGIBINDIR="${WWWPREFIX}/cgi-bin"
[ -z "${INSTALL_PROGRAM}" ] && INSTALL_PROGRAM="${INSTALL} -m 0555"
[ -z "${INSTALL_LIB}" ] && INSTALL_LIB="${INSTALL} -m 0444"
@ -493,6 +495,7 @@ STATIC = ${STATIC}
PREFIX = ${PREFIX}
BINDIR = ${BINDIR}
SBINDIR = ${SBINDIR}
BIN_FROM_SBIN = ${BIN_FROM_SBIN}
INCLUDEDIR = ${INCLUDEDIR}
LIBDIR = ${LIBDIR}
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>
#
@ -85,6 +85,13 @@ BINDIR="${PREFIX}/bin"
SBINDIR="${PREFIX}/sbin"
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
# with the configuration files of other man(1) implementations.
# 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) 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 *
eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
{
static size_t last_len;
static int lim;
char *start, *next;
int q, diff, lim;
int q, diff;
size_t ssz, dummy;
struct eqn_def *def;
if (NULL == sz)
sz = &dummy;
lim = 0;
if (ep->cur >= last_len)
lim = 0;
ep->rew = ep->cur;
again:
/* 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,
(strlen(start) - *sz) + 1);
memcpy(start, def->val, def->valsz);
last_len = start - ep->data + def->valsz;
lim++;
goto again;
}

13
gmdiff
View File

@ -29,21 +29,24 @@ if [ "X$1" = "X-h" ]; then
EQN="neqn"
ROFF="nroff"
MOPT="-Omdoc $MOPT"
elif [ "X$1" = "X-u" ]; then
shift
ROFF="groff -ket -ww -Tutf8 -P -c"
MOPT="-Werror -Tutf8 $MOPT"
else
EQN="eqn -Tascii"
ROFF="groff -ww -Tascii -P -c"
ROFF="groff -et -ww -Tascii -P -c"
MOPT="-Werror -Tascii $MOPT"
fi
MOPT="-Werror -Tascii $MOPT"
while [ -n "$1" ]; do
file=$1
shift
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 \
2> /tmp/mandoc.err > /tmp/mandoc.out
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
diff -au /tmp/roff.out /tmp/mandoc.out 2>&1
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) 2011-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -28,8 +28,9 @@
#include <string.h>
#include <unistd.h>
#include "mandoc.h"
#include "mandoc_aux.h"
#include "mandoc.h"
#include "roff.h"
#include "out.h"
#include "html.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
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, '"');
switch (*fmt) {
case 'M':
print_href(h, arg1, arg2, 1);
fmt++;
break;
case 'I':
print_href(h, arg1, NULL, 0);
fmt++;
break;
case 'M':
print_href(h, arg1, arg2, 1);
fmt++;
break;
case 'R':
print_byte(h, '#');
print_encode(h, arg1, NULL, 1);
fmt++;
/* FALLTHROUGH */
break;
case 'T':
print_encode(h, arg1, NULL, 1);
print_word(h, "\" title=\"");
print_encode(h, arg1, NULL, 1);
fmt++;
break;
default:
print_encode(h, arg1, NULL, 1);
break;
@ -579,13 +609,21 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
SCALE_VS_INIT(su, i);
break;
case 'w':
case 'W':
if ((arg2 = va_arg(ap, char *)) == NULL)
break;
su = &mysu;
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;
fmt++;
}
break;
default:
abort();
@ -912,7 +950,10 @@ print_word(struct html *h, const char *cp)
static void
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->scale = html_strlen(p);
} 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) 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -112,9 +112,12 @@ struct html {
};
struct roff_node;
struct tbl_span;
struct eqn;
void roff_html_pre(struct html *, const struct roff_node *);
void print_gen_decls(struct html *);
void print_gen_head(struct html *);
struct tag *print_otag(struct html *, enum htmltag, const char *, ...);
@ -127,4 +130,5 @@ void print_eqn(struct html *, const struct eqn *);
void print_paragraph(struct html *);
void print_endline(struct html *);
char *html_make_id(const struct roff_node *);
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) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -17,7 +17,7 @@
*/
#define MACRO_PROT_ARGS struct roff_man *man, \
int tok, \
enum roff_tok tok, \
int line, \
int ppos, \
int *pos, \
@ -35,7 +35,6 @@ struct man_macro {
extern const struct man_macro *const man_macros;
int man_hash_find(const char *);
void man_node_validate(struct roff_man *);
void man_state(struct roff_man *, 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) 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);
const char *mandoc_a2msec(const char*);
void mdoc_hash_init(void);
int mdoc_parseln(struct roff_man *, int, char *, int);
void mdoc_endparse(struct roff_man *);
void man_hash_init(void);
int man_parseln(struct roff_man *, int, char *, int);
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) 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
* purpose with or without fee is hereby granted, provided that the above
@ -17,7 +17,7 @@
*/
#define MACRO_PROT_ARGS struct roff_man *mdoc, \
int tok, \
enum roff_tok tok, \
int line, \
int ppos, \
int *pos, \
@ -39,7 +39,6 @@ enum margserr {
ARGS_EOLN, /* end-of-line */
ARGS_WORD, /* normal word */
ARGS_PUNCT, /* series of punctuation */
ARGS_QWORD, /* quoted word */
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_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,
int, struct mdoc_arg *);
void mdoc_tail_alloc(struct roff_man *, int, int, int);
struct roff_node *mdoc_endbody_alloc(struct roff_man *, int, int, int,
struct roff_node *);
enum roff_tok, struct mdoc_arg *);
void mdoc_tail_alloc(struct roff_man *, int, int,
enum roff_tok);
struct roff_node *mdoc_endbody_alloc(struct roff_man *, int, int,
enum roff_tok, struct roff_node *);
void mdoc_node_relink(struct roff_man *, struct roff_node *);
void mdoc_node_validate(struct roff_man *);
void mdoc_state(struct roff_man *, struct roff_node *);
void mdoc_state_reset(struct roff_man *);
int mdoc_hash_find(const char *);
const char *mdoc_a2arch(const char *);
const char *mdoc_a2att(const char *);
const char *mdoc_a2lib(const char *);
enum roff_sec mdoc_a2sec(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 *);
enum margserr mdoc_args(struct roff_man *, int,
int *, char *, int, char **);
int *, char *, enum roff_tok, 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) 2010-2012, 2014-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -56,7 +56,6 @@ enum outmode {
OUTMODE_FLN,
OUTMODE_LST,
OUTMODE_ALL,
OUTMODE_INT,
OUTMODE_ONE
};
@ -67,6 +66,7 @@ enum outt {
OUTT_TREE, /* -Ttree */
OUTT_MAN, /* -Tman */
OUTT_HTML, /* -Thtml */
OUTT_MARKDOWN, /* -Tmarkdown */
OUTT_LINT, /* -Tlint */
OUTT_PS, /* -Tps */
OUTT_PDF /* -Tpdf */
@ -92,7 +92,7 @@ static void fs_search(const struct mansearch *,
const struct manpaths *, int, char**,
struct manpage **, size_t *);
static int koptions(int *, char *);
static int moptions(int *, char *);
static void moptions(int *, char *);
static void mmsg(enum mandocerr, enum mandoclevel,
const char *, int, int, const char *);
static void outdata_alloc(struct curparse *);
@ -149,7 +149,7 @@ main(int argc, char *argv[])
return mandocdb(argc, argv);
#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");
#endif
@ -193,8 +193,12 @@ main(int argc, char *argv[])
show_usage = 0;
outmode = OUTMODE_DEF;
while (-1 != (c = getopt(argc, argv,
"aC:cfhI:iK:klM:m:O:S:s:T:VW:w"))) {
while ((c = getopt(argc, argv,
"aC:cfhI:iK:klM:m:O:S:s:T:VW:w")) != -1) {
if (c == 'i' && search.argmode == ARG_EXPR) {
optind--;
break;
}
switch (c) {
case 'a':
outmode = OUTMODE_ALL;
@ -224,9 +228,6 @@ main(int argc, char *argv[])
}
defos = mandoc_strdup(optarg + 3);
break;
case 'i':
outmode = OUTMODE_INT;
break;
case 'K':
if ( ! koptions(&options, optarg))
return (int)MANDOCLEVEL_BADARG;
@ -312,7 +313,7 @@ main(int argc, char *argv[])
#if HAVE_PLEDGE
if (!use_pager)
if (pledge("stdio rpath flock", NULL) == -1)
if (pledge("stdio rpath", NULL) == -1)
err((int)MANDOCLEVEL_SYSERR, "pledge");
#endif
@ -441,8 +442,8 @@ main(int argc, char *argv[])
}
#endif
if (search.argmode == ARG_FILE && ! moptions(&options, auxpaths))
return (int)MANDOCLEVEL_BADARG;
if (search.argmode == ARG_FILE)
moptions(&options, auxpaths);
mchars_alloc();
curp.mp = mparse_alloc(options, curp.wlevel, mmsg, defos);
@ -591,24 +592,22 @@ usage(enum argmode argmode)
switch (argmode) {
case ARG_FILE:
fputs("usage: mandoc [-acfhkl] [-I os=name] "
"[-K encoding] [-mformat] [-O option]\n"
fputs("usage: mandoc [-ac] [-I os=name] "
"[-K encoding] [-mdoc | -man] [-O options]\n"
"\t [-T output] [-W level] [file ...]\n", stderr);
break;
case ARG_NAME:
fputs("usage: man [-acfhklw] [-C file] [-I os=name] "
"[-K encoding] [-M path] [-m path]\n"
"\t [-O option=value] [-S subsection] [-s section] "
"[-T output] [-W level]\n"
"\t [section] name ...\n", stderr);
fputs("usage: man [-acfhklw] [-C file] [-M path] "
"[-m path] [-S subsection]\n"
"\t [[-s] section] name ...\n", stderr);
break;
case ARG_WORD:
fputs("usage: whatis [-acfhklw] [-C file] "
fputs("usage: whatis [-afk] [-C file] "
"[-M path] [-m path] [-O outkey] [-S arch]\n"
"\t [-s section] name ...\n", stderr);
break;
case ARG_EXPR:
fputs("usage: apropos [-acfhklw] [-C file] "
fputs("usage: apropos [-afk] [-C file] "
"[-M path] [-m path] [-O outkey] [-S arch]\n"
"\t [-s section] expression ...\n", stderr);
break;
@ -766,6 +765,9 @@ parse(struct curparse *curp, int fd, const char *file)
case OUTT_PS:
terminal_mdoc(curp->outdata, man);
break;
case OUTT_MARKDOWN:
markdown_mdoc(curp->outdata, man);
break;
default:
break;
}
@ -915,24 +917,16 @@ koptions(int *options, char *arg)
return 1;
}
static int
static void
moptions(int *options, char *arg)
{
if (arg == NULL)
/* nothing to do */;
else if (0 == strcmp(arg, "doc"))
return;
if (strcmp(arg, "doc") == 0)
*options |= MPARSE_MDOC;
else if (0 == strcmp(arg, "andoc"))
/* nothing to do */;
else if (0 == strcmp(arg, "an"))
else if (strcmp(arg, "an") == 0)
*options |= MPARSE_MAN;
else {
warnx("-m %s: Bad argument", arg);
return 0;
}
return 1;
}
static int
@ -943,19 +937,19 @@ toptions(struct curparse *curp, char *arg)
curp->outtype = OUTT_ASCII;
else if (0 == strcmp(arg, "lint")) {
curp->outtype = OUTT_LINT;
curp->wlevel = MANDOCLEVEL_WARNING;
curp->wlevel = MANDOCLEVEL_STYLE;
} else if (0 == strcmp(arg, "tree"))
curp->outtype = OUTT_TREE;
else if (0 == strcmp(arg, "man"))
curp->outtype = OUTT_MAN;
else if (0 == strcmp(arg, "html"))
curp->outtype = OUTT_HTML;
else if (0 == strcmp(arg, "markdown"))
curp->outtype = OUTT_MARKDOWN;
else if (0 == strcmp(arg, "utf8"))
curp->outtype = OUTT_UTF8;
else if (0 == strcmp(arg, "locale"))
curp->outtype = OUTT_LOCALE;
else if (0 == strcmp(arg, "xhtml"))
curp->outtype = OUTT_HTML;
else if (0 == strcmp(arg, "ps"))
curp->outtype = OUTT_PS;
else if (0 == strcmp(arg, "pdf"))
@ -972,15 +966,16 @@ static int
woptions(struct curparse *curp, char *arg)
{
char *v, *o;
const char *toks[7];
const char *toks[8];
toks[0] = "stop";
toks[1] = "all";
toks[2] = "warning";
toks[3] = "error";
toks[4] = "unsupp";
toks[5] = "fatal";
toks[6] = NULL;
toks[2] = "style";
toks[3] = "warning";
toks[4] = "error";
toks[5] = "unsupp";
toks[6] = "fatal";
toks[7] = NULL;
while (*arg) {
o = arg;
@ -990,15 +985,18 @@ woptions(struct curparse *curp, char *arg)
break;
case 1:
case 2:
curp->wlevel = MANDOCLEVEL_WARNING;
curp->wlevel = MANDOCLEVEL_STYLE;
break;
case 3:
curp->wlevel = MANDOCLEVEL_ERROR;
curp->wlevel = MANDOCLEVEL_WARNING;
break;
case 4:
curp->wlevel = MANDOCLEVEL_UNSUPP;
curp->wlevel = MANDOCLEVEL_ERROR;
break;
case 5:
curp->wlevel = MANDOCLEVEL_UNSUPP;
break;
case 6:
curp->wlevel = MANDOCLEVEL_BADARG;
break;
default:
@ -1006,7 +1004,6 @@ woptions(struct curparse *curp, char *arg)
return 0;
}
}
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) 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_man(void *, const struct roff_man *);
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 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
.\" purpose with or without fee is hereby granted, provided that the above
@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: July 19 2016 $
.Dd $Mdocdate: May 17 2017 $
.Dt MAKEWHATIS 8
.Os
.Sh NAME
@ -74,6 +74,8 @@ and
.Sm on
in that directory.
Existing databases are replaced.
If a directory contains no manual pages, no database is created in that
directory.
If
.Ar dir
is not provided,
@ -130,11 +132,22 @@ Remove
.Ar
from the database in
.Ar dir .
If that causes the database to become empty, also delete the database file.
.El
.Pp
If fatal parse errors are encountered while parsing, the offending file
is printed to stderr, omitted from the index, and the parse continues
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
.Bl -tag -width Ds
.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
.\" The Regents of the University of California. All rights reserved.
.\" Copyright (c) 2003, 2007, 2008, 2014 Jason McIntyre <jmc@openbsd.org>
.\" Copyright (c) 2010, 2011, 2014, 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
.\" modification, are permitted provided that the following conditions
@ -31,7 +31,7 @@
.\"
.\" @(#)man.1 8.2 (Berkeley) 1/2/94
.\"
.Dd $Mdocdate: January 31 2017 $
.Dd $Mdocdate: May 17 2017 $
.Dt MAN 1
.Os
.Sh NAME
@ -41,16 +41,10 @@
.Nm man
.Op Fl acfhklw
.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 O Ar option Ns = Ns Ar value
.Op Fl S Ar subsection
.Op Fl s Ar section
.Op Fl T Ar output
.Op Fl W Ar level
.Op Ar section
.Op Oo Fl s Oc Ar section
.Ar name ...
.Sh DESCRIPTION
The
@ -91,39 +85,12 @@ It searches for
.Ar name
in manual page names and displays the header lines from all matching pages.
The search is case insensitive and matches whole words only.
This overrides any earlier
.Fl k
and
.Fl l
options.
.It Fl h
Display only the SYNOPSIS lines of the requested manual pages.
Implies
.Fl a
and
.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
A synonym for
.Xr apropos 1 .
@ -133,11 +100,6 @@ an expression can be provided using the syntax described in the
.Xr apropos 1
manual.
By default, it displays the header lines of all matching pages.
This overrides any earlier
.Fl f
and
.Fl l
options.
.It Fl l
A synonym for
.Xr mandoc 1
@ -149,15 +111,10 @@ No search is done and
.Ar file ,
.Ar path ,
.Ar section ,
and
.Ar subsection
are ignored.
This overrides any earlier
.Fl f ,
.Fl k ,
.Ar subsection ,
and
.Fl w
options.
are ignored.
.It Fl M Ar path
Override the list of standard directories which
.Nm
@ -184,15 +141,8 @@ the directories specified using the
option or the
.Ev MANPATH
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
Restricts the directories that
.Nm
will search to those of a specific
Only show pages for the specified
.Xr machine 1
architecture.
.Ar subsection
@ -234,53 +184,23 @@ System maintenance and operation commands.
.It 9
Kernel internals.
.El
.It Fl T Ar output
Select the output format.
The default is
.Cm locale .
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.
.Pp
If not specified and a match is found in more than one section,
the first match is selected from the following list:
1, 8, 6, 2, 3, 5, 7, 4, 9, 3p.
.It Fl w
List the pathnames of the manual pages which
.Nm
would display for the specified
.Ar section
and
.Ar name
combination.
List the pathnames of all matching manual pages instead of displaying
any of them.
.El
.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
man pages can be found in
.Xr mdoc 7 .
@ -290,13 +210,7 @@ for example
.Pa cat1/foo.0
and
.Pa man1/foo.1 ,
exist in the same directory, and at least one of them is selected,
only the newer one is used.
However, if both the
.Fl a
and the
.Fl w
options are specified, both file names are printed.
exist in the same directory, only the unformatted version is used.
.Sh ENVIRONMENT
.Bl -tag -width MANPATHX
.It Ev MACHINE
@ -318,7 +232,7 @@ is case insensitive.
.It Ev MANPAGER
Any non-empty value of the environment variable
.Ev MANPAGER
will be used instead of the standard pagination program,
is used instead of the standard pagination program,
.Xr more 1 .
If
.Xr less 1
@ -342,13 +256,27 @@ information about the term last searched for with
.It Ev MANPATH
The standard search path used by
.Nm
may be overridden by specifying a path in the
may be changed by specifying a path in the
.Ev MANPATH
environment
variable.
environment variable.
The format of the path is a colon
.Pq Ql \&:
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
Specifies the pagination program to use when
.Ev MANPAGER
@ -356,7 +284,12 @@ is not defined.
If neither PAGER nor MANPAGER is defined,
.Xr more 1
.Fl s
will be used.
is used.
Only used if
.Fl a
or
.Fl l
is specified.
.El
.Sh FILES
.Bl -tag -width /etc/man.conf -compact
@ -365,10 +298,12 @@ default man configuration file
.El
.Sh EXIT STATUS
.Ex -std man
See
.Xr mandoc 1
for details.
.Sh SEE ALSO
.Xr apropos 1 ,
.Xr intro 1 ,
.Xr whatis 1 ,
.Xr whereis 1 ,
.Xr intro 2 ,
.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) 2011-2015 Ingo Schwarze <schwarze@openbsd.org>
@ -16,7 +16,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: January 29 2015 $
.Dd $Mdocdate: May 7 2017 $
.Dt MAN 7
.Os
.Sh NAME
@ -266,8 +266,6 @@ in the alphabetical reference below.
.It Sx TP Ta tagged 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 \&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 in Ta additional indent: Op Ar width
.El
@ -350,8 +348,12 @@ See also
and
.Sx \&IR .
.Ss \&DT
Has no effect.
Included for compatibility.
Restore the default tabulator positions.
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
This is a non-standard GNU extension, included only for compatibility.
In
@ -708,12 +710,6 @@ It has the following syntax:
link description to be shown
.Pf \. Sx UE
.Ed
.Ss \&br
Breaks the current line.
Consecutive invocations have no further effect.
.Pp
See also
.Sx \&sp .
.Ss \&fi
End literal mode begun by
.Sx \&nf .
@ -736,24 +732,6 @@ Literal mode is implicitly ended by
.Sx \&SH
or
.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
The
.Nm
@ -777,10 +755,7 @@ is equivalent to
.Sq \&.I foo .
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
raised, except for
.Sx \&br
and
.Sx \&sp .
raised.
.Pp
The syntax is as follows:
.Bd -literal -offset indent
@ -808,11 +783,9 @@ The syntax is as follows:
.It Sx \&SM Ta n Ta next-line Ta \&
.It Sx \&TH Ta >1, <6 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 \&in Ta 1 Ta current Ta compat
.It Sx \&nf Ta 0 Ta current Ta compat
.It Sx \&sp Ta 1 Ta current Ta compat
.El
.Pp
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) 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>
*
* Permission to use, copy, modify, and distribute this software for any
@ -35,21 +35,6 @@
#include "roff_int.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 int man_ptext(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. */ ;
/*
* Blank lines are ignored right after headings
* but add a single vertical space elsewhere.
* Blank lines are ignored in next line scope and right
* after headings but add a single vertical space elsewhere.
*/
if (buf[i] == '\0') {
/* Allocate a blank entry. */
if (man->last->tok != MAN_SH &&
if (man->flags & (MAN_ELINE | MAN_BLINE))
mandoc_msg(MANDOCERR_BLK_BLANK, man->parse,
line, 0, NULL);
else if (man->last->tok != MAN_SH &&
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;
}
return 1;
@ -160,26 +147,19 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
{
struct roff_node *n;
const char *cp;
int tok;
int i, ppos;
size_t sz;
enum roff_tok tok;
int ppos;
int bline;
char mac[5];
/* Determine the line macro. */
ppos = offs;
/*
* Copy the first word into a nil-terminated buffer.
* Stop when a space, tab, escape, or eoln is encountered.
*/
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;
tok = TOKEN_NONE;
for (sz = 0; sz < 4 && strchr(" \t\\", buf[offs]) == NULL; sz++)
offs++;
if (sz > 0 && sz < 4)
tok = roffhash_find(man->manmac, buf + ppos, sz);
if (tok == TOKEN_NONE) {
mandoc_msg(MANDOCERR_MACRO, man->parse,
ln, ppos, buf + ppos - 1);
@ -203,7 +183,7 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
/* Jump to the next non-whitespace word. */
while (buf[offs] && buf[offs] == ' ')
while (buf[offs] == ' ')
offs++;
/*
@ -223,6 +203,20 @@ man_pmacro(struct roff_man *man, int ln, char *buf, int offs)
man_breakscope(man, tok);
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... */
assert(man_macros[tok].fp);
@ -266,7 +260,7 @@ man_breakscope(struct roff_man *man, int tok)
* 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))) {
n = man->last;
assert(n->type != ROFFT_TEXT);
@ -275,8 +269,7 @@ man_breakscope(struct roff_man *man, int tok)
mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
n->line, n->pos, "%s breaks %s",
tok == TOKEN_NONE ? "TS" : man_macronames[tok],
man_macronames[n->tok]);
roff_name[tok], roff_name[n->tok]);
roff_node_delete(man, n);
man->flags &= ~MAN_ELINE;
@ -302,7 +295,7 @@ man_breakscope(struct roff_man *man, int tok)
* 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)) {
n = man->last;
if (n->type == ROFFT_TEXT)
@ -317,8 +310,7 @@ man_breakscope(struct roff_man *man, int tok)
mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
n->line, n->pos, "%s breaks %s",
tok == TOKEN_NONE ? "TS" : man_macronames[tok],
man_macronames[n->tok]);
roff_name[tok], roff_name[n->tok]);
roff_node_delete(man, n);
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
.\" purpose with or without fee is hereby granted, provided that the above
@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: July 7 2016 $
.Dd $Mdocdate: March 15 2017 $
.Dt MAN.CGI 3
.Os
.Sh NAME
@ -126,12 +126,30 @@ contains a search query in short format or when
is empty and a
.Ev QUERY_STRING
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 .
Depending on the result, it calls either
.Fn pg_noresult
or
.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"
This function calls
.Fn resp_begin_html ,
@ -219,13 +237,18 @@ and
are used.
The highest level result generators are:
.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
.Fn resp_begin_http
to print the HTTP headers, then prints the HTML header up to the
opening tag of the <body> element, then copies the file
.Pa header.html
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"
This generator prints a search form, filling it with data
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>
.\"
@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: July 11 2016 $
.Dd $Mdocdate: March 18 2017 $
.Dt MAN.CGI 8
.Os
.Sh NAME
@ -186,11 +186,6 @@ Otherwise, a leading slash is needed.
This is used in generated HTML code.
.It Dv CUSTOMIZE_TITLE
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
A file system path to the
.Nm
@ -411,15 +406,16 @@ A version of
based on
.Xr mandoc 1
first appeared in mdocml-1.12.1 (March 2012).
The current SQLite3-based version first appeared in
.Ox 5.6 .
The current
.Xr mandoc.db 5
database format first appeared in
.Ox 6.1 .
.Sh AUTHORS
.An -nosplit
The
.Nm
program was written by
.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
and ported to the SQLite3-based
.Xr mandoc.db 5
backend by
.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
and is maintained by
.An Ingo Schwarze Aq Mt schwarze@openbsd.org ,
who also designed and implemented the database format.

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) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -16,50 +16,6 @@
* 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;
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) 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_UR_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_in_pre(MAN_ARGS);
static void man_root_post(MAN_ARGS);
static void man_root_pre(MAN_ARGS);
static const struct htmlman mans[MAN_MAX] = {
{ man_br_pre, NULL }, /* br */
static const struct htmlman __mans[MAN_MAX - MAN_TH] = {
{ NULL, NULL }, /* TH */
{ man_SH_pre, NULL }, /* SH */
{ man_SS_pre, NULL }, /* SS */
@ -93,7 +91,6 @@ static const struct htmlman mans[MAN_MAX] = {
{ man_I_pre, NULL }, /* I */
{ man_alt_pre, NULL }, /* IR */
{ man_alt_pre, NULL }, /* RI */
{ man_br_pre, NULL }, /* sp */
{ NULL, NULL }, /* nf */
{ NULL, NULL }, /* fi */
{ NULL, NULL }, /* RE */
@ -103,14 +100,13 @@ static const struct htmlman mans[MAN_MAX] = {
{ man_ign_pre, NULL }, /* PD */
{ man_ign_pre, NULL }, /* AT */
{ man_in_pre, NULL }, /* in */
{ man_ign_pre, NULL }, /* ft */
{ man_OP_pre, NULL }, /* OP */
{ NULL, NULL }, /* EX */
{ NULL, NULL }, /* EE */
{ man_UR_pre, NULL }, /* UR */
{ 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:
if (fillmode(h, 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, "");
if (*n->string != '\0')
break;
@ -304,6 +301,13 @@ print_man_node(MAN_ARGS)
print_tblclose(h);
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)
child = (*mans[n->tok].pre)(man, n, h);
@ -354,13 +358,9 @@ fillmode(struct html *h, int want)
static int
a2width(const struct roff_node *n, struct roffsu *su)
{
if (n->type != ROFFT_TEXT)
return 0;
if (a2roffsu(n->string, su, SCALE_EN))
return 1;
return 0;
return a2roffsu(n->string, su, SCALE_EN) != NULL;
}
static void
@ -409,34 +409,18 @@ man_root_post(MAN_ARGS)
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
man_SH_pre(MAN_ARGS)
{
if (n->type == ROFFT_HEAD)
print_otag(h, TAG_H1, "c", "Sh");
char *id;
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;
}
@ -498,8 +482,15 @@ man_SM_pre(MAN_ARGS)
static int
man_SS_pre(MAN_ARGS)
{
if (n->type == ROFFT_HEAD)
print_otag(h, TAG_H2, "c", "Ss");
char *id;
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;
}
@ -656,7 +647,7 @@ man_UR_pre(MAN_ARGS)
assert(n->type == ROFFT_HEAD);
if (n->child != NULL) {
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);

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) 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>
*
* 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 int man_args(struct roff_man *, int,
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] = {
{ in_line_eoln, MAN_NSCOPED }, /* br */
const struct man_macro __man_macros[MAN_MAX - MAN_TH] = {
{ in_line_eoln, MAN_BSCOPE }, /* TH */
{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SH */
{ blk_imp, MAN_BSCOPE | MAN_SCOPED }, /* SS */
@ -62,7 +61,6 @@ const struct man_macro __man_macros[MAN_MAX] = {
{ in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* I */
{ in_line_eoln, 0 }, /* IR */
{ in_line_eoln, 0 }, /* RI */
{ in_line_eoln, MAN_NSCOPED }, /* sp */
{ in_line_eoln, MAN_NSCOPED }, /* nf */
{ in_line_eoln, MAN_NSCOPED }, /* fi */
{ 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, 0 }, /* AT */
{ in_line_eoln, 0 }, /* in */
{ in_line_eoln, 0 }, /* ft */
{ in_line_eoln, 0 }, /* OP */
{ in_line_eoln, MAN_BSCOPE }, /* EX */
{ in_line_eoln, MAN_BSCOPE }, /* EE */
{ blk_exp, MAN_BSCOPE }, /* UR */
{ blk_close, MAN_BSCOPE }, /* UE */
{ in_line_eoln, 0 }, /* ll */
};
const struct man_macro * const man_macros = __man_macros;
const struct man_macro *const man_macros = __man_macros - MAN_TH;
void
@ -100,8 +95,7 @@ man_unscope(struct roff_man *man, const struct roff_node *to)
man_macros[n->tok].flags & MAN_SCOPED) {
mandoc_vmsg(MANDOCERR_BLK_LINE,
man->parse, n->line, n->pos,
"EOF breaks %s",
man_macronames[n->tok]);
"EOF breaks %s", roff_name[n->tok]);
if (man->flags & MAN_ELINE)
man->flags &= ~MAN_ELINE;
else {
@ -118,7 +112,7 @@ man_unscope(struct roff_man *man, const struct roff_node *to)
man_macros[n->tok].fp == blk_exp)
mandoc_msg(MANDOCERR_BLK_NOEND,
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.
*/
static void
rew_scope(struct roff_man *man, int tok)
rew_scope(struct roff_man *man, enum roff_tok tok)
{
struct roff_node *n;
@ -193,7 +187,7 @@ rew_scope(struct roff_man *man, int tok)
void
blk_close(MACRO_PROT_ARGS)
{
int ntok;
enum roff_tok ntok;
const struct roff_node *nn;
char *p;
int nrew, target;
@ -233,7 +227,7 @@ blk_close(MACRO_PROT_ARGS)
if (nn == NULL) {
mandoc_msg(MANDOCERR_BLK_NOTOPEN, man->parse,
line, ppos, man_macronames[tok]);
line, ppos, roff_name[tok]);
rew_scope(man, MAN_PP);
} else {
line = man->last->line;
@ -266,9 +260,8 @@ blk_exp(MACRO_PROT_ARGS)
roff_word_alloc(man, line, la, p);
if (buf[*pos] != '\0')
mandoc_vmsg(MANDOCERR_ARG_EXCESS,
man->parse, line, *pos, "%s ... %s",
man_macronames[tok], buf + *pos);
mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse, line,
*pos, "%s ... %s", roff_name[tok], buf + *pos);
man_unscope(man, head);
roff_body_alloc(man, line, ppos, tok);
@ -331,18 +324,16 @@ in_line_eoln(MACRO_PROT_ARGS)
n = man->last;
for (;;) {
if (buf[*pos] != '\0' && (tok == MAN_br ||
tok == MAN_fi || tok == MAN_nf)) {
if (buf[*pos] != '\0' && (tok == MAN_fi || tok == MAN_nf)) {
mandoc_vmsg(MANDOCERR_ARG_SKIP,
man->parse, line, *pos, "%s %s",
man_macronames[tok], buf + *pos);
roff_name[tok], buf + *pos);
break;
}
if (buf[*pos] != '\0' && man->last != n &&
(tok == MAN_PD || tok == MAN_ft || tok == MAN_sp)) {
if (buf[*pos] != '\0' && man->last != n && tok == MAN_PD) {
mandoc_vmsg(MANDOCERR_ARG_EXCESS,
man->parse, line, *pos, "%s ... %s",
man_macronames[tok], buf + *pos);
roff_name[tok], buf + *pos);
break;
}
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) 2010-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -68,6 +68,7 @@ static void print_bvspace(struct termp *,
const struct roff_node *, int);
static int pre_B(DECL_ARGS);
static int pre_DT(DECL_ARGS);
static int pre_HP(DECL_ARGS);
static int pre_I(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_UR(DECL_ARGS);
static int pre_alternate(DECL_ARGS);
static int pre_ft(DECL_ARGS);
static int pre_ign(DECL_ARGS);
static int pre_in(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_HP(DECL_ARGS);
@ -95,8 +93,7 @@ static void post_SS(DECL_ARGS);
static void post_TP(DECL_ARGS);
static void post_UR(DECL_ARGS);
static const struct termact termacts[MAN_MAX] = {
{ pre_sp, NULL, MAN_NOTEXT }, /* br */
static const struct termact __termacts[MAN_MAX - MAN_TH] = {
{ NULL, NULL, 0 }, /* TH */
{ pre_SH, post_SH, 0 }, /* SH */
{ pre_SS, post_SS, 0 }, /* SS */
@ -117,24 +114,22 @@ static const struct termact termacts[MAN_MAX] = {
{ pre_I, NULL, 0 }, /* I */
{ pre_alternate, NULL, 0 }, /* IR */
{ pre_alternate, NULL, 0 }, /* RI */
{ pre_sp, NULL, MAN_NOTEXT }, /* sp */
{ pre_literal, NULL, 0 }, /* nf */
{ pre_literal, NULL, 0 }, /* fi */
{ NULL, NULL, 0 }, /* RE */
{ pre_RS, post_RS, 0 }, /* RS */
{ pre_ign, NULL, 0 }, /* DT */
{ pre_DT, NULL, 0 }, /* DT */
{ pre_ign, NULL, MAN_NOTEXT }, /* UC */
{ pre_PD, NULL, MAN_NOTEXT }, /* PD */
{ pre_ign, NULL, 0 }, /* AT */
{ pre_in, NULL, MAN_NOTEXT }, /* in */
{ pre_ft, NULL, MAN_NOTEXT }, /* ft */
{ pre_OP, NULL, 0 }, /* OP */
{ pre_literal, NULL, 0 }, /* EX */
{ pre_literal, NULL, 0 }, /* EE */
{ pre_UR, post_UR, 0 }, /* UR */
{ NULL, NULL, 0 }, /* UE */
{ pre_ll, NULL, MAN_NOTEXT }, /* ll */
};
static const struct termact *termacts = __termacts - MAN_TH;
void
@ -146,9 +141,10 @@ terminal_man(void *arg, const struct roff_man *man)
size_t save_defindent;
p = (struct termp *)arg;
p->overstep = 0;
p->rmargin = p->maxrmargin = p->defrmargin;
p->tabwidth = term_len(p, 5);
p->tcol->rmargin = p->maxrmargin = p->defrmargin;
term_tab_set(p, NULL);
term_tab_set(p, "T");
term_tab_set(p, ".5i");
memset(&mt, 0, sizeof(struct mtermp));
mt.lmargin[mt.lmargincur] = term_len(p, p->defindent);
@ -218,14 +214,6 @@ pre_ign(DECL_ARGS)
return 0;
}
static int
pre_ll(DECL_ARGS)
{
term_setwidth(p, n->child != NULL ? n->child->string : NULL);
return 0;
}
static int
pre_I(DECL_ARGS)
{
@ -240,7 +228,7 @@ pre_literal(DECL_ARGS)
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;
else
mt->fl &= ~MANT_LITERAL;
@ -250,9 +238,9 @@ pre_literal(DECL_ARGS)
* So in case a second call to term_flushln() is needed,
* indentation has to be set up explicitly.
*/
if (MAN_HP == n->parent->tok && p->rmargin < p->maxrmargin) {
p->offset = p->rmargin;
p->rmargin = p->maxrmargin;
if (n->parent->tok == MAN_HP && p->tcol->rmargin < p->maxrmargin) {
p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = p->maxrmargin;
p->trailspace = 0;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
p->flags |= TERMP_NOSPACE;
@ -272,7 +260,7 @@ pre_PD(DECL_ARGS)
return 0;
}
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);
return 0;
}
@ -361,41 +349,6 @@ pre_OP(DECL_ARGS)
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
pre_in(DECL_ARGS)
{
@ -406,8 +359,8 @@ pre_in(DECL_ARGS)
term_newln(p);
if (NULL == n->child) {
p->offset = mt->offset;
if (n->child == NULL) {
p->tcol->offset = mt->offset;
return 0;
}
@ -421,71 +374,29 @@ pre_in(DECL_ARGS)
else
cp--;
if ( ! a2roffsu(++cp, &su, SCALE_EN))
if (a2roffsu(++cp, &su, SCALE_EN) == NULL)
return 0;
v = (term_hspan(p, &su) + 11) / 24;
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)
p->offset += v;
p->tcol->offset += v;
else
p->offset = v;
if (p->offset > SHRT_MAX)
p->offset = term_len(p, p->defindent);
p->tcol->offset = v;
if (p->tcol->offset > SHRT_MAX)
p->tcol->offset = term_len(p, p->defindent);
return 0;
}
static int
pre_sp(DECL_ARGS)
pre_DT(DECL_ARGS)
{
struct roffsu su;
int i, len;
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);
}
term_tab_set(p, NULL);
term_tab_set(p, "T");
term_tab_set(p, ".5i");
return 0;
}
@ -514,7 +425,7 @@ pre_HP(DECL_ARGS)
/* Calculate offset. */
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;
if (len < 0 && (size_t)(-len) > mt->offset)
len = -mt->offset;
@ -524,8 +435,8 @@ pre_HP(DECL_ARGS)
} else
len = mt->lmargin[mt->lmargincur];
p->offset = mt->offset;
p->rmargin = mt->offset + len;
p->tcol->offset = mt->offset;
p->tcol->rmargin = mt->offset + len;
return 1;
}
@ -549,8 +460,8 @@ post_HP(DECL_ARGS)
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
p->trailspace = 0;
p->offset = mt->offset;
p->rmargin = p->maxrmargin;
p->tcol->offset = mt->offset;
p->tcol->rmargin = p->maxrmargin;
break;
default:
break;
@ -567,7 +478,7 @@ pre_PP(DECL_ARGS)
print_bvspace(p, n, mt->pardist);
break;
default:
p->offset = mt->offset;
p->tcol->offset = mt->offset;
break;
}
@ -599,7 +510,7 @@ pre_IP(DECL_ARGS)
/* Calculate the offset from the optional second argument. */
if ((nn = n->parent->head->child) != NULL &&
(nn = nn->next) != NULL &&
a2roffsu(nn->string, &su, SCALE_EN)) {
a2roffsu(nn->string, &su, SCALE_EN) != NULL) {
len = term_hspan(p, &su) / 24;
if (len < 0 && (size_t)(-len) > mt->offset)
len = -mt->offset;
@ -611,8 +522,8 @@ pre_IP(DECL_ARGS)
switch (n->type) {
case ROFFT_HEAD:
p->offset = mt->offset;
p->rmargin = mt->offset + len;
p->tcol->offset = mt->offset;
p->tcol->rmargin = mt->offset + len;
savelit = MANT_LITERAL & mt->fl;
mt->fl &= ~MANT_LITERAL;
@ -625,8 +536,8 @@ pre_IP(DECL_ARGS)
return 0;
case ROFFT_BODY:
p->offset = mt->offset + len;
p->rmargin = p->maxrmargin;
p->tcol->offset = mt->offset + len;
p->tcol->rmargin = p->maxrmargin;
break;
default:
break;
@ -644,11 +555,11 @@ post_IP(DECL_ARGS)
term_flushln(p);
p->flags &= ~TERMP_NOBREAK;
p->trailspace = 0;
p->rmargin = p->maxrmargin;
p->tcol->rmargin = p->maxrmargin;
break;
case ROFFT_BODY:
term_newln(p);
p->offset = mt->offset;
p->tcol->offset = mt->offset;
break;
default:
break;
@ -681,7 +592,7 @@ pre_TP(DECL_ARGS)
if ((nn = n->parent->head->child) != NULL &&
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;
if (len < 0 && (size_t)(-len) > mt->offset)
len = -mt->offset;
@ -693,8 +604,8 @@ pre_TP(DECL_ARGS)
switch (n->type) {
case ROFFT_HEAD:
p->offset = mt->offset;
p->rmargin = mt->offset + len;
p->tcol->offset = mt->offset;
p->tcol->rmargin = mt->offset + len;
savelit = MANT_LITERAL & mt->fl;
mt->fl &= ~MANT_LITERAL;
@ -713,8 +624,8 @@ pre_TP(DECL_ARGS)
mt->fl |= MANT_LITERAL;
return 0;
case ROFFT_BODY:
p->offset = mt->offset + len;
p->rmargin = p->maxrmargin;
p->tcol->offset = mt->offset + len;
p->tcol->rmargin = p->maxrmargin;
p->trailspace = 0;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP);
break;
@ -735,7 +646,7 @@ post_TP(DECL_ARGS)
break;
case ROFFT_BODY:
term_newln(p);
p->offset = mt->offset;
p->tcol->offset = mt->offset;
break;
default:
break;
@ -770,14 +681,14 @@ pre_SS(DECL_ARGS)
break;
case ROFFT_HEAD:
term_fontrepl(p, TERMFONT_BOLD);
p->offset = term_len(p, 3);
p->rmargin = mt->offset;
p->tcol->offset = term_len(p, 3);
p->tcol->rmargin = mt->offset;
p->trailspace = mt->offset;
p->flags |= TERMP_NOBREAK | TERMP_BRIND;
break;
case ROFFT_BODY:
p->offset = mt->offset;
p->rmargin = p->maxrmargin;
p->tcol->offset = mt->offset;
p->tcol->rmargin = p->maxrmargin;
p->trailspace = 0;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
break;
@ -832,14 +743,14 @@ pre_SH(DECL_ARGS)
break;
case ROFFT_HEAD:
term_fontrepl(p, TERMFONT_BOLD);
p->offset = 0;
p->rmargin = mt->offset;
p->tcol->offset = 0;
p->tcol->rmargin = mt->offset;
p->trailspace = mt->offset;
p->flags |= TERMP_NOBREAK | TERMP_BRIND;
break;
case ROFFT_BODY:
p->offset = mt->offset;
p->rmargin = p->maxrmargin;
p->tcol->offset = mt->offset;
p->tcol->rmargin = p->maxrmargin;
p->trailspace = 0;
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
break;
@ -885,7 +796,7 @@ pre_RS(DECL_ARGS)
n->aux = SHRT_MAX + 1;
if (n->child == NULL)
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;
if (n->aux < 0 && (size_t)(-n->aux) > mt->offset)
n->aux = -mt->offset;
@ -893,8 +804,8 @@ pre_RS(DECL_ARGS)
n->aux = term_len(p, p->defindent);
mt->offset += n->aux;
p->offset = mt->offset;
p->rmargin = p->maxrmargin;
p->tcol->offset = mt->offset;
p->tcol->rmargin = p->maxrmargin;
if (++mt->lmarginsz < MAXMARGINS)
mt->lmargincur = mt->lmarginsz;
@ -918,7 +829,7 @@ post_RS(DECL_ARGS)
}
mt->offset -= n->parent->head->aux;
p->offset = mt->offset;
p->tcol->offset = mt->offset;
if (--mt->lmarginsz < MAXMARGINS)
mt->lmargincur = mt->lmarginsz;
@ -951,7 +862,6 @@ post_UR(DECL_ARGS)
static void
print_man_node(DECL_ARGS)
{
size_t rm, rmax;
int c;
switch (n->type) {
@ -961,10 +871,11 @@ print_man_node(DECL_ARGS)
* If we have a space as the first character, break
* before printing the line's data.
*/
if ('\0' == *n->string) {
if (*n->string == '\0') {
term_vspace(p);
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_word(p, n->string);
@ -986,6 +897,12 @@ print_man_node(DECL_ARGS)
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))
term_fontrepl(p, TERMFONT_NONE);
@ -1012,20 +929,17 @@ print_man_node(DECL_ARGS)
if (mt->fl & MANT_LITERAL &&
! (p->flags & (TERMP_NOBREAK | TERMP_NONEWLINE)) &&
(n->next == NULL || n->next->flags & NODE_LINE)) {
rm = p->rmargin;
rmax = p->maxrmargin;
p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
p->flags |= TERMP_NOSPACE;
p->flags |= TERMP_BRNEVER | TERMP_NOSPACE;
if (n->string != NULL && *n->string != '\0')
term_flushln(p);
else
term_newln(p);
if (rm < rmax && n->parent->tok == MAN_HP) {
p->offset = rm;
p->rmargin = rmax;
} else
p->rmargin = rm;
p->maxrmargin = rmax;
p->flags &= ~TERMP_BRNEVER;
if (p->tcol->rmargin < p->maxrmargin &&
n->parent->tok == MAN_HP) {
p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = p->maxrmargin;
}
}
if (NODE_EOS & n->flags)
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->trailspace = 1;
p->offset = 0;
p->rmargin = p->maxrmargin > datelen ?
p->tcol->offset = 0;
p->tcol->rmargin = p->maxrmargin > datelen ?
(p->maxrmargin + term_len(p, 1) - datelen) / 2 : 0;
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. */
p->offset = p->rmargin;
p->tcol->offset = p->tcol->rmargin;
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;
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_NOSPACE;
p->trailspace = 0;
p->offset = p->rmargin;
p->rmargin = p->maxrmargin;
p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = p->maxrmargin;
term_word(p, title);
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->trailspace = 1;
p->offset = 0;
p->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
p->tcol->offset = 0;
p->tcol->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
(p->maxrmargin - vollen + term_len(p, 1)) / 2 :
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. */
p->flags |= TERMP_NOSPACE;
p->offset = p->rmargin;
p->rmargin = p->offset + vollen + titlen < p->maxrmargin ?
p->maxrmargin - titlen : p->maxrmargin;
p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = p->tcol->offset + vollen + titlen <
p->maxrmargin ? p->maxrmargin - titlen : p->maxrmargin;
term_word(p, volume);
term_flushln(p);
@ -1154,17 +1069,17 @@ print_man_head(struct termp *p, const struct roff_meta *meta)
p->flags &= ~TERMP_NOBREAK;
p->trailspace = 0;
if (p->rmargin + titlen <= p->maxrmargin) {
if (p->tcol->rmargin + titlen <= p->maxrmargin) {
p->flags |= TERMP_NOSPACE;
p->offset = p->rmargin;
p->rmargin = p->maxrmargin;
p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = p->maxrmargin;
term_word(p, title);
term_flushln(p);
}
p->flags &= ~TERMP_NOSPACE;
p->offset = 0;
p->rmargin = p->maxrmargin;
p->tcol->offset = 0;
p->tcol->rmargin = p->maxrmargin;
/*
* Groff prints three blank lines before the content.

View File

@ -1,7 +1,7 @@
/* $OpenBSD$ */
/*
* 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
* 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_IP(CHKARGS);
static void post_vs(CHKARGS);
static void post_ft(CHKARGS);
static void post_OP(CHKARGS);
static void post_TH(CHKARGS);
static void post_UC(CHKARGS);
static void post_UR(CHKARGS);
static v_check man_valids[MAN_MAX] = {
post_vs, /* br */
static const v_check __man_valids[MAN_MAX - MAN_TH] = {
post_TH, /* TH */
NULL, /* SH */
NULL, /* SS */
@ -76,7 +74,6 @@ static v_check man_valids[MAN_MAX] = {
NULL, /* I */
NULL, /* IR */
NULL, /* RI */
post_vs, /* sp */
NULL, /* nf */
NULL, /* fi */
NULL, /* RE */
@ -86,21 +83,20 @@ static v_check man_valids[MAN_MAX] = {
NULL, /* PD */
post_AT, /* AT */
NULL, /* in */
post_ft, /* ft */
post_OP, /* OP */
NULL, /* EX */
NULL, /* EE */
post_UR, /* UR */
NULL, /* UE */
NULL, /* ll */
};
static const v_check *man_valids = __man_valids - MAN_TH;
void
man_node_validate(struct roff_man *man)
{
struct roff_node *n;
v_check *cp;
const v_check *cp;
n = man->last;
man->last = man->last->child;
@ -125,6 +121,19 @@ man_node_validate(struct roff_man *man)
case ROFFT_TBL:
break;
default:
if (n->tok < ROFF_MAX) {
switch (n->tok) {
case ROFF_br:
case ROFF_sp:
post_vs(man, n);
break;
default:
roff_validate(man);
break;
}
break;
}
assert(n->tok >= MAN_TH && n->tok < MAN_MAX);
cp = man_valids + n->tok;
if (*cp)
(*cp)(man, n);
@ -200,54 +209,13 @@ post_UR(CHKARGS)
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
check_part(CHKARGS)
{
if (n->type == ROFFT_BODY && n->child == NULL)
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
@ -263,14 +231,13 @@ check_par(CHKARGS)
if (n->child == NULL)
mandoc_vmsg(MANDOCERR_PAR_SKIP,
man->parse, n->line, n->pos,
"%s empty", man_macronames[n->tok]);
"%s empty", roff_name[n->tok]);
break;
case ROFFT_HEAD:
if (n->child != NULL)
mandoc_vmsg(MANDOCERR_ARG_SKIP,
man->parse, n->line, n->pos,
"%s %s%s", man_macronames[n->tok],
n->child->string,
man->parse, n->line, n->pos, "%s %s%s",
roff_name[n->tok], n->child->string,
n->child->next != NULL ? " ..." : "");
break;
default:
@ -291,7 +258,7 @@ post_IP(CHKARGS)
if (n->parent->head->child == NULL && n->child == NULL)
mandoc_vmsg(MANDOCERR_PAR_SKIP,
man->parse, n->line, n->pos,
"%s empty", man_macronames[n->tok]);
"%s empty", roff_name[n->tok]);
break;
default:
break;
@ -478,9 +445,12 @@ post_vs(CHKARGS)
switch (n->parent->tok) {
case MAN_SH:
case MAN_SS:
case MAN_PP:
case MAN_LP:
case MAN_P:
mandoc_vmsg(MANDOCERR_PAR_SKIP, man->parse, n->line, n->pos,
"%s after %s", man_macronames[n->tok],
man_macronames[n->parent->tok]);
"%s after %s", roff_name[n->tok],
roff_name[n->parent->tok]);
/* FALLTHROUGH */
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) 2012, 2014-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -15,19 +15,19 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: February 10 2017 $
.Dd $Mdocdate: June 8 2017 $
.Dt MANDOC 1
.Os
.Sh NAME
.Nm mandoc
.Nd format and display UNIX manuals
.Nd format manual pages
.Sh SYNOPSIS
.Nm mandoc
.Op Fl acfhkl
.Op Fl ac
.Op Fl I Cm os Ns = Ns Ar name
.Op Fl K Ar encoding
.Op Fl m Ns Ar format
.Op Fl O Ar option
.Op Fl mdoc | man
.Op Fl O Ar options
.Op Fl T Ar output
.Op Fl W Ar level
.Op Ar
@ -44,9 +44,7 @@ reads
.Xr mdoc 7
or
.Xr man 7
text from stdin, implying
.Fl m Ns Cm andoc ,
and produces
text from stdin and produces
.Fl T Cm locale
output.
.Pp
@ -67,28 +65,21 @@ to paginate them.
This is the default.
It can be specified to override
.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
Override the default operating system
.Ar name
for the
.Xr mdoc 7
.Sq \&Os
.Ic \&Os
and for the
.Xr man 7
.Sq \&TH
.Ic \&TH
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
Specify the input encoding.
The supported
@ -98,46 +89,53 @@ arguments are
.Cm iso-8859-1 ,
and
.Cm utf-8 .
If not specified, autodetection uses the first match:
.Bl -tag -width iso-8859-1
.It Cm utf-8
if the first three bytes of the input file
are the UTF-8 byte order mark (BOM, 0xefbbbf)
.It Ar encoding
if the first or second line of the input file matches the
If not specified, autodetection uses the first match in the following
list:
.Bl -enum
.It
If the first three bytes of the input file are the UTF-8 byte order
mark (BOM, 0xefbbbf), input is interpreted as
.Cm utf-8 .
.It
If the first or second line of the input file matches the
.Sy emacs
mode line format
.Pp
.D1 .\e" -*- Oo ...; Oc coding: Ar encoding ; No -*-
.It Cm utf-8
if the first non-ASCII byte in the file introduces a valid UTF-8 sequence
.It Cm iso-8859-1
otherwise
.Pp
then input is interpreted according to
.Ar encoding .
.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
.It Fl k
A synonym for
.Xr apropos 1 .
This overrides any earlier
.Fl f
and
.Fl l
options.
.It Fl l
A synonym for
.Fl a .
Also reverts any earlier
.Fl f
and
.Fl k
options.
.It Fl m Ns Ar format
Input format.
See
.Sx Input Formats
for available formats.
Defaults to
.Fl m Ns Cm andoc .
.It Fl O Ar option
.It Fl mdoc | man
With
.Fl mdoc ,
all input files are interpreted as
.Xr mdoc 7 .
With
.Fl man ,
all input files are interpreted as
.Xr man 7 .
By default, the input language is automatically detected for each file:
if the the first macro is
.Ic \&Dd
or
.Ic \&Dt ,
the
.Xr mdoc 7
parser is used; otherwise, the
.Xr man 7
parser is used.
With other arguments,
.Fl m
is silently ignored.
.It Fl O Ar options
Comma-separated output options.
.It Fl T Ar output
Output format.
@ -153,13 +151,14 @@ to be reported on the standard error output and to affect the exit status.
The
.Ar level
can be
.Cm style ,
.Cm warning ,
.Cm error ,
or
.Cm unsupp ;
.Cm all
is an alias for
.Cm warning .
.Cm style .
By default,
.Nm
is silent.
@ -190,6 +189,9 @@ If multiple files are specified,
will halt with the first failed parse.
.El
.Pp
The options
.Fl fhklw
are also supported and are documented in man(1).
In
.Fl f
and
@ -197,60 +199,20 @@ and
mode,
.Nm
also supports the options
.Fl CMmOSsw
.Fl CMmOSs
described in the
.Xr apropos 1
manual.
.Ss Input Formats
The
.Nm
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.
The options
.Fl fkl
are mutually exclusive and override each other.
.Ss Output Formats
The
.Nm
utility accepts the following
.Fl T
arguments, which correspond to output modes:
.Bl -tag -width "-T locale"
.Bl -tag -width "-T markdown"
.It Fl T Cm ascii
Produce 7-bit ASCII output.
See
@ -262,7 +224,7 @@ See
.It Fl T Cm lint
Parse only: produce no output.
Implies
.Fl W Cm warning .
.Fl W Cm style .
.It Fl T Cm locale
Encode output using the current locale.
This is the default.
@ -274,6 +236,12 @@ Produce
format output.
See
.Sx Man Output .
.It Fl T Cm markdown
Produce output in
.Sy markdown
format.
See
.Sx Markdown Output .
.It Fl T Cm pdf
Produce PDF output.
See
@ -290,9 +258,6 @@ See
Encode output in the UTF\-8 multi-byte format.
See
.Sx UTF\-8 Output .
.It Fl T Cm xhtml
This is a synonym for
.Fl T Cm html .
.El
.Pp
If multiple input files are specified, these will be processed by the
@ -377,7 +342,7 @@ The string
for example,
.Ar ../src/%I.html ,
is used as a template for linked header files (usually via the
.Sq \&In
.Ic \&In
macro).
Instances of
.Sq \&%I
@ -390,7 +355,7 @@ The string
for example,
.Ar ../html%S/%N.%S.html ,
is used as a template for linked manuals (usually via the
.Sq \&Xr
.Ic \&Xr
macro).
Instances of
.Sq \&%N
@ -436,13 +401,47 @@ If the input format is
.Xr man 7 ,
the input is copied to the output, expanding any
.Xr roff 7
.Sq so
.Ic so
requests.
The parser is also run, and as usual, the
.Fl W
level controls which
.Sx DIAGNOSTICS
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
PDF-1.1 output may be generated by
.Fl T Cm pdf .
@ -563,8 +562,16 @@ Meta data is not available in this case.
.It Ev MANPAGER
Any non-empty value of the environment variable
.Ev MANPAGER
will be used instead of the standard pagination program,
.Xr more 1 .
is used instead of the standard pagination program,
.Xr more 1 ;
see
.Xr man 1
for details.
Only used if
.Fl a
or
.Fl l
is specified.
.It Ev PAGER
Specifies the pagination program to use when
.Ev MANPAGER
@ -572,7 +579,12 @@ is not defined.
If neither PAGER nor MANPAGER is defined,
.Xr more 1
.Fl s
will be used.
is used.
Only used if
.Fl a
or
.Fl l
is specified.
.El
.Sh EXIT STATUS
The
@ -585,27 +597,32 @@ option:
.Pp
.Bl -tag -width Ds -compact
.It 0
No warnings or errors occurred, or those that did were ignored because
they were lower than the requested
No style suggestions, warnings or errors occurred, or those that
did were ignored because they were lower than the requested
.Ar level .
.It 1
At least one style suggestion occurred, but no warning or error, and
.Fl W Cm style
was specified.
.It 2
At least one warning occurred, but no error, and
.Fl W Cm warning
or
.Fl W Cm style
was specified.
.It 3
At least one parsing error occurred,
but no unsupported feature was encountered, and
.Fl W Cm error
or
.Fl W Cm warning
was specified.
or a lower
.Ar level
was requested.
.It 4
At least one unsupported feature was encountered, and
.Fl W Cm unsupp ,
.Fl W Cm error
or
.Fl W Cm warning
was specified.
.Fl W Cm unsupp
or a lower
.Ar level
was requested.
.It 5
Invalid command line arguments were specified.
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
.Fl T Cm lint
output mode implies
.Fl W Cm warning .
.Fl W Cm style .
.Sh EXAMPLES
To page manuals to the terminal:
.Pp
.Dl $ mandoc \-W all,stop mandoc.1 2\*(Gt&1 | less
.Dl $ mandoc mandoc.1 mdoc.3 mdoc.7 | less
.Dl $ mandoc -l mandoc.1 man.1 apropos.1 makewhatis.8
.Pp
To produce HTML manuals with
.Pa mandoc.css
@ -705,9 +721,22 @@ rendering can be produced.
Documents causing warnings may render poorly when using other
formatting tools instead of
.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
.Pp
Messages of the
.Cm style ,
.Cm warning ,
.Cm error ,
and
@ -718,6 +747,58 @@ are hidden unless their level, or a lower level, is requested using a
option or
.Fl T Cm lint
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
.Bl -ohang
.It Sy "missing manual title, using UNTITLED"
@ -870,6 +951,14 @@ The
.Ic \&Nd
macro lacks the required argument.
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"
.Pq mdoc
A standard section occurs after another section it usually precedes.
@ -1088,7 +1177,7 @@ or
.Ic \&Bl
.Fl offset
or
.Fl width.
.Fl width .
.It Sy "missing display type, using -ragged"
.Pq mdoc
The
@ -1310,6 +1399,12 @@ or
.Ic \&Fn
macro contains an opening or closing parenthesis; that's probably wrong,
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"
.Pq mdoc
An
@ -1657,6 +1752,11 @@ whatever mode was active before the block.
A
.Ic \&Bl
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"
.Pq mdoc
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) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: January 9 2017 $
.Dd $Mdocdate: May 17 2017 $
.Dt MANDOC 3
.Os
.Sh NAME
@ -669,11 +669,9 @@ Using badly-nested blocks is
.Em strongly discouraged ;
for example, the
.Fl T Ns Cm html
and
.Fl T Ns Cm xhtml
front-ends to
front-end to
.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
consistent across troff implementations, especially when using multiple
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) 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
* 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;
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;
*start = ++*end;
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).
*/
@ -14,6 +14,11 @@ ul, ol, dl { margin-top: 0em;
margin-bottom: 0em; }
li, dt { margin-top: 1em; }
a.selflink { border-bottom: thin dotted;
color: inherit;
font: inherit;
text-decoration: inherit; }
/* Search form and search results. */
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-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -28,7 +28,7 @@
*/
enum mandoclevel {
MANDOCLEVEL_OK = 0,
MANDOCLEVEL_RESERVED,
MANDOCLEVEL_STYLE, /* style suggestions */
MANDOCLEVEL_WARNING, /* warnings: syntax, whitespace, etc. */
MANDOCLEVEL_ERROR, /* input has been thrown away */
MANDOCLEVEL_UNSUPP, /* input needs unimplemented features */
@ -44,6 +44,14 @@ enum mandoclevel {
enum mandocerr {
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 ===== */
/* related to the prologue */
@ -71,6 +79,7 @@ enum mandocerr {
MANDOCERR_NAMESEC_BAD, /* bad NAME section content: macro */
MANDOCERR_NAMESEC_PUNCT, /* missing comma before name: Nm name */
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_REP, /* duplicate section title: Sh title */
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_NF_SKIP, /* fill mode already disabled, skipping: nf */
MANDOCERR_BLK_LINE, /* line scope broken: macro breaks macro */
MANDOCERR_BLK_BLANK, /* skipping blank line in line scope */
/* related to missing arguments */
MANDOCERR_REQ_EMPTY, /* skipping empty request: request */
@ -125,6 +135,7 @@ enum mandocerr {
MANDOCERR_AT_BAD, /* unknown AT&T UNIX version: At version */
MANDOCERR_FA_COMMA, /* comma in function argument: 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_SM_BAD, /* invalid Boolean argument: macro arg */
MANDOCERR_FT_BAD, /* unknown font, skipping request: ft font */
@ -177,6 +188,7 @@ enum mandocerr {
MANDOCERR_BD_FILE, /* NOT IMPLEMENTED: Bd -file */
MANDOCERR_BD_NOARG, /* skipping display without arguments: Bd */
MANDOCERR_BL_NOTYPE, /* missing list type, using -item: Bl */
MANDOCERR_CE_NONUM, /* argument is not numeric, using 1: ce ... */
MANDOCERR_NM_NONAME, /* missing manual name, using "": Nm */
MANDOCERR_OS_UNAME, /* uname(3) system call failed, using UNKNOWN */
MANDOCERR_ST_BAD, /* unknown standard specifier: St standard */
@ -234,9 +246,10 @@ enum tbl_cellt {
*/
struct tbl_cell {
struct tbl_cell *next;
char *wstr; /* min width represented as a string */
size_t width; /* minimum column width */
size_t spacing; /* to the right of the column */
int vert; /* width of subsequent vertical line */
enum tbl_cellt pos;
size_t spacing;
int col; /* column number, starting from 0 */
int flags;
#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_WIGN (1 << 6) /* z, Z */
#define TBL_CELL_WMAX (1 << 7) /* x, X */
enum tbl_cellt pos;
};
/*
@ -274,9 +288,10 @@ enum tbl_datt {
*/
struct tbl_dat {
struct tbl_cell *layout; /* layout cell */
int spans; /* how many spans follow */
struct tbl_dat *next;
char *string; /* data (NULL if not TBL_DATA_DATA) */
int spans; /* how many spans follow */
int block; /* T{ text block T} */
enum tbl_datt pos;
};
@ -404,6 +419,8 @@ enum mandoc_esc {
ESCAPE_NUMBERED, /* a numbered glyph */
ESCAPE_UNICODE, /* a unicode codepoint */
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_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) 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
.\" purpose with or without fee is hereby granted, provided that the above
@ -16,7 +16,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: February 5 2017 $
.Dd $Mdocdate: June 2 2017 $
.Dt MANDOC_CHAR 7
.Os
.Sh NAME
@ -169,6 +169,8 @@ even on request and macro lines.
.Ss Accents
In output modes supporting such special output characters, for example
.Fl T Cm pdf ,
and sometimes less consistently in
.Fl T Cm utf8 ,
some
.Xr roff 7
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 \(aq Ta U+2019 Ta right single quotation mark
.It \(ti Ta U+02DC Ta small tilde
.It \(ha Ta U+02C6 Ta modifier letter circumflex
.El
.Pp
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(aq Ta U+0027 Ta apostrophe
.It \e(ti Ta U+007E Ta tilde
.It \e(ha Ta U+005E Ta circumflex accent
.El
.Ss Periods
The period
@ -279,6 +283,10 @@ Text markers:
.It \e(sh Ta \(sh Ta hash (pound)
.It \e(CR Ta \(CR Ta carriage return
.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
.Pp
Legal symbols:
@ -372,6 +380,7 @@ Arrows:
.It \e(uA Ta \(uA Ta up double-arrow
.It \e(dA Ta \(dA Ta down double-arrow
.It \e(vA Ta \(vA Ta up-down double-arrow
.It \e(an Ta \(an Ta horizontal arrow extension
.El
.Pp
Logical:
@ -450,11 +459,20 @@ Mathematical:
.It \e(Ah Ta \(Ah Ta aleph
.It \e(Im Ta \(Im Ta imaginary
.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(-h Ta \(-h Ta Planck constant over 2\(*p
.It \e[12] Ta \[12] Ta one-half
.It \e[14] Ta \[14] Ta one-fourth
.It \e[34] Ta \[34] Ta three-fourths
.It \e[hbar] Ta \[hbar] Ta Planck constant over 2\(*p
.It \e(12 Ta \(12 Ta one-half
.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
.Pp
Ligatures:
@ -588,6 +606,8 @@ Units:
.It \e(fm Ta \(fm Ta minute
.It \e(sd Ta \(sd Ta second
.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
.Pp
Greek letters:
@ -748,9 +768,7 @@ the
differently between mandoc and groff.
.It
In
.Fl T Ns Cm html
and
.Fl T Ns Cm xhtml ,
.Fl T Ns Cm html ,
the \e(\(ti=, \e(nb, and \e(nc special characters render differently
between mandoc and groff.
.It

View File

@ -60,9 +60,19 @@ Requires
.In sys/types.h
for
.Vt size_t .
.Pp
Provides the utility functions documented in
.Xr mandoc_malloc 3 .
.It Qq Pa mandoc_ohash.h
Requires
.In stddef.h
for
.Vt ptrdiff_t
and
.In stdint.h
for
.Vt uint32_t .
.Pp
Includes
.In ohash.h
and provides
@ -113,17 +123,30 @@ from
.Pa roff.h
as an opaque type for function prototypes.
.It Qq Pa roff.h
Requires
.Qq Pa mandoc_ohash.h
for
.Vt struct ohash .
.Pp
Provides
.Vt enum mdoc_endbody ,
.Vt enum roff_macroset ,
.Vt enum roff_next ,
.Vt enum roff_sec ,
.Vt enum roff_tok ,
.Vt enum roff_type ,
.Vt struct roff_man ,
.Vt struct roff_meta ,
.Vt struct roff_node ,
and the function
.Fn deroff .
the constant array
.Va roff_name
and the functions
.Fn deroff ,
.Fn roffhash_alloc ,
.Fn roffhash_find ,
.Fn roffhash_free ,
and
.Fn roff_validate .
.Pp
Uses pointers to the types
.Vt struct mdoc_arg
@ -198,9 +221,10 @@ or
.El
.Ss Parser internals
The following headers require inclusion of a parser interface header
before they can be included. All parser interface headers should
precede all parser internal headers. When any parser internal headers
are included, the same file should not include any formatter headers.
before they can be included.
All parser interface headers should precede all parser internal headers.
When any parser internal headers are included, the same file should
not include any formatter headers.
.Bl -tag -width Ds
.It Qq Pa libmandoc.h
Requires
@ -271,6 +295,10 @@ from
as opaque types for function prototypes.
.It Qq Pa libmdoc.h
Requires
.Qq Pa roff.h
for
.Vt enum roff_tok
and
.Qq Pa mdoc.h
for
.Vt enum mdoc_*
@ -303,6 +331,11 @@ When this header is included, the same file should not include
or
.Pa libroff.h .
.It Qq Pa libman.h
Requires
.Qq Pa roff.h
for
.Vt enum roff_tok .
.Pp
Provides
.Vt struct man_macro
and some functions internal to the
@ -405,6 +438,7 @@ Provides
.Vt enum termtype ,
.Vt struct termp_tbl ,
.Vt struct termp ,
.Fn roff_term_pre ,
and many terminal formatting functions.
.Pp
Uses the opaque type
@ -419,6 +453,8 @@ from
.Pa mandoc.h
and
.Vt struct roff_meta
and
.Vt struct roff_node
from
.Pa roff.h
as opaque types for function prototypes.
@ -431,10 +467,7 @@ or
Requires
.In sys/types.h
for
.Vt size_t ,
.In stdio.h
for
.Dv BUFSIZ ,
.Vt size_t
and
.Qq Pa out.h
for
@ -450,8 +483,21 @@ Provides
.Vt struct tagq ,
.Vt struct htmlpair ,
.Vt struct html ,
.Fn roff_html_pre ,
and many HTML formatting functions.
.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
.Pa term.h
or
@ -506,8 +552,7 @@ Provides
.Vt struct manpage ,
.Vt struct mansearch ,
and the functions
.Fn mansearch_setup ,
.Fn mansearch ,
.Fn mansearch
and
.Fn mansearch_free .
.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>
.\"
@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: January 28 2017 $
.Dd $Mdocdate: May 12 2017 $
.Dt MANDOC_HTML 3
.Os
.Sh NAME
@ -48,6 +48,14 @@
.Fa "struct html *h"
.Fa "const char *word"
.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
The mandoc HTML formatter is not a formal library.
However, as it is compiled into more than one program, in particular
@ -145,6 +153,11 @@ the respective attribute is not written.
Print a
.Cm class
attribute.
This attribute letter can optionally be followed by the modifier letter
.Cm T .
In that case, a
.Cm title
attribute with the same value is also printed.
.It Cm h
Print a
.Cm href
@ -191,7 +204,7 @@ Instead, the rest of the format string consists of pairs of
argument type letters and style name letters.
.El
.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
.It Cm h
Requires one
@ -220,10 +233,18 @@ width specifier.
If the argument is
.Dv NULL ,
nothing is printed for this pair.
.It Cm W
Similar to
.Cm w ,
but makes the width negative by multiplying it with \(mi1.
.Pp
The
.Cm w
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
.Pp
Style name letters decide what to do with the preceding argument:
@ -301,8 +322,27 @@ and
.Fn print_tagq
functions.
.Pp
The function
.Fn html_make_id
takes a node containing one or more text children
and returns a newly allocated string containing the concatenation
of the child strings, with blanks replaced by underscores.
If the node
.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
.Fn html_strlen ,
.Fn print_eqn ,
.Fn print_tbl ,
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>
.\"
@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: February 6 2017 $
.Dd $Mdocdate: March 18 2017 $
.Dt MANDOCD 8
.Os
.Sh NAME
@ -85,7 +85,7 @@ Override the default operating system
.Ar name
for the
.Xr mdoc 7
.Ic Os
.Ic \&Os
and for the
.Xr man 7
.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-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 uint64_t name_mask;
static const struct mdoc_handler mdocs[MDOC_MAX] = {
{ NULL, 0, 0 }, /* Ap */
static const struct mdoc_handler __mdocs[MDOC_MAX - MDOC_Dd] = {
{ NULL, 0, NODE_NOPRT }, /* Dd */
{ NULL, 0, NODE_NOPRT }, /* Dt */
{ NULL, 0, NODE_NOPRT }, /* Os */
@ -200,6 +199,7 @@ static const struct mdoc_handler mdocs[MDOC_MAX] = {
{ NULL, 0, 0 }, /* It */
{ NULL, 0, 0 }, /* Ad */
{ NULL, TYPE_An, 0 }, /* An */
{ NULL, 0, 0 }, /* Ap */
{ NULL, TYPE_Ar, 0 }, /* Ar */
{ NULL, TYPE_Cd, 0 }, /* Cd */
{ NULL, TYPE_Cm, 0 }, /* Cm */
@ -302,12 +302,10 @@ static const struct mdoc_handler mdocs[MDOC_MAX] = {
{ NULL, 0, 0 }, /* En */
{ NULL, TYPE_Dx, NODE_NOSRC }, /* Dx */
{ NULL, 0, 0 }, /* %Q */
{ NULL, 0, 0 }, /* br */
{ NULL, 0, 0 }, /* sp */
{ NULL, 0, 0 }, /* %U */
{ NULL, 0, 0 }, /* Ta */
{ NULL, 0, 0 }, /* ll */
};
static const struct mdoc_handler *const mdocs = __mdocs - MDOC_Dd;
int
@ -1211,7 +1209,7 @@ mpages_merge(struct dba *dba, struct mparse *mp)
} else if (man != NULL && man->macroset == MACROSET_MAN) {
man_validate(man);
if (*man->meta.msec != '\0' ||
*man->meta.msec != '\0') {
*man->meta.title != '\0') {
mpage->form = FORM_SRC;
mpage->sec = mandoc_strdup(man->meta.msec);
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)
{
assert(NULL != n);
for (n = n->child; NULL != n; n = n->next) {
if (n->flags & mdocs[n->tok].taboo)
for (n = n->child; n != NULL; n = n->next) {
if (n->tok == TOKEN_NONE ||
n->tok < ROFF_MAX ||
n->flags & mdocs[n->tok].taboo)
continue;
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
switch (n->type) {
case ROFFT_ELEM:
case ROFFT_BLOCK:
case ROFFT_HEAD:
case ROFFT_BODY:
case ROFFT_TAIL:
if (NULL != mdocs[n->tok].fp)
if (0 == (*mdocs[n->tok].fp)(mpage, meta, n))
break;
if (mdocs[n->tok].fp != NULL &&
(*mdocs[n->tok].fp)(mpage, meta, n) == 0)
break;
if (mdocs[n->tok].mask)
putmdockey(mpage, n->child,
mdocs[n->tok].mask, mdocs[n->tok].taboo);
break;
default:
assert(n->type != ROFFT_ROOT);
continue;
}
if (NULL != n->child)
@ -2123,6 +2122,23 @@ dbwrite(struct dba *dba)
int status;
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 (rename(MANDOC_DB "~", MANDOC_DB) == -1) {
exitcode = (int)MANDOCLEVEL_SYSERR;
@ -2132,6 +2148,11 @@ dbwrite(struct dba *dba)
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));
if (mkdtemp(tfn) == NULL) {
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>
.\"
@ -14,28 +14,22 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: March 27 2015 $
.Dd $Mdocdate: March 30 2017 $
.Dt MANSEARCH 3
.Os
.Sh NAME
.Nm mansearch ,
.Nm mansearch_setup
.Nm mansearch
.Nd search manual page databases
.Sh SYNOPSIS
.In stdint.h
.In manconf.h
.In mansearch.h
.Ft int
.Fo mansearch_setup
.Fa "int start"
.Fc
.Ft int
.Fo mansearch
.Fa "const struct mansearch *search"
.Fa "const struct manpaths *paths"
.Fa "int argc"
.Fa "char *argv[]"
.Fa "const char *outkey"
.Fa "struct manpage **res"
.Fa "size_t *sz"
.Fc
@ -44,7 +38,7 @@ The
.Fn mansearch
function returns information about manuals matching a search query from a
.Xr mandoc.db 5
SQLite3 database.
database.
.Pp
The query arguments are as follows:
.Bl -tag -width Ds
@ -58,18 +52,6 @@ Directories to be searched, defined in
Search criteria, usually taken from the command line.
.El
.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:
.Bl -tag -width Ds
.It Fa "struct manpage **res"
@ -89,19 +71,6 @@ array itself.
Returns the number of result structures contained in
.Fa res .
.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
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.
@ -112,103 +81,26 @@ array.
.Pp
All function mentioned here are defined in the file
.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
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
.Fn exprcomp
building a singly linked list of
.Vt expr
structures, using the helper functions
.Fn exprterm
.Fn expr_and
and
.Fn exprspec .
The resulting SQL statement is assembled by the function
.Fn sql_statement
and evaluated in the main loop of the
.Fn mansearch
function.
.Fn exprterm .
.Ss Assembling the results
The names, sections, and architectures of the manuals found
are assembled into the
.Va names
field of the result structure by the function
.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 & ?"
.Fn buildnames .
.Sh FILES
.Bl -tag -width mandoc.db -compact
.It Pa mandoc.db
The manual page database.
.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
.Xr apropos 1 ,
.Xr mandoc.db 5 ,
@ -223,6 +115,6 @@ subsystem first appeared in
A module to search manual page databases was first written by
.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
in 2011, at first using the Berkeley DB;
he rewrote it for SQLite3 in 2012.
The current version received major changes from
.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
he rewrote it for SQLite3 in 2012, and
.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 $ */
/*
* 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
* 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_and(struct expr *, struct ohash *);
static char *buildnames(const struct dbm_page *);
static char *buildoutput(size_t, int32_t);
static size_t lstlen(const char *);
static void lstcat(char *, size_t *, const char *);
static char *buildoutput(size_t, struct dbm_page *);
static size_t lstlen(const char *, size_t);
static void lstcat(char *, size_t *, const char *, const char *);
static int lstmatch(const char *, const char *);
static struct expr *exprcomp(const struct mansearch *,
int, char *[], int *);
@ -155,7 +155,8 @@ mansearch(const struct mansearch *search,
chdir_status = 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;
}
@ -181,9 +182,7 @@ mansearch(const struct mansearch *search,
mandoc_asprintf(&mpage->file, "%s/%s",
paths->paths[i], page->file + 1);
mpage->names = buildnames(page);
mpage->output = (int)outkey == KEY_Nd ?
mandoc_strdup(page->desc) :
buildoutput(outkey, page->addr);
mpage->output = buildoutput(outkey, page);
mpage->ipath = i;
mpage->bits = rp->bits;
mpage->sec = *page->sect - '0';
@ -404,16 +403,16 @@ buildnames(const struct dbm_page *page)
char *buf;
size_t i, sz;
sz = lstlen(page->name) + 1 + lstlen(page->sect) +
(page->arch == NULL ? 0 : 1 + lstlen(page->arch)) + 2;
sz = lstlen(page->name, 2) + 1 + lstlen(page->sect, 2) +
(page->arch == NULL ? 0 : 1 + lstlen(page->arch, 2)) + 2;
buf = mandoc_malloc(sz);
i = 0;
lstcat(buf, &i, page->name);
lstcat(buf, &i, page->name, ", ");
buf[i++] = '(';
lstcat(buf, &i, page->sect);
lstcat(buf, &i, page->sect, ", ");
if (page->arch != NULL) {
buf[i++] = '/';
lstcat(buf, &i, page->arch);
lstcat(buf, &i, page->arch, ", ");
}
buf[i++] = ')';
buf[i++] = '\0';
@ -423,11 +422,11 @@ buildnames(const struct dbm_page *page)
/*
* 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.
*/
static size_t
lstlen(const char *cp)
lstlen(const char *cp, size_t sep)
{
size_t sz;
@ -435,7 +434,7 @@ lstlen(const char *cp)
if (cp[0] == '\0') {
if (cp[1] == '\0')
break;
sz++;
sz += sep - 1;
} else if (cp[0] < ' ')
sz--;
cp++;
@ -445,17 +444,20 @@ lstlen(const char *cp)
/*
* 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
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 (;;) {
if (cp[0] == '\0') {
if (cp[1] == '\0')
break;
buf[(*i)++] = ',';
buf[(*i)++] = ' ';
s = sep;
while (*s != '\0')
buf[(*i)++] = *s++;
} else if (cp[0] >= ' ')
buf[(*i)++] = cp[0];
cp++;
@ -482,17 +484,46 @@ lstmatch(const char *want, const char *have)
}
/*
* Build a list of values taken by the macro im
* in the manual page with big-endian address addr.
* Build a list of values taken by the macro im in the manual page.
*/
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;
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;
dbm_macro_bypage(im - 2, addr);
dbm_macro_bypage(im - 2, page->addr);
while ((value = dbm_macro_next()) != NULL) {
if (output == NULL) {
oldoutput = "";
@ -642,6 +673,12 @@ exprterm(const struct mansearch *search, int argc, char *argv[], int *argi)
return e;
}
if (strcmp("-i", argv[*argi]) == 0 && *argi + 1 < argc) {
cs = 0;
++*argi;
} else
cs = 1;
e = mandoc_calloc(1, sizeof(*e));
e->type = EXPR_TERM;
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) 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
* purpose with or without fee is hereby granted, provided that the above
@ -21,6 +21,9 @@
#define MANDOCDB_VERSION 1
#define MACRO_MAX 36
#define KEY_arch 0
#define KEY_sec 1
#define KEY_Nm 38
#define KEY_Nd 39
#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) 2010, 2011, 2013-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: February 16 2017 $
.Dd $Mdocdate: May 5 2017 $
.Dt MDOC 7
.Os
.Sh NAME
@ -476,8 +476,6 @@ in the alphabetical
.It Sx \&Ap Ta apostrophe without surrounding whitespace (no arguments)
.It Sx \&Sm Ta switch horizontal spacing mode: Op Cm on | off
.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
.Ss Semantic markup for command line utilities:
.Bl -column "Brq, Bro, Brc" description
@ -2736,29 +2734,6 @@ Examples:
.Dl \&.Xr mandoc 1
.Dl \&.Xr mandoc 1 \&;
.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
The syntax of a macro depends on its classification.
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 \&Vt Ta Yes Ta Yes Ta >0
.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
.Ss Delimiters
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) 2010, 2012-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -35,41 +35,6 @@
#include "roff_int.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] = {
"split", "nosplit", "ragged",
"unfilled", "literal", "file",
@ -80,9 +45,7 @@ const char *const __mdoc_argnames[MDOC_ARG_MAX] = {
"width", "compact", "std",
"filled", "words", "emphasis",
"symbolic", "nested", "centered"
};
const char * const *mdoc_macronames = __mdoc_macronames + 1;
};
const char * const *mdoc_argnames = __mdoc_argnames;
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
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);
}
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;
@ -135,8 +97,8 @@ mdoc_tail_alloc(struct roff_man *mdoc, int line, int pos, int tok)
}
struct roff_node *
mdoc_endbody_alloc(struct roff_man *mdoc, int line, int pos, int tok,
struct roff_node *body)
mdoc_endbody_alloc(struct roff_man *mdoc, int line, int pos,
enum roff_tok tok, struct roff_node *body)
{
struct roff_node *p;
@ -153,7 +115,7 @@ mdoc_endbody_alloc(struct roff_man *mdoc, int line, int pos, int tok,
struct roff_node *
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;
@ -180,7 +142,7 @@ mdoc_block_alloc(struct roff_man *mdoc, int line, int pos,
void
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;
@ -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
* 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->next = ROFF_NEXT_SIBLING;
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, '.')) {
if (c - buf < offs + 2)
continue;
if (end - c < 4)
if (end - c < 3)
break;
if (isalpha((unsigned char)c[-2]) &&
isalpha((unsigned char)c[-1]) &&
c[1] == ' ' &&
isupper((unsigned char)(c[2] == ' ' ? c[3] : c[2])) &&
(c[-2] != 'n' || c[-1] != 'c') &&
(c[-2] != 'v' || c[-1] != 's'))
if (c[1] != ' ' ||
isalpha((unsigned char)c[-2]) == 0 ||
isalpha((unsigned char)c[-1]) == 0 ||
(c[-2] == 'n' && c[-1] == 'c') ||
(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,
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;
const char *cp;
int tok;
int i, sv;
char mac[5];
size_t sz;
enum roff_tok tok;
int sv;
/* Determine the line macro. */
sv = offs;
/*
* Copy the first word into a nil-terminated buffer.
* Stop when a space, tab, escape, or eoln is encountered.
*/
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;
tok = TOKEN_NONE;
for (sz = 0; sz < 4 && strchr(" \t\\", buf[offs]) == NULL; sz++)
offs++;
if (sz == 2 || sz == 3)
tok = roffhash_find(mdoc->mdocmac, buf + sv, sz);
if (tok == TOKEN_NONE) {
mandoc_msg(MANDOCERR_MACRO, mdoc->parse,
ln, sv, buf + sv - 1);
@ -382,7 +343,7 @@ mdoc_pmacro(struct roff_man *mdoc, int ln, char *buf, int offs)
/* Jump to the next non-whitespace word. */
while (buf[offs] && ' ' == buf[offs])
while (buf[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) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -16,131 +16,6 @@
* 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 {
MDOC_Split, /* -split */
MDOC_Nosplit, /* -nospli */
@ -274,11 +149,7 @@ union mdoc_data {
struct mdoc_rs Rs;
};
/* Names of macros. */
extern const char *const *mdoc_macronames;
/* Names of macro args. Index is enum mdocargt. */
extern const char *const *mdoc_argnames;
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) 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
* 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
};
static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_DELIM, NULL }, /* Ap */
static const struct mdocarg __mdocargs[MDOC_MAX - MDOC_Dd] = {
{ ARGSFL_NONE, NULL }, /* Dd */
{ ARGSFL_NONE, NULL }, /* Dt */
{ ARGSFL_NONE, NULL }, /* Os */
@ -161,6 +160,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_NONE, NULL }, /* It */
{ ARGSFL_DELIM, NULL }, /* Ad */
{ ARGSFL_DELIM, args_An }, /* An */
{ ARGSFL_DELIM, NULL }, /* Ap */
{ ARGSFL_DELIM, NULL }, /* Ar */
{ ARGSFL_DELIM, NULL }, /* Cd */
{ ARGSFL_DELIM, NULL }, /* Cm */
@ -263,12 +263,10 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_DELIM, NULL }, /* En */
{ ARGSFL_DELIM, NULL }, /* Dx */
{ ARGSFL_NONE, NULL }, /* %Q */
{ ARGSFL_NONE, NULL }, /* br */
{ ARGSFL_NONE, NULL }, /* sp */
{ ARGSFL_NONE, NULL }, /* %U */
{ 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.
*/
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_argv tmpv;
@ -291,6 +289,7 @@ mdoc_argv(struct roff_man *mdoc, int line, int tok,
/* Which flags does this macro support? */
assert(tok >= MDOC_Dd && tok < MDOC_MAX);
argtable = mdocargs[tok].argvs;
if (argtable == NULL)
return;
@ -415,7 +414,7 @@ argn_free(struct mdoc_arg *p, int iarg)
enum margserr
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;
char *v_local;
@ -424,8 +423,6 @@ mdoc_args(struct roff_man *mdoc, int line, int *pos,
if (v == NULL)
v = &v_local;
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
@ -434,12 +431,15 @@ mdoc_args(struct roff_man *mdoc, int line, int *pos,
* safe fall-back into the default behaviour.
*/
for (n = mdoc->last; n; n = n->parent)
if (MDOC_Bl == n->tok)
if (LIST_column == n->norm->Bl.type) {
if (tok == MDOC_It) {
for (n = mdoc->last; n != NULL; n = n->parent) {
if (n->tok != MDOC_Bl)
continue;
if (n->norm->Bl.type == LIST_column)
fl = ARGSFL_TABSEP;
break;
}
break;
}
}
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))
mandoc_msg(MANDOCERR_ARG_QUOTE,
mdoc->parse, line, *pos, NULL);
return ARGS_QWORD;
return ARGS_WORD;
}
mdoc->flags &= ~MDOC_PHRASELIT;
buf[(*pos)++] = '\0';
if ('\0' == buf[*pos])
return ARGS_QWORD;
return ARGS_WORD;
while (' ' == buf[*pos])
(*pos)++;
@ -571,7 +571,7 @@ args(struct roff_man *mdoc, int line, int *pos,
mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
line, *pos, NULL);
return ARGS_QWORD;
return ARGS_WORD;
}
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) 2014, 2015, 2016, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -48,7 +48,7 @@ struct htmlmdoc {
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_node(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_skip_pre(MDOC_ARGS);
static int mdoc_sm_pre(MDOC_ARGS);
static int mdoc_sp_pre(MDOC_ARGS);
static int mdoc_ss_pre(MDOC_ARGS);
static int mdoc_st_pre(MDOC_ARGS);
static int mdoc_sx_pre(MDOC_ARGS);
@ -118,8 +117,7 @@ static int mdoc_vt_pre(MDOC_ARGS);
static int mdoc_xr_pre(MDOC_ARGS);
static int mdoc_xx_pre(MDOC_ARGS);
static const struct htmlmdoc mdocs[MDOC_MAX] = {
{mdoc_ap_pre, NULL}, /* Ap */
static const struct htmlmdoc __mdocs[MDOC_MAX - MDOC_Dd] = {
{NULL, NULL}, /* Dd */
{NULL, NULL}, /* Dt */
{NULL, NULL}, /* Os */
@ -135,6 +133,7 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = {
{mdoc_it_pre, NULL}, /* It */
{mdoc_ad_pre, NULL}, /* Ad */
{mdoc_an_pre, NULL}, /* An */
{mdoc_ap_pre, NULL}, /* Ap */
{mdoc_ar_pre, NULL}, /* Ar */
{mdoc_cd_pre, NULL}, /* Cd */
{mdoc_cm_pre, NULL}, /* Cm */
@ -237,12 +236,10 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = {
{mdoc_quote_pre, mdoc_quote_post}, /* En */
{mdoc_xx_pre, NULL}, /* Dx */
{mdoc__x_pre, mdoc__x_post}, /* %Q */
{mdoc_sp_pre, NULL}, /* br */
{mdoc_sp_pre, NULL}, /* sp */
{mdoc__x_pre, mdoc__x_post}, /* %U */
{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
* (i.e., within a <PRE>) don't print the newline.
*/
if (' ' == *n->string && NODE_LINE & n->flags)
if ( ! (HTML_LITERAL & h->flags))
print_otag(h, TAG_BR, "");
if (*n->string == ' ' && n->flags & NODE_LINE &&
(h->flags & (HTML_LITERAL | HTML_NONEWLINE)) == 0)
print_otag(h, TAG_BR, "");
if (NODE_DELIMC & n->flags)
h->flags |= HTML_NOSPACE;
print_text(h, n->string);
@ -393,7 +390,14 @@ print_mdoc_node(MDOC_ARGS)
t = h->tag;
}
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);
break;
}
@ -412,7 +416,9 @@ print_mdoc_node(MDOC_ARGS)
case ROFFT_EQN:
break;
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;
(*mdocs[n->tok].post)(meta, n, h);
if (n->end != ENDBODY_NOT)
@ -477,25 +483,19 @@ mdoc_root_pre(MDOC_ARGS)
}
static char *
make_id(const struct roff_node *n)
cond_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;
if (n->child != NULL &&
n->child->type == ROFFT_TEXT &&
(n->prev == NULL ||
(n->prev->type == ROFFT_TEXT &&
strcmp(n->prev->string, "|") == 0)) &&
(n->parent->tok == MDOC_It ||
(n->parent->tok == MDOC_Xo &&
n->parent->parent->prev == NULL &&
n->parent->parent->parent->tok == MDOC_It)))
return html_make_id(n);
return NULL;
}
static int
@ -505,8 +505,10 @@ mdoc_sh_pre(MDOC_ARGS)
switch (n->type) {
case ROFFT_HEAD:
id = make_id(n);
print_otag(h, TAG_H1, "ci", "Sh", id);
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);
break;
case ROFFT_BODY:
@ -527,8 +529,10 @@ mdoc_ss_pre(MDOC_ARGS)
if (n->type != ROFFT_HEAD)
return 1;
id = make_id(n);
print_otag(h, TAG_H2, "ci", "Ss", id);
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;
}
@ -536,9 +540,14 @@ mdoc_ss_pre(MDOC_ARGS)
static int
mdoc_fl_pre(MDOC_ARGS)
{
print_otag(h, TAG_B, "c", "Fl");
print_text(h, "\\-");
char *id;
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 &&
(n->next == NULL ||
n->next->type == ROFFT_TEXT ||
@ -551,7 +560,12 @@ mdoc_fl_pre(MDOC_ARGS)
static int
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;
}
@ -564,22 +578,19 @@ mdoc_nd_pre(MDOC_ARGS)
/* XXX: this tag in theory can contain block elements. */
print_text(h, "\\(em");
print_otag(h, TAG_SPAN, "c", "Nd");
print_otag(h, TAG_SPAN, "cT", "Nd");
return 1;
}
static int
mdoc_nm_pre(MDOC_ARGS)
{
struct tag *t;
int len;
switch (n->type) {
case ROFFT_HEAD:
print_otag(h, TAG_TD, "");
/* FALLTHROUGH */
case ROFFT_ELEM:
print_otag(h, TAG_B, "c", "Nm");
print_otag(h, TAG_B, "cT", "Nm");
return 1;
case ROFFT_BODY:
print_otag(h, TAG_TD, "");
@ -587,21 +598,8 @@ mdoc_nm_pre(MDOC_ARGS)
default:
break;
}
synopsis_pre(h, n);
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, "");
return 1;
}
@ -613,11 +611,11 @@ mdoc_xr_pre(MDOC_ARGS)
return 0;
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 ?
NULL : n->child->next->string);
else
print_otag(h, TAG_A, "c", "Xr");
print_otag(h, TAG_A, "cT", "Xr");
n = n->child;
print_text(h, n->string);
@ -646,7 +644,7 @@ mdoc_ns_pre(MDOC_ARGS)
static int
mdoc_ar_pre(MDOC_ARGS)
{
print_otag(h, TAG_VAR, "c", "Ar");
print_otag(h, TAG_VAR, "cT", "Ar");
return 1;
}
@ -666,7 +664,7 @@ mdoc_it_pre(MDOC_ARGS)
enum mdoc_list type;
bl = n->parent;
while (bl != NULL && bl->tok != MDOC_Bl)
while (bl->tok != MDOC_Bl)
bl = bl->parent;
type = bl->norm->Bl.type;
@ -751,8 +749,9 @@ mdoc_it_pre(MDOC_ARGS)
case ROFFT_HEAD:
if (h->style != NULL && !bl->norm->Bl.comp &&
(n->parent->prev == NULL ||
n->parent->prev->body == NULL ||
n->parent->prev->body->child != NULL)) {
t = print_otag(h, TAG_DT, "csWl",
t = print_otag(h, TAG_DT, "csw+-l",
cattr, bl->norm->Bl.width);
print_text(h, "\\ ");
print_tagq(h, t);
@ -760,7 +759,7 @@ mdoc_it_pre(MDOC_ARGS)
print_text(h, "\\ ");
print_tagq(h, t);
}
print_otag(h, TAG_DT, "csWl", cattr,
print_otag(h, TAG_DT, "csw+-l", cattr,
bl->norm->Bl.width);
break;
case ROFFT_BODY:
@ -823,7 +822,7 @@ mdoc_bl_pre(MDOC_ARGS)
t = print_otag(h, TAG_COLGROUP, "");
for (i = 0; i < bl->ncols - 1; i++)
print_otag(h, TAG_COL, "sww", bl->cols[i]);
print_otag(h, TAG_COL, "sw+w", bl->cols[i]);
print_otag(h, TAG_COL, "swW", bl->cols[i]);
print_tagq(h, t);
return 0;
@ -870,7 +869,7 @@ mdoc_bl_pre(MDOC_ARGS)
cattr = "Bl-tag";
if (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;
case LIST_column:
elemtype = TAG_TABLE;
@ -894,14 +893,14 @@ mdoc_ex_pre(MDOC_ARGS)
static int
mdoc_st_pre(MDOC_ARGS)
{
print_otag(h, TAG_SPAN, "c", "St");
print_otag(h, TAG_SPAN, "cT", "St");
return 1;
}
static int
mdoc_em_pre(MDOC_ARGS)
{
print_otag(h, TAG_I, "c", "Em");
print_otag(h, TAG_I, "cT", "Em");
return 1;
}
@ -924,8 +923,8 @@ mdoc_sx_pre(MDOC_ARGS)
{
char *id;
id = make_id(n);
print_otag(h, TAG_A, "chR", "Sx", id);
id = html_make_id(n);
print_otag(h, TAG_A, "cThR", "Sx", id);
free(id);
return 1;
}
@ -991,9 +990,9 @@ mdoc_bd_pre(MDOC_ARGS)
* anyway, so don't sweat it.
*/
switch (nn->tok) {
case ROFF_br:
case ROFF_sp:
case MDOC_Sm:
case MDOC_br:
case MDOC_sp:
case MDOC_Bl:
case MDOC_D1:
case MDOC_Dl:
@ -1021,7 +1020,7 @@ mdoc_bd_pre(MDOC_ARGS)
static int
mdoc_pa_pre(MDOC_ARGS)
{
print_otag(h, TAG_I, "c", "Pa");
print_otag(h, TAG_I, "cT", "Pa");
return 1;
}
@ -1052,7 +1051,7 @@ mdoc_an_pre(MDOC_ARGS)
if (n->sec == SEC_AUTHORS && ! (h->flags & HTML_NOSPLIT))
h->flags |= HTML_SPLIT;
print_otag(h, TAG_SPAN, "c", "An");
print_otag(h, TAG_SPAN, "cT", "An");
return 1;
}
@ -1060,28 +1059,49 @@ static int
mdoc_cd_pre(MDOC_ARGS)
{
synopsis_pre(h, n);
print_otag(h, TAG_B, "c", "Cd");
print_otag(h, TAG_B, "cT", "Cd");
return 1;
}
static int
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;
}
static int
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;
}
static int
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;
}
@ -1092,12 +1112,12 @@ mdoc_fa_pre(MDOC_ARGS)
struct tag *t;
if (n->parent->tok != MDOC_Fo) {
print_otag(h, TAG_VAR, "c", "Fa");
print_otag(h, TAG_VAR, "cT", "Fa");
return 1;
}
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_tagq(h, t);
if (nn->next) {
@ -1128,11 +1148,11 @@ mdoc_fd_pre(MDOC_ARGS)
assert(n->type == ROFFT_TEXT);
if (strcmp(n->string, "#include")) {
print_otag(h, TAG_B, "c", "Fd");
print_otag(h, TAG_B, "cT", "Fd");
return 1;
}
print_otag(h, TAG_B, "c", "In");
print_otag(h, TAG_B, "cT", "In");
print_text(h, n->string);
if (NULL != (n = n->next)) {
@ -1146,10 +1166,10 @@ mdoc_fd_pre(MDOC_ARGS)
cp = strchr(buf, '\0') - 1;
if (cp >= buf && (*cp == '>' || *cp == '"'))
*cp = '\0';
t = print_otag(h, TAG_A, "chI", "In", buf);
t = print_otag(h, TAG_A, "cThI", "In", buf);
free(buf);
} else
t = print_otag(h, TAG_A, "c", "In");
t = print_otag(h, TAG_A, "cT", "In");
print_text(h, n->string);
print_tagq(h, t);
@ -1176,7 +1196,7 @@ mdoc_vt_pre(MDOC_ARGS)
} else if (n->type == ROFFT_HEAD)
return 0;
print_otag(h, TAG_VAR, "c", "Vt");
print_otag(h, TAG_VAR, "cT", "Vt");
return 1;
}
@ -1184,7 +1204,7 @@ static int
mdoc_ft_pre(MDOC_ARGS)
{
synopsis_pre(h, n);
print_otag(h, TAG_VAR, "c", "Ft");
print_otag(h, TAG_VAR, "cT", "Ft");
return 1;
}
@ -1205,7 +1225,7 @@ mdoc_fn_pre(MDOC_ARGS)
ep = strchr(sp, ' ');
if (NULL != ep) {
t = print_otag(h, TAG_VAR, "c", "Ft");
t = print_otag(h, TAG_VAR, "cT", "Ft");
while (ep) {
sz = MIN((int)(ep - sp), BUFSIZ - 1);
@ -1218,7 +1238,7 @@ mdoc_fn_pre(MDOC_ARGS)
print_tagq(h, t);
}
t = print_otag(h, TAG_B, "c", "Fn");
t = print_otag(h, TAG_B, "cT", "Fn");
if (sp)
print_text(h, sp);
@ -1231,10 +1251,10 @@ mdoc_fn_pre(MDOC_ARGS)
for (n = n->child->next; n; n = n->next) {
if (NODE_SYNPRETTY & n->flags)
t = print_otag(h, TAG_VAR, "css?", "Fa",
t = print_otag(h, TAG_VAR, "cTss?", "Fa",
"white-space", "nowrap");
else
t = print_otag(h, TAG_VAR, "c", "Fa");
t = print_otag(h, TAG_VAR, "cT", "Fa");
print_text(h, n->string);
print_tagq(h, t);
if (n->next) {
@ -1286,48 +1306,36 @@ mdoc_pp_pre(MDOC_ARGS)
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
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;
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);
if (NULL == n->next)
print_text(h, n->string);
for (n = n->next; n; n = n->next)
print_text(h, n->string);
/* Link target and link text. */
t = print_otag(h, TAG_A, "cTh", "Lk", link->string);
for (descr = link->next; descr != punct; descr = descr->next) {
if (descr->flags & (NODE_DELIMC | NODE_DELIMO))
h->flags |= HTML_NOSPACE;
print_text(h, descr->string);
}
print_tagq(h, t);
/* Trailing punctuation. */
while (punct != NULL) {
h->flags |= HTML_NOSPACE;
print_text(h, punct->string);
punct = punct->next;
}
return 0;
}
@ -1341,7 +1349,7 @@ mdoc_mt_pre(MDOC_ARGS)
assert(n->type == ROFFT_TEXT);
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_tagq(h, t);
free(cp);
@ -1369,7 +1377,7 @@ mdoc_fo_pre(MDOC_ARGS)
return 0;
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_tagq(h, t);
return 0;
@ -1393,7 +1401,7 @@ mdoc_in_pre(MDOC_ARGS)
struct tag *t;
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
@ -1412,9 +1420,9 @@ mdoc_in_pre(MDOC_ARGS)
assert(n->type == ROFFT_TEXT);
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
t = print_otag(h, TAG_A, "c", "In");
t = print_otag(h, TAG_A, "cT", "In");
print_text(h, n->string);
print_tagq(h, t);
@ -1435,14 +1443,19 @@ mdoc_in_pre(MDOC_ARGS)
static int
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;
}
static int
mdoc_va_pre(MDOC_ARGS)
{
print_otag(h, TAG_VAR, "c", "Va");
print_otag(h, TAG_VAR, "cT", "Va");
return 1;
}
@ -1487,7 +1500,12 @@ mdoc_bf_pre(MDOC_ARGS)
static int
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;
}
@ -1516,28 +1534,38 @@ mdoc_rs_pre(MDOC_ARGS)
if (n->prev && SEC_SEE_ALSO == n->sec)
print_paragraph(h);
print_otag(h, TAG_CITE, "c", "Rs");
print_otag(h, TAG_CITE, "cT", "Rs");
return 1;
}
static int
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;
}
static int
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;
}
static int
mdoc_sy_pre(MDOC_ARGS)
{
print_otag(h, TAG_B, "c", "Sy");
print_otag(h, TAG_B, "cT", "Sy");
return 1;
}
@ -1547,7 +1575,7 @@ mdoc_lb_pre(MDOC_ARGS)
if (SEC_LIBRARY == n->sec && NODE_LINE & n->flags && n->prev)
print_otag(h, TAG_BR, "");
print_otag(h, TAG_SPAN, "c", "Lb");
print_otag(h, TAG_SPAN, "cT", "Lb");
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) 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 dword(struct roff_man *, int, int, const char *,
enum mdelim, int);
static int find_pending(struct roff_man *, int, int, int,
struct roff_node *);
static int find_pending(struct roff_man *, enum roff_tok,
int, int, struct roff_node *);
static int lookup(struct roff_man *, int, int, int, const char *);
static int macro_or_word(MACRO_PROT_ARGS, int);
static void break_intermediate(struct roff_node *,
struct roff_node *);
static int parse_rest(struct roff_man *, int, int, int *, char *);
static int rew_alt(int);
static void rew_elem(struct roff_man *, int);
struct roff_node *);
static int parse_rest(struct roff_man *, enum roff_tok,
int, int *, char *);
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_pending(struct roff_man *,
const struct roff_node *);
const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ap */
const struct mdoc_macro __mdoc_macros[MDOC_MAX - MDOC_Dd] = {
{ in_line_eoln, MDOC_PROLOGUE }, /* Dd */
{ in_line_eoln, MDOC_PROLOGUE }, /* Dt */
{ in_line_eoln, MDOC_PROLOGUE }, /* Os */
@ -76,6 +76,8 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
{ blk_full, MDOC_PARSED | MDOC_JOIN }, /* It */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */
{ 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 | MDOC_JOIN }, /* Cd */
{ 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 */
{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Dx */
{ in_line_eoln, MDOC_JOIN }, /* %Q */
{ in_line_eoln, 0 }, /* br */
{ in_line_eoln, 0 }, /* sp */
{ in_line_eoln, 0 }, /* %U */
{ phrase_ta, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ta */
{ in_line_eoln, MDOC_PROLOGUE }, /* ll */
};
const struct mdoc_macro * const mdoc_macros = __mdoc_macros;
const struct mdoc_macro *const mdoc_macros = __mdoc_macros - MDOC_Dd;
/*
@ -225,7 +223,7 @@ mdoc_endparse(struct roff_man *mdoc)
if (n->type == ROFFT_BLOCK &&
mdoc_macros[n->tok].flags & MDOC_EXPLICIT)
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. */
@ -240,20 +238,19 @@ mdoc_endparse(struct roff_man *mdoc)
static int
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) {
mdoc->flags &= ~MDOC_PHRASEQF;
return TOKEN_NONE;
}
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 (mdoc_macros[res].flags & MDOC_CALLABLE)
return res;
if (res != MDOC_br && res != MDOC_sp && res != MDOC_ll)
mandoc_msg(MANDOCERR_MACRO_CALL,
mdoc->parse, line, ppos, p);
mandoc_msg(MANDOCERR_MACRO_CALL,
mdoc->parse, line, ppos, p);
}
}
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.
* Otherwise, return the macro itself.
*/
static int
rew_alt(int tok)
static enum roff_tok
rew_alt(enum roff_tok tok)
{
switch (tok) {
case MDOC_Ac:
@ -366,7 +363,7 @@ rew_alt(int tok)
}
static void
rew_elem(struct roff_man *mdoc, int tok)
rew_elem(struct roff_man *mdoc, enum roff_tok tok)
{
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.
*/
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 *n;
@ -420,8 +417,8 @@ find_pending(struct roff_man *mdoc, int tok, int line, int ppos,
else if ( ! (target->flags & NODE_ENDED)) {
mandoc_vmsg(MANDOCERR_BLK_NEST,
mdoc->parse, line, ppos,
"%s breaks %s", mdoc_macronames[tok],
mdoc_macronames[n->tok]);
"%s breaks %s", roff_name[tok],
roff_name[n->tok]);
mdoc_endbody_alloc(mdoc, line, ppos,
tok, target);
}
@ -524,7 +521,8 @@ macro_or_word(MACRO_PROT_ARGS, int parsed)
mdoc_macros[tok].flags & MDOC_JOIN);
return 0;
} else {
if (mdoc_macros[tok].fp == in_line_eoln)
if (tok != TOKEN_NONE &&
mdoc_macros[tok].fp == in_line_eoln)
rew_elem(mdoc, tok);
mdoc_macro(mdoc, ntok, line, ppos, pos, buf);
if (tok == TOKEN_NONE)
@ -548,7 +546,7 @@ blk_exp_close(MACRO_PROT_ARGS)
int j, lastarg, maxargs, nl, pending;
enum margserr ac;
int atok, ntok;
enum roff_tok atok, ntok;
char *p;
nl = MDOC_NEWLINE & mdoc->flags;
@ -633,8 +631,7 @@ blk_exp_close(MACRO_PROT_ARGS)
mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse,
line, ppos, "%s breaks %s",
mdoc_macronames[atok],
mdoc_macronames[later->tok]);
roff_name[atok], roff_name[later->tok]);
endbody = mdoc_endbody_alloc(mdoc, line, ppos,
atok, body);
@ -676,14 +673,14 @@ blk_exp_close(MACRO_PROT_ARGS)
if (body == NULL) {
mandoc_msg(MANDOCERR_BLK_NOTOPEN, mdoc->parse,
line, ppos, mdoc_macronames[tok]);
line, ppos, roff_name[tok]);
if (maxargs && endbody == NULL) {
/*
* Stray .Ec without previous .Eo:
* Break the output line, keep the arguments.
*/
roff_elem_alloc(mdoc, line, ppos, MDOC_br);
rew_elem(mdoc, MDOC_br);
roff_elem_alloc(mdoc, line, ppos, ROFF_br);
rew_elem(mdoc, ROFF_br);
}
} else if (endbody == NULL) {
rew_last(mdoc, body);
@ -695,7 +692,7 @@ blk_exp_close(MACRO_PROT_ARGS)
if (buf[*pos] != '\0')
mandoc_vmsg(MANDOCERR_ARG_SKIP,
mdoc->parse, line, ppos,
"%s %s", mdoc_macronames[tok],
"%s %s", roff_name[tok],
buf + *pos);
if (endbody == NULL && n != NULL)
rew_pending(mdoc, n);
@ -716,8 +713,7 @@ blk_exp_close(MACRO_PROT_ARGS)
if (ac == ARGS_PUNCT || ac == ARGS_EOLN)
break;
ntok = ac == ARGS_QWORD ? TOKEN_NONE :
lookup(mdoc, tok, line, lastarg, p);
ntok = lookup(mdoc, tok, line, lastarg, p);
if (ntok == TOKEN_NONE) {
dword(mdoc, line, lastarg, p, DELIM_MAX,
@ -752,7 +748,7 @@ static void
in_line(MACRO_PROT_ARGS)
{
int la, scope, cnt, firstarg, mayopen, nc, nl;
int ntok;
enum roff_tok ntok;
enum margserr ac;
enum mdelim d;
struct mdoc_arg *arg;
@ -813,7 +809,7 @@ in_line(MACRO_PROT_ARGS)
break;
}
ntok = (ac == ARGS_QWORD || (tok == MDOC_Fn && !cnt)) ?
ntok = (tok == MDOC_Fn && !cnt) ?
TOKEN_NONE : lookup(mdoc, tok, line, la, p);
/*
@ -833,7 +829,7 @@ in_line(MACRO_PROT_ARGS)
mdoc_argv_free(arg);
mandoc_msg(MANDOCERR_MACRO_EMPTY,
mdoc->parse, line, ppos,
mdoc_macronames[tok]);
roff_name[tok]);
}
mdoc_macro(mdoc, ntok, line, la, pos, buf);
if (nl)
@ -842,14 +838,11 @@ in_line(MACRO_PROT_ARGS)
}
/*
* Non-quote-enclosed punctuation. Set up our scope, if
* a word; rewind the scope, if a delimiter; then append
* the word.
* Handle punctuation. Set up our scope, if a word;
* rewind the scope, if a delimiter; then append the word.
*/
d = ac == ARGS_QWORD ? DELIM_NONE : mdoc_isdelim(p);
if (DELIM_NONE != d) {
if ((d = mdoc_isdelim(p)) != DELIM_NONE) {
/*
* If we encounter closing punctuation, no word
* 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
* any punctuation.
*/
if (scope)
if (scope && tok != MDOC_Lk) {
rew_elem(mdoc, tok);
scope = 0;
if (tok == MDOC_Fn)
mayopen = 0;
scope = 0;
if (tok == MDOC_Fn)
mayopen = 0;
}
} else if (mayopen && !scope) {
mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
scope = 1;
@ -881,7 +875,7 @@ in_line(MACRO_PROT_ARGS)
}
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,
@ -903,8 +897,10 @@ in_line(MACRO_PROT_ARGS)
}
}
if (scope)
if (scope && tok != MDOC_Lk) {
rew_elem(mdoc, tok);
scope = 0;
}
/*
* If no elements have been collected and we're allowed to have
@ -919,11 +915,13 @@ in_line(MACRO_PROT_ARGS)
} else {
mdoc_argv_free(arg);
mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
line, ppos, mdoc_macronames[tok]);
line, ppos, roff_name[tok]);
}
}
if (nl)
append_delims(mdoc, line, pos, buf);
if (scope)
rew_elem(mdoc, tok);
}
static void
@ -942,7 +940,7 @@ blk_full(MACRO_PROT_ARGS)
if (buf[*pos] == '\0' && (tok == MDOC_Sh || tok == MDOC_Ss)) {
mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
line, ppos, mdoc_macronames[tok]);
line, ppos, roff_name[tok]);
return;
}
@ -965,7 +963,7 @@ blk_full(MACRO_PROT_ARGS)
mandoc_vmsg(MANDOCERR_BLK_BROKEN,
mdoc->parse, line, ppos,
"It breaks %s",
mdoc_macronames[blk->tok]);
roff_name[blk->tok]);
rew_pending(mdoc, blk);
}
break;
@ -977,9 +975,8 @@ blk_full(MACRO_PROT_ARGS)
case MDOC_Ss:
mandoc_vmsg(MANDOCERR_BLK_BROKEN,
mdoc->parse, line, ppos,
"%s breaks %s",
mdoc_macronames[tok],
mdoc_macronames[n->tok]);
"%s breaks %s", roff_name[tok],
roff_name[n->tok]);
rew_pending(mdoc, n);
n = mdoc->last;
continue;
@ -1005,8 +1002,7 @@ blk_full(MACRO_PROT_ARGS)
if (blk != NULL) {
mandoc_vmsg(MANDOCERR_BLK_BROKEN,
mdoc->parse, line, ppos,
"It breaks %s",
mdoc_macronames[blk->tok]);
"It breaks %s", roff_name[blk->tok]);
rew_pending(mdoc, blk);
blk = NULL;
}
@ -1021,8 +1017,8 @@ blk_full(MACRO_PROT_ARGS)
if (tok == MDOC_It && (n == NULL || n->tok != MDOC_Bl)) {
mandoc_vmsg(MANDOCERR_IT_STRAY, mdoc->parse,
line, ppos, "It %s", buf + *pos);
roff_elem_alloc(mdoc, line, ppos, MDOC_br);
rew_elem(mdoc, MDOC_br);
roff_elem_alloc(mdoc, line, ppos, ROFF_br);
rew_elem(mdoc, ROFF_br);
return;
}
}
@ -1099,7 +1095,7 @@ blk_full(MACRO_PROT_ARGS)
if (tok == MDOC_Bd || tok == MDOC_Bk) {
mandoc_vmsg(MANDOCERR_ARG_EXCESS,
mdoc->parse, line, la, "%s ... %s",
mdoc_macronames[tok], buf + la);
roff_name[tok], buf + la);
break;
}
if (tok == MDOC_Rs) {
@ -1117,7 +1113,6 @@ blk_full(MACRO_PROT_ARGS)
if (head == NULL &&
ac != ARGS_PHRASE &&
ac != ARGS_QWORD &&
mdoc_isdelim(p) == DELIM_OPEN) {
dword(mdoc, line, la, p, DELIM_OPEN, 0);
continue;
@ -1214,8 +1209,7 @@ blk_part_imp(MACRO_PROT_ARGS)
if (ac == ARGS_EOLN || ac == ARGS_PUNCT)
break;
if (body == NULL && ac != ARGS_QWORD &&
mdoc_isdelim(p) == DELIM_OPEN) {
if (body == NULL && mdoc_isdelim(p) == DELIM_OPEN) {
dword(mdoc, line, la, p, DELIM_OPEN, 0);
continue;
}
@ -1271,8 +1265,7 @@ blk_part_exp(MACRO_PROT_ARGS)
/* Flush out leading punctuation. */
if (head == NULL && ac != ARGS_QWORD &&
mdoc_isdelim(p) == DELIM_OPEN) {
if (head == NULL && mdoc_isdelim(p) == DELIM_OPEN) {
dword(mdoc, line, la, p, DELIM_OPEN, 0);
continue;
}
@ -1307,7 +1300,7 @@ in_line_argn(MACRO_PROT_ARGS)
struct mdoc_arg *arg;
char *p;
enum margserr ac;
int ntok;
enum roff_tok ntok;
int state; /* arg#; -1: not yet open; -2: closed */
int la, maxargs, nl;
@ -1371,7 +1364,7 @@ in_line_argn(MACRO_PROT_ARGS)
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);
if (ntok != TOKEN_NONE) {
@ -1383,8 +1376,7 @@ in_line_argn(MACRO_PROT_ARGS)
break;
}
if (ac == ARGS_QWORD ||
mdoc_macros[tok].flags & MDOC_IGNDELIM ||
if (mdoc_macros[tok].flags & MDOC_IGNDELIM ||
mdoc_isdelim(p) == DELIM_NONE) {
if (state == -1) {
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,
MDOC_JOIN & mdoc_macros[tok].flags);
mdoc_macros[tok].flags & MDOC_JOIN);
}
if (state == -1) {
mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
line, ppos, mdoc_macronames[tok]);
line, ppos, roff_name[tok]);
return;
}
@ -1430,9 +1422,9 @@ in_line_eoln(MACRO_PROT_ARGS)
}
if (buf[*pos] == '\0' &&
(tok == MDOC_Fd || mdoc_macronames[tok][0] == '%')) {
(tok == MDOC_Fd || *roff_name[tok] == '%')) {
mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
line, ppos, mdoc_macronames[tok]);
line, ppos, roff_name[tok]);
return;
}
@ -1449,7 +1441,8 @@ in_line_eoln(MACRO_PROT_ARGS)
* or until the next macro, call that macro, and return 1.
*/
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;

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>
*
@ -20,6 +20,7 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mandoc_aux.h"
@ -32,10 +33,13 @@
#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 {
int (*cond)(DECL_ARGS); /* DON'T run actions */
int (*pre)(DECL_ARGS); /* pre-node action */
void (*post)(DECL_ARGS); /* post-node action */
int_fp cond; /* DON'T run actions */
int_fp pre; /* pre-node action */
void_fp post; /* post-node action */
const char *prefix; /* pre-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 void font_push(char);
static void font_pop(void);
static int man_strlen(const char *);
static void mid_it(void);
static void post__t(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_pf(DECL_ARGS);
static void post_sect(DECL_ARGS);
static void post_sp(DECL_ARGS);
static void post_vt(DECL_ARGS);
static int pre__t(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_bk(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_en(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_fn(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_it(DECL_ARGS);
static int pre_lk(DECL_ARGS);
static int pre_li(DECL_ARGS);
static int pre_ll(DECL_ARGS);
static int pre_nm(DECL_ARGS);
static int pre_no(DECL_ARGS);
static int pre_ns(DECL_ARGS);
static void pre_onearg(DECL_ARGS);
static int pre_pp(DECL_ARGS);
static int pre_rs(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_sy(DECL_ARGS);
static void pre_syn(const struct roff_node *);
static void pre_ta(DECL_ARGS);
static int pre_vt(DECL_ARGS);
static int pre_xr(DECL_ARGS);
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_node(DECL_ARGS);
static const struct manact manacts[MDOC_MAX + 1] = {
{ NULL, pre_ap, NULL, NULL, NULL }, /* Ap */
static const void_fp roff_manacts[ROFF_MAX] = {
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 }, /* Dt */
{ 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_em, post_font, NULL, NULL }, /* Ad */
{ NULL, pre_an, NULL, NULL, NULL }, /* An */
{ NULL, pre_ap, NULL, NULL, NULL }, /* Ap */
{ NULL, pre_em, post_font, NULL, NULL }, /* Ar */
{ NULL, pre_sy, post_font, NULL, NULL }, /* Cd */
{ 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_fl, post_fl, NULL, NULL }, /* Fl */
{ 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_in, post_in, NULL, NULL }, /* In */
{ NULL, pre_li, post_font, NULL, NULL }, /* Li */
{ cond_head, pre_enc, NULL, "\\- ", NULL }, /* Nd */
{ NULL, pre_nm, post_nm, NULL, NULL }, /* Nm */
{ cond_body, pre_enc, post_enc, "[", "]" }, /* Op */
{ NULL, pre_ft, post_font, NULL, NULL }, /* Ot */
{ NULL, pre_Ft, post_font, NULL, NULL }, /* Ot */
{ NULL, pre_em, post_font, NULL, NULL }, /* Pa */
{ NULL, pre_ex, NULL, NULL, NULL }, /* Rv */
{ 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 */
{ NULL, NULL, NULL, NULL, NULL }, /* Dx */
{ 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, 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;
#define MMAN_spc (1 << 0) /* blank character before next word */
@ -274,6 +288,49 @@ static struct {
} 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
font_push(char newfont)
{
@ -391,7 +448,6 @@ static void
print_line(const char *s, int newflags)
{
outflags &= ~MMAN_br;
outflags |= MMAN_nl;
print_word(s);
outflags |= newflags;
@ -420,6 +476,7 @@ print_offs(const char *v, int keywords)
{
char buf[24];
struct roffsu su;
const char *end;
int sz;
print_line(".RS", MMAN_Bk_susp);
@ -431,8 +488,11 @@ print_offs(const char *v, int keywords)
sz = 6;
else if (keywords && !strcmp(v, "indent-two"))
sz = 12;
else if (a2roffsu(v, &su, SCALE_EN) > 1) {
if (SCALE_EN == su.unit)
else {
end = a2roffsu(v, &su, SCALE_EN);
if (end == NULL || *end != '\0')
sz = man_strlen(v);
else if (SCALE_EN == su.unit)
sz = su.scale;
else {
/*
@ -446,8 +506,7 @@ print_offs(const char *v, int keywords)
outflags |= MMAN_nl;
return;
}
} else
sz = strlen(v);
}
/*
* 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];
struct roffsu su;
const char *end;
int numeric, remain, sz, chsz;
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). */
if (bl->width == NULL)
sz = (bl->type == LIST_hang) ? 6 : 0;
else if (a2roffsu(bl->width, &su, SCALE_MAX) > 1) {
if (SCALE_EN == su.unit)
else {
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;
else {
sz = 0;
numeric = 0;
}
} else
sz = strlen(bl->width);
}
/* XXX Rough estimation, might have multiple parts. */
if (bl->type == LIST_enum)
chsz = (bl->count > 8) + 1;
else if (child != NULL && child->type == ROFFT_TEXT)
chsz = strlen(child->string);
chsz = man_strlen(child->string);
else
chsz = 0;
@ -607,7 +669,11 @@ print_node(DECL_ARGS)
outflags &= ~(MMAN_spc | MMAN_spc_force);
else if (outflags & MMAN_Sm)
outflags |= MMAN_spc;
} else if (n->tok < ROFF_MAX) {
(*roff_manacts[n->tok])(meta, n);
return;
} else {
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
/*
* Conditionally run the pre-node action handler for a
* node.
@ -715,8 +781,7 @@ static int
pre__t(DECL_ARGS)
{
if (n->parent && MDOC_Rs == n->parent->tok &&
n->parent->norm->Rs.quote_T) {
if (n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T) {
print_word("\\(lq");
outflags &= ~MMAN_spc;
} else
@ -728,8 +793,7 @@ static void
post__t(DECL_ARGS)
{
if (n->parent && MDOC_Rs == n->parent->tok &&
n->parent->norm->Rs.quote_T) {
if (n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T) {
outflags &= ~MMAN_spc;
print_word("\\(rq");
} else
@ -1013,12 +1077,10 @@ post_bl(DECL_ARGS)
}
static int
static void
pre_br(DECL_ARGS)
{
outflags |= MMAN_br;
return 0;
}
static int
@ -1263,7 +1325,7 @@ post_fo(DECL_ARGS)
}
static int
pre_ft(DECL_ARGS)
pre_Ft(DECL_ARGS)
{
pre_syn(n);
@ -1271,6 +1333,14 @@ pre_ft(DECL_ARGS)
return 1;
}
static void
pre_ft(DECL_ARGS)
{
print_line(".ft", 0);
print_word(n->child->string);
outflags |= MMAN_nl;
}
static int
pre_in(DECL_ARGS)
{
@ -1465,33 +1535,63 @@ post_lb(DECL_ARGS)
static int
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;
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');
while (NULL != descr) {
while (descr != punct) {
print_word(descr->string);
descr = descr->next;
}
print_word(":");
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');
print_word(link->string);
font_pop();
/* Trailing punctuation. */
while (punct != NULL) {
print_word(punct->string);
punct = punct->next;
}
if (display)
print_line(".RE", MMAN_nl);
return 0;
}
static int
pre_ll(DECL_ARGS)
static void
pre_onearg(DECL_ARGS)
{
print_line(".ll", 0);
return 1;
outflags |= MMAN_nl;
print_word(".");
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
@ -1520,7 +1620,7 @@ pre_nm(DECL_ARGS)
if (NULL == n->parent->prev)
outflags |= MMAN_sp;
print_block(".HP", 0);
printf(" %zun", strlen(name) + 1);
printf(" %dn", man_strlen(name) + 1);
outflags |= MMAN_nl;
}
font_push('B');
@ -1615,22 +1715,17 @@ pre_sm(DECL_ARGS)
return 0;
}
static int
static void
pre_sp(DECL_ARGS)
{
if (MMAN_PP & outflags) {
if (outflags & MMAN_PP) {
outflags &= ~MMAN_PP;
print_line(".PP", 0);
} else
} else {
print_line(".sp", 0);
return 1;
}
static void
post_sp(DECL_ARGS)
{
if (n->child != NULL)
print_word(n->child->string);
}
outflags |= MMAN_nl;
}
@ -1642,6 +1737,15 @@ pre_sy(DECL_ARGS)
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
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
* purpose with or without fee is hereby granted, provided that the above
@ -16,6 +16,7 @@
*/
#include <sys/types.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
@ -35,8 +36,7 @@ static void state_dl(STATE_ARGS);
static void state_sh(STATE_ARGS);
static void state_sm(STATE_ARGS);
static const state_handler state_handlers[MDOC_MAX] = {
NULL, /* Ap */
static const state_handler __state_handlers[MDOC_MAX - MDOC_Dd] = {
NULL, /* Dd */
NULL, /* Dt */
NULL, /* Os */
@ -52,6 +52,7 @@ static const state_handler state_handlers[MDOC_MAX] = {
NULL, /* It */
NULL, /* Ad */
NULL, /* An */
NULL, /* Ap */
NULL, /* Ar */
NULL, /* Cd */
NULL, /* Cm */
@ -154,12 +155,10 @@ static const state_handler state_handlers[MDOC_MAX] = {
NULL, /* En */
NULL, /* Dx */
NULL, /* %Q */
NULL, /* br */
NULL, /* sp */
NULL, /* %U */
NULL, /* Ta */
NULL, /* ll */
};
static const state_handler *const state_handlers = __state_handlers - MDOC_Dd;
void
@ -167,9 +166,10 @@ mdoc_state(struct roff_man *mdoc, struct roff_node *n)
{
state_handler handler;
if (n->tok == TOKEN_NONE)
if (n->tok == TOKEN_NONE || n->tok < ROFF_MAX)
return;
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
if ( ! (mdoc_macros[n->tok].flags & MDOC_PROLOGUE))
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) 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_it_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_nd_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_skip_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_sy_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_xx_pre(DECL_ARGS);
static const struct termact termacts[MDOC_MAX] = {
{ termp_ap_pre, NULL }, /* Ap */
static const struct termact __termacts[MDOC_MAX - MDOC_Dd] = {
{ NULL, NULL }, /* Dd */
{ NULL, NULL }, /* Dt */
{ NULL, NULL }, /* Os */
{ termp_sh_pre, termp_sh_post }, /* Sh */
{ 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 }, /* Dl */
{ 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_under_pre, NULL }, /* Ad */
{ termp_an_pre, NULL }, /* An */
{ termp_ap_pre, NULL }, /* Ap */
{ termp_under_pre, NULL }, /* Ar */
{ termp_cd_pre, NULL }, /* Cd */
{ termp_bold_pre, NULL }, /* Cm */
@ -233,7 +232,7 @@ static const struct termact termacts[MDOC_MAX] = {
{ termp_under_pre, NULL }, /* Fr */
{ NULL, NULL }, /* Ud */
{ NULL, termp_lb_post }, /* Lb */
{ termp_sp_pre, NULL }, /* Lp */
{ termp_pp_pre, NULL }, /* Lp */
{ termp_lk_pre, NULL }, /* Lk */
{ termp_under_pre, NULL }, /* Mt */
{ 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_xx_pre, termp_xx_post }, /* Dx */
{ NULL, termp____post }, /* %Q */
{ termp_sp_pre, NULL }, /* br */
{ termp_sp_pre, NULL }, /* sp */
{ NULL, termp____post }, /* %U */
{ NULL, NULL }, /* Ta */
{ termp_ll_pre, NULL }, /* ll */
};
static const struct termact *const termacts = __termacts - MDOC_Dd;
static int fn_prio;
void
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;
p = (struct termp *)arg;
p->overstep = 0;
p->rmargin = p->maxrmargin = p->defrmargin;
p->tabwidth = term_len(p, 5);
p->tcol->rmargin = p->maxrmargin = p->defrmargin;
term_tab_set(p, NULL);
term_tab_set(p, "T");
term_tab_set(p, ".5i");
n = mdoc->first->child;
if (p->synopsisonly) {
@ -317,8 +316,8 @@ print_mdoc_node(DECL_ARGS)
return;
chld = 1;
offset = p->offset;
rmargin = p->rmargin;
offset = p->tcol->offset;
rmargin = p->tcol->rmargin;
n->flags &= ~NODE_ENDED;
n->prev_font = p->fonti;
@ -342,7 +341,8 @@ print_mdoc_node(DECL_ARGS)
switch (n->type) {
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);
if (NODE_DELIMC & n->flags)
p->flags |= TERMP_NOSPACE;
@ -363,7 +363,12 @@ print_mdoc_node(DECL_ARGS)
term_tbl(p, n->span);
break;
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))
chld = (*termacts[n->tok].pre)
(p, &npair, meta, n);
@ -384,7 +389,7 @@ print_mdoc_node(DECL_ARGS)
case ROFFT_EQN:
break;
default:
if ( ! termacts[n->tok].post || NODE_ENDED & n->flags)
if (termacts[n->tok].post == NULL || n->flags & NODE_ENDED)
break;
(void)(*termacts[n->tok].post)(p, &npair, meta, n);
@ -401,10 +406,9 @@ print_mdoc_node(DECL_ARGS)
if (NODE_EOS & n->flags)
p->flags |= TERMP_SENTENCE;
if (MDOC_ll != n->tok) {
p->offset = offset;
p->rmargin = rmargin;
}
if (n->type != ROFFT_TEXT)
p->tcol->offset = offset;
p->tcol->rmargin = rmargin;
}
static void
@ -424,9 +428,9 @@ print_mdoc_foot(struct termp *p, const struct roff_meta *meta)
term_vspace(p);
p->offset = 0;
p->tcol->offset = 0;
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->trailspace = 1;
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_flushln(p);
p->offset = p->rmargin;
p->tcol->offset = p->tcol->rmargin;
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;
term_word(p, meta->date);
term_flushln(p);
p->offset = p->rmargin;
p->rmargin = p->maxrmargin;
p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = p->maxrmargin;
p->trailspace = 0;
p->flags &= ~TERMP_NOBREAK;
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_flushln(p);
p->offset = 0;
p->rmargin = p->maxrmargin;
p->tcol->offset = 0;
p->tcol->rmargin = p->maxrmargin;
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->trailspace = 1;
p->offset = 0;
p->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
p->tcol->offset = 0;
p->tcol->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
(p->maxrmargin - vollen + term_len(p, 1)) / 2 :
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);
p->flags |= TERMP_NOSPACE;
p->offset = p->rmargin;
p->rmargin = p->offset + vollen + titlen < p->maxrmargin ?
p->maxrmargin - titlen : p->maxrmargin;
p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = p->tcol->offset + vollen + titlen <
p->maxrmargin ? p->maxrmargin - titlen : p->maxrmargin;
term_word(p, volume);
term_flushln(p);
p->flags &= ~TERMP_NOBREAK;
p->trailspace = 0;
if (p->rmargin + titlen <= p->maxrmargin) {
if (p->tcol->rmargin + titlen <= p->maxrmargin) {
p->flags |= TERMP_NOSPACE;
p->offset = p->rmargin;
p->rmargin = p->maxrmargin;
p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = p->maxrmargin;
term_word(p, title);
term_flushln(p);
}
p->flags &= ~TERMP_NOSPACE;
p->offset = 0;
p->rmargin = p->maxrmargin;
p->tcol->offset = 0;
p->tcol->rmargin = p->maxrmargin;
free(title);
free(volume);
}
@ -529,8 +533,10 @@ static int
a2width(const struct termp *p, const char *v)
{
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));
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
termp_it_pre(DECL_ARGS)
{
@ -653,8 +651,8 @@ termp_it_pre(DECL_ARGS)
if (bl->norm->Bl.offs != NULL) {
offset = a2width(p, bl->norm->Bl.offs);
if (offset < 0 && (size_t)(-offset) > p->offset)
offset = -p->offset;
if (offset < 0 && (size_t)(-offset) > p->tcol->offset)
offset = -p->tcol->offset;
else if (offset > SHRT_MAX)
offset = 0;
}
@ -718,8 +716,8 @@ termp_it_pre(DECL_ARGS)
* handling for column for how this changes.
*/
width = a2width(p, bl->norm->Bl.width) + term_len(p, 2);
if (width < 0 && (size_t)(-width) > p->offset)
width = -p->offset;
if (width < 0 && (size_t)(-width) > p->tcol->offset)
width = -p->tcol->offset;
else if (width > SHRT_MAX)
width = 0;
break;
@ -768,33 +766,15 @@ termp_it_pre(DECL_ARGS)
case LIST_bullet:
case LIST_dash:
case LIST_hyphen:
/*
* Weird special case.
* Some very narrow lists actually hang.
*/
if (width <= (int)term_len(p, 2))
p->flags |= TERMP_HANG;
if (n->type != ROFFT_HEAD)
break;
p->flags |= TERMP_NOBREAK;
p->trailspace = 1;
if (n->type == ROFFT_HEAD) {
p->flags |= TERMP_NOBREAK | TERMP_HANG;
p->trailspace = 1;
} else if (width <= (int)term_len(p, 2))
p->flags |= TERMP_NOPAD;
break;
case LIST_hang:
if (n->type != ROFFT_HEAD)
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->trailspace = 1;
break;
@ -806,7 +786,7 @@ termp_it_pre(DECL_ARGS)
p->trailspace = 2;
if (NULL == n->next || NULL == n->next->child)
p->flags |= TERMP_DANGLE;
p->flags |= TERMP_HANG;
break;
case LIST_column:
if (n->type == ROFFT_HEAD)
@ -837,43 +817,31 @@ termp_it_pre(DECL_ARGS)
* necessarily lengthened. Everybody gets the offset.
*/
p->offset += offset;
p->tcol->offset += offset;
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_dash:
case LIST_enum:
case LIST_hyphen:
case LIST_hang:
case LIST_tag:
if (n->type == ROFFT_HEAD)
p->rmargin = p->offset + width;
p->tcol->rmargin = p->tcol->offset + width;
else
p->offset += width;
p->tcol->offset += width;
break;
case LIST_column:
assert(width);
p->rmargin = p->offset + width;
p->tcol->rmargin = p->tcol->offset + width;
/*
* XXX - this behaviour is not documented: the
* right-most column is filled to the right margin.
*/
if (n->type == ROFFT_HEAD)
break;
if (NULL == n->next && p->rmargin < p->maxrmargin)
p->rmargin = p->maxrmargin;
if (n->next == NULL && p->tcol->rmargin < p->maxrmargin)
p->tcol->rmargin = p->maxrmargin;
break;
default:
break;
@ -923,6 +891,7 @@ termp_it_pre(DECL_ARGS)
case LIST_column:
if (n->type == ROFFT_HEAD)
return 0;
p->minbl = 0;
break;
default:
break;
@ -963,8 +932,7 @@ termp_it_post(DECL_ARGS)
* has munged them in the meanwhile.
*/
p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP | TERMP_BRIND |
TERMP_DANGLE | TERMP_HANG);
p->flags &= ~(TERMP_NOBREAK | TERMP_BRTRSP | TERMP_BRIND | TERMP_HANG);
p->trailspace = 0;
}
@ -979,7 +947,7 @@ termp_nm_pre(DECL_ARGS)
}
if (n->type == ROFFT_BODY) {
if (NULL == n->child)
if (n->child == NULL)
return 0;
p->flags |= TERMP_NOSPACE;
cp = NULL;
@ -988,9 +956,10 @@ termp_nm_pre(DECL_ARGS)
if (cp == NULL)
cp = meta->name;
if (cp == NULL)
p->offset += term_len(p, 6);
p->tcol->offset += term_len(p, 6);
else
p->offset += term_len(p, 1) + term_strlen(p, cp);
p->tcol->offset += term_len(p, 1) +
term_strlen(p, cp);
return 1;
}
@ -1001,18 +970,18 @@ termp_nm_pre(DECL_ARGS)
synopsis_pre(p, n->parent);
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->trailspace = 1;
p->rmargin = p->offset + term_len(p, 1);
if (NULL == n->child) {
p->rmargin += term_strlen(p, meta->name);
} else if (n->child->type == ROFFT_TEXT) {
p->rmargin += term_strlen(p, n->child->string);
if (n->child->next)
p->tcol->rmargin = p->tcol->offset + term_len(p, 1);
if (n->child == NULL)
p->tcol->rmargin += term_strlen(p, meta->name);
else if (n->child->type == ROFFT_TEXT) {
p->tcol->rmargin += term_strlen(p, n->child->string);
if (n->child->next != NULL)
p->flags |= TERMP_HANG;
} else {
p->rmargin += term_len(p, 5);
p->tcol->rmargin += term_len(p, 5);
p->flags |= TERMP_HANG;
}
}
@ -1135,8 +1104,14 @@ static void
termp_bl_post(DECL_ARGS)
{
if (n->type == ROFFT_BLOCK)
term_newln(p);
if (n->type != ROFFT_BLOCK)
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
@ -1278,7 +1253,10 @@ termp_sh_pre(DECL_ARGS)
term_fontpush(p, TERMFONT_BOLD);
break;
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) {
case SEC_DESCRIPTION:
fn_prio = 0;
@ -1306,7 +1284,7 @@ termp_sh_post(DECL_ARGS)
break;
case ROFFT_BODY:
term_newln(p);
p->offset = 0;
p->tcol->offset = 0;
break;
default:
break;
@ -1328,7 +1306,10 @@ termp_d1_pre(DECL_ARGS)
if (n->type != ROFFT_BLOCK)
return 1;
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;
}
@ -1356,8 +1337,8 @@ termp_fn_pre(DECL_ARGS)
return 0;
if (pretty) {
rmargin = p->rmargin;
p->rmargin = p->offset + term_len(p, 4);
rmargin = p->tcol->rmargin;
p->tcol->rmargin = p->tcol->offset + term_len(p, 4);
p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG;
}
@ -1372,8 +1353,9 @@ termp_fn_pre(DECL_ARGS)
if (pretty) {
term_flushln(p);
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
p->offset = p->rmargin;
p->rmargin = rmargin;
p->flags |= TERMP_NOPAD;
p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = rmargin;
}
p->flags |= TERMP_NOSPACE;
@ -1434,7 +1416,7 @@ termp_fa_pre(DECL_ARGS)
static int
termp_bd_pre(DECL_ARGS)
{
size_t tabwidth, lm, len, rm, rmax;
size_t lm, len;
struct roff_node *nn;
int offset;
@ -1450,15 +1432,15 @@ termp_bd_pre(DECL_ARGS)
! strcmp(n->norm->Bd.offs, "left"))
/* nothing */;
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"))
p->offset += term_len(p, (p->defindent + 1) * 2);
p->tcol->offset += term_len(p, (p->defindent + 1) * 2);
else {
offset = a2width(p, n->norm->Bd.offs);
if (offset < 0 && (size_t)(-offset) > p->offset)
p->offset = 0;
if (offset < 0 && (size_t)(-offset) > p->tcol->offset)
p->tcol->offset = 0;
else if (offset < SHRT_MAX)
p->offset += offset;
p->tcol->offset += offset;
}
/*
@ -1469,29 +1451,29 @@ termp_bd_pre(DECL_ARGS)
* lines are allowed.
*/
if (DISP_literal != n->norm->Bd.type &&
DISP_unfilled != n->norm->Bd.type &&
DISP_centered != n->norm->Bd.type)
if (n->norm->Bd.type != DISP_literal &&
n->norm->Bd.type != DISP_unfilled &&
n->norm->Bd.type != DISP_centered)
return 1;
tabwidth = p->tabwidth;
if (DISP_literal == n->norm->Bd.type)
p->tabwidth = term_len(p, 8);
if (n->norm->Bd.type == DISP_literal) {
term_tab_set(p, NULL);
term_tab_set(p, "T");
term_tab_set(p, "8n");
}
lm = p->offset;
rm = p->rmargin;
rmax = p->maxrmargin;
p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
for (nn = n->child; nn; nn = nn->next) {
if (DISP_centered == n->norm->Bd.type) {
lm = p->tcol->offset;
p->flags |= TERMP_BRNEVER;
for (nn = n->child; nn != NULL; nn = nn->next) {
if (n->norm->Bd.type == DISP_centered) {
if (nn->type == ROFFT_TEXT) {
len = term_strlen(p, nn->string);
p->offset = len >= rm ? 0 :
lm + len >= rm ? rm - len :
(lm + rm - len) / 2;
p->tcol->offset = len >= p->tcol->rmargin ?
0 : lm + len >= p->tcol->rmargin ?
p->tcol->rmargin - len :
(lm + p->tcol->rmargin - len) / 2;
} else
p->offset = lm;
p->tcol->offset = lm;
}
print_mdoc_node(p, pair, meta, nn);
/*
@ -1500,10 +1482,10 @@ termp_bd_pre(DECL_ARGS)
* notion of selective eoln whitespace is pretty dumb
* anyway, so don't sweat it.
*/
if (nn->tok < ROFF_MAX)
continue;
switch (nn->tok) {
case MDOC_Sm:
case MDOC_br:
case MDOC_sp:
case MDOC_Bl:
case MDOC_D1:
case MDOC_Dl:
@ -1519,33 +1501,21 @@ termp_bd_pre(DECL_ARGS)
term_flushln(p);
p->flags |= TERMP_NOSPACE;
}
p->tabwidth = tabwidth;
p->rmargin = rm;
p->maxrmargin = rmax;
p->flags &= ~TERMP_BRNEVER;
return 0;
}
static void
termp_bd_post(DECL_ARGS)
{
size_t rm, rmax;
if (n->type != ROFFT_BODY)
return;
rm = p->rmargin;
rmax = p->maxrmargin;
if (DISP_literal == n->norm->Bd.type ||
DISP_unfilled == n->norm->Bd.type)
p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
p->flags |= TERMP_BRNEVER;
p->flags |= TERMP_NOSPACE;
term_newln(p);
p->rmargin = rm;
p->maxrmargin = rmax;
p->flags &= ~TERMP_BRNEVER;
}
static int
@ -1587,10 +1557,13 @@ termp_ss_pre(DECL_ARGS)
break;
case ROFFT_HEAD:
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;
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;
default:
break;
@ -1650,37 +1623,10 @@ termp_in_post(DECL_ARGS)
}
static int
termp_sp_pre(DECL_ARGS)
termp_pp_pre(DECL_ARGS)
{
struct roffsu su;
int i, len;
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);
fn_prio = 0;
term_vspace(p);
return 0;
}
@ -1861,8 +1807,8 @@ termp_fo_pre(DECL_ARGS)
return 1;
} else if (n->type == ROFFT_BODY) {
if (pretty) {
rmargin = p->rmargin;
p->rmargin = p->offset + term_len(p, 4);
rmargin = p->tcol->rmargin;
p->tcol->rmargin = p->tcol->offset + term_len(p, 4);
p->flags |= TERMP_NOBREAK | TERMP_BRIND |
TERMP_HANG;
}
@ -1873,8 +1819,9 @@ termp_fo_pre(DECL_ARGS)
term_flushln(p);
p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND |
TERMP_HANG);
p->offset = p->rmargin;
p->rmargin = rmargin;
p->flags |= TERMP_NOPAD;
p->tcol->offset = p->tcol->rmargin;
p->tcol->rmargin = rmargin;
}
return 1;
}
@ -1992,26 +1939,50 @@ termp_li_pre(DECL_ARGS)
static int
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;
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);
while (NULL != descr) {
while (descr != punct) {
if (descr->flags & (NODE_DELIMC | NODE_DELIMO))
p->flags |= TERMP_NOSPACE;
term_word(p, descr->string);
descr = descr->next;
}
term_fontpop(p);
p->flags |= TERMP_NOSPACE;
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_word(p, link->string);
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;
}

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) 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 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 *,
struct roff_node *, struct mdoc_argv *);
static void check_args(struct roff_man *, struct roff_node *);
static int child_an(const struct roff_node *);
static size_t macro2len(int);
static void rewrite_macro2len(char **);
static size_t macro2len(enum roff_tok);
static void rewrite_macro2len(struct roff_man *, char **);
static void post_an(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_st(POST_ARGS);
static void post_std(POST_ARGS);
static void post_useless(POST_ARGS);
static void post_xr(POST_ARGS);
static void post_xx(POST_ARGS);
static v_post mdoc_valids[MDOC_MAX] = {
NULL, /* Ap */
static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] = {
post_dd, /* Dd */
post_dt, /* Dt */
post_os, /* Os */
@ -125,6 +126,7 @@ static v_post mdoc_valids[MDOC_MAX] = {
post_it, /* It */
NULL, /* Ad */
post_an, /* An */
NULL, /* Ap */
post_defaults, /* Ar */
NULL, /* Cd */
NULL, /* Cm */
@ -201,7 +203,7 @@ static v_post mdoc_valids[MDOC_MAX] = {
post_sm, /* Sm */
post_hyph, /* Sx */
NULL, /* Sy */
NULL, /* Tn */
post_useless, /* Tn */
post_xx, /* Ux */
NULL, /* Xc */
NULL, /* Xo */
@ -227,16 +229,14 @@ static v_post mdoc_valids[MDOC_MAX] = {
post_en, /* En */
post_xx, /* Dx */
NULL, /* %Q */
post_par, /* br */
post_par, /* sp */
NULL, /* %U */
NULL, /* Ta */
NULL, /* ll */
};
static const v_post *const mdoc_valids = __mdoc_valids - MDOC_Dd;
#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__T,
MDOC__B,
@ -284,7 +284,7 @@ void
mdoc_node_validate(struct roff_man *mdoc)
{
struct roff_node *n;
v_post *p;
const v_post *p;
n = mdoc->last;
mdoc->last = mdoc->last->child;
@ -303,6 +303,10 @@ mdoc_node_validate(struct roff_man *mdoc)
if (n->sec != SEC_SYNOPSIS ||
(n->parent->tok != MDOC_Cd && n->parent->tok != MDOC_Fd))
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;
case ROFFT_EQN:
case ROFFT_TBL:
@ -326,6 +330,20 @@ mdoc_node_validate(struct roff_man *mdoc)
/* 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;
if (*p)
(*p)(mdoc);
@ -370,6 +388,25 @@ check_text(struct roff_man *mdoc, int ln, int pos, char *p)
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
post_bl_norm(POST_ARGS)
{
@ -450,7 +487,7 @@ post_bl_norm(POST_ARGS)
mdoc->parse, argv->line,
argv->pos, "Bl -width %s",
argv->value[0]);
rewrite_macro2len(argv->value);
rewrite_macro2len(mdoc, argv->value);
n->norm->Bl.width = argv->value[0];
break;
case MDOC_Offset:
@ -465,7 +502,7 @@ post_bl_norm(POST_ARGS)
mdoc->parse, argv->line,
argv->pos, "Bl -offset %s",
argv->value[0]);
rewrite_macro2len(argv->value);
rewrite_macro2len(mdoc, argv->value);
n->norm->Bl.offs = argv->value[0];
break;
default:
@ -592,7 +629,7 @@ post_bd(POST_ARGS)
mdoc->parse, argv->line,
argv->pos, "Bd -offset %s",
argv->value[0]);
rewrite_macro2len(argv->value);
rewrite_macro2len(mdoc, argv->value);
n->norm->Bd.offs = argv->value[0];
break;
case MDOC_Compact:
@ -659,11 +696,11 @@ post_eoln(POST_ARGS)
{
struct roff_node *n;
post_useless(mdoc);
n = mdoc->last;
if (n->child != NULL)
mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse,
n->line, n->pos, "%s %s",
mdoc_macronames[n->tok], n->child->string);
mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse, n->line,
n->pos, "%s %s", roff_name[n->tok], n->child->string);
while (n->child != NULL)
roff_node_delete(mdoc, n->child);
@ -757,6 +794,9 @@ post_lb(POST_ARGS)
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");
mdoc->last->flags = NODE_NOSRC;
roff_word_alloc(mdoc, n->line, n->pos, "\\(Lq");
@ -817,7 +857,7 @@ post_std(POST_ARGS)
return;
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
@ -852,7 +892,17 @@ post_obsolete(POST_ARGS)
n = mdoc->last;
if (n->type == ROFFT_ELEM || n->type == ROFFT_BLOCK)
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)
{
struct roff_node *n;
size_t sz;
n = mdoc->last;
if (n->type != ROFFT_BODY)
return;
if (n->sec != SEC_NAME)
mandoc_msg(MANDOCERR_ND_LATE, mdoc->parse,
n->line, n->pos, "Nd");
if (n->child == NULL)
mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse,
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);
}
@ -1056,7 +1116,7 @@ post_display(POST_ARGS)
roff_node_delete(mdoc, n);
} else if (n->child == NULL)
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)
post_hyph(mdoc);
break;
@ -1079,7 +1139,7 @@ post_display(POST_ARGS)
if (np->type == ROFFT_BLOCK && np->tok == MDOC_Bd) {
mandoc_vmsg(MANDOCERR_BD_NEST,
mdoc->parse, n->line, n->pos,
"%s in Bd", mdoc_macronames[n->tok]);
"%s in Bd", roff_name[n->tok]);
break;
}
}
@ -1265,10 +1325,10 @@ post_it(POST_ARGS)
/* FALLTHROUGH */
case LIST_item:
if ((nch = nit->head->child) != NULL)
mandoc_vmsg(MANDOCERR_ARG_SKIP,
mdoc->parse, nit->line, nit->pos,
"It %s", nch->string == NULL ?
mdoc_macronames[nch->tok] : nch->string);
mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse,
nit->line, nit->pos, "It %s",
nch->string == NULL ? roff_name[nch->tok] :
nch->string);
break;
case LIST_column:
cols = (int)nbl->norm->Bl.ncols;
@ -1306,7 +1366,7 @@ post_bl_block(POST_ARGS)
switch (nc->tok) {
case MDOC_Pp:
case MDOC_Lp:
case MDOC_br:
case ROFF_br:
break;
default:
nc = NULL;
@ -1315,14 +1375,13 @@ post_bl_block(POST_ARGS)
if (ni->next == NULL) {
mandoc_msg(MANDOCERR_PAR_MOVE,
mdoc->parse, nc->line, nc->pos,
mdoc_macronames[nc->tok]);
roff_name[nc->tok]);
mdoc_node_relink(mdoc, nc);
} else if (n->norm->Bl.comp == 0 &&
n->norm->Bl.type != LIST_column) {
mandoc_vmsg(MANDOCERR_PAR_SKIP,
mdoc->parse, nc->line, nc->pos,
"%s before It",
mdoc_macronames[nc->tok]);
"%s before It", roff_name[nc->tok]);
roff_node_delete(mdoc, nc);
} else
break;
@ -1335,17 +1394,17 @@ post_bl_block(POST_ARGS)
* If the argument of -offset or -width is a macro,
* replace it with the associated default width.
*/
void
rewrite_macro2len(char **arg)
static void
rewrite_macro2len(struct roff_man *mdoc, char **arg)
{
size_t width;
int tok;
enum roff_tok tok;
if (*arg == NULL)
return;
else if ( ! strcmp(*arg, "Ds"))
width = 6;
else if ((tok = mdoc_hash_find(*arg)) == TOKEN_NONE)
else if ((tok = roffhash_find(mdoc->mdocmac, *arg, 0)) == TOKEN_NONE)
return;
else
width = macro2len(tok);
@ -1423,6 +1482,8 @@ post_bl(POST_ARGS)
struct roff_node *nparent, *nprev; /* of the Bl block */
struct roff_node *nblock, *nbody; /* of the Bl */
struct roff_node *nchild, *nnext; /* of the Bl body */
const char *prev_Er;
int order;
nbody = mdoc->last;
switch (nbody->type) {
@ -1486,8 +1547,7 @@ post_bl(POST_ARGS)
}
mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse,
nchild->line, nchild->pos,
mdoc_macronames[nchild->tok]);
nchild->line, nchild->pos, roff_name[nchild->tok]);
/*
* Move the node out of the Bl block.
@ -1524,6 +1584,34 @@ post_bl(POST_ARGS)
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
@ -1565,7 +1653,7 @@ post_sm(POST_ARGS)
mandoc_vmsg(MANDOCERR_SM_BAD,
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);
return;
}
@ -1608,7 +1696,7 @@ post_root(POST_ARGS)
mandoc_msg(MANDOCERR_DOC_EMPTY, mdoc->parse, 0, 0, NULL);
else if (n->tok != MDOC_Sh)
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
@ -1642,9 +1730,8 @@ post_rs(POST_ARGS)
break;
if (i == RSORD_MAX) {
mandoc_msg(MANDOCERR_RS_BAD,
mdoc->parse, nch->line, nch->pos,
mdoc_macronames[nch->tok]);
mandoc_msg(MANDOCERR_RS_BAD, mdoc->parse,
nch->line, nch->pos, roff_name[nch->tok]);
i = -1;
} else if (nch->tok == MDOC__J || nch->tok == MDOC__B)
np->norm->Rs.quote_T++;
@ -1797,7 +1884,7 @@ post_sh_name(POST_ARGS)
/* FALLTHROUGH */
default:
mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
n->line, n->pos, mdoc_macronames[n->tok]);
n->line, n->pos, roff_name[n->tok]);
continue;
}
break;
@ -1867,7 +1954,7 @@ post_sh_see_also(POST_ARGS)
if (isalpha((const unsigned char)*name))
return;
lastpunct = n->string;
if (n->next == NULL)
if (n->next == NULL || n->next->tok == MDOC_Rs)
mandoc_vmsg(MANDOCERR_XR_PUNCT, mdoc->parse,
n->line, n->pos, "%s after %s(%s)",
lastpunct, lastname, lastsec);
@ -1918,7 +2005,7 @@ post_sh_head(POST_ARGS)
sec != SEC_CUSTOM ? secnames[sec] :
(nch = mdoc->last->child) == NULL ? "" :
nch->type == ROFFT_TEXT ? nch->string :
mdoc_macronames[nch->tok]);
roff_name[nch->tok]);
/* The SYNOPSIS gets special attention in other areas. */
@ -2014,6 +2101,9 @@ post_ignpar(POST_ARGS)
struct roff_node *np;
switch (mdoc->last->type) {
case ROFFT_BLOCK:
post_prevpar(mdoc);
return;
case ROFFT_HEAD:
post_hyph(mdoc);
return;
@ -2027,8 +2117,8 @@ post_ignpar(POST_ARGS)
if (np->tok == MDOC_Pp || np->tok == MDOC_Lp) {
mandoc_vmsg(MANDOCERR_PAR_SKIP,
mdoc->parse, np->line, np->pos,
"%s after %s", mdoc_macronames[np->tok],
mdoc_macronames[mdoc->last->tok]);
"%s after %s", roff_name[np->tok],
roff_name[mdoc->last->tok]);
roff_node_delete(mdoc, np);
}
@ -2036,8 +2126,8 @@ post_ignpar(POST_ARGS)
if (np->tok == MDOC_Pp || np->tok == MDOC_Lp) {
mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
np->line, np->pos, "%s at the end of %s",
mdoc_macronames[np->tok],
mdoc_macronames[mdoc->last->tok]);
roff_name[np->tok],
roff_name[mdoc->last->tok]);
roff_node_delete(mdoc, np);
}
}
@ -2060,7 +2150,7 @@ post_prevpar(POST_ARGS)
if (n->prev->tok != MDOC_Pp &&
n->prev->tok != MDOC_Lp &&
n->prev->tok != MDOC_br)
n->prev->tok != ROFF_br)
return;
if (n->tok == MDOC_Bl && n->norm->Bl.comp)
return;
@ -2070,9 +2160,8 @@ post_prevpar(POST_ARGS)
return;
mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
n->prev->line, n->prev->pos,
"%s before %s", mdoc_macronames[n->prev->tok],
mdoc_macronames[n->tok]);
n->prev->line, n->prev->pos, "%s before %s",
roff_name[n->prev->tok], roff_name[n->tok]);
roff_node_delete(mdoc, n->prev);
}
@ -2082,10 +2171,10 @@ post_par(POST_ARGS)
struct roff_node *np;
np = mdoc->last;
if (np->tok != MDOC_br && np->tok != MDOC_sp)
if (np->tok != ROFF_br && np->tok != ROFF_sp)
post_prevpar(mdoc);
if (np->tok == MDOC_sp) {
if (np->tok == ROFF_sp) {
if (np->child != NULL && np->child->next != NULL)
mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
np->child->next->line, np->child->next->pos,
@ -2093,21 +2182,20 @@ post_par(POST_ARGS)
} else if (np->child != NULL)
mandoc_vmsg(MANDOCERR_ARG_SKIP,
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) {
np = mdoc->last->parent;
if (np->tok != MDOC_Sh && np->tok != MDOC_Ss)
return;
} else if (np->tok != MDOC_Pp && np->tok != MDOC_Lp &&
(mdoc->last->tok != MDOC_br ||
(np->tok != MDOC_sp && np->tok != MDOC_br)))
(mdoc->last->tok != ROFF_br ||
(np->tok != ROFF_sp && np->tok != ROFF_br)))
return;
mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
mdoc->last->line, mdoc->last->pos,
"%s after %s", mdoc_macronames[mdoc->last->tok],
mdoc_macronames[np->tok]);
mdoc->last->line, mdoc->last->pos, "%s after %s",
roff_name[mdoc->last->tok], roff_name[np->tok]);
roff_node_delete(mdoc, mdoc->last);
}
@ -2251,11 +2339,19 @@ static void
post_bx(POST_ARGS)
{
struct roff_node *n, *nch;
const char *macro;
n = mdoc->last;
nch = n->child;
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;
nch = nch->next;
mdoc->next = ROFF_NEXT_SIBLING;
@ -2322,11 +2418,11 @@ post_os(POST_ARGS)
mdoc->meta.os = NULL;
deroff(&mdoc->meta.os, n);
if (mdoc->meta.os)
return;
goto out;
if (mdoc->defos) {
mdoc->meta.os = mandoc_strdup(mdoc->defos);
return;
goto out;
}
#ifdef OSNAME
@ -2343,6 +2439,10 @@ post_os(POST_ARGS)
}
mdoc->meta.os = mandoc_strdup(defbuf);
#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
@ -2358,7 +2458,7 @@ mdoc_a2sec(const char *p)
}
static size_t
macro2len(int macro)
macro2len(enum roff_tok 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) 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
* purpose with or without fee is hereby granted, provided that the above
@ -29,9 +29,10 @@
#include "out.h"
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 *,
const struct tbl_dat *);
const struct tbl_dat *, size_t);
static void tblcalc_number(struct rofftbl *, struct roffcol *,
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.
* If the string doesn't specify the unit, use the default.
* If no default is specified, fail.
* Return 2 on complete success, 1 when a conversion was done,
* but there was trailing garbage, and 0 on total failure.
* Return a pointer to the byte after the last byte used,
* or NULL on total failure.
*/
int
const char *
a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
{
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->scale = strtod(src, &endptr);
if (endptr == src)
return 0;
return NULL;
switch (*endptr++) {
case 'c':
@ -89,12 +90,11 @@ a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
/* FALLTHROUGH */
default:
if (SCALE_MAX == def)
return 0;
return NULL;
dst->unit = def;
break;
}
return *endptr == '\0' ? 2 : 1;
return endptr;
}
/*
@ -107,6 +107,7 @@ void
tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
size_t totalwidth)
{
struct roffsu su;
const struct tbl_opts *opts;
const struct tbl_dat *dp;
struct roffcol *col;
@ -147,7 +148,16 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
col->flags |= dp->layout->flags;
if (dp->layout->flags & TBL_CELL_WIGN)
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) {
xwidth = totalwidth - xwidth - 3*maxcol -
xwidth += 3*maxcol +
(opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) ?
2 : !!opts->lvert + !!opts->rvert);
if (xwidth >= totalwidth)
return;
xwidth = totalwidth - xwidth;
/*
* Emulate a bug in GNU tbl width calculation that
@ -232,7 +245,7 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
static void
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;
@ -249,7 +262,7 @@ tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
case TBL_CELL_CENTRE:
case TBL_CELL_LEFT:
case TBL_CELL_RIGHT:
tblcalc_literal(tbl, col, dp);
tblcalc_literal(tbl, col, dp, mw);
break;
case TBL_CELL_NUMBER:
tblcalc_number(tbl, col, opts, dp);
@ -263,16 +276,29 @@ tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
static void
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;
const char *str; /* Beginning of the first line. */
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 : "";
sz = (*tbl->slen)(str, tbl->arg);
if (col->width < sz)
col->width = sz;
if (dp->string == NULL || *dp->string == '\0')
return;
str = mw ? mandoc_strdup(dp->string) : dp->string;
for (beg = str; beg != NULL && *beg != '\0'; beg = end) {
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

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) 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
@ -40,14 +41,16 @@ struct roffsu {
double scale;
};
typedef size_t (*tbl_sulen)(const struct roffsu *, void *);
typedef size_t (*tbl_strlen)(const char *, void *);
typedef size_t (*tbl_len)(size_t, void *);
struct rofftbl {
tbl_sulen sulen; /* calculate scaling unit length */
tbl_strlen slen; /* calculate string length */
tbl_len len; /* produce width of empty space */
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) \
@ -63,6 +66,6 @@ struct rofftbl {
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,
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) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -66,7 +66,7 @@ struct mparse {
static void choose_parser(struct mparse *);
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,
struct buf *, int *);
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] = {
MANDOCERR_OK,
MANDOCERR_WARNING,
MANDOCERR_STYLE,
MANDOCERR_WARNING,
MANDOCERR_ERROR,
MANDOCERR_UNSUPP,
@ -86,6 +86,14 @@ static const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = {
static const char * const mandocerrs[MANDOCERR_MAX] = {
"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",
/* related to the prologue */
@ -113,6 +121,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"bad NAME section content",
"missing comma before name",
"missing description line, using \"\"",
"description line outside NAME section",
"sections out of conventional order",
"duplicate section title",
"unexpected section",
@ -132,6 +141,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"fill mode already enabled, skipping",
"fill mode already disabled, skipping",
"line scope broken",
"skipping blank line in line scope",
/* related to missing macro arguments */
"skipping empty request",
@ -167,6 +177,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"unknown AT&T UNIX version",
"comma in function argument",
"parenthesis in function name",
"unknown library name",
"invalid content in Rs block",
"invalid Boolean argument",
"unknown font, skipping request",
@ -219,6 +230,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"NOT IMPLEMENTED: Bd -file",
"skipping display without arguments",
"missing list type, using -item",
"argument is not numeric, using 1",
"missing manual name, using \"\"",
"uname(3) system call failed, using UNKNOWN",
"unknown standard specifier",
@ -240,7 +252,7 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
static const char * const mandoclevels[MANDOCLEVEL_MAX] = {
"SUCCESS",
"RESERVED",
"STYLE",
"WARNING",
"ERROR",
"UNSUPP",
@ -292,14 +304,15 @@ choose_parser(struct mparse *curp)
}
if (format == MPARSE_MDOC) {
mdoc_hash_init();
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 {
man_hash_init();
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)
* and indirectly (for .so file inclusion).
*/
static void
static int
mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
{
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;
char *cp;
size_t pos; /* byte number in the ln buffer */
size_t j; /* auxiliary byte number in the blk buffer */
enum rofferr rr;
int of;
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;
}
/* 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++];
}
if (pos >= ln.sz)
if (pos + 1 >= ln.sz)
resize_buf(&ln, 256);
if (i == blk.sz || blk.buf[i] == '\0')
ln.buf[pos++] = '\n';
ln.buf[pos] = '\0';
/*
@ -510,13 +457,16 @@ mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
switch (rr) {
case ROFF_REPARSE:
if (REPARSE_LIMIT >= ++curp->reparse_count)
mparse_buf_r(curp, ln, of, 0);
else
if (++curp->reparse_count > REPARSE_LIMIT)
mandoc_msg(MANDOCERR_ROFFLOOP, curp,
curp->line, pos, NULL);
pos = 0;
continue;
else if (mparse_buf_r(curp, ln, of, 0) == 1 ||
start == 1) {
pos = 0;
continue;
}
free(ln.buf);
return 0;
case ROFF_APPEND:
pos = strlen(ln.buf);
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')) {
curp->sodest = mandoc_strdup(ln.buf + of);
free(ln.buf);
return;
return 1;
}
/*
* 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);
return 1;
}
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->options & MPARSE_QUICK ? 1 : 0);
if (curp->options & MPARSE_MDOC) {
mdoc_hash_init();
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) {
man_hash_init();
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;
return curp;
@ -843,6 +796,8 @@ void
mparse_free(struct mparse *curp)
{
roffhash_free(curp->man->mdocmac);
roffhash_free(curp->man->manmac);
roff_man_free(curp->man);
roff_free(curp->roff);
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) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -16,6 +16,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
struct ohash;
struct mdoc_arg;
union mdoc_data;
@ -25,6 +26,12 @@ enum roff_macroset {
MACROSET_MAN
};
enum mdoc_os {
MDOC_OS_OTHER = 0,
MDOC_OS_NETBSD,
MDOC_OS_OPENBSD
};
enum roff_sec {
SEC_NONE = 0,
SEC_NAME,
@ -64,6 +71,411 @@ enum roff_type {
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 {
ROFF_NEXT_SIBLING = 0,
ROFF_NEXT_CHILD
@ -94,8 +506,6 @@ struct roff_node {
const struct eqn *eqn; /* EQN */
int line; /* Input file line number. */
int pos; /* Input file column number. */
int tok; /* Request or macro ID. */
#define TOKEN_NONE (-1) /* No request or macro. */
int flags;
#define NODE_VALID (1 << 0) /* Has been validated. */
#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. */
int prev_font; /* Before entering this node. */
int aux; /* Decoded node data, type-dependent. */
enum roff_tok tok; /* Request or macro ID. */
enum roff_type type; /* AST node type. */
enum roff_sec sec; /* Current named section. */
enum mdoc_endbody end; /* BODY */
@ -123,12 +534,15 @@ struct roff_meta {
char *name; /* Leading manual name. */
char *date; /* Normalized date. */
int hasbody; /* Document is not empty. */
enum mdoc_os os_e; /* Operating system. */
};
struct roff_man {
struct roff_meta meta; /* Document meta-data. */
struct mparse *parse; /* Parse pointer. */
struct roff *roff; /* Roff parser state data. */
struct ohash *mdocmac; /* Mdoc macro lookup table. */
struct ohash *manmac; /* Man macro lookup table. */
const char *defos; /* Default operating system. */
struct roff_node *first; /* The first 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. */
};
extern const char *const *roff_name;
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>
.\" All rights reserved.
@ -24,7 +24,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd $Mdocdate: May 20 2015 $
.Dd $Mdocdate: March 18 2017 $
.Dt SOELIM 1
.Os
.Sh NAME
@ -69,8 +69,8 @@ This option specify directories where
searches for files (both those on the command line and those named in
.Dq .so
directive.)
This options may be specified multiple times. The directories will be searched
in the order specified.
This options may be specified multiple times.
The directories will be searched in the order specified.
.El
.Pp
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) 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
.\" purpose with or without fee is hereby granted, provided that the above
@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: January 29 2015 $
.Dd $Mdocdate: June 8 2017 $
.Dt TBL 7
.Os
.Sh NAME
@ -245,7 +245,7 @@ Emit a double-vertical bar instead of data.
.Pp
Keys may be followed by a set of modifiers.
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:
.Bl -tag -width 2n
.It Cm b
@ -284,8 +284,7 @@ Currently ignored.
Move cell content up by half a table line.
Currently ignored.
.It Cm w
Specify minimum column width.
Currently ignored.
Specify the minimum column width.
.It Cm x
After determining the width of all other columns, distribute 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
bold font justified about the decimal point in numbers:
.Pp
.Dl c10 | l10 | nfB
.Dl cw10 | lw10 | nfB
.Ss Data
The data section follows the last layout row.
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) 2011, 2015 Ingo Schwarze <schwarze@openbsd.org>
@ -114,6 +114,7 @@ tbl_free(struct tbl_node *tbl)
while (rp->first != NULL) {
cp = rp->first;
rp->first = cp->next;
free(cp->wstr);
free(cp);
}
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) 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
* 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->block = 1;
if (dat->string != NULL) {
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) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@ -31,22 +31,48 @@
static void html_tblopen(struct html *, const struct tbl_span *);
static size_t html_tbl_len(size_t, void *);
static size_t html_tbl_strlen(const char *, void *);
static size_t html_tbl_sulen(const struct roffsu *, void *);
static size_t
html_tbl_len(size_t sz, void *arg)
{
return sz;
}
static size_t
html_tbl_strlen(const char *p, void *arg)
{
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
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) {
h->tbl.len = html_tbl_len;
h->tbl.slen = html_tbl_strlen;
h->tbl.sulen = html_tbl_sulen;
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) 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
* 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)
{
char *endptr;
size_t sz;
mod:
while (p[*pos] == ' ' || p[*pos] == '\t')
@ -127,7 +128,22 @@ mods(struct tbl_node *tbl, struct tbl_cell *cp,
case 'u':
cp->flags |= TBL_CELL_UP;
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;
case 'x':
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) 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
* 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_strlen(const char *, void *);
static size_t term_tbl_sulen(const struct roffsu *, void *);
static void tbl_char(struct termp *, char, size_t);
static void tbl_data(struct termp *, const struct tbl_opts *,
const struct tbl_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 size_t
term_tbl_sulen(const struct roffsu *su, void *arg)
{
return term_hspan((const struct termp *)arg, su) / 24;
}
static size_t
term_tbl_strlen(const char *p, void *arg)
{
return term_strlen((const struct termp *)arg, p);
}
static size_t
term_tbl_len(size_t sz, void *arg)
{
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_dat *dp;
static size_t offset;
size_t rmargin, maxrmargin, tsz;
size_t tsz;
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. */
tp->flags |= TERMP_NONOSPACE;
tp->flags |= TERMP_NOSPACE;
tp->flags |= TERMP_NOSPACE | TERMP_NONOSPACE | TERMP_BRNEVER;
/*
* 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) {
tp->tbl.len = term_tbl_len;
tp->tbl.slen = term_tbl_strlen;
tp->tbl.sulen = term_tbl_sulen;
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. */
offset = tp->offset;
offset = tp->tcol->offset;
if (sp->opts->opts & TBL_OPT_CENTRE) {
tsz = sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)
? 2 : !!sp->opts->lvert + !!sp->opts->rvert;
for (ic = 0; ic < sp->opts->cols; ic++)
tsz += tp->tbl.cols[ic].width + 3;
tsz -= 3;
if (offset + tsz > rmargin)
if (offset + tsz > tp->tcol->rmargin)
tsz -= 1;
tp->offset = (offset + rmargin > tsz) ?
(offset + rmargin - tsz) / 2 : 0;
tp->tcol->offset = offset + tp->tcol->rmargin > tsz ?
(offset + tp->tcol->rmargin - tsz) / 2 : 0;
}
/* 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);
free(tp->tbl.cols);
tp->tbl.cols = NULL;
tp->offset = offset;
tp->tcol->offset = offset;
}
tp->flags &= ~TERMP_NONOSPACE;
tp->rmargin = rmargin;
tp->maxrmargin = maxrmargin;
tp->flags &= ~(TERMP_NONOSPACE | TERMP_BRNEVER);
}
/*

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) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
@ -32,17 +32,19 @@
#include "main.h"
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 encode(struct termp *, const char *, size_t);
static void encode1(struct termp *, int);
static void endline(struct termp *);
void
term_free(struct termp *p)
{
free(p->buf);
for (p->tcol = p->tcols; p->tcol < p->tcols + p->maxtcol; p->tcol++)
free(p->tcol->buf);
free(p->tcols);
free(p->fontq);
free(p);
}
@ -84,69 +86,53 @@ term_end(struct termp *p)
* to be broken, start the next line at the right margin instead
* of at the offset. Used together with TERMP_NOBREAK for the tags
* in various kinds of tagged lists.
* - TERMP_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.
* To be used together with TERMP_NOBREAK.
* - TERMP_HANG: Like TERMP_DANGLE, and also suppress padding before
* the next chunk if this column is not full.
* - TERMP_NOPAD: Start writing at the current position,
* do not pad with blank characters up to the offset.
*/
void
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 vbl; /* number of blanks to prepend to output */
size_t vend; /* end of word visual position on output */
size_t bp; /* visual right border position */
size_t dv; /* temporary for visual pos calculations */
size_t j; /* temporary loop index for p->buf */
size_t j; /* temporary loop index for p->tcol->buf */
size_t jhy; /* last hyph before overflow w/r/t j */
size_t maxvis; /* output position of visible boundary */
int ntab; /* number of tabs to prepend */
/*
* First, establish the maximum columns of "visible" content.
* This is usually the difference between the right-margin and
* an indentation, but can be, for tagged lists or columns, a
* small set of values.
*
* The following unsigned-signed subtractions look strange,
* but they are actually correct. If the int p->overstep
* is negative, it gets sign extended. Subtracting that
* 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;
vbl = (p->flags & TERMP_NOPAD) || p->tcol->offset < p->viscol ?
0 : p->tcol->offset - p->viscol;
if (p->minbl && vbl < p->minbl)
vbl = p->minbl;
maxvis = p->tcol->rmargin > p->viscol + vbl ?
p->tcol->rmargin - p->viscol - vbl : 0;
bp = !(p->flags & TERMP_NOBREAK) ? maxvis :
p->maxrmargin > p->viscol + vbl ?
p->maxrmargin - p->viscol - vbl : 0;
vis = vend = 0;
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
* subsequent tabs into a single huge set of spaces.
*/
ntab = 0;
while (i < p->col && '\t' == p->buf[i]) {
vend = (vis / p->tabwidth + 1) * p->tabwidth;
while (p->tcol->col < p->lastcol &&
p->tcol->buf[p->tcol->col] == '\t') {
vend = term_tab_next(vis);
vbl += vend - vis;
vis = vend;
ntab++;
i++;
p->tcol->col++;
}
/*
@ -156,84 +142,90 @@ term_flushln(struct termp *p)
* space is printed according to regular spacing rules).
*/
for (j = i, jhy = 0; j < p->col; j++) {
if (' ' == p->buf[j] || '\t' == p->buf[j])
jhy = 0;
for (j = p->tcol->col; j < p->lastcol; j++) {
if (p->tcol->buf[j] == ' ' || p->tcol->buf[j] == '\t')
break;
/* Back over the last printed character. */
if (8 == p->buf[j]) {
if (p->tcol->buf[j] == '\b') {
assert(j);
vend -= (*p->width)(p, p->buf[j - 1]);
vend -= (*p->width)(p, p->tcol->buf[j - 1]);
continue;
}
/* Regular word. */
/* Break at the hyphen point if we overrun. */
if (vend > vis && vend < bp &&
(ASCII_HYPH == p->buf[j] ||
ASCII_BREAK == p->buf[j]))
(p->tcol->buf[j] == ASCII_HYPH||
p->tcol->buf[j] == ASCII_BREAK))
jhy = j;
/*
* Hyphenation now decided, put back a real
* hyphen such that we get the correct width.
*/
if (ASCII_HYPH == p->buf[j])
p->buf[j] = '-';
if (p->tcol->buf[j] == ASCII_HYPH)
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.
* 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;
(*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 += ntab * p->tabwidth;
vbl = 0;
while (ntab--)
vbl = term_tab_next(vbl);
/*
* Remove the p->overstep width.
* Again, if p->overstep is negative,
* sign extension does the right thing.
*/
/* Re-establish indentation. */
bp += (size_t)p->overstep;
p->overstep = 0;
if (p->flags & TERMP_BRIND)
vbl += p->tcol->rmargin;
else
vbl += p->tcol->offset;
maxvis = p->tcol->rmargin > vbl ?
p->tcol->rmargin - vbl : 0;
bp = !(p->flags & TERMP_NOBREAK) ? maxvis :
p->maxrmargin > vbl ? p->maxrmargin - vbl : 0;
}
/* Write out the [remaining] word. */
for ( ; i < p->col; i++) {
if (vend > bp && jhy > 0 && i > jhy)
/*
* Write out the rest of the word.
*/
for ( ; p->tcol->col < p->lastcol; p->tcol->col++) {
if (vend > bp && jhy > 0 && p->tcol->col > jhy)
break;
if ('\t' == p->buf[i])
if (p->tcol->buf[p->tcol->col] == '\t')
break;
if (' ' == p->buf[i]) {
j = i;
while (i < p->col && ' ' == p->buf[i])
i++;
dv = (i - j) * (*p->width)(p, ' ');
if (p->tcol->buf[p->tcol->col] == ' ') {
j = p->tcol->col;
while (p->tcol->col < p->lastcol &&
p->tcol->buf[p->tcol->col] == ' ')
p->tcol->col++;
dv = (p->tcol->col - j) * (*p->width)(p, ' ');
vbl += dv;
vend += dv;
break;
}
if (ASCII_NBRSP == p->buf[i]) {
if (p->tcol->buf[p->tcol->col] == ASCII_NBRSP) {
vbl += (*p->width)(p, ' ');
continue;
}
if (ASCII_BREAK == p->buf[i])
if (p->tcol->buf[p->tcol->col] == ASCII_BREAK)
continue;
/*
@ -247,11 +239,13 @@ term_flushln(struct termp *p)
vbl = 0;
}
(*p->letter)(p, p->buf[i]);
if (8 == p->buf[i])
p->viscol -= (*p->width)(p, p->buf[i-1]);
(*p->letter)(p, p->tcol->buf[p->tcol->col]);
if (p->tcol->buf[p->tcol->col] == '\b')
p->viscol -= (*p->width)(p,
p->tcol->buf[p->tcol->col - 1]);
else
p->viscol += (*p->width)(p, p->buf[i]);
p->viscol += (*p->width)(p,
p->tcol->buf[p->tcol->col]);
}
vis = vend;
}
@ -260,48 +254,45 @@ term_flushln(struct termp *p)
* If there was trailing white space, it was not printed;
* so reset the cursor position accordingly.
*/
if (vis > vbl)
vis -= vbl;
else
vis = 0;
p->col = 0;
p->overstep = 0;
p->flags &= ~(TERMP_BACKAFTER | TERMP_BACKBEFORE);
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;
p->col = p->lastcol = 0;
p->minbl = p->trailspace;
p->flags &= ~(TERMP_BACKAFTER | TERMP_BACKBEFORE | TERMP_NOPAD);
/* Trailing whitespace is significant in some columns. */
if (vis && vbl && (TERMP_BRTRSP & p->flags))
vis += vbl;
/* If the column was overrun, break the line. */
if (maxvis < vis + p->trailspace * (*p->width)(p, ' ')) {
(*p->endline)(p);
p->viscol = 0;
if ((p->flags & TERMP_NOBREAK) == 0 ||
((p->flags & TERMP_HANG) == 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;
if (p->col || p->viscol)
if (p->lastcol || p->viscol)
term_flushln(p);
}
@ -330,6 +321,7 @@ term_vspace(struct termp *p)
term_newln(p);
p->viscol = 0;
p->minbl = 0;
if (0 < p->skipvsp)
p->skipvsp--;
else
@ -397,30 +389,31 @@ term_fontpop(struct termp *p)
void
term_word(struct termp *p, const char *word)
{
struct roffsu su;
const char nbrsp[2] = { ASCII_NBRSP, 0 };
const char *seq, *cp;
int sz, uc;
size_t ssz;
size_t csz, lsz, ssz;
enum mandoc_esc esc;
if ( ! (TERMP_NOSPACE & p->flags)) {
if ( ! (TERMP_KEEP & p->flags)) {
bufferc(p, ' ');
if (TERMP_SENTENCE & p->flags)
if ((p->flags & TERMP_NOBUF) == 0) {
if ((p->flags & TERMP_NOSPACE) == 0) {
if ((p->flags & TERMP_KEEP) == 0) {
bufferc(p, ' ');
} else
bufferc(p, ASCII_NBRSP);
if (p->flags & TERMP_SENTENCE)
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) {
if ('\\' != *word) {
@ -485,6 +478,74 @@ term_word(struct termp *p, const char *word)
else if (*word == '\0')
p->flags |= (TERMP_NOSPACE | TERMP_NONEWLINE);
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:
p->flags |= TERMP_BACKAFTER;
continue;
@ -504,10 +565,12 @@ term_word(struct termp *p, const char *word)
}
}
/* Trim trailing backspace/blank pair. */
if (p->col > 2 &&
(p->buf[p->col - 1] == ' ' ||
p->buf[p->col - 1] == '\t'))
p->col -= 2;
if (p->lastcol > 2 &&
(p->tcol->buf[p->lastcol - 1] == ' ' ||
p->tcol->buf[p->lastcol - 1] == '\t'))
p->lastcol -= 2;
if (p->col > p->lastcol)
p->col = p->lastcol;
continue;
default:
continue;
@ -532,25 +595,28 @@ term_word(struct termp *p, const char *word)
}
static void
adjbuf(struct termp *p, size_t sz)
adjbuf(struct termp_col *c, size_t sz)
{
if (0 == p->maxcols)
p->maxcols = 1024;
while (sz >= p->maxcols)
p->maxcols <<= 2;
p->buf = mandoc_reallocarray(p->buf, p->maxcols, sizeof(int));
if (c->maxcols == 0)
c->maxcols = 1024;
while (c->maxcols <= sz)
c->maxcols <<= 2;
c->buf = mandoc_reallocarray(c->buf, c->maxcols, sizeof(*c->buf));
}
static void
bufferc(struct termp *p, char c)
{
if (p->col + 1 >= p->maxcols)
adjbuf(p, p->col + 1);
p->buf[p->col++] = c;
if (p->flags & TERMP_NOBUF) {
(*p->letter)(p, c);
return;
}
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;
if (p->col + 7 >= p->maxcols)
adjbuf(p, p->col + 7);
if (p->flags & TERMP_NOBUF) {
(*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)) ?
p->fontq[p->fonti] : TERMFONT_NONE;
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--;
else
p->buf[p->col++] = 8;
p->tcol->buf[p->col++] = '\b';
p->flags &= ~TERMP_BACKBEFORE;
}
if (TERMFONT_UNDER == f || TERMFONT_BI == f) {
p->buf[p->col++] = '_';
p->buf[p->col++] = 8;
if (f == TERMFONT_UNDER || f == TERMFONT_BI) {
p->tcol->buf[p->col++] = '_';
p->tcol->buf[p->col++] = '\b';
}
if (TERMFONT_BOLD == f || TERMFONT_BI == f) {
if (ASCII_HYPH == c)
p->buf[p->col++] = '-';
if (f == TERMFONT_BOLD || f == TERMFONT_BI) {
if (c == ASCII_HYPH)
p->tcol->buf[p->col++] = '-';
else
p->buf[p->col++] = c;
p->buf[p->col++] = 8;
p->tcol->buf[p->col++] = c;
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) {
p->flags |= TERMP_BACKBEFORE;
p->flags &= ~TERMP_BACKAFTER;
@ -599,15 +674,24 @@ encode(struct termp *p, const char *word, size_t sz)
{
size_t i;
if (p->col + 2 + (sz * 5) >= p->maxcols)
adjbuf(p, p->col + 2 + (sz * 5));
if (p->flags & TERMP_NOBUF) {
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++) {
if (ASCII_HYPH == word[i] ||
isgraph((unsigned char)word[i]))
encode1(p, word[i]);
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
@ -621,6 +705,8 @@ encode(struct termp *p, const char *word, size_t sz)
}
}
}
if (p->lastcol < p->col)
p->lastcol = p->col;
}
void
@ -644,7 +730,7 @@ term_setwidth(struct termp *p, const char *wstr)
default:
break;
}
if (a2roffsu(wstr, &su, SCALE_MAX))
if (a2roffsu(wstr, &su, SCALE_MAX) != NULL)
width = term_hspan(p, &su);
else
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) 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
* purpose with or without fee is hereby granted, provided that the above
@ -36,9 +36,10 @@ enum termfont {
TERMFONT__MAX
};
#define TERM_MAXMARGIN 100000 /* FIXME */
struct eqn;
struct roff_meta;
struct roff_node;
struct tbl_span;
struct termp;
typedef void (*term_margin)(struct termp *, const struct roff_meta *);
@ -48,24 +49,33 @@ struct termp_tbl {
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 {
enum termtype type;
struct rofftbl tbl; /* table configuration */
int synopsisonly; /* print the synopsis only */
int mdocstyle; /* imitate mdoc(7) output */
struct rofftbl tbl; /* Table configuration. */
struct termp_col *tcols; /* Array of table columns. */
struct termp_col *tcol; /* Current table column. */
size_t maxtcol; /* Allocated table columns. */
size_t lasttcol; /* Last column currently used. */
size_t line; /* Current output line number. */
size_t defindent; /* Default indent for text. */
size_t defrmargin; /* Right margin of the device. */
size_t lastrmargin; /* Right margin before the last ll. */
size_t rmargin; /* Current right margin. */
size_t maxrmargin; /* Max right margin. */
size_t maxcols; /* Max size of buf. */
size_t offset; /* Margin offest. */
size_t tabwidth; /* Distance of tab positions. */
size_t col; /* Bytes in buf. */
size_t col; /* Byte position in buf. */
size_t lastcol; /* Bytes in buf. */
size_t viscol; /* Chars on current line. */
size_t trailspace; /* See termp_flushln(). */
int overstep; /* See termp_flushln(). */
size_t trailspace; /* See term_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 flags;
#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_BRTRSP (1 << 9) /* See term_flushln(). */
#define TERMP_BRIND (1 << 10) /* See term_flushln(). */
#define TERMP_DANGLE (1 << 11) /* See term_flushln(). */
#define TERMP_HANG (1 << 12) /* See term_flushln(). */
#define TERMP_HANG (1 << 11) /* See term_flushln(). */
#define TERMP_NOPAD (1 << 12) /* See term_flushln(). */
#define TERMP_NOSPLIT (1 << 13) /* Do not break line before .An. */
#define TERMP_SPLIT (1 << 14) /* Break line before .An. */
#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 termfont fontl; /* Last font set. */
enum termfont *fontq; /* Symmetric fonts. */
@ -102,15 +116,15 @@ struct termp {
int (*hspan)(const struct termp *,
const struct roffsu *);
const void *argf; /* arg for headf/footf */
const char *mc; /* Margin character. */
struct termp_ps *ps;
};
struct tbl_span;
struct eqn;
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_tbl(struct termp *, const struct tbl_span *);
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_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_fontpop(struct termp *);
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) 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
* 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
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->tabwidth = 5;
p->defrmargin = p->lastrmargin = 78;
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->begin = ascii_begin;
@ -149,7 +150,7 @@ ascii_setwidth(struct termp *p, int iop, int width)
{
width /= 24;
p->rmargin = p->defrmargin;
p->tcol->rmargin = p->defrmargin;
if (iop > 0)
p->defrmargin += width;
else if (iop == 0)
@ -158,8 +159,8 @@ ascii_setwidth(struct termp *p, int iop, int width)
p->defrmargin -= width;
else
p->defrmargin = 0;
p->lastrmargin = p->rmargin;
p->rmargin = p->maxrmargin = p->defrmargin;
p->lastrmargin = p->tcol->rmargin;
p->tcol->rmargin = p->maxrmargin = p->defrmargin;
}
void
@ -216,6 +217,8 @@ ascii_endline(struct termp *p)
{
p->line++;
p->tcol->offset -= p->ti;
p->ti = 0;
putchar('\n');
}
@ -370,6 +373,8 @@ locale_endline(struct termp *p)
{
p->line++;
p->tcol->offset -= p->ti;
p->ti = 0;
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) 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
* 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;
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->fontq = mandoc_reallocarray(NULL,
(p->fontsz = 8), sizeof(enum termfont));
(p->fontsz = 8), sizeof(*p->fontq));
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->begin = ps_begin;
@ -1219,6 +1222,9 @@ ps_endline(struct termp *p)
}
ps_closepage(p);
p->tcol->offset -= p->ti;
p->ti = 0;
}
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) 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;
break;
case ROFFT_BODY:
p = mdoc_macronames[n->tok];
p = roff_name[n->tok];
break;
case ROFFT_HEAD:
p = mdoc_macronames[n->tok];
p = roff_name[n->tok];
break;
case ROFFT_TAIL:
p = mdoc_macronames[n->tok];
p = roff_name[n->tok];
break;
case ROFFT_ELEM:
p = mdoc_macronames[n->tok];
p = roff_name[n->tok];
if (n->args) {
argv = n->args->argv;
argc = n->args->argc;
}
break;
case ROFFT_BLOCK:
p = mdoc_macronames[n->tok];
p = roff_name[n->tok];
if (n->args) {
argv = n->args->argv;
argc = n->args->argc;
@ -257,7 +257,7 @@ print_man(const struct roff_node *n, int indent)
case ROFFT_BLOCK:
case ROFFT_HEAD:
case ROFFT_BODY:
p = man_macronames[n->tok];
p = roff_name[n->tok];
break;
case ROFFT_ROOT:
p = "root";