summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/man/man.c23
-rw-r--r--usr/src/cmd/man/man.h3
-rw-r--r--usr/src/cmd/mandoc/Makefile26
-rw-r--r--usr/src/cmd/mandoc/Makefile.common61
-rw-r--r--usr/src/cmd/mandoc/THIRDPARTYLICENSE41
-rw-r--r--usr/src/cmd/mandoc/THIRDPARTYLICENSE.descrip2
-rw-r--r--usr/src/cmd/mandoc/arch.in112
-rw-r--r--usr/src/cmd/mandoc/att.c26
-rw-r--r--usr/src/cmd/mandoc/att.in40
-rw-r--r--usr/src/cmd/mandoc/chars.c58
-rw-r--r--usr/src/cmd/mandoc/chars.in294
-rw-r--r--usr/src/cmd/mandoc/compat_fgetln.c94
-rw-r--r--usr/src/cmd/mandoc/compat_reallocarray.c49
-rw-r--r--usr/src/cmd/mandoc/compat_strtonum.c76
-rw-r--r--usr/src/cmd/mandoc/config.h66
-rw-r--r--usr/src/cmd/mandoc/eqn.c1462
-rw-r--r--usr/src/cmd/mandoc/eqn_html.c189
-rw-r--r--usr/src/cmd/mandoc/eqn_term.c91
-rw-r--r--usr/src/cmd/mandoc/html.c373
-rw-r--r--usr/src/cmd/mandoc/html.h68
-rw-r--r--usr/src/cmd/mandoc/lib.c9
-rw-r--r--usr/src/cmd/mandoc/libman.h39
-rw-r--r--usr/src/cmd/mandoc/libmandoc.h75
-rw-r--r--usr/src/cmd/mandoc/libmdoc.h57
-rw-r--r--usr/src/cmd/mandoc/libroff.h52
-rw-r--r--usr/src/cmd/mandoc/main.c853
-rw-r--r--usr/src/cmd/mandoc/main.h29
-rw-r--r--usr/src/cmd/mandoc/man.c510
-rw-r--r--usr/src/cmd/mandoc/man.h13
-rw-r--r--usr/src/cmd/mandoc/man_hash.c11
-rw-r--r--usr/src/cmd/mandoc/man_html.c193
-rw-r--r--usr/src/cmd/mandoc/man_macro.c370
-rw-r--r--usr/src/cmd/mandoc/man_term.c574
-rw-r--r--usr/src/cmd/mandoc/man_validate.c474
-rw-r--r--usr/src/cmd/mandoc/mandoc.c277
-rw-r--r--usr/src/cmd/mandoc/mandoc.h360
-rw-r--r--usr/src/cmd/mandoc/mandoc_aux.c119
-rw-r--r--usr/src/cmd/mandoc/mandoc_aux.h (renamed from usr/src/cmd/mandoc/vol.c)34
-rw-r--r--usr/src/cmd/mandoc/manpath.c237
-rw-r--r--usr/src/cmd/mandoc/manpath.h (renamed from usr/src/cmd/mandoc/arch.c)37
-rw-r--r--usr/src/cmd/mandoc/mansearch.h111
-rw-r--r--usr/src/cmd/mandoc/mdoc.c539
-rw-r--r--usr/src/cmd/mandoc/mdoc.h40
-rw-r--r--usr/src/cmd/mandoc/mdoc_argv.c286
-rw-r--r--usr/src/cmd/mandoc/mdoc_hash.c8
-rw-r--r--usr/src/cmd/mandoc/mdoc_html.c895
-rw-r--r--usr/src/cmd/mandoc/mdoc_macro.c1852
-rw-r--r--usr/src/cmd/mandoc/mdoc_man.c536
-rw-r--r--usr/src/cmd/mandoc/mdoc_term.c1148
-rw-r--r--usr/src/cmd/mandoc/mdoc_validate.c2696
-rw-r--r--usr/src/cmd/mandoc/msec.c7
-rw-r--r--usr/src/cmd/mandoc/out.c237
-rw-r--r--usr/src/cmd/mandoc/out.h20
-rw-r--r--usr/src/cmd/mandoc/preconv.c523
-rw-r--r--usr/src/cmd/mandoc/read.c784
-rw-r--r--usr/src/cmd/mandoc/roff.c2322
-rw-r--r--usr/src/cmd/mandoc/st.c9
-rw-r--r--usr/src/cmd/mandoc/st.in97
-rw-r--r--usr/src/cmd/mandoc/tbl.c130
-rw-r--r--usr/src/cmd/mandoc/tbl_data.c172
-rw-r--r--usr/src/cmd/mandoc/tbl_html.c41
-rw-r--r--usr/src/cmd/mandoc/tbl_layout.c472
-rw-r--r--usr/src/cmd/mandoc/tbl_opts.c308
-rw-r--r--usr/src/cmd/mandoc/tbl_term.c354
-rw-r--r--usr/src/cmd/mandoc/term.c484
-rw-r--r--usr/src/cmd/mandoc/term.h53
-rw-r--r--usr/src/cmd/mandoc/term_ascii.c260
-rw-r--r--usr/src/cmd/mandoc/term_ps.c506
-rw-r--r--usr/src/cmd/mandoc/tree.c206
-rw-r--r--usr/src/cmd/mandoc/vol.in35
-rw-r--r--usr/src/man/man1/mandoc.11434
-rw-r--r--usr/src/man/man5/eqn.5339
-rw-r--r--usr/src/man/man5/mandoc_char.5113
-rw-r--r--usr/src/man/man5/mandoc_roff.51469
-rw-r--r--usr/src/man/man5/mdoc.5870
-rw-r--r--usr/src/man/man5/tbl.5206
-rw-r--r--usr/src/pkg/manifests/system-man.mf6
-rw-r--r--usr/src/tools/mandoc/Makefile36
78 files changed, 15717 insertions, 11364 deletions
diff --git a/usr/src/cmd/man/man.c b/usr/src/cmd/man/man.c
index 8038cabbac..d181c6d374 100644
--- a/usr/src/cmd/man/man.c
+++ b/usr/src/cmd/man/man.c
@@ -22,8 +22,8 @@
/*
* Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2012, Josef 'Jeff' Sipek <jeffpc@31bits.net>. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
* Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T. */
@@ -1193,7 +1193,6 @@ format(char *path, char *dir, char *name, char *pg)
char manpname[MAXPATHLEN], catpname[MAXPATHLEN];
char cmdbuf[BUFSIZ], tmpbuf[BUFSIZ];
char *cattool;
- int utf8 = 0;
struct stat sbman, sbcat;
found++;
@@ -1227,22 +1226,16 @@ format(char *path, char *dir, char *name, char *pg)
else
cattool = "cat";
- /* Preprocess UTF-8 input with preconv (could be smarter) */
- if (strstr(path, "UTF-8") != NULL)
- utf8 = 1;
-
if (psoutput) {
(void) snprintf(cmdbuf, BUFSIZ,
- "cd %s; %s %s%s | mandoc -Tps | lp -Tpostscript",
- path, cattool, manpname,
- utf8 ? " | " PRECONV " -e UTF-8" : "");
+ "cd %s; %s %s | mandoc -Tps | lp -Tpostscript",
+ path, cattool, manpname);
DPRINTF("-- Using manpage: %s\n", manpname);
goto cmd;
} else if (lintout) {
(void) snprintf(cmdbuf, BUFSIZ,
- "cd %s; %s %s%s | mandoc -Tlint",
- path, cattool, manpname,
- utf8 ? " | " PRECONV " -e UTF-8" : "");
+ "cd %s; %s %s | mandoc -Tlint",
+ path, cattool, manpname);
DPRINTF("-- Linting manpage: %s\n", manpname);
goto cmd;
}
@@ -1262,10 +1255,8 @@ format(char *path, char *dir, char *name, char *pg)
DPRINTF("-- Using manpage: %s\n", manpname);
if (manwidth > 0)
(void) snprintf(tmpbuf, BUFSIZ, "-Owidth=%d ", manwidth);
- (void) snprintf(cmdbuf, BUFSIZ, "cd %s; %s %s%s | mandoc -T%s %s| %s",
- path, cattool, manpname,
- utf8 ? " | " PRECONV " -e UTF-8 " : "",
- utf8 ? "utf8" : "ascii", (manwidth > 0) ? tmpbuf : "", pager);
+ (void) snprintf(cmdbuf, BUFSIZ, "cd %s; %s %s | mandoc %s| %s",
+ path, cattool, manpname, (manwidth > 0) ? tmpbuf : "", pager);
cmd:
DPRINTF("-- Command: %s\n", cmdbuf);
diff --git a/usr/src/cmd/man/man.h b/usr/src/cmd/man/man.h
index e6803a7969..b4ec3f380a 100644
--- a/usr/src/cmd/man/man.h
+++ b/usr/src/cmd/man/man.h
@@ -10,8 +10,8 @@
*/
/*
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
* Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -26,7 +26,6 @@
#define INDENT 24
#define PAGER "less -ins"
#define WHATIS "whatis"
-#define PRECONV "/usr/lib/mandoc_preconv"
#define LINE_ALLOC 4096
#define MAXDIRS 128
diff --git a/usr/src/cmd/mandoc/Makefile b/usr/src/cmd/mandoc/Makefile
index 08cea9764a..4353cb74d7 100644
--- a/usr/src/cmd/mandoc/Makefile
+++ b/usr/src/cmd/mandoc/Makefile
@@ -10,40 +10,24 @@
#
#
-# Copyright 2014 Nexenta Systems, Inc. All rights reserved.
# Copyright 2014 Garrett D'Amore <garrett@damore.org>
+# Copyright 2015 Nexenta Systems, Inc. All rights reserved.
#
-PROGS= mandoc mandoc_preconv
-
-# We place preconv in /usr/lib. This is done to avoid conflicting with
-# GNU groff, which puts it into /usr/bin. We also rename it so that it
-# will only be seen by mandoc -- it isn't intended for general end-user use.
-
-ROOTPROGS = $(ROOTBIN)/mandoc $(ROOTLIB)/mandoc_preconv
-
-OBJS= $(preconv_OBJS) $(mandoc_OBJS)
-
-CLOBBERFILES += $(PROGS)
-
include $(SRC)/cmd/Makefile.cmd
include $(SRC)/cmd/mandoc/Makefile.common
.KEEP_STATE:
-all: $(PROGS)
-
-mandoc_preconv: $(preconv_OBJS)
- $(LINK.c) $(preconv_OBJS) -o $@ $(LDLIBS)
- $(POST_PROCESS)
+all: $(PROG)
-mandoc: $(mandoc_OBJS)
- $(LINK.c) $(mandoc_OBJS) -o $@ $(LDLIBS)
+$(PROG): $(OBJS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
$(POST_PROCESS)
clean:
$(RM) $(OBJS)
-install: all $(ROOTPROGS)
+install: all $(ROOTPROG)
include $(SRC)/cmd/Makefile.targ
diff --git a/usr/src/cmd/mandoc/Makefile.common b/usr/src/cmd/mandoc/Makefile.common
index b1a67b3805..d4e95ffbfd 100644
--- a/usr/src/cmd/mandoc/Makefile.common
+++ b/usr/src/cmd/mandoc/Makefile.common
@@ -10,23 +10,58 @@
#
#
-# Copyright 2012 Nexenta Systems, Inc. All rights reserved.
# Copyright 2014 Garrett D'Amore <garrett@damore.org>
+# Copyright 2015 Nexenta Systems, Inc. All rights reserved.
#
-PROGS= mandoc mandoc_preconv
-mandoc_OBJS = arch.o att.o chars.o eqn.o eqn_html.o eqn_term.o \
- html.o lib.o main.o man.o man_hash.o man_html.o \
- man_macro.o man_term.o man_validate.o mandoc.o mdoc.o \
- mdoc_argv.o mdoc_hash.o mdoc_html.o mdoc_macro.o \
- mdoc_man.o mdoc_term.o mdoc_validate.o msec.o out.o \
- read.o roff.o st.o tbl.o tbl_data.o tbl_html.o \
- tbl_layout.o tbl_opts.o tbl_term.o term.o term_ascii.o \
- term_ps.o tree.o vol.o
+PROG= mandoc
-preconv_OBJS = preconv.o
+OBJS= att.o \
+ chars.o \
+ eqn.o \
+ eqn_html.o \
+ eqn_term.o \
+ html.o \
+ lib.o \
+ main.o \
+ man.o \
+ manpath.o \
+ man_hash.o \
+ man_html.o \
+ man_macro.o \
+ man_term.o \
+ man_validate.o \
+ mandoc.o \
+ mandoc_aux.o \
+ mdoc.o \
+ mdoc_argv.o \
+ mdoc_hash.o \
+ mdoc_html.o \
+ mdoc_macro.o \
+ mdoc_man.o \
+ mdoc_term.o \
+ mdoc_validate.o \
+ msec.o \
+ out.o \
+ read.o \
+ roff.o \
+ preconv.o \
+ st.o \
+ tbl.o \
+ tbl_data.o \
+ tbl_html.o \
+ tbl_layout.o \
+ tbl_opts.o \
+ tbl_term.o \
+ term.o \
+ term_ascii.o \
+ term_ps.o \
+ tree.o
+
+OBJS += compat_fgetln.o \
+ compat_reallocarray.o \
+ compat_strtonum.o
CFLAGS += $(CC_VERBOSE)
-CPPFLAGS += -DHAVE_CONFIG_H -DUSE_WCHAR \
- -DOSNAME="\"illumos\""
+CPPFLAGS += -DOSNAME="\"illumos\""
diff --git a/usr/src/cmd/mandoc/THIRDPARTYLICENSE b/usr/src/cmd/mandoc/THIRDPARTYLICENSE
index 0fae1fd4b2..080c04fa26 100644
--- a/usr/src/cmd/mandoc/THIRDPARTYLICENSE
+++ b/usr/src/cmd/mandoc/THIRDPARTYLICENSE
@@ -1,14 +1,47 @@
-Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
-Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
+$Id: LICENSE,v 1.7 2015/02/16 14:56:22 schwarze Exp $
+
+With the exceptions noted below, all code and documentation
+contained in the mdocml toolkit is protected by the Copyright
+of the following developers:
+
+Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
+Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
+Copyright (c) 2009, 2010, 2011, 2012 Joerg Sonnenberger <joerg@netbsd.org>
+Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
+Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
+Copyright (c) 1998, 2004, 2010 Todd C. Miller <Todd.Miller@courtesan.com>
+Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
+Copyright (c) 2004 Ted Unangst <tedu@openbsd.org>
+Copyright (c) 2003, 2007, 2008, 2014 Jason McIntyre <jmc@openbsd.org>
+
+See the individual source files for information about who contributed
+to which file during which years.
+
+
+The mdocml distribution as a whole is distributed by its developers
+under the following license:
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+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 AUTHORS BE LIABLE FOR
+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.
+
+
+The following files included from outside sources are protected by
+other people's Copyright and are distributed under a 3-clause BSD
+license; see these individual files for details.
+
+compat_fts.c, compat_fts.h,
+compat_getsubopt.c, compat_strcasestr.c, compat_strsep.c,
+man.1:
+Copyright (c) 1989,1990,1993,1994 The Regents of the University of California
+
+compat_fgetln.c:
+Copyright (c) 1998 The NetBSD Foundation, Inc.
diff --git a/usr/src/cmd/mandoc/THIRDPARTYLICENSE.descrip b/usr/src/cmd/mandoc/THIRDPARTYLICENSE.descrip
index ecb8c678a0..b89cd5be30 100644
--- a/usr/src/cmd/mandoc/THIRDPARTYLICENSE.descrip
+++ b/usr/src/cmd/mandoc/THIRDPARTYLICENSE.descrip
@@ -1 +1 @@
-MANDOC - FORMAT AND DISPLAY UNIX MANUALS
+MDOCML - The mandoc UNIX manpage compiler toolset
diff --git a/usr/src/cmd/mandoc/arch.in b/usr/src/cmd/mandoc/arch.in
deleted file mode 100644
index d0c445f308..0000000000
--- a/usr/src/cmd/mandoc/arch.in
+++ /dev/null
@@ -1,112 +0,0 @@
-/* $Id: arch.in,v 1.14 2013/09/16 22:12:57 schwarze Exp $ */
-/*
- * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/*
- * This file defines the architecture token of the .Dt prologue macro.
- * All architectures that your system supports (or the manuals of your
- * system) should be included here. The right-hand-side is the
- * formatted output.
- *
- * Be sure to escape strings.
- *
- * REMEMBER TO ADD NEW ARCHITECTURES TO MDOC.7!
- */
-
-LINE("acorn26", "Acorn26")
-LINE("acorn32", "Acorn32")
-LINE("algor", "Algor")
-LINE("alpha", "Alpha")
-LINE("amd64", "AMD64")
-LINE("amiga", "Amiga")
-LINE("amigappc", "AmigaPPC")
-LINE("arc", "ARC")
-LINE("arm", "ARM")
-LINE("arm26", "ARM26")
-LINE("arm32", "ARM32")
-LINE("armish", "ARMISH")
-LINE("armv7", "ARMv7")
-LINE("aviion", "AViiON")
-LINE("atari", "ATARI")
-LINE("bebox", "BeBox")
-LINE("cats", "cats")
-LINE("cesfic", "CESFIC")
-LINE("cobalt", "Cobalt")
-LINE("dreamcast", "Dreamcast")
-LINE("emips", "EMIPS")
-LINE("evbarm", "evbARM")
-LINE("evbmips", "evbMIPS")
-LINE("evbppc", "evbPPC")
-LINE("evbsh3", "evbSH3")
-LINE("ews4800mips", "EWS4800MIPS")
-LINE("hp300", "HP300")
-LINE("hp700", "HP700")
-LINE("hpcarm", "HPCARM")
-LINE("hpcmips", "HPCMIPS")
-LINE("hpcsh", "HPCSH")
-LINE("hppa", "HPPA")
-LINE("hppa64", "HPPA64")
-LINE("ia64", "ia64")
-LINE("i386", "i386")
-LINE("ibmnws", "IBMNWS")
-LINE("iyonix", "Iyonix")
-LINE("landisk", "LANDISK")
-LINE("loongson", "Loongson")
-LINE("luna68k", "Luna68k")
-LINE("luna88k", "Luna88k")
-LINE("m68k", "m68k")
-LINE("mac68k", "Mac68k")
-LINE("macppc", "MacPPC")
-LINE("mips", "MIPS")
-LINE("mips64", "MIPS64")
-LINE("mipsco", "MIPSCo")
-LINE("mmeye", "mmEye")
-LINE("mvme68k", "MVME68k")
-LINE("mvme88k", "MVME88k")
-LINE("mvmeppc", "MVMEPPC")
-LINE("netwinder", "NetWinder")
-LINE("news68k", "NeWS68k")
-LINE("newsmips", "NeWSMIPS")
-LINE("next68k", "NeXT68k")
-LINE("octeon", "OCTEON")
-LINE("ofppc", "OFPPC")
-LINE("palm", "Palm")
-LINE("pc532", "PC532")
-LINE("playstation2", "PlayStation2")
-LINE("pmax", "PMAX")
-LINE("pmppc", "pmPPC")
-LINE("powerpc", "PowerPC")
-LINE("prep", "PReP")
-LINE("rs6000", "RS6000")
-LINE("sandpoint", "Sandpoint")
-LINE("sbmips", "SBMIPS")
-LINE("sgi", "SGI")
-LINE("sgimips", "SGIMIPS")
-LINE("sh3", "SH3")
-LINE("shark", "Shark")
-LINE("socppc", "SOCPPC")
-LINE("solbourne", "Solbourne")
-LINE("sparc", "SPARC")
-LINE("sparc64", "SPARC64")
-LINE("sun2", "Sun2")
-LINE("sun3", "Sun3")
-LINE("tahoe", "Tahoe")
-LINE("vax", "VAX")
-LINE("x68k", "X68k")
-LINE("x86", "x86")
-LINE("x86_64", "x86_64")
-LINE("xen", "Xen")
-LINE("zaurus", "Zaurus")
diff --git a/usr/src/cmd/mandoc/att.c b/usr/src/cmd/mandoc/att.c
index 24d757ddf7..a1703ebcc6 100644
--- a/usr/src/cmd/mandoc/att.c
+++ b/usr/src/cmd/mandoc/att.c
@@ -1,4 +1,4 @@
-/* $Id: att.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */
+/* $Id: att.c,v 1.13 2014/11/28 18:57:31 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -14,26 +14,36 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
-#include <stdlib.h>
+#include <sys/types.h>
#include <string.h>
-#include <time.h>
#include "mdoc.h"
-#include "mandoc.h"
#include "libmdoc.h"
#define LINE(x, y) \
- if (0 == strcmp(p, x)) return(y);
+ if (0 == strcmp(p, x)) return(y)
+
const char *
mdoc_a2att(const char *p)
{
-#include "att.in"
+ LINE("v1", "Version\\~1 AT&T UNIX");
+ LINE("v2", "Version\\~2 AT&T UNIX");
+ LINE("v3", "Version\\~3 AT&T UNIX");
+ LINE("v4", "Version\\~4 AT&T UNIX");
+ LINE("v5", "Version\\~5 AT&T UNIX");
+ LINE("v6", "Version\\~6 AT&T UNIX");
+ LINE("v7", "Version\\~7 AT&T UNIX");
+ LINE("32v", "Version\\~32V AT&T UNIX");
+ LINE("III", "AT&T System\\~III UNIX");
+ LINE("V", "AT&T System\\~V UNIX");
+ LINE("V.1", "AT&T System\\~V Release\\~1 UNIX");
+ LINE("V.2", "AT&T System\\~V Release\\~2 UNIX");
+ LINE("V.3", "AT&T System\\~V Release\\~3 UNIX");
+ LINE("V.4", "AT&T System\\~V Release\\~4 UNIX");
return(NULL);
}
diff --git a/usr/src/cmd/mandoc/att.in b/usr/src/cmd/mandoc/att.in
deleted file mode 100644
index b4ef822158..0000000000
--- a/usr/src/cmd/mandoc/att.in
+++ /dev/null
@@ -1,40 +0,0 @@
-/* $Id: att.in,v 1.8 2011/07/31 17:30:33 schwarze Exp $ */
-/*
- * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/*
- * This file defines the AT&T versions of the .At macro. This probably
- * isn't going to change. The right-hand side is the formatted string.
- *
- * Be sure to escape strings.
- * The non-breaking blanks prevent ending an output line right before
- * a number. Groff prevent line breaks at the same places.
- */
-
-LINE("v1", "Version\\~1 AT&T UNIX")
-LINE("v2", "Version\\~2 AT&T UNIX")
-LINE("v3", "Version\\~3 AT&T UNIX")
-LINE("v4", "Version\\~4 AT&T UNIX")
-LINE("v5", "Version\\~5 AT&T UNIX")
-LINE("v6", "Version\\~6 AT&T UNIX")
-LINE("v7", "Version\\~7 AT&T UNIX")
-LINE("32v", "Version\\~32V AT&T UNIX")
-LINE("III", "AT&T System\\~III UNIX")
-LINE("V", "AT&T System\\~V UNIX")
-LINE("V.1", "AT&T System\\~V Release\\~1 UNIX")
-LINE("V.2", "AT&T System\\~V Release\\~2 UNIX")
-LINE("V.3", "AT&T System\\~V Release\\~3 UNIX")
-LINE("V.4", "AT&T System\\~V Release\\~4 UNIX")
diff --git a/usr/src/cmd/mandoc/chars.c b/usr/src/cmd/mandoc/chars.c
index 3ad1f57471..6b5eba9537 100644
--- a/usr/src/cmd/mandoc/chars.c
+++ b/usr/src/cmd/mandoc/chars.c
@@ -1,7 +1,7 @@
-/* $Id: chars.c,v 1.54 2013/06/20 22:39:30 schwarze Exp $ */
+/* $Id: chars.c,v 1.66 2015/02/17 20:37:16 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 2014 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,9 +15,9 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
+
+#include <sys/types.h>
#include <assert.h>
#include <ctype.h>
@@ -25,6 +25,7 @@
#include <string.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libmandoc.h"
#define PRINT_HI 126
@@ -37,7 +38,7 @@ struct ln {
int unicode;
};
-#define LINES_MAX 329
+#define LINES_MAX 332
#define CHAR(in, ch, code) \
{ NULL, (in), (ch), (code) },
@@ -51,9 +52,10 @@ struct mchars {
struct ln **htab;
};
-static const struct ln *find(const struct mchars *,
+static const struct ln *find(const struct mchars *,
const char *, size_t);
+
void
mchars_free(struct mchars *arg)
{
@@ -102,49 +104,55 @@ mchars_spec2cp(const struct mchars *arg, const char *p, size_t sz)
const struct ln *ln;
ln = find(arg, p, sz);
- if (NULL == ln)
- return(-1);
- return(ln->unicode);
+ return(ln != NULL ? ln->unicode : sz == 1 ? (unsigned char)*p : -1);
}
-char
+int
mchars_num2char(const char *p, size_t sz)
{
- int i;
+ int i;
- if ((i = mandoc_strntoi(p, sz, 10)) < 0)
- return('\0');
- return(i > 0 && i < 256 && isprint(i) ?
- /* LINTED */ i : '\0');
+ i = mandoc_strntoi(p, sz, 10);
+ return(i >= 0 && i < 256 ? i : -1);
}
int
mchars_num2uc(const char *p, size_t sz)
{
- int i;
+ int i;
- if ((i = mandoc_strntoi(p, sz, 16)) < 0)
- return('\0');
- /* FIXME: make sure we're not in a bogus range. */
- return(i > 0x80 && i <= 0x10FFFF ? i : '\0');
+ i = mandoc_strntoi(p, sz, 16);
+ assert(i >= 0 && i <= 0x10FFFF);
+ return(i);
}
const char *
-mchars_spec2str(const struct mchars *arg,
+mchars_spec2str(const struct mchars *arg,
const char *p, size_t sz, size_t *rsz)
{
const struct ln *ln;
ln = find(arg, p, sz);
- if (NULL == ln) {
+ if (ln == NULL) {
*rsz = 1;
- return(NULL);
+ return(sz == 1 ? p : NULL);
}
*rsz = strlen(ln->ascii);
return(ln->ascii);
}
+const char *
+mchars_uc2str(int uc)
+{
+ int i;
+
+ for (i = 0; i < LINES_MAX; i++)
+ if (uc == lines[i].unicode)
+ return(lines[i].ascii);
+ return("<?>");
+}
+
static const struct ln *
find(const struct mchars *tab, const char *p, size_t sz)
{
@@ -159,8 +167,8 @@ find(const struct mchars *tab, const char *p, size_t sz)
hash = (int)p[0] - PRINT_LO;
for (pp = tab->htab[hash]; pp; pp = pp->next)
- if (0 == strncmp(pp->code, p, sz) &&
- '\0' == pp->code[(int)sz])
+ if (0 == strncmp(pp->code, p, sz) &&
+ '\0' == pp->code[(int)sz])
return(pp);
return(NULL);
diff --git a/usr/src/cmd/mandoc/chars.in b/usr/src/cmd/mandoc/chars.in
index cc6549e7e5..ac72aba858 100644
--- a/usr/src/cmd/mandoc/chars.in
+++ b/usr/src/cmd/mandoc/chars.in
@@ -1,6 +1,7 @@
-/* $Id: chars.in,v 1.43 2013/06/20 22:39:30 schwarze Exp $ */
+/* $Id: chars.in,v 1.52 2015/02/17 20:37:16 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014 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 +17,7 @@
*/
/*
- * The ASCII translation tables.
+ * The ASCII translation tables.
*
* The left-hand side corresponds to the input sequence (\x, \(xx, \*(xx
* and so on) whose length is listed second element. The right-hand
@@ -27,47 +28,52 @@
* XXX - update LINES_MAX if adding more!
*/
-/* Non-breaking, non-collapsing space uses unit separator. */
+/* Special break control characters. */
static const char ascii_nbrsp[2] = { ASCII_NBRSP, '\0' };
+static const char ascii_break[2] = { ASCII_BREAK, '\0' };
CHAR_TBL_START
/* Spacing. */
-CHAR("c", "", 0)
-CHAR("0", " ", 8194)
CHAR(" ", ascii_nbrsp, 160)
CHAR("~", ascii_nbrsp, 160)
-CHAR("%", "", 0)
-CHAR("&", "", 0)
-CHAR("^", "", 0)
+CHAR("0", " ", 8194)
CHAR("|", "", 0)
-CHAR("}", "", 0)
+CHAR("^", "", 0)
+CHAR("&", "", 0)
+CHAR("%", "", 0)
+CHAR(":", ascii_break, 0)
+/* XXX The following three do not really belong into this file. */
CHAR("t", "", 0)
+CHAR("c", "", 0)
+CHAR("}", "", 0)
/* Accents. */
-CHAR("a\"", "\"", 779)
+CHAR("a\"", "\"", 733)
CHAR("a-", "-", 175)
CHAR("a.", ".", 729)
-CHAR("a^", "^", 770)
-CHAR("\'", "\'", 769)
-CHAR("aa", "\'", 769)
-CHAR("ga", "`", 768)
-CHAR("`", "`", 768)
-CHAR("ab", "`", 774)
-CHAR("ac", ",", 807)
-CHAR("ad", "\"", 776)
+CHAR("a^", "^", 94)
+CHAR("\'", "\'", 180)
+CHAR("aa", "\'", 180)
+CHAR("ga", "`", 96)
+CHAR("`", "`", 96)
+CHAR("ab", "'\b`", 728)
+CHAR("ac", ",", 184)
+CHAR("ad", "\"", 168)
CHAR("ah", "v", 711)
CHAR("ao", "o", 730)
-CHAR("a~", "~", 771)
-CHAR("ho", ",", 808)
+CHAR("a~", "~", 126)
+CHAR("ho", ",", 731)
CHAR("ha", "^", 94)
CHAR("ti", "~", 126)
/* Quotes. */
CHAR("Bq", ",,", 8222)
CHAR("bq", ",", 8218)
-CHAR("lq", "``", 8220)
-CHAR("rq", "\'\'", 8221)
+CHAR("lq", "\"", 8220)
+CHAR("rq", "\"", 8221)
+CHAR("Lq", "``", 8220)
+CHAR("Rq", "''", 8221)
CHAR("oq", "`", 8216)
CHAR("cq", "\'", 8217)
CHAR("aq", "\'", 39)
@@ -82,161 +88,161 @@ CHAR("lB", "[", 91)
CHAR("rB", "]", 93)
CHAR("lC", "{", 123)
CHAR("rC", "}", 125)
-CHAR("la", "<", 60)
-CHAR("ra", ">", 62)
+CHAR("la", "<", 10216)
+CHAR("ra", ">", 10217)
CHAR("bv", "|", 9130)
CHAR("braceex", "|", 9130)
CHAR("bracketlefttp", "|", 9121)
-CHAR("bracketleftbp", "|", 9123)
+CHAR("bracketleftbt", "|", 9123)
CHAR("bracketleftex", "|", 9122)
CHAR("bracketrighttp", "|", 9124)
-CHAR("bracketrightbp", "|", 9126)
+CHAR("bracketrightbt", "|", 9126)
CHAR("bracketrightex", "|", 9125)
CHAR("lt", ",-", 9127)
CHAR("bracelefttp", ",-", 9127)
CHAR("lk", "{", 9128)
CHAR("braceleftmid", "{", 9128)
-CHAR("lb", ",-", 9129)
-CHAR("braceleftbp", "`-", 9129)
+CHAR("lb", "`-", 9129)
+CHAR("braceleftbt", "`-", 9129)
CHAR("braceleftex", "|", 9130)
CHAR("rt", "-.", 9131)
CHAR("bracerighttp", "-.", 9131)
CHAR("rk", "}", 9132)
CHAR("bracerightmid", "}", 9132)
CHAR("rb", "-\'", 9133)
-CHAR("bracerightbp", "-\'", 9133)
+CHAR("bracerightbt", "-\'", 9133)
CHAR("bracerightex", "|", 9130)
CHAR("parenlefttp", "/", 9115)
-CHAR("parenleftbp", "\\", 9117)
+CHAR("parenleftbt", "\\", 9117)
CHAR("parenleftex", "|", 9116)
CHAR("parenrighttp", "\\", 9118)
-CHAR("parenrightbp", "/", 9120)
+CHAR("parenrightbt", "/", 9120)
CHAR("parenrightex", "|", 9119)
/* Greek characters. */
CHAR("*A", "A", 913)
CHAR("*B", "B", 914)
-CHAR("*G", "|", 915)
-CHAR("*D", "/\\", 916)
+CHAR("*G", "G", 915)
+CHAR("*D", "_\b/_\b\\", 916)
CHAR("*E", "E", 917)
CHAR("*Z", "Z", 918)
CHAR("*Y", "H", 919)
-CHAR("*H", "O", 920)
+CHAR("*H", "-\bO", 920)
CHAR("*I", "I", 921)
CHAR("*K", "K", 922)
CHAR("*L", "/\\", 923)
CHAR("*M", "M", 924)
CHAR("*N", "N", 925)
-CHAR("*C", "H", 926)
+CHAR("*C", "_\bH", 926)
CHAR("*O", "O", 927)
CHAR("*P", "TT", 928)
CHAR("*R", "P", 929)
-CHAR("*S", ">", 931)
+CHAR("*S", "S", 931)
CHAR("*T", "T", 932)
CHAR("*U", "Y", 933)
-CHAR("*F", "O_", 934)
+CHAR("*F", "I\bO", 934)
CHAR("*X", "X", 935)
-CHAR("*Q", "Y", 936)
-CHAR("*W", "O", 937)
+CHAR("*Q", "I\bY", 936)
+CHAR("*W", "_\bO", 937)
CHAR("*a", "a", 945)
CHAR("*b", "B", 946)
CHAR("*g", "y", 947)
CHAR("*d", "d", 948)
CHAR("*e", "e", 949)
-CHAR("*z", "C", 950)
+CHAR("*z", ",\bC", 950)
CHAR("*y", "n", 951)
-CHAR("*h", "0", 952)
+CHAR("*h", "-\b0", 952)
CHAR("*i", "i", 953)
CHAR("*k", "k", 954)
-CHAR("*l", "\\", 955)
-CHAR("*m", "u", 956)
+CHAR("*l", ">\b\\", 955)
+CHAR("*m", ",\bu", 956)
CHAR("*n", "v", 957)
-CHAR("*c", "E", 958)
+CHAR("*c", ",\bE", 958)
CHAR("*o", "o", 959)
-CHAR("*p", "n", 960)
+CHAR("*p", "-\bn", 960)
CHAR("*r", "p", 961)
-CHAR("*s", "o", 963)
-CHAR("*t", "t", 964)
+CHAR("*s", "-\bo", 963)
+CHAR("*t", "~\bt", 964)
CHAR("*u", "u", 965)
-CHAR("*f", "o", 981)
+CHAR("*f", "|\bo", 981)
CHAR("*x", "x", 967)
-CHAR("*q", "u", 968)
+CHAR("*q", "|\bu", 968)
CHAR("*w", "w", 969)
-CHAR("+h", "0", 977)
-CHAR("+f", "o", 966)
-CHAR("+p", "w", 982)
+CHAR("+h", "-\b0", 977)
+CHAR("+f", "|\bo", 966)
+CHAR("+p", "-\bw", 982)
CHAR("+e", "e", 1013)
CHAR("ts", "s", 962)
/* Accented letters. */
-CHAR(",C", "C", 199)
-CHAR(",c", "c", 231)
-CHAR("/L", "L", 321)
-CHAR("/O", "O", 216)
-CHAR("/l", "l", 322)
-CHAR("/o", "o", 248)
-CHAR("oA", "A", 197)
-CHAR("oa", "a", 229)
-CHAR(":A", "A", 196)
-CHAR(":E", "E", 203)
-CHAR(":I", "I", 207)
-CHAR(":O", "O", 214)
-CHAR(":U", "U", 220)
-CHAR(":a", "a", 228)
-CHAR(":e", "e", 235)
-CHAR(":i", "i", 239)
-CHAR(":o", "o", 246)
-CHAR(":u", "u", 252)
-CHAR(":y", "y", 255)
-CHAR("\'A", "A", 193)
-CHAR("\'E", "E", 201)
-CHAR("\'I", "I", 205)
-CHAR("\'O", "O", 211)
-CHAR("\'U", "U", 218)
-CHAR("\'a", "a", 225)
-CHAR("\'e", "e", 233)
-CHAR("\'i", "i", 237)
-CHAR("\'o", "o", 243)
-CHAR("\'u", "u", 250)
-CHAR("^A", "A", 194)
-CHAR("^E", "E", 202)
-CHAR("^I", "I", 206)
-CHAR("^O", "O", 212)
-CHAR("^U", "U", 219)
-CHAR("^a", "a", 226)
-CHAR("^e", "e", 234)
-CHAR("^i", "i", 238)
-CHAR("^o", "o", 244)
-CHAR("^u", "u", 251)
-CHAR("`A", "A", 192)
-CHAR("`E", "E", 200)
-CHAR("`I", "I", 204)
-CHAR("`O", "O", 210)
-CHAR("`U", "U", 217)
-CHAR("`a", "a", 224)
-CHAR("`e", "e", 232)
-CHAR("`i", "i", 236)
-CHAR("`o", "o", 242)
-CHAR("`u", "u", 249)
-CHAR("~A", "A", 195)
-CHAR("~N", "N", 209)
-CHAR("~O", "O", 213)
-CHAR("~a", "a", 227)
-CHAR("~n", "n", 241)
-CHAR("~o", "o", 245)
+CHAR(",C", ",\bC", 199)
+CHAR(",c", ",\bc", 231)
+CHAR("/L", "/\bL", 321)
+CHAR("/O", "/\bO", 216)
+CHAR("/l", "/\bl", 322)
+CHAR("/o", "/\bo", 248)
+CHAR("oA", "o\bA", 197)
+CHAR("oa", "o\ba", 229)
+CHAR(":A", "\"\bA", 196)
+CHAR(":E", "\"\bE", 203)
+CHAR(":I", "\"\bI", 207)
+CHAR(":O", "\"\bO", 214)
+CHAR(":U", "\"\bU", 220)
+CHAR(":a", "\"\ba", 228)
+CHAR(":e", "\"\be", 235)
+CHAR(":i", "\"\bi", 239)
+CHAR(":o", "\"\bo", 246)
+CHAR(":u", "\"\bu", 252)
+CHAR(":y", "\"\by", 255)
+CHAR("'A", "'\bA", 193)
+CHAR("'E", "'\bE", 201)
+CHAR("'I", "'\bI", 205)
+CHAR("'O", "'\bO", 211)
+CHAR("'U", "'\bU", 218)
+CHAR("'a", "'\ba", 225)
+CHAR("'e", "'\be", 233)
+CHAR("'i", "'\bi", 237)
+CHAR("'o", "'\bo", 243)
+CHAR("'u", "'\bu", 250)
+CHAR("^A", "^\bA", 194)
+CHAR("^E", "^\bE", 202)
+CHAR("^I", "^\bI", 206)
+CHAR("^O", "^\bO", 212)
+CHAR("^U", "^\bU", 219)
+CHAR("^a", "^\ba", 226)
+CHAR("^e", "^\be", 234)
+CHAR("^i", "^\bi", 238)
+CHAR("^o", "^\bo", 244)
+CHAR("^u", "^\bu", 251)
+CHAR("`A", "`\bA", 192)
+CHAR("`E", "`\bE", 200)
+CHAR("`I", "`\bI", 204)
+CHAR("`O", "`\bO", 210)
+CHAR("`U", "`\bU", 217)
+CHAR("`a", "`\ba", 224)
+CHAR("`e", "`\be", 232)
+CHAR("`i", "`\bi", 236)
+CHAR("`o", "`\bo", 242)
+CHAR("`u", "`\bu", 249)
+CHAR("~A", "~\bA", 195)
+CHAR("~N", "~\bN", 209)
+CHAR("~O", "~\bO", 213)
+CHAR("~a", "~\ba", 227)
+CHAR("~n", "~\bn", 241)
+CHAR("~o", "~\bo", 245)
/* Arrows and lines. */
CHAR("<-", "<-", 8592)
CHAR("->", "->", 8594)
-CHAR("<>", "<>", 8596)
-CHAR("da", "v", 8595)
-CHAR("ua", "^", 8593)
+CHAR("<>", "<->", 8596)
+CHAR("da", "|\bv", 8595)
+CHAR("ua", "|\b^", 8593)
CHAR("va", "^v", 8597)
CHAR("lA", "<=", 8656)
CHAR("rA", "=>", 8658)
CHAR("hA", "<=>", 8660)
-CHAR("dA", "v", 8659)
-CHAR("uA", "^", 8657)
+CHAR("dA", "=\bv", 8659)
+CHAR("uA", "=\b^", 8657)
CHAR("vA", "^=v", 8661)
/* Logic. */
@@ -245,7 +251,7 @@ CHAR("OR", "v", 8744)
CHAR("no", "~", 172)
CHAR("tno", "~", 172)
CHAR("te", "3", 8707)
-CHAR("fa", "V", 8704)
+CHAR("fa", "-\bV", 8704)
CHAR("st", "-)", 8715)
CHAR("tf", ".:.", 8756)
CHAR("3d", ".:.", 8756)
@@ -262,8 +268,8 @@ CHAR("pc", ".", 183)
CHAR("md", ".", 8901)
CHAR("mu", "x", 215)
CHAR("tmu", "x", 215)
-CHAR("c*", "x", 8855)
-CHAR("c+", "+", 8853)
+CHAR("c*", "O\bx", 8855)
+CHAR("c+", "O\b+", 8853)
CHAR("di", "-:-", 247)
CHAR("tdi", "-:-", 247)
CHAR("f/", "/", 8260)
@@ -277,10 +283,10 @@ CHAR("!=", "!=", 8800)
CHAR("==", "==", 8801)
CHAR("ne", "!==", 8802)
CHAR("=~", "=~", 8773)
-CHAR("-~", "-~", 8771)
+CHAR("|=", "-~", 8771)
CHAR("ap", "~", 8764)
CHAR("~~", "~~", 8776)
-CHAR("~=", "~=", 8780)
+CHAR("~=", "~=", 8776)
CHAR("pt", "oc", 8733)
CHAR("es", "{}", 8709)
CHAR("mo", "E", 8712)
@@ -289,14 +295,14 @@ CHAR("sb", "(=", 8834)
CHAR("nb", "(!=", 8836)
CHAR("sp", "=)", 8835)
CHAR("nc", "!=)", 8837)
-CHAR("ib", "(=", 8838)
-CHAR("ip", "=)", 8839)
+CHAR("ib", "(=\b_", 8838)
+CHAR("ip", "=\b_)", 8839)
CHAR("ca", "(^)", 8745)
CHAR("cu", "U", 8746)
-CHAR("/_", "/_", 8736)
-CHAR("pp", "_|_", 8869)
-CHAR("is", "I", 8747)
-CHAR("integral", "I", 8747)
+CHAR("/_", "_\b/", 8736)
+CHAR("pp", "_\b|", 8869)
+CHAR("is", "'\b,\bI", 8747)
+CHAR("integral", "'\b,\bI", 8747)
CHAR("sum", "E", 8721)
CHAR("product", "TT", 8719)
CHAR("coproduct", "U", 8720)
@@ -332,41 +338,41 @@ CHAR("IJ", "IJ", 306)
CHAR("ij", "ij", 307)
/* Special letters. */
-CHAR("-D", "D", 208)
-CHAR("Sd", "o", 240)
-CHAR("TP", "b", 222)
-CHAR("Tp", "b", 254)
+CHAR("-D", "-\bD", 208)
+CHAR("Sd", "d", 240)
+CHAR("TP", "Th", 222)
+CHAR("Tp", "th", 254)
CHAR(".i", "i", 305)
CHAR(".j", "j", 567)
/* Currency. */
CHAR("Do", "$", 36)
-CHAR("ct", "c", 162)
+CHAR("ct", "/\bc", 162)
CHAR("Eu", "EUR", 8364)
CHAR("eu", "EUR", 8364)
-CHAR("Ye", "Y", 165)
-CHAR("Po", "L", 163)
-CHAR("Cs", "x", 164)
-CHAR("Fn", "f", 402)
+CHAR("Ye", "=\bY", 165)
+CHAR("Po", "GBP", 163)
+CHAR("Cs", "o\bx", 164)
+CHAR("Fn", ",\bf", 402)
/* Lines. */
CHAR("ba", "|", 124)
CHAR("br", "|", 9474)
CHAR("ul", "_", 95)
-CHAR("rl", "-", 8254)
+CHAR("rn", "-", 8254)
CHAR("bb", "|", 166)
CHAR("sl", "/", 47)
CHAR("rs", "\\", 92)
/* Text markers. */
-CHAR("ci", "o", 9675)
-CHAR("bu", "o", 8226)
-CHAR("dd", "=", 8225)
-CHAR("dg", "-", 8224)
+CHAR("ci", "O", 9675)
+CHAR("bu", "+\bo", 8226)
+CHAR("dd", "|\b=", 8225)
+CHAR("dg", "|\b-", 8224)
CHAR("lz", "<>", 9674)
CHAR("sq", "[]", 9633)
-CHAR("ps", "9|", 182)
-CHAR("sc", "S", 167)
+CHAR("ps", "<par>", 182)
+CHAR("sc", "<sec>", 167)
CHAR("lh", "<=", 9756)
CHAR("rh", "=>", 9758)
CHAR("at", "@", 64)
@@ -381,18 +387,18 @@ CHAR("tm", "tm", 8482)
/* Punctuation. */
CHAR(".", ".", 46)
-CHAR("r!", "i", 161)
-CHAR("r?", "c", 191)
+CHAR("r!", "!", 161)
+CHAR("r?", "?", 191)
CHAR("em", "--", 8212)
CHAR("en", "-", 8211)
CHAR("hy", "-", 8208)
CHAR("e", "\\", 92)
/* Units. */
-CHAR("de", "o", 176)
+CHAR("de", "<deg>", 176)
CHAR("%0", "%o", 8240)
CHAR("fm", "\'", 8242)
-CHAR("sd", "\"", 8243)
-CHAR("mc", "mu", 181)
+CHAR("sd", "''", 8243)
+CHAR("mc", ",\bu", 181)
CHAR_TBL_END
diff --git a/usr/src/cmd/mandoc/compat_fgetln.c b/usr/src/cmd/mandoc/compat_fgetln.c
new file mode 100644
index 0000000000..3760ab994d
--- /dev/null
+++ b/usr/src/cmd/mandoc/compat_fgetln.c
@@ -0,0 +1,94 @@
+#include "config.h"
+
+#if HAVE_FGETLN
+
+int dummy;
+
+#else
+
+/* $NetBSD: fgetln.c,v 1.3 2006/09/25 07:18:17 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+char *
+fgetln(fp, len)
+ FILE *fp;
+ size_t *len;
+{
+ static char *buf = NULL;
+ static size_t bufsiz = 0;
+ char *ptr;
+
+
+ if (buf == NULL) {
+ bufsiz = BUFSIZ;
+ if ((buf = malloc(bufsiz)) == NULL)
+ return NULL;
+ }
+
+ if (fgets(buf, bufsiz, fp) == NULL)
+ return NULL;
+
+ *len = 0;
+ while ((ptr = strchr(&buf[*len], '\n')) == NULL) {
+ size_t nbufsiz = bufsiz + BUFSIZ;
+ char *nbuf = realloc(buf, nbufsiz);
+
+ if (nbuf == NULL) {
+ int oerrno = errno;
+ free(buf);
+ errno = oerrno;
+ buf = NULL;
+ return NULL;
+ } else
+ buf = nbuf;
+
+ *len = bufsiz;
+ if (fgets(&buf[bufsiz], BUFSIZ, fp) == NULL)
+ return buf;
+
+ bufsiz = nbufsiz;
+ }
+
+ *len = (ptr - buf) + 1;
+ return buf;
+}
+
+#endif
diff --git a/usr/src/cmd/mandoc/compat_reallocarray.c b/usr/src/cmd/mandoc/compat_reallocarray.c
new file mode 100644
index 0000000000..6615190425
--- /dev/null
+++ b/usr/src/cmd/mandoc/compat_reallocarray.c
@@ -0,0 +1,49 @@
+#include "config.h"
+
+#if HAVE_REALLOCARRAY
+
+int dummy;
+
+#else
+
+/* $Id: compat_reallocarray.c,v 1.4 2014/12/11 09:05:01 schwarze Exp $ */
+/* $OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $ */
+/*
+ * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * 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 <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+/*
+ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
+ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
+ */
+#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
+
+void *
+reallocarray(void *optr, size_t nmemb, size_t size)
+{
+ if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ nmemb > 0 && SIZE_MAX / nmemb < size) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ return realloc(optr, size * nmemb);
+}
+
+#endif /*!HAVE_REALLOCARRAY*/
diff --git a/usr/src/cmd/mandoc/compat_strtonum.c b/usr/src/cmd/mandoc/compat_strtonum.c
new file mode 100644
index 0000000000..628e5d51b8
--- /dev/null
+++ b/usr/src/cmd/mandoc/compat_strtonum.c
@@ -0,0 +1,76 @@
+#include "config.h"
+
+#if HAVE_STRTONUM
+
+int dummy;
+
+#else
+
+/* $Id: compat_strtonum.c,v 1.1 2015/02/16 14:56:22 schwarze Exp $ */
+/* $OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $ */
+
+/*
+ * Copyright (c) 2004 Ted Unangst and Todd Miller
+ * All rights reserved.
+ *
+ * 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 <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#define INVALID 1
+#define TOOSMALL 2
+#define TOOLARGE 3
+
+long long
+strtonum(const char *numstr, long long minval, long long maxval,
+ const char **errstrp)
+{
+ long long ll = 0;
+ int error = 0;
+ char *ep;
+ struct errval {
+ const char *errstr;
+ int err;
+ } ev[4] = {
+ { NULL, 0 },
+ { "invalid", EINVAL },
+ { "too small", ERANGE },
+ { "too large", ERANGE },
+ };
+
+ ev[0].err = errno;
+ errno = 0;
+ if (minval > maxval) {
+ error = INVALID;
+ } else {
+ ll = strtoll(numstr, &ep, 10);
+ if (numstr == ep || *ep != '\0')
+ error = INVALID;
+ else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
+ error = TOOSMALL;
+ else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
+ error = TOOLARGE;
+ }
+ if (errstrp != NULL)
+ *errstrp = ev[error].errstr;
+ errno = ev[error].err;
+ if (error)
+ ll = 0;
+
+ return (ll);
+}
+
+#endif /* !HAVE_STRTONUM */
diff --git a/usr/src/cmd/mandoc/config.h b/usr/src/cmd/mandoc/config.h
index 7f4f1edf09..040fc56e39 100644
--- a/usr/src/cmd/mandoc/config.h
+++ b/usr/src/cmd/mandoc/config.h
@@ -1,20 +1,35 @@
-#ifndef MANDOC_CONFIG_H
-#define MANDOC_CONFIG_H
+#ifndef MANDOC_CONFIG_H
+#define MANDOC_CONFIG_H
#if defined(__linux__) || defined(__MINT__)
-# define _GNU_SOURCE /* strptime(), getsubopt() */
+#define _GNU_SOURCE /* See test-*.c what needs this. */
#endif
+#include <sys/types.h>
#include <stdio.h>
-#define VERSION "1.12.3"
-#define HAVE_STRPTIME
-#define HAVE_GETSUBOPT
-#define HAVE_STRLCAT
-#define HAVE_STRLCPY
-#define HAVE_MMAP
-
-#include <sys/types.h>
+#define HAVE_DIRENT_NAMLEN 0
+#define HAVE_FGETLN 0
+#define HAVE_FTS 0
+#define HAVE_GETSUBOPT 1
+#define HAVE_MMAP 1
+#define HAVE_REALLOCARRAY 0
+#define HAVE_STRCASESTR 1
+#define HAVE_STRLCAT 1
+#define HAVE_STRLCPY 1
+#define HAVE_STRPTIME 1
+#define HAVE_STRSEP 1
+#define HAVE_STRTONUM 0
+#define HAVE_WCHAR 1
+#define HAVE_SQLITE3 0
+#define HAVE_SQLITE3_ERRSTR 1
+#define HAVE_OHASH 1
+#define HAVE_MANPATH 0
+
+#define BINM_APROPOS "apropos"
+#define BINM_MAN "man"
+#define BINM_WHATIS "whatis"
+#define BINM_MAKEWHATIS "makewhatis"
#if !defined(__BEGIN_DECLS)
# ifdef __cplusplus
@@ -31,30 +46,13 @@
# endif
#endif
-#ifndef HAVE_BETOH64
-# if defined(__APPLE__)
-# define betoh64(x) OSSwapBigToHostInt64(x)
-# define htobe64(x) OSSwapHostToBigInt64(x)
-# elif defined(__sun)
-# define betoh64(x) BE_64(x)
-# define htobe64(x) BE_64(x)
-# else
-# define betoh64(x) be64toh(x)
-# endif
-#endif
-
-#ifndef HAVE_STRLCAT
+extern char *fgetln(FILE *, size_t *);
+extern int getsubopt(char **, char * const *, char **);
+extern void *reallocarray(void *, size_t, size_t);
+extern char *strcasestr(const char *, const char *);
extern size_t strlcat(char *, const char *, size_t);
-#endif
-#ifndef HAVE_STRLCPY
extern size_t strlcpy(char *, const char *, size_t);
-#endif
-#ifndef HAVE_GETSUBOPT
-extern int getsubopt(char **, char * const *, char **);
-extern char *suboptarg;
-#endif
-#ifndef HAVE_FGETLN
-extern char *fgetln(FILE *, size_t *);
-#endif
+extern char *strsep(char **, const char *);
+extern long long strtonum(const char *, long long, long long, const char **);
#endif /* MANDOC_CONFIG_H */
diff --git a/usr/src/cmd/mandoc/eqn.c b/usr/src/cmd/mandoc/eqn.c
index 37f01bcb5b..9da57f06e2 100644
--- a/usr/src/cmd/mandoc/eqn.c
+++ b/usr/src/cmd/mandoc/eqn.c
@@ -1,6 +1,7 @@
-/* $Id: eqn.c,v 1.38 2011/07/25 15:37:00 kristaps Exp $ */
+/* $Id: eqn.c,v 1.58 2015/03/04 12:19:49 schwarze Exp $ */
/*
- * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014, 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
@@ -14,9 +15,9 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
+
+#include <sys/types.h>
#include <assert.h>
#include <limits.h>
@@ -26,17 +27,111 @@
#include <time.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libmandoc.h"
#include "libroff.h"
#define EQN_NEST_MAX 128 /* maximum nesting of defines */
-#define EQN_MSG(t, x) mandoc_msg((t), (x)->parse, (x)->eqn.ln, (x)->eqn.pos, NULL)
+#define STRNEQ(p1, sz1, p2, sz2) \
+ ((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1)))
-enum eqn_rest {
- EQN_DESCOPE,
- EQN_ERR,
- EQN_OK,
- EQN_EOF
+enum eqn_tok {
+ EQN_TOK_DYAD = 0,
+ EQN_TOK_VEC,
+ EQN_TOK_UNDER,
+ EQN_TOK_BAR,
+ EQN_TOK_TILDE,
+ EQN_TOK_HAT,
+ EQN_TOK_DOT,
+ EQN_TOK_DOTDOT,
+ EQN_TOK_FWD,
+ EQN_TOK_BACK,
+ EQN_TOK_DOWN,
+ EQN_TOK_UP,
+ EQN_TOK_FAT,
+ EQN_TOK_ROMAN,
+ EQN_TOK_ITALIC,
+ EQN_TOK_BOLD,
+ EQN_TOK_SIZE,
+ EQN_TOK_SUB,
+ EQN_TOK_SUP,
+ EQN_TOK_SQRT,
+ EQN_TOK_OVER,
+ EQN_TOK_FROM,
+ EQN_TOK_TO,
+ EQN_TOK_BRACE_OPEN,
+ EQN_TOK_BRACE_CLOSE,
+ EQN_TOK_GSIZE,
+ EQN_TOK_GFONT,
+ EQN_TOK_MARK,
+ EQN_TOK_LINEUP,
+ EQN_TOK_LEFT,
+ EQN_TOK_RIGHT,
+ EQN_TOK_PILE,
+ EQN_TOK_LPILE,
+ EQN_TOK_RPILE,
+ EQN_TOK_CPILE,
+ EQN_TOK_MATRIX,
+ EQN_TOK_CCOL,
+ EQN_TOK_LCOL,
+ EQN_TOK_RCOL,
+ EQN_TOK_DELIM,
+ EQN_TOK_DEFINE,
+ EQN_TOK_TDEFINE,
+ EQN_TOK_NDEFINE,
+ EQN_TOK_UNDEF,
+ EQN_TOK_EOF,
+ EQN_TOK_ABOVE,
+ EQN_TOK__MAX
+};
+
+static const char *eqn_toks[EQN_TOK__MAX] = {
+ "dyad", /* EQN_TOK_DYAD */
+ "vec", /* EQN_TOK_VEC */
+ "under", /* EQN_TOK_UNDER */
+ "bar", /* EQN_TOK_BAR */
+ "tilde", /* EQN_TOK_TILDE */
+ "hat", /* EQN_TOK_HAT */
+ "dot", /* EQN_TOK_DOT */
+ "dotdot", /* EQN_TOK_DOTDOT */
+ "fwd", /* EQN_TOK_FWD * */
+ "back", /* EQN_TOK_BACK */
+ "down", /* EQN_TOK_DOWN */
+ "up", /* EQN_TOK_UP */
+ "fat", /* EQN_TOK_FAT */
+ "roman", /* EQN_TOK_ROMAN */
+ "italic", /* EQN_TOK_ITALIC */
+ "bold", /* EQN_TOK_BOLD */
+ "size", /* EQN_TOK_SIZE */
+ "sub", /* EQN_TOK_SUB */
+ "sup", /* EQN_TOK_SUP */
+ "sqrt", /* EQN_TOK_SQRT */
+ "over", /* EQN_TOK_OVER */
+ "from", /* EQN_TOK_FROM */
+ "to", /* EQN_TOK_TO */
+ "{", /* EQN_TOK_BRACE_OPEN */
+ "}", /* EQN_TOK_BRACE_CLOSE */
+ "gsize", /* EQN_TOK_GSIZE */
+ "gfont", /* EQN_TOK_GFONT */
+ "mark", /* EQN_TOK_MARK */
+ "lineup", /* EQN_TOK_LINEUP */
+ "left", /* EQN_TOK_LEFT */
+ "right", /* EQN_TOK_RIGHT */
+ "pile", /* EQN_TOK_PILE */
+ "lpile", /* EQN_TOK_LPILE */
+ "rpile", /* EQN_TOK_RPILE */
+ "cpile", /* EQN_TOK_CPILE */
+ "matrix", /* EQN_TOK_MATRIX */
+ "ccol", /* EQN_TOK_CCOL */
+ "lcol", /* EQN_TOK_LCOL */
+ "rcol", /* EQN_TOK_RCOL */
+ "delim", /* EQN_TOK_DELIM */
+ "define", /* EQN_TOK_DEFINE */
+ "tdefine", /* EQN_TOK_TDEFINE */
+ "ndefine", /* EQN_TOK_NDEFINE */
+ "undef", /* EQN_TOK_UNDEF */
+ NULL, /* EQN_TOK_EOF */
+ "above", /* EQN_TOK_ABOVE */
};
enum eqn_symt {
@@ -99,187 +194,95 @@ enum eqn_symt {
EQNSYM_equiv,
EQNSYM_lessequal,
EQNSYM_moreequal,
+ EQNSYM_minus,
EQNSYM__MAX
};
-enum eqnpartt {
- EQN_DEFINE = 0,
- EQN_NDEFINE,
- EQN_TDEFINE,
- EQN_SET,
- EQN_UNDEF,
- EQN_GFONT,
- EQN_GSIZE,
- EQN_BACK,
- EQN_FWD,
- EQN_UP,
- EQN_DOWN,
- EQN__MAX
-};
-
-struct eqnstr {
- const char *name;
- size_t sz;
-};
-
-#define STRNEQ(p1, sz1, p2, sz2) \
- ((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1)))
-#define EQNSTREQ(x, p, sz) \
- STRNEQ((x)->name, (x)->sz, (p), (sz))
-
-struct eqnpart {
- struct eqnstr str;
- int (*fp)(struct eqn_node *);
-};
-
struct eqnsym {
- struct eqnstr str;
+ const char *str;
const char *sym;
};
+static const struct eqnsym eqnsyms[EQNSYM__MAX] = {
+ { "alpha", "*a" }, /* EQNSYM_alpha */
+ { "beta", "*b" }, /* EQNSYM_beta */
+ { "chi", "*x" }, /* EQNSYM_chi */
+ { "delta", "*d" }, /* EQNSYM_delta */
+ { "epsilon", "*e" }, /* EQNSYM_epsilon */
+ { "eta", "*y" }, /* EQNSYM_eta */
+ { "gamma", "*g" }, /* EQNSYM_gamma */
+ { "iota", "*i" }, /* EQNSYM_iota */
+ { "kappa", "*k" }, /* EQNSYM_kappa */
+ { "lambda", "*l" }, /* EQNSYM_lambda */
+ { "mu", "*m" }, /* EQNSYM_mu */
+ { "nu", "*n" }, /* EQNSYM_nu */
+ { "omega", "*w" }, /* EQNSYM_omega */
+ { "omicron", "*o" }, /* EQNSYM_omicron */
+ { "phi", "*f" }, /* EQNSYM_phi */
+ { "pi", "*p" }, /* EQNSYM_pi */
+ { "psi", "*q" }, /* EQNSYM_psi */
+ { "rho", "*r" }, /* EQNSYM_rho */
+ { "sigma", "*s" }, /* EQNSYM_sigma */
+ { "tau", "*t" }, /* EQNSYM_tau */
+ { "theta", "*h" }, /* EQNSYM_theta */
+ { "upsilon", "*u" }, /* EQNSYM_upsilon */
+ { "xi", "*c" }, /* EQNSYM_xi */
+ { "zeta", "*z" }, /* EQNSYM_zeta */
+ { "DELTA", "*D" }, /* EQNSYM_DELTA */
+ { "GAMMA", "*G" }, /* EQNSYM_GAMMA */
+ { "LAMBDA", "*L" }, /* EQNSYM_LAMBDA */
+ { "OMEGA", "*W" }, /* EQNSYM_OMEGA */
+ { "PHI", "*F" }, /* EQNSYM_PHI */
+ { "PI", "*P" }, /* EQNSYM_PI */
+ { "PSI", "*Q" }, /* EQNSYM_PSI */
+ { "SIGMA", "*S" }, /* EQNSYM_SIGMA */
+ { "THETA", "*H" }, /* EQNSYM_THETA */
+ { "UPSILON", "*U" }, /* EQNSYM_UPSILON */
+ { "XI", "*C" }, /* EQNSYM_XI */
+ { "inter", "ca" }, /* EQNSYM_inter */
+ { "union", "cu" }, /* EQNSYM_union */
+ { "prod", "product" }, /* EQNSYM_prod */
+ { "int", "integral" }, /* EQNSYM_int */
+ { "sum", "sum" }, /* EQNSYM_sum */
+ { "grad", "gr" }, /* EQNSYM_grad */
+ { "del", "gr" }, /* EQNSYM_del */
+ { "times", "mu" }, /* EQNSYM_times */
+ { "cdot", "pc" }, /* EQNSYM_cdot */
+ { "nothing", "&" }, /* EQNSYM_nothing */
+ { "approx", "~~" }, /* EQNSYM_approx */
+ { "prime", "fm" }, /* EQNSYM_prime */
+ { "half", "12" }, /* EQNSYM_half */
+ { "partial", "pd" }, /* EQNSYM_partial */
+ { "inf", "if" }, /* EQNSYM_inf */
+ { ">>", ">>" }, /* EQNSYM_muchgreat */
+ { "<<", "<<" }, /* EQNSYM_muchless */
+ { "<-", "<-" }, /* EQNSYM_larrow */
+ { "->", "->" }, /* EQNSYM_rarrow */
+ { "+-", "+-" }, /* EQNSYM_pm */
+ { "!=", "!=" }, /* EQNSYM_nequal */
+ { "==", "==" }, /* EQNSYM_equiv */
+ { "<=", "<=" }, /* EQNSYM_lessequal */
+ { ">=", ">=" }, /* EQNSYM_moreequal */
+ { "-", "mi" }, /* EQNSYM_minus */
+};
-static enum eqn_rest eqn_box(struct eqn_node *, struct eqn_box *);
-static struct eqn_box *eqn_box_alloc(struct eqn_node *,
- struct eqn_box *);
+static struct eqn_box *eqn_box_alloc(struct eqn_node *, struct eqn_box *);
static void eqn_box_free(struct eqn_box *);
-static struct eqn_def *eqn_def_find(struct eqn_node *,
- const char *, size_t);
-static int eqn_do_gfont(struct eqn_node *);
-static int eqn_do_gsize(struct eqn_node *);
-static int eqn_do_define(struct eqn_node *);
-static int eqn_do_ign1(struct eqn_node *);
-static int eqn_do_ign2(struct eqn_node *);
-static int eqn_do_tdefine(struct eqn_node *);
-static int eqn_do_undef(struct eqn_node *);
-static enum eqn_rest eqn_eqn(struct eqn_node *, struct eqn_box *);
-static enum eqn_rest eqn_list(struct eqn_node *, struct eqn_box *);
-static enum eqn_rest eqn_matrix(struct eqn_node *, struct eqn_box *);
-static const char *eqn_nexttok(struct eqn_node *, size_t *);
+static struct eqn_box *eqn_box_makebinary(struct eqn_node *,
+ enum eqn_post, struct eqn_box *);
+static void eqn_def(struct eqn_node *);
+static struct eqn_def *eqn_def_find(struct eqn_node *, const char *, size_t);
+static void eqn_delim(struct eqn_node *);
+static const char *eqn_next(struct eqn_node *, char, size_t *, int);
static const char *eqn_nextrawtok(struct eqn_node *, size_t *);
-static const char *eqn_next(struct eqn_node *,
- char, size_t *, int);
-static void eqn_rewind(struct eqn_node *);
-
-static const struct eqnpart eqnparts[EQN__MAX] = {
- { { "define", 6 }, eqn_do_define }, /* EQN_DEFINE */
- { { "ndefine", 7 }, eqn_do_define }, /* EQN_NDEFINE */
- { { "tdefine", 7 }, eqn_do_tdefine }, /* EQN_TDEFINE */
- { { "set", 3 }, eqn_do_ign2 }, /* EQN_SET */
- { { "undef", 5 }, eqn_do_undef }, /* EQN_UNDEF */
- { { "gfont", 5 }, eqn_do_gfont }, /* EQN_GFONT */
- { { "gsize", 5 }, eqn_do_gsize }, /* EQN_GSIZE */
- { { "back", 4 }, eqn_do_ign1 }, /* EQN_BACK */
- { { "fwd", 3 }, eqn_do_ign1 }, /* EQN_FWD */
- { { "up", 2 }, eqn_do_ign1 }, /* EQN_UP */
- { { "down", 4 }, eqn_do_ign1 }, /* EQN_DOWN */
-};
-
-static const struct eqnstr eqnmarks[EQNMARK__MAX] = {
- { "", 0 }, /* EQNMARK_NONE */
- { "dot", 3 }, /* EQNMARK_DOT */
- { "dotdot", 6 }, /* EQNMARK_DOTDOT */
- { "hat", 3 }, /* EQNMARK_HAT */
- { "tilde", 5 }, /* EQNMARK_TILDE */
- { "vec", 3 }, /* EQNMARK_VEC */
- { "dyad", 4 }, /* EQNMARK_DYAD */
- { "bar", 3 }, /* EQNMARK_BAR */
- { "under", 5 }, /* EQNMARK_UNDER */
-};
-
-static const struct eqnstr eqnfonts[EQNFONT__MAX] = {
- { "", 0 }, /* EQNFONT_NONE */
- { "roman", 5 }, /* EQNFONT_ROMAN */
- { "bold", 4 }, /* EQNFONT_BOLD */
- { "fat", 3 }, /* EQNFONT_FAT */
- { "italic", 6 }, /* EQNFONT_ITALIC */
-};
-
-static const struct eqnstr eqnposs[EQNPOS__MAX] = {
- { "", 0 }, /* EQNPOS_NONE */
- { "over", 4 }, /* EQNPOS_OVER */
- { "sup", 3 }, /* EQNPOS_SUP */
- { "sub", 3 }, /* EQNPOS_SUB */
- { "to", 2 }, /* EQNPOS_TO */
- { "from", 4 }, /* EQNPOS_FROM */
-};
-
-static const struct eqnstr eqnpiles[EQNPILE__MAX] = {
- { "", 0 }, /* EQNPILE_NONE */
- { "pile", 4 }, /* EQNPILE_PILE */
- { "cpile", 5 }, /* EQNPILE_CPILE */
- { "rpile", 5 }, /* EQNPILE_RPILE */
- { "lpile", 5 }, /* EQNPILE_LPILE */
- { "col", 3 }, /* EQNPILE_COL */
- { "ccol", 4 }, /* EQNPILE_CCOL */
- { "rcol", 4 }, /* EQNPILE_RCOL */
- { "lcol", 4 }, /* EQNPILE_LCOL */
-};
+static const char *eqn_nexttok(struct eqn_node *, size_t *);
+static enum rofferr eqn_parse(struct eqn_node *, struct eqn_box *);
+static enum eqn_tok eqn_tok_parse(struct eqn_node *, char **);
+static void eqn_undef(struct eqn_node *);
-static const struct eqnsym eqnsyms[EQNSYM__MAX] = {
- { { "alpha", 5 }, "*a" }, /* EQNSYM_alpha */
- { { "beta", 4 }, "*b" }, /* EQNSYM_beta */
- { { "chi", 3 }, "*x" }, /* EQNSYM_chi */
- { { "delta", 5 }, "*d" }, /* EQNSYM_delta */
- { { "epsilon", 7 }, "*e" }, /* EQNSYM_epsilon */
- { { "eta", 3 }, "*y" }, /* EQNSYM_eta */
- { { "gamma", 5 }, "*g" }, /* EQNSYM_gamma */
- { { "iota", 4 }, "*i" }, /* EQNSYM_iota */
- { { "kappa", 5 }, "*k" }, /* EQNSYM_kappa */
- { { "lambda", 6 }, "*l" }, /* EQNSYM_lambda */
- { { "mu", 2 }, "*m" }, /* EQNSYM_mu */
- { { "nu", 2 }, "*n" }, /* EQNSYM_nu */
- { { "omega", 5 }, "*w" }, /* EQNSYM_omega */
- { { "omicron", 7 }, "*o" }, /* EQNSYM_omicron */
- { { "phi", 3 }, "*f" }, /* EQNSYM_phi */
- { { "pi", 2 }, "*p" }, /* EQNSYM_pi */
- { { "psi", 2 }, "*q" }, /* EQNSYM_psi */
- { { "rho", 3 }, "*r" }, /* EQNSYM_rho */
- { { "sigma", 5 }, "*s" }, /* EQNSYM_sigma */
- { { "tau", 3 }, "*t" }, /* EQNSYM_tau */
- { { "theta", 5 }, "*h" }, /* EQNSYM_theta */
- { { "upsilon", 7 }, "*u" }, /* EQNSYM_upsilon */
- { { "xi", 2 }, "*c" }, /* EQNSYM_xi */
- { { "zeta", 4 }, "*z" }, /* EQNSYM_zeta */
- { { "DELTA", 5 }, "*D" }, /* EQNSYM_DELTA */
- { { "GAMMA", 5 }, "*G" }, /* EQNSYM_GAMMA */
- { { "LAMBDA", 6 }, "*L" }, /* EQNSYM_LAMBDA */
- { { "OMEGA", 5 }, "*W" }, /* EQNSYM_OMEGA */
- { { "PHI", 3 }, "*F" }, /* EQNSYM_PHI */
- { { "PI", 2 }, "*P" }, /* EQNSYM_PI */
- { { "PSI", 3 }, "*Q" }, /* EQNSYM_PSI */
- { { "SIGMA", 5 }, "*S" }, /* EQNSYM_SIGMA */
- { { "THETA", 5 }, "*H" }, /* EQNSYM_THETA */
- { { "UPSILON", 7 }, "*U" }, /* EQNSYM_UPSILON */
- { { "XI", 2 }, "*C" }, /* EQNSYM_XI */
- { { "inter", 5 }, "ca" }, /* EQNSYM_inter */
- { { "union", 5 }, "cu" }, /* EQNSYM_union */
- { { "prod", 4 }, "product" }, /* EQNSYM_prod */
- { { "int", 3 }, "integral" }, /* EQNSYM_int */
- { { "sum", 3 }, "sum" }, /* EQNSYM_sum */
- { { "grad", 4 }, "gr" }, /* EQNSYM_grad */
- { { "del", 3 }, "gr" }, /* EQNSYM_del */
- { { "times", 5 }, "mu" }, /* EQNSYM_times */
- { { "cdot", 4 }, "pc" }, /* EQNSYM_cdot */
- { { "nothing", 7 }, "&" }, /* EQNSYM_nothing */
- { { "approx", 6 }, "~~" }, /* EQNSYM_approx */
- { { "prime", 5 }, "aq" }, /* EQNSYM_prime */
- { { "half", 4 }, "12" }, /* EQNSYM_half */
- { { "partial", 7 }, "pd" }, /* EQNSYM_partial */
- { { "inf", 3 }, "if" }, /* EQNSYM_inf */
- { { ">>", 2 }, ">>" }, /* EQNSYM_muchgreat */
- { { "<<", 2 }, "<<" }, /* EQNSYM_muchless */
- { { "<-", 2 }, "<-" }, /* EQNSYM_larrow */
- { { "->", 2 }, "->" }, /* EQNSYM_rarrow */
- { { "+-", 2 }, "+-" }, /* EQNSYM_pm */
- { { "!=", 2 }, "!=" }, /* EQNSYM_nequal */
- { { "==", 2 }, "==" }, /* EQNSYM_equiv */
- { { "<=", 2 }, "<=" }, /* EQNSYM_lessequal */
- { { ">=", 2 }, ">=" }, /* EQNSYM_moreequal */
-};
-/* ARGSUSED */
enum rofferr
-eqn_read(struct eqn_node **epp, int ln,
+eqn_read(struct eqn_node **epp, int ln,
const char *p, int pos, int *offs)
{
size_t sz;
@@ -298,9 +301,10 @@ eqn_read(struct eqn_node **epp, int ln,
p += 3;
while (' ' == *p || '\t' == *p)
p++;
- if ('\0' == *p)
+ if ('\0' == *p)
return(er);
- mandoc_msg(MANDOCERR_ARGSLOST, ep->parse, ln, pos, NULL);
+ mandoc_vmsg(MANDOCERR_ARG_SKIP, ep->parse,
+ ln, pos, "EN %s", p);
return(er);
}
@@ -324,24 +328,12 @@ eqn_read(struct eqn_node **epp, int ln,
}
struct eqn_node *
-eqn_alloc(const char *name, int pos, int line, struct mparse *parse)
+eqn_alloc(int pos, int line, struct mparse *parse)
{
struct eqn_node *p;
- size_t sz;
- const char *end;
p = mandoc_calloc(1, sizeof(struct eqn_node));
- if (name && '\0' != *name) {
- sz = strlen(name);
- assert(sz);
- do {
- sz--;
- end = name + (int)sz;
- } while (' ' == *end || '\t' == *end);
- p->eqn.name = mandoc_strndup(name, sz + 1);
- }
-
p->parse = parse;
p->eqn.ln = line;
p->eqn.pos = pos;
@@ -350,366 +342,27 @@ eqn_alloc(const char *name, int pos, int line, struct mparse *parse)
return(p);
}
-enum rofferr
-eqn_end(struct eqn_node **epp)
-{
- struct eqn_node *ep;
- struct eqn_box *root;
- enum eqn_rest c;
-
- ep = *epp;
- *epp = NULL;
-
- ep->eqn.root = mandoc_calloc(1, sizeof(struct eqn_box));
-
- root = ep->eqn.root;
- root->type = EQN_ROOT;
-
- if (0 == ep->sz)
- return(ROFF_IGN);
-
- if (EQN_DESCOPE == (c = eqn_eqn(ep, root))) {
- EQN_MSG(MANDOCERR_EQNNSCOPE, ep);
- c = EQN_ERR;
- }
-
- return(EQN_EOF == c ? ROFF_EQN : ROFF_IGN);
-}
-
-static enum eqn_rest
-eqn_eqn(struct eqn_node *ep, struct eqn_box *last)
-{
- struct eqn_box *bp;
- enum eqn_rest c;
-
- bp = eqn_box_alloc(ep, last);
- bp->type = EQN_SUBEXPR;
-
- while (EQN_OK == (c = eqn_box(ep, bp)))
- /* Spin! */ ;
-
- return(c);
-}
-
-static enum eqn_rest
-eqn_matrix(struct eqn_node *ep, struct eqn_box *last)
-{
- struct eqn_box *bp;
- const char *start;
- size_t sz;
- enum eqn_rest c;
-
- bp = eqn_box_alloc(ep, last);
- bp->type = EQN_MATRIX;
-
- if (NULL == (start = eqn_nexttok(ep, &sz))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(EQN_ERR);
- }
- if ( ! STRNEQ(start, sz, "{", 1)) {
- EQN_MSG(MANDOCERR_EQNSYNT, ep);
- return(EQN_ERR);
- }
-
- while (EQN_OK == (c = eqn_box(ep, bp)))
- switch (bp->last->pile) {
- case (EQNPILE_LCOL):
- /* FALLTHROUGH */
- case (EQNPILE_CCOL):
- /* FALLTHROUGH */
- case (EQNPILE_RCOL):
- continue;
- default:
- EQN_MSG(MANDOCERR_EQNSYNT, ep);
- return(EQN_ERR);
- };
-
- if (EQN_DESCOPE != c) {
- if (EQN_EOF == c)
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(EQN_ERR);
- }
-
- eqn_rewind(ep);
- start = eqn_nexttok(ep, &sz);
- assert(start);
- if (STRNEQ(start, sz, "}", 1))
- return(EQN_OK);
-
- EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
- return(EQN_ERR);
-}
-
-static enum eqn_rest
-eqn_list(struct eqn_node *ep, struct eqn_box *last)
-{
- struct eqn_box *bp;
- const char *start;
- size_t sz;
- enum eqn_rest c;
-
- bp = eqn_box_alloc(ep, last);
- bp->type = EQN_LIST;
-
- if (NULL == (start = eqn_nexttok(ep, &sz))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(EQN_ERR);
- }
- if ( ! STRNEQ(start, sz, "{", 1)) {
- EQN_MSG(MANDOCERR_EQNSYNT, ep);
- return(EQN_ERR);
- }
-
- while (EQN_DESCOPE == (c = eqn_eqn(ep, bp))) {
- eqn_rewind(ep);
- start = eqn_nexttok(ep, &sz);
- assert(start);
- if ( ! STRNEQ(start, sz, "above", 5))
- break;
- }
-
- if (EQN_DESCOPE != c) {
- if (EQN_ERR != c)
- EQN_MSG(MANDOCERR_EQNSCOPE, ep);
- return(EQN_ERR);
- }
-
- eqn_rewind(ep);
- start = eqn_nexttok(ep, &sz);
- assert(start);
- if (STRNEQ(start, sz, "}", 1))
- return(EQN_OK);
-
- EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
- return(EQN_ERR);
-}
-
-static enum eqn_rest
-eqn_box(struct eqn_node *ep, struct eqn_box *last)
-{
- size_t sz;
- const char *start;
- char *left;
- char sym[64];
- enum eqn_rest c;
- int i, size;
- struct eqn_box *bp;
-
- if (NULL == (start = eqn_nexttok(ep, &sz)))
- return(EQN_EOF);
-
- if (STRNEQ(start, sz, "}", 1))
- return(EQN_DESCOPE);
- else if (STRNEQ(start, sz, "right", 5))
- return(EQN_DESCOPE);
- else if (STRNEQ(start, sz, "above", 5))
- return(EQN_DESCOPE);
- else if (STRNEQ(start, sz, "mark", 4))
- return(EQN_OK);
- else if (STRNEQ(start, sz, "lineup", 6))
- return(EQN_OK);
-
- for (i = 0; i < (int)EQN__MAX; i++) {
- if ( ! EQNSTREQ(&eqnparts[i].str, start, sz))
- continue;
- return((*eqnparts[i].fp)(ep) ?
- EQN_OK : EQN_ERR);
- }
-
- if (STRNEQ(start, sz, "{", 1)) {
- if (EQN_DESCOPE != (c = eqn_eqn(ep, last))) {
- if (EQN_ERR != c)
- EQN_MSG(MANDOCERR_EQNSCOPE, ep);
- return(EQN_ERR);
- }
- eqn_rewind(ep);
- start = eqn_nexttok(ep, &sz);
- assert(start);
- if (STRNEQ(start, sz, "}", 1))
- return(EQN_OK);
- EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
- return(EQN_ERR);
- }
-
- for (i = 0; i < (int)EQNPILE__MAX; i++) {
- if ( ! EQNSTREQ(&eqnpiles[i], start, sz))
- continue;
- if (EQN_OK == (c = eqn_list(ep, last)))
- last->last->pile = (enum eqn_pilet)i;
- return(c);
- }
-
- if (STRNEQ(start, sz, "matrix", 6))
- return(eqn_matrix(ep, last));
-
- if (STRNEQ(start, sz, "left", 4)) {
- if (NULL == (start = eqn_nexttok(ep, &sz))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(EQN_ERR);
- }
- left = mandoc_strndup(start, sz);
- c = eqn_eqn(ep, last);
- if (last->last)
- last->last->left = left;
- else
- free(left);
- if (EQN_DESCOPE != c)
- return(c);
- assert(last->last);
- eqn_rewind(ep);
- start = eqn_nexttok(ep, &sz);
- assert(start);
- if ( ! STRNEQ(start, sz, "right", 5))
- return(EQN_DESCOPE);
- if (NULL == (start = eqn_nexttok(ep, &sz))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(EQN_ERR);
- }
- last->last->right = mandoc_strndup(start, sz);
- return(EQN_OK);
- }
-
- for (i = 0; i < (int)EQNPOS__MAX; i++) {
- if ( ! EQNSTREQ(&eqnposs[i], start, sz))
- continue;
- if (NULL == last->last) {
- EQN_MSG(MANDOCERR_EQNSYNT, ep);
- return(EQN_ERR);
- }
- last->last->pos = (enum eqn_post)i;
- if (EQN_EOF == (c = eqn_box(ep, last))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(EQN_ERR);
- }
- return(c);
- }
-
- for (i = 0; i < (int)EQNMARK__MAX; i++) {
- if ( ! EQNSTREQ(&eqnmarks[i], start, sz))
- continue;
- if (NULL == last->last) {
- EQN_MSG(MANDOCERR_EQNSYNT, ep);
- return(EQN_ERR);
- }
- last->last->mark = (enum eqn_markt)i;
- if (EQN_EOF == (c = eqn_box(ep, last))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(EQN_ERR);
- }
- return(c);
- }
-
- for (i = 0; i < (int)EQNFONT__MAX; i++) {
- if ( ! EQNSTREQ(&eqnfonts[i], start, sz))
- continue;
- if (EQN_EOF == (c = eqn_box(ep, last))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(EQN_ERR);
- } else if (EQN_OK == c)
- last->last->font = (enum eqn_fontt)i;
- return(c);
- }
-
- if (STRNEQ(start, sz, "size", 4)) {
- if (NULL == (start = eqn_nexttok(ep, &sz))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(EQN_ERR);
- }
- size = mandoc_strntoi(start, sz, 10);
- if (EQN_EOF == (c = eqn_box(ep, last))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(EQN_ERR);
- } else if (EQN_OK != c)
- return(c);
- last->last->size = size;
- }
-
- bp = eqn_box_alloc(ep, last);
- bp->type = EQN_TEXT;
- for (i = 0; i < (int)EQNSYM__MAX; i++)
- if (EQNSTREQ(&eqnsyms[i].str, start, sz)) {
- sym[63] = '\0';
- snprintf(sym, 62, "\\[%s]", eqnsyms[i].sym);
- bp->text = mandoc_strdup(sym);
- return(EQN_OK);
- }
-
- bp->text = mandoc_strndup(start, sz);
- return(EQN_OK);
-}
-
-void
-eqn_free(struct eqn_node *p)
+/*
+ * Find the key "key" of the give size within our eqn-defined values.
+ */
+static struct eqn_def *
+eqn_def_find(struct eqn_node *ep, const char *key, size_t sz)
{
int i;
- eqn_box_free(p->eqn.root);
-
- for (i = 0; i < (int)p->defsz; i++) {
- free(p->defs[i].key);
- free(p->defs[i].val);
- }
-
- free(p->eqn.name);
- free(p->data);
- free(p->defs);
- free(p);
-}
-
-static struct eqn_box *
-eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent)
-{
- struct eqn_box *bp;
-
- bp = mandoc_calloc(1, sizeof(struct eqn_box));
- bp->parent = parent;
- bp->size = ep->gsize;
-
- if (NULL == parent->first)
- parent->first = bp;
- else
- parent->last->next = bp;
-
- parent->last = bp;
- return(bp);
-}
-
-static void
-eqn_box_free(struct eqn_box *bp)
-{
-
- if (bp->first)
- eqn_box_free(bp->first);
- if (bp->next)
- eqn_box_free(bp->next);
-
- free(bp->text);
- free(bp->left);
- free(bp->right);
- free(bp);
-}
-
-static const char *
-eqn_nextrawtok(struct eqn_node *ep, size_t *sz)
-{
-
- return(eqn_next(ep, '"', sz, 0));
-}
-
-static const char *
-eqn_nexttok(struct eqn_node *ep, size_t *sz)
-{
-
- return(eqn_next(ep, '"', sz, 1));
-}
-
-static void
-eqn_rewind(struct eqn_node *ep)
-{
+ for (i = 0; i < (int)ep->defsz; i++)
+ if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key,
+ ep->defs[i].keysz, key, sz))
+ return(&ep->defs[i]);
- ep->cur = ep->rew;
+ return(NULL);
}
+/*
+ * Get the next token from the input stream using the given quote
+ * character.
+ * Optionally make any replacements.
+ */
static const char *
eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
{
@@ -727,7 +380,8 @@ again:
/* Prevent self-definitions. */
if (lim >= EQN_NEST_MAX) {
- EQN_MSG(MANDOCERR_ROFFLOOP, ep);
+ mandoc_msg(MANDOCERR_ROFFLOOP, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, NULL);
return(NULL);
}
@@ -762,13 +416,14 @@ again:
if (q)
ep->cur++;
while (' ' == ep->data[(int)ep->cur] ||
- '\t' == ep->data[(int)ep->cur] ||
- '^' == ep->data[(int)ep->cur] ||
- '~' == ep->data[(int)ep->cur])
+ '\t' == ep->data[(int)ep->cur] ||
+ '^' == ep->data[(int)ep->cur] ||
+ '~' == ep->data[(int)ep->cur])
ep->cur++;
} else {
if (q)
- EQN_MSG(MANDOCERR_BADQUOTE, ep);
+ mandoc_msg(MANDOCERR_ARG_QUOTE, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, NULL);
next = strchr(start, '\0');
*sz = (size_t)(next - start);
ep->cur += *sz;
@@ -790,8 +445,8 @@ again:
}
diff = def->valsz - *sz;
- memmove(start + *sz + diff, start + *sz,
- (strlen(start) - *sz) + 1);
+ memmove(start + *sz + diff, start + *sz,
+ (strlen(start) - *sz) + 1);
memcpy(start, def->val, def->valsz);
goto again;
}
@@ -799,64 +454,207 @@ again:
return(start);
}
-static int
-eqn_do_ign1(struct eqn_node *ep)
+/*
+ * Get the next delimited token using the default current quote
+ * character.
+ */
+static const char *
+eqn_nexttok(struct eqn_node *ep, size_t *sz)
{
- if (NULL == eqn_nextrawtok(ep, NULL))
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- else
- return(1);
+ return(eqn_next(ep, '"', sz, 1));
+}
+
+/*
+ * Get next token without replacement.
+ */
+static const char *
+eqn_nextrawtok(struct eqn_node *ep, size_t *sz)
+{
- return(0);
+ return(eqn_next(ep, '"', sz, 0));
}
-static int
-eqn_do_ign2(struct eqn_node *ep)
+/*
+ * Parse a token from the stream of text.
+ * A token consists of one of the recognised eqn(7) strings.
+ * Strings are separated by delimiting marks.
+ * This returns EQN_TOK_EOF when there are no more tokens.
+ * If the token is an unrecognised string literal, then it returns
+ * EQN_TOK__MAX and sets the "p" pointer to an allocated, nil-terminated
+ * string.
+ * This must be later freed with free(3).
+ */
+static enum eqn_tok
+eqn_tok_parse(struct eqn_node *ep, char **p)
{
+ const char *start;
+ size_t i, sz;
+ int quoted;
+
+ if (NULL != p)
+ *p = NULL;
+
+ quoted = ep->data[ep->cur] == '"';
+
+ if (NULL == (start = eqn_nexttok(ep, &sz)))
+ return(EQN_TOK_EOF);
+
+ if (quoted) {
+ if (p != NULL)
+ *p = mandoc_strndup(start, sz);
+ return(EQN_TOK__MAX);
+ }
+
+ for (i = 0; i < EQN_TOK__MAX; i++) {
+ if (NULL == eqn_toks[i])
+ continue;
+ if (STRNEQ(start, sz, eqn_toks[i], strlen(eqn_toks[i])))
+ break;
+ }
- if (NULL == eqn_nextrawtok(ep, NULL))
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- else if (NULL == eqn_nextrawtok(ep, NULL))
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- else
- return(1);
+ if (i == EQN_TOK__MAX && NULL != p)
+ *p = mandoc_strndup(start, sz);
- return(0);
+ return(i);
}
-static int
-eqn_do_tdefine(struct eqn_node *ep)
+static void
+eqn_box_free(struct eqn_box *bp)
{
- if (NULL == eqn_nextrawtok(ep, NULL))
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- else if (NULL == eqn_next(ep, ep->data[(int)ep->cur], NULL, 0))
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- else
- return(1);
+ if (bp->first)
+ eqn_box_free(bp->first);
+ if (bp->next)
+ eqn_box_free(bp->next);
- return(0);
+ free(bp->text);
+ free(bp->left);
+ free(bp->right);
+ free(bp->top);
+ free(bp->bottom);
+ free(bp);
}
-static int
-eqn_do_define(struct eqn_node *ep)
+/*
+ * Allocate a box as the last child of the parent node.
+ */
+static struct eqn_box *
+eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent)
+{
+ struct eqn_box *bp;
+
+ bp = mandoc_calloc(1, sizeof(struct eqn_box));
+ bp->parent = parent;
+ bp->parent->args++;
+ bp->expectargs = UINT_MAX;
+ bp->size = ep->gsize;
+
+ if (NULL != parent->first) {
+ parent->last->next = bp;
+ bp->prev = parent->last;
+ } else
+ parent->first = bp;
+
+ parent->last = bp;
+ return(bp);
+}
+
+/*
+ * Reparent the current last node (of the current parent) under a new
+ * EQN_SUBEXPR as the first element.
+ * Then return the new parent.
+ * The new EQN_SUBEXPR will have a two-child limit.
+ */
+static struct eqn_box *
+eqn_box_makebinary(struct eqn_node *ep,
+ enum eqn_post pos, struct eqn_box *parent)
+{
+ struct eqn_box *b, *newb;
+
+ assert(NULL != parent->last);
+ b = parent->last;
+ if (parent->last == parent->first)
+ parent->first = NULL;
+ parent->args--;
+ parent->last = b->prev;
+ b->prev = NULL;
+ newb = eqn_box_alloc(ep, parent);
+ newb->pos = pos;
+ newb->type = EQN_SUBEXPR;
+ newb->expectargs = 2;
+ newb->args = 1;
+ newb->first = newb->last = b;
+ newb->first->next = NULL;
+ b->parent = newb;
+ return(newb);
+}
+
+/*
+ * Parse the "delim" control statement.
+ */
+static void
+eqn_delim(struct eqn_node *ep)
+{
+ const char *start;
+ size_t sz;
+
+ if ((start = eqn_nextrawtok(ep, &sz)) == NULL)
+ mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, "delim");
+ else if (strncmp(start, "off", 3) == 0)
+ ep->delim = 0;
+ else if (strncmp(start, "on", 2) == 0) {
+ if (ep->odelim && ep->cdelim)
+ ep->delim = 1;
+ } else if (start[1] != '\0') {
+ ep->odelim = start[0];
+ ep->cdelim = start[1];
+ ep->delim = 1;
+ }
+}
+
+/*
+ * Undefine a previously-defined string.
+ */
+static void
+eqn_undef(struct eqn_node *ep)
+{
+ const char *start;
+ struct eqn_def *def;
+ size_t sz;
+
+ if ((start = eqn_nextrawtok(ep, &sz)) == NULL) {
+ mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, "undef");
+ return;
+ }
+ if ((def = eqn_def_find(ep, start, sz)) == NULL)
+ return;
+ free(def->key);
+ free(def->val);
+ def->key = def->val = NULL;
+ def->keysz = def->valsz = 0;
+}
+
+static void
+eqn_def(struct eqn_node *ep)
{
const char *start;
size_t sz;
struct eqn_def *def;
int i;
- if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(0);
+ if ((start = eqn_nextrawtok(ep, &sz)) == NULL) {
+ mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, "define");
+ return;
}
- /*
- * Search for a key that already exists.
+ /*
+ * Search for a key that already exists.
* Create a new key if none is found.
*/
-
if (NULL == (def = eqn_def_find(ep, start, sz))) {
/* Find holes in string array. */
for (i = 0; i < (int)ep->defsz; i++)
@@ -865,85 +663,463 @@ eqn_do_define(struct eqn_node *ep)
if (i == (int)ep->defsz) {
ep->defsz++;
- ep->defs = mandoc_realloc
- (ep->defs, ep->defsz *
- sizeof(struct eqn_def));
+ ep->defs = mandoc_reallocarray(ep->defs,
+ ep->defsz, sizeof(struct eqn_def));
ep->defs[i].key = ep->defs[i].val = NULL;
}
- ep->defs[i].keysz = sz;
- ep->defs[i].key = mandoc_realloc
- (ep->defs[i].key, sz + 1);
-
- memcpy(ep->defs[i].key, start, sz);
- ep->defs[i].key[(int)sz] = '\0';
- def = &ep->defs[i];
+ def = ep->defs + i;
+ free(def->key);
+ def->key = mandoc_strndup(start, sz);
+ def->keysz = sz;
}
start = eqn_next(ep, ep->data[(int)ep->cur], &sz, 0);
-
- if (NULL == start) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(0);
+ if (start == NULL) {
+ mandoc_vmsg(MANDOCERR_REQ_EMPTY, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, "define %s", def->key);
+ free(def->key);
+ free(def->val);
+ def->key = def->val = NULL;
+ def->keysz = def->valsz = 0;
+ return;
}
-
+ free(def->val);
+ def->val = mandoc_strndup(start, sz);
def->valsz = sz;
- def->val = mandoc_realloc(def->val, sz + 1);
- memcpy(def->val, start, sz);
- def->val[(int)sz] = '\0';
- return(1);
}
-static int
-eqn_do_gfont(struct eqn_node *ep)
+/*
+ * Recursively parse an eqn(7) expression.
+ */
+static enum rofferr
+eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
{
+ char sym[64];
+ struct eqn_box *cur;
+ const char *start;
+ char *p;
+ size_t i, sz;
+ enum eqn_tok tok, subtok;
+ enum eqn_post pos;
+ int size;
- if (NULL == eqn_nextrawtok(ep, NULL)) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(0);
- }
- return(1);
-}
+ assert(parent != NULL);
-static int
-eqn_do_gsize(struct eqn_node *ep)
-{
- const char *start;
- size_t sz;
+ /*
+ * Empty equation.
+ * Do not add it to the high-level syntax tree.
+ */
+
+ if (ep->data == NULL)
+ return(ROFF_IGN);
+
+next_tok:
+ tok = eqn_tok_parse(ep, &p);
+
+this_tok:
+ switch (tok) {
+ case (EQN_TOK_UNDEF):
+ eqn_undef(ep);
+ break;
+ case (EQN_TOK_NDEFINE):
+ case (EQN_TOK_DEFINE):
+ eqn_def(ep);
+ break;
+ case (EQN_TOK_TDEFINE):
+ if (eqn_nextrawtok(ep, NULL) == NULL ||
+ eqn_next(ep, ep->data[(int)ep->cur], NULL, 0) == NULL)
+ mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, "tdefine");
+ break;
+ case (EQN_TOK_DELIM):
+ eqn_delim(ep);
+ break;
+ case (EQN_TOK_GFONT):
+ if (eqn_nextrawtok(ep, NULL) == NULL)
+ mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+ break;
+ case (EQN_TOK_MARK):
+ case (EQN_TOK_LINEUP):
+ /* Ignore these. */
+ break;
+ case (EQN_TOK_DYAD):
+ case (EQN_TOK_VEC):
+ case (EQN_TOK_UNDER):
+ case (EQN_TOK_BAR):
+ case (EQN_TOK_TILDE):
+ case (EQN_TOK_HAT):
+ case (EQN_TOK_DOT):
+ case (EQN_TOK_DOTDOT):
+ if (parent->last == NULL) {
+ mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+ cur = eqn_box_alloc(ep, parent);
+ cur->type = EQN_TEXT;
+ cur->text = mandoc_strdup("");
+ }
+ parent = eqn_box_makebinary(ep, EQNPOS_NONE, parent);
+ parent->type = EQN_LISTONE;
+ parent->expectargs = 1;
+ switch (tok) {
+ case (EQN_TOK_DOTDOT):
+ strlcpy(sym, "\\[ad]", sizeof(sym));
+ break;
+ case (EQN_TOK_VEC):
+ strlcpy(sym, "\\[->]", sizeof(sym));
+ break;
+ case (EQN_TOK_DYAD):
+ strlcpy(sym, "\\[<>]", sizeof(sym));
+ break;
+ case (EQN_TOK_TILDE):
+ strlcpy(sym, "\\[a~]", sizeof(sym));
+ break;
+ case (EQN_TOK_UNDER):
+ strlcpy(sym, "\\[ul]", sizeof(sym));
+ break;
+ case (EQN_TOK_BAR):
+ strlcpy(sym, "\\[rl]", sizeof(sym));
+ break;
+ case (EQN_TOK_DOT):
+ strlcpy(sym, "\\[a.]", sizeof(sym));
+ break;
+ case (EQN_TOK_HAT):
+ strlcpy(sym, "\\[ha]", sizeof(sym));
+ break;
+ default:
+ abort();
+ }
- if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(0);
- }
- ep->gsize = mandoc_strntoi(start, sz, 10);
- return(1);
+ switch (tok) {
+ case (EQN_TOK_DOTDOT):
+ case (EQN_TOK_VEC):
+ case (EQN_TOK_DYAD):
+ case (EQN_TOK_TILDE):
+ case (EQN_TOK_BAR):
+ case (EQN_TOK_DOT):
+ case (EQN_TOK_HAT):
+ parent->top = mandoc_strdup(sym);
+ break;
+ case (EQN_TOK_UNDER):
+ parent->bottom = mandoc_strdup(sym);
+ break;
+ default:
+ abort();
+ }
+ parent = parent->parent;
+ break;
+ case (EQN_TOK_FWD):
+ case (EQN_TOK_BACK):
+ case (EQN_TOK_DOWN):
+ case (EQN_TOK_UP):
+ subtok = eqn_tok_parse(ep, NULL);
+ if (subtok != EQN_TOK__MAX) {
+ mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+ tok = subtok;
+ goto this_tok;
+ }
+ break;
+ case (EQN_TOK_FAT):
+ case (EQN_TOK_ROMAN):
+ case (EQN_TOK_ITALIC):
+ case (EQN_TOK_BOLD):
+ while (parent->args == parent->expectargs)
+ parent = parent->parent;
+ /*
+ * These values apply to the next word or sequence of
+ * words; thus, we mark that we'll have a child with
+ * exactly one of those.
+ */
+ parent = eqn_box_alloc(ep, parent);
+ parent->type = EQN_LISTONE;
+ parent->expectargs = 1;
+ switch (tok) {
+ case (EQN_TOK_FAT):
+ parent->font = EQNFONT_FAT;
+ break;
+ case (EQN_TOK_ROMAN):
+ parent->font = EQNFONT_ROMAN;
+ break;
+ case (EQN_TOK_ITALIC):
+ parent->font = EQNFONT_ITALIC;
+ break;
+ case (EQN_TOK_BOLD):
+ parent->font = EQNFONT_BOLD;
+ break;
+ default:
+ abort();
+ }
+ break;
+ case (EQN_TOK_SIZE):
+ case (EQN_TOK_GSIZE):
+ /* Accept two values: integral size and a single. */
+ if (NULL == (start = eqn_nexttok(ep, &sz))) {
+ mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+ break;
+ }
+ size = mandoc_strntoi(start, sz, 10);
+ if (-1 == size) {
+ mandoc_msg(MANDOCERR_IT_NONUM, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+ break;
+ }
+ if (EQN_TOK_GSIZE == tok) {
+ ep->gsize = size;
+ break;
+ }
+ parent = eqn_box_alloc(ep, parent);
+ parent->type = EQN_LISTONE;
+ parent->expectargs = 1;
+ parent->size = size;
+ break;
+ case (EQN_TOK_FROM):
+ case (EQN_TOK_TO):
+ case (EQN_TOK_SUB):
+ case (EQN_TOK_SUP):
+ /*
+ * We have a left-right-associative expression.
+ * Repivot under a positional node, open a child scope
+ * and keep on reading.
+ */
+ if (parent->last == NULL) {
+ mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+ cur = eqn_box_alloc(ep, parent);
+ cur->type = EQN_TEXT;
+ cur->text = mandoc_strdup("");
+ }
+ /* Handle the "subsup" and "fromto" positions. */
+ if (EQN_TOK_SUP == tok && parent->pos == EQNPOS_SUB) {
+ parent->expectargs = 3;
+ parent->pos = EQNPOS_SUBSUP;
+ break;
+ }
+ if (EQN_TOK_TO == tok && parent->pos == EQNPOS_FROM) {
+ parent->expectargs = 3;
+ parent->pos = EQNPOS_FROMTO;
+ break;
+ }
+ switch (tok) {
+ case (EQN_TOK_FROM):
+ pos = EQNPOS_FROM;
+ break;
+ case (EQN_TOK_TO):
+ pos = EQNPOS_TO;
+ break;
+ case (EQN_TOK_SUP):
+ pos = EQNPOS_SUP;
+ break;
+ case (EQN_TOK_SUB):
+ pos = EQNPOS_SUB;
+ break;
+ default:
+ abort();
+ }
+ parent = eqn_box_makebinary(ep, pos, parent);
+ break;
+ case (EQN_TOK_SQRT):
+ while (parent->args == parent->expectargs)
+ parent = parent->parent;
+ /*
+ * Accept a left-right-associative set of arguments just
+ * like sub and sup and friends but without rebalancing
+ * under a pivot.
+ */
+ parent = eqn_box_alloc(ep, parent);
+ parent->type = EQN_SUBEXPR;
+ parent->pos = EQNPOS_SQRT;
+ parent->expectargs = 1;
+ break;
+ case (EQN_TOK_OVER):
+ /*
+ * We have a right-left-associative fraction.
+ * Close out anything that's currently open, then
+ * rebalance and continue reading.
+ */
+ if (parent->last == NULL) {
+ mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+ cur = eqn_box_alloc(ep, parent);
+ cur->type = EQN_TEXT;
+ cur->text = mandoc_strdup("");
+ }
+ while (EQN_SUBEXPR == parent->type)
+ parent = parent->parent;
+ parent = eqn_box_makebinary(ep, EQNPOS_OVER, parent);
+ break;
+ case (EQN_TOK_RIGHT):
+ case (EQN_TOK_BRACE_CLOSE):
+ /*
+ * Close out the existing brace.
+ * FIXME: this is a shitty sentinel: we should really
+ * have a native EQN_BRACE type or whatnot.
+ */
+ for (cur = parent; cur != NULL; cur = cur->parent)
+ if (cur->type == EQN_LIST &&
+ (tok == EQN_TOK_BRACE_CLOSE ||
+ cur->left != NULL))
+ break;
+ if (cur == NULL) {
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+ break;
+ }
+ parent = cur;
+ if (EQN_TOK_RIGHT == tok) {
+ if (NULL == (start = eqn_nexttok(ep, &sz))) {
+ mandoc_msg(MANDOCERR_REQ_EMPTY,
+ ep->parse, ep->eqn.ln,
+ ep->eqn.pos, eqn_toks[tok]);
+ break;
+ }
+ /* Handling depends on right/left. */
+ if (STRNEQ(start, sz, "ceiling", 7)) {
+ strlcpy(sym, "\\[rc]", sizeof(sym));
+ parent->right = mandoc_strdup(sym);
+ } else if (STRNEQ(start, sz, "floor", 5)) {
+ strlcpy(sym, "\\[rf]", sizeof(sym));
+ parent->right = mandoc_strdup(sym);
+ } else
+ parent->right = mandoc_strndup(start, sz);
+ }
+ parent = parent->parent;
+ if (EQN_TOK_BRACE_CLOSE == tok && parent &&
+ (parent->type == EQN_PILE ||
+ parent->type == EQN_MATRIX))
+ parent = parent->parent;
+ /* Close out any "singleton" lists. */
+ while (parent->type == EQN_LISTONE &&
+ parent->args == parent->expectargs)
+ parent = parent->parent;
+ break;
+ case (EQN_TOK_BRACE_OPEN):
+ case (EQN_TOK_LEFT):
+ /*
+ * If we already have something in the stack and we're
+ * in an expression, then rewind til we're not any more
+ * (just like with the text node).
+ */
+ while (parent->args == parent->expectargs)
+ parent = parent->parent;
+ if (EQN_TOK_LEFT == tok &&
+ (start = eqn_nexttok(ep, &sz)) == NULL) {
+ mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+ break;
+ }
+ parent = eqn_box_alloc(ep, parent);
+ parent->type = EQN_LIST;
+ if (EQN_TOK_LEFT == tok) {
+ if (STRNEQ(start, sz, "ceiling", 7)) {
+ strlcpy(sym, "\\[lc]", sizeof(sym));
+ parent->left = mandoc_strdup(sym);
+ } else if (STRNEQ(start, sz, "floor", 5)) {
+ strlcpy(sym, "\\[lf]", sizeof(sym));
+ parent->left = mandoc_strdup(sym);
+ } else
+ parent->left = mandoc_strndup(start, sz);
+ }
+ break;
+ case (EQN_TOK_PILE):
+ case (EQN_TOK_LPILE):
+ case (EQN_TOK_RPILE):
+ case (EQN_TOK_CPILE):
+ case (EQN_TOK_CCOL):
+ case (EQN_TOK_LCOL):
+ case (EQN_TOK_RCOL):
+ while (parent->args == parent->expectargs)
+ parent = parent->parent;
+ parent = eqn_box_alloc(ep, parent);
+ parent->type = EQN_PILE;
+ parent->expectargs = 1;
+ break;
+ case (EQN_TOK_ABOVE):
+ for (cur = parent; cur != NULL; cur = cur->parent)
+ if (cur->type == EQN_PILE)
+ break;
+ if (cur == NULL) {
+ mandoc_msg(MANDOCERR_IT_STRAY, ep->parse,
+ ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+ break;
+ }
+ parent = eqn_box_alloc(ep, cur);
+ parent->type = EQN_LIST;
+ break;
+ case (EQN_TOK_MATRIX):
+ while (parent->args == parent->expectargs)
+ parent = parent->parent;
+ parent = eqn_box_alloc(ep, parent);
+ parent->type = EQN_MATRIX;
+ parent->expectargs = 1;
+ break;
+ case (EQN_TOK_EOF):
+ /*
+ * End of file!
+ * TODO: make sure we're not in an open subexpression.
+ */
+ return(ROFF_EQN);
+ default:
+ assert(tok == EQN_TOK__MAX);
+ assert(NULL != p);
+ /*
+ * If we already have something in the stack and we're
+ * in an expression, then rewind til we're not any more.
+ */
+ while (parent->args == parent->expectargs)
+ parent = parent->parent;
+ cur = eqn_box_alloc(ep, parent);
+ cur->type = EQN_TEXT;
+ for (i = 0; i < EQNSYM__MAX; i++)
+ if (0 == strcmp(eqnsyms[i].str, p)) {
+ (void)snprintf(sym, sizeof(sym),
+ "\\[%s]", eqnsyms[i].sym);
+ cur->text = mandoc_strdup(sym);
+ free(p);
+ break;
+ }
+
+ if (i == EQNSYM__MAX)
+ cur->text = p;
+ /*
+ * Post-process list status.
+ */
+ while (parent->type == EQN_LISTONE &&
+ parent->args == parent->expectargs)
+ parent = parent->parent;
+ break;
+ }
+ goto next_tok;
}
-static int
-eqn_do_undef(struct eqn_node *ep)
+enum rofferr
+eqn_end(struct eqn_node **epp)
{
- const char *start;
- struct eqn_def *def;
- size_t sz;
+ struct eqn_node *ep;
- if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
- EQN_MSG(MANDOCERR_EQNEOF, ep);
- return(0);
- } else if (NULL != (def = eqn_def_find(ep, start, sz)))
- def->keysz = 0;
+ ep = *epp;
+ *epp = NULL;
- return(1);
+ ep->eqn.root = mandoc_calloc(1, sizeof(struct eqn_box));
+ ep->eqn.root->expectargs = UINT_MAX;
+ return(eqn_parse(ep, ep->eqn.root));
}
-static struct eqn_def *
-eqn_def_find(struct eqn_node *ep, const char *key, size_t sz)
+void
+eqn_free(struct eqn_node *p)
{
int i;
- for (i = 0; i < (int)ep->defsz; i++)
- if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key,
- ep->defs[i].keysz, key, sz))
- return(&ep->defs[i]);
+ eqn_box_free(p->eqn.root);
- return(NULL);
+ for (i = 0; i < (int)p->defsz; i++) {
+ free(p->defs[i].key);
+ free(p->defs[i].val);
+ }
+
+ free(p->data);
+ free(p->defs);
+ free(p);
}
diff --git a/usr/src/cmd/mandoc/eqn_html.c b/usr/src/cmd/mandoc/eqn_html.c
index 80c82f1de5..f29733613b 100644
--- a/usr/src/cmd/mandoc/eqn_html.c
+++ b/usr/src/cmd/mandoc/eqn_html.c
@@ -1,6 +1,6 @@
-/* $Id: eqn_html.c,v 1.2 2011/07/24 10:09:03 kristaps Exp $ */
+/* $Id: eqn_html.c,v 1.10 2014/10/12 19:31:41 schwarze Exp $ */
/*
- * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,9 +14,9 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
+
+#include <sys/types.h>
#include <assert.h>
#include <stdio.h>
@@ -27,16 +27,153 @@
#include "out.h"
#include "html.h"
-static const enum htmltag fontmap[EQNFONT__MAX] = {
- TAG_SPAN, /* EQNFONT_NONE */
- TAG_SPAN, /* EQNFONT_ROMAN */
- TAG_B, /* EQNFONT_BOLD */
- TAG_B, /* EQNFONT_FAT */
- TAG_I /* EQNFONT_ITALIC */
-};
+static void
+eqn_box(struct html *p, const struct eqn_box *bp)
+{
+ struct tag *post, *row, *cell, *t;
+ struct htmlpair tag[2];
+ const struct eqn_box *child, *parent;
+ size_t i, j, rows;
+
+ if (NULL == bp)
+ return;
+
+ post = NULL;
+
+ /*
+ * Special handling for a matrix, which is presented to us in
+ * column order, but must be printed in row-order.
+ */
+ if (EQN_MATRIX == bp->type) {
+ if (NULL == bp->first)
+ goto out;
+ if (EQN_LIST != bp->first->type) {
+ eqn_box(p, bp->first);
+ goto out;
+ }
+ if (NULL == (parent = bp->first->first))
+ goto out;
+ /* Estimate the number of rows, first. */
+ if (NULL == (child = parent->first))
+ goto out;
+ for (rows = 0; NULL != child; rows++)
+ child = child->next;
+ /* Print row-by-row. */
+ post = print_otag(p, TAG_MTABLE, 0, NULL);
+ for (i = 0; i < rows; i++) {
+ parent = bp->first->first;
+ row = print_otag(p, TAG_MTR, 0, NULL);
+ while (NULL != parent) {
+ child = parent->first;
+ for (j = 0; j < i; j++) {
+ if (NULL == child)
+ break;
+ child = child->next;
+ }
+ cell = print_otag
+ (p, TAG_MTD, 0, NULL);
+ /*
+ * If we have no data for this
+ * particular cell, then print a
+ * placeholder and continue--don't puke.
+ */
+ if (NULL != child)
+ eqn_box(p, child->first);
+ print_tagq(p, cell);
+ parent = parent->next;
+ }
+ print_tagq(p, row);
+ }
+ goto out;
+ }
+
+ switch (bp->pos) {
+ case (EQNPOS_TO):
+ post = print_otag(p, TAG_MOVER, 0, NULL);
+ break;
+ case (EQNPOS_SUP):
+ post = print_otag(p, TAG_MSUP, 0, NULL);
+ break;
+ case (EQNPOS_FROM):
+ post = print_otag(p, TAG_MUNDER, 0, NULL);
+ break;
+ case (EQNPOS_SUB):
+ post = print_otag(p, TAG_MSUB, 0, NULL);
+ break;
+ case (EQNPOS_OVER):
+ post = print_otag(p, TAG_MFRAC, 0, NULL);
+ break;
+ case (EQNPOS_FROMTO):
+ post = print_otag(p, TAG_MUNDEROVER, 0, NULL);
+ break;
+ case (EQNPOS_SUBSUP):
+ post = print_otag(p, TAG_MSUBSUP, 0, NULL);
+ break;
+ case (EQNPOS_SQRT):
+ post = print_otag(p, TAG_MSQRT, 0, NULL);
+ break;
+ default:
+ break;
+ }
+
+ if (bp->top || bp->bottom) {
+ assert(NULL == post);
+ if (bp->top && NULL == bp->bottom)
+ post = print_otag(p, TAG_MOVER, 0, NULL);
+ else if (bp->top && bp->bottom)
+ post = print_otag(p, TAG_MUNDEROVER, 0, NULL);
+ else if (bp->bottom)
+ post = print_otag(p, TAG_MUNDER, 0, NULL);
+ }
+
+ if (EQN_PILE == bp->type) {
+ assert(NULL == post);
+ if (bp->first != NULL && bp->first->type == EQN_LIST)
+ post = print_otag(p, TAG_MTABLE, 0, NULL);
+ } else if (bp->type == EQN_LIST &&
+ bp->parent && bp->parent->type == EQN_PILE) {
+ assert(NULL == post);
+ post = print_otag(p, TAG_MTR, 0, NULL);
+ print_otag(p, TAG_MTD, 0, NULL);
+ }
+
+ if (NULL != bp->text) {
+ assert(NULL == post);
+ post = print_otag(p, TAG_MI, 0, NULL);
+ print_text(p, bp->text);
+ } else if (NULL == post) {
+ if (NULL != bp->left || NULL != bp->right) {
+ PAIR_INIT(&tag[0], ATTR_OPEN,
+ NULL == bp->left ? "" : bp->left);
+ PAIR_INIT(&tag[1], ATTR_CLOSE,
+ NULL == bp->right ? "" : bp->right);
+ post = print_otag(p, TAG_MFENCED, 2, tag);
+ }
+ if (NULL == post)
+ post = print_otag(p, TAG_MROW, 0, NULL);
+ else
+ print_otag(p, TAG_MROW, 0, NULL);
+ }
+
+ eqn_box(p, bp->first);
+
+out:
+ if (NULL != bp->bottom) {
+ t = print_otag(p, TAG_MO, 0, NULL);
+ print_text(p, bp->bottom);
+ print_tagq(p, t);
+ }
+ if (NULL != bp->top) {
+ t = print_otag(p, TAG_MO, 0, NULL);
+ print_text(p, bp->top);
+ print_tagq(p, t);
+ }
+ if (NULL != post)
+ print_tagq(p, post);
-static void eqn_box(struct html *, const struct eqn_box *);
+ eqn_box(p, bp->next);
+}
void
print_eqn(struct html *p, const struct eqn *ep)
@@ -45,7 +182,7 @@ print_eqn(struct html *p, const struct eqn *ep)
struct tag *t;
PAIR_CLASS_INIT(&tag, "eqn");
- t = print_otag(p, TAG_SPAN, 1, &tag);
+ t = print_otag(p, TAG_MATH, 1, &tag);
p->flags |= HTML_NONOSPACE;
eqn_box(p, ep->root);
@@ -53,29 +190,3 @@ print_eqn(struct html *p, const struct eqn *ep)
print_tagq(p, t);
}
-
-static void
-eqn_box(struct html *p, const struct eqn_box *bp)
-{
- struct tag *t;
-
- t = EQNFONT_NONE == bp->font ? NULL :
- print_otag(p, fontmap[(int)bp->font], 0, NULL);
-
- if (bp->left)
- print_text(p, bp->left);
-
- if (bp->text)
- print_text(p, bp->text);
-
- if (bp->first)
- eqn_box(p, bp->first);
-
- if (NULL != t)
- print_tagq(p, t);
- if (bp->right)
- print_text(p, bp->right);
-
- if (bp->next)
- eqn_box(p, bp->next);
-}
diff --git a/usr/src/cmd/mandoc/eqn_term.c b/usr/src/cmd/mandoc/eqn_term.c
index cfbd8d48f8..5f2818b405 100644
--- a/usr/src/cmd/mandoc/eqn_term.c
+++ b/usr/src/cmd/mandoc/eqn_term.c
@@ -1,6 +1,7 @@
-/* $Id: eqn_term.c,v 1.4 2011/07/24 10:09:03 kristaps Exp $ */
+/* $Id: eqn_term.c,v 1.8 2015/01/01 15:36:08 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014, 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
@@ -14,9 +15,9 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
+
+#include <sys/types.h>
#include <assert.h>
#include <stdio.h>
@@ -37,40 +38,90 @@ static const enum termfont fontmap[EQNFONT__MAX] = {
static void eqn_box(struct termp *, const struct eqn_box *);
+
void
term_eqn(struct termp *p, const struct eqn *ep)
{
- p->flags |= TERMP_NONOSPACE;
eqn_box(p, ep->root);
- term_word(p, " ");
- p->flags &= ~TERMP_NONOSPACE;
+ p->flags &= ~TERMP_NOSPACE;
}
static void
eqn_box(struct termp *p, const struct eqn_box *bp)
{
+ const struct eqn_box *child;
- if (EQNFONT_NONE != bp->font)
+ if (bp->type == EQN_LIST ||
+ (bp->type == EQN_PILE && (bp->prev || bp->next)) ||
+ (bp->parent != NULL && bp->parent->pos == EQNPOS_SQRT)) {
+ if (bp->parent->type == EQN_SUBEXPR && bp->prev != NULL)
+ p->flags |= TERMP_NOSPACE;
+ term_word(p, bp->left != NULL ? bp->left : "(");
+ p->flags |= TERMP_NOSPACE;
+ }
+ if (bp->font != EQNFONT_NONE)
term_fontpush(p, fontmap[(int)bp->font]);
- if (bp->left)
- term_word(p, bp->left);
- if (EQN_SUBEXPR == bp->type)
- term_word(p, "(");
- if (bp->text)
+ if (bp->text != NULL)
term_word(p, bp->text);
- if (bp->first)
+ if (bp->pos == EQNPOS_SQRT) {
+ term_word(p, "sqrt");
+ p->flags |= TERMP_NOSPACE;
eqn_box(p, bp->first);
+ } else if (bp->type == EQN_SUBEXPR) {
+ child = bp->first;
+ eqn_box(p, child);
+ p->flags |= TERMP_NOSPACE;
+ term_word(p, bp->pos == EQNPOS_OVER ? "/" :
+ (bp->pos == EQNPOS_SUP ||
+ bp->pos == EQNPOS_TO) ? "^" : "_");
+ p->flags |= TERMP_NOSPACE;
+ child = child->next;
+ if (child != NULL) {
+ eqn_box(p, child);
+ if (bp->pos == EQNPOS_FROMTO ||
+ bp->pos == EQNPOS_SUBSUP) {
+ p->flags |= TERMP_NOSPACE;
+ term_word(p, "^");
+ p->flags |= TERMP_NOSPACE;
+ child = child->next;
+ if (child != NULL)
+ eqn_box(p, child);
+ }
+ }
+ } else {
+ child = bp->first;
+ if (bp->type == EQN_MATRIX && child->type == EQN_LIST)
+ child = child->first;
+ while (child != NULL) {
+ eqn_box(p,
+ bp->type == EQN_PILE &&
+ child->type == EQN_LIST &&
+ child->args == 1 ?
+ child->first : child);
+ child = child->next;
+ }
+ }
- if (EQN_SUBEXPR == bp->type)
- term_word(p, ")");
- if (bp->right)
- term_word(p, bp->right);
- if (EQNFONT_NONE != bp->font)
+ if (bp->font != EQNFONT_NONE)
term_fontpop(p);
+ if (bp->type == EQN_LIST ||
+ (bp->type == EQN_PILE && (bp->prev || bp->next)) ||
+ (bp->parent != NULL && bp->parent->pos == EQNPOS_SQRT)) {
+ p->flags |= TERMP_NOSPACE;
+ term_word(p, bp->right != NULL ? bp->right : ")");
+ if (bp->parent->type == EQN_SUBEXPR && bp->next != NULL)
+ p->flags |= TERMP_NOSPACE;
+ }
- if (bp->next)
- eqn_box(p, bp->next);
+ if (bp->top != NULL) {
+ p->flags |= TERMP_NOSPACE;
+ term_word(p, bp->top);
+ }
+ if (bp->bottom != NULL) {
+ p->flags |= TERMP_NOSPACE;
+ term_word(p, "_");
+ }
}
diff --git a/usr/src/cmd/mandoc/html.c b/usr/src/cmd/mandoc/html.c
index 9d28b4270e..487dacda94 100644
--- a/usr/src/cmd/mandoc/html.c
+++ b/usr/src/cmd/mandoc/html.c
@@ -1,7 +1,7 @@
-/* $Id: html.c,v 1.152 2013/08/08 20:07:47 schwarze Exp $ */
+/* $Id: html.c,v 1.185 2015/01/21 20:33:25 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2011-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
@@ -15,9 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#include <sys/types.h>
@@ -31,7 +29,7 @@
#include <unistd.h>
#include "mandoc.h"
-#include "libmandoc.h"
+#include "mandoc_aux.h"
#include "out.h"
#include "html.h"
#include "main.h"
@@ -69,17 +67,31 @@ static const struct htmldata htmltags[TAG_MAX] = {
{"dt", HTML_CLRLINE}, /* TAG_DT */
{"dd", HTML_CLRLINE}, /* TAG_DD */
{"blockquote", HTML_CLRLINE}, /* TAG_BLOCKQUOTE */
- {"p", HTML_CLRLINE | HTML_NOSTACK | HTML_AUTOCLOSE}, /* TAG_P */
{"pre", HTML_CLRLINE }, /* TAG_PRE */
{"b", 0 }, /* TAG_B */
{"i", 0 }, /* TAG_I */
{"code", 0 }, /* TAG_CODE */
{"small", 0 }, /* TAG_SMALL */
+ {"style", HTML_CLRLINE}, /* TAG_STYLE */
+ {"math", HTML_CLRLINE}, /* TAG_MATH */
+ {"mrow", 0}, /* TAG_MROW */
+ {"mi", 0}, /* TAG_MI */
+ {"mo", 0}, /* TAG_MO */
+ {"msup", 0}, /* TAG_MSUP */
+ {"msub", 0}, /* TAG_MSUB */
+ {"msubsup", 0}, /* TAG_MSUBSUP */
+ {"mfrac", 0}, /* TAG_MFRAC */
+ {"msqrt", 0}, /* TAG_MSQRT */
+ {"mfenced", 0}, /* TAG_MFENCED */
+ {"mtable", 0}, /* TAG_MTABLE */
+ {"mtr", 0}, /* TAG_MTR */
+ {"mtd", 0}, /* TAG_MTD */
+ {"munderover", 0}, /* TAG_MUNDEROVER */
+ {"munder", 0}, /* TAG_MUNDER*/
+ {"mover", 0}, /* TAG_MOVER*/
};
static const char *const htmlattrs[ATTR_MAX] = {
- "http-equiv", /* ATTR_HTTPEQUIV */
- "content", /* ATTR_CONTENT */
"name", /* ATTR_NAME */
"rel", /* ATTR_REL */
"href", /* ATTR_HREF */
@@ -87,11 +99,12 @@ static const char *const htmlattrs[ATTR_MAX] = {
"media", /* ATTR_MEDIA */
"class", /* ATTR_CLASS */
"style", /* ATTR_STYLE */
- "width", /* ATTR_WIDTH */
"id", /* ATTR_ID */
- "summary", /* ATTR_SUMMARY */
- "align", /* ATTR_ALIGN */
"colspan", /* ATTR_COLSPAN */
+ "charset", /* ATTR_CHARSET */
+ "open", /* ATTR_OPEN */
+ "close", /* ATTR_CLOSE */
+ "mathvariant", /* ATTR_MATHVARIANT */
};
static const char *const roffscales[SCALE_MAX] = {
@@ -108,14 +121,15 @@ static const char *const roffscales[SCALE_MAX] = {
};
static void bufncat(struct html *, const char *, size_t);
-static void print_ctag(struct html *, enum htmltag);
+static void print_ctag(struct html *, struct tag *);
+static int print_escape(char);
static int print_encode(struct html *, const char *, int);
static void print_metaf(struct html *, enum mandoc_esc);
static void print_attr(struct html *, const char *, const char *);
-static void *ml_alloc(char *, enum htmltype);
-static void *
-ml_alloc(char *outopts, enum htmltype type)
+
+void *
+html_alloc(const struct mchars *mchars, char *outopts)
{
struct html *h;
const char *toks[5];
@@ -129,22 +143,21 @@ ml_alloc(char *outopts, enum htmltype type)
h = mandoc_calloc(1, sizeof(struct html));
- h->type = type;
h->tags.head = NULL;
- h->symtab = mchars_alloc();
+ h->symtab = mchars;
while (outopts && *outopts)
switch (getsubopt(&outopts, UNCONST(toks), &v)) {
- case (0):
+ case 0:
h->style = v;
break;
- case (1):
+ case 1:
h->base_man = v;
break;
- case (2):
+ case 2:
h->base_includes = v;
break;
- case (3):
+ case 3:
h->oflags |= HTML_FRAGMENT;
break;
default:
@@ -154,22 +167,6 @@ ml_alloc(char *outopts, enum htmltype type)
return(h);
}
-void *
-html_alloc(char *outopts)
-{
-
- return(ml_alloc(outopts, HTML_HTML_4_01_STRICT));
-}
-
-
-void *
-xhtml_alloc(char *outopts)
-{
-
- return(ml_alloc(outopts, HTML_XHTML_1_0_STRICT));
-}
-
-
void
html_free(void *p)
{
@@ -179,33 +176,34 @@ html_free(void *p)
h = (struct html *)p;
while ((tag = h->tags.head) != NULL) {
- h->tags.head = tag->next;
+ h->tags.head = tag->next;
free(tag);
}
-
- if (h->symtab)
- mchars_free(h->symtab);
free(h);
}
-
void
print_gen_head(struct html *h)
{
struct htmlpair tag[4];
+ struct tag *t;
- tag[0].key = ATTR_HTTPEQUIV;
- tag[0].val = "Content-Type";
- tag[1].key = ATTR_CONTENT;
- tag[1].val = "text/html; charset=utf-8";
- print_otag(h, TAG_META, 2, tag);
+ tag[0].key = ATTR_CHARSET;
+ tag[0].val = "utf-8";
+ print_otag(h, TAG_META, 1, tag);
- tag[0].key = ATTR_NAME;
- tag[0].val = "resource-type";
- tag[1].key = ATTR_CONTENT;
- tag[1].val = "document";
- print_otag(h, TAG_META, 2, tag);
+ /*
+ * Print a default style-sheet.
+ */
+ t = print_otag(h, TAG_STYLE, 0, NULL);
+ print_text(h, "table.head, table.foot { width: 100%; }\n"
+ "td.head-rtitle, td.foot-os { text-align: right; }\n"
+ "td.head-vol { text-align: center; }\n"
+ "table.foot td { width: 50%; }\n"
+ "table.head td { width: 33%; }\n"
+ "div.spacer { margin: 1em 0; }\n");
+ print_tagq(h, t);
if (h->style) {
tag[0].key = ATTR_REL;
@@ -226,21 +224,21 @@ print_metaf(struct html *h, enum mandoc_esc deco)
enum htmlfont font;
switch (deco) {
- case (ESCAPE_FONTPREV):
+ case ESCAPE_FONTPREV:
font = h->metal;
break;
- case (ESCAPE_FONTITALIC):
+ case ESCAPE_FONTITALIC:
font = HTMLFONT_ITALIC;
break;
- case (ESCAPE_FONTBOLD):
+ case ESCAPE_FONTBOLD:
font = HTMLFONT_BOLD;
break;
- case (ESCAPE_FONTBI):
+ case ESCAPE_FONTBI:
font = HTMLFONT_BI;
break;
- case (ESCAPE_FONT):
+ case ESCAPE_FONT:
/* FALLTHROUGH */
- case (ESCAPE_FONTROMAN):
+ case ESCAPE_FONTROMAN:
font = HTMLFONT_NONE;
break;
default:
@@ -257,13 +255,13 @@ print_metaf(struct html *h, enum mandoc_esc deco)
h->metac = font;
switch (font) {
- case (HTMLFONT_ITALIC):
+ case HTMLFONT_ITALIC:
h->metaf = print_otag(h, TAG_I, 0, NULL);
break;
- case (HTMLFONT_BOLD):
+ case HTMLFONT_BOLD:
h->metaf = print_otag(h, TAG_B, 0, NULL);
break;
- case (HTMLFONT_BI):
+ case HTMLFONT_BI:
h->metaf = print_otag(h, TAG_B, 0, NULL);
print_otag(h, TAG_I, 0, NULL);
break;
@@ -302,19 +300,21 @@ html_strlen(const char *cp)
break;
cp++;
switch (mandoc_escape(&cp, NULL, NULL)) {
- case (ESCAPE_ERROR):
+ case ESCAPE_ERROR:
return(sz);
- case (ESCAPE_UNICODE):
+ case ESCAPE_UNICODE:
/* FALLTHROUGH */
- case (ESCAPE_NUMBERED):
+ case ESCAPE_NUMBERED:
/* FALLTHROUGH */
- case (ESCAPE_SPECIAL):
+ case ESCAPE_SPECIAL:
+ /* FALLTHROUGH */
+ case ESCAPE_OVERSTRIKE:
if (skip)
skip = 0;
else
sz++;
break;
- case (ESCAPE_SKIPCHAR):
+ case ESCAPE_SKIPCHAR:
skip = 1;
break;
default:
@@ -325,13 +325,45 @@ html_strlen(const char *cp)
}
static int
+print_escape(char c)
+{
+
+ switch (c) {
+ case '<':
+ printf("&lt;");
+ break;
+ case '>':
+ printf("&gt;");
+ break;
+ case '&':
+ printf("&amp;");
+ break;
+ case '"':
+ printf("&quot;");
+ break;
+ case ASCII_NBRSP:
+ putchar('-');
+ break;
+ case ASCII_HYPH:
+ putchar('-');
+ /* FALLTHROUGH */
+ case ASCII_BREAK:
+ break;
+ default:
+ return(0);
+ }
+ return(1);
+}
+
+static int
print_encode(struct html *h, const char *p, int norecurse)
{
size_t sz;
int c, len, nospace;
const char *seq;
enum mandoc_esc esc;
- static const char rejs[6] = { '\\', '<', '>', '&', ASCII_HYPH, '\0' };
+ static const char rejs[9] = { '\\', '<', '>', '&', '"',
+ ASCII_NBRSP, ASCII_HYPH, ASCII_BREAK, '\0' };
nospace = 0;
@@ -350,43 +382,29 @@ print_encode(struct html *h, const char *p, int norecurse)
if ('\0' == *p)
break;
- switch (*p++) {
- case ('<'):
- printf("&lt;");
- continue;
- case ('>'):
- printf("&gt;");
- continue;
- case ('&'):
- printf("&amp;");
- continue;
- case (ASCII_HYPH):
- putchar('-');
+ if (print_escape(*p++))
continue;
- default:
- break;
- }
esc = mandoc_escape(&p, &seq, &len);
if (ESCAPE_ERROR == esc)
break;
switch (esc) {
- case (ESCAPE_FONT):
+ case ESCAPE_FONT:
/* FALLTHROUGH */
- case (ESCAPE_FONTPREV):
+ case ESCAPE_FONTPREV:
/* FALLTHROUGH */
- case (ESCAPE_FONTBOLD):
+ case ESCAPE_FONTBOLD:
/* FALLTHROUGH */
- case (ESCAPE_FONTITALIC):
+ case ESCAPE_FONTITALIC:
/* FALLTHROUGH */
- case (ESCAPE_FONTBI):
+ case ESCAPE_FONTBI:
/* FALLTHROUGH */
- case (ESCAPE_FONTROMAN):
+ case ESCAPE_FONTROMAN:
if (0 == norecurse)
print_metaf(h, esc);
continue;
- case (ESCAPE_SKIPCHAR):
+ case ESCAPE_SKIPCHAR:
h->flags |= HTML_SKIPCHAR;
continue;
default:
@@ -399,37 +417,44 @@ print_encode(struct html *h, const char *p, int norecurse)
}
switch (esc) {
- case (ESCAPE_UNICODE):
- /* Skip passed "u" header. */
+ case ESCAPE_UNICODE:
+ /* Skip past "u" header. */
c = mchars_num2uc(seq + 1, len - 1);
- if ('\0' != c)
- printf("&#x%x;", c);
break;
- case (ESCAPE_NUMBERED):
+ case ESCAPE_NUMBERED:
c = mchars_num2char(seq, len);
- if ('\0' != c)
- putchar(c);
+ if (c < 0)
+ continue;
break;
- case (ESCAPE_SPECIAL):
+ case ESCAPE_SPECIAL:
c = mchars_spec2cp(h->symtab, seq, len);
- if (c > 0)
- printf("&#%d;", c);
- else if (-1 == c && 1 == len)
- putchar((int)*seq);
+ if (c <= 0)
+ continue;
break;
- case (ESCAPE_NOSPACE):
+ case ESCAPE_NOSPACE:
if ('\0' == *p)
nospace = 1;
+ continue;
+ case ESCAPE_OVERSTRIKE:
+ if (len == 0)
+ continue;
+ c = seq[len - 1];
break;
default:
- break;
+ continue;
}
+ if ((c < 0x20 && c != 0x09) ||
+ (c > 0x7E && c < 0xA0))
+ c = 0xFFFD;
+ if (c > 0x7E)
+ printf("&#%d;", c);
+ else if ( ! print_escape(c))
+ putchar(c);
}
return(nospace);
}
-
static void
print_attr(struct html *h, const char *key, const char *val)
{
@@ -438,9 +463,8 @@ print_attr(struct html *h, const char *key, const char *val)
putchar('\"');
}
-
struct tag *
-print_otag(struct html *h, enum htmltag tag,
+print_otag(struct html *h, enum htmltag tag,
int sz, const struct htmlpair *p)
{
int i;
@@ -478,24 +502,10 @@ print_otag(struct html *h, enum htmltag tag,
for (i = 0; i < sz; i++)
print_attr(h, htmlattrs[p[i].key], p[i].val);
- /* Add non-overridable attributes. */
-
- if (TAG_HTML == tag && HTML_XHTML_1_0_STRICT == h->type) {
- print_attr(h, "xmlns", "http://www.w3.org/1999/xhtml");
- print_attr(h, "xml:lang", "en");
- print_attr(h, "lang", "en");
- }
-
- /* Accommodate for XML "well-formed" singleton escaping. */
+ /* Accommodate for "well-formed" singleton escaping. */
if (HTML_AUTOCLOSE & htmltags[tag].flags)
- switch (h->type) {
- case (HTML_XHTML_1_0_STRICT):
- putchar('/');
- break;
- default:
- break;
- }
+ putchar('/');
putchar('>');
@@ -507,41 +517,34 @@ print_otag(struct html *h, enum htmltag tag,
return(t);
}
-
static void
-print_ctag(struct html *h, enum htmltag tag)
+print_ctag(struct html *h, struct tag *tag)
{
-
- printf("</%s>", htmltags[tag].name);
- if (HTML_CLRLINE & htmltags[tag].flags) {
+
+ /*
+ * Remember to close out and nullify the current
+ * meta-font and table, if applicable.
+ */
+ if (tag == h->metaf)
+ h->metaf = NULL;
+ if (tag == h->tblt)
+ h->tblt = NULL;
+
+ printf("</%s>", htmltags[tag->tag].name);
+ if (HTML_CLRLINE & htmltags[tag->tag].flags) {
h->flags |= HTML_NOSPACE;
putchar('\n');
- }
+ }
+
+ h->tags.head = tag->next;
+ free(tag);
}
void
print_gen_decls(struct html *h)
{
- const char *doctype;
- const char *dtd;
- const char *name;
-
- switch (h->type) {
- case (HTML_HTML_4_01_STRICT):
- name = "HTML";
- doctype = "-//W3C//DTD HTML 4.01//EN";
- dtd = "http://www.w3.org/TR/html4/strict.dtd";
- break;
- default:
- puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
- name = "html";
- doctype = "-//W3C//DTD XHTML 1.0 Strict//EN";
- dtd = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";
- break;
- }
- printf("<!DOCTYPE %s PUBLIC \"%s\" \"%s\">\n",
- name, doctype, dtd);
+ puts("<!DOCTYPE html>");
}
void
@@ -560,13 +563,13 @@ print_text(struct html *h, const char *word)
assert(NULL == h->metaf);
switch (h->metac) {
- case (HTMLFONT_ITALIC):
+ case HTMLFONT_ITALIC:
h->metaf = print_otag(h, TAG_I, 0, NULL);
break;
- case (HTMLFONT_BOLD):
+ case HTMLFONT_BOLD:
h->metaf = print_otag(h, TAG_B, 0, NULL);
break;
- case (HTMLFONT_BI):
+ case HTMLFONT_BI:
h->metaf = print_otag(h, TAG_B, 0, NULL);
print_otag(h, TAG_I, 0, NULL);
break;
@@ -578,8 +581,9 @@ print_text(struct html *h, const char *word)
if ( ! print_encode(h, word, 0)) {
if ( ! (h->flags & HTML_NONOSPACE))
h->flags &= ~HTML_NOSPACE;
+ h->flags &= ~HTML_NONEWLINE;
} else
- h->flags |= HTML_NOSPACE;
+ h->flags |= HTML_NOSPACE | HTML_NONEWLINE;
if (h->metaf) {
print_tagq(h, h->metaf);
@@ -589,30 +593,18 @@ print_text(struct html *h, const char *word)
h->flags &= ~HTML_IGNDELIM;
}
-
void
print_tagq(struct html *h, const struct tag *until)
{
struct tag *tag;
while ((tag = h->tags.head) != NULL) {
- /*
- * Remember to close out and nullify the current
- * meta-font and table, if applicable.
- */
- if (tag == h->metaf)
- h->metaf = NULL;
- if (tag == h->tblt)
- h->tblt = NULL;
- print_ctag(h, tag->tag);
- h->tags.head = tag->next;
- free(tag);
+ print_ctag(h, tag);
if (until && tag == until)
return;
}
}
-
void
print_stagq(struct html *h, const struct tag *suntil)
{
@@ -621,21 +613,23 @@ print_stagq(struct html *h, const struct tag *suntil)
while ((tag = h->tags.head) != NULL) {
if (suntil && tag == suntil)
return;
- /*
- * Remember to close out and nullify the current
- * meta-font and table, if applicable.
- */
- if (tag == h->metaf)
- h->metaf = NULL;
- if (tag == h->tblt)
- h->tblt = NULL;
- print_ctag(h, tag->tag);
- h->tags.head = tag->next;
- free(tag);
+ print_ctag(h, tag);
}
}
void
+print_paragraph(struct html *h)
+{
+ struct tag *t;
+ struct htmlpair tag;
+
+ PAIR_CLASS_INIT(&tag, "spacer");
+ t = print_otag(h, TAG_DIV, 1, &tag);
+ print_tagq(h, t);
+}
+
+
+void
bufinit(struct html *h)
{
@@ -657,6 +651,12 @@ void
bufcat(struct html *h, const char *p)
{
+ /*
+ * XXX This is broken and not easy to fix.
+ * When using the -Oincludes option, buffmt_includes()
+ * may pass in strings overrunning BUFSIZ, causing a crash.
+ */
+
h->buflen = strlcat(h->buf, p, BUFSIZ);
assert(h->buflen < BUFSIZ);
}
@@ -667,8 +667,8 @@ bufcat_fmt(struct html *h, const char *fmt, ...)
va_list ap;
va_start(ap, fmt);
- (void)vsnprintf(h->buf + (int)h->buflen,
- BUFSIZ - h->buflen - 1, fmt, ap);
+ (void)vsnprintf(h->buf + (int)h->buflen,
+ BUFSIZ - h->buflen - 1, fmt, ap);
va_end(ap);
h->buflen = strlen(h->buf);
}
@@ -688,12 +688,12 @@ buffmt_includes(struct html *h, const char *name)
const char *p, *pp;
pp = h->base_includes;
-
+
bufinit(h);
while (NULL != (p = strchr(pp, '%'))) {
bufncat(h, pp, (size_t)(p - pp));
switch (*(p + 1)) {
- case('I'):
+ case'I':
bufcat(h, name);
break;
default:
@@ -707,22 +707,21 @@ buffmt_includes(struct html *h, const char *name)
}
void
-buffmt_man(struct html *h,
- const char *name, const char *sec)
+buffmt_man(struct html *h, const char *name, const char *sec)
{
const char *p, *pp;
pp = h->base_man;
-
+
bufinit(h);
while (NULL != (p = strchr(pp, '%'))) {
bufncat(h, pp, (size_t)(p - pp));
switch (*(p + 1)) {
- case('S'):
+ case 'S':
bufcat(h, sec ? sec : "1");
break;
- case('N'):
- bufcat_fmt(h, name);
+ case 'N':
+ bufcat_fmt(h, "%s", name);
break;
default:
bufncat(h, p, 2);
@@ -742,6 +741,8 @@ bufcat_su(struct html *h, const char *p, const struct roffsu *su)
v = su->scale;
if (SCALE_MM == su->unit && 0.0 == (v /= 100.0))
v = 1.0;
+ else if (SCALE_BU == su->unit)
+ v /= 24.0;
bufcat_fmt(h, "%s: %.2f%s;", p, v, roffscales[su->unit]);
}
diff --git a/usr/src/cmd/mandoc/html.h b/usr/src/cmd/mandoc/html.h
index 894cfc4cff..bbf6183cc5 100644
--- a/usr/src/cmd/mandoc/html.h
+++ b/usr/src/cmd/mandoc/html.h
@@ -1,6 +1,6 @@
-/* $Id: html.h,v 1.49 2013/08/08 20:07:47 schwarze Exp $ */
+/* $Id: html.h,v 1.70 2014/12/02 10:08:06 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,10 +14,6 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef HTML_H
-#define HTML_H
-
-__BEGIN_DECLS
enum htmltag {
TAG_HTML,
@@ -44,18 +40,32 @@ enum htmltag {
TAG_DT,
TAG_DD,
TAG_BLOCKQUOTE,
- TAG_P,
TAG_PRE,
TAG_B,
TAG_I,
TAG_CODE,
TAG_SMALL,
+ TAG_STYLE,
+ TAG_MATH,
+ TAG_MROW,
+ TAG_MI,
+ TAG_MO,
+ TAG_MSUP,
+ TAG_MSUB,
+ TAG_MSUBSUP,
+ TAG_MFRAC,
+ TAG_MSQRT,
+ TAG_MFENCED,
+ TAG_MTABLE,
+ TAG_MTR,
+ TAG_MTD,
+ TAG_MUNDEROVER,
+ TAG_MUNDER,
+ TAG_MOVER,
TAG_MAX
};
enum htmlattr {
- ATTR_HTTPEQUIV,
- ATTR_CONTENT,
ATTR_NAME,
ATTR_REL,
ATTR_HREF,
@@ -63,11 +73,12 @@ enum htmlattr {
ATTR_MEDIA,
ATTR_CLASS,
ATTR_STYLE,
- ATTR_WIDTH,
ATTR_ID,
- ATTR_SUMMARY,
- ATTR_ALIGN,
ATTR_COLSPAN,
+ ATTR_CHARSET,
+ ATTR_OPEN,
+ ATTR_CLOSE,
+ ATTR_MATHVARIANT,
ATTR_MAX
};
@@ -103,12 +114,6 @@ struct htmlpair {
#define PAIR_CLASS_INIT(p, v) PAIR_INIT(p, ATTR_CLASS, v)
#define PAIR_HREF_INIT(p, v) PAIR_INIT(p, ATTR_HREF, v)
#define PAIR_STYLE_INIT(p, h) PAIR_INIT(p, ATTR_STYLE, (h)->buf)
-#define PAIR_SUMMARY_INIT(p, v) PAIR_INIT(p, ATTR_SUMMARY, v)
-
-enum htmltype {
- HTML_HTML_4_01_STRICT,
- HTML_XHTML_1_0_STRICT
-};
struct html {
int flags;
@@ -119,26 +124,33 @@ struct html {
#define HTML_NONOSPACE (1 << 4) /* never add spaces */
#define HTML_LITERAL (1 << 5) /* literal (e.g., <PRE>) context */
#define HTML_SKIPCHAR (1 << 6) /* skip the next character */
+#define HTML_NOSPLIT (1 << 7) /* do not break line before .An */
+#define HTML_SPLIT (1 << 8) /* break line before .An */
+#define HTML_NONEWLINE (1 << 9) /* No line break in nofill mode. */
struct tagq tags; /* stack of open tags */
struct rofftbl tbl; /* current table */
struct tag *tblt; /* current open table scope */
- struct mchars *symtab; /* character-escapes */
+ const struct mchars *symtab; /* character table */
char *base_man; /* base for manpage href */
char *base_includes; /* base for include href */
char *style; /* style-sheet URI */
char buf[BUFSIZ]; /* see bufcat and friends */
- size_t buflen;
+ size_t buflen;
struct tag *metaf; /* current open font scope */
enum htmlfont metal; /* last used font */
enum htmlfont metac; /* current font mode */
- enum htmltype type; /* output media type */
int oflags; /* output options */
#define HTML_FRAGMENT (1 << 0) /* don't emit HTML/HEAD/BODY */
};
+__BEGIN_DECLS
+
+struct tbl_span;
+struct eqn;
+
void print_gen_decls(struct html *);
void print_gen_head(struct html *);
-struct tag *print_otag(struct html *, enum htmltag,
+struct tag *print_otag(struct html *, enum htmltag,
int, const struct htmlpair *);
void print_tagq(struct html *, const struct tag *);
void print_stagq(struct html *, const struct tag *);
@@ -146,21 +158,23 @@ void print_text(struct html *, const char *);
void print_tblclose(struct html *);
void print_tbl(struct html *, const struct tbl_span *);
void print_eqn(struct html *, const struct eqn *);
+void print_paragraph(struct html *);
+#if __GNUC__ - 0 >= 4
+__attribute__((__format__ (__printf__, 2, 3)))
+#endif
void bufcat_fmt(struct html *, const char *, ...);
void bufcat(struct html *, const char *);
void bufcat_id(struct html *, const char *);
-void bufcat_style(struct html *,
+void bufcat_style(struct html *,
const char *, const char *);
-void bufcat_su(struct html *, const char *,
+void bufcat_su(struct html *, const char *,
const struct roffsu *);
void bufinit(struct html *);
-void buffmt_man(struct html *,
+void buffmt_man(struct html *,
const char *, const char *);
void buffmt_includes(struct html *, const char *);
int html_strlen(const char *);
__END_DECLS
-
-#endif /*!HTML_H*/
diff --git a/usr/src/cmd/mandoc/lib.c b/usr/src/cmd/mandoc/lib.c
index 7a18a5dd4f..17ce5296de 100644
--- a/usr/src/cmd/mandoc/lib.c
+++ b/usr/src/cmd/mandoc/lib.c
@@ -1,4 +1,4 @@
-/* $Id: lib.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */
+/* $Id: lib.c,v 1.11 2014/08/10 23:54:41 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -14,16 +14,13 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
-#include <stdlib.h>
+#include <sys/types.h>
+
#include <string.h>
-#include <time.h>
#include "mdoc.h"
-#include "mandoc.h"
#include "libmdoc.h"
#define LINE(x, y) \
diff --git a/usr/src/cmd/mandoc/libman.h b/usr/src/cmd/mandoc/libman.h
index f2ba6a1256..8d115b3abe 100644
--- a/usr/src/cmd/mandoc/libman.h
+++ b/usr/src/cmd/mandoc/libman.h
@@ -1,6 +1,7 @@
-/* $Id: libman.h,v 1.56 2012/11/17 00:26:33 schwarze Exp $ */
+/* $Id: libman.h,v 1.67 2014/12/28 14:42:27 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,8 +15,6 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef LIBMAN_H
-#define LIBMAN_H
enum man_next {
MAN_NEXT_SIBLING = 0,
@@ -24,13 +23,12 @@ enum man_next {
struct man {
struct mparse *parse; /* parse pointer */
+ const char *defos; /* default OS argument for .TH */
+ int quick; /* abort parse early */
int flags; /* parse flags */
-#define MAN_HALT (1 << 0) /* badness happened: die */
#define MAN_ELINE (1 << 1) /* Next-line element scope. */
#define MAN_BLINE (1 << 2) /* Next-line block scope. */
-#define MAN_ILINE (1 << 3) /* Ignored in next-line scope. */
#define MAN_LITERAL (1 << 4) /* Literal input. */
-#define MAN_BPLINE (1 << 5)
#define MAN_NEWLINE (1 << 6) /* first macro/text in a line */
enum man_next next; /* where to put the next node */
struct man_node *last; /* the last parsed node */
@@ -47,7 +45,7 @@ struct man {
char *buf
struct man_macro {
- int (*fp)(MACRO_PROT_ARGS);
+ void (*fp)(MACRO_PROT_ARGS);
int flags;
#define MAN_SCOPED (1 << 0)
#define MAN_EXPLICIT (1 << 1) /* See blk_imp(). */
@@ -55,31 +53,24 @@ struct man_macro {
#define MAN_NSCOPED (1 << 3) /* See in_line_eoln(). */
#define MAN_NOCLOSE (1 << 4) /* See blk_exp(). */
#define MAN_BSCOPE (1 << 5) /* Break BLINE scope. */
+#define MAN_JOIN (1 << 6) /* Join arguments together. */
};
extern const struct man_macro *const man_macros;
__BEGIN_DECLS
-#define man_pmsg(man, l, p, t) \
- mandoc_msg((t), (man)->parse, (l), (p), NULL)
-#define man_nmsg(man, n, t) \
- mandoc_msg((t), (man)->parse, (n)->line, (n)->pos, NULL)
-int man_word_alloc(struct man *, int, int, const char *);
-int man_block_alloc(struct man *, int, int, enum mant);
-int man_head_alloc(struct man *, int, int, enum mant);
-int man_tail_alloc(struct man *, int, int, enum mant);
-int man_body_alloc(struct man *, int, int, enum mant);
-int man_elem_alloc(struct man *, int, int, enum mant);
+void man_word_alloc(struct man *, int, int, const char *);
+void man_word_append(struct man *, const char *);
+void man_block_alloc(struct man *, int, int, enum mant);
+void man_head_alloc(struct man *, int, int, enum mant);
+void man_body_alloc(struct man *, int, int, enum mant);
+void man_elem_alloc(struct man *, int, int, enum mant);
void man_node_delete(struct man *, struct man_node *);
void man_hash_init(void);
enum mant man_hash_find(const char *);
-int man_macroend(struct man *);
-int man_valid_post(struct man *);
-int man_valid_pre(struct man *, struct man_node *);
-int man_unscope(struct man *,
- const struct man_node *, enum mandocerr);
+void man_macroend(struct man *);
+void man_valid_post(struct man *);
+void man_unscope(struct man *, const struct man_node *);
__END_DECLS
-
-#endif /*!LIBMAN_H*/
diff --git a/usr/src/cmd/mandoc/libmandoc.h b/usr/src/cmd/mandoc/libmandoc.h
index 3c005e106d..11feebdc10 100644
--- a/usr/src/cmd/mandoc/libmandoc.h
+++ b/usr/src/cmd/mandoc/libmandoc.h
@@ -1,7 +1,7 @@
-/* $Id: libmandoc.h,v 1.35 2013/12/15 21:23:52 schwarze Exp $ */
+/* $Id: libmandoc.h,v 1.55 2015/01/15 04:26:39 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013, 2014 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,8 +15,6 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef LIBMANDOC_H
-#define LIBMANDOC_H
enum rofferr {
ROFF_CONT, /* continue processing line */
@@ -26,63 +24,72 @@ enum rofferr {
ROFF_SO, /* include another file */
ROFF_IGN, /* ignore current line */
ROFF_TBL, /* a table row was successfully parsed */
- ROFF_EQN, /* an equation was successfully parsed */
- ROFF_ERR /* badness: puke and stop */
+ ROFF_EQN /* an equation was successfully parsed */
+};
+
+struct buf {
+ char *buf;
+ size_t sz;
};
__BEGIN_DECLS
+struct mparse;
+struct mchars;
+struct tbl_span;
+struct eqn;
struct roff;
struct mdoc;
struct man;
-void mandoc_msg(enum mandocerr, struct mparse *,
+void mandoc_msg(enum mandocerr, struct mparse *,
int, int, const char *);
-void mandoc_vmsg(enum mandocerr, struct mparse *,
+#if __GNUC__ - 0 >= 4
+__attribute__((__format__ (__printf__, 5, 6)))
+#endif
+void mandoc_vmsg(enum mandocerr, struct mparse *,
int, int, const char *, ...);
char *mandoc_getarg(struct mparse *, char **, int, int *);
char *mandoc_normdate(struct mparse *, char *, int, int);
-int mandoc_eos(const char *, size_t, int);
+int mandoc_eos(const char *, size_t);
int mandoc_strntoi(const char *, size_t, int);
const char *mandoc_a2msec(const char*);
-void mdoc_free(struct mdoc *);
-struct mdoc *mdoc_alloc(struct roff *, struct mparse *, char *);
+void mdoc_free(struct mdoc *);
+struct mdoc *mdoc_alloc(struct roff *, struct mparse *,
+ const char *, int);
void mdoc_reset(struct mdoc *);
-int mdoc_parseln(struct mdoc *, int, char *, int);
-int mdoc_endparse(struct mdoc *);
-int mdoc_addspan(struct mdoc *, const struct tbl_span *);
-int mdoc_addeqn(struct mdoc *, const struct eqn *);
+int mdoc_parseln(struct mdoc *, int, char *, int);
+void mdoc_endparse(struct mdoc *);
+void mdoc_addspan(struct mdoc *, const struct tbl_span *);
+void mdoc_addeqn(struct mdoc *, const struct eqn *);
-void man_free(struct man *);
-struct man *man_alloc(struct roff *, struct mparse *);
+void man_free(struct man *);
+struct man *man_alloc(struct roff *, struct mparse *,
+ const char *, int);
void man_reset(struct man *);
-int man_parseln(struct man *, int, char *, int);
-int man_endparse(struct man *);
-int man_addspan(struct man *, const struct tbl_span *);
-int man_addeqn(struct man *, const struct eqn *);
+int man_parseln(struct man *, int, char *, int);
+void man_endparse(struct man *);
+void man_addspan(struct man *, const struct tbl_span *);
+void man_addeqn(struct man *, const struct eqn *);
+
+int preconv_cue(const struct buf *, size_t);
+int preconv_encode(struct buf *, size_t *,
+ struct buf *, size_t *, int *);
-void roff_free(struct roff *);
-struct roff *roff_alloc(enum mparset, struct mparse *);
+void roff_free(struct roff *);
+struct roff *roff_alloc(struct mparse *, const struct mchars *, int);
void roff_reset(struct roff *);
-enum rofferr roff_parseln(struct roff *, int,
- char **, size_t *, int, int *);
+enum rofferr roff_parseln(struct roff *, int, struct buf *, int *);
void roff_endparse(struct roff *);
void roff_setreg(struct roff *, const char *, int, char sign);
int roff_getreg(const struct roff *, const char *);
char *roff_strdup(const struct roff *, const char *);
-int roff_getcontrol(const struct roff *,
+int roff_getcontrol(const struct roff *,
const char *, int *);
-#if 0
-char roff_eqndelim(const struct roff *);
-void roff_openeqn(struct roff *, const char *,
- int, int, const char *);
-int roff_closeeqn(struct roff *);
-#endif
+int roff_getformat(const struct roff *);
const struct tbl_span *roff_span(const struct roff *);
const struct eqn *roff_eqn(const struct roff *);
__END_DECLS
-
-#endif /*!LIBMANDOC_H*/
diff --git a/usr/src/cmd/mandoc/libmdoc.h b/usr/src/cmd/mandoc/libmdoc.h
index 3f14519d3b..527fe02703 100644
--- a/usr/src/cmd/mandoc/libmdoc.h
+++ b/usr/src/cmd/mandoc/libmdoc.h
@@ -1,7 +1,7 @@
-/* $Id: libmdoc.h,v 1.82 2013/10/21 23:47:58 schwarze Exp $ */
+/* $Id: libmdoc.h,v 1.97 2015/02/02 04:26:44 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013, 2014 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,8 +15,6 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef LIBMDOC_H
-#define LIBMDOC_H
enum mdoc_next {
MDOC_NEXT_SIBLING = 0,
@@ -25,9 +23,9 @@ enum mdoc_next {
struct mdoc {
struct mparse *parse; /* parse pointer */
- char *defos; /* default argument for .Os */
+ const char *defos; /* default argument for .Os */
+ int quick; /* abort parse early */
int flags; /* parse flags */
-#define MDOC_HALT (1 << 0) /* error in parse: halt */
#define MDOC_LITERAL (1 << 1) /* in a literal scope */
#define MDOC_PBODY (1 << 2) /* in the document body */
#define MDOC_NEWLINE (1 << 3) /* first macro/text in a line */
@@ -37,9 +35,11 @@ struct mdoc {
#define MDOC_SYNOPSIS (1 << 7) /* SYNOPSIS-style formatting */
#define MDOC_KEEP (1 << 8) /* in a word keep */
#define MDOC_SMOFF (1 << 9) /* spacing is off */
+#define MDOC_NODELIMC (1 << 10) /* disable closing delimiter handling */
enum mdoc_next next; /* where to put the next node */
struct mdoc_node *last; /* the last node parsed */
struct mdoc_node *first; /* the first node parsed */
+ struct mdoc_node *last_es; /* the most recent Es node */
struct mdoc_meta meta; /* document meta-data */
enum mdoc_sec lastnamed;
enum mdoc_sec lastsec;
@@ -54,7 +54,7 @@ struct mdoc {
char *buf
struct mdoc_macro {
- int (*fp)(MACRO_PROT_ARGS);
+ void (*fp)(MACRO_PROT_ARGS);
int flags;
#define MDOC_CALLABLE (1 << 0)
#define MDOC_PARSED (1 << 1)
@@ -75,13 +75,6 @@ enum margserr {
ARGS_PEND /* last phrase (-column) */
};
-enum margverr {
- ARGV_ERROR,
- ARGV_EOLN, /* end of line */
- ARGV_ARG, /* valid argument */
- ARGV_WORD /* normal word (or bad argument---same thing) */
-};
-
/*
* A punctuation delimiter is opening, closing, or "middle mark"
* punctuation. These govern spacing.
@@ -103,44 +96,34 @@ extern const struct mdoc_macro *const mdoc_macros;
__BEGIN_DECLS
-#define mdoc_pmsg(mdoc, l, p, t) \
- mandoc_msg((t), (mdoc)->parse, (l), (p), NULL)
-#define mdoc_nmsg(mdoc, n, t) \
- mandoc_msg((t), (mdoc)->parse, (n)->line, (n)->pos, NULL)
-int mdoc_macro(MACRO_PROT_ARGS);
-int mdoc_word_alloc(struct mdoc *,
- int, int, const char *);
+void mdoc_macro(MACRO_PROT_ARGS);
+void mdoc_word_alloc(struct mdoc *, int, int, const char *);
void mdoc_word_append(struct mdoc *, const char *);
-int mdoc_elem_alloc(struct mdoc *, int, int,
+void mdoc_elem_alloc(struct mdoc *, int, int,
enum mdoct, struct mdoc_arg *);
-int mdoc_block_alloc(struct mdoc *, int, int,
+struct mdoc_node *mdoc_block_alloc(struct mdoc *, int, int,
enum mdoct, struct mdoc_arg *);
-int mdoc_head_alloc(struct mdoc *, int, int, enum mdoct);
-int mdoc_tail_alloc(struct mdoc *, int, int, enum mdoct);
-int mdoc_body_alloc(struct mdoc *, int, int, enum mdoct);
-int mdoc_endbody_alloc(struct mdoc *, int, int, enum mdoct,
+struct mdoc_node *mdoc_head_alloc(struct mdoc *, int, int, enum mdoct);
+void mdoc_tail_alloc(struct mdoc *, int, int, enum mdoct);
+struct mdoc_node *mdoc_body_alloc(struct mdoc *, int, int, enum mdoct);
+struct mdoc_node *mdoc_endbody_alloc(struct mdoc *, int, int, enum mdoct,
struct mdoc_node *, enum mdoc_endbody);
void mdoc_node_delete(struct mdoc *, struct mdoc_node *);
-int mdoc_node_relink(struct mdoc *, struct mdoc_node *);
+void mdoc_node_relink(struct mdoc *, struct mdoc_node *);
void mdoc_hash_init(void);
enum mdoct mdoc_hash_find(const char *);
const char *mdoc_a2att(const char *);
const char *mdoc_a2lib(const char *);
const char *mdoc_a2st(const char *);
const char *mdoc_a2arch(const char *);
-const char *mdoc_a2vol(const char *);
-int mdoc_valid_pre(struct mdoc *, struct mdoc_node *);
-int mdoc_valid_post(struct mdoc *);
-enum margverr mdoc_argv(struct mdoc *, int, enum mdoct,
+void mdoc_valid_pre(struct mdoc *, struct mdoc_node *);
+void mdoc_valid_post(struct mdoc *);
+void mdoc_argv(struct mdoc *, int, enum mdoct,
struct mdoc_arg **, int *, char *);
void mdoc_argv_free(struct mdoc_arg *);
enum margserr mdoc_args(struct mdoc *, int,
int *, char *, enum mdoct, char **);
-enum margserr mdoc_zargs(struct mdoc *, int,
- int *, char *, char **);
-int mdoc_macroend(struct mdoc *);
+void mdoc_macroend(struct mdoc *);
enum mdelim mdoc_isdelim(const char *);
__END_DECLS
-
-#endif /*!LIBMDOC_H*/
diff --git a/usr/src/cmd/mandoc/libroff.h b/usr/src/cmd/mandoc/libroff.h
index 5b84c5fc45..08ed1f7925 100644
--- a/usr/src/cmd/mandoc/libroff.h
+++ b/usr/src/cmd/mandoc/libroff.h
@@ -1,6 +1,7 @@
-/* $Id: libroff.h,v 1.28 2013/05/31 21:37:17 schwarze Exp $ */
+/* $Id: libroff.h,v 1.38 2015/01/30 04:11:50 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014, 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
@@ -14,10 +15,6 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef LIBROFF_H
-#define LIBROFF_H
-
-__BEGIN_DECLS
enum tbl_part {
TBL_PART_OPTS, /* in options (first line) */
@@ -37,22 +34,23 @@ struct tbl_node {
struct tbl_span *first_span;
struct tbl_span *current_span;
struct tbl_span *last_span;
- struct tbl_head *first_head;
- struct tbl_head *last_head;
struct tbl_node *next;
};
struct eqn_node {
- struct eqn_def *defs;
- size_t defsz;
- char *data;
- size_t rew;
- size_t cur;
- size_t sz;
- int gsize;
- struct eqn eqn;
- struct mparse *parse;
- struct eqn_node *next;
+ struct eqn eqn; /* syntax tree of this equation */
+ struct mparse *parse; /* main parser, for error reporting */
+ struct eqn_node *next; /* singly linked list of equations */
+ struct eqn_def *defs; /* array of definitions */
+ char *data; /* source code of this equation */
+ size_t defsz; /* number of definitions */
+ size_t sz; /* length of the source code */
+ size_t cur; /* parse point in the source code */
+ size_t rew; /* beginning of the current token */
+ int gsize; /* default point size */
+ int delim; /* in-line delimiters enabled */
+ char odelim; /* in-line opening delimiter */
+ char cdelim; /* in-line closing delimiter */
};
struct eqn_def {
@@ -62,23 +60,23 @@ struct eqn_def {
size_t valsz;
};
+__BEGIN_DECLS
+
struct tbl_node *tbl_alloc(int, int, struct mparse *);
void tbl_restart(int, int, struct tbl_node *);
void tbl_free(struct tbl_node *);
void tbl_reset(struct tbl_node *);
-enum rofferr tbl_read(struct tbl_node *, int, const char *, int);
-int tbl_option(struct tbl_node *, int, const char *);
-int tbl_layout(struct tbl_node *, int, const char *);
-int tbl_data(struct tbl_node *, int, const char *);
-int tbl_cdata(struct tbl_node *, int, const char *);
+enum rofferr tbl_read(struct tbl_node *, int, const char *, int);
+void tbl_option(struct tbl_node *, int, const char *, int *);
+void tbl_layout(struct tbl_node *, int, const char *, int);
+void tbl_data(struct tbl_node *, int, const char *, int);
+int tbl_cdata(struct tbl_node *, int, const char *, int);
const struct tbl_span *tbl_span(struct tbl_node *);
-void tbl_end(struct tbl_node **);
-struct eqn_node *eqn_alloc(const char *, int, int, struct mparse *);
+int tbl_end(struct tbl_node **);
+struct eqn_node *eqn_alloc(int, int, struct mparse *);
enum rofferr eqn_end(struct eqn_node **);
void eqn_free(struct eqn_node *);
-enum rofferr eqn_read(struct eqn_node **, int,
+enum rofferr eqn_read(struct eqn_node **, int,
const char *, int, int *);
__END_DECLS
-
-#endif /*LIBROFF_H*/
diff --git a/usr/src/cmd/mandoc/main.c b/usr/src/cmd/mandoc/main.c
index 7e5c7a98ae..f0cd8ca0cc 100644
--- a/usr/src/cmd/mandoc/main.c
+++ b/usr/src/cmd/mandoc/main.c
@@ -1,7 +1,8 @@
-/* $Id: main.c,v 1.167 2012/11/19 17:22:26 schwarze Exp $ */
+/* $Id: main.c,v 1.225 2015/03/10 13:50:03 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2011, 2012 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2010-2012, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -15,11 +16,17 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
+
+#include <sys/types.h>
+#include <sys/param.h> /* MACHINE */
+#include <sys/wait.h>
#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <glob.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
@@ -27,9 +34,12 @@
#include <unistd.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "main.h"
#include "mdoc.h"
#include "man.h"
+#include "manpath.h"
+#include "mansearch.h"
#if !defined(__GNUC__) || (__GNUC__ < 2)
# if !defined(lint)
@@ -37,6 +47,15 @@
# endif
#endif /* !defined(__GNUC__) || (__GNUC__ < 2) */
+enum outmode {
+ OUTMODE_DEF = 0,
+ OUTMODE_FLN,
+ OUTMODE_LST,
+ OUTMODE_ALL,
+ OUTMODE_INT,
+ OUTMODE_ONE
+};
+
typedef void (*out_mdoc)(void *, const struct mdoc *);
typedef void (*out_man)(void *, const struct man *);
typedef void (*out_free)(void *);
@@ -48,7 +67,6 @@ enum outt {
OUTT_TREE, /* -Ttree */
OUTT_MAN, /* -Tman */
OUTT_HTML, /* -Thtml */
- OUTT_XHTML, /* -Txhtml */
OUTT_LINT, /* -Tlint */
OUTT_PS, /* -Tps */
OUTT_PDF /* -Tpdf */
@@ -56,91 +74,342 @@ enum outt {
struct curparse {
struct mparse *mp;
+ struct mchars *mchars; /* character table */
enum mandoclevel wlevel; /* ignore messages below this */
int wstop; /* stop after a file with a warning */
- enum outt outtype; /* which output to use */
+ enum outt outtype; /* which output to use */
out_mdoc outmdoc; /* mdoc output ptr */
- out_man outman; /* man output ptr */
+ out_man outman; /* man output ptr */
out_free outfree; /* free output ptr */
void *outdata; /* data for output */
char outopts[BUFSIZ]; /* buf of output opts */
};
-static int moptions(enum mparset *, char *);
+static int fs_lookup(const struct manpaths *,
+ size_t ipath, const char *,
+ const char *, const char *,
+ struct manpage **, size_t *);
+static void fs_search(const struct mansearch *,
+ const struct manpaths *, int, char**,
+ struct manpage **, size_t *);
+static int koptions(int *, char *);
+#if HAVE_SQLITE3
+int mandocdb(int, char**);
+#endif
+static int moptions(int *, char *);
static void mmsg(enum mandocerr, enum mandoclevel,
const char *, int, int, const char *);
-static void parse(struct curparse *, int,
+static void parse(struct curparse *, int,
const char *, enum mandoclevel *);
+static enum mandoclevel passthrough(const char *, int, int);
+static pid_t spawn_pager(void);
static int toptions(struct curparse *, char *);
-static void usage(void) __attribute__((noreturn));
-static void version(void) __attribute__((noreturn));
+static void usage(enum argmode) __attribute__((noreturn));
static int woptions(struct curparse *, char *);
+static const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9};
+static char help_arg[] = "help";
+static char *help_argv[] = {help_arg, NULL};
static const char *progname;
+
int
main(int argc, char *argv[])
{
- int c;
struct curparse curp;
- enum mparset type;
- enum mandoclevel rc;
+ struct mansearch search;
+ struct manpaths paths;
+ char *auxpaths;
char *defos;
+ unsigned char *uc;
+ struct manpage *res, *resp;
+ char *conf_file, *defpaths;
+ size_t isec, i, sz;
+ int prio, best_prio, synopsis_only;
+ char sec;
+ enum mandoclevel rc, rctmp;
+ enum outmode outmode;
+ int fd;
+ int show_usage;
+ int options;
+ int c;
+ pid_t pager_pid; /* 0: don't use; 1: not yet spawned. */
- progname = strrchr(argv[0], '/');
- if (progname == NULL)
+ if (argc < 1)
+ progname = "mandoc";
+ else if ((progname = strrchr(argv[0], '/')) == NULL)
progname = argv[0];
else
++progname;
- memset(&curp, 0, sizeof(struct curparse));
+#if HAVE_SQLITE3
+ if (strcmp(progname, BINM_MAKEWHATIS) == 0)
+ return(mandocdb(argc, argv));
+#endif
+
+ /* Search options. */
- type = MPARSE_AUTO;
- curp.outtype = OUTT_ASCII;
- curp.wlevel = MANDOCLEVEL_FATAL;
+ memset(&paths, 0, sizeof(struct manpaths));
+ conf_file = defpaths = NULL;
+ auxpaths = NULL;
+
+ memset(&search, 0, sizeof(struct mansearch));
+ search.outkey = "Nd";
+
+ if (strcmp(progname, BINM_MAN) == 0)
+ search.argmode = ARG_NAME;
+ else if (strcmp(progname, BINM_APROPOS) == 0)
+ search.argmode = ARG_EXPR;
+ else if (strcmp(progname, BINM_WHATIS) == 0)
+ search.argmode = ARG_WORD;
+ else if (strncmp(progname, "help", 4) == 0)
+ search.argmode = ARG_NAME;
+ else
+ search.argmode = ARG_FILE;
+
+ /* Parser and formatter options. */
+
+ memset(&curp, 0, sizeof(struct curparse));
+ curp.outtype = OUTT_LOCALE;
+ curp.wlevel = MANDOCLEVEL_BADARG;
+ options = MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1;
defos = NULL;
- /* LINTED */
- while (-1 != (c = getopt(argc, argv, "I:m:O:T:VW:")))
+ pager_pid = 1;
+ show_usage = 0;
+ synopsis_only = 0;
+ outmode = OUTMODE_DEF;
+
+ while (-1 != (c = getopt(argc, argv,
+ "aC:cfhI:iK:klM:m:O:S:s:T:VW:w"))) {
switch (c) {
- case ('I'):
+ case 'a':
+ outmode = OUTMODE_ALL;
+ break;
+ case 'C':
+ conf_file = optarg;
+ break;
+ case 'c':
+ pager_pid = 0;
+ break;
+ case 'f':
+ search.argmode = ARG_WORD;
+ break;
+ case 'h':
+ (void)strlcat(curp.outopts, "synopsis,", BUFSIZ);
+ synopsis_only = 1;
+ pager_pid = 0;
+ outmode = OUTMODE_ALL;
+ break;
+ case 'I':
if (strncmp(optarg, "os=", 3)) {
- fprintf(stderr, "-I%s: Bad argument\n",
- optarg);
+ fprintf(stderr,
+ "%s: -I %s: Bad argument\n",
+ progname, optarg);
return((int)MANDOCLEVEL_BADARG);
}
if (defos) {
- fprintf(stderr, "-I%s: Duplicate argument\n",
- optarg);
+ fprintf(stderr,
+ "%s: -I %s: Duplicate argument\n",
+ progname, optarg);
return((int)MANDOCLEVEL_BADARG);
}
defos = mandoc_strdup(optarg + 3);
break;
- case ('m'):
- if ( ! moptions(&type, optarg))
+ case 'i':
+ outmode = OUTMODE_INT;
+ break;
+ case 'K':
+ if ( ! koptions(&options, optarg))
return((int)MANDOCLEVEL_BADARG);
break;
- case ('O'):
+ case 'k':
+ search.argmode = ARG_EXPR;
+ break;
+ case 'l':
+ search.argmode = ARG_FILE;
+ outmode = OUTMODE_ALL;
+ break;
+ case 'M':
+ defpaths = optarg;
+ break;
+ case 'm':
+ auxpaths = optarg;
+ break;
+ case 'O':
+ search.outkey = optarg;
(void)strlcat(curp.outopts, optarg, BUFSIZ);
(void)strlcat(curp.outopts, ",", BUFSIZ);
break;
- case ('T'):
+ case 'S':
+ search.arch = optarg;
+ break;
+ case 's':
+ search.sec = optarg;
+ break;
+ case 'T':
if ( ! toptions(&curp, optarg))
return((int)MANDOCLEVEL_BADARG);
break;
- case ('W'):
+ case 'W':
if ( ! woptions(&curp, optarg))
return((int)MANDOCLEVEL_BADARG);
break;
- case ('V'):
- version();
- /* NOTREACHED */
+ case 'w':
+ outmode = OUTMODE_FLN;
+ break;
default:
- usage();
- /* NOTREACHED */
+ show_usage = 1;
+ break;
}
+ }
+
+ if (show_usage)
+ usage(search.argmode);
- curp.mp = mparse_alloc(type, curp.wlevel, mmsg, &curp, defos);
+ /* Postprocess options. */
+
+ if (outmode == OUTMODE_DEF) {
+ switch (search.argmode) {
+ case ARG_FILE:
+ outmode = OUTMODE_ALL;
+ pager_pid = 0;
+ break;
+ case ARG_NAME:
+ outmode = OUTMODE_ONE;
+ break;
+ default:
+ outmode = OUTMODE_LST;
+ break;
+ }
+ }
+
+ /* Parse arguments. */
+
+ if (argc > 0) {
+ argc -= optind;
+ argv += optind;
+ }
+ resp = NULL;
+
+ /*
+ * Quirks for help(1)
+ * and for a man(1) section argument without -s.
+ */
+
+ if (search.argmode == ARG_NAME) {
+ if (*progname == 'h') {
+ if (argc == 0) {
+ argv = help_argv;
+ argc = 1;
+ }
+ } else if (argc > 1 &&
+ ((uc = (unsigned char *)argv[0]) != NULL) &&
+ ((isdigit(uc[0]) && (uc[1] == '\0' ||
+ (isalpha(uc[1]) && uc[2] == '\0'))) ||
+ (uc[0] == 'n' && uc[1] == '\0'))) {
+ search.sec = (char *)uc;
+ argv++;
+ argc--;
+ }
+ if (search.arch == NULL)
+ search.arch = getenv("MACHINE");
+#ifdef MACHINE
+ if (search.arch == NULL)
+ search.arch = MACHINE;
+#endif
+ }
+
+ rc = MANDOCLEVEL_OK;
+
+ /* man(1), whatis(1), apropos(1) */
+
+ if (search.argmode != ARG_FILE) {
+ if (argc == 0)
+ usage(search.argmode);
+
+ if (search.argmode == ARG_NAME &&
+ outmode == OUTMODE_ONE)
+ search.firstmatch = 1;
+
+ /* Access the mandoc database. */
+
+ manpath_parse(&paths, conf_file, defpaths, auxpaths);
+#if HAVE_SQLITE3
+ mansearch_setup(1);
+ if( ! mansearch(&search, &paths, argc, argv, &res, &sz))
+ usage(search.argmode);
+#else
+ if (search.argmode != ARG_NAME) {
+ fputs("mandoc: database support not compiled in\n",
+ stderr);
+ return((int)MANDOCLEVEL_BADARG);
+ }
+ sz = 0;
+#endif
+
+ if (sz == 0 && search.argmode == ARG_NAME)
+ fs_search(&search, &paths, argc, argv, &res, &sz);
+
+ if (sz == 0) {
+ rc = MANDOCLEVEL_BADARG;
+ goto out;
+ }
+
+ /*
+ * For standard man(1) and -a output mode,
+ * prepare for copying filename pointers
+ * into the program parameter array.
+ */
+
+ if (outmode == OUTMODE_ONE) {
+ argc = 1;
+ best_prio = 10;
+ } else if (outmode == OUTMODE_ALL)
+ argc = (int)sz;
+
+ /* Iterate all matching manuals. */
+
+ resp = res;
+ for (i = 0; i < sz; i++) {
+ if (outmode == OUTMODE_FLN)
+ puts(res[i].file);
+ else if (outmode == OUTMODE_LST)
+ printf("%s - %s\n", res[i].names,
+ res[i].output == NULL ? "" :
+ res[i].output);
+ else if (outmode == OUTMODE_ONE) {
+ /* Search for the best section. */
+ isec = strcspn(res[i].file, "123456789");
+ sec = res[i].file[isec];
+ if ('\0' == sec)
+ continue;
+ prio = sec_prios[sec - '1'];
+ if (prio >= best_prio)
+ continue;
+ best_prio = prio;
+ resp = res + i;
+ }
+ }
+
+ /*
+ * For man(1), -a and -i output mode, fall through
+ * to the main mandoc(1) code iterating files
+ * and running the parsers on each of them.
+ */
+
+ if (outmode == OUTMODE_FLN || outmode == OUTMODE_LST)
+ goto out;
+ }
+
+ /* mandoc(1) */
+
+ if (search.argmode == ARG_FILE && ! moptions(&options, auxpaths))
+ return((int)MANDOCLEVEL_BADARG);
+
+ curp.mchars = mchars_alloc();
+ curp.mp = mparse_alloc(options, curp.wlevel, mmsg,
+ curp.mchars, defos);
/*
* Conditionally start up the lookaside buffer before parsing.
@@ -148,58 +417,220 @@ main(int argc, char *argv[])
if (OUTT_MAN == curp.outtype)
mparse_keep(curp.mp);
- argc -= optind;
- argv += optind;
+ if (argc < 1) {
+ if (pager_pid == 1 && isatty(STDOUT_FILENO))
+ pager_pid = spawn_pager();
+ parse(&curp, STDIN_FILENO, "<stdin>", &rc);
+ }
- rc = MANDOCLEVEL_OK;
+ while (argc > 0) {
+ rctmp = mparse_open(curp.mp, &fd,
+ resp != NULL ? resp->file : *argv);
+ if (rc < rctmp)
+ rc = rctmp;
+
+ if (fd != -1) {
+ if (pager_pid == 1 && isatty(STDOUT_FILENO))
+ pager_pid = spawn_pager();
+
+ if (resp == NULL)
+ parse(&curp, fd, *argv, &rc);
+ else if (resp->form & FORM_SRC) {
+ /* For .so only; ignore failure. */
+ chdir(paths.paths[resp->ipath]);
+ parse(&curp, fd, resp->file, &rc);
+ } else {
+ rctmp = passthrough(resp->file, fd,
+ synopsis_only);
+ if (rc < rctmp)
+ rc = rctmp;
+ }
- if (NULL == *argv)
- parse(&curp, STDIN_FILENO, "<stdin>", &rc);
+ rctmp = mparse_wait(curp.mp);
+ if (rc < rctmp)
+ rc = rctmp;
+
+ if (argc > 1 && curp.outtype <= OUTT_UTF8)
+ ascii_sepline(curp.outdata);
+ }
- while (*argv) {
- parse(&curp, -1, *argv, &rc);
if (MANDOCLEVEL_OK != rc && curp.wstop)
break;
- ++argv;
+
+ if (resp != NULL)
+ resp++;
+ else
+ argv++;
+ if (--argc)
+ mparse_reset(curp.mp);
}
if (curp.outfree)
(*curp.outfree)(curp.outdata);
- if (curp.mp)
- mparse_free(curp.mp);
+ mparse_free(curp.mp);
+ mchars_free(curp.mchars);
+
+out:
+ if (search.argmode != ARG_FILE) {
+ manpath_free(&paths);
+#if HAVE_SQLITE3
+ mansearch_free(res, sz);
+ mansearch_setup(0);
+#endif
+ }
+
free(defos);
+ /*
+ * If a pager is attached, flush the pipe leading to it
+ * and signal end of file such that the user can browse
+ * to the end. Then wait for the user to close the pager.
+ */
+
+ if (pager_pid != 0 && pager_pid != 1) {
+ fclose(stdout);
+ waitpid(pager_pid, NULL, 0);
+ }
+
return((int)rc);
}
static void
-version(void)
+usage(enum argmode argmode)
{
- printf("%s %s\n", progname, VERSION);
- exit((int)MANDOCLEVEL_OK);
+ switch (argmode) {
+ case ARG_FILE:
+ fputs("usage: mandoc [-acfhkl] [-Ios=name] "
+ "[-Kencoding] [-mformat] [-Ooption]\n"
+ "\t [-Toutput] [-Wlevel] [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);
+ break;
+ case ARG_WORD:
+ fputs("usage: whatis [-acfhklw] [-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] "
+ "[-M path] [-m path] [-O outkey] [-S arch]\n"
+ "\t [-s section] expression ...\n", stderr);
+ break;
+ }
+ exit((int)MANDOCLEVEL_BADARG);
}
-static void
-usage(void)
+static int
+fs_lookup(const struct manpaths *paths, size_t ipath,
+ const char *sec, const char *arch, const char *name,
+ struct manpage **res, size_t *ressz)
{
+ glob_t globinfo;
+ struct manpage *page;
+ char *file;
+ int form, globres;
+
+ form = FORM_SRC;
+ mandoc_asprintf(&file, "%s/man%s/%s.%s",
+ paths->paths[ipath], sec, name, sec);
+ if (access(file, R_OK) != -1)
+ goto found;
+ free(file);
+
+ mandoc_asprintf(&file, "%s/cat%s/%s.0",
+ paths->paths[ipath], sec, name);
+ if (access(file, R_OK) != -1) {
+ form = FORM_CAT;
+ goto found;
+ }
+ free(file);
+
+ if (arch != NULL) {
+ mandoc_asprintf(&file, "%s/man%s/%s/%s.%s",
+ paths->paths[ipath], sec, arch, name, sec);
+ if (access(file, R_OK) != -1)
+ goto found;
+ free(file);
+ }
+
+ mandoc_asprintf(&file, "%s/man%s/%s.*",
+ paths->paths[ipath], sec, name);
+ globres = glob(file, 0, NULL, &globinfo);
+ if (globres != 0 && globres != GLOB_NOMATCH)
+ fprintf(stderr, "%s: %s: glob: %s\n",
+ progname, file, strerror(errno));
+ free(file);
+ if (globres == 0)
+ file = mandoc_strdup(*globinfo.gl_pathv);
+ globfree(&globinfo);
+ if (globres != 0)
+ return(0);
- fprintf(stderr, "usage: %s "
- "[-V] "
- "[-Ios=name] "
- "[-mformat] "
- "[-Ooption] "
- "[-Toutput] "
- "[-Wlevel]\n"
- "\t [file ...]\n",
- progname);
+found:
+#if HAVE_SQLITE3
+ fprintf(stderr, "%s: outdated mandoc.db lacks %s(%s) entry,\n"
+ " consider running # makewhatis %s\n",
+ progname, name, sec, paths->paths[ipath]);
+#endif
- exit((int)MANDOCLEVEL_BADARG);
+ *res = mandoc_reallocarray(*res, ++*ressz, sizeof(struct manpage));
+ page = *res + (*ressz - 1);
+ page->file = file;
+ page->names = NULL;
+ page->output = NULL;
+ page->ipath = ipath;
+ page->bits = NAME_FILE & NAME_MASK;
+ page->sec = (*sec >= '1' && *sec <= '9') ? *sec - '1' + 1 : 10;
+ page->form = form;
+ return(1);
+}
+
+static void
+fs_search(const struct mansearch *cfg, const struct manpaths *paths,
+ int argc, char **argv, struct manpage **res, size_t *ressz)
+{
+ const char *const sections[] =
+ {"1", "8", "6", "2", "3", "3p", "5", "7", "4", "9"};
+ const size_t nsec = sizeof(sections)/sizeof(sections[0]);
+
+ size_t ipath, isec, lastsz;
+
+ assert(cfg->argmode == ARG_NAME);
+
+ *res = NULL;
+ *ressz = lastsz = 0;
+ while (argc) {
+ for (ipath = 0; ipath < paths->sz; ipath++) {
+ if (cfg->sec != NULL) {
+ if (fs_lookup(paths, ipath, cfg->sec,
+ cfg->arch, *argv, res, ressz) &&
+ cfg->firstmatch)
+ return;
+ } else for (isec = 0; isec < nsec; isec++)
+ if (fs_lookup(paths, ipath, sections[isec],
+ cfg->arch, *argv, res, ressz) &&
+ cfg->firstmatch)
+ return;
+ }
+ if (*ressz == lastsz)
+ fprintf(stderr,
+ "%s: No entry for %s in the manual.\n",
+ progname, *argv);
+ lastsz = *ressz;
+ argv++;
+ argc--;
+ }
}
static void
-parse(struct curparse *curp, int fd,
- const char *file, enum mandoclevel *level)
+parse(struct curparse *curp, int fd, const char *file,
+ enum mandoclevel *level)
{
enum mandoclevel rc;
struct mdoc *mdoc;
@@ -212,11 +643,6 @@ parse(struct curparse *curp, int fd,
rc = mparse_readfd(curp->mp, fd, file);
- /* Stop immediately if the parse has failed. */
-
- if (MANDOCLEVEL_FATAL <= rc)
- goto cleanup;
-
/*
* With -Wstop and warnings or errors of at least the requested
* level, do not produce output.
@@ -229,32 +655,34 @@ parse(struct curparse *curp, int fd,
if ( ! (curp->outman && curp->outmdoc)) {
switch (curp->outtype) {
- case (OUTT_XHTML):
- curp->outdata = xhtml_alloc(curp->outopts);
- curp->outfree = html_free;
- break;
- case (OUTT_HTML):
- curp->outdata = html_alloc(curp->outopts);
+ case OUTT_HTML:
+ curp->outdata = html_alloc(curp->mchars,
+ curp->outopts);
curp->outfree = html_free;
break;
- case (OUTT_UTF8):
- curp->outdata = utf8_alloc(curp->outopts);
+ case OUTT_UTF8:
+ curp->outdata = utf8_alloc(curp->mchars,
+ curp->outopts);
curp->outfree = ascii_free;
break;
- case (OUTT_LOCALE):
- curp->outdata = locale_alloc(curp->outopts);
+ case OUTT_LOCALE:
+ curp->outdata = locale_alloc(curp->mchars,
+ curp->outopts);
curp->outfree = ascii_free;
break;
- case (OUTT_ASCII):
- curp->outdata = ascii_alloc(curp->outopts);
+ case OUTT_ASCII:
+ curp->outdata = ascii_alloc(curp->mchars,
+ curp->outopts);
curp->outfree = ascii_free;
break;
- case (OUTT_PDF):
- curp->outdata = pdf_alloc(curp->outopts);
+ case OUTT_PDF:
+ curp->outdata = pdf_alloc(curp->mchars,
+ curp->outopts);
curp->outfree = pspdf_free;
break;
- case (OUTT_PS):
- curp->outdata = ps_alloc(curp->outopts);
+ case OUTT_PS:
+ curp->outdata = ps_alloc(curp->mchars,
+ curp->outopts);
curp->outfree = pspdf_free;
break;
default:
@@ -262,29 +690,27 @@ parse(struct curparse *curp, int fd,
}
switch (curp->outtype) {
- case (OUTT_HTML):
- /* FALLTHROUGH */
- case (OUTT_XHTML):
+ case OUTT_HTML:
curp->outman = html_man;
curp->outmdoc = html_mdoc;
break;
- case (OUTT_TREE):
+ case OUTT_TREE:
curp->outman = tree_man;
curp->outmdoc = tree_mdoc;
break;
- case (OUTT_MAN):
+ case OUTT_MAN:
curp->outmdoc = man_mdoc;
curp->outman = man_man;
break;
- case (OUTT_PDF):
+ case OUTT_PDF:
/* FALLTHROUGH */
- case (OUTT_ASCII):
+ case OUTT_ASCII:
/* FALLTHROUGH */
- case (OUTT_UTF8):
+ case OUTT_UTF8:
/* FALLTHROUGH */
- case (OUTT_LOCALE):
+ case OUTT_LOCALE:
/* FALLTHROUGH */
- case (OUTT_PS):
+ case OUTT_PS:
curp->outman = terminal_man;
curp->outmdoc = terminal_mdoc;
break;
@@ -293,7 +719,7 @@ parse(struct curparse *curp, int fd,
}
}
- mparse_result(curp->mp, &mdoc, &man);
+ mparse_result(curp->mp, &mdoc, &man, NULL);
/* Execute the out device, if it exists. */
@@ -302,26 +728,112 @@ parse(struct curparse *curp, int fd,
if (mdoc && curp->outmdoc)
(*curp->outmdoc)(curp->outdata, mdoc);
- cleanup:
-
- mparse_reset(curp->mp);
-
+cleanup:
if (*level < rc)
*level = rc;
}
+static enum mandoclevel
+passthrough(const char *file, int fd, int synopsis_only)
+{
+ const char synb[] = "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS";
+ const char synr[] = "SYNOPSIS";
+
+ FILE *stream;
+ const char *syscall;
+ char *line;
+ size_t len, off;
+ ssize_t nw;
+ int print;
+
+ fflush(stdout);
+
+ if ((stream = fdopen(fd, "r")) == NULL) {
+ close(fd);
+ syscall = "fdopen";
+ goto fail;
+ }
+
+ print = 0;
+ while ((line = fgetln(stream, &len)) != NULL) {
+ if (synopsis_only) {
+ if (print) {
+ if ( ! isspace((unsigned char)*line))
+ goto done;
+ while (len &&
+ isspace((unsigned char)*line)) {
+ line++;
+ len--;
+ }
+ } else {
+ if ((len == sizeof(synb) &&
+ ! strncmp(line, synb, len - 1)) ||
+ (len == sizeof(synr) &&
+ ! strncmp(line, synr, len - 1)))
+ print = 1;
+ continue;
+ }
+ }
+ for (off = 0; off < len; off += nw)
+ if ((nw = write(STDOUT_FILENO, line + off,
+ len - off)) == -1 || nw == 0) {
+ fclose(stream);
+ syscall = "write";
+ goto fail;
+ }
+ }
+
+ if (ferror(stream)) {
+ fclose(stream);
+ syscall = "fgetln";
+ goto fail;
+ }
+
+done:
+ fclose(stream);
+ return(MANDOCLEVEL_OK);
+
+fail:
+ fprintf(stderr, "%s: %s: SYSERR: %s: %s",
+ progname, file, syscall, strerror(errno));
+ return(MANDOCLEVEL_SYSERR);
+}
+
+static int
+koptions(int *options, char *arg)
+{
+
+ if ( ! strcmp(arg, "utf-8")) {
+ *options |= MPARSE_UTF8;
+ *options &= ~MPARSE_LATIN1;
+ } else if ( ! strcmp(arg, "iso-8859-1")) {
+ *options |= MPARSE_LATIN1;
+ *options &= ~MPARSE_UTF8;
+ } else if ( ! strcmp(arg, "us-ascii")) {
+ *options &= ~(MPARSE_UTF8 | MPARSE_LATIN1);
+ } else {
+ fprintf(stderr, "%s: -K %s: Bad argument\n",
+ progname, arg);
+ return(0);
+ }
+ return(1);
+}
+
static int
-moptions(enum mparset *tflags, char *arg)
+moptions(int *options, char *arg)
{
- if (0 == strcmp(arg, "doc"))
- *tflags = MPARSE_MDOC;
+ if (arg == NULL)
+ /* nothing to do */;
+ else if (0 == strcmp(arg, "doc"))
+ *options |= MPARSE_MDOC;
else if (0 == strcmp(arg, "andoc"))
- *tflags = MPARSE_AUTO;
+ /* nothing to do */;
else if (0 == strcmp(arg, "an"))
- *tflags = MPARSE_MAN;
+ *options |= MPARSE_MAN;
else {
- fprintf(stderr, "%s: Bad argument\n", arg);
+ fprintf(stderr, "%s: -m %s: Bad argument\n",
+ progname, arg);
return(0);
}
@@ -348,13 +860,14 @@ toptions(struct curparse *curp, char *arg)
else if (0 == strcmp(arg, "locale"))
curp->outtype = OUTT_LOCALE;
else if (0 == strcmp(arg, "xhtml"))
- curp->outtype = OUTT_XHTML;
+ curp->outtype = OUTT_HTML;
else if (0 == strcmp(arg, "ps"))
curp->outtype = OUTT_PS;
else if (0 == strcmp(arg, "pdf"))
curp->outtype = OUTT_PDF;
else {
- fprintf(stderr, "%s: Bad argument\n", arg);
+ fprintf(stderr, "%s: -T %s: Bad argument\n",
+ progname, arg);
return(0);
}
@@ -365,34 +878,39 @@ static int
woptions(struct curparse *curp, char *arg)
{
char *v, *o;
- const char *toks[6];
+ const char *toks[7];
toks[0] = "stop";
toks[1] = "all";
toks[2] = "warning";
toks[3] = "error";
- toks[4] = "fatal";
- toks[5] = NULL;
+ toks[4] = "unsupp";
+ toks[5] = "fatal";
+ toks[6] = NULL;
while (*arg) {
o = arg;
switch (getsubopt(&arg, UNCONST(toks), &v)) {
- case (0):
+ case 0:
curp->wstop = 1;
break;
- case (1):
+ case 1:
/* FALLTHROUGH */
- case (2):
+ case 2:
curp->wlevel = MANDOCLEVEL_WARNING;
break;
- case (3):
+ case 3:
curp->wlevel = MANDOCLEVEL_ERROR;
break;
- case (4):
- curp->wlevel = MANDOCLEVEL_FATAL;
+ case 4:
+ curp->wlevel = MANDOCLEVEL_UNSUPP;
+ break;
+ case 5:
+ curp->wlevel = MANDOCLEVEL_BADARG;
break;
default:
- fprintf(stderr, "-W%s: Bad argument\n", o);
+ fprintf(stderr, "%s: -W %s: Bad argument\n",
+ progname, o);
return(0);
}
}
@@ -401,17 +919,102 @@ woptions(struct curparse *curp, char *arg)
}
static void
-mmsg(enum mandocerr t, enum mandoclevel lvl,
+mmsg(enum mandocerr t, enum mandoclevel lvl,
const char *file, int line, int col, const char *msg)
{
+ const char *mparse_msg;
+
+ fprintf(stderr, "%s: %s:", progname, file);
+
+ if (line)
+ fprintf(stderr, "%d:%d:", line, col + 1);
- fprintf(stderr, "%s:%d:%d: %s: %s",
- file, line, col + 1,
- mparse_strlevel(lvl),
- mparse_strerror(t));
+ fprintf(stderr, " %s", mparse_strlevel(lvl));
+
+ if (NULL != (mparse_msg = mparse_strerror(t)))
+ fprintf(stderr, ": %s", mparse_msg);
if (msg)
fprintf(stderr, ": %s", msg);
fputc('\n', stderr);
}
+
+static pid_t
+spawn_pager(void)
+{
+#define MAX_PAGER_ARGS 16
+ char *argv[MAX_PAGER_ARGS];
+ const char *pager;
+ char *cp;
+ int fildes[2];
+ int argc;
+ pid_t pager_pid;
+
+ if (pipe(fildes) == -1) {
+ fprintf(stderr, "%s: pipe: %s\n",
+ progname, strerror(errno));
+ return(0);
+ }
+
+ switch (pager_pid = fork()) {
+ case -1:
+ fprintf(stderr, "%s: fork: %s\n",
+ progname, strerror(errno));
+ exit((int)MANDOCLEVEL_SYSERR);
+ case 0:
+ break;
+ default:
+ close(fildes[0]);
+ if (dup2(fildes[1], STDOUT_FILENO) == -1) {
+ fprintf(stderr, "%s: dup output: %s\n",
+ progname, strerror(errno));
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+ close(fildes[1]);
+ return(pager_pid);
+ }
+
+ /* The child process becomes the pager. */
+
+ close(fildes[1]);
+ if (dup2(fildes[0], STDIN_FILENO) == -1) {
+ fprintf(stderr, "%s: dup input: %s\n",
+ progname, strerror(errno));
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+ close(fildes[0]);
+
+ pager = getenv("MANPAGER");
+ if (pager == NULL || *pager == '\0')
+ pager = getenv("PAGER");
+ if (pager == NULL || *pager == '\0')
+ pager = "/usr/bin/more -s";
+ cp = mandoc_strdup(pager);
+
+ /*
+ * Parse the pager command into words.
+ * Intentionally do not do anything fancy here.
+ */
+
+ argc = 0;
+ while (argc + 1 < MAX_PAGER_ARGS) {
+ argv[argc++] = cp;
+ cp = strchr(cp, ' ');
+ if (cp == NULL)
+ break;
+ *cp++ = '\0';
+ while (*cp == ' ')
+ cp++;
+ if (*cp == '\0')
+ break;
+ }
+ argv[argc] = NULL;
+
+ /* Hand over to the pager. */
+
+ execvp(argv[0], argv);
+ fprintf(stderr, "%s: exec: %s\n",
+ progname, strerror(errno));
+ exit((int)MANDOCLEVEL_SYSERR);
+}
diff --git a/usr/src/cmd/mandoc/main.h b/usr/src/cmd/mandoc/main.h
index 79dcf489ae..9b04a7816a 100644
--- a/usr/src/cmd/mandoc/main.h
+++ b/usr/src/cmd/mandoc/main.h
@@ -1,6 +1,7 @@
-/* $Id: main.h,v 1.15 2011/10/06 22:29:12 kristaps Exp $ */
+/* $Id: main.h,v 1.20 2014/12/31 16:52:40 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014 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,26 +15,23 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef MAIN_H
-#define MAIN_H
+
+#define UNCONST(a) ((void *)(uintptr_t)(const void *)(a))
__BEGIN_DECLS
+struct mchars;
struct mdoc;
struct man;
-#define UNCONST(a) ((void *)(uintptr_t)(const void *)(a))
-
-
-/*
+/*
* Definitions for main.c-visible output device functions, e.g., -Thtml
* and -Tascii. Note that ascii_alloc() is named as such in
* anticipation of latin1_alloc() and so on, all of which map into the
* terminal output routines with different character settings.
*/
-void *html_alloc(char *);
-void *xhtml_alloc(char *);
+void *html_alloc(const struct mchars *, char *);
void html_mdoc(void *, const struct mdoc *);
void html_man(void *, const struct man *);
void html_free(void *);
@@ -44,18 +42,17 @@ void tree_man(void *, const struct man *);
void man_mdoc(void *, const struct mdoc *);
void man_man(void *, const struct man *);
-void *locale_alloc(char *);
-void *utf8_alloc(char *);
-void *ascii_alloc(char *);
+void *locale_alloc(const struct mchars *, char *);
+void *utf8_alloc(const struct mchars *, char *);
+void *ascii_alloc(const struct mchars *, char *);
void ascii_free(void *);
+void ascii_sepline(void *);
-void *pdf_alloc(char *);
-void *ps_alloc(char *);
+void *pdf_alloc(const struct mchars *, char *);
+void *ps_alloc(const struct mchars *, char *);
void pspdf_free(void *);
void terminal_mdoc(void *, const struct mdoc *);
void terminal_man(void *, const struct man *);
__END_DECLS
-
-#endif /*!MAIN_H*/
diff --git a/usr/src/cmd/mandoc/man.c b/usr/src/cmd/mandoc/man.c
index e6e1c28992..4e7a398d9b 100644
--- a/usr/src/cmd/mandoc/man.c
+++ b/usr/src/cmd/mandoc/man.c
@@ -1,6 +1,8 @@
-/* $Id: man.c,v 1.121 2013/11/10 22:54:40 schwarze Exp $ */
+/* $Id: man.c,v 1.149 2015/01/30 21:28:46 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) 2011 Joerg Sonnenberger <joerg@netbsd.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,13 +16,12 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#include <sys/types.h>
#include <assert.h>
+#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
@@ -28,56 +29,53 @@
#include "man.h"
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libman.h"
#include "libmandoc.h"
-const char *const __man_macronames[MAN_MAX] = {
+const char *const __man_macronames[MAN_MAX] = {
"br", "TH", "SH", "SS",
- "TP", "LP", "PP", "P",
+ "TP", "LP", "PP", "P",
"IP", "HP", "SM", "SB",
"BI", "IB", "BR", "RB",
"R", "B", "I", "IR",
- "RI", "na", "sp", "nf",
+ "RI", "sp", "nf",
"fi", "RE", "RS", "DT",
"UC", "PD", "AT", "in",
"ft", "OP", "EX", "EE",
- "UR", "UE"
+ "UR", "UE", "ll"
};
const char * const *man_macronames = __man_macronames;
-static struct man_node *man_node_alloc(struct man *, int, int,
+static void man_alloc1(struct man *);
+static void man_breakscope(struct man *, enum mant);
+static void man_descope(struct man *, int, int);
+static void man_free1(struct man *);
+static struct man_node *man_node_alloc(struct man *, int, int,
enum man_type, enum mant);
-static int man_node_append(struct man *,
- struct man_node *);
+static void man_node_append(struct man *, struct man_node *);
static void man_node_free(struct man_node *);
-static void man_node_unlink(struct man *,
+static void man_node_unlink(struct man *,
struct man_node *);
static int man_ptext(struct man *, int, char *, int);
static int man_pmacro(struct man *, int, char *, int);
-static void man_free1(struct man *);
-static void man_alloc1(struct man *);
-static int man_descope(struct man *, int, int);
const struct man_node *
man_node(const struct man *man)
{
- assert( ! (MAN_HALT & man->flags));
return(man->first);
}
-
const struct man_meta *
man_meta(const struct man *man)
{
- assert( ! (MAN_HALT & man->flags));
return(&man->meta);
}
-
void
man_reset(struct man *man)
{
@@ -86,7 +84,6 @@ man_reset(struct man *man)
man_alloc1(man);
}
-
void
man_free(struct man *man)
{
@@ -95,9 +92,9 @@ man_free(struct man *man)
free(man);
}
-
struct man *
-man_alloc(struct roff *roff, struct mparse *parse)
+man_alloc(struct roff *roff, struct mparse *parse,
+ const char *defos, int quick)
{
struct man *p;
@@ -105,58 +102,46 @@ man_alloc(struct roff *roff, struct mparse *parse)
man_hash_init();
p->parse = parse;
+ p->defos = defos;
+ p->quick = quick;
p->roff = roff;
man_alloc1(p);
return(p);
}
-
-int
+void
man_endparse(struct man *man)
{
- assert( ! (MAN_HALT & man->flags));
- if (man_macroend(man))
- return(1);
- man->flags |= MAN_HALT;
- return(0);
+ man_macroend(man);
}
-
int
man_parseln(struct man *man, int ln, char *buf, int offs)
{
- man->flags |= MAN_NEWLINE;
-
- assert( ! (MAN_HALT & man->flags));
+ if (man->last->type != MAN_EQN || ln > man->last->line)
+ man->flags |= MAN_NEWLINE;
return (roff_getcontrol(man->roff, buf, &offs) ?
- man_pmacro(man, ln, buf, offs) :
- man_ptext(man, ln, buf, offs));
+ man_pmacro(man, ln, buf, offs) :
+ man_ptext(man, ln, buf, offs));
}
-
static void
man_free1(struct man *man)
{
if (man->first)
man_node_delete(man, man->first);
- if (man->meta.title)
- free(man->meta.title);
- if (man->meta.source)
- free(man->meta.source);
- if (man->meta.date)
- free(man->meta.date);
- if (man->meta.vol)
- free(man->meta.vol);
- if (man->meta.msec)
- free(man->meta.msec);
+ free(man->meta.title);
+ free(man->meta.source);
+ free(man->meta.date);
+ free(man->meta.vol);
+ free(man->meta.msec);
}
-
static void
man_alloc1(struct man *man)
{
@@ -171,21 +156,21 @@ man_alloc1(struct man *man)
}
-static int
+static void
man_node_append(struct man *man, struct man_node *p)
{
assert(man->last);
assert(man->first);
- assert(MAN_ROOT != p->type);
+ assert(p->type != MAN_ROOT);
switch (man->next) {
- case (MAN_NEXT_SIBLING):
+ case MAN_NEXT_SIBLING:
man->last->next = p;
p->prev = man->last;
p->parent = man->last->parent;
break;
- case (MAN_NEXT_CHILD):
+ case MAN_NEXT_CHILD:
man->last->child = p;
p->parent = man->last;
break;
@@ -193,24 +178,21 @@ man_node_append(struct man *man, struct man_node *p)
abort();
/* NOTREACHED */
}
-
+
assert(p->parent);
p->parent->nchild++;
- if ( ! man_valid_pre(man, p))
- return(0);
-
switch (p->type) {
- case (MAN_HEAD):
- assert(MAN_BLOCK == p->parent->type);
- p->parent->head = p;
+ case MAN_BLOCK:
+ if (p->tok == MAN_SH || p->tok == MAN_SS)
+ man->flags &= ~MAN_LITERAL;
break;
- case (MAN_TAIL):
- assert(MAN_BLOCK == p->parent->type);
- p->parent->tail = p;
+ case MAN_HEAD:
+ assert(p->parent->type == MAN_BLOCK);
+ p->parent->head = p;
break;
- case (MAN_BODY):
- assert(MAN_BLOCK == p->parent->type);
+ case MAN_BODY:
+ assert(p->parent->type == MAN_BLOCK);
p->parent->body = p;
break;
default:
@@ -220,22 +202,18 @@ man_node_append(struct man *man, struct man_node *p)
man->last = p;
switch (p->type) {
- case (MAN_TBL):
+ case MAN_TBL:
/* FALLTHROUGH */
- case (MAN_TEXT):
- if ( ! man_valid_post(man))
- return(0);
+ case MAN_TEXT:
+ man_valid_post(man);
break;
default:
break;
}
-
- return(1);
}
-
static struct man_node *
-man_node_alloc(struct man *man, int line, int pos,
+man_node_alloc(struct man *man, int line, int pos,
enum man_type type, enum mant tok)
{
struct man_node *p;
@@ -246,92 +224,77 @@ man_node_alloc(struct man *man, int line, int pos,
p->type = type;
p->tok = tok;
- if (MAN_NEWLINE & man->flags)
+ if (man->flags & MAN_NEWLINE)
p->flags |= MAN_LINE;
man->flags &= ~MAN_NEWLINE;
return(p);
}
-
-int
+void
man_elem_alloc(struct man *man, int line, int pos, enum mant tok)
{
struct man_node *p;
p = man_node_alloc(man, line, pos, MAN_ELEM, tok);
- if ( ! man_node_append(man, p))
- return(0);
+ man_node_append(man, p);
man->next = MAN_NEXT_CHILD;
- return(1);
}
-
-int
-man_tail_alloc(struct man *man, int line, int pos, enum mant tok)
-{
- struct man_node *p;
-
- p = man_node_alloc(man, line, pos, MAN_TAIL, tok);
- if ( ! man_node_append(man, p))
- return(0);
- man->next = MAN_NEXT_CHILD;
- return(1);
-}
-
-
-int
+void
man_head_alloc(struct man *man, int line, int pos, enum mant tok)
{
struct man_node *p;
p = man_node_alloc(man, line, pos, MAN_HEAD, tok);
- if ( ! man_node_append(man, p))
- return(0);
+ man_node_append(man, p);
man->next = MAN_NEXT_CHILD;
- return(1);
}
-
-int
+void
man_body_alloc(struct man *man, int line, int pos, enum mant tok)
{
struct man_node *p;
p = man_node_alloc(man, line, pos, MAN_BODY, tok);
- if ( ! man_node_append(man, p))
- return(0);
+ man_node_append(man, p);
man->next = MAN_NEXT_CHILD;
- return(1);
}
-
-int
+void
man_block_alloc(struct man *man, int line, int pos, enum mant tok)
{
struct man_node *p;
p = man_node_alloc(man, line, pos, MAN_BLOCK, tok);
- if ( ! man_node_append(man, p))
- return(0);
+ man_node_append(man, p);
man->next = MAN_NEXT_CHILD;
- return(1);
}
-int
+void
man_word_alloc(struct man *man, int line, int pos, const char *word)
{
struct man_node *n;
n = man_node_alloc(man, line, pos, MAN_TEXT, MAN_MAX);
n->string = roff_strdup(man->roff, word);
-
- if ( ! man_node_append(man, n))
- return(0);
-
+ man_node_append(man, n);
man->next = MAN_NEXT_SIBLING;
- return(1);
}
+void
+man_word_append(struct man *man, const char *word)
+{
+ struct man_node *n;
+ char *addstr, *newstr;
+
+ n = man->last;
+ addstr = roff_strdup(man->roff, word);
+ mandoc_asprintf(&newstr, "%s %s", n->string, addstr);
+ free(addstr);
+ free(n->string);
+ n->string = newstr;
+ man->next = MAN_NEXT_SIBLING;
+}
/*
* Free all of the resources held by a node. This does NOT unlink a
@@ -341,12 +304,10 @@ static void
man_node_free(struct man_node *p)
{
- if (p->string)
- free(p->string);
+ free(p->string);
free(p);
}
-
void
man_node_delete(struct man *man, struct man_node *p)
{
@@ -358,41 +319,34 @@ man_node_delete(struct man *man, struct man_node *p)
man_node_free(p);
}
-int
+void
man_addeqn(struct man *man, const struct eqn *ep)
{
struct man_node *n;
- assert( ! (MAN_HALT & man->flags));
-
n = man_node_alloc(man, ep->ln, ep->pos, MAN_EQN, MAN_MAX);
n->eqn = ep;
-
- if ( ! man_node_append(man, n))
- return(0);
-
+ if (ep->ln > man->last->line)
+ n->flags |= MAN_LINE;
+ man_node_append(man, n);
man->next = MAN_NEXT_SIBLING;
- return(man_descope(man, ep->ln, ep->pos));
+ man_descope(man, ep->ln, ep->pos);
}
-int
+void
man_addspan(struct man *man, const struct tbl_span *sp)
{
struct man_node *n;
- assert( ! (MAN_HALT & man->flags));
-
+ man_breakscope(man, MAN_MAX);
n = man_node_alloc(man, sp->line, 0, MAN_TBL, MAN_MAX);
n->span = sp;
-
- if ( ! man_node_append(man, n))
- return(0);
-
+ man_node_append(man, n);
man->next = MAN_NEXT_SIBLING;
- return(man_descope(man, sp->line, 0));
+ man_descope(man, sp->line, 0);
}
-static int
+static void
man_descope(struct man *man, int line, int offs)
{
/*
@@ -401,19 +355,15 @@ man_descope(struct man *man, int line, int offs)
* out the block scope (also if applicable).
*/
- if (MAN_ELINE & man->flags) {
+ if (man->flags & MAN_ELINE) {
man->flags &= ~MAN_ELINE;
- if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX))
- return(0);
+ man_unscope(man, man->last->parent);
}
-
- if ( ! (MAN_BLINE & man->flags))
- return(1);
+ if ( ! (man->flags & MAN_BLINE))
+ return;
man->flags &= ~MAN_BLINE;
-
- if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX))
- return(0);
- return(man_body_alloc(man, line, offs, man->last->tok));
+ man_unscope(man, man->last->parent);
+ man_body_alloc(man, line, offs, man->last->tok);
}
static int
@@ -423,13 +373,13 @@ man_ptext(struct man *man, int line, char *buf, int offs)
/* Literal free-form text whitespace is preserved. */
- if (MAN_LITERAL & man->flags) {
- if ( ! man_word_alloc(man, line, offs, buf + offs))
- return(0);
- return(man_descope(man, line, offs));
+ if (man->flags & MAN_LITERAL) {
+ man_word_alloc(man, line, offs, buf + offs);
+ man_descope(man, line, offs);
+ return(1);
}
- for (i = offs; ' ' == buf[i]; i++)
+ for (i = offs; buf[i] == ' '; i++)
/* Skip leading whitespace. */ ;
/*
@@ -437,20 +387,19 @@ man_ptext(struct man *man, int line, char *buf, int offs)
* but add a single vertical space elsewhere.
*/
- if ('\0' == buf[i]) {
+ if (buf[i] == '\0') {
/* Allocate a blank entry. */
- if (MAN_SH != man->last->tok &&
- MAN_SS != man->last->tok) {
- if ( ! man_elem_alloc(man, line, offs, MAN_sp))
- return(0);
+ if (man->last->tok != MAN_SH &&
+ man->last->tok != MAN_SS) {
+ man_elem_alloc(man, line, offs, MAN_sp);
man->next = MAN_NEXT_SIBLING;
}
return(1);
}
- /*
+ /*
* Warn if the last un-escaped character is whitespace. Then
- * strip away the remaining spaces (tabs stay!).
+ * strip away the remaining spaces (tabs stay!).
*/
i = (int)strlen(buf);
@@ -458,7 +407,8 @@ man_ptext(struct man *man, int line, char *buf, int offs)
if (' ' == buf[i - 1] || '\t' == buf[i - 1]) {
if (i > 1 && '\\' != buf[i - 2])
- man_pmsg(man, line, i - 1, MANDOCERR_EOLNSPACE);
+ mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
+ line, i - 1, NULL);
for (--i; i && ' ' == buf[i]; i--)
/* Spin back to non-space. */ ;
@@ -468,9 +418,7 @@ man_ptext(struct man *man, int line, char *buf, int offs)
buf[i] = '\0';
}
-
- if ( ! man_word_alloc(man, line, offs, buf + offs))
- return(0);
+ man_word_alloc(man, line, offs, buf + offs);
/*
* End-of-sentence check. If the last character is an unescaped
@@ -479,173 +427,167 @@ man_ptext(struct man *man, int line, char *buf, int offs)
*/
assert(i);
- if (mandoc_eos(buf, (size_t)i, 0))
+ if (mandoc_eos(buf, (size_t)i))
man->last->flags |= MAN_EOS;
- return(man_descope(man, line, offs));
+ man_descope(man, line, offs);
+ return(1);
}
static int
man_pmacro(struct man *man, int ln, char *buf, int offs)
{
- int i, ppos;
+ struct man_node *n;
+ const char *cp;
enum mant tok;
+ int i, ppos;
+ int bline;
char mac[5];
- struct man_node *n;
-
- if ('"' == buf[offs]) {
- man_pmsg(man, ln, offs, MANDOCERR_BADCOMMENT);
- return(1);
- } else if ('\0' == buf[offs])
- return(1);
ppos = offs;
/*
* Copy the first word into a nil-terminated buffer.
- * Stop copying when a tab, space, or eoln is encountered.
+ * Stop when a space, tab, escape, or eoln is encountered.
*/
i = 0;
- while (i < 4 && '\0' != buf[offs] &&
- ' ' != buf[offs] && '\t' != buf[offs])
+ while (i < 4 && strchr(" \t\\", buf[offs]) == NULL)
mac[i++] = buf[offs++];
mac[i] = '\0';
tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX;
- if (MAN_MAX == tok) {
- mandoc_vmsg(MANDOCERR_MACRO, man->parse, ln,
- ppos, "%s", buf + ppos - 1);
+ if (tok == MAN_MAX) {
+ mandoc_msg(MANDOCERR_MACRO, man->parse,
+ ln, ppos, buf + ppos - 1);
return(1);
}
- /* The macro is sane. Jump to the next word. */
+ /* Skip a leading escape sequence or tab. */
- while (buf[offs] && ' ' == buf[offs])
+ switch (buf[offs]) {
+ case '\\':
+ cp = buf + offs + 1;
+ mandoc_escape(&cp, NULL, NULL);
+ offs = cp - buf;
+ break;
+ case '\t':
offs++;
+ break;
+ default:
+ break;
+ }
+
+ /* Jump to the next non-whitespace word. */
- /*
+ while (buf[offs] && buf[offs] == ' ')
+ offs++;
+
+ /*
* Trailing whitespace. Note that tabs are allowed to be passed
* into the parser as "text", so we only warn about spaces here.
*/
- if ('\0' == buf[offs] && ' ' == buf[offs - 1])
- man_pmsg(man, ln, offs - 1, MANDOCERR_EOLNSPACE);
+ if (buf[offs] == '\0' && buf[offs - 1] == ' ')
+ mandoc_msg(MANDOCERR_SPACE_EOL, man->parse,
+ ln, offs - 1, NULL);
- /*
- * Remove prior ELINE macro, as it's being clobbered by a new
- * macro. Note that NSCOPED macros do not close out ELINE
- * macros---they don't print text---so we let those slip by.
+ /*
+ * Some macros break next-line scopes; otherwise, remember
+ * whether we are in next-line scope for a block head.
*/
- if ( ! (MAN_NSCOPED & man_macros[tok].flags) &&
- man->flags & MAN_ELINE) {
- n = man->last;
- assert(MAN_TEXT != n->type);
+ man_breakscope(man, tok);
+ bline = man->flags & MAN_BLINE;
- /* Remove repeated NSCOPED macros causing ELINE. */
+ /* Call to handler... */
- if (MAN_NSCOPED & man_macros[n->tok].flags)
- n = n->parent;
+ assert(man_macros[tok].fp);
+ (*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf);
- mandoc_vmsg(MANDOCERR_LINESCOPE, man->parse, n->line,
- n->pos, "%s breaks %s", man_macronames[tok],
- man_macronames[n->tok]);
+ /* In quick mode (for mandocdb), abort after the NAME section. */
- man_node_delete(man, n);
- man->flags &= ~MAN_ELINE;
+ if (man->quick && tok == MAN_SH) {
+ n = man->last;
+ if (n->type == MAN_BODY &&
+ strcmp(n->prev->child->string, "NAME"))
+ return(2);
}
/*
- * Remove prior BLINE macro that is being clobbered.
+ * If we are in a next-line scope for a block head,
+ * close it out now and switch to the body,
+ * unless the next-line scope is allowed to continue.
*/
- if ((man->flags & MAN_BLINE) &&
- (MAN_BSCOPE & man_macros[tok].flags)) {
- n = man->last;
-
- /* Might be a text node like 8 in
- * .TP 8
- * .SH foo
- */
- if (MAN_TEXT == n->type)
- n = n->parent;
- /* Remove element that didn't end BLINE, if any. */
- if ( ! (MAN_BSCOPE & man_macros[n->tok].flags))
- n = n->parent;
+ if ( ! bline || man->flags & MAN_ELINE ||
+ man_macros[tok].flags & MAN_NSCOPED)
+ return(1);
- assert(MAN_HEAD == n->type);
- n = n->parent;
- assert(MAN_BLOCK == n->type);
- assert(MAN_SCOPED & man_macros[n->tok].flags);
+ assert(man->flags & MAN_BLINE);
+ man->flags &= ~MAN_BLINE;
- mandoc_vmsg(MANDOCERR_LINESCOPE, man->parse, n->line,
- n->pos, "%s breaks %s", man_macronames[tok],
- man_macronames[n->tok]);
+ man_unscope(man, man->last->parent);
+ man_body_alloc(man, ln, ppos, man->last->tok);
+ return(1);
+}
- man_node_delete(man, n);
- man->flags &= ~MAN_BLINE;
- }
+void
+man_breakscope(struct man *man, enum mant tok)
+{
+ struct man_node *n;
/*
- * Save the fact that we're in the next-line for a block. In
- * this way, embedded roff instructions can "remember" state
- * when they exit.
+ * An element next line scope is open,
+ * and the new macro is not allowed inside elements.
+ * Delete the element that is being broken.
*/
- if (MAN_BLINE & man->flags)
- man->flags |= MAN_BPLINE;
-
- /* Call to handler... */
-
- assert(man_macros[tok].fp);
- if ( ! (*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf))
- goto err;
+ if (man->flags & MAN_ELINE && (tok == MAN_MAX ||
+ ! (man_macros[tok].flags & MAN_NSCOPED))) {
+ n = man->last;
+ assert(n->type != MAN_TEXT);
+ if (man_macros[n->tok].flags & MAN_NSCOPED)
+ n = n->parent;
- /*
- * We weren't in a block-line scope when entering the
- * above-parsed macro, so return.
- */
+ mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
+ n->line, n->pos, "%s breaks %s",
+ tok == MAN_MAX ? "TS" : man_macronames[tok],
+ man_macronames[n->tok]);
- if ( ! (MAN_BPLINE & man->flags)) {
- man->flags &= ~MAN_ILINE;
- return(1);
+ man_node_delete(man, n);
+ man->flags &= ~MAN_ELINE;
}
- man->flags &= ~MAN_BPLINE;
/*
- * If we're in a block scope, then allow this macro to slip by
- * without closing scope around it.
+ * A block header next line scope is open,
+ * and the new macro is not allowed inside block headers.
+ * Delete the block that is being broken.
*/
- if (MAN_ILINE & man->flags) {
- man->flags &= ~MAN_ILINE;
- return(1);
- }
-
- /*
- * If we've opened a new next-line element scope, then return
- * now, as the next line will close out the block scope.
- */
-
- if (MAN_ELINE & man->flags)
- return(1);
-
- /* Close out the block scope opened in the prior line. */
-
- assert(MAN_BLINE & man->flags);
- man->flags &= ~MAN_BLINE;
+ if (man->flags & MAN_BLINE && (tok == MAN_MAX ||
+ man_macros[tok].flags & MAN_BSCOPE)) {
+ n = man->last;
+ if (n->type == MAN_TEXT)
+ n = n->parent;
+ if ( ! (man_macros[n->tok].flags & MAN_BSCOPE))
+ n = n->parent;
- if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX))
- return(0);
- return(man_body_alloc(man, ln, ppos, man->last->tok));
+ assert(n->type == MAN_HEAD);
+ n = n->parent;
+ assert(n->type == MAN_BLOCK);
+ assert(man_macros[n->tok].flags & MAN_SCOPED);
-err: /* Error out. */
+ mandoc_vmsg(MANDOCERR_BLK_LINE, man->parse,
+ n->line, n->pos, "%s breaks %s",
+ tok == MAN_MAX ? "TS" : man_macronames[tok],
+ man_macronames[n->tok]);
- man->flags |= MAN_HALT;
- return(0);
+ man_node_delete(man, n);
+ man->flags &= ~MAN_BLINE;
+ }
}
/*
@@ -696,3 +638,49 @@ man_mparse(const struct man *man)
assert(man && man->parse);
return(man->parse);
}
+
+void
+man_deroff(char **dest, const struct man_node *n)
+{
+ char *cp;
+ size_t sz;
+
+ if (n->type != MAN_TEXT) {
+ for (n = n->child; n; n = n->next)
+ man_deroff(dest, n);
+ return;
+ }
+
+ /* Skip leading whitespace and escape sequences. */
+
+ cp = n->string;
+ while ('\0' != *cp) {
+ if ('\\' == *cp) {
+ cp++;
+ mandoc_escape((const char **)&cp, NULL, NULL);
+ } else if (isspace((unsigned char)*cp))
+ cp++;
+ else
+ break;
+ }
+
+ /* Skip trailing whitespace. */
+
+ for (sz = strlen(cp); sz; sz--)
+ if (0 == isspace((unsigned char)cp[sz-1]))
+ break;
+
+ /* Skip empty strings. */
+
+ if (0 == sz)
+ return;
+
+ if (NULL == *dest) {
+ *dest = mandoc_strndup(cp, sz);
+ return;
+ }
+
+ mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp);
+ free(*dest);
+ *dest = cp;
+}
diff --git a/usr/src/cmd/mandoc/man.h b/usr/src/cmd/mandoc/man.h
index ef9480f276..9e8eb03e57 100644
--- a/usr/src/cmd/mandoc/man.h
+++ b/usr/src/cmd/mandoc/man.h
@@ -1,6 +1,7 @@
-/* $Id: man.h,v 1.62 2013/10/17 20:54:58 schwarze Exp $ */
+/* $Id: man.h,v 1.69 2015/01/24 02:41:49 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,8 +15,6 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef MAN_H
-#define MAN_H
enum mant {
MAN_br = 0,
@@ -39,7 +38,6 @@ enum mant {
MAN_I,
MAN_IR,
MAN_RI,
- MAN_na,
MAN_sp,
MAN_nf,
MAN_fi,
@@ -56,6 +54,7 @@ enum mant {
MAN_EE,
MAN_UR,
MAN_UE,
+ MAN_ll,
MAN_MAX
};
@@ -66,7 +65,6 @@ enum man_type {
MAN_BLOCK,
MAN_HEAD,
MAN_BODY,
- MAN_TAIL,
MAN_TBL,
MAN_EQN
};
@@ -77,6 +75,7 @@ struct man_meta {
char *vol; /* `TH' volume */
char *title; /* `TH' title (e.g., FOO) */
char *source; /* `TH' source (e.g., GNU) */
+ int hasbody; /* document is not empty */
};
struct man_node {
@@ -99,6 +98,7 @@ struct man_node {
struct man_node *body; /* BLOCK node BODY ptr */
const struct tbl_span *span; /* TBL */
const struct eqn *eqn; /* EQN */
+ int aux; /* decoded node data, type-dependent */
};
/* Names of macros. Index is enum mant. */
@@ -111,7 +111,6 @@ struct man;
const struct man_node *man_node(const struct man *);
const struct man_meta *man_meta(const struct man *);
const struct mparse *man_mparse(const struct man *);
+void man_deroff(char **, const struct man_node *);
__END_DECLS
-
-#endif /*!MAN_H*/
diff --git a/usr/src/cmd/mandoc/man_hash.c b/usr/src/cmd/mandoc/man_hash.c
index 86c5c40a19..1cbfb1b7f8 100644
--- a/usr/src/cmd/mandoc/man_hash.c
+++ b/usr/src/cmd/mandoc/man_hash.c
@@ -1,4 +1,4 @@
-/* $Id: man_hash.c,v 1.25 2011/07/24 18:15:14 kristaps Exp $ */
+/* $Id: man_hash.c,v 1.29 2014/12/01 08:05:52 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -14,20 +14,16 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#include <sys/types.h>
#include <assert.h>
#include <ctype.h>
#include <limits.h>
-#include <stdlib.h>
#include <string.h>
#include "man.h"
-#include "mandoc.h"
#include "libman.h"
#define HASH_DEPTH 6
@@ -49,6 +45,7 @@
*/
static unsigned char table[26 * HASH_DEPTH];
+
/*
* XXX - this hash has global scope, so if intended for use as a library
* with multiple callers, it will need re-invocation protection.
@@ -60,8 +57,7 @@ man_hash_init(void)
memset(table, UCHAR_MAX, sizeof(table));
- assert(/* LINTED */
- MAN_MAX < UCHAR_MAX);
+ assert(MAN_MAX < UCHAR_MAX);
for (i = 0; i < (int)MAN_MAX; i++) {
x = man_macronames[i][0];
@@ -80,7 +76,6 @@ man_hash_init(void)
}
}
-
enum mant
man_hash_find(const char *tmp)
{
diff --git a/usr/src/cmd/mandoc/man_html.c b/usr/src/cmd/mandoc/man_html.c
index 2c4e220a11..1109415025 100644
--- a/usr/src/cmd/mandoc/man_html.c
+++ b/usr/src/cmd/mandoc/man_html.c
@@ -1,7 +1,7 @@
-/* $Id: man_html.c,v 1.90 2013/10/17 20:54:58 schwarze Exp $ */
+/* $Id: man_html.c,v 1.112 2015/03/03 21:11:34 schwarze Exp $ */
/*
- * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2013, 2014, 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
@@ -15,9 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#include <sys/types.h>
@@ -27,10 +25,10 @@
#include <stdlib.h>
#include <string.h>
-#include "mandoc.h"
+#include "mandoc_aux.h"
+#include "man.h"
#include "out.h"
#include "html.h"
-#include "man.h"
#include "main.h"
/* TODO: preserve ident widths. */
@@ -53,7 +51,7 @@ struct htmlman {
int (*post)(MAN_ARGS);
};
-static void print_bvspace(struct html *,
+static void print_bvspace(struct html *,
const struct man_node *);
static void print_man(MAN_ARGS);
static void print_man_head(MAN_ARGS);
@@ -90,7 +88,7 @@ static const struct htmlman mans[MAN_MAX] = {
{ man_PP_pre, NULL }, /* PP */
{ man_PP_pre, NULL }, /* P */
{ man_IP_pre, NULL }, /* IP */
- { man_HP_pre, NULL }, /* HP */
+ { man_HP_pre, NULL }, /* HP */
{ man_SM_pre, NULL }, /* SM */
{ man_SM_pre, NULL }, /* SB */
{ man_alt_pre, NULL }, /* BI */
@@ -102,7 +100,6 @@ static const struct htmlman mans[MAN_MAX] = {
{ man_I_pre, NULL }, /* I */
{ man_alt_pre, NULL }, /* IR */
{ man_alt_pre, NULL }, /* RI */
- { man_ign_pre, NULL }, /* na */
{ man_br_pre, NULL }, /* sp */
{ man_literal_pre, NULL }, /* nf */
{ man_literal_pre, NULL }, /* fi */
@@ -119,8 +116,10 @@ static const struct htmlman mans[MAN_MAX] = {
{ man_literal_pre, NULL }, /* EE */
{ man_UR_pre, NULL }, /* UR */
{ NULL, NULL }, /* UE */
+ { man_ign_pre, NULL }, /* ll */
};
+
/*
* Printing leading vertical space before a block.
* This is used for the paragraph macros.
@@ -141,7 +140,7 @@ print_bvspace(struct html *h, const struct man_node *n)
if (NULL == n->prev)
return;
- print_otag(h, TAG_P, 0, NULL);
+ print_paragraph(h);
}
void
@@ -155,7 +154,7 @@ html_man(void *arg, const struct man *man)
}
static void
-print_man(MAN_ARGS)
+print_man(MAN_ARGS)
{
struct tag *t, *tt;
struct htmlpair tag;
@@ -170,15 +169,13 @@ print_man(MAN_ARGS)
print_tagq(h, tt);
print_otag(h, TAG_BODY, 0, NULL);
print_otag(h, TAG_DIV, 1, &tag);
- } else
+ } else
t = print_otag(h, TAG_DIV, 1, &tag);
print_man_nodelist(man, n, mh, h);
print_tagq(h, t);
}
-
-/* ARGSUSED */
static void
print_man_head(MAN_ARGS)
{
@@ -191,17 +188,16 @@ print_man_head(MAN_ARGS)
print_text(h, h->buf);
}
-
static void
print_man_nodelist(MAN_ARGS)
{
- print_man_node(man, n, mh, h);
- if (n->next)
- print_man_nodelist(man, n->next, mh, h);
+ while (n != NULL) {
+ print_man_node(man, n, mh, h);
+ n = n->next;
+ }
}
-
static void
print_man_node(MAN_ARGS)
{
@@ -212,31 +208,26 @@ print_man_node(MAN_ARGS)
t = h->tags.head;
switch (n->type) {
- case (MAN_ROOT):
+ case MAN_ROOT:
man_root_pre(man, n, mh, h);
break;
- case (MAN_TEXT):
- /*
- * If we have a blank line, output a vertical space.
- * If we have a space as the first character, break
- * before printing the line's data.
- */
+ case MAN_TEXT:
if ('\0' == *n->string) {
- print_otag(h, TAG_P, 0, NULL);
+ print_paragraph(h);
return;
}
-
- if (' ' == *n->string && MAN_LINE & n->flags)
- print_otag(h, TAG_BR, 0, NULL);
- else if (MANH_LITERAL & mh->fl && n->prev)
+ if (n->flags & MAN_LINE && (*n->string == ' ' ||
+ (n->prev != NULL && mh->fl & MANH_LITERAL &&
+ ! (h->flags & HTML_NONEWLINE))))
print_otag(h, TAG_BR, 0, NULL);
-
print_text(h, n->string);
return;
- case (MAN_EQN):
+ case MAN_EQN:
+ if (n->flags & MAN_LINE)
+ putchar('\n');
print_eqn(h, n->eqn);
break;
- case (MAN_TBL):
+ case MAN_TBL:
/*
* This will take care of initialising all of the table
* state data for the first table, then tearing it down
@@ -245,7 +236,7 @@ print_man_node(MAN_ARGS)
print_tbl(h, n->span);
return;
default:
- /*
+ /*
* Close out scope of font prior to opening a macro
* scope.
*/
@@ -275,10 +266,10 @@ print_man_node(MAN_ARGS)
print_stagq(h, t);
switch (n->type) {
- case (MAN_ROOT):
+ case MAN_ROOT:
man_root_post(man, n, mh, h);
break;
- case (MAN_EQN):
+ case MAN_EQN:
break;
default:
if (mans[n->tok].post)
@@ -287,95 +278,74 @@ print_man_node(MAN_ARGS)
}
}
-
static int
a2width(const struct man_node *n, struct roffsu *su)
{
if (MAN_TEXT != n->type)
return(0);
- if (a2roffsu(n->string, su, SCALE_BU))
+ if (a2roffsu(n->string, su, SCALE_EN))
return(1);
return(0);
}
-
-/* ARGSUSED */
static void
man_root_pre(MAN_ARGS)
{
- struct htmlpair tag[3];
+ struct htmlpair tag;
struct tag *t, *tt;
- char b[BUFSIZ], title[BUFSIZ];
-
- b[0] = 0;
- if (man->vol)
- (void)strlcat(b, man->vol, BUFSIZ);
+ char *title;
assert(man->title);
assert(man->msec);
- snprintf(title, BUFSIZ - 1, "%s(%s)", man->title, man->msec);
+ mandoc_asprintf(&title, "%s(%s)", man->title, man->msec);
- PAIR_SUMMARY_INIT(&tag[0], "Document Header");
- PAIR_CLASS_INIT(&tag[1], "head");
- PAIR_INIT(&tag[2], ATTR_WIDTH, "100%");
- t = print_otag(h, TAG_TABLE, 3, tag);
- PAIR_INIT(&tag[0], ATTR_WIDTH, "30%");
- print_otag(h, TAG_COL, 1, tag);
- print_otag(h, TAG_COL, 1, tag);
- print_otag(h, TAG_COL, 1, tag);
+ PAIR_CLASS_INIT(&tag, "head");
+ t = print_otag(h, TAG_TABLE, 1, &tag);
print_otag(h, TAG_TBODY, 0, NULL);
tt = print_otag(h, TAG_TR, 0, NULL);
- PAIR_CLASS_INIT(&tag[0], "head-ltitle");
- print_otag(h, TAG_TD, 1, tag);
+ PAIR_CLASS_INIT(&tag, "head-ltitle");
+ print_otag(h, TAG_TD, 1, &tag);
print_text(h, title);
print_stagq(h, tt);
- PAIR_CLASS_INIT(&tag[0], "head-vol");
- PAIR_INIT(&tag[1], ATTR_ALIGN, "center");
- print_otag(h, TAG_TD, 2, tag);
- print_text(h, b);
+ PAIR_CLASS_INIT(&tag, "head-vol");
+ print_otag(h, TAG_TD, 1, &tag);
+ if (NULL != man->vol)
+ print_text(h, man->vol);
print_stagq(h, tt);
- PAIR_CLASS_INIT(&tag[0], "head-rtitle");
- PAIR_INIT(&tag[1], ATTR_ALIGN, "right");
- print_otag(h, TAG_TD, 2, tag);
+ PAIR_CLASS_INIT(&tag, "head-rtitle");
+ print_otag(h, TAG_TD, 1, &tag);
print_text(h, title);
print_tagq(h, t);
+ free(title);
}
-
-/* ARGSUSED */
static void
man_root_post(MAN_ARGS)
{
- struct htmlpair tag[3];
+ struct htmlpair tag;
struct tag *t, *tt;
- PAIR_SUMMARY_INIT(&tag[0], "Document Footer");
- PAIR_CLASS_INIT(&tag[1], "foot");
- PAIR_INIT(&tag[2], ATTR_WIDTH, "100%");
- t = print_otag(h, TAG_TABLE, 3, tag);
- PAIR_INIT(&tag[0], ATTR_WIDTH, "50%");
- print_otag(h, TAG_COL, 1, tag);
- print_otag(h, TAG_COL, 1, tag);
+ PAIR_CLASS_INIT(&tag, "foot");
+ t = print_otag(h, TAG_TABLE, 1, &tag);
tt = print_otag(h, TAG_TR, 0, NULL);
- PAIR_CLASS_INIT(&tag[0], "foot-date");
- print_otag(h, TAG_TD, 1, tag);
+ PAIR_CLASS_INIT(&tag, "foot-date");
+ print_otag(h, TAG_TD, 1, &tag);
assert(man->date);
print_text(h, man->date);
print_stagq(h, tt);
- PAIR_CLASS_INIT(&tag[0], "foot-os");
- PAIR_INIT(&tag[1], ATTR_ALIGN, "right");
- print_otag(h, TAG_TD, 2, tag);
+ PAIR_CLASS_INIT(&tag, "foot-os");
+ print_otag(h, TAG_TD, 1, &tag);
if (man->source)
print_text(h, man->source);
@@ -383,7 +353,6 @@ man_root_post(MAN_ARGS)
}
-/* ARGSUSED */
static int
man_br_pre(MAN_ARGS)
{
@@ -395,9 +364,9 @@ man_br_pre(MAN_ARGS)
if (MAN_sp == n->tok) {
if (NULL != (n = n->child))
if ( ! a2roffsu(n->string, &su, SCALE_VS))
- SCALE_VS_INIT(&su, atoi(n->string));
+ su.scale = 1.0;
} else
- su.scale = 0;
+ su.scale = 0.0;
bufinit(h);
bufcat_su(h, "height", &su);
@@ -410,7 +379,6 @@ man_br_pre(MAN_ARGS)
return(0);
}
-/* ARGSUSED */
static int
man_SH_pre(MAN_ARGS)
{
@@ -428,7 +396,6 @@ man_SH_pre(MAN_ARGS)
return(1);
}
-/* ARGSUSED */
static int
man_alt_pre(MAN_ARGS)
{
@@ -437,7 +404,7 @@ man_alt_pre(MAN_ARGS)
enum htmltag fp;
struct tag *t;
- if ((savelit = mh->fl & MANH_LITERAL))
+ if ((savelit = mh->fl & MANH_LITERAL))
print_otag(h, TAG_BR, 0, NULL);
mh->fl &= ~MANH_LITERAL;
@@ -445,22 +412,22 @@ man_alt_pre(MAN_ARGS)
for (i = 0, nn = n->child; nn; nn = nn->next, i++) {
t = NULL;
switch (n->tok) {
- case (MAN_BI):
+ case MAN_BI:
fp = i % 2 ? TAG_I : TAG_B;
break;
- case (MAN_IB):
+ case MAN_IB:
fp = i % 2 ? TAG_B : TAG_I;
break;
- case (MAN_RI):
+ case MAN_RI:
fp = i % 2 ? TAG_I : TAG_MAX;
break;
- case (MAN_IR):
+ case MAN_IR:
fp = i % 2 ? TAG_MAX : TAG_I;
break;
- case (MAN_BR):
+ case MAN_BR:
fp = i % 2 ? TAG_MAX : TAG_B;
break;
- case (MAN_RB):
+ case MAN_RB:
fp = i % 2 ? TAG_B : TAG_MAX;
break;
default:
@@ -486,18 +453,16 @@ man_alt_pre(MAN_ARGS)
return(0);
}
-/* ARGSUSED */
static int
man_SM_pre(MAN_ARGS)
{
-
+
print_otag(h, TAG_SMALL, 0, NULL);
if (MAN_SB == n->tok)
print_otag(h, TAG_B, 0, NULL);
return(1);
}
-/* ARGSUSED */
static int
man_SS_pre(MAN_ARGS)
{
@@ -515,7 +480,6 @@ man_SS_pre(MAN_ARGS)
return(1);
}
-/* ARGSUSED */
static int
man_PP_pre(MAN_ARGS)
{
@@ -528,13 +492,12 @@ man_PP_pre(MAN_ARGS)
return(1);
}
-/* ARGSUSED */
static int
man_IP_pre(MAN_ARGS)
{
const struct man_node *nn;
- if (MAN_BODY == n->type) {
+ if (MAN_BODY == n->type) {
print_otag(h, TAG_DD, 0, NULL);
return(1);
} else if (MAN_HEAD != n->type) {
@@ -553,19 +516,23 @@ man_IP_pre(MAN_ARGS)
/* For TP, only print next-line header elements. */
- if (MAN_TP == n->tok)
- for (nn = n->child; nn; nn = nn->next)
- if (nn->line > n->line)
- print_man_node(man, nn, mh, h);
+ if (MAN_TP == n->tok) {
+ nn = n->child;
+ while (NULL != nn && 0 == (MAN_LINE & nn->flags))
+ nn = nn->next;
+ while (NULL != nn) {
+ print_man_node(man, nn, mh, h);
+ nn = nn->next;
+ }
+ }
return(0);
}
-/* ARGSUSED */
static int
man_HP_pre(MAN_ARGS)
{
- struct htmlpair tag;
+ struct htmlpair tag[2];
struct roffsu su;
const struct man_node *np;
@@ -585,12 +552,12 @@ man_HP_pre(MAN_ARGS)
bufcat_su(h, "margin-left", &su);
su.scale = -su.scale;
bufcat_su(h, "text-indent", &su);
- PAIR_STYLE_INIT(&tag, h);
- print_otag(h, TAG_P, 1, &tag);
+ PAIR_STYLE_INIT(&tag[0], h);
+ PAIR_CLASS_INIT(&tag[1], "spacer");
+ print_otag(h, TAG_DIV, 2, tag);
return(1);
}
-/* ARGSUSED */
static int
man_OP_pre(MAN_ARGS)
{
@@ -620,8 +587,6 @@ man_OP_pre(MAN_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
man_B_pre(MAN_ARGS)
{
@@ -630,16 +595,14 @@ man_B_pre(MAN_ARGS)
return(1);
}
-/* ARGSUSED */
static int
man_I_pre(MAN_ARGS)
{
-
+
print_otag(h, TAG_I, 0, NULL);
return(1);
}
-/* ARGSUSED */
static int
man_literal_pre(MAN_ARGS)
{
@@ -653,7 +616,6 @@ man_literal_pre(MAN_ARGS)
return(0);
}
-/* ARGSUSED */
static int
man_in_pre(MAN_ARGS)
{
@@ -662,7 +624,6 @@ man_in_pre(MAN_ARGS)
return(0);
}
-/* ARGSUSED */
static int
man_ign_pre(MAN_ARGS)
{
@@ -670,7 +631,6 @@ man_ign_pre(MAN_ARGS)
return(0);
}
-/* ARGSUSED */
static int
man_RS_pre(MAN_ARGS)
{
@@ -693,7 +653,6 @@ man_RS_pre(MAN_ARGS)
return(1);
}
-/* ARGSUSED */
static int
man_UR_pre(MAN_ARGS)
{
diff --git a/usr/src/cmd/mandoc/man_macro.c b/usr/src/cmd/mandoc/man_macro.c
index 479d0484c4..c86ab6f13f 100644
--- a/usr/src/cmd/mandoc/man_macro.c
+++ b/usr/src/cmd/mandoc/man_macro.c
@@ -1,7 +1,7 @@
-/* $Id: man_macro.c,v 1.79 2013/12/25 00:50:05 schwarze Exp $ */
+/* $Id: man_macro.c,v 1.98 2015/02/06 11:54:36 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2012, 2013, 2014, 2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -16,9 +16,9 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
+
+#include <sys/types.h>
#include <assert.h>
#include <ctype.h>
@@ -36,21 +36,19 @@ enum rew {
REW_HALT
};
-static int blk_close(MACRO_PROT_ARGS);
-static int blk_exp(MACRO_PROT_ARGS);
-static int blk_imp(MACRO_PROT_ARGS);
-static int in_line_eoln(MACRO_PROT_ARGS);
-static int man_args(struct man *, int,
+static void blk_close(MACRO_PROT_ARGS);
+static void blk_exp(MACRO_PROT_ARGS);
+static void blk_imp(MACRO_PROT_ARGS);
+static void in_line_eoln(MACRO_PROT_ARGS);
+static int man_args(struct man *, int,
int *, char *, char **);
-static int rew_scope(enum man_type,
+static void rew_scope(enum man_type,
struct man *, enum mant);
-static enum rew rew_dohalt(enum mant, enum man_type,
+static enum rew rew_dohalt(enum mant, enum man_type,
const struct man_node *);
-static enum rew rew_block(enum mant, enum man_type,
+static enum rew rew_block(enum mant, enum man_type,
const struct man_node *);
-static void rew_warn(struct man *,
- struct man_node *, enum mandocerr);
const struct man_macro __man_macros[MAN_MAX] = {
{ in_line_eoln, MAN_NSCOPED }, /* br */
@@ -63,22 +61,21 @@ const struct man_macro __man_macros[MAN_MAX] = {
{ blk_imp, MAN_BSCOPE }, /* P */
{ blk_imp, MAN_BSCOPE }, /* IP */
{ blk_imp, MAN_BSCOPE }, /* HP */
- { in_line_eoln, MAN_SCOPED }, /* SM */
- { in_line_eoln, MAN_SCOPED }, /* SB */
+ { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* SM */
+ { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* SB */
{ in_line_eoln, 0 }, /* BI */
{ in_line_eoln, 0 }, /* IB */
{ in_line_eoln, 0 }, /* BR */
{ in_line_eoln, 0 }, /* RB */
- { in_line_eoln, MAN_SCOPED }, /* R */
- { in_line_eoln, MAN_SCOPED }, /* B */
- { in_line_eoln, MAN_SCOPED }, /* I */
+ { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* R */
+ { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* B */
+ { in_line_eoln, MAN_SCOPED | MAN_JOIN }, /* I */
{ in_line_eoln, 0 }, /* IR */
{ in_line_eoln, 0 }, /* RI */
- { in_line_eoln, MAN_NSCOPED }, /* na */
{ in_line_eoln, MAN_NSCOPED }, /* sp */
{ in_line_eoln, MAN_BSCOPE }, /* nf */
{ in_line_eoln, MAN_BSCOPE }, /* fi */
- { blk_close, 0 }, /* RE */
+ { blk_close, MAN_BSCOPE }, /* RE */
{ blk_exp, MAN_BSCOPE | MAN_EXPLICIT }, /* RS */
{ in_line_eoln, 0 }, /* DT */
{ in_line_eoln, 0 }, /* UC */
@@ -90,86 +87,89 @@ const struct man_macro __man_macros[MAN_MAX] = {
{ in_line_eoln, MAN_BSCOPE }, /* EX */
{ in_line_eoln, MAN_BSCOPE }, /* EE */
{ blk_exp, MAN_BSCOPE | MAN_EXPLICIT }, /* UR */
- { blk_close, 0 }, /* UE */
+ { blk_close, MAN_BSCOPE }, /* UE */
+ { in_line_eoln, 0 }, /* ll */
};
const struct man_macro * const man_macros = __man_macros;
-/*
- * Warn when "n" is an explicit non-roff macro.
- */
-static void
-rew_warn(struct man *man, struct man_node *n, enum mandocerr er)
-{
-
- if (er == MANDOCERR_MAX || MAN_BLOCK != n->type)
- return;
- if (MAN_VALID & n->flags)
- return;
- if ( ! (MAN_EXPLICIT & man_macros[n->tok].flags))
- return;
-
- assert(er < MANDOCERR_FATAL);
- man_nmsg(man, n, er);
-}
-
-
-/*
- * Rewind scope. If a code "er" != MANDOCERR_MAX has been provided, it
- * will be used if an explicit block scope is being closed out.
- */
-int
-man_unscope(struct man *man, const struct man_node *to,
- enum mandocerr er)
+void
+man_unscope(struct man *man, const struct man_node *to)
{
struct man_node *n;
- assert(to);
-
- man->next = MAN_NEXT_SIBLING;
+ to = to->parent;
+ n = man->last;
+ while (n != to) {
+
+ /* Reached the end of the document? */
+
+ if (to == NULL && ! (n->flags & MAN_VALID)) {
+ if (man->flags & (MAN_BLINE | MAN_ELINE) &&
+ man_macros[n->tok].flags & MAN_SCOPED) {
+ mandoc_vmsg(MANDOCERR_BLK_LINE,
+ man->parse, n->line, n->pos,
+ "EOF breaks %s",
+ man_macronames[n->tok]);
+ if (man->flags & MAN_ELINE)
+ man->flags &= ~MAN_ELINE;
+ else {
+ assert(n->type == MAN_HEAD);
+ n = n->parent;
+ man->flags &= ~MAN_BLINE;
+ }
+ man->last = n;
+ n = n->parent;
+ man_node_delete(man, man->last);
+ continue;
+ }
+ if (n->type == MAN_BLOCK &&
+ man_macros[n->tok].flags & MAN_EXPLICIT)
+ mandoc_msg(MANDOCERR_BLK_NOEND,
+ man->parse, n->line, n->pos,
+ man_macronames[n->tok]);
+ }
- /* LINTED */
- while (man->last != to) {
/*
- * Save the parent here, because we may delete the
- * man->last node in the post-validation phase and reset
- * it to man->last->parent, causing a step in the closing
- * out to be lost.
+ * We might delete the man->last node
+ * in the post-validation phase.
+ * Save a pointer to the parent such that
+ * we know where to continue the iteration.
*/
- n = man->last->parent;
- rew_warn(man, man->last, er);
- if ( ! man_valid_post(man))
- return(0);
+
man->last = n;
- assert(man->last);
+ n = n->parent;
+ man_valid_post(man);
}
- rew_warn(man, man->last, er);
- if ( ! man_valid_post(man))
- return(0);
+ /*
+ * If we ended up at the parent of the node we were
+ * supposed to rewind to, that means the target node
+ * got deleted, so add the next node we parse as a child
+ * of the parent instead of as a sibling of the target.
+ */
- return(1);
+ man->next = (man->last == to) ?
+ MAN_NEXT_CHILD : MAN_NEXT_SIBLING;
}
-
static enum rew
rew_block(enum mant ntok, enum man_type type, const struct man_node *n)
{
- if (MAN_BLOCK == type && ntok == n->parent->tok &&
- MAN_BODY == n->parent->type)
+ if (type == MAN_BLOCK && ntok == n->parent->tok &&
+ n->parent->type == MAN_BODY)
return(REW_REWIND);
return(ntok == n->tok ? REW_HALT : REW_NOHALT);
}
-
/*
* There are three scope levels: scoped to the root (all), scoped to the
* section (all less sections), and scoped to subsections (all less
* sections and subsections).
*/
-static enum rew
+static enum rew
rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n)
{
enum rew c;
@@ -196,20 +196,20 @@ rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n)
return(REW_REWIND);
}
- /*
+ /*
* Next follow the implicit scope-smashings as defined by man.7:
* section, sub-section, etc.
*/
switch (tok) {
- case (MAN_SH):
+ case MAN_SH:
break;
- case (MAN_SS):
+ case MAN_SS:
/* Rewind to a section, if a block. */
if (REW_NOHALT != (c = rew_block(MAN_SH, type, n)))
return(c);
break;
- case (MAN_RS):
+ case MAN_RS:
/* Preserve empty paragraphs before RS. */
if (0 == n->nchild && (MAN_P == n->tok ||
MAN_PP == n->tok || MAN_LP == n->tok))
@@ -237,57 +237,73 @@ rew_dohalt(enum mant tok, enum man_type type, const struct man_node *n)
return(REW_NOHALT);
}
-
/*
* Rewinding entails ascending the parse tree until a coherent point,
* for example, the `SH' macro will close out any intervening `SS'
* scopes. When a scope is closed, it must be validated and actioned.
*/
-static int
+static void
rew_scope(enum man_type type, struct man *man, enum mant tok)
{
struct man_node *n;
enum rew c;
- /* LINTED */
for (n = man->last; n; n = n->parent) {
- /*
+ /*
* Whether we should stop immediately (REW_HALT), stop
* and rewind until this point (REW_REWIND), or keep
* rewinding (REW_NOHALT).
*/
c = rew_dohalt(tok, type, n);
if (REW_HALT == c)
- return(1);
+ return;
if (REW_REWIND == c)
break;
}
- /*
+ /*
* Rewind until the current point. Warn if we're a roff
* instruction that's mowing over explicit scopes.
*/
- assert(n);
- return(man_unscope(man, n, MANDOCERR_MAX));
+ man_unscope(man, n);
}
/*
* Close out a generic explicit macro.
*/
-/* ARGSUSED */
-int
+void
blk_close(MACRO_PROT_ARGS)
{
- enum mant ntok;
+ enum mant ntok;
const struct man_node *nn;
+ char *p;
+ int nrew, target;
+ nrew = 1;
switch (tok) {
- case (MAN_RE):
+ case MAN_RE:
ntok = MAN_RS;
+ if ( ! man_args(man, line, pos, buf, &p))
+ break;
+ for (nn = man->last->parent; nn; nn = nn->parent)
+ if (nn->tok == ntok && nn->type == MAN_BLOCK)
+ nrew++;
+ target = strtol(p, &p, 10);
+ if (*p != '\0')
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
+ line, p - buf, "RE ... %s", p);
+ if (target == 0)
+ target = 1;
+ nrew -= target;
+ if (nrew < 1) {
+ mandoc_vmsg(MANDOCERR_RE_NOTOPEN, man->parse,
+ line, ppos, "RE %d", target);
+ return;
+ }
break;
- case (MAN_UE):
+ case MAN_UE:
ntok = MAN_UR;
break;
default:
@@ -296,90 +312,70 @@ blk_close(MACRO_PROT_ARGS)
}
for (nn = man->last->parent; nn; nn = nn->parent)
- if (ntok == nn->tok && MAN_BLOCK == nn->type)
+ if (nn->tok == ntok && nn->type == MAN_BLOCK && ! --nrew)
break;
- if (NULL == nn) {
- man_pmsg(man, line, ppos, MANDOCERR_NOSCOPE);
- if ( ! rew_scope(MAN_BLOCK, man, MAN_PP))
- return(0);
- } else
- man_unscope(man, nn, MANDOCERR_MAX);
-
- return(1);
+ if (nn == NULL) {
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, man->parse,
+ line, ppos, man_macronames[tok]);
+ rew_scope(MAN_BLOCK, man, MAN_PP);
+ } else {
+ line = man->last->line;
+ ppos = man->last->pos;
+ ntok = man->last->tok;
+ man_unscope(man, nn);
+
+ /* Move a trailing paragraph behind the block. */
+
+ if (ntok == MAN_LP || ntok == MAN_PP || ntok == MAN_P) {
+ *pos = strlen(buf);
+ blk_imp(man, ntok, line, ppos, pos, buf);
+ }
+ }
}
-
-/* ARGSUSED */
-int
+void
blk_exp(MACRO_PROT_ARGS)
{
- struct man_node *n;
- int la;
+ struct man_node *head;
char *p;
+ int la;
- /* Close out prior implicit scopes. */
-
- if ( ! rew_scope(MAN_BLOCK, man, tok))
- return(0);
-
- if ( ! man_block_alloc(man, line, ppos, tok))
- return(0);
- if ( ! man_head_alloc(man, line, ppos, tok))
- return(0);
-
- for (;;) {
- la = *pos;
- if ( ! man_args(man, line, pos, buf, &p))
- break;
- if ( ! man_word_alloc(man, line, la, p))
- return(0);
- }
+ rew_scope(MAN_BLOCK, man, tok);
+ man_block_alloc(man, line, ppos, tok);
+ man_head_alloc(man, line, ppos, tok);
+ head = man->last;
- assert(man);
- assert(tok != MAN_MAX);
+ la = *pos;
+ if (man_args(man, line, pos, buf, &p))
+ man_word_alloc(man, line, la, p);
- for (n = man->last; n; n = n->parent) {
- if (n->tok != tok)
- continue;
- assert(MAN_HEAD == n->type);
- man_unscope(man, n, MANDOCERR_MAX);
- break;
- }
+ if (buf[*pos] != '\0')
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS,
+ man->parse, line, *pos, "%s ... %s",
+ man_macronames[tok], buf + *pos);
- return(man_body_alloc(man, line, ppos, tok));
+ man_unscope(man, head);
+ man_body_alloc(man, line, ppos, tok);
}
-
-
/*
* Parse an implicit-block macro. These contain a MAN_HEAD and a
* MAN_BODY contained within a MAN_BLOCK. Rules for closing out other
* scopes, such as `SH' closing out an `SS', are defined in the rew
* routines.
*/
-/* ARGSUSED */
-int
+void
blk_imp(MACRO_PROT_ARGS)
{
int la;
char *p;
struct man_node *n;
- /* Close out prior scopes. */
-
- if ( ! rew_scope(MAN_BODY, man, tok))
- return(0);
- if ( ! rew_scope(MAN_BLOCK, man, tok))
- return(0);
-
- /* Allocate new block & head scope. */
-
- if ( ! man_block_alloc(man, line, ppos, tok))
- return(0);
- if ( ! man_head_alloc(man, line, ppos, tok))
- return(0);
-
+ rew_scope(MAN_BODY, man, tok);
+ rew_scope(MAN_BLOCK, man, tok);
+ man_block_alloc(man, line, ppos, tok);
+ man_head_alloc(man, line, ppos, tok);
n = man->last;
/* Add line arguments. */
@@ -388,48 +384,58 @@ blk_imp(MACRO_PROT_ARGS)
la = *pos;
if ( ! man_args(man, line, pos, buf, &p))
break;
- if ( ! man_word_alloc(man, line, la, p))
- return(0);
+ man_word_alloc(man, line, la, p);
}
/* Close out head and open body (unless MAN_SCOPE). */
- if (MAN_SCOPED & man_macros[tok].flags) {
+ if (man_macros[tok].flags & MAN_SCOPED) {
/* If we're forcing scope (`TP'), keep it open. */
- if (MAN_FSCOPED & man_macros[tok].flags) {
+ if (man_macros[tok].flags & MAN_FSCOPED) {
man->flags |= MAN_BLINE;
- return(1);
+ return;
} else if (n == man->last) {
man->flags |= MAN_BLINE;
- return(1);
+ return;
}
}
-
- if ( ! rew_scope(MAN_HEAD, man, tok))
- return(0);
- return(man_body_alloc(man, line, ppos, tok));
+ rew_scope(MAN_HEAD, man, tok);
+ man_body_alloc(man, line, ppos, tok);
}
-
-/* ARGSUSED */
-int
+void
in_line_eoln(MACRO_PROT_ARGS)
{
int la;
char *p;
struct man_node *n;
- if ( ! man_elem_alloc(man, line, ppos, tok))
- return(0);
-
+ man_elem_alloc(man, line, ppos, tok);
n = man->last;
for (;;) {
+ if (buf[*pos] != '\0' && (tok == MAN_br ||
+ tok == MAN_fi || tok == MAN_nf)) {
+ mandoc_vmsg(MANDOCERR_ARG_SKIP,
+ man->parse, line, *pos, "%s %s",
+ man_macronames[tok], buf + *pos);
+ break;
+ }
+ if (buf[*pos] != '\0' && man->last != n &&
+ (tok == MAN_PD || tok == MAN_ft || tok == MAN_sp)) {
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS,
+ man->parse, line, *pos, "%s ... %s",
+ man_macronames[tok], buf + *pos);
+ break;
+ }
la = *pos;
if ( ! man_args(man, line, pos, buf, &p))
break;
- if ( ! man_word_alloc(man, line, la, p))
- return(0);
+ if (man_macros[tok].flags & MAN_JOIN &&
+ man->last->type == MAN_TEXT)
+ man_word_append(man, p);
+ else
+ man_word_alloc(man, line, la, p);
}
/*
@@ -438,7 +444,7 @@ in_line_eoln(MACRO_PROT_ARGS)
*/
if (n != man->last &&
- mandoc_eos(man->last->string, strlen(man->last->string), 0))
+ mandoc_eos(man->last->string, strlen(man->last->string)))
man->last->flags |= MAN_EOS;
/*
@@ -447,22 +453,15 @@ in_line_eoln(MACRO_PROT_ARGS)
* waiting for terms to load into our context.
*/
- if (n == man->last && MAN_SCOPED & man_macros[tok].flags) {
- assert( ! (MAN_NSCOPED & man_macros[tok].flags));
+ if (n == man->last && man_macros[tok].flags & MAN_SCOPED) {
+ assert( ! (man_macros[tok].flags & MAN_NSCOPED));
man->flags |= MAN_ELINE;
- return(1);
- }
-
- /* Set ignorable context, if applicable. */
-
- if (MAN_NSCOPED & man_macros[tok].flags) {
- assert( ! (MAN_SCOPED & man_macros[tok].flags));
- man->flags |= MAN_ILINE;
+ return;
}
- assert(MAN_ROOT != man->last->type);
+ assert(man->last->type != MAN_ROOT);
man->next = MAN_NEXT_SIBLING;
-
+
/*
* Rewind our element scope. Note that when TH is pruned, we'll
* be back at the root, so make sure that we don't clobber as
@@ -474,28 +473,25 @@ in_line_eoln(MACRO_PROT_ARGS)
break;
if (man->last->type == MAN_ROOT)
break;
- if ( ! man_valid_post(man))
- return(0);
+ man_valid_post(man);
}
assert(man->last);
/*
- * Same here regarding whether we're back at the root.
+ * Same here regarding whether we're back at the root.
*/
- if (man->last->type != MAN_ROOT && ! man_valid_post(man))
- return(0);
-
- return(1);
+ if (man->last->type != MAN_ROOT)
+ man_valid_post(man);
}
-int
+void
man_macroend(struct man *man)
{
- return(man_unscope(man, man->first, MANDOCERR_SCOPEEXIT));
+ man_unscope(man, man->first);
}
static int
diff --git a/usr/src/cmd/mandoc/man_term.c b/usr/src/cmd/mandoc/man_term.c
index 4bd62443b4..8be7927a65 100644
--- a/usr/src/cmd/mandoc/man_term.c
+++ b/usr/src/cmd/mandoc/man_term.c
@@ -1,7 +1,7 @@
-/* $Id: man_term.c,v 1.139 2013/12/22 23:34:13 schwarze Exp $ */
+/* $Id: man_term.c,v 1.169 2015/03/06 15:48:52 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-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
@@ -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.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#include <sys/types.h>
#include <assert.h>
#include <ctype.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "out.h"
#include "man.h"
#include "term.h"
@@ -38,16 +38,16 @@
struct mtermp {
int fl;
#define MANT_LITERAL (1 << 0)
- size_t lmargin[MAXMARGINS]; /* margins (incl. visible page) */
+ int lmargin[MAXMARGINS]; /* margins (incl. vis. page) */
int lmargincur; /* index of current margin */
int lmarginsz; /* actual number of nested margins */
size_t offset; /* default offset to visible page */
int pardist; /* vert. space before par., unit: [v] */
};
-#define DECL_ARGS struct termp *p, \
+#define DECL_ARGS struct termp *p, \
struct mtermp *mt, \
- const struct man_node *n, \
+ struct man_node *n, \
const struct man_meta *meta
struct termact {
@@ -57,14 +57,11 @@ struct termact {
#define MAN_NOTEXT (1 << 0) /* Never has text children. */
};
-static int a2width(const struct termp *, const char *);
-static size_t a2height(const struct termp *, const char *);
-
static void print_man_nodelist(DECL_ARGS);
static void print_man_node(DECL_ARGS);
static void print_man_head(struct termp *, const void *);
static void print_man_foot(struct termp *, const void *);
-static void print_bvspace(struct termp *,
+static void print_bvspace(struct termp *,
const struct man_node *, int);
static int pre_B(DECL_ARGS);
@@ -84,6 +81,7 @@ 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);
@@ -104,7 +102,7 @@ static const struct termact termacts[MAN_MAX] = {
{ pre_PP, NULL, 0 }, /* PP */
{ pre_PP, NULL, 0 }, /* P */
{ pre_IP, post_IP, 0 }, /* IP */
- { pre_HP, post_HP, 0 }, /* HP */
+ { pre_HP, post_HP, 0 }, /* HP */
{ NULL, NULL, 0 }, /* SM */
{ pre_B, NULL, 0 }, /* SB */
{ pre_alternate, NULL, 0 }, /* BI */
@@ -116,14 +114,13 @@ static const struct termact termacts[MAN_MAX] = {
{ pre_I, NULL, 0 }, /* I */
{ pre_alternate, NULL, 0 }, /* IR */
{ pre_alternate, NULL, 0 }, /* RI */
- { pre_ign, NULL, MAN_NOTEXT }, /* na */
{ 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_ign, NULL, 0 }, /* UC */
+ { pre_ign, NULL, MAN_NOTEXT }, /* UC */
{ pre_PD, NULL, MAN_NOTEXT }, /* PD */
{ pre_ign, NULL, 0 }, /* AT */
{ pre_in, NULL, MAN_NOTEXT }, /* in */
@@ -133,70 +130,55 @@ static const struct termact termacts[MAN_MAX] = {
{ pre_literal, NULL, 0 }, /* EE */
{ pre_UR, post_UR, 0 }, /* UR */
{ NULL, NULL, 0 }, /* UE */
+ { pre_ll, NULL, MAN_NOTEXT }, /* ll */
};
-
void
terminal_man(void *arg, const struct man *man)
{
struct termp *p;
- const struct man_node *n;
const struct man_meta *meta;
+ struct man_node *n;
struct mtermp mt;
p = (struct termp *)arg;
- if (0 == p->defindent)
- p->defindent = 7;
-
p->overstep = 0;
- p->maxrmargin = p->defrmargin;
+ p->rmargin = p->maxrmargin = p->defrmargin;
p->tabwidth = term_len(p, 5);
- if (NULL == p->symtab)
- p->symtab = mchars_alloc();
-
- n = man_node(man);
+ n = man_node(man)->child;
meta = man_meta(man);
- term_begin(p, print_man_head, print_man_foot, meta);
- p->flags |= TERMP_NOSPACE;
-
memset(&mt, 0, sizeof(struct mtermp));
mt.lmargin[mt.lmargincur] = term_len(p, p->defindent);
mt.offset = term_len(p, p->defindent);
mt.pardist = 1;
- if (n->child)
- print_man_nodelist(p, &mt, n->child, meta);
-
- term_end(p);
-}
-
-
-static size_t
-a2height(const struct termp *p, const char *cp)
-{
- struct roffsu su;
-
- if ( ! a2roffsu(cp, &su, SCALE_VS))
- SCALE_VS_INIT(&su, atoi(cp));
-
- return(term_vspan(p, &su));
-}
-
-
-static int
-a2width(const struct termp *p, const char *cp)
-{
- struct roffsu su;
-
- if ( ! a2roffsu(cp, &su, SCALE_BU))
- return(-1);
-
- return((int)term_hspan(p, &su));
+ if (p->synopsisonly) {
+ while (n != NULL) {
+ if (n->tok == MAN_SH &&
+ n->child->child->type == MAN_TEXT &&
+ !strcmp(n->child->child->string, "SYNOPSIS")) {
+ if (n->child->next->child != NULL)
+ print_man_nodelist(p, &mt,
+ n->child->next->child, meta);
+ term_newln(p);
+ break;
+ }
+ n = n->next;
+ }
+ } else {
+ if (p->defindent == 0)
+ p->defindent = 7;
+ term_begin(p, print_man_head, print_man_foot, meta);
+ p->flags |= TERMP_NOSPACE;
+ if (n != NULL)
+ print_man_nodelist(p, &mt, n, meta);
+ term_end(p);
+ }
}
/*
@@ -226,7 +208,7 @@ print_bvspace(struct termp *p, const struct man_node *n, int pardist)
term_vspace(p);
}
-/* ARGSUSED */
+
static int
pre_ign(DECL_ARGS)
{
@@ -234,8 +216,14 @@ pre_ign(DECL_ARGS)
return(0);
}
+static int
+pre_ll(DECL_ARGS)
+{
+
+ term_setwidth(p, n->nchild ? n->child->string : NULL);
+ return(0);
+}
-/* ARGSUSED */
static int
pre_I(DECL_ARGS)
{
@@ -244,8 +232,6 @@ pre_I(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
pre_literal(DECL_ARGS)
{
@@ -266,58 +252,58 @@ pre_literal(DECL_ARGS)
p->offset = p->rmargin;
p->rmargin = p->maxrmargin;
p->trailspace = 0;
- p->flags &= ~TERMP_NOBREAK;
+ p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
p->flags |= TERMP_NOSPACE;
}
return(0);
}
-/* ARGSUSED */
static int
pre_PD(DECL_ARGS)
{
+ struct roffsu su;
n = n->child;
- if (0 == n) {
+ if (n == NULL) {
mt->pardist = 1;
return(0);
}
assert(MAN_TEXT == n->type);
- mt->pardist = atoi(n->string);
+ if (a2roffsu(n->string, &su, SCALE_VS))
+ mt->pardist = term_vspan(p, &su);
return(0);
}
-/* ARGSUSED */
static int
pre_alternate(DECL_ARGS)
{
enum termfont font[2];
- const struct man_node *nn;
+ struct man_node *nn;
int savelit, i;
switch (n->tok) {
- case (MAN_RB):
+ case MAN_RB:
font[0] = TERMFONT_NONE;
font[1] = TERMFONT_BOLD;
break;
- case (MAN_RI):
+ case MAN_RI:
font[0] = TERMFONT_NONE;
font[1] = TERMFONT_UNDER;
break;
- case (MAN_BR):
+ case MAN_BR:
font[0] = TERMFONT_BOLD;
font[1] = TERMFONT_NONE;
break;
- case (MAN_BI):
+ case MAN_BI:
font[0] = TERMFONT_BOLD;
font[1] = TERMFONT_UNDER;
break;
- case (MAN_IR):
+ case MAN_IR:
font[0] = TERMFONT_UNDER;
font[1] = TERMFONT_NONE;
break;
- case (MAN_IB):
+ case MAN_IB:
font[0] = TERMFONT_UNDER;
font[1] = TERMFONT_BOLD;
break;
@@ -340,7 +326,6 @@ pre_alternate(DECL_ARGS)
return(0);
}
-/* ARGSUSED */
static int
pre_B(DECL_ARGS)
{
@@ -349,7 +334,6 @@ pre_B(DECL_ARGS)
return(1);
}
-/* ARGSUSED */
static int
pre_OP(DECL_ARGS)
{
@@ -372,7 +356,6 @@ pre_OP(DECL_ARGS)
return(0);
}
-/* ARGSUSED */
static int
pre_ft(DECL_ARGS)
{
@@ -385,26 +368,26 @@ pre_ft(DECL_ARGS)
cp = n->child->string;
switch (*cp) {
- case ('4'):
+ case '4':
/* FALLTHROUGH */
- case ('3'):
+ case '3':
/* FALLTHROUGH */
- case ('B'):
+ case 'B':
term_fontrepl(p, TERMFONT_BOLD);
break;
- case ('2'):
+ case '2':
/* FALLTHROUGH */
- case ('I'):
+ case 'I':
term_fontrepl(p, TERMFONT_UNDER);
break;
- case ('P'):
+ case 'P':
term_fontlast(p);
break;
- case ('1'):
+ case '1':
/* FALLTHROUGH */
- case ('C'):
+ case 'C':
/* FALLTHROUGH */
- case ('R'):
+ case 'R':
term_fontrepl(p, TERMFONT_NONE);
break;
default:
@@ -413,13 +396,13 @@ pre_ft(DECL_ARGS)
return(0);
}
-/* ARGSUSED */
static int
pre_in(DECL_ARGS)
{
- int len, less;
- size_t v;
+ struct roffsu su;
const char *cp;
+ size_t v;
+ int less;
term_newln(p);
@@ -438,46 +421,40 @@ pre_in(DECL_ARGS)
else
cp--;
- if ((len = a2width(p, ++cp)) < 0)
+ if ( ! a2roffsu(++cp, &su, SCALE_EN))
return(0);
- v = (size_t)len;
+ v = term_hspan(p, &su);
if (less < 0)
p->offset -= p->offset > v ? v : p->offset;
else if (less > 0)
p->offset += v;
- else
+ else
p->offset = v;
-
- /* Don't let this creep beyond the right margin. */
-
- if (p->offset > p->rmargin)
- p->offset = p->rmargin;
+ if (p->offset > SHRT_MAX)
+ p->offset = term_len(p, p->defindent);
return(0);
}
-
-/* ARGSUSED */
static int
pre_sp(DECL_ARGS)
{
- char *s;
- size_t i, len;
- int neg;
+ struct roffsu su;
+ int i, len;
if ((NULL == n->prev && n->parent)) {
switch (n->parent->tok) {
- case (MAN_SH):
+ case MAN_SH:
/* FALLTHROUGH */
- case (MAN_SS):
+ case MAN_SS:
/* FALLTHROUGH */
- case (MAN_PP):
+ case MAN_PP:
/* FALLTHROUGH */
- case (MAN_LP):
+ case MAN_LP:
/* FALLTHROUGH */
- case (MAN_P):
+ case MAN_P:
/* FALLTHROUGH */
return(0);
default:
@@ -485,29 +462,20 @@ pre_sp(DECL_ARGS)
}
}
- neg = 0;
- switch (n->tok) {
- case (MAN_br):
+ if (n->tok == MAN_br)
len = 0;
- break;
- default:
- if (NULL == n->child) {
- len = 1;
- break;
- }
- s = n->child->string;
- if ('-' == *s) {
- neg = 1;
- s++;
- }
- len = a2height(p, s);
- break;
+ 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 (0 == len)
+ if (len == 0)
term_newln(p);
- else if (neg)
- p->skipvsp += len;
+ else if (len < 0)
+ p->skipvsp -= len;
else
for (i = 0; i < len; i++)
term_vspace(p);
@@ -515,62 +483,54 @@ pre_sp(DECL_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
pre_HP(DECL_ARGS)
{
- size_t len, one;
- int ival;
+ struct roffsu su;
const struct man_node *nn;
+ int len;
switch (n->type) {
- case (MAN_BLOCK):
+ case MAN_BLOCK:
print_bvspace(p, n, mt->pardist);
return(1);
- case (MAN_BODY):
+ case MAN_BODY:
break;
default:
return(0);
}
if ( ! (MANT_LITERAL & mt->fl)) {
- p->flags |= TERMP_NOBREAK;
+ p->flags |= TERMP_NOBREAK | TERMP_BRIND;
p->trailspace = 2;
}
- len = mt->lmargin[mt->lmargincur];
- ival = -1;
-
/* Calculate offset. */
- if (NULL != (nn = n->parent->head->child))
- if ((ival = a2width(p, nn->string)) >= 0)
- len = (size_t)ival;
-
- one = term_len(p, 1);
- if (len < one)
- len = one;
+ if ((nn = n->parent->head->child) != NULL &&
+ a2roffsu(nn->string, &su, SCALE_EN)) {
+ len = term_hspan(p, &su);
+ if (len < 0 && (size_t)(-len) > mt->offset)
+ len = -mt->offset;
+ else if (len > SHRT_MAX)
+ len = term_len(p, p->defindent);
+ mt->lmargin[mt->lmargincur] = len;
+ } else
+ len = mt->lmargin[mt->lmargincur];
p->offset = mt->offset;
p->rmargin = mt->offset + len;
-
- if (ival >= 0)
- mt->lmargin[mt->lmargincur] = (size_t)ival;
-
return(1);
}
-
-/* ARGSUSED */
static void
post_HP(DECL_ARGS)
{
switch (n->type) {
- case (MAN_BODY):
+ case MAN_BODY:
term_newln(p);
- p->flags &= ~TERMP_NOBREAK;
+ p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND);
p->trailspace = 0;
p->offset = mt->offset;
p->rmargin = p->maxrmargin;
@@ -580,14 +540,12 @@ post_HP(DECL_ARGS)
}
}
-
-/* ARGSUSED */
static int
pre_PP(DECL_ARGS)
{
switch (n->type) {
- case (MAN_BLOCK):
+ case MAN_BLOCK:
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
print_bvspace(p, n, mt->pardist);
break;
@@ -599,52 +557,45 @@ pre_PP(DECL_ARGS)
return(MAN_HEAD != n->type);
}
-
-/* ARGSUSED */
static int
pre_IP(DECL_ARGS)
{
+ struct roffsu su;
const struct man_node *nn;
- size_t len;
- int savelit, ival;
+ int len, savelit;
switch (n->type) {
- case (MAN_BODY):
+ case MAN_BODY:
p->flags |= TERMP_NOSPACE;
break;
- case (MAN_HEAD):
+ case MAN_HEAD:
p->flags |= TERMP_NOBREAK;
p->trailspace = 1;
break;
- case (MAN_BLOCK):
+ case MAN_BLOCK:
print_bvspace(p, n, mt->pardist);
/* FALLTHROUGH */
default:
return(1);
}
- len = mt->lmargin[mt->lmargincur];
- ival = -1;
-
/* Calculate the offset from the optional second argument. */
- if (NULL != (nn = n->parent->head->child))
- if (NULL != (nn = nn->next))
- if ((ival = a2width(p, nn->string)) >= 0)
- len = (size_t)ival;
+ if ((nn = n->parent->head->child) != NULL &&
+ (nn = nn->next) != NULL &&
+ a2roffsu(nn->string, &su, SCALE_EN)) {
+ len = term_hspan(p, &su);
+ if (len < 0 && (size_t)(-len) > mt->offset)
+ len = -mt->offset;
+ else if (len > SHRT_MAX)
+ len = term_len(p, p->defindent);
+ mt->lmargin[mt->lmargincur] = len;
+ } else
+ len = mt->lmargin[mt->lmargincur];
switch (n->type) {
- case (MAN_HEAD):
- /* Handle zero-width lengths. */
- if (0 == len)
- len = term_len(p, 1);
-
+ case MAN_HEAD:
p->offset = mt->offset;
p->rmargin = mt->offset + len;
- if (ival < 0)
- break;
-
- /* Set the saved left-margin. */
- mt->lmargin[mt->lmargincur] = (size_t)ival;
savelit = MANT_LITERAL & mt->fl;
mt->fl &= ~MANT_LITERAL;
@@ -656,7 +607,7 @@ pre_IP(DECL_ARGS)
mt->fl |= MANT_LITERAL;
return(0);
- case (MAN_BODY):
+ case MAN_BODY:
p->offset = mt->offset + len;
p->rmargin = p->maxrmargin;
break;
@@ -667,20 +618,18 @@ pre_IP(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
post_IP(DECL_ARGS)
{
switch (n->type) {
- case (MAN_HEAD):
+ case MAN_HEAD:
term_flushln(p);
p->flags &= ~TERMP_NOBREAK;
p->trailspace = 0;
p->rmargin = p->maxrmargin;
break;
- case (MAN_BODY):
+ case MAN_BODY:
term_newln(p);
p->offset = mt->offset;
break;
@@ -689,46 +638,44 @@ post_IP(DECL_ARGS)
}
}
-
-/* ARGSUSED */
static int
pre_TP(DECL_ARGS)
{
- const struct man_node *nn;
- size_t len;
- int savelit, ival;
+ struct roffsu su;
+ struct man_node *nn;
+ int len, savelit;
switch (n->type) {
- case (MAN_HEAD):
+ case MAN_HEAD:
p->flags |= TERMP_NOBREAK;
p->trailspace = 1;
break;
- case (MAN_BODY):
+ case MAN_BODY:
p->flags |= TERMP_NOSPACE;
break;
- case (MAN_BLOCK):
+ case MAN_BLOCK:
print_bvspace(p, n, mt->pardist);
/* FALLTHROUGH */
default:
return(1);
}
- len = (size_t)mt->lmargin[mt->lmargincur];
- ival = -1;
-
/* Calculate offset. */
- if (NULL != (nn = n->parent->head->child))
- if (nn->string && nn->parent->line == nn->line)
- if ((ival = a2width(p, nn->string)) >= 0)
- len = (size_t)ival;
+ if ((nn = n->parent->head->child) != NULL &&
+ nn->string != NULL && ! (MAN_LINE & nn->flags) &&
+ a2roffsu(nn->string, &su, SCALE_EN)) {
+ len = term_hspan(p, &su);
+ if (len < 0 && (size_t)(-len) > mt->offset)
+ len = -mt->offset;
+ else if (len > SHRT_MAX)
+ len = term_len(p, p->defindent);
+ mt->lmargin[mt->lmargincur] = len;
+ } else
+ len = mt->lmargin[mt->lmargincur];
switch (n->type) {
- case (MAN_HEAD):
- /* Handle zero-length properly. */
- if (0 == len)
- len = term_len(p, 1);
-
+ case MAN_HEAD:
p->offset = mt->offset;
p->rmargin = mt->offset + len;
@@ -736,17 +683,19 @@ pre_TP(DECL_ARGS)
mt->fl &= ~MANT_LITERAL;
/* Don't print same-line elements. */
- for (nn = n->child; nn; nn = nn->next)
- if (nn->line > n->line)
- print_man_node(p, mt, nn, meta);
+ nn = n->child;
+ while (NULL != nn && 0 == (MAN_LINE & nn->flags))
+ nn = nn->next;
+
+ while (NULL != nn) {
+ print_man_node(p, mt, nn, meta);
+ nn = nn->next;
+ }
if (savelit)
mt->fl |= MANT_LITERAL;
- if (ival >= 0)
- mt->lmargin[mt->lmargincur] = (size_t)ival;
-
return(0);
- case (MAN_BODY):
+ case MAN_BODY:
p->offset = mt->offset + len;
p->rmargin = p->maxrmargin;
p->trailspace = 0;
@@ -759,17 +708,15 @@ pre_TP(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
post_TP(DECL_ARGS)
{
switch (n->type) {
- case (MAN_HEAD):
+ case MAN_HEAD:
term_flushln(p);
break;
- case (MAN_BODY):
+ case MAN_BODY:
term_newln(p);
p->offset = mt->offset;
break;
@@ -778,32 +725,36 @@ post_TP(DECL_ARGS)
}
}
-
-/* ARGSUSED */
static int
pre_SS(DECL_ARGS)
{
int i;
switch (n->type) {
- case (MAN_BLOCK):
+ case MAN_BLOCK:
mt->fl &= ~MANT_LITERAL;
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
mt->offset = term_len(p, p->defindent);
- /* If following a prior empty `SS', no vspace. */
- if (n->prev && MAN_SS == n->prev->tok)
- if (NULL == n->prev->body->child)
- break;
- if (NULL == n->prev)
+
+ /*
+ * No vertical space before the first subsection
+ * and after an empty subsection.
+ */
+
+ do {
+ n = n->prev;
+ } while (n != NULL && termacts[n->tok].flags & MAN_NOTEXT);
+ if (n == NULL || (n->tok == MAN_SS && n->body->child == NULL))
break;
+
for (i = 0; i < mt->pardist; i++)
term_vspace(p);
break;
- case (MAN_HEAD):
+ case MAN_HEAD:
term_fontrepl(p, TERMFONT_BOLD);
p->offset = term_len(p, 3);
break;
- case (MAN_BODY):
+ case MAN_BODY:
p->offset = mt->offset;
break;
default:
@@ -813,17 +764,15 @@ pre_SS(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
post_SS(DECL_ARGS)
{
-
+
switch (n->type) {
- case (MAN_HEAD):
+ case MAN_HEAD:
term_newln(p);
break;
- case (MAN_BODY):
+ case MAN_BODY:
term_newln(p);
break;
default:
@@ -831,33 +780,36 @@ post_SS(DECL_ARGS)
}
}
-
-/* ARGSUSED */
static int
pre_SH(DECL_ARGS)
{
int i;
switch (n->type) {
- case (MAN_BLOCK):
+ case MAN_BLOCK:
mt->fl &= ~MANT_LITERAL;
mt->lmargin[mt->lmargincur] = term_len(p, p->defindent);
mt->offset = term_len(p, p->defindent);
- /* If following a prior empty `SH', no vspace. */
- if (n->prev && MAN_SH == n->prev->tok)
- if (NULL == n->prev->body->child)
- break;
- /* If the first macro, no vspae. */
- if (NULL == n->prev)
+
+ /*
+ * No vertical space before the first section
+ * and after an empty section.
+ */
+
+ do {
+ n = n->prev;
+ } while (n != NULL && termacts[n->tok].flags & MAN_NOTEXT);
+ if (n == NULL || (n->tok == MAN_SH && n->body->child == NULL))
break;
+
for (i = 0; i < mt->pardist; i++)
term_vspace(p);
break;
- case (MAN_HEAD):
+ case MAN_HEAD:
term_fontrepl(p, TERMFONT_BOLD);
p->offset = 0;
break;
- case (MAN_BODY):
+ case MAN_BODY:
p->offset = mt->offset;
break;
default:
@@ -867,17 +819,15 @@ pre_SH(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
post_SH(DECL_ARGS)
{
-
+
switch (n->type) {
- case (MAN_HEAD):
+ case MAN_HEAD:
term_newln(p);
break;
- case (MAN_BODY):
+ case MAN_BODY:
term_newln(p);
break;
default:
@@ -885,32 +835,33 @@ post_SH(DECL_ARGS)
}
}
-/* ARGSUSED */
static int
pre_RS(DECL_ARGS)
{
- int ival;
- size_t sz;
+ struct roffsu su;
switch (n->type) {
- case (MAN_BLOCK):
+ case MAN_BLOCK:
term_newln(p);
return(1);
- case (MAN_HEAD):
+ case MAN_HEAD:
return(0);
default:
break;
}
- sz = term_len(p, p->defindent);
-
- if (NULL != (n = n->parent->head->child))
- if ((ival = a2width(p, n->string)) >= 0)
- sz = (size_t)ival;
+ n = n->parent->head;
+ n->aux = SHRT_MAX + 1;
+ if (n->child != NULL && a2roffsu(n->child->string, &su, SCALE_EN))
+ n->aux = term_hspan(p, &su);
+ if (n->aux < 0 && (size_t)(-n->aux) > mt->offset)
+ n->aux = -mt->offset;
+ else if (n->aux > SHRT_MAX)
+ n->aux = term_len(p, p->defindent);
- mt->offset += sz;
+ mt->offset += n->aux;
+ p->offset = mt->offset;
p->rmargin = p->maxrmargin;
- p->offset = mt->offset < p->rmargin ? mt->offset : p->rmargin;
if (++mt->lmarginsz < MAXMARGINS)
mt->lmargincur = mt->lmarginsz;
@@ -919,37 +870,27 @@ pre_RS(DECL_ARGS)
return(1);
}
-/* ARGSUSED */
static void
post_RS(DECL_ARGS)
{
- int ival;
- size_t sz;
switch (n->type) {
- case (MAN_BLOCK):
+ case MAN_BLOCK:
return;
- case (MAN_HEAD):
+ case MAN_HEAD:
return;
default:
term_newln(p);
break;
}
- sz = term_len(p, p->defindent);
-
- if (NULL != (n = n->parent->head->child))
- if ((ival = a2width(p, n->string)) >= 0)
- sz = (size_t)ival;
-
- mt->offset = mt->offset < sz ? 0 : mt->offset - sz;
+ mt->offset -= n->parent->head->aux;
p->offset = mt->offset;
if (--mt->lmarginsz < MAXMARGINS)
mt->lmargincur = mt->lmarginsz;
}
-/* ARGSUSED */
static int
pre_UR(DECL_ARGS)
{
@@ -957,7 +898,6 @@ pre_UR(DECL_ARGS)
return (MAN_HEAD != n->type);
}
-/* ARGSUSED */
static void
post_UR(DECL_ARGS)
{
@@ -982,7 +922,7 @@ print_man_node(DECL_ARGS)
int c;
switch (n->type) {
- case(MAN_TEXT):
+ case MAN_TEXT:
/*
* If we have a blank line, output a vertical space.
* If we have a space as the first character, break
@@ -997,16 +937,16 @@ print_man_node(DECL_ARGS)
term_word(p, n->string);
goto out;
- case (MAN_EQN):
+ case MAN_EQN:
+ if ( ! (n->flags & MAN_LINE))
+ p->flags |= TERMP_NOSPACE;
term_eqn(p, n->eqn);
+ if (n->next != NULL && ! (n->next->flags & MAN_LINE))
+ p->flags |= TERMP_NOSPACE;
return;
- case (MAN_TBL):
- /*
- * Tables are preceded by a newline. Then process a
- * table line, which will cause line termination,
- */
- if (TBL_SPAN_FIRST & n->span->flags)
- term_newln(p);
+ case MAN_TBL:
+ if (p->tbl.cols == NULL)
+ term_vspace(p);
term_tbl(p, n->span);
return;
default:
@@ -1036,13 +976,14 @@ out:
* -man doesn't have nested macros, we don't need to be
* more specific than this.
*/
- if (MANT_LITERAL & mt->fl && ! (TERMP_NOBREAK & p->flags) &&
- (NULL == n->next || n->next->line > n->line)) {
+ if (mt->fl & MANT_LITERAL &&
+ ! (p->flags & (TERMP_NOBREAK | TERMP_NONEWLINE)) &&
+ (n->next == NULL || n->next->flags & MAN_LINE)) {
rm = p->rmargin;
rmax = p->maxrmargin;
p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
p->flags |= TERMP_NOSPACE;
- if (NULL != n->string && '\0' != *n->string)
+ if (n->string != NULL && *n->string != '\0')
term_flushln(p);
else
term_newln(p);
@@ -1062,19 +1003,18 @@ static void
print_man_nodelist(DECL_ARGS)
{
- print_man_node(p, mt, n, meta);
- if ( ! n->next)
- return;
- print_man_nodelist(p, mt, n->next, meta);
+ while (n != NULL) {
+ print_man_node(p, mt, n, meta);
+ n = n->next;
+ }
}
-
static void
print_man_foot(struct termp *p, const void *arg)
{
- char title[BUFSIZ];
- size_t datelen;
- const struct man_meta *meta;
+ const struct man_meta *meta;
+ char *title;
+ size_t datelen, titlen;
meta = (const struct man_meta *)arg;
assert(meta->title);
@@ -1083,7 +1023,8 @@ print_man_foot(struct termp *p, const void *arg)
term_fontrepl(p, TERMFONT_NONE);
- term_vspace(p);
+ if (meta->hasbody)
+ term_vspace(p);
/*
* Temporary, undocumented option to imitate mdoc(7) output.
@@ -1092,13 +1033,16 @@ print_man_foot(struct termp *p, const void *arg)
*/
if ( ! p->mdocstyle) {
- term_vspace(p);
- term_vspace(p);
- snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec);
+ if (meta->hasbody) {
+ term_vspace(p);
+ term_vspace(p);
+ }
+ mandoc_asprintf(&title, "%s(%s)",
+ meta->title, meta->msec);
} else if (meta->source) {
- strlcpy(title, meta->source, BUFSIZ);
+ title = mandoc_strdup(meta->source);
} else {
- title[0] = '\0';
+ title = mandoc_strdup("");
}
datelen = term_strlen(p, meta->date);
@@ -1107,7 +1051,8 @@ print_man_foot(struct termp *p, const void *arg)
p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
p->trailspace = 1;
p->offset = 0;
- p->rmargin = (p->maxrmargin - datelen + term_len(p, 1)) / 2;
+ p->rmargin = p->maxrmargin > datelen ?
+ (p->maxrmargin + term_len(p, 1) - datelen) / 2 : 0;
if (meta->source)
term_word(p, meta->source);
@@ -1115,11 +1060,10 @@ print_man_foot(struct termp *p, const void *arg)
/* At the bottom in the middle: manual date. */
- p->flags |= TERMP_NOSPACE;
p->offset = p->rmargin;
- p->rmargin = p->maxrmargin - term_strlen(p, title);
- if (p->offset + datelen >= p->rmargin)
- p->rmargin = p->offset + datelen;
+ titlen = term_strlen(p, title);
+ p->rmargin = p->maxrmargin > titlen ? p->maxrmargin - titlen : 0;
+ p->flags |= TERMP_NOSPACE;
term_word(p, meta->date);
term_flushln(p);
@@ -1134,38 +1078,35 @@ print_man_foot(struct termp *p, const void *arg)
term_word(p, title);
term_flushln(p);
+ free(title);
}
-
static void
print_man_head(struct termp *p, const void *arg)
{
- char buf[BUFSIZ], title[BUFSIZ];
- size_t buflen, titlen;
- const struct man_meta *meta;
+ const struct man_meta *meta;
+ const char *volume;
+ char *title;
+ size_t vollen, titlen;
meta = (const struct man_meta *)arg;
assert(meta->title);
assert(meta->msec);
- if (meta->vol)
- strlcpy(buf, meta->vol, BUFSIZ);
- else
- buf[0] = '\0';
- buflen = term_strlen(p, buf);
+ volume = NULL == meta->vol ? "" : meta->vol;
+ vollen = term_strlen(p, volume);
/* Top left corner: manual title and section. */
- snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec);
+ mandoc_asprintf(&title, "%s(%s)", meta->title, meta->msec);
titlen = term_strlen(p, title);
p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
p->trailspace = 1;
p->offset = 0;
- p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
- (p->maxrmargin -
- term_strlen(p, buf) + term_len(p, 1)) / 2 :
- p->maxrmargin - buflen;
+ p->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
+ (p->maxrmargin - vollen + term_len(p, 1)) / 2 :
+ vollen < p->maxrmargin ? p->maxrmargin - vollen : 0;
term_word(p, title);
term_flushln(p);
@@ -1174,10 +1115,10 @@ print_man_head(struct termp *p, const void *arg)
p->flags |= TERMP_NOSPACE;
p->offset = p->rmargin;
- p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
+ p->rmargin = p->offset + vollen + titlen < p->maxrmargin ?
p->maxrmargin - titlen : p->maxrmargin;
- term_word(p, buf);
+ term_word(p, volume);
term_flushln(p);
/* Top right corner: title and section, again. */
@@ -1196,7 +1137,7 @@ print_man_head(struct termp *p, const void *arg)
p->offset = 0;
p->rmargin = p->maxrmargin;
- /*
+ /*
* Groff prints three blank lines before the content.
* Do the same, except in the temporary, undocumented
* mode imitating mdoc(7) output.
@@ -1207,4 +1148,5 @@ print_man_head(struct termp *p, const void *arg)
term_vspace(p);
term_vspace(p);
}
+ free(title);
}
diff --git a/usr/src/cmd/mandoc/man_validate.c b/usr/src/cmd/mandoc/man_validate.c
index da2e557ebb..93ee9b3f20 100644
--- a/usr/src/cmd/mandoc/man_validate.c
+++ b/usr/src/cmd/mandoc/man_validate.c
@@ -1,7 +1,7 @@
-/* $Id: man_validate.c,v 1.86 2013/10/17 20:54:58 schwarze Exp $ */
+/* $OpenBSD$ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012-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
@@ -15,9 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#include <sys/types.h>
@@ -32,190 +30,128 @@
#include "man.h"
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libman.h"
#include "libmandoc.h"
#define CHKARGS struct man *man, struct man_node *n
-typedef int (*v_check)(CHKARGS);
+typedef void (*v_check)(CHKARGS);
-struct man_valid {
- v_check *pres;
- v_check *posts;
-};
-
-static int check_eq0(CHKARGS);
-static int check_eq2(CHKARGS);
-static int check_le1(CHKARGS);
-static int check_ge2(CHKARGS);
-static int check_le5(CHKARGS);
-static int check_head1(CHKARGS);
-static int check_par(CHKARGS);
-static int check_part(CHKARGS);
-static int check_root(CHKARGS);
+static void check_par(CHKARGS);
+static void check_part(CHKARGS);
+static void check_root(CHKARGS);
static void check_text(CHKARGS);
-static int post_AT(CHKARGS);
-static int post_IP(CHKARGS);
-static int post_vs(CHKARGS);
-static int post_fi(CHKARGS);
-static int post_ft(CHKARGS);
-static int post_nf(CHKARGS);
-static int post_sec(CHKARGS);
-static int post_TH(CHKARGS);
-static int post_UC(CHKARGS);
-static int pre_sec(CHKARGS);
-
-static v_check posts_at[] = { post_AT, NULL };
-static v_check posts_br[] = { post_vs, check_eq0, NULL };
-static v_check posts_eq0[] = { check_eq0, NULL };
-static v_check posts_eq2[] = { check_eq2, NULL };
-static v_check posts_fi[] = { check_eq0, post_fi, NULL };
-static v_check posts_ft[] = { post_ft, NULL };
-static v_check posts_ip[] = { post_IP, NULL };
-static v_check posts_le1[] = { check_le1, NULL };
-static v_check posts_nf[] = { check_eq0, post_nf, NULL };
-static v_check posts_par[] = { check_par, NULL };
-static v_check posts_part[] = { check_part, NULL };
-static v_check posts_sec[] = { post_sec, NULL };
-static v_check posts_sp[] = { post_vs, check_le1, NULL };
-static v_check posts_th[] = { check_ge2, check_le5, post_TH, NULL };
-static v_check posts_uc[] = { post_UC, NULL };
-static v_check posts_ur[] = { check_head1, check_part, NULL };
-static v_check pres_sec[] = { pre_sec, NULL };
-
-static const struct man_valid man_valids[MAN_MAX] = {
- { NULL, posts_br }, /* br */
- { NULL, posts_th }, /* TH */
- { pres_sec, posts_sec }, /* SH */
- { pres_sec, posts_sec }, /* SS */
- { NULL, NULL }, /* TP */
- { NULL, posts_par }, /* LP */
- { NULL, posts_par }, /* PP */
- { NULL, posts_par }, /* P */
- { NULL, posts_ip }, /* IP */
- { NULL, NULL }, /* HP */
- { NULL, NULL }, /* SM */
- { NULL, NULL }, /* SB */
- { NULL, NULL }, /* BI */
- { NULL, NULL }, /* IB */
- { NULL, NULL }, /* BR */
- { NULL, NULL }, /* RB */
- { NULL, NULL }, /* R */
- { NULL, NULL }, /* B */
- { NULL, NULL }, /* I */
- { NULL, NULL }, /* IR */
- { NULL, NULL }, /* RI */
- { NULL, posts_eq0 }, /* na */
- { NULL, posts_sp }, /* sp */
- { NULL, posts_nf }, /* nf */
- { NULL, posts_fi }, /* fi */
- { NULL, NULL }, /* RE */
- { NULL, posts_part }, /* RS */
- { NULL, NULL }, /* DT */
- { NULL, posts_uc }, /* UC */
- { NULL, posts_le1 }, /* PD */
- { NULL, posts_at }, /* AT */
- { NULL, NULL }, /* in */
- { NULL, posts_ft }, /* ft */
- { NULL, posts_eq2 }, /* OP */
- { NULL, posts_nf }, /* EX */
- { NULL, posts_fi }, /* EE */
- { NULL, posts_ur }, /* UR */
- { NULL, NULL }, /* UE */
+static void post_AT(CHKARGS);
+static void post_IP(CHKARGS);
+static void post_vs(CHKARGS);
+static void post_fi(CHKARGS);
+static void post_ft(CHKARGS);
+static void post_nf(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 */
+ post_TH, /* TH */
+ NULL, /* SH */
+ NULL, /* SS */
+ NULL, /* TP */
+ check_par, /* LP */
+ check_par, /* PP */
+ check_par, /* P */
+ post_IP, /* IP */
+ NULL, /* HP */
+ NULL, /* SM */
+ NULL, /* SB */
+ NULL, /* BI */
+ NULL, /* IB */
+ NULL, /* BR */
+ NULL, /* RB */
+ NULL, /* R */
+ NULL, /* B */
+ NULL, /* I */
+ NULL, /* IR */
+ NULL, /* RI */
+ post_vs, /* sp */
+ post_nf, /* nf */
+ post_fi, /* fi */
+ NULL, /* RE */
+ check_part, /* RS */
+ NULL, /* DT */
+ post_UC, /* UC */
+ NULL, /* PD */
+ post_AT, /* AT */
+ NULL, /* in */
+ post_ft, /* ft */
+ post_OP, /* OP */
+ post_nf, /* EX */
+ post_fi, /* EE */
+ post_UR, /* UR */
+ NULL, /* UE */
+ NULL, /* ll */
};
-int
-man_valid_pre(struct man *man, struct man_node *n)
+void
+man_valid_post(struct man *man)
{
+ struct man_node *n;
v_check *cp;
+ n = man->last;
+ if (n->flags & MAN_VALID)
+ return;
+ n->flags |= MAN_VALID;
+
switch (n->type) {
- case (MAN_TEXT):
- /* FALLTHROUGH */
- case (MAN_ROOT):
- /* FALLTHROUGH */
- case (MAN_EQN):
- /* FALLTHROUGH */
- case (MAN_TBL):
- return(1);
- default:
+ case MAN_TEXT:
+ check_text(man, n);
break;
- }
-
- if (NULL == (cp = man_valids[n->tok].pres))
- return(1);
- for ( ; *cp; cp++)
- if ( ! (*cp)(man, n))
- return(0);
- return(1);
-}
-
-
-int
-man_valid_post(struct man *man)
-{
- v_check *cp;
-
- if (MAN_VALID & man->last->flags)
- return(1);
- man->last->flags |= MAN_VALID;
-
- switch (man->last->type) {
- case (MAN_TEXT):
- check_text(man, man->last);
- return(1);
- case (MAN_ROOT):
- return(check_root(man, man->last));
- case (MAN_EQN):
+ case MAN_ROOT:
+ check_root(man, n);
+ break;
+ case MAN_EQN:
/* FALLTHROUGH */
- case (MAN_TBL):
- return(1);
+ case MAN_TBL:
+ break;
default:
+ cp = man_valids + n->tok;
+ if (*cp)
+ (*cp)(man, n);
break;
}
-
- if (NULL == (cp = man_valids[man->last->tok].posts))
- return(1);
- for ( ; *cp; cp++)
- if ( ! (*cp)(man, man->last))
- return(0);
-
- return(1);
}
-
-static int
-check_root(CHKARGS)
+static void
+check_root(CHKARGS)
{
- if (MAN_BLINE & man->flags)
- man_nmsg(man, n, MANDOCERR_SCOPEEXIT);
- else if (MAN_ELINE & man->flags)
- man_nmsg(man, n, MANDOCERR_SCOPEEXIT);
+ assert((man->flags & (MAN_BLINE | MAN_ELINE)) == 0);
- man->flags &= ~MAN_BLINE;
- man->flags &= ~MAN_ELINE;
+ if (NULL == man->first->child)
+ mandoc_msg(MANDOCERR_DOC_EMPTY, man->parse,
+ n->line, n->pos, NULL);
+ else
+ man->meta.hasbody = 1;
- if (NULL == man->first->child) {
- man_nmsg(man, n, MANDOCERR_NODOCBODY);
- return(0);
- } else if (NULL == man->meta.title) {
- man_nmsg(man, n, MANDOCERR_NOTITLE);
+ if (NULL == man->meta.title) {
+ mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse,
+ n->line, n->pos, NULL);
/*
* If a title hasn't been set, do so now (by
* implication, date and section also aren't set).
*/
- man->meta.title = mandoc_strdup("unknown");
- man->meta.msec = mandoc_strdup("1");
- man->meta.date = mandoc_normdate
- (man->parse, NULL, n->line, n->pos);
+ man->meta.title = mandoc_strdup("");
+ man->meta.msec = mandoc_strdup("");
+ man->meta.date = man->quick ? mandoc_strdup("") :
+ mandoc_normdate(man->parse, NULL, n->line, n->pos);
}
-
- return(1);
}
static void
@@ -228,71 +164,67 @@ check_text(CHKARGS)
cp = n->string;
for (p = cp; NULL != (p = strchr(p, '\t')); p++)
- man_pmsg(man, n->line, (int)(p - cp), MANDOCERR_BADTAB);
+ mandoc_msg(MANDOCERR_FI_TAB, man->parse,
+ n->line, n->pos + (p - cp), NULL);
}
-#define INEQ_DEFINE(x, ineq, name) \
-static int \
-check_##name(CHKARGS) \
-{ \
- if (n->nchild ineq (x)) \
- return(1); \
- mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line, n->pos, \
- "line arguments %s %d (have %d)", \
- #ineq, (x), n->nchild); \
- return(1); \
-}
+static void
+post_OP(CHKARGS)
+{
-INEQ_DEFINE(0, ==, eq0)
-INEQ_DEFINE(2, ==, eq2)
-INEQ_DEFINE(1, <=, le1)
-INEQ_DEFINE(2, >=, ge2)
-INEQ_DEFINE(5, <=, le5)
+ if (n->nchild == 0)
+ mandoc_msg(MANDOCERR_OP_EMPTY, man->parse,
+ n->line, n->pos, "OP");
+ else if (n->nchild > 2) {
+ n = n->child->next->next;
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
+ n->line, n->pos, "OP ... %s", n->string);
+ }
+}
-static int
-check_head1(CHKARGS)
+static void
+post_UR(CHKARGS)
{
- if (MAN_HEAD == n->type && 1 != n->nchild)
- mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line,
- n->pos, "line arguments eq 1 (have %d)", n->nchild);
-
- return(1);
+ if (n->type == MAN_HEAD && n->child == NULL)
+ mandoc_vmsg(MANDOCERR_UR_NOHEAD, man->parse,
+ n->line, n->pos, "UR");
+ check_part(man, n);
}
-static int
+static void
post_ft(CHKARGS)
{
char *cp;
int ok;
if (0 == n->nchild)
- return(1);
+ return;
ok = 0;
cp = n->child->string;
switch (*cp) {
- case ('1'):
+ case '1':
/* FALLTHROUGH */
- case ('2'):
+ case '2':
/* FALLTHROUGH */
- case ('3'):
+ case '3':
/* FALLTHROUGH */
- case ('4'):
+ case '4':
/* FALLTHROUGH */
- case ('I'):
+ case 'I':
/* FALLTHROUGH */
- case ('P'):
+ case 'P':
/* FALLTHROUGH */
- case ('R'):
+ case 'R':
if ('\0' == cp[1])
ok = 1;
break;
- case ('B'):
+ case 'B':
if ('\0' == cp[1] || ('I' == cp[1] && '\0' == cp[2]))
ok = 1;
break;
- case ('C'):
+ case 'C':
if ('W' == cp[1] && '\0' == cp[2])
ok = 1;
break;
@@ -301,101 +233,74 @@ post_ft(CHKARGS)
}
if (0 == ok) {
- mandoc_vmsg
- (MANDOCERR_BADFONT, man->parse,
- n->line, n->pos, "%s", cp);
+ mandoc_vmsg(MANDOCERR_FT_BAD, man->parse,
+ n->line, n->pos, "ft %s", cp);
*cp = '\0';
}
-
- if (1 < n->nchild)
- mandoc_vmsg
- (MANDOCERR_ARGCOUNT, man->parse, n->line,
- n->pos, "want one child (have %d)",
- n->nchild);
-
- return(1);
-}
-
-static int
-pre_sec(CHKARGS)
-{
-
- if (MAN_BLOCK == n->type)
- man->flags &= ~MAN_LITERAL;
- return(1);
-}
-
-static int
-post_sec(CHKARGS)
-{
-
- if ( ! (MAN_HEAD == n->type && 0 == n->nchild))
- return(1);
-
- man_nmsg(man, n, MANDOCERR_SYNTARGCOUNT);
- return(0);
}
-static int
+static void
check_part(CHKARGS)
{
- if (MAN_BODY == n->type && 0 == n->nchild)
- mandoc_msg(MANDOCERR_ARGCWARN, man->parse, n->line,
- n->pos, "want children (have none)");
-
- return(1);
+ if (n->type == MAN_BODY && n->child == NULL)
+ mandoc_msg(MANDOCERR_BLK_EMPTY, man->parse,
+ n->line, n->pos, man_macronames[n->tok]);
}
-
-static int
+static void
check_par(CHKARGS)
{
switch (n->type) {
- case (MAN_BLOCK):
+ case MAN_BLOCK:
if (0 == n->body->nchild)
man_node_delete(man, n);
break;
- case (MAN_BODY):
+ case MAN_BODY:
if (0 == n->nchild)
- man_nmsg(man, n, MANDOCERR_IGNPAR);
+ mandoc_vmsg(MANDOCERR_PAR_SKIP,
+ man->parse, n->line, n->pos,
+ "%s empty", man_macronames[n->tok]);
break;
- case (MAN_HEAD):
+ case MAN_HEAD:
if (n->nchild)
- man_nmsg(man, n, MANDOCERR_ARGSLOST);
+ mandoc_vmsg(MANDOCERR_ARG_SKIP,
+ man->parse, n->line, n->pos,
+ "%s %s%s", man_macronames[n->tok],
+ n->child->string,
+ n->nchild > 1 ? " ..." : "");
break;
default:
break;
}
-
- return(1);
}
-static int
+static void
post_IP(CHKARGS)
{
switch (n->type) {
- case (MAN_BLOCK):
+ case MAN_BLOCK:
if (0 == n->head->nchild && 0 == n->body->nchild)
man_node_delete(man, n);
break;
- case (MAN_BODY):
+ case MAN_BODY:
if (0 == n->parent->head->nchild && 0 == n->nchild)
- man_nmsg(man, n, MANDOCERR_IGNPAR);
+ mandoc_vmsg(MANDOCERR_PAR_SKIP,
+ man->parse, n->line, n->pos,
+ "%s empty", man_macronames[n->tok]);
break;
default:
break;
}
- return(1);
}
-static int
+static void
post_TH(CHKARGS)
{
+ struct man_node *nb;
const char *p;
- int line, pos;
free(man->meta.title);
free(man->meta.vol);
@@ -403,10 +308,10 @@ post_TH(CHKARGS)
free(man->meta.msec);
free(man->meta.date);
- line = n->line;
- pos = n->pos;
man->meta.title = man->meta.vol = man->meta.date =
- man->meta.msec = man->meta.source = NULL;
+ man->meta.msec = man->meta.source = NULL;
+
+ nb = n;
/* ->TITLE<- MSEC DATE SOURCE VOL */
@@ -414,15 +319,21 @@ post_TH(CHKARGS)
if (n && n->string) {
for (p = n->string; '\0' != *p; p++) {
/* Only warn about this once... */
- if (isalpha((unsigned char)*p) &&
- ! isupper((unsigned char)*p)) {
- man_nmsg(man, n, MANDOCERR_UPPERCASE);
+ if (isalpha((unsigned char)*p) &&
+ ! isupper((unsigned char)*p)) {
+ mandoc_vmsg(MANDOCERR_TITLE_CASE,
+ man->parse, n->line,
+ n->pos + (p - n->string),
+ "TH %s", n->string);
break;
}
}
man->meta.title = mandoc_strdup(n->string);
- } else
+ } else {
man->meta.title = mandoc_strdup("");
+ mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse,
+ nb->line, nb->pos, "TH");
+ }
/* TITLE ->MSEC<- DATE SOURCE VOL */
@@ -430,24 +341,34 @@ post_TH(CHKARGS)
n = n->next;
if (n && n->string)
man->meta.msec = mandoc_strdup(n->string);
- else
+ else {
man->meta.msec = mandoc_strdup("");
+ mandoc_vmsg(MANDOCERR_MSEC_MISSING, man->parse,
+ nb->line, nb->pos, "TH %s", man->meta.title);
+ }
/* TITLE MSEC ->DATE<- SOURCE VOL */
if (n)
n = n->next;
if (n && n->string && '\0' != n->string[0]) {
- pos = n->pos;
- man->meta.date = mandoc_normdate
- (man->parse, n->string, line, pos);
- } else
+ man->meta.date = man->quick ?
+ mandoc_strdup(n->string) :
+ mandoc_normdate(man->parse, n->string,
+ n->line, n->pos);
+ } else {
man->meta.date = mandoc_strdup("");
+ mandoc_msg(MANDOCERR_DATE_MISSING, man->parse,
+ n ? n->line : nb->line,
+ n ? n->pos : nb->pos, "TH");
+ }
/* TITLE MSEC DATE ->SOURCE<- VOL */
if (n && (n = n->next))
man->meta.source = mandoc_strdup(n->string);
+ else if (man->defos != NULL)
+ man->meta.source = mandoc_strdup(man->defos);
/* TITLE MSEC DATE SOURCE ->VOL<- */
/* If missing, use the default VOL name for MSEC. */
@@ -458,37 +379,40 @@ post_TH(CHKARGS)
(NULL != (p = mandoc_a2msec(man->meta.msec))))
man->meta.vol = mandoc_strdup(p);
+ if (n != NULL && (n = n->next) != NULL)
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
+ n->line, n->pos, "TH ... %s", n->string);
+
/*
* Remove the `TH' node after we've processed it for our
* meta-data.
*/
man_node_delete(man, man->last);
- return(1);
}
-static int
+static void
post_nf(CHKARGS)
{
- if (MAN_LITERAL & man->flags)
- man_nmsg(man, n, MANDOCERR_SCOPEREP);
+ if (man->flags & MAN_LITERAL)
+ mandoc_msg(MANDOCERR_NF_SKIP, man->parse,
+ n->line, n->pos, "nf");
man->flags |= MAN_LITERAL;
- return(1);
}
-static int
+static void
post_fi(CHKARGS)
{
if ( ! (MAN_LITERAL & man->flags))
- man_nmsg(man, n, MANDOCERR_WNOSCOPE);
+ mandoc_msg(MANDOCERR_FI_SKIP, man->parse,
+ n->line, n->pos, "fi");
man->flags &= ~MAN_LITERAL;
- return(1);
}
-static int
+static void
post_UC(CHKARGS)
{
static const char * const bsd_versions[] = {
@@ -523,10 +447,9 @@ post_UC(CHKARGS)
free(man->meta.source);
man->meta.source = mandoc_strdup(p);
- return(1);
}
-static int
+static void
post_AT(CHKARGS)
{
static const char * const unix_versions[] = {
@@ -561,24 +484,25 @@ post_AT(CHKARGS)
free(man->meta.source);
man->meta.source = mandoc_strdup(p);
- return(1);
}
-static int
+static void
post_vs(CHKARGS)
{
if (NULL != n->prev)
- return(1);
+ return;
switch (n->parent->tok) {
- case (MAN_SH):
+ case MAN_SH:
/* FALLTHROUGH */
- case (MAN_SS):
- man_nmsg(man, n, MANDOCERR_IGNPAR);
+ case MAN_SS:
+ mandoc_vmsg(MANDOCERR_PAR_SKIP, man->parse, n->line, n->pos,
+ "%s after %s", man_macronames[n->tok],
+ man_macronames[n->parent->tok]);
/* FALLTHROUGH */
- case (MAN_MAX):
- /*
+ case MAN_MAX:
+ /*
* Don't warn about this because it occurs in pod2man
* and would cause considerable (unfixable) warnage.
*/
@@ -587,6 +511,4 @@ post_vs(CHKARGS)
default:
break;
}
-
- return(1);
}
diff --git a/usr/src/cmd/mandoc/mandoc.c b/usr/src/cmd/mandoc/mandoc.c
index da738f20fa..0619420cb1 100644
--- a/usr/src/cmd/mandoc/mandoc.c
+++ b/usr/src/cmd/mandoc/mandoc.c
@@ -1,7 +1,7 @@
-/* $Id: mandoc.c,v 1.74 2013/12/30 18:30:32 schwarze Exp $ */
+/* $Id: mandoc.c,v 1.92 2015/02/20 23:55:10 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2011-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
@@ -15,9 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#include <sys/types.h>
@@ -31,6 +29,7 @@
#include <time.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libmandoc.h"
#define DATESIZE 32
@@ -45,7 +44,7 @@ mandoc_escape(const char **end, const char **start, int *sz)
const char *local_start;
int local_sz;
char term;
- enum mandoc_esc gly;
+ enum mandoc_esc gly;
/*
* When the caller doesn't provide return storage,
@@ -74,80 +73,69 @@ mandoc_escape(const char **end, const char **start, int *sz)
* these, but each eventually returns a substring of the glyph
* name.
*/
- case ('('):
+ case '(':
gly = ESCAPE_SPECIAL;
*sz = 2;
break;
- case ('['):
+ case '[':
gly = ESCAPE_SPECIAL;
- /*
- * Unicode escapes are defined in groff as \[uXXXX] to
- * \[u10FFFF], where the contained value must be a valid
- * Unicode codepoint. Here, however, only check whether
- * it's not a zero-width escape.
- */
- if ('u' == (*start)[0] && ']' != (*start)[1])
- gly = ESCAPE_UNICODE;
term = ']';
break;
- case ('C'):
+ case 'C':
if ('\'' != **start)
return(ESCAPE_ERROR);
*start = ++*end;
- if ('u' == (*start)[0] && '\'' != (*start)[1])
- gly = ESCAPE_UNICODE;
- else
- gly = ESCAPE_SPECIAL;
+ gly = ESCAPE_SPECIAL;
term = '\'';
break;
/*
* Escapes taking no arguments at all.
*/
- case ('d'):
+ case 'd':
/* FALLTHROUGH */
- case ('u'):
+ case 'u':
return(ESCAPE_IGNORE);
/*
* The \z escape is supposed to output the following
- * character without advancing the cursor position.
+ * character without advancing the cursor position.
* Since we are mostly dealing with terminal mode,
* let us just skip the next character.
*/
- case ('z'):
+ case 'z':
return(ESCAPE_SKIPCHAR);
/*
* Handle all triggers matching \X(xy, \Xx, and \X[xxxx], where
* 'X' is the trigger. These have opaque sub-strings.
*/
- case ('F'):
+ case 'F':
/* FALLTHROUGH */
- case ('g'):
+ case 'g':
/* FALLTHROUGH */
- case ('k'):
+ case 'k':
/* FALLTHROUGH */
- case ('M'):
+ case 'M':
/* FALLTHROUGH */
- case ('m'):
+ case 'm':
/* FALLTHROUGH */
- case ('n'):
+ case 'n':
/* FALLTHROUGH */
- case ('V'):
+ case 'V':
/* FALLTHROUGH */
- case ('Y'):
+ case 'Y':
gly = ESCAPE_IGNORE;
/* FALLTHROUGH */
- case ('f'):
+ case 'f':
if (ESCAPE_ERROR == gly)
gly = ESCAPE_FONT;
switch (**start) {
- case ('('):
+ case '(':
*start = ++*end;
*sz = 2;
break;
- case ('['):
+ case '[':
*start = ++*end;
term = ']';
break;
@@ -160,60 +148,62 @@ mandoc_escape(const char **end, const char **start, int *sz)
/*
* These escapes are of the form \X'Y', where 'X' is the trigger
* and 'Y' is any string. These have opaque sub-strings.
+ * The \B and \w escapes are handled in roff.c, roff_res().
*/
- case ('A'):
- /* FALLTHROUGH */
- case ('b'):
- /* FALLTHROUGH */
- case ('B'):
+ case 'A':
/* FALLTHROUGH */
- case ('D'):
+ case 'b':
/* FALLTHROUGH */
- case ('o'):
+ case 'D':
/* FALLTHROUGH */
- case ('R'):
+ case 'R':
/* FALLTHROUGH */
- case ('w'):
+ case 'X':
/* FALLTHROUGH */
- case ('X'):
+ case 'Z':
+ gly = ESCAPE_IGNORE;
/* FALLTHROUGH */
- case ('Z'):
- if ('\'' != **start)
+ case 'o':
+ if (**start == '\0')
return(ESCAPE_ERROR);
- gly = ESCAPE_IGNORE;
+ if (gly == ESCAPE_ERROR)
+ gly = ESCAPE_OVERSTRIKE;
+ term = **start;
*start = ++*end;
- term = '\'';
break;
/*
* These escapes are of the form \X'N', where 'X' is the trigger
* and 'N' resolves to a numerical expression.
*/
- case ('h'):
+ case 'h':
/* FALLTHROUGH */
- case ('H'):
+ case 'H':
/* FALLTHROUGH */
- case ('L'):
+ case 'L':
/* FALLTHROUGH */
- case ('l'):
+ case 'l':
/* FALLTHROUGH */
- case ('S'):
+ case 'S':
/* FALLTHROUGH */
- case ('v'):
+ case 'v':
/* FALLTHROUGH */
- case ('x'):
- if ('\'' != **start)
+ case 'x':
+ if (strchr(" %&()*+-./0123456789:<=>", **start)) {
+ if ('\0' != **start)
+ ++*end;
return(ESCAPE_ERROR);
+ }
gly = ESCAPE_IGNORE;
+ term = **start;
*start = ++*end;
- term = '\'';
break;
/*
* Special handling for the numbered character escape.
* XXX Do any other escapes need similar handling?
*/
- case ('N'):
+ case 'N':
if ('\0' == **start)
return(ESCAPE_ERROR);
(*end)++;
@@ -229,29 +219,37 @@ mandoc_escape(const char **end, const char **start, int *sz)
(*end)++;
return(ESCAPE_NUMBERED);
- /*
+ /*
* Sizes get a special category of their own.
*/
- case ('s'):
+ case 's':
gly = ESCAPE_IGNORE;
/* See +/- counts as a sign. */
if ('+' == **end || '-' == **end || ASCII_HYPH == **end)
- (*end)++;
+ *start = ++*end;
switch (**end) {
- case ('('):
+ case '(':
*start = ++*end;
*sz = 2;
break;
- case ('['):
+ case '[':
*start = ++*end;
term = ']';
break;
- case ('\''):
+ case '\'':
*start = ++*end;
term = '\'';
break;
+ case '3':
+ /* FALLTHROUGH */
+ case '2':
+ /* FALLTHROUGH */
+ case '1':
+ *sz = (*end)[-1] == 's' &&
+ isdigit((unsigned char)(*end)[1]) ? 2 : 1;
+ break;
default:
*sz = 1;
break;
@@ -280,9 +278,9 @@ mandoc_escape(const char **end, const char **start, int *sz)
if ('\0' != term) {
while (**end != term) {
switch (**end) {
- case ('\0'):
+ case '\0':
return(ESCAPE_ERROR);
- case ('\\'):
+ case '\\':
(*end)++;
if (ESCAPE_ERROR ==
mandoc_escape(end, NULL, NULL))
@@ -304,7 +302,7 @@ mandoc_escape(const char **end, const char **start, int *sz)
/* Run post-processors. */
switch (gly) {
- case (ESCAPE_FONT):
+ case ESCAPE_FONT:
if (2 == *sz) {
if ('C' == **start) {
/*
@@ -322,29 +320,44 @@ mandoc_escape(const char **end, const char **start, int *sz)
break;
switch (**start) {
- case ('3'):
+ case '3':
/* FALLTHROUGH */
- case ('B'):
+ case 'B':
gly = ESCAPE_FONTBOLD;
break;
- case ('2'):
+ case '2':
/* FALLTHROUGH */
- case ('I'):
+ case 'I':
gly = ESCAPE_FONTITALIC;
break;
- case ('P'):
+ case 'P':
gly = ESCAPE_FONTPREV;
break;
- case ('1'):
+ case '1':
/* FALLTHROUGH */
- case ('R'):
+ case 'R':
gly = ESCAPE_FONTROMAN;
break;
}
break;
- case (ESCAPE_SPECIAL):
+ case ESCAPE_SPECIAL:
if (1 == *sz && 'c' == **start)
gly = ESCAPE_NOSPACE;
+ /*
+ * Unicode escapes are defined in groff as \[u0000]
+ * to \[u10FFFF], where the contained value must be
+ * a valid Unicode codepoint. Here, however, only
+ * check the length and range.
+ */
+ if (**start != 'u' || *sz < 5 || *sz > 7)
+ break;
+ if (*sz == 7 && ((*start)[1] != '1' || (*start)[2] != '0'))
+ break;
+ if (*sz == 6 && (*start)[1] == '0')
+ break;
+ if ((int)strspn(*start + 1, "0123456789ABCDEFabcdef")
+ + 1 == *sz)
+ gly = ESCAPE_UNICODE;
break;
default:
break;
@@ -353,74 +366,6 @@ mandoc_escape(const char **end, const char **start, int *sz)
return(gly);
}
-void *
-mandoc_calloc(size_t num, size_t size)
-{
- void *ptr;
-
- ptr = calloc(num, size);
- if (NULL == ptr) {
- perror(NULL);
- exit((int)MANDOCLEVEL_SYSERR);
- }
-
- return(ptr);
-}
-
-
-void *
-mandoc_malloc(size_t size)
-{
- void *ptr;
-
- ptr = malloc(size);
- if (NULL == ptr) {
- perror(NULL);
- exit((int)MANDOCLEVEL_SYSERR);
- }
-
- return(ptr);
-}
-
-
-void *
-mandoc_realloc(void *ptr, size_t size)
-{
-
- ptr = realloc(ptr, size);
- if (NULL == ptr) {
- perror(NULL);
- exit((int)MANDOCLEVEL_SYSERR);
- }
-
- return(ptr);
-}
-
-char *
-mandoc_strndup(const char *ptr, size_t sz)
-{
- char *p;
-
- p = mandoc_malloc(sz + 1);
- memcpy(p, ptr, sz);
- p[(int)sz] = '\0';
- return(p);
-}
-
-char *
-mandoc_strdup(const char *ptr)
-{
- char *p;
-
- p = strdup(ptr);
- if (NULL == p) {
- perror(NULL);
- exit((int)MANDOCLEVEL_SYSERR);
- }
-
- return(p);
-}
-
/*
* Parse a quoted or unquoted roff-style request or macro argument.
* Return a pointer to the parsed argument, which is either the original
@@ -442,7 +387,7 @@ mandoc_getarg(struct mparse *parse, char **cpp, int ln, int *pos)
if ('"' == *start) {
quoted = 1;
start++;
- }
+ }
pairs = 0;
white = 0;
@@ -461,14 +406,14 @@ mandoc_getarg(struct mparse *parse, char **cpp, int ln, int *pos)
* backslashes and backslash-t to literal tabs.
*/
switch (cp[1]) {
- case ('t'):
+ case 't':
cp[0] = '\t';
/* FALLTHROUGH */
- case ('\\'):
+ case '\\':
pairs++;
cp++;
break;
- case (' '):
+ case ' ':
/* Skip escaped blanks. */
if (0 == quoted)
cp++;
@@ -497,7 +442,7 @@ mandoc_getarg(struct mparse *parse, char **cpp, int ln, int *pos)
/* Quoted argument without a closing quote. */
if (1 == quoted)
- mandoc_msg(MANDOCERR_BADQUOTE, parse, ln, *pos, NULL);
+ mandoc_msg(MANDOCERR_ARG_QUOTE, parse, ln, *pos, NULL);
/* NUL-terminate this argument and move to the next one. */
if (pairs)
@@ -511,7 +456,7 @@ mandoc_getarg(struct mparse *parse, char **cpp, int ln, int *pos)
*cpp = cp;
if ('\0' == *cp && (white || ' ' == cp[-1]))
- mandoc_msg(MANDOCERR_EOLNSPACE, parse, ln, *pos, NULL);
+ mandoc_msg(MANDOCERR_SPACE_EOL, parse, ln, *pos, NULL);
return(start);
}
@@ -525,7 +470,7 @@ a2time(time_t *t, const char *fmt, const char *p)
memset(&tm, 0, sizeof(struct tm));
pp = NULL;
-#ifdef HAVE_STRPTIME
+#if HAVE_STRPTIME
pp = strptime(p, fmt, &tm);
#endif
if (NULL != pp && '\0' == *pp) {
@@ -545,6 +490,8 @@ time2a(time_t t)
int isz;
tm = localtime(&t);
+ if (tm == NULL)
+ return(NULL);
/*
* Reserve space:
@@ -579,14 +526,14 @@ mandoc_normdate(struct mparse *parse, char *in, int ln, int pos)
if (NULL == in || '\0' == *in ||
0 == strcmp(in, "$" "Mdocdate$")) {
- mandoc_msg(MANDOCERR_NODATE, parse, ln, pos, NULL);
+ mandoc_msg(MANDOCERR_DATE_MISSING, parse, ln, pos, NULL);
time(&t);
}
else if (a2time(&t, "%Y-%m-%d", in))
t = 0;
else if (!a2time(&t, "$" "Mdocdate: %b %d %Y $", in) &&
!a2time(&t, "%b %d, %Y", in)) {
- mandoc_msg(MANDOCERR_BADDATE, parse, ln, pos, NULL);
+ mandoc_msg(MANDOCERR_DATE_BAD, parse, ln, pos, in);
t = 0;
}
out = t ? time2a(t) : NULL;
@@ -594,10 +541,10 @@ mandoc_normdate(struct mparse *parse, char *in, int ln, int pos)
}
int
-mandoc_eos(const char *p, size_t sz, int enclosed)
+mandoc_eos(const char *p, size_t sz)
{
- const char *q;
- int found;
+ const char *q;
+ int enclosed, found;
if (0 == sz)
return(0);
@@ -608,24 +555,24 @@ mandoc_eos(const char *p, size_t sz, int enclosed)
* propagate outward.
*/
- found = 0;
+ enclosed = found = 0;
for (q = p + (int)sz - 1; q >= p; q--) {
switch (*q) {
- case ('\"'):
+ case '\"':
/* FALLTHROUGH */
- case ('\''):
+ case '\'':
/* FALLTHROUGH */
- case (']'):
+ case ']':
/* FALLTHROUGH */
- case (')'):
+ case ')':
if (0 == found)
enclosed = 1;
break;
- case ('.'):
+ case '.':
/* FALLTHROUGH */
- case ('!'):
+ case '!':
/* FALLTHROUGH */
- case ('?'):
+ case '?':
found = 1;
break;
default:
diff --git a/usr/src/cmd/mandoc/mandoc.h b/usr/src/cmd/mandoc/mandoc.h
index 4c6a32f7a6..eb8a1aa6f2 100644
--- a/usr/src/cmd/mandoc/mandoc.h
+++ b/usr/src/cmd/mandoc/mandoc.h
@@ -1,7 +1,7 @@
-/* $Id: mandoc.h,v 1.112 2013/12/30 18:30:32 schwarze Exp $ */
+/* $Id: mandoc.h,v 1.201 2015/02/23 13:31:04 schwarze Exp $ */
/*
- * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2010-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
@@ -15,11 +15,10 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef MANDOC_H
-#define MANDOC_H
#define ASCII_NBRSP 31 /* non-breaking space */
#define ASCII_HYPH 30 /* breakable hyphen */
+#define ASCII_BREAK 29 /* breakable zero-width space */
/*
* Status level. This refers to both internal status (i.e., whilst
@@ -32,7 +31,7 @@ enum mandoclevel {
MANDOCLEVEL_RESERVED,
MANDOCLEVEL_WARNING, /* warnings: syntax, whitespace, etc. */
MANDOCLEVEL_ERROR, /* input has been thrown away */
- MANDOCLEVEL_FATAL, /* input is borked */
+ MANDOCLEVEL_UNSUPP, /* input needs unimplemented features */
MANDOCLEVEL_BADARG, /* bad argument in invocation */
MANDOCLEVEL_SYSERR, /* system error */
MANDOCLEVEL_MAX
@@ -48,127 +47,158 @@ enum mandocerr {
MANDOCERR_WARNING, /* ===== start of warnings ===== */
/* related to the prologue */
- MANDOCERR_NOTITLE, /* no title in document */
- MANDOCERR_UPPERCASE, /* document title should be all caps */
- MANDOCERR_BADMSEC, /* unknown manual section */
- MANDOCERR_BADVOLARCH, /* unknown manual volume or arch */
- MANDOCERR_NODATE, /* date missing, using today's date */
- MANDOCERR_BADDATE, /* cannot parse date, using it verbatim */
- MANDOCERR_PROLOGOOO, /* prologue macros out of order */
- MANDOCERR_PROLOGREP, /* duplicate prologue macro */
- MANDOCERR_BADPROLOG, /* macro not allowed in prologue */
- MANDOCERR_BADBODY, /* macro not allowed in body */
+ MANDOCERR_DT_NOTITLE, /* missing manual title, using UNTITLED: line */
+ MANDOCERR_TH_NOTITLE, /* missing manual title, using "": [macro] */
+ MANDOCERR_TITLE_CASE, /* lower case character in document title */
+ MANDOCERR_MSEC_MISSING, /* missing manual section, using "": macro */
+ MANDOCERR_MSEC_BAD, /* unknown manual section: Dt ... section */
+ MANDOCERR_DATE_MISSING, /* missing date, using today's date */
+ MANDOCERR_DATE_BAD, /* cannot parse date, using it verbatim: date */
+ MANDOCERR_OS_MISSING, /* missing Os macro, using "" */
+ MANDOCERR_PROLOG_REP, /* duplicate prologue macro: macro */
+ MANDOCERR_PROLOG_LATE, /* late prologue macro: macro */
+ MANDOCERR_DT_LATE, /* skipping late title macro: Dt args */
+ MANDOCERR_PROLOG_ORDER, /* prologue macros out of order: macros */
/* related to document structure */
- MANDOCERR_SO, /* .so is fragile, better use ln(1) */
- MANDOCERR_NAMESECFIRST, /* NAME section must come first */
- MANDOCERR_BADNAMESEC, /* bad NAME section contents */
- MANDOCERR_SECOOO, /* sections out of conventional order */
- MANDOCERR_SECREP, /* duplicate section name */
- MANDOCERR_SECMSEC, /* section header suited to sections ... */
+ MANDOCERR_SO, /* .so is fragile, better use ln(1): so path */
+ MANDOCERR_DOC_EMPTY, /* no document body */
+ MANDOCERR_SEC_BEFORE, /* content before first section header: macro */
+ MANDOCERR_NAMESEC_FIRST, /* first section is not NAME: Sh title */
+ MANDOCERR_NAMESEC_NONM, /* NAME section without name */
+ MANDOCERR_NAMESEC_NOND, /* NAME section without description */
+ MANDOCERR_NAMESEC_ND, /* description not at the end of NAME */
+ MANDOCERR_NAMESEC_BAD, /* bad NAME section content: macro */
+ MANDOCERR_ND_EMPTY, /* missing description line, using "" */
+ 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 */
+ MANDOCERR_XR_ORDER, /* unusual Xr order: ... after ... */
+ MANDOCERR_XR_PUNCT, /* unusual Xr punctuation: ... after ... */
+ MANDOCERR_AN_MISSING, /* AUTHORS section without An macro */
/* related to macros and nesting */
- MANDOCERR_MACROOBS, /* skipping obsolete macro */
- MANDOCERR_IGNPAR, /* skipping paragraph macro */
- MANDOCERR_MOVEPAR, /* moving paragraph macro out of list */
- MANDOCERR_IGNNS, /* skipping no-space macro */
- MANDOCERR_SCOPENEST, /* blocks badly nested */
- MANDOCERR_CHILD, /* child violates parent syntax */
- MANDOCERR_NESTEDDISP, /* nested displays are not portable */
- MANDOCERR_SCOPEREP, /* already in literal mode */
- MANDOCERR_LINESCOPE, /* line scope broken */
-
- /* related to missing macro arguments */
- MANDOCERR_MACROEMPTY, /* skipping empty macro */
- MANDOCERR_ARGCWARN, /* argument count wrong */
- MANDOCERR_DISPTYPE, /* missing display type */
- MANDOCERR_LISTFIRST, /* list type must come first */
- MANDOCERR_NOWIDTHARG, /* tag lists require a width argument */
- MANDOCERR_FONTTYPE, /* missing font type */
- MANDOCERR_WNOSCOPE, /* skipping end of block that is not open */
-
- /* related to bad macro arguments */
- MANDOCERR_IGNARGV, /* skipping argument */
- MANDOCERR_ARGVREP, /* duplicate argument */
- MANDOCERR_DISPREP, /* duplicate display type */
- MANDOCERR_LISTREP, /* duplicate list type */
- MANDOCERR_BADATT, /* unknown AT&T UNIX version */
- MANDOCERR_BADBOOL, /* bad Boolean value */
- MANDOCERR_BADFONT, /* unknown font */
- MANDOCERR_BADSTANDARD, /* unknown standard specifier */
- MANDOCERR_BADWIDTH, /* bad width argument */
+ MANDOCERR_MACRO_OBS, /* obsolete macro: macro */
+ MANDOCERR_MACRO_CALL, /* macro neither callable nor escaped: macro */
+ MANDOCERR_PAR_SKIP, /* skipping paragraph macro: macro ... */
+ MANDOCERR_PAR_MOVE, /* moving paragraph macro out of list: macro */
+ MANDOCERR_NS_SKIP, /* skipping no-space macro */
+ MANDOCERR_BLK_NEST, /* blocks badly nested: macro ... */
+ MANDOCERR_BD_NEST, /* nested displays are not portable: macro ... */
+ MANDOCERR_BL_MOVE, /* moving content out of list: macro */
+ MANDOCERR_VT_CHILD, /* .Vt block has child macro: macro */
+ 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 */
+
+ /* related to missing arguments */
+ MANDOCERR_REQ_EMPTY, /* skipping empty request: request */
+ MANDOCERR_COND_EMPTY, /* conditional request controls empty scope */
+ MANDOCERR_MACRO_EMPTY, /* skipping empty macro: macro */
+ MANDOCERR_BLK_EMPTY, /* empty block: macro */
+ MANDOCERR_ARG_EMPTY, /* empty argument, using 0n: macro arg */
+ MANDOCERR_BD_NOTYPE, /* missing display type, using -ragged: Bd */
+ MANDOCERR_BL_LATETYPE, /* list type is not the first argument: Bl arg */
+ MANDOCERR_BL_NOWIDTH, /* missing -width in -tag list, using 8n */
+ MANDOCERR_EX_NONAME, /* missing utility name, using "": Ex */
+ MANDOCERR_FO_NOHEAD, /* missing function name, using "": Fo */
+ MANDOCERR_IT_NOHEAD, /* empty head in list item: Bl -type It */
+ MANDOCERR_IT_NOBODY, /* empty list item: Bl -type It */
+ MANDOCERR_BF_NOFONT, /* missing font type, using \fR: Bf */
+ MANDOCERR_BF_BADFONT, /* unknown font type, using \fR: Bf font */
+ MANDOCERR_PF_SKIP, /* nothing follows prefix: Pf arg */
+ MANDOCERR_RS_EMPTY, /* empty reference block: Rs */
+ MANDOCERR_ARG_STD, /* missing -std argument, adding it: macro */
+ MANDOCERR_OP_EMPTY, /* missing option string, using "": OP */
+ MANDOCERR_UR_NOHEAD, /* missing resource identifier, using "": UR */
+ MANDOCERR_EQN_NOBOX, /* missing eqn box, using "": op */
+
+ /* related to bad arguments */
+ MANDOCERR_ARG_QUOTE, /* unterminated quoted argument */
+ MANDOCERR_ARG_REP, /* duplicate argument: macro arg */
+ MANDOCERR_AN_REP, /* skipping duplicate argument: An -arg */
+ MANDOCERR_BD_REP, /* skipping duplicate display type: Bd -type */
+ MANDOCERR_BL_REP, /* skipping duplicate list type: Bl -type */
+ MANDOCERR_BL_SKIPW, /* skipping -width argument: Bl -type */
+ MANDOCERR_BL_COL, /* wrong number of cells */
+ 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_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 */
+ MANDOCERR_TR_ODD, /* odd number of characters in request: tr char */
/* related to plain text */
- MANDOCERR_NOBLANKLN, /* blank line in non-literal context */
- MANDOCERR_BADTAB, /* tab in non-literal context */
- MANDOCERR_EOLNSPACE, /* end of line whitespace */
- MANDOCERR_BADCOMMENT, /* bad comment style */
- MANDOCERR_BADESCAPE, /* unknown escape sequence */
- MANDOCERR_BADQUOTE, /* unterminated quoted string */
+ MANDOCERR_FI_BLANK, /* blank line in fill mode, using .sp */
+ MANDOCERR_FI_TAB, /* tab in filled text */
+ MANDOCERR_SPACE_EOL, /* whitespace at end of input line */
+ MANDOCERR_COMMENT_BAD, /* bad comment style */
+ MANDOCERR_ESC_BAD, /* invalid escape sequence: esc */
+ MANDOCERR_STR_UNDEF, /* undefined string, using "": name */
- /* related to equations */
- MANDOCERR_EQNQUOTE, /* unexpected literal in equation */
+ /* related to tables */
+ MANDOCERR_TBLLAYOUT_SPAN, /* tbl line starts with span */
+ MANDOCERR_TBLLAYOUT_DOWN, /* tbl column starts with span */
+ MANDOCERR_TBLLAYOUT_VERT, /* skipping vertical bar in tbl layout */
MANDOCERR_ERROR, /* ===== start of errors ===== */
- /* related to equations */
- MANDOCERR_EQNNSCOPE, /* unexpected equation scope closure*/
- MANDOCERR_EQNSCOPE, /* equation scope open on exit */
- MANDOCERR_EQNBADSCOPE, /* overlapping equation scopes */
- MANDOCERR_EQNEOF, /* unexpected end of equation */
- MANDOCERR_EQNSYNT, /* equation syntax error */
-
/* related to tables */
- MANDOCERR_TBL, /* bad table syntax */
- MANDOCERR_TBLOPT, /* bad table option */
- MANDOCERR_TBLLAYOUT, /* bad table layout */
- MANDOCERR_TBLNOLAYOUT, /* no table layout cells specified */
- MANDOCERR_TBLNODATA, /* no table data cells specified */
- MANDOCERR_TBLIGNDATA, /* ignore data in cell */
- MANDOCERR_TBLBLOCK, /* data block still open */
- MANDOCERR_TBLEXTRADAT, /* ignoring extra data cells */
-
+ MANDOCERR_TBLOPT_ALPHA, /* non-alphabetic character in tbl options */
+ MANDOCERR_TBLOPT_BAD, /* skipping unknown tbl option: option */
+ MANDOCERR_TBLOPT_NOARG, /* missing tbl option argument: option */
+ MANDOCERR_TBLOPT_ARGSZ, /* wrong tbl option argument size: option */
+ MANDOCERR_TBLLAYOUT_NONE, /* empty tbl layout */
+ MANDOCERR_TBLLAYOUT_CHAR, /* invalid character in tbl layout: char */
+ MANDOCERR_TBLLAYOUT_PAR, /* unmatched parenthesis in tbl layout */
+ MANDOCERR_TBLDATA_NONE, /* tbl without any data cells */
+ MANDOCERR_TBLDATA_SPAN, /* ignoring data in spanned tbl cell: data */
+ MANDOCERR_TBLDATA_EXTRA, /* ignoring extra tbl data cells: data */
+ MANDOCERR_TBLDATA_BLK, /* data block open at end of tbl: macro */
+
+ /* related to document structure and macros */
+ MANDOCERR_FILE, /* cannot open file */
MANDOCERR_ROFFLOOP, /* input stack limit exceeded, infinite loop? */
- MANDOCERR_BADCHAR, /* skipping bad character */
- MANDOCERR_NAMESC, /* escaped character not allowed in a name */
- MANDOCERR_NONAME, /* manual name not yet set */
- MANDOCERR_NOTEXT, /* skipping text before the first section header */
- MANDOCERR_MACRO, /* skipping unknown macro */
- MANDOCERR_REQUEST, /* NOT IMPLEMENTED: skipping request */
- MANDOCERR_ARGCOUNT, /* argument count wrong */
- MANDOCERR_STRAYTA, /* skipping column outside column list */
- MANDOCERR_NOSCOPE, /* skipping end of block that is not open */
- MANDOCERR_SCOPEBROKEN, /* missing end of block */
- MANDOCERR_SCOPEEXIT, /* scope open on exit */
- MANDOCERR_UNAME, /* uname(3) system call failed */
- /* FIXME: merge following with MANDOCERR_ARGCOUNT */
- MANDOCERR_NOARGS, /* macro requires line argument(s) */
- MANDOCERR_NOBODY, /* macro requires body argument(s) */
- MANDOCERR_NOARGV, /* macro requires argument(s) */
- MANDOCERR_NUMERIC, /* request requires a numeric argument */
- MANDOCERR_LISTTYPE, /* missing list type */
- MANDOCERR_ARGSLOST, /* line argument(s) will be lost */
- MANDOCERR_BODYLOST, /* body argument(s) will be lost */
-
- MANDOCERR_FATAL, /* ===== start of fatal errors ===== */
-
- MANDOCERR_NOTMANUAL, /* manual isn't really a manual */
- MANDOCERR_COLUMNS, /* column syntax is inconsistent */
- MANDOCERR_BADDISP, /* NOT IMPLEMENTED: .Bd -file */
- MANDOCERR_SYNTARGVCOUNT, /* argument count wrong, violates syntax */
- MANDOCERR_SYNTCHILD, /* child violates parent syntax */
- MANDOCERR_SYNTARGCOUNT, /* argument count wrong, violates syntax */
- MANDOCERR_SOPATH, /* NOT IMPLEMENTED: .so with absolute path or ".." */
- MANDOCERR_NODOCBODY, /* no document body */
- MANDOCERR_NODOCPROLOG, /* no document prologue */
- MANDOCERR_MEM, /* static buffer exhausted */
+ MANDOCERR_CHAR_BAD, /* skipping bad character: number */
+ MANDOCERR_MACRO, /* skipping unknown macro: macro */
+ MANDOCERR_REQ_INSEC, /* skipping insecure request: request */
+ MANDOCERR_IT_STRAY, /* skipping item outside list: It ... */
+ MANDOCERR_TA_STRAY, /* skipping column outside column list: Ta */
+ MANDOCERR_BLK_NOTOPEN, /* skipping end of block that is not open */
+ MANDOCERR_RE_NOTOPEN, /* fewer RS blocks open, skipping: RE arg */
+ MANDOCERR_BLK_BROKEN, /* inserting missing end of block: macro ... */
+ MANDOCERR_BLK_NOEND, /* appending missing end of block: macro */
+
+ /* related to request and macro arguments */
+ MANDOCERR_NAMESC, /* escaped character not allowed in a name: name */
+ MANDOCERR_BD_FILE, /* NOT IMPLEMENTED: Bd -file */
+ MANDOCERR_BL_NOTYPE, /* missing list type, using -item: Bl */
+ MANDOCERR_NM_NONAME, /* missing manual name, using "": Nm */
+ MANDOCERR_OS_UNAME, /* uname(3) system call failed, using UNKNOWN */
+ MANDOCERR_ST_BAD, /* unknown standard specifier: St standard */
+ MANDOCERR_IT_NONUM, /* skipping request without numeric argument */
+ MANDOCERR_SO_PATH, /* NOT IMPLEMENTED: .so with absolute path or ".." */
+ MANDOCERR_SO_FAIL, /* .so request failed */
+ MANDOCERR_ARG_SKIP, /* skipping all arguments: macro args */
+ MANDOCERR_ARG_EXCESS, /* skipping excess arguments: macro ... args */
+ MANDOCERR_DIVZERO, /* divide by zero */
+
+ MANDOCERR_UNSUPP, /* ===== start of unsupported features ===== */
+
+ MANDOCERR_TOOLARGE, /* input too large */
+ MANDOCERR_CHAR_UNSUPP, /* unsupported control character: number */
+ MANDOCERR_REQ_UNSUPP, /* unsupported roff request: request */
+ MANDOCERR_TBLOPT_EQN, /* eqn delim option in tbl: arg */
+ MANDOCERR_TBLLAYOUT_MOD, /* unsupported tbl layout modifier: m */
+ MANDOCERR_TBLMACRO, /* ignoring macro in table: macro */
+
MANDOCERR_MAX
};
struct tbl_opts {
char tab; /* cell-separator */
char decimal; /* decimal point */
- int linesize;
int opts;
#define TBL_OPT_CENTRE (1 << 0)
#define TBL_OPT_EXPAND (1 << 1)
@@ -177,19 +207,10 @@ struct tbl_opts {
#define TBL_OPT_ALLBOX (1 << 4)
#define TBL_OPT_NOKEEP (1 << 5)
#define TBL_OPT_NOSPACE (1 << 6)
+#define TBL_OPT_NOWARN (1 << 7)
int cols; /* number of columns */
-};
-
-/*
- * The head of a table specifies all of its columns. When formatting a
- * tbl_span, iterate over these and plug in data from the tbl_span when
- * appropriate, using tbl_cell as a guide to placement.
- */
-struct tbl_head {
- int ident; /* 0 <= unique id < cols */
- int vert; /* width of preceding vertical line */
- struct tbl_head *next;
- struct tbl_head *prev;
+ int lvert; /* width of left vertical line */
+ int rvert; /* width of right vertical line */
};
enum tbl_cellt {
@@ -210,9 +231,10 @@ enum tbl_cellt {
*/
struct tbl_cell {
struct tbl_cell *next;
- int vert; /* width of preceding vertical line */
+ 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 */
#define TBL_CELL_BALIGN (1 << 1) /* d, D */
@@ -221,7 +243,7 @@ struct tbl_cell {
#define TBL_CELL_EQUAL (1 << 4) /* e, E */
#define TBL_CELL_UP (1 << 5) /* u, U */
#define TBL_CELL_WIGN (1 << 6) /* z, Z */
- struct tbl_head *head;
+#define TBL_CELL_WMAX (1 << 7) /* x, X */
};
/*
@@ -231,6 +253,7 @@ struct tbl_row {
struct tbl_row *next;
struct tbl_cell *first;
struct tbl_cell *last;
+ int vert; /* width of left vertical line */
};
enum tbl_datt {
@@ -265,37 +288,23 @@ enum tbl_spant {
*/
struct tbl_span {
struct tbl_opts *opts;
- struct tbl_head *head;
struct tbl_row *layout; /* layout row */
struct tbl_dat *first;
struct tbl_dat *last;
+ struct tbl_span *prev;
+ struct tbl_span *next;
int line; /* parse line */
- int flags;
-#define TBL_SPAN_FIRST (1 << 0)
-#define TBL_SPAN_LAST (1 << 1)
enum tbl_spant pos;
- struct tbl_span *next;
};
enum eqn_boxt {
EQN_ROOT, /* root of parse tree */
EQN_TEXT, /* text (number, variable, whatever) */
EQN_SUBEXPR, /* nested `eqn' subexpression */
- EQN_LIST, /* subexpressions list */
- EQN_MATRIX /* matrix subexpression */
-};
-
-enum eqn_markt {
- EQNMARK_NONE = 0,
- EQNMARK_DOT,
- EQNMARK_DOTDOT,
- EQNMARK_HAT,
- EQNMARK_TILDE,
- EQNMARK_VEC,
- EQNMARK_DYAD,
- EQNMARK_BAR,
- EQNMARK_UNDER,
- EQNMARK__MAX
+ EQN_LIST, /* list (braces, etc.) */
+ EQN_LISTONE, /* singleton list */
+ EQN_PILE, /* vertical pile */
+ EQN_MATRIX /* pile of piles */
};
enum eqn_fontt {
@@ -309,11 +318,14 @@ enum eqn_fontt {
enum eqn_post {
EQNPOS_NONE = 0,
- EQNPOS_OVER,
EQNPOS_SUP,
+ EQNPOS_SUBSUP,
EQNPOS_SUB,
EQNPOS_TO,
EQNPOS_FROM,
+ EQNPOS_FROMTO,
+ EQNPOS_OVER,
+ EQNPOS_SQRT,
EQNPOS__MAX
};
@@ -341,19 +353,23 @@ struct eqn_box {
struct eqn_box *first; /* first child node */
struct eqn_box *last; /* last child node */
struct eqn_box *next; /* node sibling */
+ struct eqn_box *prev; /* node sibling */
struct eqn_box *parent; /* node sibling */
char *text; /* text (or NULL) */
- char *left;
- char *right;
+ char *left; /* fence left-hand */
+ char *right; /* fence right-hand */
+ char *top; /* expression over-symbol */
+ char *bottom; /* expression under-symbol */
+ size_t args; /* arguments in parent */
+ size_t expectargs; /* max arguments in parent */
enum eqn_post pos; /* position of next box */
- enum eqn_markt mark; /* a mark about the box */
enum eqn_fontt font; /* font of box */
enum eqn_pilet pile; /* equation piling */
};
/*
* An equation consists of a tree of expressions starting at a given
- * line and position.
+ * line and position.
*/
struct eqn {
char *name; /* identifier (or NULL) */
@@ -363,15 +379,14 @@ struct eqn {
};
/*
- * The type of parse sequence. This value is usually passed via the
- * mandoc(1) command line of -man and -mdoc. It's almost exclusively
- * -mandoc but the others have been retained for compatibility.
+ * Parse options.
*/
-enum mparset {
- MPARSE_AUTO, /* magically determine the document type */
- MPARSE_MDOC, /* assume -mdoc */
- MPARSE_MAN /* assume -man */
-};
+#define MPARSE_MDOC 1 /* assume -mdoc */
+#define MPARSE_MAN 2 /* assume -man */
+#define MPARSE_SO 4 /* honour .so requests */
+#define MPARSE_QUICK 8 /* abort the parse early */
+#define MPARSE_UTF8 16 /* accept UTF-8 input */
+#define MPARSE_LATIN1 32 /* accept ISO-LATIN-1 input */
enum mandoc_esc {
ESCAPE_ERROR = 0, /* bail! unparsable escape */
@@ -386,47 +401,44 @@ enum mandoc_esc {
ESCAPE_NUMBERED, /* a numbered glyph */
ESCAPE_UNICODE, /* a unicode codepoint */
ESCAPE_NOSPACE, /* suppress space if the last on a line */
- ESCAPE_SKIPCHAR /* skip the next character */
+ ESCAPE_SKIPCHAR, /* skip the next character */
+ ESCAPE_OVERSTRIKE /* overstrike all chars in the argument */
};
typedef void (*mandocmsg)(enum mandocerr, enum mandoclevel,
const char *, int, int, const char *);
+__BEGIN_DECLS
+
struct mparse;
struct mchars;
struct mdoc;
struct man;
-__BEGIN_DECLS
-
-void *mandoc_calloc(size_t, size_t);
enum mandoc_esc mandoc_escape(const char **, const char **, int *);
-void *mandoc_malloc(size_t);
-void *mandoc_realloc(void *, size_t);
-char *mandoc_strdup(const char *);
-char *mandoc_strndup(const char *, size_t);
struct mchars *mchars_alloc(void);
void mchars_free(struct mchars *);
-char mchars_num2char(const char *, size_t);
+int mchars_num2char(const char *, size_t);
+const char *mchars_uc2str(int);
int mchars_num2uc(const char *, size_t);
-int mchars_spec2cp(const struct mchars *,
+int mchars_spec2cp(const struct mchars *,
const char *, size_t);
-const char *mchars_spec2str(const struct mchars *,
+const char *mchars_spec2str(const struct mchars *,
const char *, size_t, size_t *);
-struct mparse *mparse_alloc(enum mparset, enum mandoclevel,
- mandocmsg, void *, char *);
+struct mparse *mparse_alloc(int, enum mandoclevel, mandocmsg,
+ const struct mchars *, const char *);
void mparse_free(struct mparse *);
void mparse_keep(struct mparse *);
+enum mandoclevel mparse_open(struct mparse *, int *, const char *);
enum mandoclevel mparse_readfd(struct mparse *, int, const char *);
-enum mandoclevel mparse_readmem(struct mparse *, const void *, size_t,
+enum mandoclevel mparse_readmem(struct mparse *, void *, size_t,
const char *);
void mparse_reset(struct mparse *);
-void mparse_result(struct mparse *,
- struct mdoc **, struct man **);
+void mparse_result(struct mparse *,
+ struct mdoc **, struct man **, char **);
const char *mparse_getkeep(const struct mparse *);
const char *mparse_strerror(enum mandocerr);
const char *mparse_strlevel(enum mandoclevel);
+enum mandoclevel mparse_wait(struct mparse *);
__END_DECLS
-
-#endif /*!MANDOC_H*/
diff --git a/usr/src/cmd/mandoc/mandoc_aux.c b/usr/src/cmd/mandoc/mandoc_aux.c
new file mode 100644
index 0000000000..2275bbcf36
--- /dev/null
+++ b/usr/src/cmd/mandoc/mandoc_aux.c
@@ -0,0 +1,119 @@
+/* $Id: mandoc_aux.c,v 1.4 2014/08/10 23:54:41 schwarze Exp $ */
+/*
+ * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "config.h"
+
+#include <sys/types.h>
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "mandoc.h"
+#include "mandoc_aux.h"
+
+int
+mandoc_asprintf(char **dest, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = vasprintf(dest, fmt, ap);
+ va_end(ap);
+
+ if (-1 == ret) {
+ perror(NULL);
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+ return(ret);
+}
+
+void *
+mandoc_calloc(size_t num, size_t size)
+{
+ void *ptr;
+
+ ptr = calloc(num, size);
+ if (NULL == ptr) {
+ perror(NULL);
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+ return(ptr);
+}
+
+void *
+mandoc_malloc(size_t size)
+{
+ void *ptr;
+
+ ptr = malloc(size);
+ if (NULL == ptr) {
+ perror(NULL);
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+ return(ptr);
+}
+
+void *
+mandoc_realloc(void *ptr, size_t size)
+{
+
+ ptr = realloc(ptr, size);
+ if (NULL == ptr) {
+ perror(NULL);
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+ return(ptr);
+}
+
+void *
+mandoc_reallocarray(void *ptr, size_t num, size_t size)
+{
+
+ ptr = reallocarray(ptr, num, size);
+ if (NULL == ptr) {
+ perror(NULL);
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+ return(ptr);
+}
+
+char *
+mandoc_strdup(const char *ptr)
+{
+ char *p;
+
+ p = strdup(ptr);
+ if (NULL == p) {
+ perror(NULL);
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+ return(p);
+}
+
+char *
+mandoc_strndup(const char *ptr, size_t sz)
+{
+ char *p;
+
+ p = mandoc_malloc(sz + 1);
+ memcpy(p, ptr, sz);
+ p[(int)sz] = '\0';
+ return(p);
+}
diff --git a/usr/src/cmd/mandoc/vol.c b/usr/src/cmd/mandoc/mandoc_aux.h
index 3ea7441a42..e72fe4e40e 100644
--- a/usr/src/cmd/mandoc/vol.c
+++ b/usr/src/cmd/mandoc/mandoc_aux.h
@@ -1,6 +1,7 @@
-/* $Id: vol.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */
+/* $Id: mandoc_aux.h,v 1.3 2014/12/01 04:05:32 schwarze Exp $ */
/*
- * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014 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,26 +15,15 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
+__BEGIN_DECLS
-#include "mdoc.h"
-#include "mandoc.h"
-#include "libmdoc.h"
+int mandoc_asprintf(char **, const char *, ...);
+void *mandoc_calloc(size_t, size_t);
+void *mandoc_malloc(size_t);
+void *mandoc_realloc(void *, size_t);
+void *mandoc_reallocarray(void *, size_t, size_t);
+char *mandoc_strdup(const char *);
+char *mandoc_strndup(const char *, size_t);
-#define LINE(x, y) \
- if (0 == strcmp(p, x)) return(y);
-
-const char *
-mdoc_a2vol(const char *p)
-{
-
-#include "vol.in"
-
- return(NULL);
-}
+__END_DECLS
diff --git a/usr/src/cmd/mandoc/manpath.c b/usr/src/cmd/mandoc/manpath.c
new file mode 100644
index 0000000000..e85175e945
--- /dev/null
+++ b/usr/src/cmd/mandoc/manpath.c
@@ -0,0 +1,237 @@
+/* $Id: manpath.c,v 1.19 2014/11/27 00:30:40 schwarze Exp $ */
+/*
+ * Copyright (c) 2011, 2014 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mandoc_aux.h"
+#include "manpath.h"
+
+#define MAN_CONF_FILE "/etc/man.conf"
+#define MAN_CONF_KEY "_whatdb"
+
+static void manpath_add(struct manpaths *, const char *, int);
+static void manpath_parseline(struct manpaths *, char *, int);
+
+void
+manpath_parse(struct manpaths *dirs, const char *file,
+ char *defp, char *auxp)
+{
+#if HAVE_MANPATH
+ char cmd[(PATH_MAX * 3) + 20];
+ FILE *stream;
+ char *buf;
+ size_t sz, bsz;
+
+ strlcpy(cmd, "manpath", sizeof(cmd));
+ if (file) {
+ strlcat(cmd, " -C ", sizeof(cmd));
+ strlcat(cmd, file, sizeof(cmd));
+ }
+ if (auxp) {
+ strlcat(cmd, " -m ", sizeof(cmd));
+ strlcat(cmd, auxp, sizeof(cmd));
+ }
+ if (defp) {
+ strlcat(cmd, " -M ", sizeof(cmd));
+ strlcat(cmd, defp, sizeof(cmd));
+ }
+
+ /* Open manpath(1). Ignore errors. */
+
+ stream = popen(cmd, "r");
+ if (NULL == stream)
+ return;
+
+ buf = NULL;
+ bsz = 0;
+
+ /* Read in as much output as we can. */
+
+ do {
+ buf = mandoc_realloc(buf, bsz + 1024);
+ sz = fread(buf + bsz, 1, 1024, stream);
+ bsz += sz;
+ } while (sz > 0);
+
+ if ( ! ferror(stream) && feof(stream) &&
+ bsz && '\n' == buf[bsz - 1]) {
+ buf[bsz - 1] = '\0';
+ manpath_parseline(dirs, buf, 1);
+ }
+
+ free(buf);
+ pclose(stream);
+#else
+ char *insert;
+
+ /* Always prepend -m. */
+ manpath_parseline(dirs, auxp, 1);
+
+ /* If -M is given, it overrides everything else. */
+ if (NULL != defp) {
+ manpath_parseline(dirs, defp, 1);
+ return;
+ }
+
+ /* MANPATH and man.conf(5) cooperate. */
+ defp = getenv("MANPATH");
+ if (NULL == file)
+ file = MAN_CONF_FILE;
+
+ /* No MANPATH; use man.conf(5) only. */
+ if (NULL == defp || '\0' == defp[0]) {
+ manpath_manconf(dirs, file);
+ return;
+ }
+
+ /* Prepend man.conf(5) to MANPATH. */
+ if (':' == defp[0]) {
+ manpath_manconf(dirs, file);
+ manpath_parseline(dirs, defp, 0);
+ return;
+ }
+
+ /* Append man.conf(5) to MANPATH. */
+ if (':' == defp[strlen(defp) - 1]) {
+ manpath_parseline(dirs, defp, 0);
+ manpath_manconf(dirs, file);
+ return;
+ }
+
+ /* Insert man.conf(5) into MANPATH. */
+ insert = strstr(defp, "::");
+ if (NULL != insert) {
+ *insert++ = '\0';
+ manpath_parseline(dirs, defp, 0);
+ manpath_manconf(dirs, file);
+ manpath_parseline(dirs, insert + 1, 0);
+ return;
+ }
+
+ /* MANPATH overrides man.conf(5) completely. */
+ manpath_parseline(dirs, defp, 0);
+#endif
+}
+
+/*
+ * Parse a FULL pathname from a colon-separated list of arrays.
+ */
+static void
+manpath_parseline(struct manpaths *dirs, char *path, int complain)
+{
+ char *dir;
+
+ if (NULL == path)
+ return;
+
+ for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":"))
+ manpath_add(dirs, dir, complain);
+}
+
+/*
+ * Add a directory to the array, ignoring bad directories.
+ * Grow the array one-by-one for simplicity's sake.
+ */
+static void
+manpath_add(struct manpaths *dirs, const char *dir, int complain)
+{
+ char buf[PATH_MAX];
+ struct stat sb;
+ char *cp;
+ size_t i;
+
+ if (NULL == (cp = realpath(dir, buf))) {
+ if (complain) {
+ fputs("manpath: ", stderr);
+ perror(dir);
+ }
+ return;
+ }
+
+ for (i = 0; i < dirs->sz; i++)
+ if (0 == strcmp(dirs->paths[i], dir))
+ return;
+
+ if (stat(cp, &sb) == -1) {
+ if (complain) {
+ fputs("manpath: ", stderr);
+ perror(dir);
+ }
+ return;
+ }
+
+ dirs->paths = mandoc_reallocarray(dirs->paths,
+ dirs->sz + 1, sizeof(char *));
+
+ dirs->paths[dirs->sz++] = mandoc_strdup(cp);
+}
+
+void
+manpath_free(struct manpaths *p)
+{
+ size_t i;
+
+ for (i = 0; i < p->sz; i++)
+ free(p->paths[i]);
+
+ free(p->paths);
+}
+
+void
+manpath_manconf(struct manpaths *dirs, const char *file)
+{
+ FILE *stream;
+ char *p, *q;
+ size_t len, keysz;
+
+ keysz = strlen(MAN_CONF_KEY);
+ assert(keysz > 0);
+
+ if (NULL == (stream = fopen(file, "r")))
+ return;
+
+ while (NULL != (p = fgetln(stream, &len))) {
+ if (0 == len || '\n' != p[--len])
+ break;
+ p[len] = '\0';
+ while (isspace((unsigned char)*p))
+ p++;
+ if (strncmp(MAN_CONF_KEY, p, keysz))
+ continue;
+ p += keysz;
+ while (isspace((unsigned char)*p))
+ p++;
+ if ('\0' == *p)
+ continue;
+ if (NULL == (q = strrchr(p, '/')))
+ continue;
+ *q = '\0';
+ manpath_add(dirs, p, 0);
+ }
+
+ fclose(stream);
+}
diff --git a/usr/src/cmd/mandoc/arch.c b/usr/src/cmd/mandoc/manpath.h
index e764bfe993..728373b2cc 100644
--- a/usr/src/cmd/mandoc/arch.c
+++ b/usr/src/cmd/mandoc/manpath.h
@@ -1,6 +1,7 @@
-/* $Id: arch.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */
+/* $Id: manpath.h,v 1.7 2014/12/01 04:05:32 schwarze Exp $ */
/*
- * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,26 +15,20 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#include "mdoc.h"
-#include "mandoc.h"
-#include "libmdoc.h"
-
-#define LINE(x, y) \
- if (0 == strcmp(p, x)) return(y);
+/*
+ * Unsorted list of unique, absolute paths to be searched for manual
+ * databases.
+ */
+struct manpaths {
+ size_t sz;
+ char **paths;
+};
-const char *
-mdoc_a2arch(const char *p)
-{
+__BEGIN_DECLS
-#include "arch.in"
+void manpath_manconf(struct manpaths *, const char *);
+void manpath_parse(struct manpaths *, const char *, char *, char *);
+void manpath_free(struct manpaths *);
- return(NULL);
-}
+__END_DECLS
diff --git a/usr/src/cmd/mandoc/mansearch.h b/usr/src/cmd/mandoc/mansearch.h
new file mode 100644
index 0000000000..14ec8ceacd
--- /dev/null
+++ b/usr/src/cmd/mandoc/mansearch.h
@@ -0,0 +1,111 @@
+/* $Id: mansearch.h,v 1.23 2014/12/01 08:05:52 schwarze Exp $ */
+/*
+ * Copyright (c) 2012 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2013, 2014 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.
+ */
+
+#define MANDOC_DB "mandoc.db"
+
+#define TYPE_arch 0x0000000000000001ULL
+#define TYPE_sec 0x0000000000000002ULL
+#define TYPE_Xr 0x0000000000000004ULL
+#define TYPE_Ar 0x0000000000000008ULL
+#define TYPE_Fa 0x0000000000000010ULL
+#define TYPE_Fl 0x0000000000000020ULL
+#define TYPE_Dv 0x0000000000000040ULL
+#define TYPE_Fn 0x0000000000000080ULL
+#define TYPE_Ic 0x0000000000000100ULL
+#define TYPE_Pa 0x0000000000000200ULL
+#define TYPE_Cm 0x0000000000000400ULL
+#define TYPE_Li 0x0000000000000800ULL
+#define TYPE_Em 0x0000000000001000ULL
+#define TYPE_Cd 0x0000000000002000ULL
+#define TYPE_Va 0x0000000000004000ULL
+#define TYPE_Ft 0x0000000000008000ULL
+#define TYPE_Tn 0x0000000000010000ULL
+#define TYPE_Er 0x0000000000020000ULL
+#define TYPE_Ev 0x0000000000040000ULL
+#define TYPE_Sy 0x0000000000080000ULL
+#define TYPE_Sh 0x0000000000100000ULL
+#define TYPE_In 0x0000000000200000ULL
+#define TYPE_Ss 0x0000000000400000ULL
+#define TYPE_Ox 0x0000000000800000ULL
+#define TYPE_An 0x0000000001000000ULL
+#define TYPE_Mt 0x0000000002000000ULL
+#define TYPE_St 0x0000000004000000ULL
+#define TYPE_Bx 0x0000000008000000ULL
+#define TYPE_At 0x0000000010000000ULL
+#define TYPE_Nx 0x0000000020000000ULL
+#define TYPE_Fx 0x0000000040000000ULL
+#define TYPE_Lk 0x0000000080000000ULL
+#define TYPE_Ms 0x0000000100000000ULL
+#define TYPE_Bsx 0x0000000200000000ULL
+#define TYPE_Dx 0x0000000400000000ULL
+#define TYPE_Rs 0x0000000800000000ULL
+#define TYPE_Vt 0x0000001000000000ULL
+#define TYPE_Lb 0x0000002000000000ULL
+#define TYPE_Nm 0x0000004000000000ULL
+#define TYPE_Nd 0x0000008000000000ULL
+
+#define NAME_SYN 0x0000004000000001ULL
+#define NAME_FIRST 0x0000004000000004ULL
+#define NAME_TITLE 0x0000004000000006ULL
+#define NAME_HEAD 0x0000004000000008ULL
+#define NAME_FILE 0x0000004000000010ULL
+#define NAME_MASK 0x000000000000001fULL
+
+#define FORM_CAT 0 /* manual page is preformatted */
+#define FORM_SRC 1 /* format is mdoc(7) or man(7) */
+#define FORM_NONE 4 /* format is unknown */
+
+enum argmode {
+ ARG_FILE = 0,
+ ARG_NAME,
+ ARG_WORD,
+ ARG_EXPR
+};
+
+struct manpage {
+ char *file; /* to be prefixed by manpath */
+ char *names; /* a list of names with sections */
+ char *output; /* user-defined additional output */
+ size_t ipath; /* number of the manpath */
+ uint64_t bits; /* name type mask */
+ int sec; /* section number, 10 means invalid */
+ int form; /* 0 == catpage */
+};
+
+struct mansearch {
+ const char *arch; /* architecture/NULL */
+ const char *sec; /* mansection/NULL */
+ const char *outkey; /* show content of this macro */
+ enum argmode argmode; /* interpretation of arguments */
+ int firstmatch; /* first matching database only */
+};
+
+__BEGIN_DECLS
+
+struct manpaths;
+
+int mansearch_setup(int);
+int mansearch(const struct mansearch *cfg, /* options */
+ const struct manpaths *paths, /* manpaths */
+ int argc, /* size of argv */
+ char *argv[], /* search terms */
+ struct manpage **res, /* results */
+ size_t *ressz); /* results returned */
+void mansearch_free(struct manpage *, size_t);
+
+__END_DECLS
diff --git a/usr/src/cmd/mandoc/mdoc.c b/usr/src/cmd/mandoc/mdoc.c
index 87b358797b..027ecbeb31 100644
--- a/usr/src/cmd/mandoc/mdoc.c
+++ b/usr/src/cmd/mandoc/mdoc.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc.c,v 1.206 2013/12/24 19:11:46 schwarze Exp $ */
+/* $Id: mdoc.c,v 1.238 2015/02/12 13:00:52 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012-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
@@ -15,13 +15,12 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#include <sys/types.h>
#include <assert.h>
+#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -30,10 +29,11 @@
#include "mdoc.h"
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libmdoc.h"
#include "libmandoc.h"
-const char *const __mdoc_macronames[MDOC_MAX] = {
+const char *const __mdoc_macronames[MDOC_MAX + 1] = {
"Ap", "Dd", "Dt", "Os",
"Sh", "Ss", "Pp", "D1",
"Dl", "Bd", "Ed", "Bl",
@@ -44,11 +44,8 @@ const char *const __mdoc_macronames[MDOC_MAX] = {
"Ic", "In", "Li", "Nd",
"Nm", "Op", "Ot", "Pa",
"Rv", "St", "Va", "Vt",
- /* LINTED */
"Xr", "%A", "%B", "%D",
- /* LINTED */
"%I", "%J", "%N", "%O",
- /* LINTED */
"%P", "%R", "%T", "%V",
"Ac", "Ao", "Aq", "At",
"Bc", "Bf", "Bo", "Bq",
@@ -65,22 +62,19 @@ const char *const __mdoc_macronames[MDOC_MAX] = {
"Bk", "Ek", "Bt", "Hf",
"Fr", "Ud", "Lb", "Lp",
"Lk", "Mt", "Brq", "Bro",
- /* LINTED */
"Brc", "%C", "Es", "En",
- /* LINTED */
"Dx", "%Q", "br", "sp",
- /* LINTED */
- "%U", "Ta"
+ "%U", "Ta", "ll", "text",
};
-const char *const __mdoc_argnames[MDOC_ARG_MAX] = {
+const char *const __mdoc_argnames[MDOC_ARG_MAX] = {
"split", "nosplit", "ragged",
- "unfilled", "literal", "file",
- "offset", "bullet", "dash",
- "hyphen", "item", "enum",
- "tag", "diag", "hang",
- "ohang", "inset", "column",
- "width", "compact", "std",
+ "unfilled", "literal", "file",
+ "offset", "bullet", "dash",
+ "hyphen", "item", "enum",
+ "tag", "diag", "hang",
+ "ohang", "inset", "column",
+ "width", "compact", "std",
"filled", "words", "emphasis",
"symbolic", "nested", "centered"
};
@@ -89,38 +83,31 @@ const char * const *mdoc_macronames = __mdoc_macronames;
const char * const *mdoc_argnames = __mdoc_argnames;
static void mdoc_node_free(struct mdoc_node *);
-static void mdoc_node_unlink(struct mdoc *,
+static void mdoc_node_unlink(struct mdoc *,
struct mdoc_node *);
static void mdoc_free1(struct mdoc *);
static void mdoc_alloc1(struct mdoc *);
-static struct mdoc_node *node_alloc(struct mdoc *, int, int,
+static struct mdoc_node *node_alloc(struct mdoc *, int, int,
enum mdoct, enum mdoc_type);
-static int node_append(struct mdoc *,
- struct mdoc_node *);
-#if 0
-static int mdoc_preptext(struct mdoc *, int, char *, int);
-#endif
+static void node_append(struct mdoc *, struct mdoc_node *);
static int mdoc_ptext(struct mdoc *, int, char *, int);
static int mdoc_pmacro(struct mdoc *, int, char *, int);
+
const struct mdoc_node *
mdoc_node(const struct mdoc *mdoc)
{
- assert( ! (MDOC_HALT & mdoc->flags));
return(mdoc->first);
}
-
const struct mdoc_meta *
mdoc_meta(const struct mdoc *mdoc)
{
- assert( ! (MDOC_HALT & mdoc->flags));
return(&mdoc->meta);
}
-
/*
* Frees volatile resources (parse tree, meta-data, fields).
*/
@@ -130,23 +117,15 @@ mdoc_free1(struct mdoc *mdoc)
if (mdoc->first)
mdoc_node_delete(mdoc, mdoc->first);
- if (mdoc->meta.title)
- free(mdoc->meta.title);
- if (mdoc->meta.os)
- free(mdoc->meta.os);
- if (mdoc->meta.name)
- free(mdoc->meta.name);
- if (mdoc->meta.arch)
- free(mdoc->meta.arch);
- if (mdoc->meta.vol)
- free(mdoc->meta.vol);
- if (mdoc->meta.msec)
- free(mdoc->meta.msec);
- if (mdoc->meta.date)
- free(mdoc->meta.date);
+ free(mdoc->meta.msec);
+ free(mdoc->meta.vol);
+ free(mdoc->meta.arch);
+ free(mdoc->meta.date);
+ free(mdoc->meta.title);
+ free(mdoc->meta.os);
+ free(mdoc->meta.name);
}
-
/*
* Allocate all volatile resources (parse tree, meta-data, fields).
*/
@@ -164,7 +143,6 @@ mdoc_alloc1(struct mdoc *mdoc)
mdoc->next = MDOC_NEXT_CHILD;
}
-
/*
* Free up volatile resources (see mdoc_free1()) then re-initialises the
* data with mdoc_alloc1(). After invocation, parse data has been reset
@@ -179,7 +157,6 @@ mdoc_reset(struct mdoc *mdoc)
mdoc_alloc1(mdoc);
}
-
/*
* Completely free up all volatile and non-volatile parse resources.
* After invocation, the pointer is no longer usable.
@@ -192,12 +169,12 @@ mdoc_free(struct mdoc *mdoc)
free(mdoc);
}
-
/*
- * Allocate volatile and non-volatile parse resources.
+ * Allocate volatile and non-volatile parse resources.
*/
struct mdoc *
-mdoc_alloc(struct roff *roff, struct mparse *parse, char *defos)
+mdoc_alloc(struct roff *roff, struct mparse *parse,
+ const char *defos, int quick)
{
struct mdoc *p;
@@ -205,6 +182,7 @@ mdoc_alloc(struct roff *roff, struct mparse *parse, char *defos)
p->parse = parse;
p->defos = defos;
+ p->quick = quick;
p->roff = roff;
mdoc_hash_init();
@@ -212,71 +190,37 @@ mdoc_alloc(struct roff *roff, struct mparse *parse, char *defos)
return(p);
}
-
-/*
- * Climb back up the parse tree, validating open scopes. Mostly calls
- * through to macro_end() in macro.c.
- */
-int
+void
mdoc_endparse(struct mdoc *mdoc)
{
- assert( ! (MDOC_HALT & mdoc->flags));
- if (mdoc_macroend(mdoc))
- return(1);
- mdoc->flags |= MDOC_HALT;
- return(0);
+ mdoc_macroend(mdoc);
}
-int
+void
mdoc_addeqn(struct mdoc *mdoc, const struct eqn *ep)
{
struct mdoc_node *n;
- assert( ! (MDOC_HALT & mdoc->flags));
-
- /* No text before an initial macro. */
-
- if (SEC_NONE == mdoc->lastnamed) {
- mdoc_pmsg(mdoc, ep->ln, ep->pos, MANDOCERR_NOTEXT);
- return(1);
- }
-
n = node_alloc(mdoc, ep->ln, ep->pos, MDOC_MAX, MDOC_EQN);
n->eqn = ep;
-
- if ( ! node_append(mdoc, n))
- return(0);
-
+ if (ep->ln > mdoc->last->line)
+ n->flags |= MDOC_LINE;
+ node_append(mdoc, n);
mdoc->next = MDOC_NEXT_SIBLING;
- return(1);
}
-int
+void
mdoc_addspan(struct mdoc *mdoc, const struct tbl_span *sp)
{
struct mdoc_node *n;
- assert( ! (MDOC_HALT & mdoc->flags));
-
- /* No text before an initial macro. */
-
- if (SEC_NONE == mdoc->lastnamed) {
- mdoc_pmsg(mdoc, sp->line, 0, MANDOCERR_NOTEXT);
- return(1);
- }
-
n = node_alloc(mdoc, sp->line, 0, MDOC_MAX, MDOC_TBL);
n->span = sp;
-
- if ( ! node_append(mdoc, n))
- return(0);
-
+ node_append(mdoc, n);
mdoc->next = MDOC_NEXT_SIBLING;
- return(1);
}
-
/*
* Main parse routine. Parses a single line -- really just hands off to
* the macro (mdoc_pmacro()) or text parser (mdoc_ptext()).
@@ -285,9 +229,8 @@ int
mdoc_parseln(struct mdoc *mdoc, int ln, char *buf, int offs)
{
- assert( ! (MDOC_HALT & mdoc->flags));
-
- mdoc->flags |= MDOC_NEWLINE;
+ if (mdoc->last->type != MDOC_EQN || ln > mdoc->last->line)
+ mdoc->flags |= MDOC_NEWLINE;
/*
* Let the roff nS register switch SYNOPSIS mode early,
@@ -301,47 +244,38 @@ mdoc_parseln(struct mdoc *mdoc, int ln, char *buf, int offs)
mdoc->flags &= ~MDOC_SYNOPSIS;
return(roff_getcontrol(mdoc->roff, buf, &offs) ?
- mdoc_pmacro(mdoc, ln, buf, offs) :
- mdoc_ptext(mdoc, ln, buf, offs));
+ mdoc_pmacro(mdoc, ln, buf, offs) :
+ mdoc_ptext(mdoc, ln, buf, offs));
}
-int
+void
mdoc_macro(MACRO_PROT_ARGS)
{
assert(tok < MDOC_MAX);
- /* If we're in the body, deny prologue calls. */
-
- if (MDOC_PROLOGUE & mdoc_macros[tok].flags &&
- MDOC_PBODY & mdoc->flags) {
- mdoc_pmsg(mdoc, line, ppos, MANDOCERR_BADBODY);
- return(1);
- }
-
- /* If we're in the prologue, deny "body" macros. */
-
- if ( ! (MDOC_PROLOGUE & mdoc_macros[tok].flags) &&
- ! (MDOC_PBODY & mdoc->flags)) {
- mdoc_pmsg(mdoc, line, ppos, MANDOCERR_BADPROLOG);
- if (NULL == mdoc->meta.msec)
- mdoc->meta.msec = mandoc_strdup("1");
- if (NULL == mdoc->meta.title)
- mdoc->meta.title = mandoc_strdup("UNKNOWN");
+ if (mdoc->flags & MDOC_PBODY) {
+ if (tok == MDOC_Dt) {
+ mandoc_vmsg(MANDOCERR_DT_LATE,
+ mdoc->parse, line, ppos,
+ "Dt %s", buf + *pos);
+ return;
+ }
+ } else if ( ! (mdoc_macros[tok].flags & MDOC_PROLOGUE)) {
+ if (mdoc->meta.title == NULL) {
+ mandoc_vmsg(MANDOCERR_DT_NOTITLE,
+ mdoc->parse, line, ppos, "%s %s",
+ mdoc_macronames[tok], buf + *pos);
+ mdoc->meta.title = mandoc_strdup("UNTITLED");
+ }
if (NULL == mdoc->meta.vol)
mdoc->meta.vol = mandoc_strdup("LOCAL");
- if (NULL == mdoc->meta.os)
- mdoc->meta.os = mandoc_strdup("LOCAL");
- if (NULL == mdoc->meta.date)
- mdoc->meta.date = mandoc_normdate
- (mdoc->parse, NULL, line, ppos);
mdoc->flags |= MDOC_PBODY;
}
-
- return((*mdoc_macros[tok].fp)(mdoc, tok, line, ppos, pos, buf));
+ (*mdoc_macros[tok].fp)(mdoc, tok, line, ppos, pos, buf);
}
-static int
+static void
node_append(struct mdoc *mdoc, struct mdoc_node *p)
{
@@ -350,12 +284,12 @@ node_append(struct mdoc *mdoc, struct mdoc_node *p)
assert(MDOC_ROOT != p->type);
switch (mdoc->next) {
- case (MDOC_NEXT_SIBLING):
+ case MDOC_NEXT_SIBLING:
mdoc->last->next = p;
p->prev = mdoc->last;
p->parent = mdoc->last->parent;
break;
- case (MDOC_NEXT_CHILD):
+ case MDOC_NEXT_CHILD:
mdoc->last->child = p;
p->parent = mdoc->last;
break;
@@ -372,32 +306,31 @@ node_append(struct mdoc *mdoc, struct mdoc_node *p)
*/
switch (p->type) {
- case (MDOC_BODY):
+ case MDOC_BODY:
if (ENDBODY_NOT != p->end)
break;
/* FALLTHROUGH */
- case (MDOC_TAIL):
+ case MDOC_TAIL:
/* FALLTHROUGH */
- case (MDOC_HEAD):
+ case MDOC_HEAD:
p->norm = p->parent->norm;
break;
default:
break;
}
- if ( ! mdoc_valid_pre(mdoc, p))
- return(0);
+ mdoc_valid_pre(mdoc, p);
switch (p->type) {
- case (MDOC_HEAD):
+ case MDOC_HEAD:
assert(MDOC_BLOCK == p->parent->type);
p->parent->head = p;
break;
- case (MDOC_TAIL):
+ case MDOC_TAIL:
assert(MDOC_BLOCK == p->parent->type);
p->parent->tail = p;
break;
- case (MDOC_BODY):
+ case MDOC_BODY:
if (p->end)
break;
assert(MDOC_BLOCK == p->parent->type);
@@ -410,22 +343,18 @@ node_append(struct mdoc *mdoc, struct mdoc_node *p)
mdoc->last = p;
switch (p->type) {
- case (MDOC_TBL):
+ case MDOC_TBL:
/* FALLTHROUGH */
- case (MDOC_TEXT):
- if ( ! mdoc_valid_post(mdoc))
- return(0);
+ case MDOC_TEXT:
+ mdoc_valid_post(mdoc);
break;
default:
break;
}
-
- return(1);
}
-
static struct mdoc_node *
-node_alloc(struct mdoc *mdoc, int line, int pos,
+node_alloc(struct mdoc *mdoc, int line, int pos,
enum mdoct tok, enum mdoc_type type)
{
struct mdoc_node *p;
@@ -434,7 +363,6 @@ node_alloc(struct mdoc *mdoc, int line, int pos,
p->sec = mdoc->lastsec;
p->line = line;
p->pos = pos;
- p->lastline = line;
p->tok = tok;
p->type = type;
@@ -451,68 +379,59 @@ node_alloc(struct mdoc *mdoc, int line, int pos,
return(p);
}
-
-int
+void
mdoc_tail_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
{
struct mdoc_node *p;
p = node_alloc(mdoc, line, pos, tok, MDOC_TAIL);
- if ( ! node_append(mdoc, p))
- return(0);
+ node_append(mdoc, p);
mdoc->next = MDOC_NEXT_CHILD;
- return(1);
}
-
-int
+struct mdoc_node *
mdoc_head_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
{
struct mdoc_node *p;
assert(mdoc->first);
assert(mdoc->last);
-
p = node_alloc(mdoc, line, pos, tok, MDOC_HEAD);
- if ( ! node_append(mdoc, p))
- return(0);
+ node_append(mdoc, p);
mdoc->next = MDOC_NEXT_CHILD;
- return(1);
+ return(p);
}
-
-int
+struct mdoc_node *
mdoc_body_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok)
{
struct mdoc_node *p;
p = node_alloc(mdoc, line, pos, tok, MDOC_BODY);
- if ( ! node_append(mdoc, p))
- return(0);
+ node_append(mdoc, p);
mdoc->next = MDOC_NEXT_CHILD;
- return(1);
+ return(p);
}
-
-int
+struct mdoc_node *
mdoc_endbody_alloc(struct mdoc *mdoc, int line, int pos, enum mdoct tok,
struct mdoc_node *body, enum mdoc_endbody end)
{
struct mdoc_node *p;
+ body->flags |= MDOC_ENDED;
+ body->parent->flags |= MDOC_ENDED;
p = node_alloc(mdoc, line, pos, tok, MDOC_BODY);
- p->pending = body;
+ p->body = body;
p->norm = body->norm;
p->end = end;
- if ( ! node_append(mdoc, p))
- return(0);
+ node_append(mdoc, p);
mdoc->next = MDOC_NEXT_SIBLING;
- return(1);
+ return(p);
}
-
-int
-mdoc_block_alloc(struct mdoc *mdoc, int line, int pos,
+struct mdoc_node *
+mdoc_block_alloc(struct mdoc *mdoc, int line, int pos,
enum mdoct tok, struct mdoc_arg *args)
{
struct mdoc_node *p;
@@ -523,28 +442,27 @@ mdoc_block_alloc(struct mdoc *mdoc, int line, int pos,
(args->refcnt)++;
switch (tok) {
- case (MDOC_Bd):
+ case MDOC_Bd:
+ /* FALLTHROUGH */
+ case MDOC_Bf:
/* FALLTHROUGH */
- case (MDOC_Bf):
+ case MDOC_Bl:
/* FALLTHROUGH */
- case (MDOC_Bl):
+ case MDOC_En:
/* FALLTHROUGH */
- case (MDOC_Rs):
+ case MDOC_Rs:
p->norm = mandoc_calloc(1, sizeof(union mdoc_data));
break;
default:
break;
}
-
- if ( ! node_append(mdoc, p))
- return(0);
+ node_append(mdoc, p);
mdoc->next = MDOC_NEXT_CHILD;
- return(1);
+ return(p);
}
-
-int
-mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos,
+void
+mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos,
enum mdoct tok, struct mdoc_arg *args)
{
struct mdoc_node *p;
@@ -555,32 +473,25 @@ mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos,
(args->refcnt)++;
switch (tok) {
- case (MDOC_An):
+ case MDOC_An:
p->norm = mandoc_calloc(1, sizeof(union mdoc_data));
break;
default:
break;
}
-
- if ( ! node_append(mdoc, p))
- return(0);
+ node_append(mdoc, p);
mdoc->next = MDOC_NEXT_CHILD;
- return(1);
}
-int
+void
mdoc_word_alloc(struct mdoc *mdoc, int line, int pos, const char *p)
{
struct mdoc_node *n;
n = node_alloc(mdoc, line, pos, MDOC_MAX, MDOC_TEXT);
n->string = roff_strdup(mdoc->roff, p);
-
- if ( ! node_append(mdoc, n))
- return(0);
-
+ node_append(mdoc, n);
mdoc->next = MDOC_NEXT_SIBLING;
- return(1);
}
void
@@ -591,10 +502,7 @@ mdoc_word_append(struct mdoc *mdoc, const char *p)
n = mdoc->last;
addstr = roff_strdup(mdoc->roff, p);
- if (-1 == asprintf(&newstr, "%s %s", n->string, addstr)) {
- perror(NULL);
- exit((int)MANDOCLEVEL_SYSERR);
- }
+ mandoc_asprintf(&newstr, "%s %s", n->string, addstr);
free(addstr);
free(n->string);
n->string = newstr;
@@ -614,7 +522,6 @@ mdoc_node_free(struct mdoc_node *p)
free(p);
}
-
static void
mdoc_node_unlink(struct mdoc *mdoc, struct mdoc_node *n)
{
@@ -652,7 +559,6 @@ mdoc_node_unlink(struct mdoc *mdoc, struct mdoc_node *n)
mdoc->first = NULL;
}
-
void
mdoc_node_delete(struct mdoc *mdoc, struct mdoc_node *p)
{
@@ -667,67 +573,13 @@ mdoc_node_delete(struct mdoc *mdoc, struct mdoc_node *p)
mdoc_node_free(p);
}
-int
+void
mdoc_node_relink(struct mdoc *mdoc, struct mdoc_node *p)
{
mdoc_node_unlink(mdoc, p);
- return(node_append(mdoc, p));
-}
-
-#if 0
-/*
- * Pre-treat a text line.
- * Text lines can consist of equations, which must be handled apart from
- * the regular text.
- * Thus, use this function to step through a line checking if it has any
- * equations embedded in it.
- * This must handle multiple equations AND equations that do not end at
- * the end-of-line, i.e., will re-enter in the next roff parse.
- */
-static int
-mdoc_preptext(struct mdoc *mdoc, int line, char *buf, int offs)
-{
- char *start, *end;
- char delim;
-
- while ('\0' != buf[offs]) {
- /* Mark starting position if eqn is set. */
- start = NULL;
- if ('\0' != (delim = roff_eqndelim(mdoc->roff)))
- if (NULL != (start = strchr(buf + offs, delim)))
- *start++ = '\0';
-
- /* Parse text as normal. */
- if ( ! mdoc_ptext(mdoc, line, buf, offs))
- return(0);
-
- /* Continue only if an equation exists. */
- if (NULL == start)
- break;
-
- /* Read past the end of the equation. */
- offs += start - (buf + offs);
- assert(start == &buf[offs]);
- if (NULL != (end = strchr(buf + offs, delim))) {
- *end++ = '\0';
- while (' ' == *end)
- end++;
- }
-
- /* Parse the equation itself. */
- roff_openeqn(mdoc->roff, NULL, line, offs, buf);
-
- /* Process a finished equation? */
- if (roff_closeeqn(mdoc->roff))
- if ( ! mdoc_addeqn(mdoc, roff_eqn(mdoc->roff)))
- return(0);
- offs += (end - (buf + offs));
- }
-
- return(1);
+ node_append(mdoc, p);
}
-#endif
/*
* Parse free-form text, that is, a line that does not begin with the
@@ -739,13 +591,6 @@ mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs)
char *c, *ws, *end;
struct mdoc_node *n;
- /* No text before an initial macro. */
-
- if (SEC_NONE == mdoc->lastnamed) {
- mdoc_pmsg(mdoc, line, offs, MANDOCERR_NOTEXT);
- return(1);
- }
-
assert(mdoc->last);
n = mdoc->last;
@@ -756,20 +601,22 @@ mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs)
* process within its context in the normal way).
*/
- if (MDOC_Bl == n->tok && MDOC_BODY == n->type &&
- LIST_column == n->norm->Bl.type) {
+ if (n->tok == MDOC_Bl && n->type == MDOC_BODY &&
+ n->end == ENDBODY_NOT && n->norm->Bl.type == LIST_column) {
/* `Bl' is open without any children. */
mdoc->flags |= MDOC_FREECOL;
- return(mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf));
+ mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf);
+ return(1);
}
if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
- NULL != n->parent &&
- MDOC_Bl == n->parent->tok &&
- LIST_column == n->parent->norm->Bl.type) {
+ NULL != n->parent &&
+ MDOC_Bl == n->parent->tok &&
+ LIST_column == n->parent->norm->Bl.type) {
/* `Bl' has block-level `It' children. */
mdoc->flags |= MDOC_FREECOL;
- return(mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf));
+ mdoc_macro(mdoc, MDOC_It, line, offs, &offs, buf);
+ return(1);
}
/*
@@ -814,28 +661,27 @@ mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs)
*end = '\0';
if (ws)
- mdoc_pmsg(mdoc, line, (int)(ws-buf), MANDOCERR_EOLNSPACE);
+ mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
+ line, (int)(ws-buf), NULL);
- if ('\0' == buf[offs] && ! (MDOC_LITERAL & mdoc->flags)) {
- mdoc_pmsg(mdoc, line, (int)(c-buf), MANDOCERR_NOBLANKLN);
+ if (buf[offs] == '\0' && ! (mdoc->flags & MDOC_LITERAL)) {
+ mandoc_msg(MANDOCERR_FI_BLANK, mdoc->parse,
+ line, (int)(c - buf), NULL);
/*
* Insert a `sp' in the case of a blank line. Technically,
* blank lines aren't allowed, but enough manuals assume this
* behaviour that we want to work around it.
*/
- if ( ! mdoc_elem_alloc(mdoc, line, offs, MDOC_sp, NULL))
- return(0);
-
+ mdoc_elem_alloc(mdoc, line, offs, MDOC_sp, NULL);
mdoc->next = MDOC_NEXT_SIBLING;
-
- return(mdoc_valid_post(mdoc));
+ mdoc_valid_post(mdoc);
+ return(1);
}
- if ( ! mdoc_word_alloc(mdoc, line, offs, buf+offs))
- return(0);
+ mdoc_word_alloc(mdoc, line, offs, buf+offs);
- if (MDOC_LITERAL & mdoc->flags)
+ if (mdoc->flags & MDOC_LITERAL)
return(1);
/*
@@ -846,13 +692,11 @@ mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs)
assert(buf < end);
- if (mandoc_eos(buf+offs, (size_t)(end-buf-offs), 0))
+ if (mandoc_eos(buf+offs, (size_t)(end-buf-offs)))
mdoc->last->flags |= MDOC_EOS;
-
return(1);
}
-
/*
* Parse a macro line, that is, a line beginning with the control
* character.
@@ -860,58 +704,61 @@ mdoc_ptext(struct mdoc *mdoc, int line, char *buf, int offs)
static int
mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs)
{
+ struct mdoc_node *n;
+ const char *cp;
enum mdoct tok;
int i, sv;
char mac[5];
- struct mdoc_node *n;
-
- /* Empty post-control lines are ignored. */
-
- if ('"' == buf[offs]) {
- mdoc_pmsg(mdoc, ln, offs, MANDOCERR_BADCOMMENT);
- return(1);
- } else if ('\0' == buf[offs])
- return(1);
sv = offs;
- /*
+ /*
* Copy the first word into a nil-terminated buffer.
- * Stop copying when a tab, space, or eoln is encountered.
+ * Stop when a space, tab, escape, or eoln is encountered.
*/
i = 0;
- while (i < 4 && '\0' != buf[offs] &&
- ' ' != buf[offs] && '\t' != buf[offs])
+ while (i < 4 && strchr(" \t\\", buf[offs]) == NULL)
mac[i++] = buf[offs++];
mac[i] = '\0';
- tok = (i > 1 || i < 4) ? mdoc_hash_find(mac) : MDOC_MAX;
+ tok = (i > 1 && i < 4) ? mdoc_hash_find(mac) : MDOC_MAX;
- if (MDOC_MAX == tok) {
- mandoc_vmsg(MANDOCERR_MACRO, mdoc->parse,
- ln, sv, "%s", buf + sv - 1);
+ if (tok == MDOC_MAX) {
+ mandoc_msg(MANDOCERR_MACRO, mdoc->parse,
+ ln, sv, buf + sv - 1);
return(1);
}
- /* Disregard the first trailing tab, if applicable. */
+ /* Skip a leading escape sequence or tab. */
- if ('\t' == buf[offs])
+ switch (buf[offs]) {
+ case '\\':
+ cp = buf + offs + 1;
+ mandoc_escape(&cp, NULL, NULL);
+ offs = cp - buf;
+ break;
+ case '\t':
offs++;
+ break;
+ default:
+ break;
+ }
/* Jump to the next non-whitespace word. */
while (buf[offs] && ' ' == buf[offs])
offs++;
- /*
+ /*
* Trailing whitespace. Note that tabs are allowed to be passed
* into the parser as "text", so we only warn about spaces here.
*/
if ('\0' == buf[offs] && ' ' == buf[offs - 1])
- mdoc_pmsg(mdoc, ln, offs - 1, MANDOCERR_EOLNSPACE);
+ mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
+ ln, offs - 1, NULL);
/*
* If an initial macro or a list invocation, divert directly
@@ -919,8 +766,7 @@ mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs)
*/
if (NULL == mdoc->last || MDOC_It == tok || MDOC_El == tok) {
- if ( ! mdoc_macro(mdoc, tok, ln, sv, &offs, buf))
- goto err;
+ mdoc_macro(mdoc, tok, ln, sv, &offs, buf);
return(1);
}
@@ -932,11 +778,10 @@ mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs)
* context around the parsed macro.
*/
- if (MDOC_Bl == n->tok && MDOC_BODY == n->type &&
- LIST_column == n->norm->Bl.type) {
+ if (n->tok == MDOC_Bl && n->type == MDOC_BODY &&
+ n->end == ENDBODY_NOT && n->norm->Bl.type == LIST_column) {
mdoc->flags |= MDOC_FREECOL;
- if ( ! mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf))
- goto err;
+ mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf);
return(1);
}
@@ -947,26 +792,25 @@ mdoc_pmacro(struct mdoc *mdoc, int ln, char *buf, int offs)
*/
if (MDOC_It == n->tok && MDOC_BLOCK == n->type &&
- NULL != n->parent &&
- MDOC_Bl == n->parent->tok &&
- LIST_column == n->parent->norm->Bl.type) {
+ NULL != n->parent &&
+ MDOC_Bl == n->parent->tok &&
+ LIST_column == n->parent->norm->Bl.type) {
mdoc->flags |= MDOC_FREECOL;
- if ( ! mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf))
- goto err;
+ mdoc_macro(mdoc, MDOC_It, ln, sv, &sv, buf);
return(1);
}
/* Normal processing of a macro. */
- if ( ! mdoc_macro(mdoc, tok, ln, sv, &offs, buf))
- goto err;
+ mdoc_macro(mdoc, tok, ln, sv, &offs, buf);
- return(1);
+ /* In quick mode (for mandocdb), abort after the NAME section. */
-err: /* Error out. */
+ if (mdoc->quick && MDOC_Sh == tok &&
+ SEC_NAME != mdoc->last->sec)
+ return(2);
- mdoc->flags |= MDOC_HALT;
- return(0);
+ return(1);
}
enum mdelim
@@ -978,27 +822,27 @@ mdoc_isdelim(const char *p)
if ('\0' == p[1])
switch (p[0]) {
- case('('):
+ case '(':
/* FALLTHROUGH */
- case('['):
+ case '[':
return(DELIM_OPEN);
- case('|'):
+ case '|':
return(DELIM_MIDDLE);
- case('.'):
+ case '.':
/* FALLTHROUGH */
- case(','):
+ case ',':
/* FALLTHROUGH */
- case(';'):
+ case ';':
/* FALLTHROUGH */
- case(':'):
+ case ':':
/* FALLTHROUGH */
- case('?'):
+ case '?':
/* FALLTHROUGH */
- case('!'):
+ case '!':
/* FALLTHROUGH */
- case(')'):
+ case ')':
/* FALLTHROUGH */
- case(']'):
+ case ']':
return(DELIM_CLOSE);
default:
return(DELIM_NONE);
@@ -1014,3 +858,42 @@ mdoc_isdelim(const char *p)
return(DELIM_NONE);
}
+
+void
+mdoc_deroff(char **dest, const struct mdoc_node *n)
+{
+ char *cp;
+ size_t sz;
+
+ if (MDOC_TEXT != n->type) {
+ for (n = n->child; n; n = n->next)
+ mdoc_deroff(dest, n);
+ return;
+ }
+
+ /* Skip leading whitespace. */
+
+ for (cp = n->string; '\0' != *cp; cp++)
+ if (0 == isspace((unsigned char)*cp))
+ break;
+
+ /* Skip trailing whitespace. */
+
+ for (sz = strlen(cp); sz; sz--)
+ if (0 == isspace((unsigned char)cp[sz-1]))
+ break;
+
+ /* Skip empty strings. */
+
+ if (0 == sz)
+ return;
+
+ if (NULL == *dest) {
+ *dest = mandoc_strndup(cp, sz);
+ return;
+ }
+
+ mandoc_asprintf(&cp, "%s %*s", *dest, (int)sz, cp);
+ free(*dest);
+ *dest = cp;
+}
diff --git a/usr/src/cmd/mandoc/mdoc.h b/usr/src/cmd/mandoc/mdoc.h
index d0153b4480..e45786d4aa 100644
--- a/usr/src/cmd/mandoc/mdoc.h
+++ b/usr/src/cmd/mandoc/mdoc.h
@@ -1,6 +1,7 @@
-/* $Id: mdoc.h,v 1.125 2013/12/24 19:11:45 schwarze Exp $ */
+/* $Id: mdoc.h,v 1.136 2015/02/12 12:24:33 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014, 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
@@ -14,8 +15,6 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef MDOC_H
-#define MDOC_H
enum mdoct {
MDOC_Ap = 0,
@@ -140,6 +139,7 @@ enum mdoct {
MDOC_sp,
MDOC__U,
MDOC_Ta,
+ MDOC_ll,
MDOC_MAX
};
@@ -186,7 +186,7 @@ enum mdoc_type {
MDOC_ROOT
};
-/*
+/*
* Section (named/unnamed) of `Sh'. Note that these appear in the
* conventional order imposed by mdoc.7. In the case of SEC_NONE, no
* section has been invoked (this shouldn't happen). SEC_CUSTOM refers
@@ -198,6 +198,7 @@ enum mdoc_sec {
SEC_LIBRARY, /* LIBRARY */
SEC_SYNOPSIS, /* SYNOPSIS */
SEC_DESCRIPTION, /* DESCRIPTION */
+ SEC_CONTEXT, /* CONTEXT */
SEC_IMPLEMENTATION, /* IMPLEMENTATION NOTES */
SEC_RETURN_VALUES, /* RETURN VALUES */
SEC_ENVIRONMENT, /* ENVIRONMENT */
@@ -214,7 +215,7 @@ enum mdoc_sec {
SEC_CAVEATS, /* CAVEATS */
SEC_BUGS, /* BUGS */
SEC_SECURITY, /* SECURITY */
- SEC_CUSTOM,
+ SEC_CUSTOM,
SEC__MAX
};
@@ -228,11 +229,11 @@ struct mdoc_meta {
char *name; /* leading `Nm' name */
};
-/*
- * An argument to a macro (multiple values = `-column xxx yyy').
+/*
+ * An argument to a macro (multiple values = `-column xxx yyy').
*/
struct mdoc_argv {
- enum mdocargt arg; /* type of argument */
+ enum mdocargt arg; /* type of argument */
int line;
int pos;
size_t sz; /* elements in "value" */
@@ -244,7 +245,7 @@ struct mdoc_argv {
* blocks have multiple instances of the same arguments spread across
* the HEAD, BODY, TAIL, and BLOCK node types.
*/
-struct mdoc_arg {
+struct mdoc_arg {
size_t argc;
struct mdoc_argv *argv;
unsigned int refcnt;
@@ -278,7 +279,7 @@ enum mdoc_list {
enum mdoc_disp {
DISP__NONE = 0,
- DISP_centred, /* -centered */
+ DISP_centered, /* -centered */
DISP_ragged, /* -ragged */
DISP_unfilled, /* -unfilled */
DISP_filled, /* -filled */
@@ -332,15 +333,16 @@ struct mdoc_rs {
* provided, etc.
*/
union mdoc_data {
- struct mdoc_an An;
+ struct mdoc_an An;
struct mdoc_bd Bd;
struct mdoc_bf Bf;
struct mdoc_bl Bl;
+ struct mdoc_node *Es;
struct mdoc_rs Rs;
};
-/*
- * Single node in tree-linked AST.
+/*
+ * Single node in tree-linked AST.
*/
struct mdoc_node {
struct mdoc_node *parent; /* parent AST node */
@@ -351,25 +353,24 @@ struct mdoc_node {
int nchild; /* number children */
int line; /* parse line */
int pos; /* parse column */
- int lastline; /* the node ends on this line */
enum mdoct tok; /* tok or MDOC__MAX if none */
int flags;
#define MDOC_VALID (1 << 0) /* has been validated */
+#define MDOC_ENDED (1 << 1) /* gone past body end mark */
#define MDOC_EOS (1 << 2) /* at sentence boundary */
#define MDOC_LINE (1 << 3) /* first macro/text on line */
#define MDOC_SYNPRETTY (1 << 4) /* SYNOPSIS-style formatting */
-#define MDOC_ENDED (1 << 5) /* rendering has been ended */
+#define MDOC_BROKEN (1 << 5) /* must validate parent when ending */
#define MDOC_DELIMO (1 << 6)
#define MDOC_DELIMC (1 << 7)
enum mdoc_type type; /* AST node type */
enum mdoc_sec sec; /* current named section */
union mdoc_data *norm; /* normalised args */
- const void *prev_font; /* before entering this node */
+ int prev_font; /* before entering this node */
/* FIXME: these can be union'd to shave a few bytes. */
struct mdoc_arg *args; /* BLOCK/ELEM */
- struct mdoc_node *pending; /* BLOCK */
struct mdoc_node *head; /* BLOCK */
- struct mdoc_node *body; /* BLOCK */
+ struct mdoc_node *body; /* BLOCK/ENDBODY */
struct mdoc_node *tail; /* BLOCK */
char *string; /* TEXT */
const struct tbl_span *span; /* TBL */
@@ -389,7 +390,6 @@ struct mdoc;
const struct mdoc_node *mdoc_node(const struct mdoc *);
const struct mdoc_meta *mdoc_meta(const struct mdoc *);
+void mdoc_deroff(char **, const struct mdoc_node *);
__END_DECLS
-
-#endif /*!MDOC_H*/
diff --git a/usr/src/cmd/mandoc/mdoc_argv.c b/usr/src/cmd/mandoc/mdoc_argv.c
index bb9bc6c339..a53389bf99 100644
--- a/usr/src/cmd/mandoc/mdoc_argv.c
+++ b/usr/src/cmd/mandoc/mdoc_argv.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc_argv.c,v 1.89 2013/12/25 00:50:05 schwarze Exp $ */
+/* $Id: mdoc_argv.c,v 1.100 2015/02/04 18:59:45 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2012 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2012, 2014 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,9 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#include <sys/types.h>
@@ -28,11 +26,12 @@
#include "mdoc.h"
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libmdoc.h"
#include "libmandoc.h"
#define MULTI_STEP 5 /* pre-allocate argument values */
-#define DELIMSZ 6 /* max possible size of a delimiter */
+#define DELIMSZ 6 /* max possible size of a delimiter */
enum argsflag {
ARGSFL_NONE = 0,
@@ -52,12 +51,12 @@ struct mdocarg {
};
static void argn_free(struct mdoc_arg *, int);
-static enum margserr args(struct mdoc *, int, int *,
+static enum margserr args(struct mdoc *, int, int *,
char *, enum argsflag, char **);
static int args_checkpunct(const char *, int);
-static int argv_multi(struct mdoc *, int,
+static void argv_multi(struct mdoc *, int,
struct mdoc_argv *, int *, char *);
-static int argv_single(struct mdoc *, int,
+static void argv_single(struct mdoc *, int,
struct mdoc_argv *, int *, char *);
static const enum argvflag argvflags[MDOC_ARG_MAX] = {
@@ -149,8 +148,8 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_NONE, NULL }, /* Dt */
{ ARGSFL_NONE, NULL }, /* Os */
{ ARGSFL_NONE, NULL }, /* Sh */
- { ARGSFL_NONE, NULL }, /* Ss */
- { ARGSFL_NONE, NULL }, /* Pp */
+ { ARGSFL_NONE, NULL }, /* Ss */
+ { ARGSFL_NONE, NULL }, /* Pp */
{ ARGSFL_DELIM, NULL }, /* D1 */
{ ARGSFL_DELIM, NULL }, /* Dl */
{ ARGSFL_NONE, args_Bd }, /* Bd */
@@ -158,32 +157,32 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_NONE, args_Bl }, /* Bl */
{ ARGSFL_NONE, NULL }, /* El */
{ ARGSFL_NONE, NULL }, /* It */
- { ARGSFL_DELIM, NULL }, /* Ad */
+ { ARGSFL_DELIM, NULL }, /* Ad */
{ ARGSFL_DELIM, args_An }, /* An */
{ ARGSFL_DELIM, NULL }, /* Ar */
{ ARGSFL_DELIM, NULL }, /* Cd */
{ ARGSFL_DELIM, NULL }, /* Cm */
- { ARGSFL_DELIM, NULL }, /* Dv */
- { ARGSFL_DELIM, NULL }, /* Er */
- { ARGSFL_DELIM, NULL }, /* Ev */
+ { ARGSFL_DELIM, NULL }, /* Dv */
+ { ARGSFL_DELIM, NULL }, /* Er */
+ { ARGSFL_DELIM, NULL }, /* Ev */
{ ARGSFL_NONE, args_Ex }, /* Ex */
- { ARGSFL_DELIM, NULL }, /* Fa */
- { ARGSFL_NONE, NULL }, /* Fd */
+ { ARGSFL_DELIM, NULL }, /* Fa */
+ { ARGSFL_NONE, NULL }, /* Fd */
{ ARGSFL_DELIM, NULL }, /* Fl */
- { ARGSFL_DELIM, NULL }, /* Fn */
- { ARGSFL_DELIM, NULL }, /* Ft */
- { ARGSFL_DELIM, NULL }, /* Ic */
- { ARGSFL_DELIM, NULL }, /* In */
+ { ARGSFL_DELIM, NULL }, /* Fn */
+ { ARGSFL_DELIM, NULL }, /* Ft */
+ { ARGSFL_DELIM, NULL }, /* Ic */
+ { ARGSFL_DELIM, NULL }, /* In */
{ ARGSFL_DELIM, NULL }, /* Li */
- { ARGSFL_NONE, NULL }, /* Nd */
- { ARGSFL_DELIM, NULL }, /* Nm */
+ { ARGSFL_NONE, NULL }, /* Nd */
+ { ARGSFL_DELIM, NULL }, /* Nm */
{ ARGSFL_DELIM, NULL }, /* Op */
- { ARGSFL_NONE, NULL }, /* Ot */
+ { ARGSFL_DELIM, NULL }, /* Ot */
{ ARGSFL_DELIM, NULL }, /* Pa */
{ ARGSFL_NONE, args_Ex }, /* Rv */
- { ARGSFL_DELIM, NULL }, /* St */
+ { ARGSFL_DELIM, NULL }, /* St */
{ ARGSFL_DELIM, NULL }, /* Va */
- { ARGSFL_DELIM, NULL }, /* Vt */
+ { ARGSFL_DELIM, NULL }, /* Vt */
{ ARGSFL_DELIM, NULL }, /* Xr */
{ ARGSFL_NONE, NULL }, /* %A */
{ ARGSFL_NONE, NULL }, /* %B */
@@ -201,7 +200,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_DELIM, NULL }, /* Aq */
{ ARGSFL_DELIM, NULL }, /* At */
{ ARGSFL_DELIM, NULL }, /* Bc */
- { ARGSFL_NONE, args_Bf }, /* Bf */
+ { ARGSFL_NONE, args_Bf }, /* Bf */
{ ARGSFL_NONE, NULL }, /* Bo */
{ ARGSFL_DELIM, NULL }, /* Bq */
{ ARGSFL_DELIM, NULL }, /* Bsx */
@@ -212,7 +211,7 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_DELIM, NULL }, /* Dq */
{ ARGSFL_DELIM, NULL }, /* Ec */
{ ARGSFL_NONE, NULL }, /* Ef */
- { ARGSFL_DELIM, NULL }, /* Em */
+ { ARGSFL_DELIM, NULL }, /* Em */
{ ARGSFL_NONE, NULL }, /* Eo */
{ ARGSFL_DELIM, NULL }, /* Fx */
{ ARGSFL_DELIM, NULL }, /* Ms */
@@ -240,15 +239,15 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_DELIM, NULL }, /* Ux */
{ ARGSFL_DELIM, NULL }, /* Xc */
{ ARGSFL_NONE, NULL }, /* Xo */
- { ARGSFL_NONE, NULL }, /* Fo */
- { ARGSFL_DELIM, NULL }, /* Fc */
+ { ARGSFL_NONE, NULL }, /* Fo */
+ { ARGSFL_DELIM, NULL }, /* Fc */
{ ARGSFL_NONE, NULL }, /* Oo */
{ ARGSFL_DELIM, NULL }, /* Oc */
{ ARGSFL_NONE, args_Bk }, /* Bk */
{ ARGSFL_NONE, NULL }, /* Ek */
{ ARGSFL_NONE, NULL }, /* Bt */
{ ARGSFL_NONE, NULL }, /* Hf */
- { ARGSFL_NONE, NULL }, /* Fr */
+ { ARGSFL_DELIM, NULL }, /* Fr */
{ ARGSFL_NONE, NULL }, /* Ud */
{ ARGSFL_DELIM, NULL }, /* Lb */
{ ARGSFL_NONE, NULL }, /* Lp */
@@ -259,111 +258,117 @@ static const struct mdocarg mdocargs[MDOC_MAX] = {
{ ARGSFL_DELIM, NULL }, /* Brc */
{ ARGSFL_NONE, NULL }, /* %C */
{ ARGSFL_NONE, NULL }, /* Es */
- { ARGSFL_NONE, NULL }, /* En */
+ { 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 */
};
/*
- * Parse an argument from line text. This comes in the form of -key
- * [value0...], which may either have a single mandatory value, at least
- * one mandatory value, an optional single value, or no value.
+ * Parse flags and their arguments from the input line.
+ * These come in the form -flag [argument ...].
+ * Some flags take no argument, some one, some multiple.
*/
-enum margverr
+void
mdoc_argv(struct mdoc *mdoc, int line, enum mdoct tok,
- struct mdoc_arg **v, int *pos, char *buf)
+ struct mdoc_arg **reta, int *pos, char *buf)
{
- char *p, sv;
- struct mdoc_argv tmp;
- struct mdoc_arg *arg;
- const enum mdocargt *ap;
+ struct mdoc_argv tmpv;
+ struct mdoc_argv **retv;
+ const enum mdocargt *argtable;
+ char *argname;
+ int ipos, retc;
+ char savechar;
- if ('\0' == buf[*pos])
- return(ARGV_EOLN);
- else if (NULL == (ap = mdocargs[tok].argvs))
- return(ARGV_WORD);
- else if ('-' != buf[*pos])
- return(ARGV_WORD);
+ *reta = NULL;
- /* Seek to the first unescaped space. */
+ /* Which flags does this macro support? */
- p = &buf[++(*pos)];
+ argtable = mdocargs[tok].argvs;
+ if (argtable == NULL)
+ return;
- assert(*pos > 0);
+ /* Loop over the flags on the input line. */
- for ( ; buf[*pos] ; (*pos)++)
- if (' ' == buf[*pos] && '\\' != buf[*pos - 1])
- break;
+ ipos = *pos;
+ while (buf[ipos] == '-') {
- /*
- * We want to nil-terminate the word to look it up (it's easier
- * that way). But we may not have a flag, in which case we need
- * to restore the line as-is. So keep around the stray byte,
- * which we'll reset upon exiting (if necessary).
- */
+ /* Seek to the first unescaped space. */
- if ('\0' != (sv = buf[*pos]))
- buf[(*pos)++] = '\0';
+ for (argname = buf + ++ipos; buf[ipos] != '\0'; ipos++)
+ if (buf[ipos] == ' ' && buf[ipos - 1] != '\\')
+ break;
- /*
- * Now look up the word as a flag. Use temporary storage that
- * we'll copy into the node's flags, if necessary.
- */
+ /*
+ * We want to nil-terminate the word to look it up.
+ * But we may not have a flag, in which case we need
+ * to restore the line as-is. So keep around the
+ * stray byte, which we'll reset upon exiting.
+ */
- memset(&tmp, 0, sizeof(struct mdoc_argv));
+ if ((savechar = buf[ipos]) != '\0')
+ buf[ipos++] = '\0';
- tmp.line = line;
- tmp.pos = *pos;
- tmp.arg = MDOC_ARG_MAX;
+ /*
+ * Now look up the word as a flag. Use temporary
+ * storage that we'll copy into the node's flags.
+ */
- while (MDOC_ARG_MAX != (tmp.arg = *ap++))
- if (0 == strcmp(p, mdoc_argnames[tmp.arg]))
+ while ((tmpv.arg = *argtable++) != MDOC_ARG_MAX)
+ if ( ! strcmp(argname, mdoc_argnames[tmpv.arg]))
+ break;
+
+ /* If it isn't a flag, restore the saved byte. */
+
+ if (tmpv.arg == MDOC_ARG_MAX) {
+ if (savechar != '\0')
+ buf[ipos - 1] = savechar;
break;
+ }
- if (MDOC_ARG_MAX == tmp.arg) {
- /*
- * The flag was not found.
- * Restore saved zeroed byte and return as a word.
- */
- if (sv)
- buf[*pos - 1] = sv;
- return(ARGV_WORD);
- }
+ /* Read to the next word (the first argument). */
- /* Read to the next word (the argument). */
-
- while (buf[*pos] && ' ' == buf[*pos])
- (*pos)++;
-
- switch (argvflags[tmp.arg]) {
- case (ARGV_SINGLE):
- if ( ! argv_single(mdoc, line, &tmp, pos, buf))
- return(ARGV_ERROR);
- break;
- case (ARGV_MULTI):
- if ( ! argv_multi(mdoc, line, &tmp, pos, buf))
- return(ARGV_ERROR);
- break;
- case (ARGV_NONE):
- break;
- }
+ while (buf[ipos] == ' ')
+ ipos++;
- if (NULL == (arg = *v))
- arg = *v = mandoc_calloc(1, sizeof(struct mdoc_arg));
+ /* Parse the arguments of the flag. */
+
+ tmpv.line = line;
+ tmpv.pos = *pos;
+ tmpv.sz = 0;
+ tmpv.value = NULL;
+
+ switch (argvflags[tmpv.arg]) {
+ case ARGV_SINGLE:
+ argv_single(mdoc, line, &tmpv, &ipos, buf);
+ break;
+ case ARGV_MULTI:
+ argv_multi(mdoc, line, &tmpv, &ipos, buf);
+ break;
+ case ARGV_NONE:
+ break;
+ }
- arg->argc++;
- arg->argv = mandoc_realloc
- (arg->argv, arg->argc * sizeof(struct mdoc_argv));
+ /* Append to the return values. */
- memcpy(&arg->argv[(int)arg->argc - 1],
- &tmp, sizeof(struct mdoc_argv));
+ if (*reta == NULL)
+ *reta = mandoc_calloc(1, sizeof(**reta));
- return(ARGV_ARG);
+ retc = ++(*reta)->argc;
+ retv = &(*reta)->argv;
+ *retv = mandoc_reallocarray(*retv, retc, sizeof(**retv));
+ memcpy(*retv + retc - 1, &tmpv, sizeof(**retv));
+
+ /* Prepare for parsing the next flag. */
+
+ *pos = ipos;
+ argtable = mdocargs[tok].argvs;
+ }
}
void
@@ -397,7 +402,7 @@ argn_free(struct mdoc_arg *p, int iarg)
arg = &p->argv[iarg];
if (arg->sz && arg->value) {
- for (j = (int)arg->sz - 1; j >= 0; j--)
+ for (j = (int)arg->sz - 1; j >= 0; j--)
free(arg->value[j]);
free(arg->value);
}
@@ -407,22 +412,17 @@ argn_free(struct mdoc_arg *p, int iarg)
}
enum margserr
-mdoc_zargs(struct mdoc *mdoc, int line, int *pos, char *buf, char **v)
-{
-
- return(args(mdoc, line, pos, buf, ARGSFL_NONE, v));
-}
-
-enum margserr
-mdoc_args(struct mdoc *mdoc, int line, int *pos,
+mdoc_args(struct mdoc *mdoc, int line, int *pos,
char *buf, enum mdoct tok, char **v)
{
- enum argsflag fl;
struct mdoc_node *n;
+ char *v_local;
+ enum argsflag fl;
- fl = mdocargs[tok].flags;
-
- if (MDOC_It != tok)
+ if (v == NULL)
+ v = &v_local;
+ fl = tok == MDOC_MAX ? ARGSFL_NONE : mdocargs[tok].flags;
+ if (tok != MDOC_It)
return(args(mdoc, line, pos, buf, fl, v));
/*
@@ -443,7 +443,7 @@ mdoc_args(struct mdoc *mdoc, int line, int *pos,
}
static enum margserr
-args(struct mdoc *mdoc, int line, int *pos,
+args(struct mdoc *mdoc, int line, int *pos,
char *buf, enum argsflag fl, char **v)
{
char *p, *pp;
@@ -459,7 +459,8 @@ args(struct mdoc *mdoc, int line, int *pos,
* is unterminated.
*/
if (MDOC_PHRASELIT & mdoc->flags)
- mdoc_pmsg(mdoc, line, *pos, MANDOCERR_BADQUOTE);
+ mandoc_msg(MANDOCERR_ARG_QUOTE,
+ mdoc->parse, line, *pos, NULL);
mdoc->flags &= ~MDOC_PHRASELIT;
return(ARGS_EOLN);
@@ -484,7 +485,7 @@ args(struct mdoc *mdoc, int line, int *pos,
pp = NULL;
/* Scan ahead to unescaped `Ta'. */
- if ( ! (MDOC_PHRASELIT & mdoc->flags))
+ if ( ! (MDOC_PHRASELIT & mdoc->flags))
for (pp = *v; ; pp++) {
if (NULL == (pp = strstr(pp, "Ta")))
break;
@@ -497,7 +498,7 @@ args(struct mdoc *mdoc, int line, int *pos,
/* By default, assume a phrase. */
rc = ARGS_PHRASE;
- /*
+ /*
* Adjust new-buffer position to be beyond delimiter
* mark (e.g., Ta -> end + 2).
*/
@@ -518,7 +519,8 @@ args(struct mdoc *mdoc, int line, int *pos,
/* Whitespace check for eoln case... */
if ('\0' == *p && ' ' == *(p - 1))
- mdoc_pmsg(mdoc, line, *pos, MANDOCERR_EOLNSPACE);
+ mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
+ line, *pos, NULL);
*pos += (int)(p - *v);
@@ -573,7 +575,8 @@ args(struct mdoc *mdoc, int line, int *pos,
if ('\0' == buf[*pos]) {
if (MDOC_PPHRASE & mdoc->flags)
return(ARGS_QWORD);
- mdoc_pmsg(mdoc, line, *pos, MANDOCERR_BADQUOTE);
+ mandoc_msg(MANDOCERR_ARG_QUOTE,
+ mdoc->parse, line, *pos, NULL);
return(ARGS_QWORD);
}
@@ -587,7 +590,8 @@ args(struct mdoc *mdoc, int line, int *pos,
(*pos)++;
if ('\0' == buf[*pos])
- mdoc_pmsg(mdoc, line, *pos, MANDOCERR_EOLNSPACE);
+ mandoc_msg(MANDOCERR_SPACE_EOL, mdoc->parse,
+ line, *pos, NULL);
return(ARGS_QWORD);
}
@@ -598,7 +602,7 @@ args(struct mdoc *mdoc, int line, int *pos,
return(ARGS_WORD);
}
-/*
+/*
* Check if the string consists only of space-separated closing
* delimiters. This is a bit of a dance: the first must be a close
* delimiter, but it may be followed by middle delimiters. Arbitrary
@@ -627,7 +631,7 @@ args_checkpunct(const char *buf, int i)
i++;
/* Remaining must NOT be open/none. */
-
+
while (buf[i]) {
j = 0;
while (buf[i] && ' ' != buf[i] && j < DELIMSZ)
@@ -648,48 +652,40 @@ args_checkpunct(const char *buf, int i)
return('\0' == buf[i]);
}
-static int
-argv_multi(struct mdoc *mdoc, int line,
+static void
+argv_multi(struct mdoc *mdoc, int line,
struct mdoc_argv *v, int *pos, char *buf)
{
enum margserr ac;
char *p;
for (v->sz = 0; ; v->sz++) {
- if ('-' == buf[*pos])
+ if (buf[*pos] == '-')
break;
ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p);
- if (ARGS_ERROR == ac)
- return(0);
- else if (ARGS_EOLN == ac)
+ if (ac == ARGS_EOLN)
break;
- if (0 == v->sz % MULTI_STEP)
- v->value = mandoc_realloc(v->value,
- (v->sz + MULTI_STEP) * sizeof(char *));
+ if (v->sz % MULTI_STEP == 0)
+ v->value = mandoc_reallocarray(v->value,
+ v->sz + MULTI_STEP, sizeof(char *));
v->value[(int)v->sz] = mandoc_strdup(p);
}
-
- return(1);
}
-static int
-argv_single(struct mdoc *mdoc, int line,
+static void
+argv_single(struct mdoc *mdoc, int line,
struct mdoc_argv *v, int *pos, char *buf)
{
enum margserr ac;
char *p;
ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p);
- if (ARGS_ERROR == ac)
- return(0);
- if (ARGS_EOLN == ac)
- return(1);
+ if (ac == ARGS_EOLN)
+ return;
v->sz = 1;
v->value = mandoc_malloc(sizeof(char *));
v->value[0] = mandoc_strdup(p);
-
- return(1);
}
diff --git a/usr/src/cmd/mandoc/mdoc_hash.c b/usr/src/cmd/mandoc/mdoc_hash.c
index 59a8d26a88..5e34fe8f58 100644
--- a/usr/src/cmd/mandoc/mdoc_hash.c
+++ b/usr/src/cmd/mandoc/mdoc_hash.c
@@ -1,4 +1,4 @@
-/* $Id: mdoc_hash.c,v 1.18 2011/07/24 18:15:14 kristaps Exp $ */
+/* $Id: mdoc_hash.c,v 1.21 2014/08/10 23:54:41 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -14,9 +14,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#include <sys/types.h>
@@ -28,11 +26,11 @@
#include <string.h>
#include "mdoc.h"
-#include "mandoc.h"
#include "libmdoc.h"
static unsigned char table[27 * 12];
+
/*
* XXX - this hash has global scope, so if intended for use as a library
* with multiple callers, it will need re-invocation protection.
@@ -77,7 +75,7 @@ mdoc_hash_find(const char *p)
major = 12 * (tolower((unsigned char)p[1]) - 97);
else if ('1' == p[1])
major = 12 * 26;
- else
+ else
return(MDOC_MAX);
if (p[2] && p[3])
diff --git a/usr/src/cmd/mandoc/mdoc_html.c b/usr/src/cmd/mandoc/mdoc_html.c
index a7aa722d94..fba7fb6fa4 100644
--- a/usr/src/cmd/mandoc/mdoc_html.c
+++ b/usr/src/cmd/mandoc/mdoc_html.c
@@ -1,6 +1,7 @@
-/* $Id: mdoc_html.c,v 1.186 2013/12/24 20:45:27 schwarze Exp $ */
+/* $Id: mdoc_html.c,v 1.226 2015/03/03 21:11:34 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014, 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
@@ -14,9 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#include <sys/types.h>
@@ -27,16 +26,16 @@
#include <string.h>
#include <unistd.h>
-#include "mandoc.h"
+#include "mandoc_aux.h"
+#include "mdoc.h"
#include "out.h"
#include "html.h"
-#include "mdoc.h"
#include "main.h"
#define INDENT 5
#define MDOC_ARGS const struct mdoc_meta *meta, \
- const struct mdoc_node *n, \
+ struct mdoc_node *n, \
struct html *h
#ifndef MIN
@@ -52,11 +51,10 @@ static void print_mdoc(MDOC_ARGS);
static void print_mdoc_head(MDOC_ARGS);
static void print_mdoc_node(MDOC_ARGS);
static void print_mdoc_nodelist(MDOC_ARGS);
-static void synopsis_pre(struct html *,
+static void synopsis_pre(struct html *,
const struct mdoc_node *);
static void a2width(const char *, struct roffsu *);
-static void a2offs(const char *, struct roffsu *);
static void mdoc_root_post(MDOC_ARGS);
static int mdoc_root_pre(MDOC_ARGS);
@@ -83,6 +81,8 @@ static int mdoc_fl_pre(MDOC_ARGS);
static int mdoc_fn_pre(MDOC_ARGS);
static int mdoc_ft_pre(MDOC_ARGS);
static int mdoc_em_pre(MDOC_ARGS);
+static void mdoc_eo_post(MDOC_ARGS);
+static int mdoc_eo_pre(MDOC_ARGS);
static int mdoc_er_pre(MDOC_ARGS);
static int mdoc_ev_pre(MDOC_ARGS);
static int mdoc_ex_pre(MDOC_ARGS);
@@ -99,6 +99,7 @@ static int mdoc_mt_pre(MDOC_ARGS);
static int mdoc_ms_pre(MDOC_ARGS);
static int mdoc_nd_pre(MDOC_ARGS);
static int mdoc_nm_pre(MDOC_ARGS);
+static int mdoc_no_pre(MDOC_ARGS);
static int mdoc_ns_pre(MDOC_ARGS);
static int mdoc_pa_pre(MDOC_ARGS);
static void mdoc_pf_post(MDOC_ARGS);
@@ -108,6 +109,7 @@ static int mdoc_quote_pre(MDOC_ARGS);
static int mdoc_rs_pre(MDOC_ARGS);
static int mdoc_rv_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);
@@ -125,8 +127,8 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = {
{NULL, NULL}, /* Dt */
{NULL, NULL}, /* Os */
{mdoc_sh_pre, NULL }, /* Sh */
- {mdoc_ss_pre, NULL }, /* Ss */
- {mdoc_pp_pre, NULL}, /* Pp */
+ {mdoc_ss_pre, NULL }, /* Ss */
+ {mdoc_pp_pre, NULL}, /* Pp */
{mdoc_d1_pre, NULL}, /* D1 */
{mdoc_d1_pre, NULL}, /* Dl */
{mdoc_bd_pre, NULL}, /* Bd */
@@ -134,32 +136,32 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = {
{mdoc_bl_pre, NULL}, /* Bl */
{NULL, NULL}, /* El */
{mdoc_it_pre, NULL}, /* It */
- {mdoc_ad_pre, NULL}, /* Ad */
+ {mdoc_ad_pre, NULL}, /* Ad */
{mdoc_an_pre, NULL}, /* An */
{mdoc_ar_pre, NULL}, /* Ar */
{mdoc_cd_pre, NULL}, /* Cd */
{mdoc_fl_pre, NULL}, /* Cm */
- {mdoc_dv_pre, NULL}, /* Dv */
- {mdoc_er_pre, NULL}, /* Er */
- {mdoc_ev_pre, NULL}, /* Ev */
+ {mdoc_dv_pre, NULL}, /* Dv */
+ {mdoc_er_pre, NULL}, /* Er */
+ {mdoc_ev_pre, NULL}, /* Ev */
{mdoc_ex_pre, NULL}, /* Ex */
- {mdoc_fa_pre, NULL}, /* Fa */
- {mdoc_fd_pre, NULL}, /* Fd */
+ {mdoc_fa_pre, NULL}, /* Fa */
+ {mdoc_fd_pre, NULL}, /* Fd */
{mdoc_fl_pre, NULL}, /* Fl */
- {mdoc_fn_pre, NULL}, /* Fn */
- {mdoc_ft_pre, NULL}, /* Ft */
- {mdoc_ic_pre, NULL}, /* Ic */
- {mdoc_in_pre, NULL}, /* In */
+ {mdoc_fn_pre, NULL}, /* Fn */
+ {mdoc_ft_pre, NULL}, /* Ft */
+ {mdoc_ic_pre, NULL}, /* Ic */
+ {mdoc_in_pre, NULL}, /* In */
{mdoc_li_pre, NULL}, /* Li */
- {mdoc_nd_pre, NULL}, /* Nd */
- {mdoc_nm_pre, NULL}, /* Nm */
+ {mdoc_nd_pre, NULL}, /* Nd */
+ {mdoc_nm_pre, NULL}, /* Nm */
{mdoc_quote_pre, mdoc_quote_post}, /* Op */
- {NULL, NULL}, /* Ot */
+ {mdoc_ft_pre, NULL}, /* Ot */
{mdoc_pa_pre, NULL}, /* Pa */
{mdoc_rv_pre, NULL}, /* Rv */
- {NULL, NULL}, /* St */
+ {NULL, NULL}, /* St */
{mdoc_va_pre, NULL}, /* Va */
- {mdoc_vt_pre, NULL}, /* Vt */
+ {mdoc_vt_pre, NULL}, /* Vt */
{mdoc_xr_pre, NULL}, /* Xr */
{mdoc__x_pre, mdoc__x_post}, /* %A */
{mdoc__x_pre, mdoc__x_post}, /* %B */
@@ -177,22 +179,22 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = {
{mdoc_quote_pre, mdoc_quote_post}, /* Aq */
{NULL, NULL}, /* At */
{NULL, NULL}, /* Bc */
- {mdoc_bf_pre, NULL}, /* Bf */
+ {mdoc_bf_pre, NULL}, /* Bf */
{mdoc_quote_pre, mdoc_quote_post}, /* Bo */
{mdoc_quote_pre, mdoc_quote_post}, /* Bq */
{mdoc_xx_pre, NULL}, /* Bsx */
{mdoc_bx_pre, NULL}, /* Bx */
- {NULL, NULL}, /* Db */
+ {mdoc_skip_pre, NULL}, /* Db */
{NULL, NULL}, /* Dc */
{mdoc_quote_pre, mdoc_quote_post}, /* Do */
{mdoc_quote_pre, mdoc_quote_post}, /* Dq */
{NULL, NULL}, /* Ec */ /* FIXME: no space */
{NULL, NULL}, /* Ef */
- {mdoc_em_pre, NULL}, /* Em */
- {mdoc_quote_pre, mdoc_quote_post}, /* Eo */
+ {mdoc_em_pre, NULL}, /* Em */
+ {mdoc_eo_pre, mdoc_eo_post}, /* Eo */
{mdoc_xx_pre, NULL}, /* Fx */
{mdoc_ms_pre, NULL}, /* Ms */
- {mdoc_igndelim_pre, NULL}, /* No */
+ {mdoc_no_pre, NULL}, /* No */
{mdoc_ns_pre, NULL}, /* Ns */
{mdoc_xx_pre, NULL}, /* Nx */
{mdoc_xx_pre, NULL}, /* Ox */
@@ -209,39 +211,40 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = {
{NULL, NULL}, /* Sc */
{mdoc_quote_pre, mdoc_quote_post}, /* So */
{mdoc_quote_pre, mdoc_quote_post}, /* Sq */
- {mdoc_sm_pre, NULL}, /* Sm */
+ {mdoc_sm_pre, NULL}, /* Sm */
{mdoc_sx_pre, NULL}, /* Sx */
{mdoc_sy_pre, NULL}, /* Sy */
{NULL, NULL}, /* Tn */
{mdoc_xx_pre, NULL}, /* Ux */
{NULL, NULL}, /* Xc */
{NULL, NULL}, /* Xo */
- {mdoc_fo_pre, mdoc_fo_post}, /* Fo */
- {NULL, NULL}, /* Fc */
+ {mdoc_fo_pre, mdoc_fo_post}, /* Fo */
+ {NULL, NULL}, /* Fc */
{mdoc_quote_pre, mdoc_quote_post}, /* Oo */
{NULL, NULL}, /* Oc */
{mdoc_bk_pre, mdoc_bk_post}, /* Bk */
{NULL, NULL}, /* Ek */
{mdoc_bt_pre, NULL}, /* Bt */
{NULL, NULL}, /* Hf */
- {NULL, NULL}, /* Fr */
+ {mdoc_em_pre, NULL}, /* Fr */
{mdoc_ud_pre, NULL}, /* Ud */
{mdoc_lb_pre, NULL}, /* Lb */
- {mdoc_pp_pre, NULL}, /* Lp */
- {mdoc_lk_pre, NULL}, /* Lk */
- {mdoc_mt_pre, NULL}, /* Mt */
- {mdoc_quote_pre, mdoc_quote_post}, /* Brq */
- {mdoc_quote_pre, mdoc_quote_post}, /* Bro */
- {NULL, NULL}, /* Brc */
- {mdoc__x_pre, mdoc__x_post}, /* %C */
- {NULL, NULL}, /* Es */ /* TODO */
- {NULL, NULL}, /* En */ /* TODO */
- {mdoc_xx_pre, NULL}, /* Dx */
- {mdoc__x_pre, mdoc__x_post}, /* %Q */
+ {mdoc_pp_pre, NULL}, /* Lp */
+ {mdoc_lk_pre, NULL}, /* Lk */
+ {mdoc_mt_pre, NULL}, /* Mt */
+ {mdoc_quote_pre, mdoc_quote_post}, /* Brq */
+ {mdoc_quote_pre, mdoc_quote_post}, /* Bro */
+ {NULL, NULL}, /* Brc */
+ {mdoc__x_pre, mdoc__x_post}, /* %C */
+ {mdoc_skip_pre, NULL}, /* Es */
+ {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_sp_pre, NULL}, /* sp */
+ {mdoc__x_pre, mdoc__x_post}, /* %U */
+ {NULL, NULL}, /* Ta */
+ {mdoc_skip_pre, NULL}, /* ll */
};
static const char * const lists[LIST_MAX] = {
@@ -259,16 +262,16 @@ static const char * const lists[LIST_MAX] = {
"list-tag"
};
+
void
html_mdoc(void *arg, const struct mdoc *mdoc)
{
- print_mdoc(mdoc_meta(mdoc), mdoc_node(mdoc),
- (struct html *)arg);
+ print_mdoc(mdoc_meta(mdoc), mdoc_node(mdoc)->child,
+ (struct html *)arg);
putchar('\n');
}
-
/*
* Calculate the scaling unit passed in a `-width' argument. This uses
* either a native scaling unit (e.g., 1i, 2m) or the string length of
@@ -278,13 +281,13 @@ static void
a2width(const char *p, struct roffsu *su)
{
- if ( ! a2roffsu(p, su, SCALE_MAX)) {
- su->unit = SCALE_BU;
+ if (a2roffsu(p, su, SCALE_MAX) < 2) {
+ su->unit = SCALE_EN;
su->scale = html_strlen(p);
- }
+ } else if (su->scale < 0.0)
+ su->scale = 0.0;
}
-
/*
* See the same function in mdoc_term.c for documentation.
*/
@@ -295,29 +298,29 @@ synopsis_pre(struct html *h, const struct mdoc_node *n)
if (NULL == n->prev || ! (MDOC_SYNPRETTY & n->flags))
return;
- if (n->prev->tok == n->tok &&
- MDOC_Fo != n->tok &&
- MDOC_Ft != n->tok &&
- MDOC_Fn != n->tok) {
+ if (n->prev->tok == n->tok &&
+ MDOC_Fo != n->tok &&
+ MDOC_Ft != n->tok &&
+ MDOC_Fn != n->tok) {
print_otag(h, TAG_BR, 0, NULL);
return;
}
switch (n->prev->tok) {
- case (MDOC_Fd):
+ case MDOC_Fd:
/* FALLTHROUGH */
- case (MDOC_Fn):
+ case MDOC_Fn:
/* FALLTHROUGH */
- case (MDOC_Fo):
+ case MDOC_Fo:
/* FALLTHROUGH */
- case (MDOC_In):
+ case MDOC_In:
/* FALLTHROUGH */
- case (MDOC_Vt):
- print_otag(h, TAG_P, 0, NULL);
+ case MDOC_Vt:
+ print_paragraph(h);
break;
- case (MDOC_Ft):
+ case MDOC_Ft:
if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
- print_otag(h, TAG_P, 0, NULL);
+ print_paragraph(h);
break;
}
/* FALLTHROUGH */
@@ -327,29 +330,6 @@ synopsis_pre(struct html *h, const struct mdoc_node *n)
}
}
-
-/*
- * Calculate the scaling unit passed in an `-offset' argument. This
- * uses either a native scaling unit (e.g., 1i, 2m), one of a set of
- * predefined strings (indent, etc.), or the string length of the value.
- */
-static void
-a2offs(const char *p, struct roffsu *su)
-{
-
- /* FIXME: "right"? */
-
- if (0 == strcmp(p, "left"))
- SCALE_HS_INIT(su, 0);
- else if (0 == strcmp(p, "indent"))
- SCALE_HS_INIT(su, INDENT);
- else if (0 == strcmp(p, "indent-two"))
- SCALE_HS_INIT(su, INDENT * 2);
- else if ( ! a2roffsu(p, su, SCALE_MAX))
- SCALE_HS_INIT(su, html_strlen(p));
-}
-
-
static void
print_mdoc(MDOC_ARGS)
{
@@ -366,23 +346,22 @@ print_mdoc(MDOC_ARGS)
print_tagq(h, tt);
print_otag(h, TAG_BODY, 0, NULL);
print_otag(h, TAG_DIV, 1, &tag);
- } else
+ } else
t = print_otag(h, TAG_DIV, 1, &tag);
print_mdoc_nodelist(meta, n, h);
print_tagq(h, t);
}
-
-/* ARGSUSED */
static void
print_mdoc_head(MDOC_ARGS)
{
print_gen_head(h);
bufinit(h);
- bufcat_fmt(h, "%s(%s)", meta->title, meta->msec);
-
+ bufcat(h, meta->title);
+ if (meta->msec)
+ bufcat_fmt(h, "(%s)", meta->msec);
if (meta->arch)
bufcat_fmt(h, " (%s)", meta->arch);
@@ -390,17 +369,16 @@ print_mdoc_head(MDOC_ARGS)
print_text(h, h->buf);
}
-
static void
print_mdoc_nodelist(MDOC_ARGS)
{
- print_mdoc_node(meta, n, h);
- if (n->next)
- print_mdoc_nodelist(meta, n->next, h);
+ while (n != NULL) {
+ print_mdoc_node(meta, n, h);
+ n = n->next;
+ }
}
-
static void
print_mdoc_node(MDOC_ARGS)
{
@@ -409,12 +387,13 @@ print_mdoc_node(MDOC_ARGS)
child = 1;
t = h->tags.head;
+ n->flags &= ~MDOC_ENDED;
switch (n->type) {
- case (MDOC_ROOT):
+ case MDOC_ROOT:
child = mdoc_root_pre(meta, n, h);
break;
- case (MDOC_TEXT):
+ case MDOC_TEXT:
/* No tables in this mode... */
assert(NULL == h->tblt);
@@ -431,10 +410,12 @@ print_mdoc_node(MDOC_ARGS)
if (MDOC_DELIMO & n->flags)
h->flags |= HTML_NOSPACE;
return;
- case (MDOC_EQN):
+ case MDOC_EQN:
+ if (n->flags & MDOC_LINE)
+ putchar('\n');
print_eqn(h, n->eqn);
break;
- case (MDOC_TBL):
+ case MDOC_TBL:
/*
* This will take care of initialising all of the table
* state data for the first table, then tearing it down
@@ -448,23 +429,19 @@ print_mdoc_node(MDOC_ARGS)
* the "meta" table state. This will be reopened on the
* next table element.
*/
- if (h->tblt) {
+ if (h->tblt != NULL) {
print_tblclose(h);
t = h->tags.head;
}
-
- assert(NULL == h->tblt);
- if (mdocs[n->tok].pre && ENDBODY_NOT == n->end)
+ assert(h->tblt == NULL);
+ if (mdocs[n->tok].pre && (n->end == ENDBODY_NOT || n->child))
child = (*mdocs[n->tok].pre)(meta, n, h);
break;
}
- if (HTML_KEEP & h->flags) {
- if (n->prev ? (n->prev->lastline != n->line) :
- (n->parent && n->parent->line != n->line)) {
- h->flags &= ~HTML_KEEP;
- h->flags |= HTML_PREKEEP;
- }
+ if (h->flags & HTML_KEEP && n->flags & MDOC_LINE) {
+ h->flags &= ~HTML_KEEP;
+ h->flags |= HTML_PREKEEP;
}
if (child && n->child)
@@ -473,113 +450,110 @@ print_mdoc_node(MDOC_ARGS)
print_stagq(h, t);
switch (n->type) {
- case (MDOC_ROOT):
+ case MDOC_ROOT:
mdoc_root_post(meta, n, h);
break;
- case (MDOC_EQN):
+ case MDOC_EQN:
break;
default:
- if (mdocs[n->tok].post && ENDBODY_NOT == n->end)
- (*mdocs[n->tok].post)(meta, n, h);
+ if ( ! mdocs[n->tok].post || n->flags & MDOC_ENDED)
+ break;
+ (*mdocs[n->tok].post)(meta, n, h);
+ if (n->end != ENDBODY_NOT)
+ n->body->flags |= MDOC_ENDED;
+ if (n->end == ENDBODY_NOSPACE)
+ h->flags |= HTML_NOSPACE;
break;
}
}
-/* ARGSUSED */
static void
mdoc_root_post(MDOC_ARGS)
{
- struct htmlpair tag[3];
+ struct htmlpair tag;
struct tag *t, *tt;
- PAIR_SUMMARY_INIT(&tag[0], "Document Footer");
- PAIR_CLASS_INIT(&tag[1], "foot");
- PAIR_INIT(&tag[2], ATTR_WIDTH, "100%");
- t = print_otag(h, TAG_TABLE, 3, tag);
- PAIR_INIT(&tag[0], ATTR_WIDTH, "50%");
- print_otag(h, TAG_COL, 1, tag);
- print_otag(h, TAG_COL, 1, tag);
+ PAIR_CLASS_INIT(&tag, "foot");
+ t = print_otag(h, TAG_TABLE, 1, &tag);
print_otag(h, TAG_TBODY, 0, NULL);
tt = print_otag(h, TAG_TR, 0, NULL);
- PAIR_CLASS_INIT(&tag[0], "foot-date");
- print_otag(h, TAG_TD, 1, tag);
+ PAIR_CLASS_INIT(&tag, "foot-date");
+ print_otag(h, TAG_TD, 1, &tag);
print_text(h, meta->date);
print_stagq(h, tt);
- PAIR_CLASS_INIT(&tag[0], "foot-os");
- PAIR_INIT(&tag[1], ATTR_ALIGN, "right");
- print_otag(h, TAG_TD, 2, tag);
+ PAIR_CLASS_INIT(&tag, "foot-os");
+ print_otag(h, TAG_TD, 1, &tag);
print_text(h, meta->os);
print_tagq(h, t);
}
-
-/* ARGSUSED */
static int
mdoc_root_pre(MDOC_ARGS)
{
- struct htmlpair tag[3];
+ struct htmlpair tag;
struct tag *t, *tt;
- char b[BUFSIZ], title[BUFSIZ];
-
- strlcpy(b, meta->vol, BUFSIZ);
+ char *volume, *title;
- if (meta->arch) {
- strlcat(b, " (", BUFSIZ);
- strlcat(b, meta->arch, BUFSIZ);
- strlcat(b, ")", BUFSIZ);
- }
+ if (NULL == meta->arch)
+ volume = mandoc_strdup(meta->vol);
+ else
+ mandoc_asprintf(&volume, "%s (%s)",
+ meta->vol, meta->arch);
- snprintf(title, BUFSIZ - 1, "%s(%s)", meta->title, meta->msec);
+ if (NULL == meta->msec)
+ title = mandoc_strdup(meta->title);
+ else
+ mandoc_asprintf(&title, "%s(%s)",
+ meta->title, meta->msec);
- PAIR_SUMMARY_INIT(&tag[0], "Document Header");
- PAIR_CLASS_INIT(&tag[1], "head");
- PAIR_INIT(&tag[2], ATTR_WIDTH, "100%");
- t = print_otag(h, TAG_TABLE, 3, tag);
- PAIR_INIT(&tag[0], ATTR_WIDTH, "30%");
- print_otag(h, TAG_COL, 1, tag);
- print_otag(h, TAG_COL, 1, tag);
- print_otag(h, TAG_COL, 1, tag);
+ PAIR_CLASS_INIT(&tag, "head");
+ t = print_otag(h, TAG_TABLE, 1, &tag);
print_otag(h, TAG_TBODY, 0, NULL);
tt = print_otag(h, TAG_TR, 0, NULL);
- PAIR_CLASS_INIT(&tag[0], "head-ltitle");
- print_otag(h, TAG_TD, 1, tag);
+ PAIR_CLASS_INIT(&tag, "head-ltitle");
+ print_otag(h, TAG_TD, 1, &tag);
print_text(h, title);
print_stagq(h, tt);
- PAIR_CLASS_INIT(&tag[0], "head-vol");
- PAIR_INIT(&tag[1], ATTR_ALIGN, "center");
- print_otag(h, TAG_TD, 2, tag);
- print_text(h, b);
+ PAIR_CLASS_INIT(&tag, "head-vol");
+ print_otag(h, TAG_TD, 1, &tag);
+ print_text(h, volume);
print_stagq(h, tt);
- PAIR_CLASS_INIT(&tag[0], "head-rtitle");
- PAIR_INIT(&tag[1], ATTR_ALIGN, "right");
- print_otag(h, TAG_TD, 2, tag);
+ PAIR_CLASS_INIT(&tag, "head-rtitle");
+ print_otag(h, TAG_TD, 1, &tag);
print_text(h, title);
print_tagq(h, t);
+
+ free(title);
+ free(volume);
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_sh_pre(MDOC_ARGS)
{
struct htmlpair tag;
- if (MDOC_BLOCK == n->type) {
+ switch (n->type) {
+ case MDOC_BLOCK:
PAIR_CLASS_INIT(&tag, "section");
print_otag(h, TAG_DIV, 1, &tag);
return(1);
- } else if (MDOC_BODY == n->type)
+ case MDOC_BODY:
+ if (n->sec == SEC_AUTHORS)
+ h->flags &= ~(HTML_SPLIT|HTML_NOSPLIT);
return(1);
+ default:
+ break;
+ }
bufinit(h);
bufcat(h, "x");
@@ -599,7 +573,6 @@ mdoc_sh_pre(MDOC_ARGS)
return(1);
}
-/* ARGSUSED */
static int
mdoc_ss_pre(MDOC_ARGS)
{
@@ -630,8 +603,6 @@ mdoc_ss_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_fl_pre(MDOC_ARGS)
{
@@ -647,16 +618,15 @@ mdoc_fl_pre(MDOC_ARGS)
print_text(h, "\\-");
- if (n->child)
- h->flags |= HTML_NOSPACE;
- else if (n->next && n->next->line == n->line)
+ if ( ! (n->nchild == 0 &&
+ (n->next == NULL ||
+ n->next->type == MDOC_TEXT ||
+ n->next->flags & MDOC_LINE)))
h->flags |= HTML_NOSPACE;
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_nd_pre(MDOC_ARGS)
{
@@ -673,7 +643,6 @@ mdoc_nd_pre(MDOC_ARGS)
return(1);
}
-
static int
mdoc_nm_pre(MDOC_ARGS)
{
@@ -682,19 +651,19 @@ mdoc_nm_pre(MDOC_ARGS)
int len;
switch (n->type) {
- case (MDOC_ELEM):
+ case MDOC_ELEM:
synopsis_pre(h, n);
PAIR_CLASS_INIT(&tag, "name");
print_otag(h, TAG_B, 1, &tag);
if (NULL == n->child && meta->name)
print_text(h, meta->name);
return(1);
- case (MDOC_HEAD):
+ case MDOC_HEAD:
print_otag(h, TAG_TD, 0, NULL);
if (NULL == n->child && meta->name)
print_text(h, meta->name);
return(1);
- case (MDOC_BODY):
+ case MDOC_BODY:
print_otag(h, TAG_TD, 0, NULL);
return(1);
default:
@@ -712,7 +681,7 @@ mdoc_nm_pre(MDOC_ARGS)
if (0 == len && meta->name)
len = html_strlen(meta->name);
- SCALE_HS_INIT(&su, (double)len);
+ SCALE_HS_INIT(&su, len);
bufinit(h);
bufcat_su(h, "width", &su);
PAIR_STYLE_INIT(&tag, h);
@@ -723,8 +692,6 @@ mdoc_nm_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_xr_pre(MDOC_ARGS)
{
@@ -736,9 +703,9 @@ mdoc_xr_pre(MDOC_ARGS)
PAIR_CLASS_INIT(&tag[0], "link-man");
if (h->base_man) {
- buffmt_man(h, n->child->string,
- n->child->next ?
- n->child->next->string : NULL);
+ buffmt_man(h, n->child->string,
+ n->child->next ?
+ n->child->next->string : NULL);
PAIR_HREF_INIT(&tag[1], h->buf);
print_otag(h, TAG_A, 2, tag);
} else
@@ -759,8 +726,6 @@ mdoc_xr_pre(MDOC_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_ns_pre(MDOC_ARGS)
{
@@ -770,8 +735,6 @@ mdoc_ns_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_ar_pre(MDOC_ARGS)
{
@@ -782,8 +745,6 @@ mdoc_ar_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_xx_pre(MDOC_ARGS)
{
@@ -792,22 +753,22 @@ mdoc_xx_pre(MDOC_ARGS)
int flags;
switch (n->tok) {
- case (MDOC_Bsx):
+ case MDOC_Bsx:
pp = "BSD/OS";
break;
- case (MDOC_Dx):
+ case MDOC_Dx:
pp = "DragonFly";
break;
- case (MDOC_Fx):
+ case MDOC_Fx:
pp = "FreeBSD";
break;
- case (MDOC_Nx):
+ case MDOC_Nx:
pp = "NetBSD";
break;
- case (MDOC_Ox):
+ case MDOC_Ox:
pp = "OpenBSD";
break;
- case (MDOC_Ux):
+ case MDOC_Ux:
pp = "UNIX";
break;
default:
@@ -827,8 +788,6 @@ mdoc_xx_pre(MDOC_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_bx_pre(MDOC_ARGS)
{
@@ -856,7 +815,6 @@ mdoc_bx_pre(MDOC_ARGS)
return(0);
}
-/* ARGSUSED */
static int
mdoc_it_pre(MDOC_ARGS)
{
@@ -880,25 +838,25 @@ mdoc_it_pre(MDOC_ARGS)
if (MDOC_HEAD == n->type) {
switch (type) {
- case(LIST_bullet):
+ case LIST_bullet:
/* FALLTHROUGH */
- case(LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case(LIST_item):
+ case LIST_item:
/* FALLTHROUGH */
- case(LIST_hyphen):
+ case LIST_hyphen:
/* FALLTHROUGH */
- case(LIST_enum):
+ case LIST_enum:
return(0);
- case(LIST_diag):
+ case LIST_diag:
/* FALLTHROUGH */
- case(LIST_hang):
+ case LIST_hang:
/* FALLTHROUGH */
- case(LIST_inset):
+ case LIST_inset:
/* FALLTHROUGH */
- case(LIST_ohang):
+ case LIST_ohang:
/* FALLTHROUGH */
- case(LIST_tag):
+ case LIST_tag:
SCALE_VS_INIT(&su, ! bl->norm->Bl.comp);
bufcat_su(h, "margin-top", &su);
PAIR_STYLE_INIT(&tag[1], h);
@@ -908,36 +866,36 @@ mdoc_it_pre(MDOC_ARGS)
PAIR_CLASS_INIT(&tag[0], "diag");
print_otag(h, TAG_B, 1, tag);
break;
- case(LIST_column):
+ case LIST_column:
break;
default:
break;
}
} else if (MDOC_BODY == n->type) {
switch (type) {
- case(LIST_bullet):
+ case LIST_bullet:
/* FALLTHROUGH */
- case(LIST_hyphen):
+ case LIST_hyphen:
/* FALLTHROUGH */
- case(LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case(LIST_enum):
+ case LIST_enum:
/* FALLTHROUGH */
- case(LIST_item):
+ case LIST_item:
SCALE_VS_INIT(&su, ! bl->norm->Bl.comp);
bufcat_su(h, "margin-top", &su);
PAIR_STYLE_INIT(&tag[1], h);
print_otag(h, TAG_LI, 2, tag);
break;
- case(LIST_diag):
+ case LIST_diag:
/* FALLTHROUGH */
- case(LIST_hang):
+ case LIST_hang:
/* FALLTHROUGH */
- case(LIST_inset):
+ case LIST_inset:
/* FALLTHROUGH */
- case(LIST_ohang):
+ case LIST_ohang:
/* FALLTHROUGH */
- case(LIST_tag):
+ case LIST_tag:
if (NULL == bl->norm->Bl.width) {
print_otag(h, TAG_DD, 1, tag);
break;
@@ -947,7 +905,7 @@ mdoc_it_pre(MDOC_ARGS)
PAIR_STYLE_INIT(&tag[1], h);
print_otag(h, TAG_DD, 2, tag);
break;
- case(LIST_column):
+ case LIST_column:
SCALE_VS_INIT(&su, ! bl->norm->Bl.comp);
bufcat_su(h, "margin-top", &su);
PAIR_STYLE_INIT(&tag[1], h);
@@ -958,7 +916,7 @@ mdoc_it_pre(MDOC_ARGS)
}
} else {
switch (type) {
- case (LIST_column):
+ case LIST_column:
print_otag(h, TAG_TR, 1, tag);
break;
default:
@@ -969,7 +927,6 @@ mdoc_it_pre(MDOC_ARGS)
return(1);
}
-/* ARGSUSED */
static int
mdoc_bl_pre(MDOC_ARGS)
{
@@ -1016,42 +973,42 @@ mdoc_bl_pre(MDOC_ARGS)
PAIR_STYLE_INIT(&tag[0], h);
assert(lists[n->norm->Bl.type]);
- strlcpy(buf, "list ", BUFSIZ);
- strlcat(buf, lists[n->norm->Bl.type], BUFSIZ);
+ (void)strlcpy(buf, "list ", BUFSIZ);
+ (void)strlcat(buf, lists[n->norm->Bl.type], BUFSIZ);
PAIR_INIT(&tag[1], ATTR_CLASS, buf);
/* Set the block's left-hand margin. */
if (n->norm->Bl.offs) {
- a2offs(n->norm->Bl.offs, &su);
+ a2width(n->norm->Bl.offs, &su);
bufcat_su(h, "margin-left", &su);
}
switch (n->norm->Bl.type) {
- case(LIST_bullet):
+ case LIST_bullet:
/* FALLTHROUGH */
- case(LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case(LIST_hyphen):
+ case LIST_hyphen:
/* FALLTHROUGH */
- case(LIST_item):
+ case LIST_item:
print_otag(h, TAG_UL, 2, tag);
break;
- case(LIST_enum):
+ case LIST_enum:
print_otag(h, TAG_OL, 2, tag);
break;
- case(LIST_diag):
+ case LIST_diag:
/* FALLTHROUGH */
- case(LIST_hang):
+ case LIST_hang:
/* FALLTHROUGH */
- case(LIST_inset):
+ case LIST_inset:
/* FALLTHROUGH */
- case(LIST_ohang):
+ case LIST_ohang:
/* FALLTHROUGH */
- case(LIST_tag):
+ case LIST_tag:
print_otag(h, TAG_DL, 2, tag);
break;
- case(LIST_column):
+ case LIST_column:
print_otag(h, TAG_TABLE, 2, tag);
break;
default:
@@ -1062,7 +1019,6 @@ mdoc_bl_pre(MDOC_ARGS)
return(1);
}
-/* ARGSUSED */
static int
mdoc_ex_pre(MDOC_ARGS)
{
@@ -1095,16 +1051,14 @@ mdoc_ex_pre(MDOC_ARGS)
}
if (nchild > 1)
- print_text(h, "utilities exit");
+ print_text(h, "utilities exit\\~0");
else
- print_text(h, "utility exits");
+ print_text(h, "utility exits\\~0");
- print_text(h, "0 on success, and >0 if an error occurs.");
+ print_text(h, "on success, and\\~>0 if an error occurs.");
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_em_pre(MDOC_ARGS)
{
@@ -1115,8 +1069,6 @@ mdoc_em_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_d1_pre(MDOC_ARGS)
{
@@ -1141,13 +1093,11 @@ mdoc_d1_pre(MDOC_ARGS)
if (MDOC_Dl == n->tok) {
PAIR_CLASS_INIT(&tag[0], "lit");
print_otag(h, TAG_CODE, 1, tag);
- }
+ }
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_sx_pre(MDOC_ARGS)
{
@@ -1170,14 +1120,12 @@ mdoc_sx_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_bd_pre(MDOC_ARGS)
{
- struct htmlpair tag[2];
- int comp, sv;
- const struct mdoc_node *nn;
+ struct htmlpair tag[2];
+ int comp, sv;
+ struct mdoc_node *nn;
struct roffsu su;
if (MDOC_HEAD == n->type)
@@ -1194,20 +1142,28 @@ mdoc_bd_pre(MDOC_ARGS)
break;
}
if ( ! comp)
- print_otag(h, TAG_P, 0, NULL);
+ print_paragraph(h);
return(1);
}
- SCALE_HS_INIT(&su, 0);
- if (n->norm->Bd.offs)
- a2offs(n->norm->Bd.offs, &su);
-
+ /* Handle the -offset argument. */
+
+ if (n->norm->Bd.offs == NULL ||
+ ! strcmp(n->norm->Bd.offs, "left"))
+ SCALE_HS_INIT(&su, 0);
+ else if ( ! strcmp(n->norm->Bd.offs, "indent"))
+ SCALE_HS_INIT(&su, INDENT);
+ else if ( ! strcmp(n->norm->Bd.offs, "indent-two"))
+ SCALE_HS_INIT(&su, INDENT * 2);
+ else
+ a2width(n->norm->Bd.offs, &su);
+
bufinit(h);
bufcat_su(h, "margin-left", &su);
PAIR_STYLE_INIT(&tag[0], h);
- if (DISP_unfilled != n->norm->Bd.type &&
- DISP_literal != n->norm->Bd.type) {
+ if (DISP_unfilled != n->norm->Bd.type &&
+ DISP_literal != n->norm->Bd.type) {
PAIR_CLASS_INIT(&tag[1], "display");
print_otag(h, TAG_DIV, 2, tag);
return(1);
@@ -1230,26 +1186,27 @@ mdoc_bd_pre(MDOC_ARGS)
* anyway, so don't sweat it.
*/
switch (nn->tok) {
- case (MDOC_Sm):
+ case MDOC_Sm:
/* FALLTHROUGH */
- case (MDOC_br):
+ case MDOC_br:
/* FALLTHROUGH */
- case (MDOC_sp):
+ case MDOC_sp:
/* FALLTHROUGH */
- case (MDOC_Bl):
+ case MDOC_Bl:
/* FALLTHROUGH */
- case (MDOC_D1):
+ case MDOC_D1:
/* FALLTHROUGH */
- case (MDOC_Dl):
+ case MDOC_Dl:
/* FALLTHROUGH */
- case (MDOC_Lp):
+ case MDOC_Lp:
/* FALLTHROUGH */
- case (MDOC_Pp):
+ case MDOC_Pp:
continue;
default:
break;
}
- if (nn->next && nn->next->line == nn->line)
+ if (h->flags & HTML_NONEWLINE ||
+ (nn->next && ! (nn->next->flags & MDOC_LINE)))
continue;
else if (nn->next)
print_text(h, "\n");
@@ -1263,8 +1220,6 @@ mdoc_bd_pre(MDOC_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_pa_pre(MDOC_ARGS)
{
@@ -1275,8 +1230,6 @@ mdoc_pa_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_ad_pre(MDOC_ARGS)
{
@@ -1287,22 +1240,33 @@ mdoc_ad_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_an_pre(MDOC_ARGS)
{
struct htmlpair tag;
- /* TODO: -split and -nosplit (see termp_an_pre()). */
+ if (n->norm->An.auth == AUTH_split) {
+ h->flags &= ~HTML_NOSPLIT;
+ h->flags |= HTML_SPLIT;
+ return(0);
+ }
+ if (n->norm->An.auth == AUTH_nosplit) {
+ h->flags &= ~HTML_SPLIT;
+ h->flags |= HTML_NOSPLIT;
+ return(0);
+ }
+
+ if (h->flags & HTML_SPLIT)
+ print_otag(h, TAG_BR, 0, NULL);
+
+ if (n->sec == SEC_AUTHORS && ! (h->flags & HTML_NOSPLIT))
+ h->flags |= HTML_SPLIT;
PAIR_CLASS_INIT(&tag, "author");
print_otag(h, TAG_SPAN, 1, &tag);
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_cd_pre(MDOC_ARGS)
{
@@ -1314,8 +1278,6 @@ mdoc_cd_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_dv_pre(MDOC_ARGS)
{
@@ -1326,8 +1288,6 @@ mdoc_dv_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_ev_pre(MDOC_ARGS)
{
@@ -1338,8 +1298,6 @@ mdoc_ev_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_er_pre(MDOC_ARGS)
{
@@ -1350,8 +1308,6 @@ mdoc_er_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_fa_pre(MDOC_ARGS)
{
@@ -1383,8 +1339,6 @@ mdoc_fa_pre(MDOC_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_fd_pre(MDOC_ARGS)
{
@@ -1413,21 +1367,30 @@ mdoc_fd_pre(MDOC_ARGS)
if (NULL != (n = n->next)) {
assert(MDOC_TEXT == n->type);
- strlcpy(buf, '<' == *n->string || '"' == *n->string ?
- n->string + 1 : n->string, BUFSIZ);
+
+ /*
+ * XXX This is broken and not easy to fix.
+ * When using -Oincludes, truncation may occur.
+ * Dynamic allocation wouldn't help because
+ * passing long strings to buffmt_includes()
+ * does not work either.
+ */
+
+ strlcpy(buf, '<' == *n->string || '"' == *n->string ?
+ n->string + 1 : n->string, BUFSIZ);
sz = strlen(buf);
if (sz && ('>' == buf[sz - 1] || '"' == buf[sz - 1]))
buf[sz - 1] = '\0';
PAIR_CLASS_INIT(&tag[0], "link-includes");
-
+
i = 1;
if (h->base_includes) {
buffmt_includes(h, buf);
PAIR_HREF_INIT(&tag[i], h->buf);
i++;
- }
+ }
t = print_otag(h, TAG_A, i, tag);
print_text(h, n->string);
@@ -1444,8 +1407,6 @@ mdoc_fd_pre(MDOC_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_vt_pre(MDOC_ARGS)
{
@@ -1464,8 +1425,6 @@ mdoc_vt_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_ft_pre(MDOC_ARGS)
{
@@ -1477,8 +1436,6 @@ mdoc_ft_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_fn_pre(MDOC_ARGS)
{
@@ -1499,7 +1456,7 @@ mdoc_fn_pre(MDOC_ARGS)
if (NULL != ep) {
PAIR_CLASS_INIT(&tag[0], "ftype");
t = print_otag(h, TAG_I, 1, tag);
-
+
while (ep) {
sz = MIN((int)(ep - sp), BUFSIZ - 1);
(void)memcpy(nbuf, sp, (size_t)sz);
@@ -1531,10 +1488,8 @@ mdoc_fn_pre(MDOC_ARGS)
t = print_otag(h, TAG_B, 1, tag);
- if (sp) {
- strlcpy(nbuf, sp, BUFSIZ);
- print_text(h, nbuf);
- }
+ if (sp)
+ print_text(h, sp);
print_tagq(h, t);
@@ -1571,43 +1526,38 @@ mdoc_fn_pre(MDOC_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_sm_pre(MDOC_ARGS)
{
- assert(n->child && MDOC_TEXT == n->child->type);
- if (0 == strcmp("on", n->child->string)) {
- /*
- * FIXME: no p->col to check. Thus, if we have
- * .Bd -literal
- * .Sm off
- * 1 2
- * .Sm on
- * 3
- * .Ed
- * the "3" is preceded by a space.
- */
- h->flags &= ~HTML_NOSPACE;
+ if (NULL == n->child)
+ h->flags ^= HTML_NONOSPACE;
+ else if (0 == strcmp("on", n->child->string))
h->flags &= ~HTML_NONOSPACE;
- } else
+ else
h->flags |= HTML_NONOSPACE;
+ if ( ! (HTML_NONOSPACE & h->flags))
+ h->flags &= ~HTML_NOSPACE;
+
return(0);
}
-/* ARGSUSED */
static int
-mdoc_pp_pre(MDOC_ARGS)
+mdoc_skip_pre(MDOC_ARGS)
{
- print_otag(h, TAG_P, 0, NULL);
return(0);
+}
+
+static int
+mdoc_pp_pre(MDOC_ARGS)
+{
+ print_paragraph(h);
+ return(0);
}
-/* ARGSUSED */
static int
mdoc_sp_pre(MDOC_ARGS)
{
@@ -1617,11 +1567,14 @@ mdoc_sp_pre(MDOC_ARGS)
SCALE_VS_INIT(&su, 1);
if (MDOC_sp == n->tok) {
- if (NULL != (n = n->child))
+ if (NULL != (n = n->child)) {
if ( ! a2roffsu(n->string, &su, SCALE_VS))
- SCALE_VS_INIT(&su, atoi(n->string));
+ su.scale = 1.0;
+ else if (su.scale < 0.0)
+ su.scale = 0.0;
+ }
} else
- su.scale = 0;
+ su.scale = 0.0;
bufinit(h);
bufcat_su(h, "height", &su);
@@ -1635,7 +1588,6 @@ mdoc_sp_pre(MDOC_ARGS)
}
-/* ARGSUSED */
static int
mdoc_lk_pre(MDOC_ARGS)
{
@@ -1660,8 +1612,6 @@ mdoc_lk_pre(MDOC_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_mt_pre(MDOC_ARGS)
{
@@ -1682,12 +1632,10 @@ mdoc_mt_pre(MDOC_ARGS)
print_text(h, n->string);
print_tagq(h, t);
}
-
+
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_fo_pre(MDOC_ARGS)
{
@@ -1716,8 +1664,6 @@ mdoc_fo_pre(MDOC_ARGS)
return(0);
}
-
-/* ARGSUSED */
static void
mdoc_fo_post(MDOC_ARGS)
{
@@ -1730,8 +1676,6 @@ mdoc_fo_post(MDOC_ARGS)
print_text(h, ";");
}
-
-/* ARGSUSED */
static int
mdoc_in_pre(MDOC_ARGS)
{
@@ -1767,7 +1711,7 @@ mdoc_in_pre(MDOC_ARGS)
buffmt_includes(h, n->string);
PAIR_HREF_INIT(&tag[i], h->buf);
i++;
- }
+ }
t = print_otag(h, TAG_A, i, tag);
print_text(h, n->string);
@@ -1787,8 +1731,6 @@ mdoc_in_pre(MDOC_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_ic_pre(MDOC_ARGS)
{
@@ -1799,8 +1741,6 @@ mdoc_ic_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_rv_pre(MDOC_ARGS)
{
@@ -1813,46 +1753,50 @@ mdoc_rv_pre(MDOC_ARGS)
PAIR_CLASS_INIT(&tag, "fname");
- print_text(h, "The");
-
nchild = n->nchild;
- for (n = n->child; n; n = n->next) {
- assert(MDOC_TEXT == n->type);
-
- t = print_otag(h, TAG_B, 1, &tag);
- print_text(h, n->string);
- print_tagq(h, t);
+ if (nchild > 0) {
+ print_text(h, "The");
- h->flags |= HTML_NOSPACE;
- print_text(h, "()");
+ for (n = n->child; n; n = n->next) {
+ t = print_otag(h, TAG_B, 1, &tag);
+ print_text(h, n->string);
+ print_tagq(h, t);
- if (nchild > 2 && n->next) {
h->flags |= HTML_NOSPACE;
- print_text(h, ",");
+ print_text(h, "()");
+
+ if (n->next == NULL)
+ continue;
+
+ if (nchild > 2) {
+ h->flags |= HTML_NOSPACE;
+ print_text(h, ",");
+ }
+ if (n->next->next == NULL)
+ print_text(h, "and");
}
- if (n->next && NULL == n->next->next)
- print_text(h, "and");
- }
+ if (nchild > 1)
+ print_text(h, "functions return");
+ else
+ print_text(h, "function returns");
- if (nchild > 1)
- print_text(h, "functions return");
- else
- print_text(h, "function returns");
+ print_text(h, "the value\\~0 if successful;");
+ } else
+ print_text(h, "Upon successful completion,"
+ " the value\\~0 is returned;");
- print_text(h, "the value 0 if successful; otherwise the value "
- "-1 is returned and the global variable");
+ print_text(h, "otherwise the value\\~\\-1 is returned"
+ " and the global variable");
PAIR_CLASS_INIT(&tag, "var");
t = print_otag(h, TAG_B, 1, &tag);
print_text(h, "errno");
print_tagq(h, t);
- print_text(h, "is set to indicate the error.");
+ print_text(h, "is set to indicate the error.");
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_va_pre(MDOC_ARGS)
{
@@ -1863,20 +1807,16 @@ mdoc_va_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_ap_pre(MDOC_ARGS)
{
-
+
h->flags |= HTML_NOSPACE;
print_text(h, "\\(aq");
h->flags |= HTML_NOSPACE;
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_bf_pre(MDOC_ARGS)
{
@@ -1888,18 +1828,18 @@ mdoc_bf_pre(MDOC_ARGS)
else if (MDOC_BODY != n->type)
return(1);
- if (FONT_Em == n->norm->Bf.font)
+ if (FONT_Em == n->norm->Bf.font)
PAIR_CLASS_INIT(&tag[0], "emph");
- else if (FONT_Sy == n->norm->Bf.font)
+ else if (FONT_Sy == n->norm->Bf.font)
PAIR_CLASS_INIT(&tag[0], "symb");
- else if (FONT_Li == n->norm->Bf.font)
+ else if (FONT_Li == n->norm->Bf.font)
PAIR_CLASS_INIT(&tag[0], "lit");
else
PAIR_CLASS_INIT(&tag[0], "none");
- /*
+ /*
* We want this to be inline-formatted, but needs to be div to
- * accept block children.
+ * accept block children.
*/
bufinit(h);
bufcat_style(h, "display", "inline");
@@ -1911,8 +1851,6 @@ mdoc_bf_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_ms_pre(MDOC_ARGS)
{
@@ -1923,8 +1861,6 @@ mdoc_ms_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_igndelim_pre(MDOC_ARGS)
{
@@ -1933,17 +1869,14 @@ mdoc_igndelim_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
mdoc_pf_post(MDOC_ARGS)
{
- h->flags |= HTML_NOSPACE;
+ if ( ! (n->next == NULL || n->next->flags & MDOC_LINE))
+ h->flags |= HTML_NOSPACE;
}
-
-/* ARGSUSED */
static int
mdoc_rs_pre(MDOC_ARGS)
{
@@ -1953,16 +1886,23 @@ mdoc_rs_pre(MDOC_ARGS)
return(1);
if (n->prev && SEC_SEE_ALSO == n->sec)
- print_otag(h, TAG_P, 0, NULL);
+ print_paragraph(h);
PAIR_CLASS_INIT(&tag, "ref");
print_otag(h, TAG_SPAN, 1, &tag);
return(1);
}
+static int
+mdoc_no_pre(MDOC_ARGS)
+{
+ struct htmlpair tag;
+ PAIR_CLASS_INIT(&tag, "none");
+ print_otag(h, TAG_CODE, 1, &tag);
+ return(1);
+}
-/* ARGSUSED */
static int
mdoc_li_pre(MDOC_ARGS)
{
@@ -1973,8 +1913,6 @@ mdoc_li_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_sy_pre(MDOC_ARGS)
{
@@ -1985,8 +1923,6 @@ mdoc_sy_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc_bt_pre(MDOC_ARGS)
{
@@ -1995,8 +1931,6 @@ mdoc_bt_pre(MDOC_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_ud_pre(MDOC_ARGS)
{
@@ -2005,8 +1939,6 @@ mdoc_ud_pre(MDOC_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
mdoc_lb_pre(MDOC_ARGS)
{
@@ -2020,8 +1952,6 @@ mdoc_lb_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
mdoc__x_pre(MDOC_ARGS)
{
@@ -2031,52 +1961,52 @@ mdoc__x_pre(MDOC_ARGS)
t = TAG_SPAN;
switch (n->tok) {
- case(MDOC__A):
+ case MDOC__A:
PAIR_CLASS_INIT(&tag[0], "ref-auth");
if (n->prev && MDOC__A == n->prev->tok)
if (NULL == n->next || MDOC__A != n->next->tok)
print_text(h, "and");
break;
- case(MDOC__B):
+ case MDOC__B:
PAIR_CLASS_INIT(&tag[0], "ref-book");
t = TAG_I;
break;
- case(MDOC__C):
+ case MDOC__C:
PAIR_CLASS_INIT(&tag[0], "ref-city");
break;
- case(MDOC__D):
+ case MDOC__D:
PAIR_CLASS_INIT(&tag[0], "ref-date");
break;
- case(MDOC__I):
+ case MDOC__I:
PAIR_CLASS_INIT(&tag[0], "ref-issue");
t = TAG_I;
break;
- case(MDOC__J):
+ case MDOC__J:
PAIR_CLASS_INIT(&tag[0], "ref-jrnl");
t = TAG_I;
break;
- case(MDOC__N):
+ case MDOC__N:
PAIR_CLASS_INIT(&tag[0], "ref-num");
break;
- case(MDOC__O):
+ case MDOC__O:
PAIR_CLASS_INIT(&tag[0], "ref-opt");
break;
- case(MDOC__P):
+ case MDOC__P:
PAIR_CLASS_INIT(&tag[0], "ref-page");
break;
- case(MDOC__Q):
+ case MDOC__Q:
PAIR_CLASS_INIT(&tag[0], "ref-corp");
break;
- case(MDOC__R):
+ case MDOC__R:
PAIR_CLASS_INIT(&tag[0], "ref-rep");
break;
- case(MDOC__T):
+ case MDOC__T:
PAIR_CLASS_INIT(&tag[0], "ref-title");
break;
- case(MDOC__U):
+ case MDOC__U:
PAIR_CLASS_INIT(&tag[0], "link-ref");
break;
- case(MDOC__V):
+ case MDOC__V:
PAIR_CLASS_INIT(&tag[0], "ref-vol");
break;
default:
@@ -2095,8 +2025,6 @@ mdoc__x_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
mdoc__x_post(MDOC_ARGS)
{
@@ -2115,18 +2043,16 @@ mdoc__x_post(MDOC_ARGS)
print_text(h, n->next ? "," : ".");
}
-
-/* ARGSUSED */
static int
mdoc_bk_pre(MDOC_ARGS)
{
switch (n->type) {
- case (MDOC_BLOCK):
+ case MDOC_BLOCK:
break;
- case (MDOC_HEAD):
+ case MDOC_HEAD:
return(0);
- case (MDOC_BODY):
+ case MDOC_BODY:
if (n->parent->args || 0 == n->prev->nchild)
h->flags |= HTML_PREKEEP;
break;
@@ -2138,8 +2064,6 @@ mdoc_bk_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
mdoc_bk_post(MDOC_ARGS)
{
@@ -2148,8 +2072,6 @@ mdoc_bk_post(MDOC_ARGS)
h->flags &= ~(HTML_KEEP | HTML_PREKEEP);
}
-
-/* ARGSUSED */
static int
mdoc_quote_pre(MDOC_ARGS)
{
@@ -2159,54 +2081,59 @@ mdoc_quote_pre(MDOC_ARGS)
return(1);
switch (n->tok) {
- case (MDOC_Ao):
+ case MDOC_Ao:
/* FALLTHROUGH */
- case (MDOC_Aq):
- print_text(h, "\\(la");
+ case MDOC_Aq:
+ print_text(h, n->nchild == 1 &&
+ n->child->tok == MDOC_Mt ? "<" : "\\(la");
break;
- case (MDOC_Bro):
+ case MDOC_Bro:
/* FALLTHROUGH */
- case (MDOC_Brq):
+ case MDOC_Brq:
print_text(h, "\\(lC");
break;
- case (MDOC_Bo):
+ case MDOC_Bo:
/* FALLTHROUGH */
- case (MDOC_Bq):
+ case MDOC_Bq:
print_text(h, "\\(lB");
break;
- case (MDOC_Oo):
+ case MDOC_Oo:
/* FALLTHROUGH */
- case (MDOC_Op):
+ case MDOC_Op:
print_text(h, "\\(lB");
h->flags |= HTML_NOSPACE;
PAIR_CLASS_INIT(&tag, "opt");
print_otag(h, TAG_SPAN, 1, &tag);
break;
- case (MDOC_Eo):
+ case MDOC_En:
+ if (NULL == n->norm->Es ||
+ NULL == n->norm->Es->child)
+ return(1);
+ print_text(h, n->norm->Es->child->string);
break;
- case (MDOC_Do):
+ case MDOC_Do:
/* FALLTHROUGH */
- case (MDOC_Dq):
+ case MDOC_Dq:
/* FALLTHROUGH */
- case (MDOC_Qo):
+ case MDOC_Qo:
/* FALLTHROUGH */
- case (MDOC_Qq):
+ case MDOC_Qq:
print_text(h, "\\(lq");
break;
- case (MDOC_Po):
+ case MDOC_Po:
/* FALLTHROUGH */
- case (MDOC_Pq):
+ case MDOC_Pq:
print_text(h, "(");
break;
- case (MDOC_Ql):
+ case MDOC_Ql:
print_text(h, "\\(oq");
h->flags |= HTML_NOSPACE;
PAIR_CLASS_INIT(&tag, "lit");
print_otag(h, TAG_CODE, 1, &tag);
break;
- case (MDOC_So):
+ case MDOC_So:
/* FALLTHROUGH */
- case (MDOC_Sq):
+ case MDOC_Sq:
print_text(h, "\\(oq");
break;
default:
@@ -2218,58 +2145,63 @@ mdoc_quote_pre(MDOC_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
mdoc_quote_post(MDOC_ARGS)
{
- if (MDOC_BODY != n->type)
+ if (n->type != MDOC_BODY && n->type != MDOC_ELEM)
return;
h->flags |= HTML_NOSPACE;
switch (n->tok) {
- case (MDOC_Ao):
+ case MDOC_Ao:
/* FALLTHROUGH */
- case (MDOC_Aq):
- print_text(h, "\\(ra");
+ case MDOC_Aq:
+ print_text(h, n->nchild == 1 &&
+ n->child->tok == MDOC_Mt ? ">" : "\\(ra");
break;
- case (MDOC_Bro):
+ case MDOC_Bro:
/* FALLTHROUGH */
- case (MDOC_Brq):
+ case MDOC_Brq:
print_text(h, "\\(rC");
break;
- case (MDOC_Oo):
+ case MDOC_Oo:
/* FALLTHROUGH */
- case (MDOC_Op):
+ case MDOC_Op:
/* FALLTHROUGH */
- case (MDOC_Bo):
+ case MDOC_Bo:
/* FALLTHROUGH */
- case (MDOC_Bq):
+ case MDOC_Bq:
print_text(h, "\\(rB");
break;
- case (MDOC_Eo):
+ case MDOC_En:
+ if (n->norm->Es == NULL ||
+ n->norm->Es->child == NULL ||
+ n->norm->Es->child->next == NULL)
+ h->flags &= ~HTML_NOSPACE;
+ else
+ print_text(h, n->norm->Es->child->next->string);
break;
- case (MDOC_Qo):
+ case MDOC_Qo:
/* FALLTHROUGH */
- case (MDOC_Qq):
+ case MDOC_Qq:
/* FALLTHROUGH */
- case (MDOC_Do):
+ case MDOC_Do:
/* FALLTHROUGH */
- case (MDOC_Dq):
+ case MDOC_Dq:
print_text(h, "\\(rq");
break;
- case (MDOC_Po):
+ case MDOC_Po:
/* FALLTHROUGH */
- case (MDOC_Pq):
+ case MDOC_Pq:
print_text(h, ")");
break;
- case (MDOC_Ql):
+ case MDOC_Ql:
/* FALLTHROUGH */
- case (MDOC_So):
+ case MDOC_So:
/* FALLTHROUGH */
- case (MDOC_Sq):
+ case MDOC_Sq:
print_text(h, "\\(cq");
break;
default:
@@ -2278,4 +2210,43 @@ mdoc_quote_post(MDOC_ARGS)
}
}
+static int
+mdoc_eo_pre(MDOC_ARGS)
+{
+
+ if (n->type != MDOC_BODY)
+ return(1);
+
+ if (n->end == ENDBODY_NOT &&
+ n->parent->head->child == NULL &&
+ n->child != NULL &&
+ n->child->end != ENDBODY_NOT)
+ print_text(h, "\\&");
+ else if (n->end != ENDBODY_NOT ? n->child != NULL :
+ n->parent->head->child != NULL && (n->child != NULL ||
+ (n->parent->tail != NULL && n->parent->tail->child != NULL)))
+ h->flags |= HTML_NOSPACE;
+ return(1);
+}
+static void
+mdoc_eo_post(MDOC_ARGS)
+{
+ int body, tail;
+
+ if (n->type != MDOC_BODY)
+ return;
+
+ if (n->end != ENDBODY_NOT) {
+ h->flags &= ~HTML_NOSPACE;
+ return;
+ }
+
+ body = n->child != NULL || n->parent->head->child != NULL;
+ tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
+
+ if (body && tail)
+ h->flags |= HTML_NOSPACE;
+ else if ( ! tail)
+ h->flags &= ~HTML_NOSPACE;
+}
diff --git a/usr/src/cmd/mandoc/mdoc_macro.c b/usr/src/cmd/mandoc/mdoc_macro.c
index 2a63ca92e3..efb48d023f 100644
--- a/usr/src/cmd/mandoc/mdoc_macro.c
+++ b/usr/src/cmd/mandoc/mdoc_macro.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc_macro.c,v 1.125 2013/12/24 20:45:27 schwarze Exp $ */
+/* $Id: mdoc_macro.c,v 1.183 2015/02/12 12:24:33 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012-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
@@ -15,9 +15,9 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
+
+#include <sys/types.h>
#include <assert.h>
#include <ctype.h>
@@ -31,43 +31,28 @@
#include "libmdoc.h"
#include "libmandoc.h"
-enum rew { /* see rew_dohalt() */
- REWIND_NONE,
- REWIND_THIS,
- REWIND_MORE,
- REWIND_FORCE,
- REWIND_LATER,
- REWIND_ERROR
-};
-
-static int blk_full(MACRO_PROT_ARGS);
-static int blk_exp_close(MACRO_PROT_ARGS);
-static int blk_part_exp(MACRO_PROT_ARGS);
-static int blk_part_imp(MACRO_PROT_ARGS);
-static int ctx_synopsis(MACRO_PROT_ARGS);
-static int in_line_eoln(MACRO_PROT_ARGS);
-static int in_line_argn(MACRO_PROT_ARGS);
-static int in_line(MACRO_PROT_ARGS);
-static int obsolete(MACRO_PROT_ARGS);
-static int phrase_ta(MACRO_PROT_ARGS);
-
-static int dword(struct mdoc *, int, int, const char *,
+static void blk_full(MACRO_PROT_ARGS);
+static void blk_exp_close(MACRO_PROT_ARGS);
+static void blk_part_exp(MACRO_PROT_ARGS);
+static void blk_part_imp(MACRO_PROT_ARGS);
+static void ctx_synopsis(MACRO_PROT_ARGS);
+static void in_line_eoln(MACRO_PROT_ARGS);
+static void in_line_argn(MACRO_PROT_ARGS);
+static void in_line(MACRO_PROT_ARGS);
+static void phrase_ta(MACRO_PROT_ARGS);
+
+static void dword(struct mdoc *, int, int, const char *,
enum mdelim, int);
-static int append_delims(struct mdoc *,
+static void append_delims(struct mdoc *, int, int *, char *);
+static enum mdoct lookup(struct mdoc *, enum mdoct,
+ int, int, const char *);
+static int macro_or_word(MACRO_PROT_ARGS, int);
+static int parse_rest(struct mdoc *, enum mdoct,
int, int *, char *);
-static enum mdoct lookup(enum mdoct, const char *);
-static enum mdoct lookup_raw(const char *);
-static int make_pending(struct mdoc_node *, enum mdoct,
- struct mdoc *, int, int);
-static int phrase(struct mdoc *, int, int, char *);
-static enum mdoct rew_alt(enum mdoct);
-static enum rew rew_dohalt(enum mdoct, enum mdoc_type,
- const struct mdoc_node *);
-static int rew_elem(struct mdoc *, enum mdoct);
-static int rew_last(struct mdoc *,
- const struct mdoc_node *);
-static int rew_sub(enum mdoc_type, struct mdoc *,
- enum mdoct, int, int);
+static enum mdoct rew_alt(enum mdoct);
+static void rew_elem(struct mdoc *, enum mdoct);
+static void rew_last(struct mdoc *, const struct mdoc_node *);
+static void rew_pending(struct mdoc *, const struct mdoc_node *);
const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ap */
@@ -87,7 +72,7 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */
{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* An */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */
- { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cd */
+ { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Cd */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Er */
@@ -98,13 +83,13 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fl */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fn */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ft */
- { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ic */
+ { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ic */
{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* In */
{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Li */
{ blk_full, MDOC_JOIN }, /* Nd */
{ ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */
{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Op */
- { obsolete, 0 }, /* Ot */
+ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ot */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */
{ in_line_eoln, 0 }, /* Rv */
{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* St */
@@ -148,8 +133,7 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Eo */
{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Fx */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ms */
- { in_line_argn, MDOC_CALLABLE | MDOC_PARSED |
- MDOC_IGNDELIM | MDOC_JOIN }, /* No */
+ { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* No */
{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED |
MDOC_IGNDELIM | MDOC_JOIN }, /* Ns */
{ in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Nx */
@@ -173,7 +157,7 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
{ blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
MDOC_EXPLICIT | MDOC_JOIN }, /* So */
{ blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sq */
- { in_line_eoln, 0 }, /* Sm */
+ { in_line_argn, 0 }, /* Sm */
{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sx */
{ in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Sy */
{ in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Tn */
@@ -191,7 +175,7 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
{ blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ek */
{ in_line_eoln, 0 }, /* Bt */
{ in_line_eoln, 0 }, /* Hf */
- { obsolete, 0 }, /* Fr */
+ { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fr */
{ in_line_eoln, 0 }, /* Ud */
{ in_line, 0 }, /* Lb */
{ in_line_eoln, 0 }, /* Lp */
@@ -203,14 +187,15 @@ const struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
{ blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
MDOC_EXPLICIT | MDOC_JOIN }, /* Brc */
{ in_line_eoln, MDOC_JOIN }, /* %C */
- { obsolete, 0 }, /* Es */
- { obsolete, 0 }, /* En */
+ { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Es */
+ { 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;
@@ -221,65 +206,59 @@ const struct mdoc_macro * const mdoc_macros = __mdoc_macros;
* closing out open [implicit] scopes. Obviously, open explicit scopes
* are errors.
*/
-int
+void
mdoc_macroend(struct mdoc *mdoc)
{
struct mdoc_node *n;
/* Scan for open explicit scopes. */
- n = MDOC_VALID & mdoc->last->flags ?
- mdoc->last->parent : mdoc->last;
+ n = mdoc->last->flags & MDOC_VALID ?
+ mdoc->last->parent : mdoc->last;
for ( ; n; n = n->parent)
- if (MDOC_BLOCK == n->type &&
- MDOC_EXPLICIT & mdoc_macros[n->tok].flags)
- mdoc_nmsg(mdoc, n, MANDOCERR_SCOPEEXIT);
+ if (n->type == MDOC_BLOCK &&
+ mdoc_macros[n->tok].flags & MDOC_EXPLICIT)
+ mandoc_msg(MANDOCERR_BLK_NOEND, mdoc->parse,
+ n->line, n->pos, mdoc_macronames[n->tok]);
/* Rewind to the first. */
- return(rew_last(mdoc, mdoc->first));
+ rew_last(mdoc, mdoc->first);
}
-
/*
- * Look up a macro from within a subsequent context.
+ * Look up the macro at *p called by "from",
+ * or as a line macro if from == MDOC_MAX.
*/
static enum mdoct
-lookup(enum mdoct from, const char *p)
-{
-
- if ( ! (MDOC_PARSED & mdoc_macros[from].flags))
- return(MDOC_MAX);
- return(lookup_raw(p));
-}
-
-
-/*
- * Lookup a macro following the initial line macro.
- */
-static enum mdoct
-lookup_raw(const char *p)
+lookup(struct mdoc *mdoc, enum mdoct from, int line, int ppos, const char *p)
{
enum mdoct res;
- if (MDOC_MAX == (res = mdoc_hash_find(p)))
- return(MDOC_MAX);
- if (MDOC_CALLABLE & mdoc_macros[res].flags)
- return(res);
+ if (from == MDOC_MAX || mdoc_macros[from].flags & MDOC_PARSED) {
+ res = mdoc_hash_find(p);
+ if (res != MDOC_MAX) {
+ 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);
+ }
+ }
return(MDOC_MAX);
}
-
-static int
+/*
+ * Rewind up to and including a specific node.
+ */
+static void
rew_last(struct mdoc *mdoc, const struct mdoc_node *to)
{
struct mdoc_node *n, *np;
assert(to);
mdoc->next = MDOC_NEXT_SIBLING;
-
- /* LINTED */
while (mdoc->last != to) {
/*
* Save the parent here, because we may delete the
@@ -288,17 +267,52 @@ rew_last(struct mdoc *mdoc, const struct mdoc_node *to)
* out to be lost.
*/
np = mdoc->last->parent;
- if ( ! mdoc_valid_post(mdoc))
- return(0);
+ mdoc_valid_post(mdoc);
n = mdoc->last;
mdoc->last = np;
assert(mdoc->last);
mdoc->last->last = n;
}
-
- return(mdoc_valid_post(mdoc));
+ mdoc_valid_post(mdoc);
}
+/*
+ * Rewind up to a specific block, including all blocks that broke it.
+ */
+static void
+rew_pending(struct mdoc *mdoc, const struct mdoc_node *n)
+{
+
+ for (;;) {
+ rew_last(mdoc, n);
+
+ switch (n->type) {
+ case MDOC_HEAD:
+ mdoc_body_alloc(mdoc, n->line, n->pos, n->tok);
+ return;
+ case MDOC_BLOCK:
+ break;
+ default:
+ return;
+ }
+
+ if ( ! (n->flags & MDOC_BROKEN))
+ return;
+
+ for (;;) {
+ if ((n = n->parent) == NULL)
+ return;
+
+ if (n->type == MDOC_BLOCK ||
+ n->type == MDOC_HEAD) {
+ if (n->flags & MDOC_ENDED)
+ break;
+ else
+ return;
+ }
+ }
+ }
+}
/*
* For a block closing macro, return the corresponding opening one.
@@ -308,37 +322,37 @@ static enum mdoct
rew_alt(enum mdoct tok)
{
switch (tok) {
- case (MDOC_Ac):
+ case MDOC_Ac:
return(MDOC_Ao);
- case (MDOC_Bc):
+ case MDOC_Bc:
return(MDOC_Bo);
- case (MDOC_Brc):
+ case MDOC_Brc:
return(MDOC_Bro);
- case (MDOC_Dc):
+ case MDOC_Dc:
return(MDOC_Do);
- case (MDOC_Ec):
+ case MDOC_Ec:
return(MDOC_Eo);
- case (MDOC_Ed):
+ case MDOC_Ed:
return(MDOC_Bd);
- case (MDOC_Ef):
+ case MDOC_Ef:
return(MDOC_Bf);
- case (MDOC_Ek):
+ case MDOC_Ek:
return(MDOC_Bk);
- case (MDOC_El):
+ case MDOC_El:
return(MDOC_Bl);
- case (MDOC_Fc):
+ case MDOC_Fc:
return(MDOC_Fo);
- case (MDOC_Oc):
+ case MDOC_Oc:
return(MDOC_Oo);
- case (MDOC_Pc):
+ case MDOC_Pc:
return(MDOC_Po);
- case (MDOC_Qc):
+ case MDOC_Qc:
return(MDOC_Qo);
- case (MDOC_Re):
+ case MDOC_Re:
return(MDOC_Rs);
- case (MDOC_Sc):
+ case MDOC_Sc:
return(MDOC_So);
- case (MDOC_Xc):
+ case MDOC_Xc:
return(MDOC_Xo);
default:
return(tok);
@@ -346,118 +360,7 @@ rew_alt(enum mdoct tok)
/* NOTREACHED */
}
-
-/*
- * Rewinding to tok, how do we have to handle *p?
- * REWIND_NONE: *p would delimit tok, but no tok scope is open
- * inside *p, so there is no need to rewind anything at all.
- * REWIND_THIS: *p matches tok, so rewind *p and nothing else.
- * REWIND_MORE: *p is implicit, rewind it and keep searching for tok.
- * REWIND_FORCE: *p is explicit, but tok is full, force rewinding *p.
- * REWIND_LATER: *p is explicit and still open, postpone rewinding.
- * REWIND_ERROR: No tok block is open at all.
- */
-static enum rew
-rew_dohalt(enum mdoct tok, enum mdoc_type type,
- const struct mdoc_node *p)
-{
-
- /*
- * No matching token, no delimiting block, no broken block.
- * This can happen when full implicit macros are called for
- * the first time but try to rewind their previous
- * instance anyway.
- */
- if (MDOC_ROOT == p->type)
- return(MDOC_BLOCK == type &&
- MDOC_EXPLICIT & mdoc_macros[tok].flags ?
- REWIND_ERROR : REWIND_NONE);
-
- /*
- * When starting to rewind, skip plain text
- * and nodes that have already been rewound.
- */
- if (MDOC_TEXT == p->type || MDOC_VALID & p->flags)
- return(REWIND_MORE);
-
- /*
- * The easiest case: Found a matching token.
- * This applies to both blocks and elements.
- */
- tok = rew_alt(tok);
- if (tok == p->tok)
- return(p->end ? REWIND_NONE :
- type == p->type ? REWIND_THIS : REWIND_MORE);
-
- /*
- * While elements do require rewinding for themselves,
- * they never affect rewinding of other nodes.
- */
- if (MDOC_ELEM == p->type)
- return(REWIND_MORE);
-
- /*
- * Blocks delimited by our target token get REWIND_MORE.
- * Blocks delimiting our target token get REWIND_NONE.
- */
- switch (tok) {
- case (MDOC_Bl):
- if (MDOC_It == p->tok)
- return(REWIND_MORE);
- break;
- case (MDOC_It):
- if (MDOC_BODY == p->type && MDOC_Bl == p->tok)
- return(REWIND_NONE);
- break;
- /*
- * XXX Badly nested block handling still fails badly
- * when one block is breaking two blocks of the same type.
- * This is an incomplete and extremely ugly workaround,
- * required to let the OpenBSD tree build.
- */
- case (MDOC_Oo):
- if (MDOC_Op == p->tok)
- return(REWIND_MORE);
- break;
- case (MDOC_Nm):
- return(REWIND_NONE);
- case (MDOC_Nd):
- /* FALLTHROUGH */
- case (MDOC_Ss):
- if (MDOC_BODY == p->type && MDOC_Sh == p->tok)
- return(REWIND_NONE);
- /* FALLTHROUGH */
- case (MDOC_Sh):
- if (MDOC_Nd == p->tok || MDOC_Ss == p->tok ||
- MDOC_Sh == p->tok)
- return(REWIND_MORE);
- break;
- default:
- break;
- }
-
- /*
- * Default block rewinding rules.
- * In particular, always skip block end markers,
- * and let all blocks rewind Nm children.
- */
- if (ENDBODY_NOT != p->end || MDOC_Nm == p->tok ||
- (MDOC_BLOCK == p->type &&
- ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)))
- return(REWIND_MORE);
-
- /*
- * By default, closing out full blocks
- * forces closing of broken explicit blocks,
- * while closing out partial blocks
- * allows delayed rewinding by default.
- */
- return (&blk_full == mdoc_macros[tok].fp ?
- REWIND_FORCE : REWIND_LATER);
-}
-
-
-static int
+static void
rew_elem(struct mdoc *mdoc, enum mdoct tok)
{
struct mdoc_node *n;
@@ -467,209 +370,60 @@ rew_elem(struct mdoc *mdoc, enum mdoct tok)
n = n->parent;
assert(MDOC_ELEM == n->type);
assert(tok == n->tok);
-
- return(rew_last(mdoc, n));
-}
-
-
-/*
- * We are trying to close a block identified by tok,
- * but the child block *broken is still open.
- * Thus, postpone closing the tok block
- * until the rew_sub call closing *broken.
- */
-static int
-make_pending(struct mdoc_node *broken, enum mdoct tok,
- struct mdoc *mdoc, int line, int ppos)
-{
- struct mdoc_node *breaker;
-
- /*
- * Iterate backwards, searching for the block matching tok,
- * that is, the block breaking the *broken block.
- */
- for (breaker = broken->parent; breaker; breaker = breaker->parent) {
-
- /*
- * If the *broken block had already been broken before
- * and we encounter its breaker, make the tok block
- * pending on the inner breaker.
- * Graphically, "[A breaker=[B broken=[C->B B] tok=A] C]"
- * becomes "[A broken=[B [C->B B] tok=A] C]"
- * and finally "[A [B->A [C->B B] A] C]".
- */
- if (breaker == broken->pending) {
- broken = breaker;
- continue;
- }
-
- if (REWIND_THIS != rew_dohalt(tok, MDOC_BLOCK, breaker))
- continue;
- if (MDOC_BODY == broken->type)
- broken = broken->parent;
-
- /*
- * Found the breaker.
- * If another, outer breaker is already pending on
- * the *broken block, we must not clobber the link
- * to the outer breaker, but make it pending on the
- * new, now inner breaker.
- * Graphically, "[A breaker=[B broken=[C->A A] tok=B] C]"
- * becomes "[A breaker=[B->A broken=[C A] tok=B] C]"
- * and finally "[A [B->A [C->B A] B] C]".
- */
- if (broken->pending) {
- struct mdoc_node *taker;
-
- /*
- * If the breaker had also been broken before,
- * it cannot take on the outer breaker itself,
- * but must hand it on to its own breakers.
- * Graphically, this is the following situation:
- * "[A [B breaker=[C->B B] broken=[D->A A] tok=C] D]"
- * "[A taker=[B->A breaker=[C->B B] [D->C A] C] D]"
- */
- taker = breaker;
- while (taker->pending)
- taker = taker->pending;
- taker->pending = broken->pending;
- }
- broken->pending = breaker;
- mandoc_vmsg(MANDOCERR_SCOPENEST, mdoc->parse, line, ppos,
- "%s breaks %s", mdoc_macronames[tok],
- mdoc_macronames[broken->tok]);
- return(1);
- }
-
- /*
- * Found no matching block for tok.
- * Are you trying to close a block that is not open?
- */
- return(0);
-}
-
-
-static int
-rew_sub(enum mdoc_type t, struct mdoc *mdoc,
- enum mdoct tok, int line, int ppos)
-{
- struct mdoc_node *n;
-
- n = mdoc->last;
- while (n) {
- switch (rew_dohalt(tok, t, n)) {
- case (REWIND_NONE):
- return(1);
- case (REWIND_THIS):
- n->lastline = line -
- (MDOC_NEWLINE & mdoc->flags &&
- ! (MDOC_EXPLICIT & mdoc_macros[tok].flags));
- break;
- case (REWIND_FORCE):
- mandoc_vmsg(MANDOCERR_SCOPEBROKEN, mdoc->parse,
- line, ppos, "%s breaks %s",
- mdoc_macronames[tok],
- mdoc_macronames[n->tok]);
- /* FALLTHROUGH */
- case (REWIND_MORE):
- n->lastline = line -
- (MDOC_NEWLINE & mdoc->flags ? 1 : 0);
- n = n->parent;
- continue;
- case (REWIND_LATER):
- if (make_pending(n, tok, mdoc, line, ppos) ||
- MDOC_BLOCK != t)
- return(1);
- /* FALLTHROUGH */
- case (REWIND_ERROR):
- mdoc_pmsg(mdoc, line, ppos, MANDOCERR_NOSCOPE);
- return(1);
- }
- break;
- }
-
- assert(n);
- if ( ! rew_last(mdoc, n))
- return(0);
-
- /*
- * The current block extends an enclosing block.
- * Now that the current block ends, close the enclosing block, too.
- */
- while (NULL != (n = n->pending)) {
- if ( ! rew_last(mdoc, n))
- return(0);
- if (MDOC_HEAD == n->type &&
- ! mdoc_body_alloc(mdoc, n->line, n->pos, n->tok))
- return(0);
- }
-
- return(1);
+ rew_last(mdoc, n);
}
/*
* Allocate a word and check whether it's punctuation or not.
* Punctuation consists of those tokens found in mdoc_isdelim().
*/
-static int
+static void
dword(struct mdoc *mdoc, int line, int col, const char *p,
enum mdelim d, int may_append)
{
-
- if (DELIM_MAX == d)
+
+ if (d == DELIM_MAX)
d = mdoc_isdelim(p);
if (may_append &&
- ! ((MDOC_SYNOPSIS | MDOC_KEEP | MDOC_SMOFF) & mdoc->flags) &&
- DELIM_NONE == d && MDOC_TEXT == mdoc->last->type &&
- DELIM_NONE == mdoc_isdelim(mdoc->last->string)) {
+ ! (mdoc->flags & (MDOC_SYNOPSIS | MDOC_KEEP | MDOC_SMOFF)) &&
+ d == DELIM_NONE && mdoc->last->type == MDOC_TEXT &&
+ mdoc_isdelim(mdoc->last->string) == DELIM_NONE) {
mdoc_word_append(mdoc, p);
- return(1);
+ return;
}
- if ( ! mdoc_word_alloc(mdoc, line, col, p))
- return(0);
-
- if (DELIM_OPEN == d)
- mdoc->last->flags |= MDOC_DELIMO;
+ mdoc_word_alloc(mdoc, line, col, p);
/*
- * Closing delimiters only suppress the preceding space
- * when they follow something, not when they start a new
- * block or element, and not when they follow `No'.
- *
- * XXX Explicitly special-casing MDOC_No here feels
- * like a layering violation. Find a better way
- * and solve this in the code related to `No'!
+ * If the word consists of a bare delimiter,
+ * flag the new node accordingly,
+ * unless doing so was vetoed by the invoking macro.
+ * Always clear the veto, it is only valid for one word.
*/
- else if (DELIM_CLOSE == d && mdoc->last->prev &&
- mdoc->last->prev->tok != MDOC_No &&
- mdoc->last->parent->tok != MDOC_Fd)
+ if (d == DELIM_OPEN)
+ mdoc->last->flags |= MDOC_DELIMO;
+ else if (d == DELIM_CLOSE &&
+ ! (mdoc->flags & MDOC_NODELIMC) &&
+ mdoc->last->parent->tok != MDOC_Fd)
mdoc->last->flags |= MDOC_DELIMC;
-
- return(1);
+ mdoc->flags &= ~MDOC_NODELIMC;
}
-static int
+static void
append_delims(struct mdoc *mdoc, int line, int *pos, char *buf)
{
- int la;
- enum margserr ac;
char *p;
+ int la;
- if ('\0' == buf[*pos])
- return(1);
+ if (buf[*pos] == '\0')
+ return;
for (;;) {
la = *pos;
- ac = mdoc_zargs(mdoc, line, pos, buf, &p);
-
- if (ARGS_ERROR == ac)
- return(0);
- else if (ARGS_EOLN == ac)
+ if (mdoc_args(mdoc, line, pos, buf, MDOC_MAX, &p) == ARGS_EOLN)
break;
-
dword(mdoc, line, la, p, DELIM_MAX, 1);
/*
@@ -683,25 +437,57 @@ append_delims(struct mdoc *mdoc, int line, int *pos, char *buf)
* knowing which symbols break this behaviour, for
* example, `. ;' shouldn't propagate the double-space.
*/
- if (mandoc_eos(p, strlen(p), 0))
+
+ if (mandoc_eos(p, strlen(p)))
mdoc->last->flags |= MDOC_EOS;
}
-
- return(1);
}
-
/*
- * Close out block partial/full explicit.
+ * Parse one word.
+ * If it is a macro, call it and return 1.
+ * Otherwise, allocate it and return 0.
*/
static int
+macro_or_word(MACRO_PROT_ARGS, int parsed)
+{
+ char *p;
+ enum mdoct ntok;
+
+ p = buf + ppos;
+ ntok = MDOC_MAX;
+ if (*p == '"')
+ p++;
+ else if (parsed && ! (mdoc->flags & MDOC_PHRASELIT))
+ ntok = lookup(mdoc, tok, line, ppos, p);
+
+ if (ntok == MDOC_MAX) {
+ dword(mdoc, line, ppos, p, DELIM_MAX, tok == MDOC_MAX ||
+ mdoc_macros[tok].flags & MDOC_JOIN);
+ return(0);
+ } else {
+ if (mdoc_macros[tok].fp == in_line_eoln)
+ rew_elem(mdoc, tok);
+ mdoc_macro(mdoc, ntok, line, ppos, pos, buf);
+ if (tok == MDOC_MAX)
+ append_delims(mdoc, line, pos, buf);
+ return(1);
+ }
+}
+
+/*
+ * Close out block partial/full explicit.
+ */
+static void
blk_exp_close(MACRO_PROT_ARGS)
{
struct mdoc_node *body; /* Our own body. */
+ struct mdoc_node *endbody; /* Our own end marker. */
+ struct mdoc_node *itblk; /* An It block starting later. */
struct mdoc_node *later; /* A sub-block starting later. */
- struct mdoc_node *n; /* For searching backwards. */
+ struct mdoc_node *n; /* Search back to our block. */
- int j, lastarg, maxargs, flushed, nl;
+ int j, lastarg, maxargs, nl;
enum margserr ac;
enum mdoct atok, ntok;
char *p;
@@ -709,11 +495,12 @@ blk_exp_close(MACRO_PROT_ARGS)
nl = MDOC_NEWLINE & mdoc->flags;
switch (tok) {
- case (MDOC_Ec):
+ case MDOC_Ec:
maxargs = 1;
break;
- case (MDOC_Ek):
+ case MDOC_Ek:
mdoc->flags &= ~MDOC_KEEP;
+ /* FALLTHROUGH */
default:
maxargs = 0;
break;
@@ -723,21 +510,32 @@ blk_exp_close(MACRO_PROT_ARGS)
* Search backwards for beginnings of blocks,
* both of our own and of pending sub-blocks.
*/
+
atok = rew_alt(tok);
- body = later = NULL;
+ body = endbody = itblk = later = NULL;
for (n = mdoc->last; n; n = n->parent) {
- if (MDOC_VALID & n->flags)
+ if (n->flags & MDOC_ENDED) {
+ if ( ! (n->flags & MDOC_VALID))
+ n->flags |= MDOC_BROKEN;
continue;
+ }
/* Remember the start of our own body. */
- if (MDOC_BODY == n->type && atok == n->tok) {
- if (ENDBODY_NOT == n->end)
+
+ if (n->type == MDOC_BODY && atok == n->tok) {
+ if (n->end == ENDBODY_NOT)
body = n;
continue;
}
- if (MDOC_BLOCK != n->type || MDOC_Nm == n->tok)
+ if (n->type != MDOC_BLOCK || n->tok == MDOC_Nm)
+ continue;
+
+ if (n->tok == MDOC_It) {
+ itblk = n;
continue;
+ }
+
if (atok == n->tok) {
assert(body);
@@ -746,109 +544,125 @@ blk_exp_close(MACRO_PROT_ARGS)
* When there is no pending sub block,
* just proceed to closing out.
*/
- if (NULL == later)
- break;
- /*
- * When there is a pending sub block,
- * postpone closing out the current block
- * until the rew_sub() closing out the sub-block.
- */
- make_pending(later, tok, mdoc, line, ppos);
+ if (later == NULL ||
+ (tok == MDOC_El && itblk == NULL))
+ break;
/*
+ * When there is a pending sub block, postpone
+ * closing out the current block until the
+ * rew_pending() closing out the sub-block.
* Mark the place where the formatting - but not
* the scope - of the current block ends.
*/
- if ( ! mdoc_endbody_alloc(mdoc, line, ppos,
- atok, body, ENDBODY_SPACE))
- return(0);
+
+ mandoc_vmsg(MANDOCERR_BLK_NEST, mdoc->parse,
+ line, ppos, "%s breaks %s",
+ mdoc_macronames[atok],
+ mdoc_macronames[later->tok]);
+
+ endbody = mdoc_endbody_alloc(mdoc, line, ppos,
+ atok, body, ENDBODY_SPACE);
+
+ if (tok == MDOC_El)
+ itblk->flags |= MDOC_ENDED | MDOC_BROKEN;
+
+ /*
+ * If a block closing macro taking arguments
+ * breaks another block, put the arguments
+ * into the end marker.
+ */
+
+ if (maxargs)
+ mdoc->next = MDOC_NEXT_CHILD;
break;
}
- /*
- * When finding an open sub block, remember the last
- * open explicit block, or, in case there are only
- * implicit ones, the first open implicit block.
- */
- if (later &&
- MDOC_EXPLICIT & mdoc_macros[later->tok].flags)
+ /* Explicit blocks close out description lines. */
+
+ if (n->tok == MDOC_Nd) {
+ rew_last(mdoc, n);
continue;
- if (MDOC_It != n->tok)
- later = n;
- }
+ }
- if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) {
- /* FIXME: do this in validate */
- if (buf[*pos])
- mdoc_pmsg(mdoc, line, ppos, MANDOCERR_ARGSLOST);
+ /* Breaking an open sub block. */
- if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos))
- return(0);
- return(rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos));
+ n->flags |= MDOC_BROKEN;
+ if (later == NULL)
+ later = n;
}
- if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos))
- return(0);
+ if (body == NULL) {
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, mdoc->parse,
+ line, ppos, mdoc_macronames[tok]);
+ if (maxargs && endbody == NULL) {
+ /*
+ * Stray .Ec without previous .Eo:
+ * Break the output line, keep the arguments.
+ */
+ mdoc_elem_alloc(mdoc, line, ppos, MDOC_br, NULL);
+ rew_elem(mdoc, MDOC_br);
+ }
+ } else if (endbody == NULL) {
+ rew_last(mdoc, body);
+ if (maxargs)
+ mdoc_tail_alloc(mdoc, line, ppos, atok);
+ }
- if (NULL == later && maxargs > 0)
- if ( ! mdoc_tail_alloc(mdoc, line, ppos, rew_alt(tok)))
- return(0);
+ if ( ! (mdoc_macros[tok].flags & MDOC_PARSED)) {
+ if (buf[*pos] != '\0')
+ mandoc_vmsg(MANDOCERR_ARG_SKIP,
+ mdoc->parse, line, ppos,
+ "%s %s", mdoc_macronames[tok],
+ buf + *pos);
+ if (endbody == NULL && n != NULL)
+ rew_pending(mdoc, n);
+ return;
+ }
- for (flushed = j = 0; ; j++) {
+ if (endbody != NULL)
+ n = endbody;
+ for (j = 0; ; j++) {
lastarg = *pos;
- if (j == maxargs && ! flushed) {
- if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos))
- return(0);
- flushed = 1;
+ if (j == maxargs && n != NULL) {
+ rew_pending(mdoc, n);
+ n = NULL;
}
ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
-
- if (ARGS_ERROR == ac)
- return(0);
- if (ARGS_PUNCT == ac)
- break;
- if (ARGS_EOLN == ac)
+ if (ac == ARGS_PUNCT || ac == ARGS_EOLN)
break;
- ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
+ ntok = ac == ARGS_QWORD ? MDOC_MAX :
+ lookup(mdoc, tok, line, lastarg, p);
- if (MDOC_MAX == ntok) {
- if ( ! dword(mdoc, line, lastarg, p, DELIM_MAX,
- MDOC_JOIN & mdoc_macros[tok].flags))
- return(0);
+ if (ntok == MDOC_MAX) {
+ dword(mdoc, line, lastarg, p, DELIM_MAX,
+ MDOC_JOIN & mdoc_macros[tok].flags);
continue;
}
- if ( ! flushed) {
- if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos))
- return(0);
- flushed = 1;
+ if (n != NULL) {
+ rew_pending(mdoc, n);
+ n = NULL;
}
-
mdoc->flags &= ~MDOC_NEWLINE;
-
- if ( ! mdoc_macro(mdoc, ntok, line, lastarg, pos, buf))
- return(0);
+ mdoc_macro(mdoc, ntok, line, lastarg, pos, buf);
break;
}
- if ( ! flushed && ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos))
- return(0);
-
- if ( ! nl)
- return(1);
- return(append_delims(mdoc, line, pos, buf));
+ if (n != NULL)
+ rew_pending(mdoc, n);
+ if (nl)
+ append_delims(mdoc, line, pos, buf);
}
-
-static int
+static void
in_line(MACRO_PROT_ARGS)
{
- int la, scope, cnt, nc, nl;
- enum margverr av;
+ int la, scope, cnt, firstarg, mayopen, nc, nl;
enum mdoct ntok;
enum margserr ac;
enum mdelim d;
@@ -863,17 +677,17 @@ in_line(MACRO_PROT_ARGS)
*/
switch (tok) {
- case (MDOC_An):
+ case MDOC_An:
/* FALLTHROUGH */
- case (MDOC_Ar):
+ case MDOC_Ar:
/* FALLTHROUGH */
- case (MDOC_Fl):
+ case MDOC_Fl:
/* FALLTHROUGH */
- case (MDOC_Mt):
+ case MDOC_Mt:
/* FALLTHROUGH */
- case (MDOC_Nm):
+ case MDOC_Nm:
/* FALLTHROUGH */
- case (MDOC_Pa):
+ case MDOC_Pa:
nc = 1;
break;
default:
@@ -881,126 +695,132 @@ in_line(MACRO_PROT_ARGS)
break;
}
- for (arg = NULL;; ) {
- la = *pos;
- av = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
-
- if (ARGV_WORD == av) {
- *pos = la;
- break;
- }
- if (ARGV_EOLN == av)
- break;
- if (ARGV_ARG == av)
- continue;
-
- mdoc_argv_free(arg);
- return(0);
- }
+ mdoc_argv(mdoc, line, tok, &arg, pos, buf);
+ d = DELIM_NONE;
+ firstarg = 1;
+ mayopen = 1;
for (cnt = scope = 0;; ) {
la = *pos;
ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
- if (ARGS_ERROR == ac)
- return(0);
- if (ARGS_EOLN == ac)
+ /*
+ * At the end of a macro line,
+ * opening delimiters do not suppress spacing.
+ */
+
+ if (ac == ARGS_EOLN) {
+ if (d == DELIM_OPEN)
+ mdoc->last->flags &= ~MDOC_DELIMO;
break;
- if (ARGS_PUNCT == ac)
+ }
+
+ /*
+ * The rest of the macro line is only punctuation,
+ * to be handled by append_delims().
+ * If there were no other arguments,
+ * do not allow the first one to suppress spacing,
+ * even if it turns out to be a closing one.
+ */
+
+ if (ac == ARGS_PUNCT) {
+ if (cnt == 0 && (nc == 0 || tok == MDOC_An))
+ mdoc->flags |= MDOC_NODELIMC;
break;
+ }
- ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
+ ntok = (ac == ARGS_QWORD || (tok == MDOC_Fn && !cnt)) ?
+ MDOC_MAX : lookup(mdoc, tok, line, la, p);
- /*
+ /*
* In this case, we've located a submacro and must
* execute it. Close out scope, if open. If no
* elements have been generated, either create one (nc)
* or raise a warning.
*/
- if (MDOC_MAX != ntok) {
- if (scope && ! rew_elem(mdoc, tok))
- return(0);
- if (nc && 0 == cnt) {
- if ( ! mdoc_elem_alloc(mdoc, line,
- ppos, tok, arg))
- return(0);
- if ( ! rew_last(mdoc, mdoc->last))
- return(0);
- } else if ( ! nc && 0 == cnt) {
+ if (ntok != MDOC_MAX) {
+ if (scope)
+ rew_elem(mdoc, tok);
+ if (nc && ! cnt) {
+ mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
+ rew_last(mdoc, mdoc->last);
+ } else if ( ! nc && ! cnt) {
mdoc_argv_free(arg);
- mdoc_pmsg(mdoc, line, ppos,
- MANDOCERR_MACROEMPTY);
+ mandoc_msg(MANDOCERR_MACRO_EMPTY,
+ mdoc->parse, line, ppos,
+ mdoc_macronames[tok]);
}
+ mdoc_macro(mdoc, ntok, line, la, pos, buf);
+ if (nl)
+ append_delims(mdoc, line, pos, buf);
+ return;
+ }
- if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf))
- return(0);
- if ( ! nl)
- return(1);
- return(append_delims(mdoc, line, pos, buf));
- }
-
- /*
+ /*
* Non-quote-enclosed punctuation. Set up our scope, if
* a word; rewind the scope, if a delimiter; then append
- * the word.
+ * the word.
*/
- d = ARGS_QWORD == ac ? DELIM_NONE : mdoc_isdelim(p);
+ d = ac == ARGS_QWORD ? DELIM_NONE : mdoc_isdelim(p);
if (DELIM_NONE != d) {
/*
* If we encounter closing punctuation, no word
- * has been omitted, no scope is open, and we're
+ * has been emitted, no scope is open, and we're
* allowed to have an empty element, then start
- * a new scope. `Ar', `Fl', and `Li', only do
- * this once per invocation. There may be more
- * of these (all of them?).
+ * a new scope.
*/
- if (0 == cnt && (nc || MDOC_Li == tok) &&
- DELIM_CLOSE == d && ! scope) {
- if ( ! mdoc_elem_alloc(mdoc, line,
- ppos, tok, arg))
- return(0);
- if (MDOC_Ar == tok || MDOC_Li == tok ||
- MDOC_Fl == tok)
- cnt++;
+ if ((d == DELIM_CLOSE ||
+ (d == DELIM_MIDDLE && tok == MDOC_Fl)) &&
+ !cnt && !scope && nc && mayopen) {
+ mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
scope = 1;
+ cnt++;
+ if (tok == MDOC_Nm)
+ mayopen = 0;
}
/*
* Close out our scope, if one is open, before
* any punctuation.
*/
- if (scope && ! rew_elem(mdoc, tok))
- return(0);
+ if (scope)
+ rew_elem(mdoc, tok);
scope = 0;
- } else if ( ! scope) {
- if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
- return(0);
+ if (tok == MDOC_Fn)
+ mayopen = 0;
+ } else if (mayopen && !scope) {
+ mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
scope = 1;
+ cnt++;
}
- if (DELIM_NONE == d)
- cnt++;
+ dword(mdoc, line, la, p, d,
+ MDOC_JOIN & mdoc_macros[tok].flags);
- if ( ! dword(mdoc, line, la, p, d,
- MDOC_JOIN & mdoc_macros[tok].flags))
- return(0);
+ /*
+ * If the first argument is a closing delimiter,
+ * do not suppress spacing before it.
+ */
+
+ if (firstarg && d == DELIM_CLOSE && !nc)
+ mdoc->last->flags &= ~MDOC_DELIMC;
+ firstarg = 0;
/*
* `Fl' macros have their scope re-opened with each new
* word so that the `-' can be added to each one without
* having to parse out spaces.
*/
- if (scope && MDOC_Fl == tok) {
- if ( ! rew_elem(mdoc, tok))
- return(0);
+ if (scope && tok == MDOC_Fl) {
+ rew_elem(mdoc, tok);
scope = 0;
}
}
- if (scope && ! rew_elem(mdoc, tok))
- return(0);
+ if (scope)
+ rew_elem(mdoc, tok);
/*
* If no elements have been collected and we're allowed to have
@@ -1008,45 +828,120 @@ in_line(MACRO_PROT_ARGS)
* raise a warning.
*/
- if (nc && 0 == cnt) {
- if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
- return(0);
- if ( ! rew_last(mdoc, mdoc->last))
- return(0);
- } else if ( ! nc && 0 == cnt) {
- mdoc_argv_free(arg);
- mdoc_pmsg(mdoc, line, ppos, MANDOCERR_MACROEMPTY);
+ if ( ! cnt) {
+ if (nc) {
+ mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
+ rew_last(mdoc, mdoc->last);
+ } else {
+ mdoc_argv_free(arg);
+ mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
+ line, ppos, mdoc_macronames[tok]);
+ }
}
-
- if ( ! nl)
- return(1);
- return(append_delims(mdoc, line, pos, buf));
+ if (nl)
+ append_delims(mdoc, line, pos, buf);
}
-
-static int
+static void
blk_full(MACRO_PROT_ARGS)
{
- int la, nl, nparsed;
+ int la, nl, parsed;
struct mdoc_arg *arg;
- struct mdoc_node *head; /* save of head macro */
- struct mdoc_node *body; /* save of body macro */
+ struct mdoc_node *blk; /* Our own or a broken block. */
+ struct mdoc_node *head; /* Our own head. */
+ struct mdoc_node *body; /* Our own body. */
struct mdoc_node *n;
- enum mdoc_type mtt;
- enum mdoct ntok;
enum margserr ac, lac;
- enum margverr av;
char *p;
nl = MDOC_NEWLINE & mdoc->flags;
- /* Close out prior implicit scope. */
+ if (buf[*pos] == '\0' && (tok == MDOC_Sh || tok == MDOC_Ss)) {
+ mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
+ line, ppos, mdoc_macronames[tok]);
+ return;
+ }
- if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) {
- if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos))
- return(0);
- if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos))
- return(0);
+ if ( ! (mdoc_macros[tok].flags & MDOC_EXPLICIT)) {
+
+ /* Here, tok is one of Sh Ss Nm Nd It. */
+
+ blk = NULL;
+ for (n = mdoc->last; n != NULL; n = n->parent) {
+ if (n->flags & MDOC_ENDED) {
+ if ( ! (n->flags & MDOC_VALID))
+ n->flags |= MDOC_BROKEN;
+ continue;
+ }
+ if (n->type != MDOC_BLOCK)
+ continue;
+
+ if (tok == MDOC_It && n->tok == MDOC_Bl) {
+ if (blk != NULL) {
+ mandoc_vmsg(MANDOCERR_BLK_BROKEN,
+ mdoc->parse, line, ppos,
+ "It breaks %s",
+ mdoc_macronames[blk->tok]);
+ rew_pending(mdoc, blk);
+ }
+ break;
+ }
+
+ if (mdoc_macros[n->tok].flags & MDOC_EXPLICIT) {
+ switch (tok) {
+ case MDOC_Sh:
+ /* FALLTHROUGH */
+ case MDOC_Ss:
+ mandoc_vmsg(MANDOCERR_BLK_BROKEN,
+ mdoc->parse, line, ppos,
+ "%s breaks %s",
+ mdoc_macronames[tok],
+ mdoc_macronames[n->tok]);
+ rew_pending(mdoc, n);
+ n = mdoc->last;
+ continue;
+ case MDOC_It:
+ /* Delay in case it's astray. */
+ blk = n;
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+
+ /* Here, n is one of Sh Ss Nm Nd It. */
+
+ if (tok != MDOC_Sh && (n->tok == MDOC_Sh ||
+ (tok != MDOC_Ss && (n->tok == MDOC_Ss ||
+ (tok != MDOC_It && n->tok == MDOC_It)))))
+ break;
+
+ /* Item breaking an explicit block. */
+
+ if (blk != NULL) {
+ mandoc_vmsg(MANDOCERR_BLK_BROKEN,
+ mdoc->parse, line, ppos,
+ "It breaks %s",
+ mdoc_macronames[blk->tok]);
+ rew_pending(mdoc, blk);
+ blk = NULL;
+ }
+
+ /* Close out prior implicit scopes. */
+
+ rew_last(mdoc, n);
+ }
+
+ /* Skip items outside lists. */
+
+ if (tok == MDOC_It && (n == NULL || n->tok != MDOC_Bl)) {
+ mandoc_vmsg(MANDOCERR_IT_STRAY, mdoc->parse,
+ line, ppos, "It %s", buf + *pos);
+ mdoc_elem_alloc(mdoc, line, ppos, MDOC_br, NULL);
+ rew_elem(mdoc, MDOC_br);
+ return;
+ }
}
/*
@@ -1058,72 +953,40 @@ blk_full(MACRO_PROT_ARGS)
* regular child nodes.
*/
- for (arg = NULL;; ) {
- la = *pos;
- av = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
-
- if (ARGV_WORD == av) {
- *pos = la;
- break;
- }
-
- if (ARGV_EOLN == av)
- break;
- if (ARGV_ARG == av)
- continue;
-
- mdoc_argv_free(arg);
- return(0);
- }
-
- if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, arg))
- return(0);
-
+ mdoc_argv(mdoc, line, tok, &arg, pos, buf);
+ blk = mdoc_block_alloc(mdoc, line, ppos, tok, arg);
head = body = NULL;
/*
* Exception: Heads of `It' macros in `-diag' lists are not
* parsed, even though `It' macros in general are parsed.
*/
- nparsed = MDOC_It == tok &&
- MDOC_Bl == mdoc->last->parent->tok &&
- LIST_diag == mdoc->last->parent->norm->Bl.type;
+
+ parsed = tok != MDOC_It ||
+ mdoc->last->parent->tok != MDOC_Bl ||
+ mdoc->last->parent->norm->Bl.type != LIST_diag;
/*
* The `Nd' macro has all arguments in its body: it's a hybrid
* of block partial-explicit and full-implicit. Stupid.
*/
- if (MDOC_Nd == tok) {
- if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
- return(0);
- head = mdoc->last;
- if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos))
- return(0);
- if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
- return(0);
- body = mdoc->last;
+ if (tok == MDOC_Nd) {
+ head = mdoc_head_alloc(mdoc, line, ppos, tok);
+ rew_last(mdoc, head);
+ body = mdoc_body_alloc(mdoc, line, ppos, tok);
}
- if (MDOC_Bk == tok)
+ if (tok == MDOC_Bk)
mdoc->flags |= MDOC_KEEP;
- ac = ARGS_ERROR;
-
- for ( ; ; ) {
+ ac = ARGS_PEND;
+ for (;;) {
la = *pos;
- /* Initialise last-phrase-type with ARGS_PEND. */
- lac = ARGS_ERROR == ac ? ARGS_PEND : ac;
+ lac = ac;
ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
-
- if (ARGS_PUNCT == ac)
- break;
-
- if (ARGS_ERROR == ac)
- return(0);
-
- if (ARGS_EOLN == ac) {
- if (ARGS_PPHRASE != lac && ARGS_PHRASE != lac)
+ if (ac == ARGS_EOLN) {
+ if (lac != ARGS_PPHRASE && lac != ARGS_PHRASE)
break;
/*
* This is necessary: if the last token on a
@@ -1132,55 +995,56 @@ blk_full(MACRO_PROT_ARGS)
* reopen our scope if the last parse was a
* phrase or partial phrase.
*/
- if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos))
- return(0);
- if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
- return(0);
- body = mdoc->last;
+ if (body != NULL)
+ rew_last(mdoc, body);
+ body = mdoc_body_alloc(mdoc, line, ppos, tok);
+ break;
+ }
+ if (tok == MDOC_Bd || tok == MDOC_Bk) {
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS,
+ mdoc->parse, line, la, "%s ... %s",
+ mdoc_macronames[tok], buf + la);
+ break;
+ }
+ if (tok == MDOC_Rs) {
+ mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse,
+ line, la, "Rs %s", buf + la);
break;
}
+ if (ac == ARGS_PUNCT)
+ break;
- /*
+ /*
* Emit leading punctuation (i.e., punctuation before
* the MDOC_HEAD) for non-phrase types.
*/
- if (NULL == head &&
- ARGS_PEND != ac &&
- ARGS_PHRASE != ac &&
- ARGS_PPHRASE != ac &&
- ARGS_QWORD != ac &&
- DELIM_OPEN == mdoc_isdelim(p)) {
- if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0))
- return(0);
+ if (head == NULL &&
+ ac != ARGS_PEND &&
+ ac != ARGS_PHRASE &&
+ ac != ARGS_PPHRASE &&
+ ac != ARGS_QWORD &&
+ mdoc_isdelim(p) == DELIM_OPEN) {
+ dword(mdoc, line, la, p, DELIM_OPEN, 0);
continue;
}
/* Open a head if one hasn't been opened. */
- if (NULL == head) {
- if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
- return(0);
- head = mdoc->last;
- }
+ if (head == NULL)
+ head = mdoc_head_alloc(mdoc, line, ppos, tok);
+
+ if (ac == ARGS_PHRASE ||
+ ac == ARGS_PEND ||
+ ac == ARGS_PPHRASE) {
- if (ARGS_PHRASE == ac ||
- ARGS_PEND == ac ||
- ARGS_PPHRASE == ac) {
/*
* If we haven't opened a body yet, rewind the
* head; if we have, rewind that instead.
*/
- mtt = body ? MDOC_BODY : MDOC_HEAD;
- if ( ! rew_sub(mtt, mdoc, tok, line, ppos))
- return(0);
-
- /* Then allocate our body context. */
-
- if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
- return(0);
- body = mdoc->last;
+ rew_last(mdoc, body == NULL ? head : body);
+ body = mdoc_body_alloc(mdoc, line, ppos, tok);
/*
* Process phrases: set whether we're in a
@@ -1188,88 +1052,65 @@ blk_full(MACRO_PROT_ARGS)
* then call down into the phrase parser.
*/
- if (ARGS_PPHRASE == ac)
+ if (ac == ARGS_PPHRASE)
mdoc->flags |= MDOC_PPHRASE;
- if (ARGS_PEND == ac && ARGS_PPHRASE == lac)
+ if (ac == ARGS_PEND && lac == ARGS_PPHRASE)
mdoc->flags |= MDOC_PPHRASE;
-
- if ( ! phrase(mdoc, line, la, buf))
- return(0);
-
+ parse_rest(mdoc, MDOC_MAX, line, &la, buf);
mdoc->flags &= ~MDOC_PPHRASE;
continue;
}
- ntok = nparsed || ARGS_QWORD == ac ?
- MDOC_MAX : lookup(tok, p);
-
- if (MDOC_MAX == ntok) {
- if ( ! dword(mdoc, line, la, p, DELIM_MAX,
- MDOC_JOIN & mdoc_macros[tok].flags))
- return(0);
- continue;
- }
-
- if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf))
- return(0);
- break;
- }
-
- if (NULL == head) {
- if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
- return(0);
- head = mdoc->last;
+ if (macro_or_word(mdoc, tok, line, la, pos, buf, parsed))
+ break;
}
-
- if (nl && ! append_delims(mdoc, line, pos, buf))
- return(0);
- /* If we've already opened our body, exit now. */
-
- if (NULL != body)
+ if (blk->flags & MDOC_VALID)
+ return;
+ if (head == NULL)
+ head = mdoc_head_alloc(mdoc, line, ppos, tok);
+ if (nl && tok != MDOC_Bd && tok != MDOC_Bl && tok != MDOC_Rs)
+ append_delims(mdoc, line, pos, buf);
+ if (body != NULL)
goto out;
/*
* If there is an open (i.e., unvalidated) sub-block requiring
* explicit close-out, postpone switching the current block from
- * head to body until the rew_sub() call closing out that
+ * head to body until the rew_pending() call closing out that
* sub-block.
*/
for (n = mdoc->last; n && n != head; n = n->parent) {
- if (MDOC_BLOCK == n->type &&
- MDOC_EXPLICIT & mdoc_macros[n->tok].flags &&
- ! (MDOC_VALID & n->flags)) {
- n->pending = head;
- return(1);
+ if (n->flags & MDOC_ENDED) {
+ if ( ! (n->flags & MDOC_VALID))
+ n->flags |= MDOC_BROKEN;
+ continue;
+ }
+ if (n->type == MDOC_BLOCK &&
+ mdoc_macros[n->tok].flags & MDOC_EXPLICIT) {
+ n->flags = MDOC_BROKEN;
+ head->flags = MDOC_ENDED;
}
}
+ if (head->flags & MDOC_ENDED)
+ return;
/* Close out scopes to remain in a consistent state. */
- if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos))
- return(0);
- if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
- return(0);
-
+ rew_last(mdoc, head);
+ body = mdoc_body_alloc(mdoc, line, ppos, tok);
out:
- if ( ! (MDOC_FREECOL & mdoc->flags))
- return(1);
-
- if ( ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos))
- return(0);
- if ( ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos))
- return(0);
-
- mdoc->flags &= ~MDOC_FREECOL;
- return(1);
+ if (mdoc->flags & MDOC_FREECOL) {
+ rew_last(mdoc, body);
+ rew_last(mdoc, blk);
+ mdoc->flags &= ~MDOC_FREECOL;
+ }
}
-
-static int
+static void
blk_part_imp(MACRO_PROT_ARGS)
{
int la, nl;
- enum mdoct ntok;
enum margserr ac;
char *p;
struct mdoc_node *blk; /* saved block context */
@@ -1287,15 +1128,8 @@ blk_part_imp(MACRO_PROT_ARGS)
* or more closing punctuation nodes.
*/
- if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL))
- return(0);
-
- blk = mdoc->last;
-
- if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
- return(0);
- if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos))
- return(0);
+ blk = mdoc_block_alloc(mdoc, line, ppos, tok, NULL);
+ rew_last(mdoc, mdoc_head_alloc(mdoc, line, ppos, tok));
/*
* Open the body scope "on-demand", that is, after we've
@@ -1306,129 +1140,74 @@ blk_part_imp(MACRO_PROT_ARGS)
for (body = NULL; ; ) {
la = *pos;
ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
-
- if (ARGS_ERROR == ac)
- return(0);
- if (ARGS_EOLN == ac)
- break;
- if (ARGS_PUNCT == ac)
+ if (ac == ARGS_EOLN || ac == ARGS_PUNCT)
break;
- if (NULL == body && ARGS_QWORD != ac &&
- DELIM_OPEN == mdoc_isdelim(p)) {
- if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0))
- return(0);
+ if (body == NULL && ac != ARGS_QWORD &&
+ mdoc_isdelim(p) == DELIM_OPEN) {
+ dword(mdoc, line, la, p, DELIM_OPEN, 0);
continue;
}
- if (NULL == body) {
- if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
- return(0);
- body = mdoc->last;
- }
-
- ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
+ if (body == NULL)
+ body = mdoc_body_alloc(mdoc, line, ppos, tok);
- if (MDOC_MAX == ntok) {
- if ( ! dword(mdoc, line, la, p, DELIM_MAX,
- MDOC_JOIN & mdoc_macros[tok].flags))
- return(0);
- continue;
- }
-
- if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf))
- return(0);
- break;
- }
-
- /* Clean-ups to leave in a consistent state. */
-
- if (NULL == body) {
- if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
- return(0);
- body = mdoc->last;
- }
-
- for (n = body->child; n && n->next; n = n->next)
- /* Do nothing. */ ;
-
- /*
- * End of sentence spacing: if the last node is a text node and
- * has a trailing period, then mark it as being end-of-sentence.
- */
-
- if (n && MDOC_TEXT == n->type && n->string)
- if (mandoc_eos(n->string, strlen(n->string), 1))
- n->flags |= MDOC_EOS;
-
- /* Up-propagate the end-of-space flag. */
-
- if (n && (MDOC_EOS & n->flags)) {
- body->flags |= MDOC_EOS;
- body->parent->flags |= MDOC_EOS;
+ if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
+ break;
}
+ if (body == NULL)
+ body = mdoc_body_alloc(mdoc, line, ppos, tok);
/*
* If there is an open sub-block requiring explicit close-out,
- * postpone closing out the current block
- * until the rew_sub() call closing out the sub-block.
+ * postpone closing out the current block until the
+ * rew_pending() call closing out the sub-block.
*/
+
for (n = mdoc->last; n && n != body && n != blk->parent;
- n = n->parent) {
- if (MDOC_BLOCK == n->type &&
- MDOC_EXPLICIT & mdoc_macros[n->tok].flags &&
- ! (MDOC_VALID & n->flags)) {
- make_pending(n, tok, mdoc, line, ppos);
- if ( ! mdoc_endbody_alloc(mdoc, line, ppos,
- tok, body, ENDBODY_NOSPACE))
- return(0);
- return(1);
+ n = n->parent) {
+ if (n->flags & MDOC_ENDED) {
+ if ( ! (n->flags & MDOC_VALID))
+ n->flags |= MDOC_BROKEN;
+ continue;
+ }
+ if (n->type == MDOC_BLOCK &&
+ mdoc_macros[n->tok].flags & MDOC_EXPLICIT) {
+ n->flags |= MDOC_BROKEN;
+ if ( ! (body->flags & MDOC_ENDED)) {
+ mandoc_vmsg(MANDOCERR_BLK_NEST,
+ mdoc->parse, line, ppos,
+ "%s breaks %s", mdoc_macronames[tok],
+ mdoc_macronames[n->tok]);
+ mdoc_endbody_alloc(mdoc, line, ppos,
+ tok, body, ENDBODY_NOSPACE);
+ }
}
}
+ assert(n == body);
+ if (body->flags & MDOC_ENDED)
+ return;
- /*
- * If we can't rewind to our body, then our scope has already
- * been closed by another macro (like `Oc' closing `Op'). This
- * is ugly behaviour nodding its head to OpenBSD's overwhelming
- * crufty use of `Op' breakage.
- */
- if (n != body)
- mandoc_vmsg(MANDOCERR_SCOPENEST, mdoc->parse, line, ppos,
- "%s broken", mdoc_macronames[tok]);
-
- if (n && ! rew_sub(MDOC_BODY, mdoc, tok, line, ppos))
- return(0);
-
- /* Standard appending of delimiters. */
-
- if (nl && ! append_delims(mdoc, line, pos, buf))
- return(0);
-
- /* Rewind scope, if applicable. */
-
- if (n && ! rew_sub(MDOC_BLOCK, mdoc, tok, line, ppos))
- return(0);
+ rew_last(mdoc, body);
+ if (nl)
+ append_delims(mdoc, line, pos, buf);
+ rew_pending(mdoc, blk);
/* Move trailing .Ns out of scope. */
for (n = body->child; n && n->next; n = n->next)
/* Do nothing. */ ;
- if (n && MDOC_Ns == n->tok)
+ if (n && n->tok == MDOC_Ns)
mdoc_node_relink(mdoc, n);
-
- return(1);
}
-
-static int
+static void
blk_part_exp(MACRO_PROT_ARGS)
{
int la, nl;
enum margserr ac;
struct mdoc_node *head; /* keep track of head */
- struct mdoc_node *body; /* keep track of body */
char *p;
- enum mdoct ntok;
nl = MDOC_NEWLINE & mdoc->flags;
@@ -1438,108 +1217,57 @@ blk_part_exp(MACRO_PROT_ARGS)
* case of `Eo'); and a body that may be empty.
*/
- if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, NULL))
- return(0);
-
- for (head = body = NULL; ; ) {
+ mdoc_block_alloc(mdoc, line, ppos, tok, NULL);
+ head = NULL;
+ for (;;) {
la = *pos;
ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
-
- if (ARGS_ERROR == ac)
- return(0);
- if (ARGS_PUNCT == ac)
- break;
- if (ARGS_EOLN == ac)
+ if (ac == ARGS_PUNCT || ac == ARGS_EOLN)
break;
/* Flush out leading punctuation. */
- if (NULL == head && ARGS_QWORD != ac &&
- DELIM_OPEN == mdoc_isdelim(p)) {
- assert(NULL == body);
- if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0))
- return(0);
+ if (head == NULL && ac != ARGS_QWORD &&
+ mdoc_isdelim(p) == DELIM_OPEN) {
+ dword(mdoc, line, la, p, DELIM_OPEN, 0);
continue;
}
- if (NULL == head) {
- assert(NULL == body);
- if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
- return(0);
- head = mdoc->last;
- }
-
- /*
- * `Eo' gobbles any data into the head, but most other
- * macros just immediately close out and begin the body.
- */
-
- if (NULL == body) {
- assert(head);
- /* No check whether it's a macro! */
- if (MDOC_Eo == tok)
- if ( ! dword(mdoc, line, la, p, DELIM_MAX, 0))
- return(0);
-
- if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos))
- return(0);
- if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
- return(0);
- body = mdoc->last;
-
- if (MDOC_Eo == tok)
+ if (head == NULL) {
+ head = mdoc_head_alloc(mdoc, line, ppos, tok);
+ if (tok == MDOC_Eo) /* Not parsed. */
+ dword(mdoc, line, la, p, DELIM_MAX, 0);
+ rew_last(mdoc, head);
+ mdoc_body_alloc(mdoc, line, ppos, tok);
+ if (tok == MDOC_Eo)
continue;
}
- assert(NULL != head && NULL != body);
-
- ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
-
- if (MDOC_MAX == ntok) {
- if ( ! dword(mdoc, line, la, p, DELIM_MAX,
- MDOC_JOIN & mdoc_macros[tok].flags))
- return(0);
- continue;
- }
-
- if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf))
- return(0);
- break;
+ if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
+ break;
}
/* Clean-up to leave in a consistent state. */
- if (NULL == head)
- if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
- return(0);
-
- if (NULL == body) {
- if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos))
- return(0);
- if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
- return(0);
+ if (head == NULL) {
+ rew_last(mdoc, mdoc_head_alloc(mdoc, line, ppos, tok));
+ mdoc_body_alloc(mdoc, line, ppos, tok);
}
-
- /* Standard appending of delimiters. */
-
- if ( ! nl)
- return(1);
- return(append_delims(mdoc, line, pos, buf));
+ if (nl)
+ append_delims(mdoc, line, pos, buf);
}
-
-/* ARGSUSED */
-static int
+static void
in_line_argn(MACRO_PROT_ARGS)
{
- int la, flushed, j, maxargs, nl;
- enum margserr ac;
- enum margverr av;
struct mdoc_arg *arg;
char *p;
+ enum margserr ac;
enum mdoct ntok;
+ int state; /* arg#; -1: not yet open; -2: closed */
+ int la, maxargs, nl;
- nl = MDOC_NEWLINE & mdoc->flags;
+ nl = mdoc->flags & MDOC_NEWLINE;
/*
* A line macro that has a fixed number of arguments (maxargs).
@@ -1550,18 +1278,18 @@ in_line_argn(MACRO_PROT_ARGS)
*/
switch (tok) {
- case (MDOC_Ap):
- /* FALLTHROUGH */
- case (MDOC_No):
+ case MDOC_Ap:
/* FALLTHROUGH */
- case (MDOC_Ns):
+ case MDOC_Ns:
/* FALLTHROUGH */
- case (MDOC_Ux):
+ case MDOC_Ux:
maxargs = 0;
break;
- case (MDOC_Bx):
+ case MDOC_Bx:
/* FALLTHROUGH */
- case (MDOC_Xr):
+ case MDOC_Es:
+ /* FALLTHROUGH */
+ case MDOC_Xr:
maxargs = 2;
break;
default:
@@ -1569,286 +1297,176 @@ in_line_argn(MACRO_PROT_ARGS)
break;
}
- for (arg = NULL; ; ) {
- la = *pos;
- av = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
+ mdoc_argv(mdoc, line, tok, &arg, pos, buf);
- if (ARGV_WORD == av) {
- *pos = la;
- break;
- }
+ state = -1;
+ p = NULL;
+ for (;;) {
+ la = *pos;
+ ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
- if (ARGV_EOLN == av)
- break;
- if (ARGV_ARG == av)
+ if (ac == ARGS_WORD && state == -1 &&
+ ! (mdoc_macros[tok].flags & MDOC_IGNDELIM) &&
+ mdoc_isdelim(p) == DELIM_OPEN) {
+ dword(mdoc, line, la, p, DELIM_OPEN, 0);
continue;
+ }
- mdoc_argv_free(arg);
- return(0);
- }
-
- for (flushed = j = 0; ; ) {
- la = *pos;
- ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
+ if (state == -1 && tok != MDOC_In &&
+ tok != MDOC_St && tok != MDOC_Xr) {
+ mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
+ state = 0;
+ }
- if (ARGS_ERROR == ac)
- return(0);
- if (ARGS_PUNCT == ac)
- break;
- if (ARGS_EOLN == ac)
+ if (ac == ARGS_PUNCT || ac == ARGS_EOLN) {
+ if (abs(state) < 2 && tok == MDOC_Pf)
+ mandoc_vmsg(MANDOCERR_PF_SKIP,
+ mdoc->parse, line, ppos, "Pf %s",
+ p == NULL ? "at eol" : p);
break;
+ }
- if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) &&
- ARGS_QWORD != ac && 0 == j &&
- DELIM_OPEN == mdoc_isdelim(p)) {
- if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0))
- return(0);
- continue;
- } else if (0 == j)
- if ( ! mdoc_elem_alloc(mdoc, line, la, tok, arg))
- return(0);
-
- if (j == maxargs && ! flushed) {
- if ( ! rew_elem(mdoc, tok))
- return(0);
- flushed = 1;
+ if (state == maxargs) {
+ rew_elem(mdoc, tok);
+ state = -2;
}
- ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
+ ntok = (ac == ARGS_QWORD || (tok == MDOC_Pf && state == 0)) ?
+ MDOC_MAX : lookup(mdoc, tok, line, la, p);
- if (MDOC_MAX != ntok) {
- if ( ! flushed && ! rew_elem(mdoc, tok))
- return(0);
- flushed = 1;
- if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf))
- return(0);
- j++;
+ if (ntok != MDOC_MAX) {
+ if (state >= 0) {
+ rew_elem(mdoc, tok);
+ state = -2;
+ }
+ mdoc_macro(mdoc, ntok, line, la, pos, buf);
break;
}
- if ( ! (MDOC_IGNDELIM & mdoc_macros[tok].flags) &&
- ARGS_QWORD != ac &&
- ! flushed &&
- DELIM_NONE != mdoc_isdelim(p)) {
- if ( ! rew_elem(mdoc, tok))
- return(0);
- flushed = 1;
+ if (ac == ARGS_QWORD ||
+ mdoc_macros[tok].flags & MDOC_IGNDELIM ||
+ mdoc_isdelim(p) == DELIM_NONE) {
+ if (state == -1) {
+ mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
+ state = 1;
+ } else if (state >= 0)
+ state++;
+ } else if (state >= 0) {
+ rew_elem(mdoc, tok);
+ state = -2;
}
- if ( ! dword(mdoc, line, la, p, DELIM_MAX,
- MDOC_JOIN & mdoc_macros[tok].flags))
- return(0);
- j++;
+ dword(mdoc, line, la, p, DELIM_MAX,
+ MDOC_JOIN & mdoc_macros[tok].flags);
}
- if (0 == j && ! mdoc_elem_alloc(mdoc, line, la, tok, arg))
- return(0);
-
- /* Close out in a consistent state. */
+ if (state == -1) {
+ mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
+ line, ppos, mdoc_macronames[tok]);
+ return;
+ }
- if ( ! flushed && ! rew_elem(mdoc, tok))
- return(0);
- if ( ! nl)
- return(1);
- return(append_delims(mdoc, line, pos, buf));
+ if (state == 0 && tok == MDOC_Pf)
+ append_delims(mdoc, line, pos, buf);
+ if (state >= 0)
+ rew_elem(mdoc, tok);
+ if (nl)
+ append_delims(mdoc, line, pos, buf);
}
-
-static int
+static void
in_line_eoln(MACRO_PROT_ARGS)
{
- int la;
- enum margserr ac;
- enum margverr av;
- struct mdoc_arg *arg;
- char *p;
- enum mdoct ntok;
-
- assert( ! (MDOC_PARSED & mdoc_macros[tok].flags));
-
- if (tok == MDOC_Pp)
- rew_sub(MDOC_BLOCK, mdoc, MDOC_Nm, line, ppos);
-
- /* Parse macro arguments. */
+ struct mdoc_node *n;
+ struct mdoc_arg *arg;
- for (arg = NULL; ; ) {
- la = *pos;
- av = mdoc_argv(mdoc, line, tok, &arg, pos, buf);
-
- if (ARGV_WORD == av) {
- *pos = la;
- break;
- }
- if (ARGV_EOLN == av)
- break;
- if (ARGV_ARG == av)
- continue;
-
- mdoc_argv_free(arg);
- return(0);
+ if ((tok == MDOC_Pp || tok == MDOC_Lp) &&
+ ! (mdoc->flags & MDOC_SYNOPSIS)) {
+ n = mdoc->last;
+ if (mdoc->next == MDOC_NEXT_SIBLING)
+ n = n->parent;
+ if (n->tok == MDOC_Nm)
+ rew_last(mdoc, mdoc->last->parent);
}
- /* Open element scope. */
+ if (buf[*pos] == '\0' &&
+ (tok == MDOC_Fd || mdoc_macronames[tok][0] == '%')) {
+ mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
+ line, ppos, mdoc_macronames[tok]);
+ return;
+ }
- if ( ! mdoc_elem_alloc(mdoc, line, ppos, tok, arg))
- return(0);
+ mdoc_argv(mdoc, line, tok, &arg, pos, buf);
+ mdoc_elem_alloc(mdoc, line, ppos, tok, arg);
+ if (parse_rest(mdoc, tok, line, pos, buf))
+ return;
+ rew_elem(mdoc, tok);
+}
- /* Parse argument terms. */
+/*
+ * The simplest argument parser available: Parse the remaining
+ * words until the end of the phrase or line and return 0
+ * or until the next macro, call that macro, and return 1.
+ */
+static int
+parse_rest(struct mdoc *mdoc, enum mdoct tok, int line, int *pos, char *buf)
+{
+ int la;
for (;;) {
la = *pos;
- ac = mdoc_args(mdoc, line, pos, buf, tok, &p);
-
- if (ARGS_ERROR == ac)
+ if (mdoc_args(mdoc, line, pos, buf, tok, NULL) == ARGS_EOLN)
return(0);
- if (ARGS_EOLN == ac)
- break;
-
- ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
-
- if (MDOC_MAX == ntok) {
- if ( ! dword(mdoc, line, la, p, DELIM_MAX,
- MDOC_JOIN & mdoc_macros[tok].flags))
- return(0);
- continue;
- }
-
- if ( ! rew_elem(mdoc, tok))
- return(0);
- return(mdoc_macro(mdoc, ntok, line, la, pos, buf));
+ if (macro_or_word(mdoc, tok, line, la, pos, buf, 1))
+ return(1);
}
-
- /* Close out (no delimiters). */
-
- return(rew_elem(mdoc, tok));
}
-
-/* ARGSUSED */
-static int
+static void
ctx_synopsis(MACRO_PROT_ARGS)
{
- int nl;
-
- nl = MDOC_NEWLINE & mdoc->flags;
-
- /* If we're not in the SYNOPSIS, go straight to in-line. */
- if ( ! (MDOC_SYNOPSIS & mdoc->flags))
- return(in_line(mdoc, tok, line, ppos, pos, buf));
-
- /* If we're a nested call, same place. */
- if ( ! nl)
- return(in_line(mdoc, tok, line, ppos, pos, buf));
-
- /*
- * XXX: this will open a block scope; however, if later we end
- * up formatting the block scope, then child nodes will inherit
- * the formatting. Be careful.
- */
- if (MDOC_Nm == tok)
- return(blk_full(mdoc, tok, line, ppos, pos, buf));
- assert(MDOC_Vt == tok);
- return(blk_part_imp(mdoc, tok, line, ppos, pos, buf));
-}
-
-/* ARGSUSED */
-static int
-obsolete(MACRO_PROT_ARGS)
-{
-
- mdoc_pmsg(mdoc, line, ppos, MANDOCERR_MACROOBS);
- return(1);
+ if (~mdoc->flags & (MDOC_SYNOPSIS | MDOC_NEWLINE))
+ in_line(mdoc, tok, line, ppos, pos, buf);
+ else if (tok == MDOC_Nm)
+ blk_full(mdoc, tok, line, ppos, pos, buf);
+ else {
+ assert(tok == MDOC_Vt);
+ blk_part_imp(mdoc, tok, line, ppos, pos, buf);
+ }
}
-
/*
* Phrases occur within `Bl -column' entries, separated by `Ta' or tabs.
* They're unusual because they're basically free-form text until a
* macro is encountered.
*/
-static int
-phrase(struct mdoc *mdoc, int line, int ppos, char *buf)
+static void
+phrase_ta(MACRO_PROT_ARGS)
{
- int la, pos;
- enum margserr ac;
- enum mdoct ntok;
- char *p;
-
- for (pos = ppos; ; ) {
- la = pos;
-
- ac = mdoc_zargs(mdoc, line, &pos, buf, &p);
+ struct mdoc_node *body, *n;
- if (ARGS_ERROR == ac)
- return(0);
- if (ARGS_EOLN == ac)
- break;
-
- ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p);
+ /* Make sure we are in a column list or ignore this macro. */
- if (MDOC_MAX == ntok) {
- if ( ! dword(mdoc, line, la, p, DELIM_MAX, 1))
- return(0);
+ body = NULL;
+ for (n = mdoc->last; n != NULL; n = n->parent) {
+ if (n->flags & MDOC_ENDED)
continue;
- }
-
- if ( ! mdoc_macro(mdoc, ntok, line, la, &pos, buf))
- return(0);
- return(append_delims(mdoc, line, &pos, buf));
+ if (n->tok == MDOC_It && n->type == MDOC_BODY)
+ body = n;
+ if (n->tok == MDOC_Bl)
+ break;
}
- return(1);
-}
-
-
-/* ARGSUSED */
-static int
-phrase_ta(MACRO_PROT_ARGS)
-{
- struct mdoc_node *n;
- int la;
- enum mdoct ntok;
- enum margserr ac;
- char *p;
-
- /* Make sure we are in a column list or ignore this macro. */
- n = mdoc->last;
- while (NULL != n && MDOC_Bl != n->tok)
- n = n->parent;
- if (NULL == n || LIST_column != n->norm->Bl.type) {
- mdoc_pmsg(mdoc, line, ppos, MANDOCERR_STRAYTA);
- return(1);
+ if (n == NULL || n->norm->Bl.type != LIST_column) {
+ mandoc_msg(MANDOCERR_TA_STRAY, mdoc->parse,
+ line, ppos, "Ta");
+ return;
}
/* Advance to the next column. */
- if ( ! rew_sub(MDOC_BODY, mdoc, MDOC_It, line, ppos))
- return(0);
- if ( ! mdoc_body_alloc(mdoc, line, ppos, MDOC_It))
- return(0);
-
- for (;;) {
- la = *pos;
- ac = mdoc_zargs(mdoc, line, pos, buf, &p);
-
- if (ARGS_ERROR == ac)
- return(0);
- if (ARGS_EOLN == ac)
- break;
-
- ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p);
-
- if (MDOC_MAX == ntok) {
- if ( ! dword(mdoc, line, la, p, DELIM_MAX,
- MDOC_JOIN & mdoc_macros[tok].flags))
- return(0);
- continue;
- }
-
- if ( ! mdoc_macro(mdoc, ntok, line, la, pos, buf))
- return(0);
- return(append_delims(mdoc, line, pos, buf));
- }
- return(1);
+ rew_last(mdoc, body);
+ mdoc_body_alloc(mdoc, line, ppos, MDOC_It);
+ parse_rest(mdoc, MDOC_MAX, line, pos, buf);
}
diff --git a/usr/src/cmd/mandoc/mdoc_man.c b/usr/src/cmd/mandoc/mdoc_man.c
index 6ee8b3abf4..9c086a576c 100644
--- a/usr/src/cmd/mandoc/mdoc_man.c
+++ b/usr/src/cmd/mandoc/mdoc_man.c
@@ -1,6 +1,6 @@
-/* $Id: mdoc_man.c,v 1.57 2013/12/25 22:00:45 schwarze Exp $ */
+/* $Id: mdoc_man.c,v 1.88 2015/02/17 20:37:17 schwarze Exp $ */
/*
- * Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011-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
@@ -14,22 +14,22 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
+
+#include <sys/types.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "out.h"
#include "man.h"
#include "mdoc.h"
#include "main.h"
-#define DECL_ARGS const struct mdoc_meta *meta, \
- const struct mdoc_node *n
+#define DECL_ARGS const struct mdoc_meta *meta, struct mdoc_node *n
struct manact {
int (*cond)(DECL_ARGS); /* DON'T run actions */
@@ -45,11 +45,13 @@ static void font_push(char);
static void font_pop(void);
static void mid_it(void);
static void post__t(DECL_ARGS);
+static void post_aq(DECL_ARGS);
static void post_bd(DECL_ARGS);
static void post_bf(DECL_ARGS);
static void post_bk(DECL_ARGS);
static void post_bl(DECL_ARGS);
static void post_dl(DECL_ARGS);
+static void post_en(DECL_ARGS);
static void post_enc(DECL_ARGS);
static void post_eo(DECL_ARGS);
static void post_fa(DECL_ARGS);
@@ -70,6 +72,7 @@ static void post_vt(DECL_ARGS);
static int pre__t(DECL_ARGS);
static int pre_an(DECL_ARGS);
static int pre_ap(DECL_ARGS);
+static int pre_aq(DECL_ARGS);
static int pre_bd(DECL_ARGS);
static int pre_bf(DECL_ARGS);
static int pre_bk(DECL_ARGS);
@@ -77,8 +80,12 @@ static int pre_bl(DECL_ARGS);
static int pre_br(DECL_ARGS);
static int pre_bx(DECL_ARGS);
static int pre_dl(DECL_ARGS);
+static int pre_en(DECL_ARGS);
static int pre_enc(DECL_ARGS);
static int pre_em(DECL_ARGS);
+static int pre_skip(DECL_ARGS);
+static int pre_eo(DECL_ARGS);
+static int pre_ex(DECL_ARGS);
static int pre_fa(DECL_ARGS);
static int pre_fd(DECL_ARGS);
static int pre_fl(DECL_ARGS);
@@ -89,11 +96,13 @@ 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 int pre_pp(DECL_ARGS);
static int pre_rs(DECL_ARGS);
+static int pre_rv(DECL_ARGS);
static int pre_sm(DECL_ARGS);
static int pre_sp(DECL_ARGS);
static int pre_sect(DECL_ARGS);
@@ -105,9 +114,9 @@ static int pre_xr(DECL_ARGS);
static void print_word(const char *);
static void print_line(const char *, int);
static void print_block(const char *, int);
-static void print_offs(const char *);
-static void print_width(const char *,
- const struct mdoc_node *, size_t);
+static void print_offs(const char *, int);
+static void print_width(const struct mdoc_bl *,
+ const struct mdoc_node *);
static void print_count(int *);
static void print_node(DECL_ARGS);
@@ -134,9 +143,7 @@ static const struct manact manacts[MDOC_MAX + 1] = {
{ NULL, pre_li, post_font, NULL, NULL }, /* Dv */
{ NULL, pre_li, post_font, NULL, NULL }, /* Er */
{ NULL, pre_li, post_font, NULL, NULL }, /* Ev */
- { NULL, pre_enc, post_enc, "The \\fB",
- "\\fP\nutility exits 0 on success, and >0 if an error occurs."
- }, /* Ex */
+ { NULL, pre_ex, NULL, NULL, NULL }, /* Ex */
{ NULL, pre_fa, post_fa, NULL, NULL }, /* Fa */
{ NULL, pre_fd, post_fd, NULL, NULL }, /* Fd */
{ NULL, pre_fl, post_fl, NULL, NULL }, /* Fl */
@@ -148,13 +155,9 @@ static const struct manact manacts[MDOC_MAX + 1] = {
{ cond_head, pre_enc, NULL, "\\- ", NULL }, /* Nd */
{ NULL, pre_nm, post_nm, NULL, NULL }, /* Nm */
{ cond_body, pre_enc, post_enc, "[", "]" }, /* Op */
- { NULL, NULL, NULL, NULL, NULL }, /* Ot */
+ { NULL, pre_ft, post_font, NULL, NULL }, /* Ot */
{ NULL, pre_em, post_font, NULL, NULL }, /* Pa */
- { NULL, pre_enc, post_enc, "The \\fB",
- "\\fP\nfunction returns the value 0 if successful;\n"
- "otherwise the value -1 is returned and the global\n"
- "variable \\fIerrno\\fP is set to indicate the error."
- }, /* Rv */
+ { NULL, pre_rv, NULL, NULL, NULL }, /* Rv */
{ NULL, NULL, NULL, NULL, NULL }, /* St */
{ NULL, pre_em, post_font, NULL, NULL }, /* Va */
{ NULL, pre_vt, post_vt, NULL, NULL }, /* Vt */
@@ -171,8 +174,8 @@ static const struct manact manacts[MDOC_MAX + 1] = {
{ NULL, pre__t, post__t, NULL, NULL }, /* %T */
{ NULL, NULL, post_percent, NULL, NULL }, /* %V */
{ NULL, NULL, NULL, NULL, NULL }, /* Ac */
- { cond_body, pre_enc, post_enc, "<", ">" }, /* Ao */
- { cond_body, pre_enc, post_enc, "<", ">" }, /* Aq */
+ { cond_body, pre_aq, post_aq, NULL, NULL }, /* Ao */
+ { cond_body, pre_aq, post_aq, NULL, NULL }, /* Aq */
{ NULL, NULL, NULL, NULL, NULL }, /* At */
{ NULL, NULL, NULL, NULL, NULL }, /* Bc */
{ NULL, pre_bf, post_bf, NULL, NULL }, /* Bf */
@@ -180,14 +183,14 @@ static const struct manact manacts[MDOC_MAX + 1] = {
{ cond_body, pre_enc, post_enc, "[", "]" }, /* Bq */
{ NULL, pre_ux, NULL, "BSD/OS", NULL }, /* Bsx */
{ NULL, pre_bx, NULL, NULL, NULL }, /* Bx */
- { NULL, NULL, NULL, NULL, NULL }, /* Db */
+ { NULL, pre_skip, NULL, NULL, NULL }, /* Db */
{ NULL, NULL, NULL, NULL, NULL }, /* Dc */
- { cond_body, pre_enc, post_enc, "\\(lq", "\\(rq" }, /* Do */
- { cond_body, pre_enc, post_enc, "\\(lq", "\\(rq" }, /* Dq */
+ { cond_body, pre_enc, post_enc, "\\(Lq", "\\(Rq" }, /* Do */
+ { cond_body, pre_enc, post_enc, "\\(Lq", "\\(Rq" }, /* Dq */
{ NULL, NULL, NULL, NULL, NULL }, /* Ec */
{ NULL, NULL, NULL, NULL, NULL }, /* Ef */
{ NULL, pre_em, post_font, NULL, NULL }, /* Em */
- { NULL, NULL, post_eo, NULL, NULL }, /* Eo */
+ { cond_body, pre_eo, post_eo, NULL, NULL }, /* Eo */
{ NULL, pre_ux, NULL, "FreeBSD", NULL }, /* Fx */
{ NULL, pre_sy, post_font, NULL, NULL }, /* Ms */
{ NULL, pre_no, NULL, NULL, NULL }, /* No */
@@ -222,7 +225,7 @@ static const struct manact manacts[MDOC_MAX + 1] = {
{ NULL, NULL, NULL, NULL, NULL }, /* Ek */
{ NULL, pre_ux, NULL, "is currently in beta test.", NULL }, /* Bt */
{ NULL, NULL, NULL, NULL, NULL }, /* Hf */
- { NULL, NULL, NULL, NULL, NULL }, /* Fr */
+ { NULL, pre_em, post_font, NULL, NULL }, /* Fr */
{ NULL, pre_ux, NULL, "currently under development.", NULL }, /* Ud */
{ NULL, NULL, post_lb, NULL, NULL }, /* Lb */
{ NULL, pre_pp, NULL, NULL, NULL }, /* Lp */
@@ -232,14 +235,15 @@ static const struct manact manacts[MDOC_MAX + 1] = {
{ cond_body, pre_enc, post_enc, "{", "}" }, /* Bro */
{ NULL, NULL, NULL, NULL, NULL }, /* Brc */
{ NULL, NULL, post_percent, NULL, NULL }, /* %C */
- { NULL, NULL, NULL, NULL, NULL }, /* Es */
- { NULL, NULL, NULL, NULL, NULL }, /* En */
+ { NULL, pre_skip, NULL, NULL, NULL }, /* Es */
+ { cond_body, pre_en, post_en, NULL, NULL }, /* En */
{ NULL, pre_ux, NULL, "DragonFly", 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 */
};
@@ -260,7 +264,7 @@ static int outflags;
#define BL_STACK_MAX 32
-static size_t Bl_stack[BL_STACK_MAX]; /* offsets [chars] */
+static int Bl_stack[BL_STACK_MAX]; /* offsets [chars] */
static int Bl_stack_post[BL_STACK_MAX]; /* add final .RE */
static int Bl_stack_len; /* number of nested Bl blocks */
static int TPremain; /* characters before tag is full */
@@ -271,6 +275,7 @@ static struct {
size_t size;
} fontqueue;
+
static void
font_push(char newfont)
{
@@ -278,7 +283,7 @@ font_push(char newfont)
if (fontqueue.head + fontqueue.size <= ++fontqueue.tail) {
fontqueue.size += 8;
fontqueue.head = mandoc_realloc(fontqueue.head,
- fontqueue.size);
+ fontqueue.size);
}
*fontqueue.tail = newfont;
print_word("");
@@ -304,7 +309,7 @@ print_word(const char *s)
{
if ((MMAN_PP | MMAN_sp | MMAN_br | MMAN_nl) & outflags) {
- /*
+ /*
* If we need a newline, print it now and start afresh.
*/
if (MMAN_PP & outflags) {
@@ -359,13 +364,16 @@ print_word(const char *s)
for ( ; *s; s++) {
switch (*s) {
- case (ASCII_NBRSP):
+ case ASCII_NBRSP:
printf("\\ ");
break;
- case (ASCII_HYPH):
+ case ASCII_HYPH:
putchar('-');
break;
- case (' '):
+ case ASCII_BREAK:
+ printf("\\:");
+ break;
+ case ' ':
if (MMAN_nbrword & outflags) {
printf("\\ ");
break;
@@ -410,22 +418,22 @@ print_block(const char *s, int newflags)
}
static void
-print_offs(const char *v)
+print_offs(const char *v, int keywords)
{
char buf[24];
struct roffsu su;
- size_t sz;
+ int sz;
print_line(".RS", MMAN_Bk_susp);
/* Convert v into a number (of characters). */
- if (NULL == v || '\0' == *v || 0 == strcmp(v, "left"))
+ if (NULL == v || '\0' == *v || (keywords && !strcmp(v, "left")))
sz = 0;
- else if (0 == strcmp(v, "indent"))
+ else if (keywords && !strcmp(v, "indent"))
sz = 6;
- else if (0 == strcmp(v, "indent-two"))
+ else if (keywords && !strcmp(v, "indent-two"))
sz = 12;
- else if (a2roffsu(v, &su, SCALE_MAX)) {
+ else if (a2roffsu(v, &su, SCALE_EN) > 1) {
if (SCALE_EN == su.unit)
sz = su.scale;
else {
@@ -450,7 +458,7 @@ print_offs(const char *v)
if (Bl_stack_len)
sz += Bl_stack[Bl_stack_len - 1];
- snprintf(buf, sizeof(buf), "%zun", sz);
+ (void)snprintf(buf, sizeof(buf), "%dn", sz);
print_word(buf);
outflags |= MMAN_nl;
}
@@ -458,21 +466,20 @@ print_offs(const char *v)
/*
* Set up the indentation for a list item; used from pre_it().
*/
-void
-print_width(const char *v, const struct mdoc_node *child, size_t defsz)
+static void
+print_width(const struct mdoc_bl *bl, const struct mdoc_node *child)
{
char buf[24];
struct roffsu su;
- size_t sz, chsz;
- int numeric, remain;
+ int numeric, remain, sz, chsz;
numeric = 1;
remain = 0;
- /* Convert v into a number (of characters). */
- if (NULL == v)
- sz = defsz;
- else if (a2roffsu(v, &su, SCALE_MAX)) {
+ /* 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)
sz = su.scale;
else {
@@ -480,11 +487,15 @@ print_width(const char *v, const struct mdoc_node *child, size_t defsz)
numeric = 0;
}
} else
- sz = strlen(v);
+ sz = strlen(bl->width);
/* XXX Rough estimation, might have multiple parts. */
- chsz = (NULL != child && MDOC_TEXT == child->type) ?
- strlen(child->string) : 0;
+ if (bl->type == LIST_enum)
+ chsz = (bl->count > 8) + 1;
+ else if (child != NULL && child->type == MDOC_TEXT)
+ chsz = strlen(child->string);
+ else
+ chsz = 0;
/* Maybe we are inside an enclosing list? */
mid_it();
@@ -496,26 +507,26 @@ print_width(const char *v, const struct mdoc_node *child, size_t defsz)
Bl_stack[Bl_stack_len++] = sz + 2;
/* Set up the current list. */
- if (defsz && chsz > sz)
+ if (chsz > sz && bl->type != LIST_tag)
print_block(".HP", 0);
else {
print_block(".TP", 0);
remain = sz + 2;
}
if (numeric) {
- snprintf(buf, sizeof(buf), "%zun", sz + 2);
+ (void)snprintf(buf, sizeof(buf), "%dn", sz + 2);
print_word(buf);
} else
- print_word(v);
+ print_word(bl->width);
TPremain = remain;
}
-void
+static void
print_count(int *count)
{
- char buf[12];
+ char buf[24];
- snprintf(buf, sizeof(buf), "%d.", ++*count);
+ (void)snprintf(buf, sizeof(buf), "%d.\\&", ++*count);
print_word(buf);
}
@@ -536,14 +547,15 @@ void
man_mdoc(void *arg, const struct mdoc *mdoc)
{
const struct mdoc_meta *meta;
- const struct mdoc_node *n;
+ struct mdoc_node *n;
meta = mdoc_meta(mdoc);
- n = mdoc_node(mdoc);
+ n = mdoc_node(mdoc)->child;
printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",
- meta->title, meta->msec, meta->date,
- meta->os, meta->vol);
+ meta->title,
+ (meta->msec == NULL ? "" : meta->msec),
+ meta->date, meta->os, meta->vol);
/* Disable hyphenation and if nroff, disable justification. */
printf(".nh\n.if n .ad l");
@@ -554,15 +566,18 @@ man_mdoc(void *arg, const struct mdoc *mdoc)
fontqueue.head = fontqueue.tail = mandoc_malloc(8);
*fontqueue.tail = 'R';
}
- print_node(meta, n);
+ while (n != NULL) {
+ print_node(meta, n);
+ n = n->next;
+ }
putchar('\n');
}
static void
print_node(DECL_ARGS)
{
- const struct mdoc_node *sub;
const struct manact *act;
+ struct mdoc_node *sub;
int cond, do_sub;
/*
@@ -575,31 +590,36 @@ print_node(DECL_ARGS)
act = NULL;
cond = 0;
do_sub = 1;
+ n->flags &= ~MDOC_ENDED;
if (MDOC_TEXT == n->type) {
/*
* Make sure that we don't happen to start with a
* control character at the start of a line.
*/
- if (MMAN_nl & outflags && ('.' == *n->string ||
- '\'' == *n->string)) {
+ if (MMAN_nl & outflags &&
+ ('.' == *n->string || '\'' == *n->string)) {
print_word("");
printf("\\&");
outflags &= ~MMAN_spc;
}
+ if (outflags & MMAN_Sm && ! (n->flags & MDOC_DELIMC))
+ outflags |= MMAN_spc_force;
print_word(n->string);
+ if (outflags & MMAN_Sm && ! (n->flags & MDOC_DELIMO))
+ outflags |= MMAN_spc;
} else {
/*
* Conditionally run the pre-node action handler for a
* node.
*/
act = manacts + n->tok;
- cond = NULL == act->cond || (*act->cond)(meta, n);
- if (cond && act->pre)
+ cond = act->cond == NULL || (*act->cond)(meta, n);
+ if (cond && act->pre && (n->end == ENDBODY_NOT || n->nchild))
do_sub = (*act->pre)(meta, n);
}
- /*
+ /*
* Conditionally run all child nodes.
* Note that this iterates over children instead of using
* recursion. This prevents unnecessary depth in the stack.
@@ -611,8 +631,17 @@ print_node(DECL_ARGS)
/*
* Lastly, conditionally run the post-node handler.
*/
+ if (MDOC_ENDED & n->flags)
+ return;
+
if (cond && act->post)
(*act->post)(meta, n);
+
+ if (ENDBODY_NOT != n->end)
+ n->body->flags |= MDOC_ENDED;
+
+ if (ENDBODY_NOSPACE == n->end)
+ outflags &= ~(MMAN_spc | MMAN_nl);
}
static int
@@ -650,10 +679,46 @@ post_enc(DECL_ARGS)
suffix = manacts[n->tok].suffix;
if (NULL == suffix)
return;
- outflags &= ~MMAN_spc;
+ outflags &= ~(MMAN_spc | MMAN_nl);
print_word(suffix);
}
+static int
+pre_ex(DECL_ARGS)
+{
+ int nchild;
+
+ outflags |= MMAN_br | MMAN_nl;
+
+ print_word("The");
+
+ nchild = n->nchild;
+ for (n = n->child; n; n = n->next) {
+ font_push('B');
+ print_word(n->string);
+ font_pop();
+
+ if (n->next == NULL)
+ continue;
+
+ if (nchild > 2) {
+ outflags &= ~MMAN_spc;
+ print_word(",");
+ }
+ if (n->next->next == NULL)
+ print_word("and");
+ }
+
+ if (nchild > 1)
+ print_word("utilities exit\\~0");
+ else
+ print_word("utility exits\\~0");
+
+ print_word("on success, and\\~>0 if an error occurs.");
+ outflags |= MMAN_nl;
+ return(0);
+}
+
static void
post_font(DECL_ARGS)
{
@@ -682,8 +747,8 @@ static int
pre__t(DECL_ARGS)
{
- if (n->parent && MDOC_Rs == n->parent->tok &&
- n->parent->norm->Rs.quote_T) {
+ if (n->parent && MDOC_Rs == n->parent->tok &&
+ n->parent->norm->Rs.quote_T) {
print_word("");
putchar('\"');
outflags &= ~MMAN_spc;
@@ -696,8 +761,8 @@ static void
post__t(DECL_ARGS)
{
- if (n->parent && MDOC_Rs == n->parent->tok &&
- n->parent->norm->Rs.quote_T) {
+ if (n->parent && MDOC_Rs == n->parent->tok &&
+ n->parent->norm->Rs.quote_T) {
outflags &= ~MMAN_spc;
print_word("");
putchar('\"');
@@ -749,26 +814,26 @@ pre_syn(const struct mdoc_node *n)
return;
if (n->prev->tok == n->tok &&
- MDOC_Ft != n->tok &&
- MDOC_Fo != n->tok &&
- MDOC_Fn != n->tok) {
+ MDOC_Ft != n->tok &&
+ MDOC_Fo != n->tok &&
+ MDOC_Fn != n->tok) {
outflags |= MMAN_br;
return;
}
switch (n->prev->tok) {
- case (MDOC_Fd):
+ case MDOC_Fd:
/* FALLTHROUGH */
- case (MDOC_Fn):
+ case MDOC_Fn:
/* FALLTHROUGH */
- case (MDOC_Fo):
+ case MDOC_Fo:
/* FALLTHROUGH */
- case (MDOC_In):
+ case MDOC_In:
/* FALLTHROUGH */
- case (MDOC_Vt):
+ case MDOC_Vt:
outflags |= MMAN_sp;
break;
- case (MDOC_Ft):
+ case MDOC_Ft:
if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
outflags |= MMAN_sp;
break;
@@ -785,11 +850,11 @@ pre_an(DECL_ARGS)
{
switch (n->norm->An.auth) {
- case (AUTH_split):
+ case AUTH_split:
outflags &= ~MMAN_An_nosplit;
outflags |= MMAN_An_split;
return(0);
- case (AUTH_nosplit):
+ case AUTH_nosplit:
outflags &= ~MMAN_An_split;
outflags |= MMAN_An_nosplit;
return(0);
@@ -814,6 +879,25 @@ pre_ap(DECL_ARGS)
}
static int
+pre_aq(DECL_ARGS)
+{
+
+ print_word(n->nchild == 1 &&
+ n->child->tok == MDOC_Mt ? "<" : "\\(la");
+ outflags &= ~MMAN_spc;
+ return(1);
+}
+
+static void
+post_aq(DECL_ARGS)
+{
+
+ outflags &= ~(MMAN_spc | MMAN_nl);
+ print_word(n->nchild == 1 &&
+ n->child->tok == MDOC_Mt ? ">" : "\\(ra");
+}
+
+static int
pre_bd(DECL_ARGS)
{
@@ -824,7 +908,7 @@ pre_bd(DECL_ARGS)
print_line(".nf", 0);
if (0 == n->norm->Bd.comp && NULL != n->parent->prev)
outflags |= MMAN_sp;
- print_offs(n->norm->Bd.offs);
+ print_offs(n->norm->Bd.offs, 1);
return(1);
}
@@ -848,18 +932,18 @@ pre_bf(DECL_ARGS)
{
switch (n->type) {
- case (MDOC_BLOCK):
+ case MDOC_BLOCK:
return(1);
- case (MDOC_BODY):
+ case MDOC_BODY:
break;
default:
return(0);
}
switch (n->norm->Bf.font) {
- case (FONT_Em):
+ case FONT_Em:
font_push('I');
break;
- case (FONT_Sy):
+ case FONT_Sy:
font_push('B');
break;
default:
@@ -882,9 +966,9 @@ pre_bk(DECL_ARGS)
{
switch (n->type) {
- case (MDOC_BLOCK):
+ case MDOC_BLOCK:
return(1);
- case (MDOC_BODY):
+ case MDOC_BODY:
outflags |= MMAN_Bk;
return(1);
default:
@@ -911,24 +995,26 @@ pre_bl(DECL_ARGS)
* just nest and do not add up their indentation.
*/
if (n->norm->Bl.offs) {
- print_offs(n->norm->Bl.offs);
+ print_offs(n->norm->Bl.offs, 0);
Bl_stack[Bl_stack_len++] = 0;
}
switch (n->norm->Bl.type) {
- case (LIST_enum):
+ case LIST_enum:
n->norm->Bl.count = 0;
return(1);
- case (LIST_column):
+ case LIST_column:
break;
default:
return(1);
}
- print_line(".TS", MMAN_nl);
- for (icol = 0; icol < n->norm->Bl.ncols; icol++)
- print_word("l");
- print_word(".");
+ if (n->nchild) {
+ print_line(".TS", MMAN_nl);
+ for (icol = 0; icol < n->norm->Bl.ncols; icol++)
+ print_word("l");
+ print_word(".");
+ }
outflags |= MMAN_nl;
return(1);
}
@@ -938,10 +1024,11 @@ post_bl(DECL_ARGS)
{
switch (n->norm->Bl.type) {
- case (LIST_column):
- print_line(".TE", 0);
+ case LIST_column:
+ if (n->nchild)
+ print_line(".TE", 0);
break;
- case (LIST_enum):
+ case LIST_enum:
n->norm->Bl.count = 0;
break;
default:
@@ -996,7 +1083,7 @@ static int
pre_dl(DECL_ARGS)
{
- print_offs("6n");
+ print_offs("6n", 0);
return(1);
}
@@ -1019,12 +1106,68 @@ pre_em(DECL_ARGS)
return(1);
}
+static int
+pre_en(DECL_ARGS)
+{
+
+ if (NULL == n->norm->Es ||
+ NULL == n->norm->Es->child)
+ return(1);
+
+ print_word(n->norm->Es->child->string);
+ outflags &= ~MMAN_spc;
+ return(1);
+}
+
+static void
+post_en(DECL_ARGS)
+{
+
+ if (NULL == n->norm->Es ||
+ NULL == n->norm->Es->child ||
+ NULL == n->norm->Es->child->next)
+ return;
+
+ outflags &= ~MMAN_spc;
+ print_word(n->norm->Es->child->next->string);
+ return;
+}
+
+static int
+pre_eo(DECL_ARGS)
+{
+
+ if (n->end == ENDBODY_NOT &&
+ n->parent->head->child == NULL &&
+ n->child != NULL &&
+ n->child->end != ENDBODY_NOT)
+ print_word("\\&");
+ else if (n->end != ENDBODY_NOT ? n->child != NULL :
+ n->parent->head->child != NULL && (n->child != NULL ||
+ (n->parent->tail != NULL && n->parent->tail->child != NULL)))
+ outflags &= ~(MMAN_spc | MMAN_nl);
+ return(1);
+}
+
static void
post_eo(DECL_ARGS)
{
+ int body, tail;
+
+ if (n->end != ENDBODY_NOT) {
+ outflags |= MMAN_spc;
+ return;
+ }
+
+ body = n->child != NULL || n->parent->head->child != NULL;
+ tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
- if (MDOC_HEAD == n->type || MDOC_BODY == n->type)
+ if (body && tail)
outflags &= ~MMAN_spc;
+ else if ( ! (body || tail))
+ print_word("\\&");
+ else if ( ! tail)
+ outflags |= MMAN_spc;
}
static int
@@ -1080,7 +1223,8 @@ pre_fl(DECL_ARGS)
font_push('B');
print_word("\\-");
- outflags &= ~MMAN_spc;
+ if (n->nchild)
+ outflags &= ~MMAN_spc;
return(1);
}
@@ -1089,8 +1233,10 @@ post_fl(DECL_ARGS)
{
font_pop();
- if (0 == n->nchild && NULL != n->next &&
- n->next->line == n->line)
+ if ( ! (n->nchild ||
+ n->next == NULL ||
+ n->next->type == MDOC_TEXT ||
+ n->next->flags & MDOC_LINE))
outflags &= ~MMAN_spc;
}
@@ -1136,16 +1282,18 @@ pre_fo(DECL_ARGS)
{
switch (n->type) {
- case (MDOC_BLOCK):
+ case MDOC_BLOCK:
pre_syn(n);
break;
- case (MDOC_HEAD):
+ case MDOC_HEAD:
+ if (n->child == NULL)
+ return(0);
if (MDOC_SYNPRETTY & n->flags)
print_block(".HP 4n", MMAN_nl);
font_push('B');
break;
- case (MDOC_BODY):
- outflags &= ~MMAN_spc;
+ case MDOC_BODY:
+ outflags &= ~(MMAN_spc | MMAN_nl);
print_word("(");
outflags &= ~MMAN_spc;
break;
@@ -1160,10 +1308,11 @@ post_fo(DECL_ARGS)
{
switch (n->type) {
- case (MDOC_HEAD):
- font_pop();
+ case MDOC_HEAD:
+ if (n->child != NULL)
+ font_pop();
break;
- case (MDOC_BODY):
+ case MDOC_BODY:
post_fn(meta, n);
break;
default:
@@ -1219,7 +1368,7 @@ pre_it(DECL_ARGS)
const struct mdoc_node *bln;
switch (n->type) {
- case (MDOC_HEAD):
+ case MDOC_HEAD:
outflags |= MMAN_PP | MMAN_nl;
bln = n->parent->parent;
if (0 == bln->norm->Bl.comp ||
@@ -1228,53 +1377,55 @@ pre_it(DECL_ARGS)
outflags |= MMAN_sp;
outflags &= ~MMAN_br;
switch (bln->norm->Bl.type) {
- case (LIST_item):
+ case LIST_item:
return(0);
- case (LIST_inset):
+ case LIST_inset:
/* FALLTHROUGH */
- case (LIST_diag):
+ case LIST_diag:
/* FALLTHROUGH */
- case (LIST_ohang):
+ case LIST_ohang:
if (bln->norm->Bl.type == LIST_diag)
print_line(".B \"", 0);
else
print_line(".R \"", 0);
outflags &= ~MMAN_spc;
return(1);
- case (LIST_bullet):
+ case LIST_bullet:
/* FALLTHROUGH */
- case (LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case (LIST_hyphen):
- print_width(bln->norm->Bl.width, NULL, 0);
+ case LIST_hyphen:
+ print_width(&bln->norm->Bl, NULL);
TPremain = 0;
outflags |= MMAN_nl;
font_push('B');
if (LIST_bullet == bln->norm->Bl.type)
- print_word("o");
+ print_word("\\(bu");
else
print_word("-");
font_pop();
- break;
- case (LIST_enum):
- print_width(bln->norm->Bl.width, NULL, 0);
+ outflags |= MMAN_nl;
+ return(0);
+ case LIST_enum:
+ print_width(&bln->norm->Bl, NULL);
TPremain = 0;
outflags |= MMAN_nl;
print_count(&bln->norm->Bl.count);
- break;
- case (LIST_hang):
- print_width(bln->norm->Bl.width, n->child, 6);
+ outflags |= MMAN_nl;
+ return(0);
+ case LIST_hang:
+ print_width(&bln->norm->Bl, n->child);
TPremain = 0;
- break;
- case (LIST_tag):
- print_width(bln->norm->Bl.width, n->child, 0);
+ outflags |= MMAN_nl;
+ return(1);
+ case LIST_tag:
+ print_width(&bln->norm->Bl, n->child);
putchar('\n');
outflags &= ~MMAN_spc;
return(1);
default:
return(1);
}
- outflags |= MMAN_nl;
default:
break;
}
@@ -1300,7 +1451,8 @@ mid_it(void)
/* Restore the indentation of the enclosing list. */
print_line(".RS", MMAN_Bk_susp);
- snprintf(buf, sizeof(buf), "%zun", Bl_stack[Bl_stack_len - 1]);
+ (void)snprintf(buf, sizeof(buf), "%dn",
+ Bl_stack[Bl_stack_len - 1]);
print_word(buf);
/* Remeber to close out this .RS block later. */
@@ -1315,32 +1467,32 @@ post_it(DECL_ARGS)
bln = n->parent->parent;
switch (n->type) {
- case (MDOC_HEAD):
+ case MDOC_HEAD:
switch (bln->norm->Bl.type) {
- case (LIST_diag):
+ case LIST_diag:
outflags &= ~MMAN_spc;
print_word("\\ ");
break;
- case (LIST_ohang):
+ case LIST_ohang:
outflags |= MMAN_br;
break;
default:
break;
}
break;
- case (MDOC_BODY):
+ case MDOC_BODY:
switch (bln->norm->Bl.type) {
- case (LIST_bullet):
+ case LIST_bullet:
/* FALLTHROUGH */
- case (LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case (LIST_hyphen):
+ case LIST_hyphen:
/* FALLTHROUGH */
- case (LIST_enum):
+ case LIST_enum:
/* FALLTHROUGH */
- case (LIST_hang):
+ case LIST_hang:
/* FALLTHROUGH */
- case (LIST_tag):
+ case LIST_tag:
assert(Bl_stack_len);
Bl_stack[--Bl_stack_len] = 0;
@@ -1354,7 +1506,7 @@ post_it(DECL_ARGS)
Bl_stack_post[Bl_stack_len] = 0;
}
break;
- case (LIST_column):
+ case LIST_column:
if (NULL != n->next) {
putchar('\t');
outflags &= ~MMAN_spc;
@@ -1402,6 +1554,14 @@ pre_lk(DECL_ARGS)
}
static int
+pre_ll(DECL_ARGS)
+{
+
+ print_line(".ll", 0);
+ return(1);
+}
+
+static int
pre_li(DECL_ARGS)
{
@@ -1441,13 +1601,14 @@ post_nm(DECL_ARGS)
{
switch (n->type) {
- case (MDOC_BLOCK):
+ case MDOC_BLOCK:
outflags &= ~MMAN_Bk;
break;
- case (MDOC_HEAD):
+ case MDOC_HEAD:
/* FALLTHROUGH */
- case (MDOC_ELEM):
- font_pop();
+ case MDOC_ELEM:
+ if (n->child != NULL || meta->name != NULL)
+ font_pop();
break;
default:
break;
@@ -1474,7 +1635,8 @@ static void
post_pf(DECL_ARGS)
{
- outflags &= ~MMAN_spc;
+ if ( ! (n->next == NULL || n->next->flags & MDOC_LINE))
+ outflags &= ~MMAN_spc;
}
static int
@@ -1500,14 +1662,78 @@ pre_rs(DECL_ARGS)
}
static int
+pre_rv(DECL_ARGS)
+{
+ int nchild;
+
+ outflags |= MMAN_br | MMAN_nl;
+
+ nchild = n->nchild;
+ if (nchild > 0) {
+ print_word("The");
+
+ for (n = n->child; n; n = n->next) {
+ font_push('B');
+ print_word(n->string);
+ font_pop();
+
+ outflags &= ~MMAN_spc;
+ print_word("()");
+
+ if (n->next == NULL)
+ continue;
+
+ if (nchild > 2) {
+ outflags &= ~MMAN_spc;
+ print_word(",");
+ }
+ if (n->next->next == NULL)
+ print_word("and");
+ }
+
+ if (nchild > 1)
+ print_word("functions return");
+ else
+ print_word("function returns");
+
+ print_word("the value\\~0 if successful;");
+ } else
+ print_word("Upon successful completion, "
+ "the value\\~0 is returned;");
+
+ print_word("otherwise the value\\~\\-1 is returned"
+ " and the global variable");
+
+ font_push('I');
+ print_word("errno");
+ font_pop();
+
+ print_word("is set to indicate the error.");
+ outflags |= MMAN_nl;
+ return(0);
+}
+
+static int
+pre_skip(DECL_ARGS)
+{
+
+ return(0);
+}
+
+static int
pre_sm(DECL_ARGS)
{
- assert(n->child && MDOC_TEXT == n->child->type);
- if (0 == strcmp("on", n->child->string))
- outflags |= MMAN_Sm | MMAN_spc;
+ if (NULL == n->child)
+ outflags ^= MMAN_Sm;
+ else if (0 == strcmp("on", n->child->string))
+ outflags |= MMAN_Sm;
else
outflags &= ~MMAN_Sm;
+
+ if (MMAN_Sm & outflags)
+ outflags |= MMAN_spc;
+
return(0);
}
@@ -1544,10 +1770,10 @@ pre_vt(DECL_ARGS)
if (MDOC_SYNPRETTY & n->flags) {
switch (n->type) {
- case (MDOC_BLOCK):
+ case MDOC_BLOCK:
pre_syn(n);
return(1);
- case (MDOC_BODY):
+ case MDOC_BODY:
break;
default:
return(0);
diff --git a/usr/src/cmd/mandoc/mdoc_term.c b/usr/src/cmd/mandoc/mdoc_term.c
index 268fcae006..20c47d6668 100644
--- a/usr/src/cmd/mandoc/mdoc_term.c
+++ b/usr/src/cmd/mandoc/mdoc_term.c
@@ -1,7 +1,7 @@
-/* $Id: mdoc_term.c,v 1.258 2013/12/25 21:24:12 schwarze Exp $ */
+/* $Id: mdoc_term.c,v 1.313 2015/03/06 15:48:52 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012-2015 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -16,20 +16,20 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#include <sys/types.h>
#include <assert.h>
#include <ctype.h>
+#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "out.h"
#include "term.h"
#include "mdoc.h"
@@ -42,7 +42,7 @@ struct termpair {
#define DECL_ARGS struct termp *p, \
struct termpair *pair, \
- const struct mdoc_meta *meta, \
+ const struct mdoc_meta *meta, \
struct mdoc_node *n
struct termact {
@@ -50,26 +50,24 @@ struct termact {
void (*post)(DECL_ARGS);
};
-static size_t a2width(const struct termp *, const char *);
-static size_t a2height(const struct termp *, const char *);
-static size_t a2offs(const struct termp *, const char *);
+static int a2width(const struct termp *, const char *);
static void print_bvspace(struct termp *,
const struct mdoc_node *,
const struct mdoc_node *);
-static void print_mdoc_node(DECL_ARGS);
+static void print_mdoc_node(DECL_ARGS);
static void print_mdoc_nodelist(DECL_ARGS);
static void print_mdoc_head(struct termp *, const void *);
static void print_mdoc_foot(struct termp *, const void *);
-static void synopsis_pre(struct termp *,
+static void synopsis_pre(struct termp *,
const struct mdoc_node *);
static void termp____post(DECL_ARGS);
static void termp__t_post(DECL_ARGS);
-static void termp_an_post(DECL_ARGS);
static void termp_bd_post(DECL_ARGS);
static void termp_bk_post(DECL_ARGS);
static void termp_bl_post(DECL_ARGS);
+static void termp_eo_post(DECL_ARGS);
static void termp_fd_post(DECL_ARGS);
static void termp_fo_post(DECL_ARGS);
static void termp_in_post(DECL_ARGS);
@@ -94,6 +92,7 @@ static int termp_bt_pre(DECL_ARGS);
static int termp_bx_pre(DECL_ARGS);
static int termp_cd_pre(DECL_ARGS);
static int termp_d1_pre(DECL_ARGS);
+static int termp_eo_pre(DECL_ARGS);
static int termp_ex_pre(DECL_ARGS);
static int termp_fa_pre(DECL_ARGS);
static int termp_fd_pre(DECL_ARGS);
@@ -104,6 +103,7 @@ 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);
@@ -112,6 +112,7 @@ static int termp_quote_pre(DECL_ARGS);
static int termp_rs_pre(DECL_ARGS);
static int termp_rv_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_ss_pre(DECL_ARGS);
@@ -127,8 +128,8 @@ static const struct termact termacts[MDOC_MAX] = {
{ 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_ss_pre, termp_ss_post }, /* Ss */
+ { termp_sp_pre, NULL }, /* Pp */
{ termp_d1_pre, termp_bl_post }, /* D1 */
{ termp_d1_pre, termp_bl_post }, /* Dl */
{ termp_bd_pre, termp_bd_post }, /* Bd */
@@ -136,30 +137,30 @@ static const struct termact termacts[MDOC_MAX] = {
{ termp_bl_pre, termp_bl_post }, /* Bl */
{ NULL, NULL }, /* El */
{ termp_it_pre, termp_it_post }, /* It */
- { termp_under_pre, NULL }, /* Ad */
- { termp_an_pre, termp_an_post }, /* An */
+ { termp_under_pre, NULL }, /* Ad */
+ { termp_an_pre, NULL }, /* An */
{ termp_under_pre, NULL }, /* Ar */
{ termp_cd_pre, NULL }, /* Cd */
{ termp_bold_pre, NULL }, /* Cm */
- { NULL, NULL }, /* Dv */
- { NULL, NULL }, /* Er */
- { NULL, NULL }, /* Ev */
+ { NULL, NULL }, /* Dv */
+ { NULL, NULL }, /* Er */
+ { NULL, NULL }, /* Ev */
{ termp_ex_pre, NULL }, /* Ex */
- { termp_fa_pre, NULL }, /* Fa */
- { termp_fd_pre, termp_fd_post }, /* Fd */
+ { termp_fa_pre, NULL }, /* Fa */
+ { termp_fd_pre, termp_fd_post }, /* Fd */
{ termp_fl_pre, NULL }, /* Fl */
- { termp_fn_pre, NULL }, /* Fn */
- { termp_ft_pre, NULL }, /* Ft */
- { termp_bold_pre, NULL }, /* Ic */
- { termp_in_pre, termp_in_post }, /* In */
+ { termp_fn_pre, NULL }, /* Fn */
+ { termp_ft_pre, NULL }, /* Ft */
+ { termp_bold_pre, NULL }, /* Ic */
+ { termp_in_pre, termp_in_post }, /* In */
{ termp_li_pre, NULL }, /* Li */
- { termp_nd_pre, NULL }, /* Nd */
- { termp_nm_pre, termp_nm_post }, /* Nm */
+ { termp_nd_pre, NULL }, /* Nd */
+ { termp_nm_pre, termp_nm_post }, /* Nm */
{ termp_quote_pre, termp_quote_post }, /* Op */
- { NULL, NULL }, /* Ot */
+ { termp_ft_pre, NULL }, /* Ot */
{ termp_under_pre, NULL }, /* Pa */
{ termp_rv_pre, NULL }, /* Rv */
- { NULL, NULL }, /* St */
+ { NULL, NULL }, /* St */
{ termp_under_pre, NULL }, /* Va */
{ termp_vt_pre, NULL }, /* Vt */
{ termp_xr_pre, NULL }, /* Xr */
@@ -179,22 +180,22 @@ static const struct termact termacts[MDOC_MAX] = {
{ termp_quote_pre, termp_quote_post }, /* Aq */
{ NULL, NULL }, /* At */
{ NULL, NULL }, /* Bc */
- { termp_bf_pre, NULL }, /* Bf */
+ { termp_bf_pre, NULL }, /* Bf */
{ termp_quote_pre, termp_quote_post }, /* Bo */
{ termp_quote_pre, termp_quote_post }, /* Bq */
{ termp_xx_pre, NULL }, /* Bsx */
{ termp_bx_pre, NULL }, /* Bx */
- { NULL, NULL }, /* Db */
+ { termp_skip_pre, NULL }, /* Db */
{ NULL, NULL }, /* Dc */
{ termp_quote_pre, termp_quote_post }, /* Do */
{ termp_quote_pre, termp_quote_post }, /* Dq */
{ NULL, NULL }, /* Ec */ /* FIXME: no space */
{ NULL, NULL }, /* Ef */
- { termp_under_pre, NULL }, /* Em */
- { termp_quote_pre, termp_quote_post }, /* Eo */
+ { termp_under_pre, NULL }, /* Em */
+ { termp_eo_pre, termp_eo_post }, /* Eo */
{ termp_xx_pre, NULL }, /* Fx */
{ termp_bold_pre, NULL }, /* Ms */
- { NULL, NULL }, /* No */
+ { termp_li_pre, NULL }, /* No */
{ termp_ns_pre, NULL }, /* Ns */
{ termp_xx_pre, NULL }, /* Nx */
{ termp_xx_pre, NULL }, /* Ox */
@@ -218,77 +219,86 @@ static const struct termact termacts[MDOC_MAX] = {
{ termp_xx_pre, NULL }, /* Ux */
{ NULL, NULL }, /* Xc */
{ NULL, NULL }, /* Xo */
- { termp_fo_pre, termp_fo_post }, /* Fo */
- { NULL, NULL }, /* Fc */
+ { termp_fo_pre, termp_fo_post }, /* Fo */
+ { NULL, NULL }, /* Fc */
{ termp_quote_pre, termp_quote_post }, /* Oo */
{ NULL, NULL }, /* Oc */
{ termp_bk_pre, termp_bk_post }, /* Bk */
{ NULL, NULL }, /* Ek */
{ termp_bt_pre, NULL }, /* Bt */
{ NULL, NULL }, /* Hf */
- { NULL, NULL }, /* Fr */
+ { termp_under_pre, NULL }, /* Fr */
{ termp_ud_pre, NULL }, /* Ud */
{ NULL, termp_lb_post }, /* Lb */
- { termp_sp_pre, NULL }, /* Lp */
- { termp_lk_pre, NULL }, /* Lk */
- { termp_under_pre, NULL }, /* Mt */
- { termp_quote_pre, termp_quote_post }, /* Brq */
- { termp_quote_pre, termp_quote_post }, /* Bro */
- { NULL, NULL }, /* Brc */
- { NULL, termp____post }, /* %C */
- { NULL, NULL }, /* Es */ /* TODO */
- { NULL, NULL }, /* En */ /* TODO */
- { termp_xx_pre, NULL }, /* Dx */
- { NULL, termp____post }, /* %Q */
+ { termp_sp_pre, NULL }, /* Lp */
+ { termp_lk_pre, NULL }, /* Lk */
+ { termp_under_pre, NULL }, /* Mt */
+ { termp_quote_pre, termp_quote_post }, /* Brq */
+ { termp_quote_pre, termp_quote_post }, /* Bro */
+ { NULL, NULL }, /* Brc */
+ { NULL, termp____post }, /* %C */
+ { termp_skip_pre, NULL }, /* Es */
+ { termp_quote_pre, termp_quote_post }, /* En */
+ { termp_xx_pre, NULL }, /* Dx */
+ { NULL, termp____post }, /* %Q */
{ termp_sp_pre, NULL }, /* br */
- { termp_sp_pre, NULL }, /* sp */
- { NULL, termp____post }, /* %U */
- { NULL, NULL }, /* Ta */
+ { termp_sp_pre, NULL }, /* sp */
+ { NULL, termp____post }, /* %U */
+ { NULL, NULL }, /* Ta */
+ { termp_ll_pre, NULL }, /* ll */
};
void
terminal_mdoc(void *arg, const struct mdoc *mdoc)
{
- const struct mdoc_node *n;
const struct mdoc_meta *meta;
+ struct mdoc_node *n;
struct termp *p;
p = (struct termp *)arg;
- if (0 == p->defindent)
- p->defindent = 5;
-
p->overstep = 0;
- p->maxrmargin = p->defrmargin;
+ p->rmargin = p->maxrmargin = p->defrmargin;
p->tabwidth = term_len(p, 5);
- if (NULL == p->symtab)
- p->symtab = mchars_alloc();
-
- n = mdoc_node(mdoc);
+ n = mdoc_node(mdoc)->child;
meta = mdoc_meta(mdoc);
- term_begin(p, print_mdoc_head, print_mdoc_foot, meta);
-
- if (n->child)
- print_mdoc_nodelist(p, NULL, meta, n->child);
-
- term_end(p);
+ if (p->synopsisonly) {
+ while (n != NULL) {
+ if (n->tok == MDOC_Sh && n->sec == SEC_SYNOPSIS) {
+ if (n->child->next->child != NULL)
+ print_mdoc_nodelist(p, NULL,
+ meta, n->child->next->child);
+ term_newln(p);
+ break;
+ }
+ n = n->next;
+ }
+ } else {
+ if (p->defindent == 0)
+ p->defindent = 5;
+ term_begin(p, print_mdoc_head, print_mdoc_foot, meta);
+ if (n != NULL) {
+ if (n->tok != MDOC_Sh)
+ term_vspace(p);
+ print_mdoc_nodelist(p, NULL, meta, n);
+ }
+ term_end(p);
+ }
}
-
static void
print_mdoc_nodelist(DECL_ARGS)
{
- print_mdoc_node(p, pair, meta, n);
- if (n->next)
- print_mdoc_nodelist(p, pair, meta, n->next);
+ while (n != NULL) {
+ print_mdoc_node(p, pair, meta, n);
+ n = n->next;
+ }
}
-
-/* ARGSUSED */
static void
print_mdoc_node(DECL_ARGS)
{
@@ -299,7 +309,8 @@ print_mdoc_node(DECL_ARGS)
chld = 1;
offset = p->offset;
rmargin = p->rmargin;
- n->prev_font = term_fontq(p);
+ n->flags &= ~MDOC_ENDED;
+ n->prev_font = p->fonti;
memset(&npair, 0, sizeof(struct termpair));
npair.ppair = pair;
@@ -309,12 +320,9 @@ print_mdoc_node(DECL_ARGS)
* invoked in a prior line, revert it to PREKEEP.
*/
- if (TERMP_KEEP & p->flags) {
- if (n->prev ? (n->prev->lastline != n->line) :
- (n->parent && n->parent->line != n->line)) {
- p->flags &= ~TERMP_KEEP;
- p->flags |= TERMP_PREKEEP;
- }
+ if (p->flags & TERMP_KEEP && n->flags & MDOC_LINE) {
+ p->flags &= ~TERMP_KEEP;
+ p->flags |= TERMP_PREKEEP;
}
/*
@@ -323,7 +331,7 @@ print_mdoc_node(DECL_ARGS)
*/
switch (n->type) {
- case (MDOC_TEXT):
+ case MDOC_TEXT:
if (' ' == *n->string && MDOC_LINE & n->flags)
term_newln(p);
if (MDOC_DELIMC & n->flags)
@@ -332,14 +340,21 @@ print_mdoc_node(DECL_ARGS)
if (MDOC_DELIMO & n->flags)
p->flags |= TERMP_NOSPACE;
break;
- case (MDOC_EQN):
+ case MDOC_EQN:
+ if ( ! (n->flags & MDOC_LINE))
+ p->flags |= TERMP_NOSPACE;
term_eqn(p, n->eqn);
+ if (n->next != NULL && ! (n->next->flags & MDOC_LINE))
+ p->flags |= TERMP_NOSPACE;
break;
- case (MDOC_TBL):
+ case MDOC_TBL:
+ if (p->tbl.cols == NULL)
+ term_newln(p);
term_tbl(p, n->span);
break;
default:
- if (termacts[n->tok].pre && ENDBODY_NOT == n->end)
+ if (termacts[n->tok].pre &&
+ (n->end == ENDBODY_NOT || n->nchild))
chld = (*termacts[n->tok].pre)
(p, &npair, meta, n);
break;
@@ -349,14 +364,14 @@ print_mdoc_node(DECL_ARGS)
print_mdoc_nodelist(p, &npair, meta, n->child);
term_fontpopq(p,
- (ENDBODY_NOT == n->end ? n : n->pending)->prev_font);
+ (ENDBODY_NOT == n->end ? n : n->body)->prev_font);
switch (n->type) {
- case (MDOC_TEXT):
+ case MDOC_TEXT:
break;
- case (MDOC_TBL):
+ case MDOC_TBL:
break;
- case (MDOC_EQN):
+ case MDOC_EQN:
break;
default:
if ( ! termacts[n->tok].post || MDOC_ENDED & n->flags)
@@ -369,7 +384,7 @@ print_mdoc_node(DECL_ARGS)
* that it must not call the post handler again.
*/
if (ENDBODY_NOT != n->end)
- n->pending->flags |= MDOC_ENDED;
+ n->body->flags |= MDOC_ENDED;
/*
* End of line terminating an implicit block
@@ -384,21 +399,23 @@ print_mdoc_node(DECL_ARGS)
if (MDOC_EOS & n->flags)
p->flags |= TERMP_SENTENCE;
- p->offset = offset;
- p->rmargin = rmargin;
+ if (MDOC_ll != n->tok) {
+ p->offset = offset;
+ p->rmargin = rmargin;
+ }
}
-
static void
print_mdoc_foot(struct termp *p, const void *arg)
{
const struct mdoc_meta *meta;
+ size_t sz;
meta = (const struct mdoc_meta *)arg;
term_fontrepl(p, TERMFONT_NONE);
- /*
+ /*
* Output the footer in new-groff style, that is, three columns
* with the middle being the manual date and flanking columns
* being the operating system:
@@ -409,8 +426,9 @@ print_mdoc_foot(struct termp *p, const void *arg)
term_vspace(p);
p->offset = 0;
- p->rmargin = (p->maxrmargin -
- term_strlen(p, meta->date) + term_len(p, 1)) / 2;
+ sz = term_strlen(p, meta->date);
+ p->rmargin = p->maxrmargin > sz ?
+ (p->maxrmargin + term_len(p, 1) - sz) / 2 : 0;
p->trailspace = 1;
p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
@@ -418,7 +436,8 @@ print_mdoc_foot(struct termp *p, const void *arg)
term_flushln(p);
p->offset = p->rmargin;
- p->rmargin = p->maxrmargin - term_strlen(p, meta->os);
+ sz = term_strlen(p, meta->os);
+ p->rmargin = p->maxrmargin > sz ? p->maxrmargin - sz : 0;
p->flags |= TERMP_NOSPACE;
term_word(p, meta->date);
@@ -438,13 +457,12 @@ print_mdoc_foot(struct termp *p, const void *arg)
p->flags = 0;
}
-
static void
print_mdoc_head(struct termp *p, const void *arg)
{
- char buf[BUFSIZ], title[BUFSIZ];
- size_t buflen, titlen;
- const struct mdoc_meta *meta;
+ const struct mdoc_meta *meta;
+ char *volume, *title;
+ size_t vollen, titlen;
meta = (const struct mdoc_meta *)arg;
@@ -461,39 +479,37 @@ print_mdoc_head(struct termp *p, const void *arg)
* switches on the manual section.
*/
- p->offset = 0;
- p->rmargin = p->maxrmargin;
-
assert(meta->vol);
- strlcpy(buf, meta->vol, BUFSIZ);
- buflen = term_strlen(p, buf);
-
- if (meta->arch) {
- strlcat(buf, " (", BUFSIZ);
- strlcat(buf, meta->arch, BUFSIZ);
- strlcat(buf, ")", BUFSIZ);
- }
+ if (NULL == meta->arch)
+ volume = mandoc_strdup(meta->vol);
+ else
+ mandoc_asprintf(&volume, "%s (%s)",
+ meta->vol, meta->arch);
+ vollen = term_strlen(p, volume);
- snprintf(title, BUFSIZ, "%s(%s)", meta->title, meta->msec);
+ if (NULL == meta->msec)
+ title = mandoc_strdup(meta->title);
+ else
+ mandoc_asprintf(&title, "%s(%s)",
+ meta->title, meta->msec);
titlen = term_strlen(p, title);
p->flags |= TERMP_NOBREAK | TERMP_NOSPACE;
p->trailspace = 1;
p->offset = 0;
- p->rmargin = 2 * (titlen+1) + buflen < p->maxrmargin ?
- (p->maxrmargin -
- term_strlen(p, buf) + term_len(p, 1)) / 2 :
- p->maxrmargin - buflen;
+ p->rmargin = 2 * (titlen+1) + vollen < p->maxrmargin ?
+ (p->maxrmargin - vollen + term_len(p, 1)) / 2 :
+ vollen < p->maxrmargin ? p->maxrmargin - vollen : 0;
term_word(p, title);
term_flushln(p);
p->flags |= TERMP_NOSPACE;
p->offset = p->rmargin;
- p->rmargin = p->offset + buflen + titlen < p->maxrmargin ?
+ p->rmargin = p->offset + vollen + titlen < p->maxrmargin ?
p->maxrmargin - titlen : p->maxrmargin;
- term_word(p, buf);
+ term_word(p, volume);
term_flushln(p);
p->flags &= ~TERMP_NOBREAK;
@@ -509,65 +525,31 @@ print_mdoc_head(struct termp *p, const void *arg)
p->flags &= ~TERMP_NOSPACE;
p->offset = 0;
p->rmargin = p->maxrmargin;
+ free(title);
+ free(volume);
}
-
-static size_t
-a2height(const struct termp *p, const char *v)
-{
- struct roffsu su;
-
-
- assert(v);
- if ( ! a2roffsu(v, &su, SCALE_VS))
- SCALE_VS_INIT(&su, atoi(v));
-
- return(term_vspan(p, &su));
-}
-
-
-static size_t
+static int
a2width(const struct termp *p, const char *v)
{
struct roffsu su;
- assert(v);
- if ( ! a2roffsu(v, &su, SCALE_MAX))
+ if (a2roffsu(v, &su, SCALE_MAX) < 2) {
SCALE_HS_INIT(&su, term_strlen(p, v));
-
- return(term_hspan(p, &su));
-}
-
-
-static size_t
-a2offs(const struct termp *p, const char *v)
-{
- struct roffsu su;
-
- if ('\0' == *v)
- return(0);
- else if (0 == strcmp(v, "left"))
- return(0);
- else if (0 == strcmp(v, "indent"))
- return(term_len(p, p->defindent + 1));
- else if (0 == strcmp(v, "indent-two"))
- return(term_len(p, (p->defindent + 1) * 2));
- else if ( ! a2roffsu(v, &su, SCALE_MAX))
- SCALE_HS_INIT(&su, term_strlen(p, v));
-
+ su.scale /= term_strlen(p, "0");
+ }
return(term_hspan(p, &su));
}
-
/*
* Determine how much space to print out before block elements of `It'
* (and thus `Bl') and `Bd'. And then go ahead and print that space,
* too.
*/
static void
-print_bvspace(struct termp *p,
- const struct mdoc_node *bl,
- const struct mdoc_node *n)
+print_bvspace(struct termp *p,
+ const struct mdoc_node *bl,
+ const struct mdoc_node *n)
{
const struct mdoc_node *nn;
@@ -582,16 +564,18 @@ print_bvspace(struct termp *p,
/* Do not vspace directly after Ss/Sh. */
- for (nn = n; nn; nn = nn->parent) {
- if (MDOC_BLOCK != nn->type)
- continue;
- if (MDOC_Ss == nn->tok)
- return;
- if (MDOC_Sh == nn->tok)
+ nn = n;
+ while (nn->prev == NULL) {
+ do {
+ nn = nn->parent;
+ if (nn->type == MDOC_ROOT)
+ return;
+ } while (nn->type != MDOC_BLOCK);
+ if (nn->tok == MDOC_Sh || nn->tok == MDOC_Ss)
return;
- if (NULL == nn->prev)
- continue;
- break;
+ if (nn->tok == MDOC_It &&
+ nn->parent->parent->norm->Bl.type != LIST_item)
+ break;
}
/* A `-column' does not assert vspace within the list. */
@@ -613,14 +597,21 @@ print_bvspace(struct termp *p,
}
-/* ARGSUSED */
+static int
+termp_ll_pre(DECL_ARGS)
+{
+
+ term_setwidth(p, n->nchild ? n->child->string : NULL);
+ return(0);
+}
+
static int
termp_it_pre(DECL_ARGS)
{
+ char buf[24];
const struct mdoc_node *bl, *nn;
- char buf[7];
- int i;
- size_t width, offset, ncols, dcol;
+ size_t ncols, dcol;
+ int i, offset, width;
enum mdoc_list type;
if (MDOC_BLOCK == n->type) {
@@ -631,19 +622,50 @@ termp_it_pre(DECL_ARGS)
bl = n->parent->parent->parent;
type = bl->norm->Bl.type;
- /*
+ /*
+ * Defaults for specific list types.
+ */
+
+ switch (type) {
+ case LIST_bullet:
+ /* FALLTHROUGH */
+ case LIST_dash:
+ /* FALLTHROUGH */
+ case LIST_hyphen:
+ /* FALLTHROUGH */
+ case LIST_enum:
+ width = term_len(p, 2);
+ break;
+ case LIST_hang:
+ width = term_len(p, 8);
+ break;
+ case LIST_column:
+ /* FALLTHROUGH */
+ case LIST_tag:
+ width = term_len(p, 10);
+ break;
+ default:
+ width = 0;
+ break;
+ }
+ offset = 0;
+
+ /*
* First calculate width and offset. This is pretty easy unless
* we're a -column list, in which case all prior columns must
* be accounted for.
*/
- width = offset = 0;
-
- if (bl->norm->Bl.offs)
- offset = a2offs(p, bl->norm->Bl.offs);
+ if (bl->norm->Bl.offs != NULL) {
+ offset = a2width(p, bl->norm->Bl.offs);
+ if (offset < 0 && (size_t)(-offset) > p->offset)
+ offset = -p->offset;
+ else if (offset > SHRT_MAX)
+ offset = 0;
+ }
switch (type) {
- case (LIST_column):
+ case LIST_column:
if (MDOC_HEAD == n->type)
break;
@@ -657,21 +679,19 @@ termp_it_pre(DECL_ARGS)
* - For more than 5 columns, add only one column.
*/
ncols = bl->norm->Bl.ncols;
-
- /* LINTED */
- dcol = ncols < 5 ? term_len(p, 4) :
- ncols == 5 ? term_len(p, 3) : term_len(p, 1);
+ dcol = ncols < 5 ? term_len(p, 4) :
+ ncols == 5 ? term_len(p, 3) : term_len(p, 1);
/*
* Calculate the offset by applying all prior MDOC_BODY,
* so we stop at the MDOC_HEAD (NULL == nn->prev).
*/
- for (i = 0, nn = n->prev;
- nn->prev && i < (int)ncols;
- nn = nn->prev, i++)
- offset += dcol + a2width
- (p, bl->norm->Bl.cols[i]);
+ for (i = 0, nn = n->prev;
+ nn->prev && i < (int)ncols;
+ nn = nn->prev, i++)
+ offset += dcol + a2width(p,
+ bl->norm->Bl.cols[i]);
/*
* When exceeding the declared number of columns, leave
@@ -692,48 +712,20 @@ termp_it_pre(DECL_ARGS)
if (NULL == bl->norm->Bl.width)
break;
- /*
+ /*
* Note: buffer the width by 2, which is groff's magic
* number for buffering single arguments. See the above
* handling for column for how this changes.
*/
- assert(bl->norm->Bl.width);
width = a2width(p, bl->norm->Bl.width) + term_len(p, 2);
+ if (width < 0 && (size_t)(-width) > p->offset)
+ width = -p->offset;
+ else if (width > SHRT_MAX)
+ width = 0;
break;
}
- /*
- * List-type can override the width in the case of fixed-head
- * values (bullet, dash/hyphen, enum). Tags need a non-zero
- * offset.
- */
-
- switch (type) {
- case (LIST_bullet):
- /* FALLTHROUGH */
- case (LIST_dash):
- /* FALLTHROUGH */
- case (LIST_hyphen):
- /* FALLTHROUGH */
- case (LIST_enum):
- if (width < term_len(p, 2))
- width = term_len(p, 2);
- break;
- case (LIST_hang):
- if (0 == width)
- width = term_len(p, 8);
- break;
- case (LIST_column):
- /* FALLTHROUGH */
- case (LIST_tag):
- if (0 == width)
- width = term_len(p, 10);
- break;
- default:
- break;
- }
-
- /*
+ /*
* Whitespace control. Inset bodies need an initial space,
* while diagonal bodies need two.
*/
@@ -741,12 +733,12 @@ termp_it_pre(DECL_ARGS)
p->flags |= TERMP_NOSPACE;
switch (type) {
- case (LIST_diag):
+ case LIST_diag:
if (MDOC_BODY == n->type)
term_word(p, "\\ \\ ");
break;
- case (LIST_inset):
- if (MDOC_BODY == n->type)
+ case LIST_inset:
+ if (MDOC_BODY == n->type && n->parent->head->nchild)
term_word(p, "\\ ");
break;
default:
@@ -756,7 +748,7 @@ termp_it_pre(DECL_ARGS)
p->flags |= TERMP_NOSPACE;
switch (type) {
- case (LIST_diag):
+ case LIST_diag:
if (MDOC_HEAD == n->type)
term_fontpush(p, TERMFONT_BOLD);
break;
@@ -772,25 +764,25 @@ termp_it_pre(DECL_ARGS)
*/
switch (type) {
- case (LIST_enum):
+ case LIST_enum:
/*
* Weird special case.
- * Very narrow enum lists actually hang.
+ * Some very narrow lists actually hang.
*/
- if (width == term_len(p, 2))
- p->flags |= TERMP_HANG;
/* FALLTHROUGH */
- case (LIST_bullet):
+ case LIST_bullet:
/* FALLTHROUGH */
- case (LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case (LIST_hyphen):
+ case LIST_hyphen:
+ if (width <= (int)term_len(p, 2))
+ p->flags |= TERMP_HANG;
if (MDOC_HEAD != n->type)
break;
p->flags |= TERMP_NOBREAK;
p->trailspace = 1;
break;
- case (LIST_hang):
+ case LIST_hang:
if (MDOC_HEAD != n->type)
break;
@@ -800,25 +792,26 @@ termp_it_pre(DECL_ARGS)
* the "overstep" effect in term_flushln() and treat
* this as a `-ohang' list instead.
*/
- if (n->next->child &&
- (MDOC_Bl == n->next->child->tok ||
- MDOC_Bd == n->next->child->tok))
+ 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_HANG;
+ p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG;
p->trailspace = 1;
break;
- case (LIST_tag):
+ case LIST_tag:
if (MDOC_HEAD != n->type)
break;
- p->flags |= TERMP_NOBREAK;
+ p->flags |= TERMP_NOBREAK | TERMP_BRIND;
p->trailspace = 2;
if (NULL == n->next || NULL == n->next->child)
p->flags |= TERMP_DANGLE;
break;
- case (LIST_column):
+ case LIST_column:
if (MDOC_HEAD == n->type)
break;
@@ -831,17 +824,17 @@ termp_it_pre(DECL_ARGS)
}
break;
- case (LIST_diag):
+ case LIST_diag:
if (MDOC_HEAD != n->type)
break;
- p->flags |= TERMP_NOBREAK;
+ p->flags |= TERMP_NOBREAK | TERMP_BRIND;
p->trailspace = 1;
break;
default:
break;
}
- /*
+ /*
* Margin control. Set-head-width lists have their right
* margins shortened. The body for these lists has the offset
* necessarily lengthened. Everybody gets the offset.
@@ -850,36 +843,37 @@ termp_it_pre(DECL_ARGS)
p->offset += offset;
switch (type) {
- case (LIST_hang):
+ 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 (MDOC_HEAD == n->type && n->next->child &&
- (MDOC_Bl == n->next->child->tok ||
- MDOC_Bd == n->next->child->tok))
+ if (MDOC_HEAD == n->type &&
+ NULL != n->next &&
+ NULL != n->next->child &&
+ (MDOC_Bl == n->next->child->tok ||
+ MDOC_Bd == n->next->child->tok))
break;
/* FALLTHROUGH */
- case (LIST_bullet):
+ case LIST_bullet:
/* FALLTHROUGH */
- case (LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case (LIST_enum):
+ case LIST_enum:
/* FALLTHROUGH */
- case (LIST_hyphen):
+ case LIST_hyphen:
/* FALLTHROUGH */
- case (LIST_tag):
- assert(width);
+ case LIST_tag:
if (MDOC_HEAD == n->type)
p->rmargin = p->offset + width;
- else
+ else
p->offset += width;
break;
- case (LIST_column):
+ case LIST_column:
assert(width);
p->rmargin = p->offset + width;
- /*
+ /*
* XXX - this behaviour is not documented: the
* right-most column is filled to the right margin.
*/
@@ -892,53 +886,53 @@ termp_it_pre(DECL_ARGS)
break;
}
- /*
+ /*
* The dash, hyphen, bullet and enum lists all have a special
- * HEAD character (temporarily bold, in some cases).
+ * HEAD character (temporarily bold, in some cases).
*/
if (MDOC_HEAD == n->type)
switch (type) {
- case (LIST_bullet):
+ case LIST_bullet:
term_fontpush(p, TERMFONT_BOLD);
term_word(p, "\\[bu]");
term_fontpop(p);
break;
- case (LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case (LIST_hyphen):
+ case LIST_hyphen:
term_fontpush(p, TERMFONT_BOLD);
term_word(p, "\\(hy");
term_fontpop(p);
break;
- case (LIST_enum):
+ case LIST_enum:
(pair->ppair->ppair->count)++;
- snprintf(buf, sizeof(buf), "%d.",
- pair->ppair->ppair->count);
+ (void)snprintf(buf, sizeof(buf), "%d.",
+ pair->ppair->ppair->count);
term_word(p, buf);
break;
default:
break;
}
- /*
+ /*
* If we're not going to process our children, indicate so here.
*/
switch (type) {
- case (LIST_bullet):
+ case LIST_bullet:
/* FALLTHROUGH */
- case (LIST_item):
+ case LIST_item:
/* FALLTHROUGH */
- case (LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case (LIST_hyphen):
+ case LIST_hyphen:
/* FALLTHROUGH */
- case (LIST_enum):
+ case LIST_enum:
if (MDOC_HEAD == n->type)
return(0);
break;
- case (LIST_column):
+ case LIST_column:
if (MDOC_HEAD == n->type)
return(0);
break;
@@ -949,8 +943,6 @@ termp_it_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
termp_it_post(DECL_ARGS)
{
@@ -962,15 +954,15 @@ termp_it_post(DECL_ARGS)
type = n->parent->parent->parent->norm->Bl.type;
switch (type) {
- case (LIST_item):
+ case LIST_item:
/* FALLTHROUGH */
- case (LIST_diag):
+ case LIST_diag:
/* FALLTHROUGH */
- case (LIST_inset):
+ case LIST_inset:
if (MDOC_BODY == n->type)
term_newln(p);
break;
- case (LIST_column):
+ case LIST_column:
if (MDOC_BODY == n->type)
term_flushln(p);
break;
@@ -979,23 +971,21 @@ termp_it_post(DECL_ARGS)
break;
}
- /*
+ /*
* Now that our output is flushed, we can reset our tags. Since
* only `It' sets these flags, we're free to assume that nobody
* has munged them in the meanwhile.
*/
- p->flags &= ~TERMP_DANGLE;
- p->flags &= ~TERMP_NOBREAK;
- p->flags &= ~TERMP_HANG;
+ p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND |
+ TERMP_DANGLE | TERMP_HANG);
p->trailspace = 0;
}
-
-/* ARGSUSED */
static int
termp_nm_pre(DECL_ARGS)
{
+ const char *cp;
if (MDOC_BLOCK == n->type) {
p->flags |= TERMP_PREKEEP;
@@ -1006,12 +996,15 @@ termp_nm_pre(DECL_ARGS)
if (NULL == n->child)
return(0);
p->flags |= TERMP_NOSPACE;
- p->offset += term_len(p, 1) +
- (NULL == n->prev->child ?
- term_strlen(p, meta->name) :
- MDOC_TEXT == n->prev->child->type ?
- term_strlen(p, n->prev->child->string) :
- term_len(p, 5));
+ cp = NULL;
+ if (n->prev->child != NULL)
+ cp = n->prev->child->string;
+ if (cp == NULL)
+ cp = meta->name;
+ if (cp == NULL)
+ p->offset += term_len(p, 6);
+ else
+ p->offset += term_len(p, 1) + term_strlen(p, cp);
return(1);
}
@@ -1021,8 +1014,9 @@ termp_nm_pre(DECL_ARGS)
if (MDOC_HEAD == n->type)
synopsis_pre(p, n->parent);
- if (MDOC_HEAD == n->type && n->next->child) {
- p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
+ if (MDOC_HEAD == n->type &&
+ NULL != n->next && NULL != n->next->child) {
+ p->flags |= TERMP_NOSPACE | TERMP_NOBREAK | TERMP_BRIND;
p->trailspace = 1;
p->rmargin = p->offset + term_len(p, 1);
if (NULL == n->child) {
@@ -1043,24 +1037,21 @@ termp_nm_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
termp_nm_post(DECL_ARGS)
{
if (MDOC_BLOCK == n->type) {
p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
- } else if (MDOC_HEAD == n->type && n->next->child) {
+ } else if (MDOC_HEAD == n->type &&
+ NULL != n->next && NULL != n->next->child) {
term_flushln(p);
- p->flags &= ~(TERMP_NOBREAK | TERMP_HANG);
+ p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
p->trailspace = 0;
} else if (MDOC_BODY == n->type && n->child)
term_flushln(p);
}
-
-/* ARGSUSED */
static int
termp_fl_pre(DECL_ARGS)
{
@@ -1068,16 +1059,15 @@ termp_fl_pre(DECL_ARGS)
term_fontpush(p, TERMFONT_BOLD);
term_word(p, "\\-");
- if (n->child)
- p->flags |= TERMP_NOSPACE;
- else if (n->next && n->next->line == n->line)
+ if ( ! (n->nchild == 0 &&
+ (n->next == NULL ||
+ n->next->type == MDOC_TEXT ||
+ n->next->flags & MDOC_LINE)))
p->flags |= TERMP_NOSPACE;
return(1);
}
-
-/* ARGSUSED */
static int
termp__a_pre(DECL_ARGS)
{
@@ -1089,66 +1079,30 @@ termp__a_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
termp_an_pre(DECL_ARGS)
{
- if (NULL == n->child)
- return(1);
-
- /*
- * If not in the AUTHORS section, `An -split' will cause
- * newlines to occur before the author name. If in the AUTHORS
- * section, by default, the first `An' invocation is nosplit,
- * then all subsequent ones, regardless of whether interspersed
- * with other macros/text, are split. -split, in this case,
- * will override the condition of the implied first -nosplit.
- */
-
- if (n->sec == SEC_AUTHORS) {
- if ( ! (TERMP_ANPREC & p->flags)) {
- if (TERMP_SPLIT & p->flags)
- term_newln(p);
- return(1);
- }
- if (TERMP_NOSPLIT & p->flags)
- return(1);
- term_newln(p);
- return(1);
- }
-
- if (TERMP_SPLIT & p->flags)
- term_newln(p);
-
- return(1);
-}
-
-
-/* ARGSUSED */
-static void
-termp_an_post(DECL_ARGS)
-{
-
- if (n->child) {
- if (SEC_AUTHORS == n->sec)
- p->flags |= TERMP_ANPREC;
- return;
- }
-
- if (AUTH_split == n->norm->An.auth) {
+ if (n->norm->An.auth == AUTH_split) {
p->flags &= ~TERMP_NOSPLIT;
p->flags |= TERMP_SPLIT;
- } else if (AUTH_nosplit == n->norm->An.auth) {
+ return(0);
+ }
+ if (n->norm->An.auth == AUTH_nosplit) {
p->flags &= ~TERMP_SPLIT;
p->flags |= TERMP_NOSPLIT;
+ return(0);
}
-}
+ if (p->flags & TERMP_SPLIT)
+ term_newln(p);
+ if (n->sec == SEC_AUTHORS && ! (p->flags & TERMP_NOSPLIT))
+ p->flags |= TERMP_SPLIT;
+
+ return(1);
+}
-/* ARGSUSED */
static int
termp_ns_pre(DECL_ARGS)
{
@@ -1158,8 +1112,6 @@ termp_ns_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
termp_rs_pre(DECL_ARGS)
{
@@ -1171,54 +1123,59 @@ termp_rs_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
termp_rv_pre(DECL_ARGS)
{
int nchild;
term_newln(p);
- term_word(p, "The");
nchild = n->nchild;
- for (n = n->child; n; n = n->next) {
- term_fontpush(p, TERMFONT_BOLD);
- term_word(p, n->string);
- term_fontpop(p);
+ if (nchild > 0) {
+ term_word(p, "The");
- p->flags |= TERMP_NOSPACE;
- term_word(p, "()");
+ for (n = n->child; n; n = n->next) {
+ term_fontpush(p, TERMFONT_BOLD);
+ term_word(p, n->string);
+ term_fontpop(p);
- if (nchild > 2 && n->next) {
p->flags |= TERMP_NOSPACE;
- term_word(p, ",");
+ term_word(p, "()");
+
+ if (n->next == NULL)
+ continue;
+
+ if (nchild > 2) {
+ p->flags |= TERMP_NOSPACE;
+ term_word(p, ",");
+ }
+ if (n->next->next == NULL)
+ term_word(p, "and");
}
- if (n->next && NULL == n->next->next)
- term_word(p, "and");
- }
+ if (nchild > 1)
+ term_word(p, "functions return");
+ else
+ term_word(p, "function returns");
- if (nchild > 1)
- term_word(p, "functions return");
- else
- term_word(p, "function returns");
+ term_word(p, "the value\\~0 if successful;");
+ } else
+ term_word(p, "Upon successful completion,"
+ " the value\\~0 is returned;");
- term_word(p, "the value 0 if successful; otherwise the value "
- "-1 is returned and the global variable");
+ term_word(p, "otherwise the value\\~\\-1 is returned"
+ " and the global variable");
term_fontpush(p, TERMFONT_UNDER);
term_word(p, "errno");
term_fontpop(p);
- term_word(p, "is set to indicate the error.");
+ term_word(p, "is set to indicate the error.");
p->flags |= TERMP_SENTENCE;
return(0);
}
-
-/* ARGSUSED */
static int
termp_ex_pre(DECL_ARGS)
{
@@ -1243,35 +1200,25 @@ termp_ex_pre(DECL_ARGS)
}
if (nchild > 1)
- term_word(p, "utilities exit");
+ term_word(p, "utilities exit\\~0");
else
- term_word(p, "utility exits");
+ term_word(p, "utility exits\\~0");
- term_word(p, "0 on success, and >0 if an error occurs.");
+ term_word(p, "on success, and\\~>0 if an error occurs.");
p->flags |= TERMP_SENTENCE;
return(0);
}
-
-/* ARGSUSED */
static int
termp_nd_pre(DECL_ARGS)
{
- if (MDOC_BODY != n->type)
- return(1);
-
-#if defined(__OpenBSD__) || defined(__linux__)
- term_word(p, "\\(en");
-#else
- term_word(p, "\\(em");
-#endif
+ if (n->type == MDOC_BODY)
+ term_word(p, "\\(en");
return(1);
}
-
-/* ARGSUSED */
static int
termp_bl_pre(DECL_ARGS)
{
@@ -1279,8 +1226,6 @@ termp_bl_pre(DECL_ARGS)
return(MDOC_HEAD != n->type);
}
-
-/* ARGSUSED */
static void
termp_bl_post(DECL_ARGS)
{
@@ -1289,7 +1234,6 @@ termp_bl_post(DECL_ARGS)
term_newln(p);
}
-/* ARGSUSED */
static int
termp_xr_pre(DECL_ARGS)
{
@@ -1300,7 +1244,7 @@ termp_xr_pre(DECL_ARGS)
assert(MDOC_TEXT == n->type);
term_word(p, n->string);
- if (NULL == (n = n->next))
+ if (NULL == (n = n->next))
return(0);
p->flags |= TERMP_NOSPACE;
@@ -1324,7 +1268,7 @@ termp_xr_pre(DECL_ARGS)
static void
synopsis_pre(struct termp *p, const struct mdoc_node *n)
{
- /*
+ /*
* Obviously, if we're not in a SYNOPSIS or no prior macros
* exist, do nothing.
*/
@@ -1336,10 +1280,10 @@ synopsis_pre(struct termp *p, const struct mdoc_node *n)
* newline and return. UNLESS we're `Fo', `Fn', `Fn', in which
* case we soldier on.
*/
- if (n->prev->tok == n->tok &&
- MDOC_Ft != n->tok &&
- MDOC_Fo != n->tok &&
- MDOC_Fn != n->tok) {
+ if (n->prev->tok == n->tok &&
+ MDOC_Ft != n->tok &&
+ MDOC_Fo != n->tok &&
+ MDOC_Fn != n->tok) {
term_newln(p);
return;
}
@@ -1350,18 +1294,18 @@ synopsis_pre(struct termp *p, const struct mdoc_node *n)
* vertical space, else only newline and move on.
*/
switch (n->prev->tok) {
- case (MDOC_Fd):
+ case MDOC_Fd:
/* FALLTHROUGH */
- case (MDOC_Fn):
+ case MDOC_Fn:
/* FALLTHROUGH */
- case (MDOC_Fo):
+ case MDOC_Fo:
/* FALLTHROUGH */
- case (MDOC_In):
+ case MDOC_In:
/* FALLTHROUGH */
- case (MDOC_Vt):
+ case MDOC_Vt:
term_vspace(p);
break;
- case (MDOC_Ft):
+ case MDOC_Ft:
if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
term_vspace(p);
break;
@@ -1373,7 +1317,6 @@ synopsis_pre(struct termp *p, const struct mdoc_node *n)
}
}
-
static int
termp_vt_pre(DECL_ARGS)
{
@@ -1390,8 +1333,6 @@ termp_vt_pre(DECL_ARGS)
return(termp_under_pre(p, pair, meta, n));
}
-
-/* ARGSUSED */
static int
termp_bold_pre(DECL_ARGS)
{
@@ -1400,8 +1341,6 @@ termp_bold_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
termp_fd_pre(DECL_ARGS)
{
@@ -1410,8 +1349,6 @@ termp_fd_pre(DECL_ARGS)
return(termp_bold_pre(p, pair, meta, n));
}
-
-/* ARGSUSED */
static void
termp_fd_post(DECL_ARGS)
{
@@ -1419,25 +1356,26 @@ termp_fd_post(DECL_ARGS)
term_newln(p);
}
-
-/* ARGSUSED */
static int
termp_sh_pre(DECL_ARGS)
{
- /* No vspace between consecutive `Sh' calls. */
-
switch (n->type) {
- case (MDOC_BLOCK):
- if (n->prev && MDOC_Sh == n->prev->tok)
- if (NULL == n->prev->body->child)
- break;
- term_vspace(p);
+ case MDOC_BLOCK:
+ /*
+ * Vertical space before sections, except
+ * when the previous section was empty.
+ */
+ if (n->prev == NULL ||
+ MDOC_Sh != n->prev->tok ||
+ (n->prev->body != NULL &&
+ n->prev->body->child != NULL))
+ term_vspace(p);
break;
- case (MDOC_HEAD):
+ case MDOC_HEAD:
term_fontpush(p, TERMFONT_BOLD);
break;
- case (MDOC_BODY):
+ case MDOC_BODY:
p->offset = term_len(p, p->defindent);
if (SEC_AUTHORS == n->sec)
p->flags &= ~(TERMP_SPLIT|TERMP_NOSPLIT);
@@ -1448,17 +1386,15 @@ termp_sh_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
termp_sh_post(DECL_ARGS)
{
switch (n->type) {
- case (MDOC_HEAD):
+ case MDOC_HEAD:
term_newln(p);
break;
- case (MDOC_BODY):
+ case MDOC_BODY:
term_newln(p);
p->offset = 0;
break;
@@ -1467,8 +1403,6 @@ termp_sh_post(DECL_ARGS)
}
}
-
-/* ARGSUSED */
static int
termp_bt_pre(DECL_ARGS)
{
@@ -1478,8 +1412,6 @@ termp_bt_pre(DECL_ARGS)
return(0);
}
-
-/* ARGSUSED */
static void
termp_lb_post(DECL_ARGS)
{
@@ -1488,8 +1420,6 @@ termp_lb_post(DECL_ARGS)
term_newln(p);
}
-
-/* ARGSUSED */
static int
termp_ud_pre(DECL_ARGS)
{
@@ -1499,8 +1429,6 @@ termp_ud_pre(DECL_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
termp_d1_pre(DECL_ARGS)
{
@@ -1512,8 +1440,6 @@ termp_d1_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
termp_ft_pre(DECL_ARGS)
{
@@ -1524,8 +1450,6 @@ termp_ft_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
termp_fn_pre(DECL_ARGS)
{
@@ -1542,7 +1466,7 @@ termp_fn_pre(DECL_ARGS)
if (pretty) {
rmargin = p->rmargin;
p->rmargin = p->offset + term_len(p, 4);
- p->flags |= TERMP_NOBREAK | TERMP_HANG;
+ p->flags |= TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG;
}
assert(MDOC_TEXT == n->type);
@@ -1552,7 +1476,7 @@ termp_fn_pre(DECL_ARGS)
if (pretty) {
term_flushln(p);
- p->flags &= ~(TERMP_NOBREAK | TERMP_HANG);
+ p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND | TERMP_HANG);
p->offset = p->rmargin;
p->rmargin = rmargin;
}
@@ -1587,8 +1511,6 @@ termp_fn_pre(DECL_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
termp_fa_pre(DECL_ARGS)
{
@@ -1614,13 +1536,12 @@ termp_fa_pre(DECL_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
termp_bd_pre(DECL_ARGS)
{
- size_t tabwidth, rm, rmax;
+ size_t tabwidth, lm, len, rm, rmax;
struct mdoc_node *nn;
+ int offset;
if (MDOC_BLOCK == n->type) {
print_bvspace(p, n, n);
@@ -1628,8 +1549,22 @@ termp_bd_pre(DECL_ARGS)
} else if (MDOC_HEAD == n->type)
return(0);
- if (n->norm->Bd.offs)
- p->offset += a2offs(p, n->norm->Bd.offs);
+ /* Handle the -offset argument. */
+
+ if (n->norm->Bd.offs == NULL ||
+ ! strcmp(n->norm->Bd.offs, "left"))
+ /* nothing */;
+ else if ( ! strcmp(n->norm->Bd.offs, "indent"))
+ p->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);
+ else {
+ offset = a2width(p, n->norm->Bd.offs);
+ if (offset < 0 && (size_t)(-offset) > p->offset)
+ p->offset = 0;
+ else if (offset < SHRT_MAX)
+ p->offset += offset;
+ }
/*
* If -ragged or -filled are specified, the block does nothing
@@ -1638,20 +1573,31 @@ termp_bd_pre(DECL_ARGS)
* for macro lines, a newline is appended to the line. Blank
* lines are allowed.
*/
-
- if (DISP_literal != n->norm->Bd.type &&
- DISP_unfilled != n->norm->Bd.type)
+
+ if (DISP_literal != n->norm->Bd.type &&
+ DISP_unfilled != n->norm->Bd.type &&
+ DISP_centered != n->norm->Bd.type)
return(1);
tabwidth = p->tabwidth;
if (DISP_literal == n->norm->Bd.type)
p->tabwidth = term_len(p, 8);
+ 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) {
+ if (MDOC_TEXT == nn->type) {
+ len = term_strlen(p, nn->string);
+ p->offset = len >= rm ? 0 :
+ lm + len >= rm ? rm - len :
+ (lm + rm - len) / 2;
+ } else
+ p->offset = lm;
+ }
print_mdoc_node(p, pair, meta, nn);
/*
* If the printed node flushes its own line, then we
@@ -1660,26 +1606,27 @@ termp_bd_pre(DECL_ARGS)
* anyway, so don't sweat it.
*/
switch (nn->tok) {
- case (MDOC_Sm):
+ case MDOC_Sm:
/* FALLTHROUGH */
- case (MDOC_br):
+ case MDOC_br:
/* FALLTHROUGH */
- case (MDOC_sp):
+ case MDOC_sp:
/* FALLTHROUGH */
- case (MDOC_Bl):
+ case MDOC_Bl:
/* FALLTHROUGH */
- case (MDOC_D1):
+ case MDOC_D1:
/* FALLTHROUGH */
- case (MDOC_Dl):
+ case MDOC_Dl:
/* FALLTHROUGH */
- case (MDOC_Lp):
+ case MDOC_Lp:
/* FALLTHROUGH */
- case (MDOC_Pp):
+ case MDOC_Pp:
continue;
default:
break;
}
- if (nn->next && nn->next->line == nn->line)
+ if (p->flags & TERMP_NONEWLINE ||
+ (nn->next && ! (nn->next->flags & MDOC_LINE)))
continue;
term_flushln(p);
p->flags |= TERMP_NOSPACE;
@@ -1691,21 +1638,19 @@ termp_bd_pre(DECL_ARGS)
return(0);
}
-
-/* ARGSUSED */
static void
termp_bd_post(DECL_ARGS)
{
size_t rm, rmax;
- if (MDOC_BODY != n->type)
+ if (MDOC_BODY != n->type)
return;
rm = p->rmargin;
rmax = p->maxrmargin;
- if (DISP_literal == n->norm->Bd.type ||
- DISP_unfilled == n->norm->Bd.type)
+ if (DISP_literal == n->norm->Bd.type ||
+ DISP_unfilled == n->norm->Bd.type)
p->rmargin = p->maxrmargin = TERM_MAXMARGIN;
p->flags |= TERMP_NOSPACE;
@@ -1715,8 +1660,6 @@ termp_bd_post(DECL_ARGS)
p->maxrmargin = rmax;
}
-
-/* ARGSUSED */
static int
termp_bx_pre(DECL_ARGS)
{
@@ -1740,8 +1683,6 @@ termp_bx_pre(DECL_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
termp_xx_pre(DECL_ARGS)
{
@@ -1750,22 +1691,22 @@ termp_xx_pre(DECL_ARGS)
pp = NULL;
switch (n->tok) {
- case (MDOC_Bsx):
+ case MDOC_Bsx:
pp = "BSD/OS";
break;
- case (MDOC_Dx):
+ case MDOC_Dx:
pp = "DragonFly";
break;
- case (MDOC_Fx):
+ case MDOC_Fx:
pp = "FreeBSD";
break;
- case (MDOC_Nx):
+ case MDOC_Nx:
pp = "NetBSD";
break;
- case (MDOC_Ox):
+ case MDOC_Ox:
pp = "OpenBSD";
break;
- case (MDOC_Ux):
+ case MDOC_Ux:
pp = "UNIX";
break;
default:
@@ -1783,31 +1724,31 @@ termp_xx_pre(DECL_ARGS)
return(0);
}
-
-/* ARGSUSED */
static void
termp_pf_post(DECL_ARGS)
{
- p->flags |= TERMP_NOSPACE;
+ if ( ! (n->next == NULL || n->next->flags & MDOC_LINE))
+ p->flags |= TERMP_NOSPACE;
}
-
-/* ARGSUSED */
static int
termp_ss_pre(DECL_ARGS)
{
switch (n->type) {
- case (MDOC_BLOCK):
+ case MDOC_BLOCK:
term_newln(p);
if (n->prev)
term_vspace(p);
break;
- case (MDOC_HEAD):
+ case MDOC_HEAD:
term_fontpush(p, TERMFONT_BOLD);
p->offset = term_len(p, (p->defindent+1)/2);
break;
+ case MDOC_BODY:
+ p->offset = term_len(p, p->defindent);
+ break;
default:
break;
}
@@ -1815,18 +1756,14 @@ termp_ss_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
termp_ss_post(DECL_ARGS)
{
- if (MDOC_HEAD == n->type)
+ if (n->type == MDOC_HEAD || n->type == MDOC_BODY)
term_newln(p);
}
-
-/* ARGSUSED */
static int
termp_cd_pre(DECL_ARGS)
{
@@ -1836,8 +1773,6 @@ termp_cd_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
termp_in_pre(DECL_ARGS)
{
@@ -1857,8 +1792,6 @@ termp_in_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
termp_in_post(DECL_ARGS)
{
@@ -1873,18 +1806,22 @@ termp_in_post(DECL_ARGS)
term_fontpop(p);
}
-
-/* ARGSUSED */
static int
termp_sp_pre(DECL_ARGS)
{
- size_t i, len;
+ struct roffsu su;
+ int i, len;
switch (n->tok) {
- case (MDOC_sp):
- len = n->child ? a2height(p, n->child->string) : 1;
- break;
- case (MDOC_br):
+ 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:
@@ -1894,14 +1831,22 @@ termp_sp_pre(DECL_ARGS)
if (0 == len)
term_newln(p);
- for (i = 0; i < len; i++)
- term_vspace(p);
+ else if (len < 0)
+ p->skipvsp -= len;
+ else
+ for (i = 0; i < len; i++)
+ term_vspace(p);
return(0);
}
+static int
+termp_skip_pre(DECL_ARGS)
+{
+
+ return(0);
+}
-/* ARGSUSED */
static int
termp_quote_pre(DECL_ARGS)
{
@@ -1910,49 +1855,54 @@ termp_quote_pre(DECL_ARGS)
return(1);
switch (n->tok) {
- case (MDOC_Ao):
+ case MDOC_Ao:
/* FALLTHROUGH */
- case (MDOC_Aq):
- term_word(p, "<");
+ case MDOC_Aq:
+ term_word(p, n->nchild == 1 &&
+ n->child->tok == MDOC_Mt ? "<" : "\\(la");
break;
- case (MDOC_Bro):
+ case MDOC_Bro:
/* FALLTHROUGH */
- case (MDOC_Brq):
+ case MDOC_Brq:
term_word(p, "{");
break;
- case (MDOC_Oo):
+ case MDOC_Oo:
/* FALLTHROUGH */
- case (MDOC_Op):
+ case MDOC_Op:
/* FALLTHROUGH */
- case (MDOC_Bo):
+ case MDOC_Bo:
/* FALLTHROUGH */
- case (MDOC_Bq):
+ case MDOC_Bq:
term_word(p, "[");
break;
- case (MDOC_Do):
+ case MDOC_Do:
/* FALLTHROUGH */
- case (MDOC_Dq):
- term_word(p, "\\(lq");
+ case MDOC_Dq:
+ term_word(p, "\\(Lq");
break;
- case (MDOC_Eo):
+ case MDOC_En:
+ if (NULL == n->norm->Es ||
+ NULL == n->norm->Es->child)
+ return(1);
+ term_word(p, n->norm->Es->child->string);
break;
- case (MDOC_Po):
+ case MDOC_Po:
/* FALLTHROUGH */
- case (MDOC_Pq):
+ case MDOC_Pq:
term_word(p, "(");
break;
- case (MDOC__T):
+ case MDOC__T:
/* FALLTHROUGH */
- case (MDOC_Qo):
+ case MDOC_Qo:
/* FALLTHROUGH */
- case (MDOC_Qq):
+ case MDOC_Qq:
term_word(p, "\"");
break;
- case (MDOC_Ql):
+ case MDOC_Ql:
/* FALLTHROUGH */
- case (MDOC_So):
+ case MDOC_So:
/* FALLTHROUGH */
- case (MDOC_Sq):
+ case MDOC_Sq:
term_word(p, "\\(oq");
break;
default:
@@ -1964,61 +1914,66 @@ termp_quote_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
termp_quote_post(DECL_ARGS)
{
- if (MDOC_BODY != n->type && MDOC_ELEM != n->type)
+ if (n->type != MDOC_BODY && n->type != MDOC_ELEM)
return;
p->flags |= TERMP_NOSPACE;
switch (n->tok) {
- case (MDOC_Ao):
+ case MDOC_Ao:
/* FALLTHROUGH */
- case (MDOC_Aq):
- term_word(p, ">");
+ case MDOC_Aq:
+ term_word(p, n->nchild == 1 &&
+ n->child->tok == MDOC_Mt ? ">" : "\\(ra");
break;
- case (MDOC_Bro):
+ case MDOC_Bro:
/* FALLTHROUGH */
- case (MDOC_Brq):
+ case MDOC_Brq:
term_word(p, "}");
break;
- case (MDOC_Oo):
+ case MDOC_Oo:
/* FALLTHROUGH */
- case (MDOC_Op):
+ case MDOC_Op:
/* FALLTHROUGH */
- case (MDOC_Bo):
+ case MDOC_Bo:
/* FALLTHROUGH */
- case (MDOC_Bq):
+ case MDOC_Bq:
term_word(p, "]");
break;
- case (MDOC_Do):
+ case MDOC_Do:
/* FALLTHROUGH */
- case (MDOC_Dq):
- term_word(p, "\\(rq");
+ case MDOC_Dq:
+ term_word(p, "\\(Rq");
break;
- case (MDOC_Eo):
+ case MDOC_En:
+ if (n->norm->Es == NULL ||
+ n->norm->Es->child == NULL ||
+ n->norm->Es->child->next == NULL)
+ p->flags &= ~TERMP_NOSPACE;
+ else
+ term_word(p, n->norm->Es->child->next->string);
break;
- case (MDOC_Po):
+ case MDOC_Po:
/* FALLTHROUGH */
- case (MDOC_Pq):
+ case MDOC_Pq:
term_word(p, ")");
break;
- case (MDOC__T):
+ case MDOC__T:
/* FALLTHROUGH */
- case (MDOC_Qo):
+ case MDOC_Qo:
/* FALLTHROUGH */
- case (MDOC_Qq):
+ case MDOC_Qq:
term_word(p, "\"");
break;
- case (MDOC_Ql):
+ case MDOC_Ql:
/* FALLTHROUGH */
- case (MDOC_So):
+ case MDOC_So:
/* FALLTHROUGH */
- case (MDOC_Sq):
+ case MDOC_Sq:
term_word(p, "\\(cq");
break;
default:
@@ -2027,8 +1982,50 @@ termp_quote_post(DECL_ARGS)
}
}
+static int
+termp_eo_pre(DECL_ARGS)
+{
+
+ if (n->type != MDOC_BODY)
+ return(1);
+
+ if (n->end == ENDBODY_NOT &&
+ n->parent->head->child == NULL &&
+ n->child != NULL &&
+ n->child->end != ENDBODY_NOT)
+ term_word(p, "\\&");
+ else if (n->end != ENDBODY_NOT ? n->child != NULL :
+ n->parent->head->child != NULL && (n->child != NULL ||
+ (n->parent->tail != NULL && n->parent->tail->child != NULL)))
+ p->flags |= TERMP_NOSPACE;
+
+ return(1);
+}
+
+static void
+termp_eo_post(DECL_ARGS)
+{
+ int body, tail;
+
+ if (n->type != MDOC_BODY)
+ return;
+
+ if (n->end != ENDBODY_NOT) {
+ p->flags &= ~TERMP_NOSPACE;
+ return;
+ }
+
+ body = n->child != NULL || n->parent->head->child != NULL;
+ tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
+
+ if (body && tail)
+ p->flags |= TERMP_NOSPACE;
+ else if ( ! (body || tail))
+ term_word(p, "\\&");
+ else if ( ! tail)
+ p->flags &= ~TERMP_NOSPACE;
+}
-/* ARGSUSED */
static int
termp_fo_pre(DECL_ARGS)
{
@@ -2044,14 +2041,16 @@ termp_fo_pre(DECL_ARGS)
if (pretty) {
rmargin = p->rmargin;
p->rmargin = p->offset + term_len(p, 4);
- p->flags |= TERMP_NOBREAK | TERMP_HANG;
+ p->flags |= TERMP_NOBREAK | TERMP_BRIND |
+ TERMP_HANG;
}
p->flags |= TERMP_NOSPACE;
term_word(p, "(");
p->flags |= TERMP_NOSPACE;
if (pretty) {
term_flushln(p);
- p->flags &= ~(TERMP_NOBREAK | TERMP_HANG);
+ p->flags &= ~(TERMP_NOBREAK | TERMP_BRIND |
+ TERMP_HANG);
p->offset = p->rmargin;
p->rmargin = rmargin;
}
@@ -2069,13 +2068,11 @@ termp_fo_pre(DECL_ARGS)
return(0);
}
-
-/* ARGSUSED */
static void
termp_fo_post(DECL_ARGS)
{
- if (MDOC_BODY != n->type)
+ if (MDOC_BODY != n->type)
return;
p->flags |= TERMP_NOSPACE;
@@ -2088,8 +2085,6 @@ termp_fo_post(DECL_ARGS)
}
}
-
-/* ARGSUSED */
static int
termp_bf_pre(DECL_ARGS)
{
@@ -2099,35 +2094,33 @@ termp_bf_pre(DECL_ARGS)
else if (MDOC_BODY != n->type)
return(1);
- if (FONT_Em == n->norm->Bf.font)
+ if (FONT_Em == n->norm->Bf.font)
term_fontpush(p, TERMFONT_UNDER);
- else if (FONT_Sy == n->norm->Bf.font)
+ else if (FONT_Sy == n->norm->Bf.font)
term_fontpush(p, TERMFONT_BOLD);
- else
+ else
term_fontpush(p, TERMFONT_NONE);
return(1);
}
-
-/* ARGSUSED */
static int
termp_sm_pre(DECL_ARGS)
{
- assert(n->child && MDOC_TEXT == n->child->type);
- if (0 == strcmp("on", n->child->string)) {
- if (p->col)
- p->flags &= ~TERMP_NOSPACE;
+ if (NULL == n->child)
+ p->flags ^= TERMP_NONOSPACE;
+ else if (0 == strcmp("on", n->child->string))
p->flags &= ~TERMP_NONOSPACE;
- } else
+ else
p->flags |= TERMP_NONOSPACE;
+ if (p->col && ! (TERMP_NONOSPACE & p->flags))
+ p->flags &= ~TERMP_NOSPACE;
+
return(0);
}
-
-/* ARGSUSED */
static int
termp_ap_pre(DECL_ARGS)
{
@@ -2138,8 +2131,6 @@ termp_ap_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
termp____post(DECL_ARGS)
{
@@ -2167,8 +2158,6 @@ termp____post(DECL_ARGS)
term_word(p, ",");
}
-
-/* ARGSUSED */
static int
termp_li_pre(DECL_ARGS)
{
@@ -2177,8 +2166,6 @@ termp_li_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static int
termp_lk_pre(DECL_ARGS)
{
@@ -2205,18 +2192,16 @@ termp_lk_pre(DECL_ARGS)
return(0);
}
-
-/* ARGSUSED */
static int
termp_bk_pre(DECL_ARGS)
{
switch (n->type) {
- case (MDOC_BLOCK):
+ case MDOC_BLOCK:
break;
- case (MDOC_HEAD):
+ case MDOC_HEAD:
return(0);
- case (MDOC_BODY):
+ case MDOC_BODY:
if (n->parent->args || 0 == n->prev->nchild)
p->flags |= TERMP_PREKEEP;
break;
@@ -2228,8 +2213,6 @@ termp_bk_pre(DECL_ARGS)
return(1);
}
-
-/* ARGSUSED */
static void
termp_bk_post(DECL_ARGS)
{
@@ -2238,7 +2221,6 @@ termp_bk_post(DECL_ARGS)
p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
}
-/* ARGSUSED */
static void
termp__t_post(DECL_ARGS)
{
@@ -2248,13 +2230,12 @@ termp__t_post(DECL_ARGS)
* us instead of underlining us (for disambiguation).
*/
if (n->parent && MDOC_Rs == n->parent->tok &&
- n->parent->norm->Rs.quote_T)
+ n->parent->norm->Rs.quote_T)
termp_quote_post(p, pair, meta, n);
termp____post(p, pair, meta, n);
}
-/* ARGSUSED */
static int
termp__t_pre(DECL_ARGS)
{
@@ -2264,14 +2245,13 @@ termp__t_pre(DECL_ARGS)
* us instead of underlining us (for disambiguation).
*/
if (n->parent && MDOC_Rs == n->parent->tok &&
- n->parent->norm->Rs.quote_T)
+ n->parent->norm->Rs.quote_T)
return(termp_quote_pre(p, pair, meta, n));
term_fontpush(p, TERMFONT_UNDER);
return(1);
}
-/* ARGSUSED */
static int
termp_under_pre(DECL_ARGS)
{
diff --git a/usr/src/cmd/mandoc/mdoc_validate.c b/usr/src/cmd/mandoc/mdoc_validate.c
index 4cfd620448..eb531e8289 100644
--- a/usr/src/cmd/mandoc/mdoc_validate.c
+++ b/usr/src/cmd/mandoc/mdoc_validate.c
@@ -1,7 +1,8 @@
-/* $Id: mdoc_validate.c,v 1.198 2013/12/15 21:23:52 schwarze Exp $ */
+/* $Id: mdoc_validate.c,v 1.283 2015/02/23 13:55:55 schwarze Exp $ */
/*
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.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,16 +16,13 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
+#include <sys/types.h>
#ifndef OSNAME
#include <sys/utsname.h>
#endif
-#include <sys/types.h>
-
#include <assert.h>
#include <ctype.h>
#include <limits.h>
@@ -35,6 +33,7 @@
#include "mdoc.h"
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libmdoc.h"
#include "libmandoc.h"
@@ -43,223 +42,162 @@
#define PRE_ARGS struct mdoc *mdoc, struct mdoc_node *n
#define POST_ARGS struct mdoc *mdoc
-#define NUMSIZ 32
-#define DATESIZE 32
-
enum check_ineq {
CHECK_LT,
CHECK_GT,
CHECK_EQ
};
-enum check_lvl {
- CHECK_WARN,
- CHECK_ERROR,
-};
-
-typedef int (*v_pre)(PRE_ARGS);
-typedef int (*v_post)(POST_ARGS);
+typedef void (*v_pre)(PRE_ARGS);
+typedef void (*v_post)(POST_ARGS);
struct valids {
- v_pre *pre;
- v_post *post;
+ v_pre pre;
+ v_post post;
};
-static int check_count(struct mdoc *, enum mdoc_type,
- enum check_lvl, enum check_ineq, int);
-static int check_parent(PRE_ARGS, enum mdoct, enum mdoc_type);
static void check_text(struct mdoc *, int, int, char *);
-static void check_argv(struct mdoc *,
+static void check_argv(struct mdoc *,
struct mdoc_node *, struct mdoc_argv *);
static void check_args(struct mdoc *, struct mdoc_node *);
-static int concat(char *, const struct mdoc_node *, size_t);
+static int child_an(const struct mdoc_node *);
static enum mdoc_sec a2sec(const char *);
static size_t macro2len(enum mdoct);
-
-static int ebool(POST_ARGS);
-static int berr_ge1(POST_ARGS);
-static int bwarn_ge1(POST_ARGS);
-static int ewarn_eq0(POST_ARGS);
-static int ewarn_eq1(POST_ARGS);
-static int ewarn_ge1(POST_ARGS);
-static int ewarn_le1(POST_ARGS);
-static int hwarn_eq0(POST_ARGS);
-static int hwarn_eq1(POST_ARGS);
-static int hwarn_ge1(POST_ARGS);
-static int hwarn_le1(POST_ARGS);
-
-static int post_an(POST_ARGS);
-static int post_at(POST_ARGS);
-static int post_bf(POST_ARGS);
-static int post_bl(POST_ARGS);
-static int post_bl_block(POST_ARGS);
-static int post_bl_block_width(POST_ARGS);
-static int post_bl_block_tag(POST_ARGS);
-static int post_bl_head(POST_ARGS);
-static int post_bx(POST_ARGS);
-static int post_defaults(POST_ARGS);
-static int post_dd(POST_ARGS);
-static int post_dt(POST_ARGS);
-static int post_eoln(POST_ARGS);
-static int post_hyph(POST_ARGS);
-static int post_ignpar(POST_ARGS);
-static int post_it(POST_ARGS);
-static int post_lb(POST_ARGS);
-static int post_literal(POST_ARGS);
-static int post_nm(POST_ARGS);
-static int post_ns(POST_ARGS);
-static int post_os(POST_ARGS);
-static int post_par(POST_ARGS);
-static int post_prol(POST_ARGS);
-static int post_root(POST_ARGS);
-static int post_rs(POST_ARGS);
-static int post_sh(POST_ARGS);
-static int post_sh_body(POST_ARGS);
-static int post_sh_head(POST_ARGS);
-static int post_st(POST_ARGS);
-static int post_std(POST_ARGS);
-static int post_vt(POST_ARGS);
-static int pre_an(PRE_ARGS);
-static int pre_bd(PRE_ARGS);
-static int pre_bl(PRE_ARGS);
-static int pre_dd(PRE_ARGS);
-static int pre_display(PRE_ARGS);
-static int pre_dt(PRE_ARGS);
-static int pre_it(PRE_ARGS);
-static int pre_literal(PRE_ARGS);
-static int pre_os(PRE_ARGS);
-static int pre_par(PRE_ARGS);
-static int pre_sh(PRE_ARGS);
-static int pre_ss(PRE_ARGS);
-static int pre_std(PRE_ARGS);
-
-static v_post posts_an[] = { post_an, NULL };
-static v_post posts_at[] = { post_at, post_defaults, NULL };
-static v_post posts_bd[] = { post_literal, hwarn_eq0, bwarn_ge1, NULL };
-static v_post posts_bf[] = { hwarn_le1, post_bf, NULL };
-static v_post posts_bk[] = { hwarn_eq0, bwarn_ge1, NULL };
-static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL };
-static v_post posts_bx[] = { post_bx, NULL };
-static v_post posts_bool[] = { ebool, NULL };
-static v_post posts_eoln[] = { post_eoln, NULL };
-static v_post posts_defaults[] = { post_defaults, NULL };
-static v_post posts_d1[] = { bwarn_ge1, post_hyph, NULL };
-static v_post posts_dd[] = { post_dd, post_prol, NULL };
-static v_post posts_dl[] = { post_literal, bwarn_ge1, NULL };
-static v_post posts_dt[] = { post_dt, post_prol, NULL };
-static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL };
-static v_post posts_hyph[] = { post_hyph, NULL };
-static v_post posts_hyphtext[] = { ewarn_ge1, post_hyph, NULL };
-static v_post posts_it[] = { post_it, NULL };
-static v_post posts_lb[] = { post_lb, NULL };
-static v_post posts_nd[] = { berr_ge1, post_hyph, NULL };
-static v_post posts_nm[] = { post_nm, NULL };
-static v_post posts_notext[] = { ewarn_eq0, NULL };
-static v_post posts_ns[] = { post_ns, NULL };
-static v_post posts_os[] = { post_os, post_prol, NULL };
-static v_post posts_pp[] = { post_par, ewarn_eq0, NULL };
-static v_post posts_rs[] = { post_rs, NULL };
-static v_post posts_sh[] = { post_ignpar,hwarn_ge1,post_sh,post_hyph,NULL };
-static v_post posts_sp[] = { post_par, ewarn_le1, NULL };
-static v_post posts_ss[] = { post_ignpar, hwarn_ge1, post_hyph, NULL };
-static v_post posts_st[] = { post_st, NULL };
-static v_post posts_std[] = { post_std, NULL };
-static v_post posts_text[] = { ewarn_ge1, NULL };
-static v_post posts_text1[] = { ewarn_eq1, NULL };
-static v_post posts_vt[] = { post_vt, NULL };
-static v_pre pres_an[] = { pre_an, NULL };
-static v_pre pres_bd[] = { pre_display, pre_bd, pre_literal, pre_par, NULL };
-static v_pre pres_bl[] = { pre_bl, pre_par, NULL };
-static v_pre pres_d1[] = { pre_display, NULL };
-static v_pre pres_dl[] = { pre_literal, pre_display, NULL };
-static v_pre pres_dd[] = { pre_dd, NULL };
-static v_pre pres_dt[] = { pre_dt, NULL };
-static v_pre pres_it[] = { pre_it, pre_par, NULL };
-static v_pre pres_os[] = { pre_os, NULL };
-static v_pre pres_pp[] = { pre_par, NULL };
-static v_pre pres_sh[] = { pre_sh, NULL };
-static v_pre pres_ss[] = { pre_ss, NULL };
-static v_pre pres_std[] = { pre_std, NULL };
+static void rewrite_macro2len(char **);
+
+static void post_an(POST_ARGS);
+static void post_at(POST_ARGS);
+static void post_bf(POST_ARGS);
+static void post_bk(POST_ARGS);
+static void post_bl(POST_ARGS);
+static void post_bl_block(POST_ARGS);
+static void post_bl_block_tag(POST_ARGS);
+static void post_bl_head(POST_ARGS);
+static void post_bx(POST_ARGS);
+static void post_d1(POST_ARGS);
+static void post_defaults(POST_ARGS);
+static void post_dd(POST_ARGS);
+static void post_dt(POST_ARGS);
+static void post_en(POST_ARGS);
+static void post_es(POST_ARGS);
+static void post_eoln(POST_ARGS);
+static void post_ex(POST_ARGS);
+static void post_fa(POST_ARGS);
+static void post_fn(POST_ARGS);
+static void post_fname(POST_ARGS);
+static void post_fo(POST_ARGS);
+static void post_hyph(POST_ARGS);
+static void post_ignpar(POST_ARGS);
+static void post_it(POST_ARGS);
+static void post_lb(POST_ARGS);
+static void post_literal(POST_ARGS);
+static void post_nd(POST_ARGS);
+static void post_nm(POST_ARGS);
+static void post_ns(POST_ARGS);
+static void post_os(POST_ARGS);
+static void post_par(POST_ARGS);
+static void post_root(POST_ARGS);
+static void post_rs(POST_ARGS);
+static void post_sh(POST_ARGS);
+static void post_sh_head(POST_ARGS);
+static void post_sh_name(POST_ARGS);
+static void post_sh_see_also(POST_ARGS);
+static void post_sh_authors(POST_ARGS);
+static void post_sm(POST_ARGS);
+static void post_st(POST_ARGS);
+static void post_vt(POST_ARGS);
+
+static void pre_an(PRE_ARGS);
+static void pre_bd(PRE_ARGS);
+static void pre_bl(PRE_ARGS);
+static void pre_dd(PRE_ARGS);
+static void pre_display(PRE_ARGS);
+static void pre_dt(PRE_ARGS);
+static void pre_literal(PRE_ARGS);
+static void pre_obsolete(PRE_ARGS);
+static void pre_os(PRE_ARGS);
+static void pre_par(PRE_ARGS);
+static void pre_std(PRE_ARGS);
static const struct valids mdoc_valids[MDOC_MAX] = {
{ NULL, NULL }, /* Ap */
- { pres_dd, posts_dd }, /* Dd */
- { pres_dt, posts_dt }, /* Dt */
- { pres_os, posts_os }, /* Os */
- { pres_sh, posts_sh }, /* Sh */
- { pres_ss, posts_ss }, /* Ss */
- { pres_pp, posts_pp }, /* Pp */
- { pres_d1, posts_d1 }, /* D1 */
- { pres_dl, posts_dl }, /* Dl */
- { pres_bd, posts_bd }, /* Bd */
+ { pre_dd, post_dd }, /* Dd */
+ { pre_dt, post_dt }, /* Dt */
+ { pre_os, post_os }, /* Os */
+ { NULL, post_sh }, /* Sh */
+ { NULL, post_ignpar }, /* Ss */
+ { pre_par, post_par }, /* Pp */
+ { pre_display, post_d1 }, /* D1 */
+ { pre_literal, post_literal }, /* Dl */
+ { pre_bd, post_literal }, /* Bd */
{ NULL, NULL }, /* Ed */
- { pres_bl, posts_bl }, /* Bl */
+ { pre_bl, post_bl }, /* Bl */
{ NULL, NULL }, /* El */
- { pres_it, posts_it }, /* It */
- { NULL, NULL }, /* Ad */
- { pres_an, posts_an }, /* An */
- { NULL, posts_defaults }, /* Ar */
- { NULL, NULL }, /* Cd */
+ { pre_par, post_it }, /* It */
+ { NULL, NULL }, /* Ad */
+ { pre_an, post_an }, /* An */
+ { NULL, post_defaults }, /* Ar */
+ { NULL, NULL }, /* Cd */
{ NULL, NULL }, /* Cm */
- { NULL, NULL }, /* Dv */
- { NULL, NULL }, /* Er */
- { NULL, NULL }, /* Ev */
- { pres_std, posts_std }, /* Ex */
- { NULL, NULL }, /* Fa */
- { NULL, posts_text }, /* Fd */
+ { NULL, NULL }, /* Dv */
+ { NULL, NULL }, /* Er */
+ { NULL, NULL }, /* Ev */
+ { pre_std, post_ex }, /* Ex */
+ { NULL, post_fa }, /* Fa */
+ { NULL, NULL }, /* Fd */
{ NULL, NULL }, /* Fl */
- { NULL, NULL }, /* Fn */
- { NULL, NULL }, /* Ft */
- { NULL, NULL }, /* Ic */
- { NULL, posts_text1 }, /* In */
- { NULL, posts_defaults }, /* Li */
- { NULL, posts_nd }, /* Nd */
- { NULL, posts_nm }, /* Nm */
+ { NULL, post_fn }, /* Fn */
+ { NULL, NULL }, /* Ft */
+ { NULL, NULL }, /* Ic */
+ { NULL, NULL }, /* In */
+ { NULL, post_defaults }, /* Li */
+ { NULL, post_nd }, /* Nd */
+ { NULL, post_nm }, /* Nm */
{ NULL, NULL }, /* Op */
- { NULL, NULL }, /* Ot */
- { NULL, posts_defaults }, /* Pa */
- { pres_std, posts_std }, /* Rv */
- { NULL, posts_st }, /* St */
+ { pre_obsolete, NULL }, /* Ot */
+ { NULL, post_defaults }, /* Pa */
+ { pre_std, NULL }, /* Rv */
+ { NULL, post_st }, /* St */
{ NULL, NULL }, /* Va */
- { NULL, posts_vt }, /* Vt */
- { NULL, posts_text }, /* Xr */
- { NULL, posts_text }, /* %A */
- { NULL, posts_hyphtext }, /* %B */ /* FIXME: can be used outside Rs/Re. */
- { NULL, posts_text }, /* %D */
- { NULL, posts_text }, /* %I */
- { NULL, posts_text }, /* %J */
- { NULL, posts_hyphtext }, /* %N */
- { NULL, posts_hyphtext }, /* %O */
- { NULL, posts_text }, /* %P */
- { NULL, posts_hyphtext }, /* %R */
- { NULL, posts_hyphtext }, /* %T */ /* FIXME: can be used outside Rs/Re. */
- { NULL, posts_text }, /* %V */
+ { NULL, post_vt }, /* Vt */
+ { NULL, NULL }, /* Xr */
+ { NULL, NULL }, /* %A */
+ { NULL, post_hyph }, /* %B */ /* FIXME: can be used outside Rs/Re. */
+ { NULL, NULL }, /* %D */
+ { NULL, NULL }, /* %I */
+ { NULL, NULL }, /* %J */
+ { NULL, post_hyph }, /* %N */
+ { NULL, post_hyph }, /* %O */
+ { NULL, NULL }, /* %P */
+ { NULL, post_hyph }, /* %R */
+ { NULL, post_hyph }, /* %T */ /* FIXME: can be used outside Rs/Re. */
+ { NULL, NULL }, /* %V */
{ NULL, NULL }, /* Ac */
{ NULL, NULL }, /* Ao */
{ NULL, NULL }, /* Aq */
- { NULL, posts_at }, /* At */
+ { NULL, post_at }, /* At */
{ NULL, NULL }, /* Bc */
- { NULL, posts_bf }, /* Bf */
+ { NULL, post_bf }, /* Bf */
{ NULL, NULL }, /* Bo */
{ NULL, NULL }, /* Bq */
{ NULL, NULL }, /* Bsx */
- { NULL, posts_bx }, /* Bx */
- { NULL, posts_bool }, /* Db */
+ { NULL, post_bx }, /* Bx */
+ { pre_obsolete, NULL }, /* Db */
{ NULL, NULL }, /* Dc */
{ NULL, NULL }, /* Do */
{ NULL, NULL }, /* Dq */
{ NULL, NULL }, /* Ec */
- { NULL, NULL }, /* Ef */
- { NULL, NULL }, /* Em */
+ { NULL, NULL }, /* Ef */
+ { NULL, NULL }, /* Em */
{ NULL, NULL }, /* Eo */
{ NULL, NULL }, /* Fx */
- { NULL, NULL }, /* Ms */
- { NULL, posts_notext }, /* No */
- { NULL, posts_ns }, /* Ns */
+ { NULL, NULL }, /* Ms */
+ { NULL, NULL }, /* No */
+ { NULL, post_ns }, /* Ns */
{ NULL, NULL }, /* Nx */
{ NULL, NULL }, /* Ox */
{ NULL, NULL }, /* Pc */
- { NULL, posts_text1 }, /* Pf */
+ { NULL, NULL }, /* Pf */
{ NULL, NULL }, /* Po */
{ NULL, NULL }, /* Pq */
{ NULL, NULL }, /* Qc */
@@ -267,43 +205,44 @@ static const struct valids mdoc_valids[MDOC_MAX] = {
{ NULL, NULL }, /* Qo */
{ NULL, NULL }, /* Qq */
{ NULL, NULL }, /* Re */
- { NULL, posts_rs }, /* Rs */
+ { NULL, post_rs }, /* Rs */
{ NULL, NULL }, /* Sc */
{ NULL, NULL }, /* So */
{ NULL, NULL }, /* Sq */
- { NULL, posts_bool }, /* Sm */
- { NULL, posts_hyph }, /* Sx */
+ { NULL, post_sm }, /* Sm */
+ { NULL, post_hyph }, /* Sx */
{ NULL, NULL }, /* Sy */
{ NULL, NULL }, /* Tn */
{ NULL, NULL }, /* Ux */
{ NULL, NULL }, /* Xc */
{ NULL, NULL }, /* Xo */
- { NULL, posts_fo }, /* Fo */
- { NULL, NULL }, /* Fc */
+ { NULL, post_fo }, /* Fo */
+ { NULL, NULL }, /* Fc */
{ NULL, NULL }, /* Oo */
{ NULL, NULL }, /* Oc */
- { NULL, posts_bk }, /* Bk */
+ { NULL, post_bk }, /* Bk */
{ NULL, NULL }, /* Ek */
- { NULL, posts_eoln }, /* Bt */
+ { NULL, post_eoln }, /* Bt */
{ NULL, NULL }, /* Hf */
- { NULL, NULL }, /* Fr */
- { NULL, posts_eoln }, /* Ud */
- { NULL, posts_lb }, /* Lb */
- { pres_pp, posts_pp }, /* Lp */
- { NULL, NULL }, /* Lk */
- { NULL, posts_defaults }, /* Mt */
- { NULL, NULL }, /* Brq */
- { NULL, NULL }, /* Bro */
- { NULL, NULL }, /* Brc */
- { NULL, posts_text }, /* %C */
- { NULL, NULL }, /* Es */
- { NULL, NULL }, /* En */
+ { pre_obsolete, NULL }, /* Fr */
+ { NULL, post_eoln }, /* Ud */
+ { NULL, post_lb }, /* Lb */
+ { pre_par, post_par }, /* Lp */
+ { NULL, NULL }, /* Lk */
+ { NULL, post_defaults }, /* Mt */
+ { NULL, NULL }, /* Brq */
+ { NULL, NULL }, /* Bro */
+ { NULL, NULL }, /* Brc */
+ { NULL, NULL }, /* %C */
+ { pre_obsolete, post_es }, /* Es */
+ { pre_obsolete, post_en }, /* En */
{ NULL, NULL }, /* Dx */
- { NULL, posts_text }, /* %Q */
- { NULL, posts_pp }, /* br */
- { NULL, posts_sp }, /* sp */
- { NULL, posts_text1 }, /* %U */
+ { NULL, NULL }, /* %Q */
+ { NULL, post_par }, /* br */
+ { NULL, post_par }, /* sp */
+ { NULL, NULL }, /* %U */
{ NULL, NULL }, /* Ta */
+ { NULL, NULL }, /* ll */
};
#define RSORD_MAX 14 /* Number of `Rs' blocks. */
@@ -331,6 +270,7 @@ static const char * const secnames[SEC__MAX] = {
"LIBRARY",
"SYNOPSIS",
"DESCRIPTION",
+ "CONTEXT",
"IMPLEMENTATION NOTES",
"RETURN VALUES",
"ENVIRONMENT",
@@ -350,169 +290,74 @@ static const char * const secnames[SEC__MAX] = {
NULL
};
-int
+
+void
mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n)
{
- v_pre *p;
- int line, pos;
- char *tp;
+ v_pre p;
switch (n->type) {
- case (MDOC_TEXT):
- tp = n->string;
- line = n->line;
- pos = n->pos;
- check_text(mdoc, line, pos, tp);
+ case MDOC_TEXT:
+ if (n->sec != SEC_SYNOPSIS || n->parent->tok != MDOC_Fd)
+ check_text(mdoc, n->line, n->pos, n->string);
/* FALLTHROUGH */
- case (MDOC_TBL):
+ case MDOC_TBL:
/* FALLTHROUGH */
- case (MDOC_EQN):
+ case MDOC_EQN:
/* FALLTHROUGH */
- case (MDOC_ROOT):
- return(1);
+ case MDOC_ROOT:
+ return;
default:
break;
}
check_args(mdoc, n);
-
- if (NULL == mdoc_valids[n->tok].pre)
- return(1);
- for (p = mdoc_valids[n->tok].pre; *p; p++)
- if ( ! (*p)(mdoc, n))
- return(0);
- return(1);
+ p = mdoc_valids[n->tok].pre;
+ if (*p)
+ (*p)(mdoc, n);
}
-
-int
+void
mdoc_valid_post(struct mdoc *mdoc)
{
- v_post *p;
+ struct mdoc_node *n;
+ v_post p;
- if (MDOC_VALID & mdoc->last->flags)
- return(1);
- mdoc->last->flags |= MDOC_VALID;
+ n = mdoc->last;
+ if (n->flags & MDOC_VALID)
+ return;
+ n->flags |= MDOC_VALID | MDOC_ENDED;
- switch (mdoc->last->type) {
- case (MDOC_TEXT):
+ switch (n->type) {
+ case MDOC_TEXT:
/* FALLTHROUGH */
- case (MDOC_EQN):
+ case MDOC_EQN:
/* FALLTHROUGH */
- case (MDOC_TBL):
- return(1);
- case (MDOC_ROOT):
- return(post_root(mdoc));
- default:
+ case MDOC_TBL:
break;
- }
-
- if (NULL == mdoc_valids[mdoc->last->tok].post)
- return(1);
- for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
- if ( ! (*p)(mdoc))
- return(0);
-
- return(1);
-}
-
-static int
-check_count(struct mdoc *mdoc, enum mdoc_type type,
- enum check_lvl lvl, enum check_ineq ineq, int val)
-{
- const char *p;
- enum mandocerr t;
-
- if (mdoc->last->type != type)
- return(1);
-
- switch (ineq) {
- case (CHECK_LT):
- p = "less than ";
- if (mdoc->last->nchild < val)
- return(1);
- break;
- case (CHECK_GT):
- p = "more than ";
- if (mdoc->last->nchild > val)
- return(1);
- break;
- case (CHECK_EQ):
- p = "";
- if (val == mdoc->last->nchild)
- return(1);
+ case MDOC_ROOT:
+ post_root(mdoc);
break;
default:
- abort();
- /* NOTREACHED */
- }
-
- t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT;
- mandoc_vmsg(t, mdoc->parse, mdoc->last->line, mdoc->last->pos,
- "want %s%d children (have %d)",
- p, val, mdoc->last->nchild);
- return(1);
-}
-
-static int
-berr_ge1(POST_ARGS)
-{
-
- return(check_count(mdoc, MDOC_BODY, CHECK_ERROR, CHECK_GT, 0));
-}
-
-static int
-bwarn_ge1(POST_ARGS)
-{
- return(check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0));
-}
-
-static int
-ewarn_eq0(POST_ARGS)
-{
- return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0));
-}
-
-static int
-ewarn_eq1(POST_ARGS)
-{
- return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1));
-}
-
-static int
-ewarn_ge1(POST_ARGS)
-{
- return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0));
-}
-static int
-ewarn_le1(POST_ARGS)
-{
- return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2));
-}
+ /*
+ * Closing delimiters are not special at the
+ * beginning of a block, opening delimiters
+ * are not special at the end.
+ */
-static int
-hwarn_eq0(POST_ARGS)
-{
- return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0));
-}
+ if (n->child != NULL)
+ n->child->flags &= ~MDOC_DELIMC;
+ if (n->last != NULL)
+ n->last->flags &= ~MDOC_DELIMO;
-static int
-hwarn_eq1(POST_ARGS)
-{
- return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 1));
-}
+ /* Call the macro's postprocessor. */
-static int
-hwarn_ge1(POST_ARGS)
-{
- return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_GT, 0));
-}
-
-static int
-hwarn_le1(POST_ARGS)
-{
- return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_LT, 2));
+ p = mdoc_valids[n->tok].post;
+ if (*p)
+ (*p)(mdoc);
+ break;
+ }
}
static void
@@ -535,12 +380,6 @@ check_argv(struct mdoc *mdoc, struct mdoc_node *n, struct mdoc_argv *v)
for (i = 0; i < (int)v->sz; i++)
check_text(mdoc, v->line, v->pos, v->value[i]);
-
- /* FIXME: move to post_std(). */
-
- if (MDOC_Std == v->arg)
- if ( ! (v->sz || mdoc->meta.name))
- mdoc_nmsg(mdoc, n, MANDOCERR_NONAME);
}
static void
@@ -552,188 +391,167 @@ check_text(struct mdoc *mdoc, int ln, int pos, char *p)
return;
for (cp = p; NULL != (p = strchr(p, '\t')); p++)
- mdoc_pmsg(mdoc, ln, pos + (int)(p - cp), MANDOCERR_BADTAB);
-}
-
-static int
-check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t)
-{
-
- assert(n->parent);
- if ((MDOC_ROOT == t || tok == n->parent->tok) &&
- (t == n->parent->type))
- return(1);
-
- mandoc_vmsg(MANDOCERR_SYNTCHILD, mdoc->parse, n->line,
- n->pos, "want parent %s", MDOC_ROOT == t ?
- "<root>" : mdoc_macronames[tok]);
- return(0);
+ mandoc_msg(MANDOCERR_FI_TAB, mdoc->parse,
+ ln, pos + (int)(p - cp), NULL);
}
-
-static int
+static void
pre_display(PRE_ARGS)
{
struct mdoc_node *node;
if (MDOC_BLOCK != n->type)
- return(1);
+ return;
- for (node = mdoc->last->parent; node; node = node->parent)
+ for (node = mdoc->last->parent; node; node = node->parent)
if (MDOC_BLOCK == node->type)
if (MDOC_Bd == node->tok)
break;
if (node)
- mdoc_nmsg(mdoc, n, MANDOCERR_NESTEDDISP);
-
- return(1);
+ mandoc_vmsg(MANDOCERR_BD_NEST,
+ mdoc->parse, n->line, n->pos,
+ "%s in Bd", mdoc_macronames[n->tok]);
}
-
-static int
+static void
pre_bl(PRE_ARGS)
{
- int i, comp, dup;
- const char *offs, *width;
+ struct mdoc_argv *argv, *wa;
+ int i;
+ enum mdocargt mdoclt;
enum mdoc_list lt;
- struct mdoc_node *np;
-
- if (MDOC_BLOCK != n->type) {
- if (ENDBODY_NOT != n->end) {
- assert(n->pending);
- np = n->pending->parent;
- } else
- np = n->parent;
- assert(np);
- assert(MDOC_BLOCK == np->type);
- assert(MDOC_Bl == np->tok);
- return(1);
- }
+ if (n->type != MDOC_BLOCK)
+ return;
- /*
+ /*
* First figure out which kind of list to use: bind ourselves to
* the first mentioned list type and warn about any remaining
* ones. If we find no list type, we default to LIST_item.
*/
- /* LINTED */
+ wa = (n->args == NULL) ? NULL : n->args->argv;
+ mdoclt = MDOC_ARG_MAX;
for (i = 0; n->args && i < (int)n->args->argc; i++) {
+ argv = n->args->argv + i;
lt = LIST__NONE;
- dup = comp = 0;
- width = offs = NULL;
- switch (n->args->argv[i].arg) {
+ switch (argv->arg) {
/* Set list types. */
- case (MDOC_Bullet):
+ case MDOC_Bullet:
lt = LIST_bullet;
break;
- case (MDOC_Dash):
+ case MDOC_Dash:
lt = LIST_dash;
break;
- case (MDOC_Enum):
+ case MDOC_Enum:
lt = LIST_enum;
break;
- case (MDOC_Hyphen):
+ case MDOC_Hyphen:
lt = LIST_hyphen;
break;
- case (MDOC_Item):
+ case MDOC_Item:
lt = LIST_item;
break;
- case (MDOC_Tag):
+ case MDOC_Tag:
lt = LIST_tag;
break;
- case (MDOC_Diag):
+ case MDOC_Diag:
lt = LIST_diag;
break;
- case (MDOC_Hang):
+ case MDOC_Hang:
lt = LIST_hang;
break;
- case (MDOC_Ohang):
+ case MDOC_Ohang:
lt = LIST_ohang;
break;
- case (MDOC_Inset):
+ case MDOC_Inset:
lt = LIST_inset;
break;
- case (MDOC_Column):
+ case MDOC_Column:
lt = LIST_column;
break;
/* Set list arguments. */
- case (MDOC_Compact):
- dup = n->norm->Bl.comp;
- comp = 1;
+ case MDOC_Compact:
+ if (n->norm->Bl.comp)
+ mandoc_msg(MANDOCERR_ARG_REP,
+ mdoc->parse, argv->line,
+ argv->pos, "Bl -compact");
+ n->norm->Bl.comp = 1;
break;
- case (MDOC_Width):
- /* NB: this can be empty! */
- if (n->args->argv[i].sz) {
- width = n->args->argv[i].value[0];
- dup = (NULL != n->norm->Bl.width);
+ case MDOC_Width:
+ wa = argv;
+ if (0 == argv->sz) {
+ mandoc_msg(MANDOCERR_ARG_EMPTY,
+ mdoc->parse, argv->line,
+ argv->pos, "Bl -width");
+ n->norm->Bl.width = "0n";
break;
}
- mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
+ if (NULL != n->norm->Bl.width)
+ mandoc_vmsg(MANDOCERR_ARG_REP,
+ mdoc->parse, argv->line,
+ argv->pos, "Bl -width %s",
+ argv->value[0]);
+ rewrite_macro2len(argv->value);
+ n->norm->Bl.width = argv->value[0];
break;
- case (MDOC_Offset):
- /* NB: this can be empty! */
- if (n->args->argv[i].sz) {
- offs = n->args->argv[i].value[0];
- dup = (NULL != n->norm->Bl.offs);
+ case MDOC_Offset:
+ if (0 == argv->sz) {
+ mandoc_msg(MANDOCERR_ARG_EMPTY,
+ mdoc->parse, argv->line,
+ argv->pos, "Bl -offset");
break;
}
- mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
+ if (NULL != n->norm->Bl.offs)
+ mandoc_vmsg(MANDOCERR_ARG_REP,
+ mdoc->parse, argv->line,
+ argv->pos, "Bl -offset %s",
+ argv->value[0]);
+ rewrite_macro2len(argv->value);
+ n->norm->Bl.offs = argv->value[0];
break;
default:
continue;
}
-
- /* Check: duplicate auxiliary arguments. */
-
- if (dup)
- mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP);
-
- if (comp && ! dup)
- n->norm->Bl.comp = comp;
- if (offs && ! dup)
- n->norm->Bl.offs = offs;
- if (width && ! dup)
- n->norm->Bl.width = width;
+ if (LIST__NONE == lt)
+ continue;
+ mdoclt = argv->arg;
/* Check: multiple list types. */
- if (LIST__NONE != lt && n->norm->Bl.type != LIST__NONE)
- mdoc_nmsg(mdoc, n, MANDOCERR_LISTREP);
-
- /* Assign list type. */
-
- if (LIST__NONE != lt && n->norm->Bl.type == LIST__NONE) {
- n->norm->Bl.type = lt;
- /* Set column information, too. */
- if (LIST_column == lt) {
- n->norm->Bl.ncols =
- n->args->argv[i].sz;
- n->norm->Bl.cols = (void *)
- n->args->argv[i].value;
- }
+ if (LIST__NONE != n->norm->Bl.type) {
+ mandoc_vmsg(MANDOCERR_BL_REP,
+ mdoc->parse, n->line, n->pos,
+ "Bl -%s", mdoc_argnames[argv->arg]);
+ continue;
}
/* The list type should come first. */
- if (n->norm->Bl.type == LIST__NONE)
- if (n->norm->Bl.width ||
- n->norm->Bl.offs ||
- n->norm->Bl.comp)
- mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST);
-
- continue;
+ if (n->norm->Bl.width ||
+ n->norm->Bl.offs ||
+ n->norm->Bl.comp)
+ mandoc_vmsg(MANDOCERR_BL_LATETYPE,
+ mdoc->parse, n->line, n->pos, "Bl -%s",
+ mdoc_argnames[n->args->argv[0].arg]);
+
+ n->norm->Bl.type = lt;
+ if (LIST_column == lt) {
+ n->norm->Bl.ncols = argv->sz;
+ n->norm->Bl.cols = (void *)argv->value;
+ }
}
/* Allow lists to default to LIST_item. */
if (LIST__NONE == n->norm->Bl.type) {
- mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE);
+ mandoc_msg(MANDOCERR_BL_NOTYPE, mdoc->parse,
+ n->line, n->pos, "Bl");
n->norm->Bl.type = LIST_item;
}
- /*
+ /*
* Validate the width field. Some list types don't need width
* types and should be warned about them. Others should have it
* and must also be warned. Yet others have a default and need
@@ -741,247 +559,216 @@ pre_bl(PRE_ARGS)
*/
switch (n->norm->Bl.type) {
- case (LIST_tag):
+ case LIST_tag:
if (NULL == n->norm->Bl.width)
- mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG);
+ mandoc_msg(MANDOCERR_BL_NOWIDTH, mdoc->parse,
+ n->line, n->pos, "Bl -tag");
break;
- case (LIST_column):
+ case LIST_column:
/* FALLTHROUGH */
- case (LIST_diag):
+ case LIST_diag:
/* FALLTHROUGH */
- case (LIST_ohang):
+ case LIST_ohang:
/* FALLTHROUGH */
- case (LIST_inset):
+ case LIST_inset:
/* FALLTHROUGH */
- case (LIST_item):
+ case LIST_item:
if (n->norm->Bl.width)
- mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
+ mandoc_vmsg(MANDOCERR_BL_SKIPW, mdoc->parse,
+ wa->line, wa->pos, "Bl -%s",
+ mdoc_argnames[mdoclt]);
break;
- case (LIST_bullet):
+ case LIST_bullet:
/* FALLTHROUGH */
- case (LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case (LIST_hyphen):
+ case LIST_hyphen:
if (NULL == n->norm->Bl.width)
n->norm->Bl.width = "2n";
break;
- case (LIST_enum):
+ case LIST_enum:
if (NULL == n->norm->Bl.width)
n->norm->Bl.width = "3n";
break;
default:
break;
}
-
- return(1);
+ pre_par(mdoc, n);
}
-
-static int
+static void
pre_bd(PRE_ARGS)
{
- int i, dup, comp;
- enum mdoc_disp dt;
- const char *offs;
- struct mdoc_node *np;
+ struct mdoc_argv *argv;
+ int i;
+ enum mdoc_disp dt;
- if (MDOC_BLOCK != n->type) {
- if (ENDBODY_NOT != n->end) {
- assert(n->pending);
- np = n->pending->parent;
- } else
- np = n->parent;
+ pre_literal(mdoc, n);
- assert(np);
- assert(MDOC_BLOCK == np->type);
- assert(MDOC_Bd == np->tok);
- return(1);
- }
+ if (n->type != MDOC_BLOCK)
+ return;
- /* LINTED */
for (i = 0; n->args && i < (int)n->args->argc; i++) {
+ argv = n->args->argv + i;
dt = DISP__NONE;
- dup = comp = 0;
- offs = NULL;
- switch (n->args->argv[i].arg) {
- case (MDOC_Centred):
- dt = DISP_centred;
+ switch (argv->arg) {
+ case MDOC_Centred:
+ dt = DISP_centered;
break;
- case (MDOC_Ragged):
+ case MDOC_Ragged:
dt = DISP_ragged;
break;
- case (MDOC_Unfilled):
+ case MDOC_Unfilled:
dt = DISP_unfilled;
break;
- case (MDOC_Filled):
+ case MDOC_Filled:
dt = DISP_filled;
break;
- case (MDOC_Literal):
+ case MDOC_Literal:
dt = DISP_literal;
break;
- case (MDOC_File):
- mdoc_nmsg(mdoc, n, MANDOCERR_BADDISP);
- return(0);
- case (MDOC_Offset):
- /* NB: this can be empty! */
- if (n->args->argv[i].sz) {
- offs = n->args->argv[i].value[0];
- dup = (NULL != n->norm->Bd.offs);
+ case MDOC_File:
+ mandoc_msg(MANDOCERR_BD_FILE, mdoc->parse,
+ n->line, n->pos, NULL);
+ break;
+ case MDOC_Offset:
+ if (0 == argv->sz) {
+ mandoc_msg(MANDOCERR_ARG_EMPTY,
+ mdoc->parse, argv->line,
+ argv->pos, "Bd -offset");
break;
}
- mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
+ if (NULL != n->norm->Bd.offs)
+ mandoc_vmsg(MANDOCERR_ARG_REP,
+ mdoc->parse, argv->line,
+ argv->pos, "Bd -offset %s",
+ argv->value[0]);
+ rewrite_macro2len(argv->value);
+ n->norm->Bd.offs = argv->value[0];
break;
- case (MDOC_Compact):
- comp = 1;
- dup = n->norm->Bd.comp;
+ case MDOC_Compact:
+ if (n->norm->Bd.comp)
+ mandoc_msg(MANDOCERR_ARG_REP,
+ mdoc->parse, argv->line,
+ argv->pos, "Bd -compact");
+ n->norm->Bd.comp = 1;
break;
default:
abort();
/* NOTREACHED */
}
+ if (DISP__NONE == dt)
+ continue;
- /* Check whether we have duplicates. */
-
- if (dup)
- mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP);
-
- /* Make our auxiliary assignments. */
-
- if (offs && ! dup)
- n->norm->Bd.offs = offs;
- if (comp && ! dup)
- n->norm->Bd.comp = comp;
-
- /* Check whether a type has already been assigned. */
-
- if (DISP__NONE != dt && n->norm->Bd.type != DISP__NONE)
- mdoc_nmsg(mdoc, n, MANDOCERR_DISPREP);
-
- /* Make our type assignment. */
-
- if (DISP__NONE != dt && n->norm->Bd.type == DISP__NONE)
+ if (DISP__NONE == n->norm->Bd.type)
n->norm->Bd.type = dt;
+ else
+ mandoc_vmsg(MANDOCERR_BD_REP,
+ mdoc->parse, n->line, n->pos,
+ "Bd -%s", mdoc_argnames[argv->arg]);
}
if (DISP__NONE == n->norm->Bd.type) {
- mdoc_nmsg(mdoc, n, MANDOCERR_DISPTYPE);
+ mandoc_msg(MANDOCERR_BD_NOTYPE, mdoc->parse,
+ n->line, n->pos, "Bd");
n->norm->Bd.type = DISP_ragged;
}
-
- return(1);
-}
-
-
-static int
-pre_ss(PRE_ARGS)
-{
-
- if (MDOC_BLOCK != n->type)
- return(1);
- return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY));
+ pre_par(mdoc, n);
}
-
-static int
-pre_sh(PRE_ARGS)
-{
-
- if (MDOC_BLOCK != n->type)
- return(1);
- return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT));
-}
-
-
-static int
-pre_it(PRE_ARGS)
-{
-
- if (MDOC_BLOCK != n->type)
- return(1);
-
- return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY));
-}
-
-
-static int
+static void
pre_an(PRE_ARGS)
{
- int i;
+ struct mdoc_argv *argv;
+ size_t i;
- if (NULL == n->args)
- return(1);
-
- for (i = 1; i < (int)n->args->argc; i++)
- mdoc_pmsg(mdoc, n->args->argv[i].line,
- n->args->argv[i].pos, MANDOCERR_IGNARGV);
+ if (n->args == NULL)
+ return;
- if (MDOC_Split == n->args->argv[0].arg)
+ for (i = 1; i < n->args->argc; i++) {
+ argv = n->args->argv + i;
+ mandoc_vmsg(MANDOCERR_AN_REP,
+ mdoc->parse, argv->line, argv->pos,
+ "An -%s", mdoc_argnames[argv->arg]);
+ }
+
+ argv = n->args->argv;
+ if (argv->arg == MDOC_Split)
n->norm->An.auth = AUTH_split;
- else if (MDOC_Nosplit == n->args->argv[0].arg)
+ else if (argv->arg == MDOC_Nosplit)
n->norm->An.auth = AUTH_nosplit;
else
abort();
-
- return(1);
}
-static int
+static void
pre_std(PRE_ARGS)
{
if (n->args && 1 == n->args->argc)
if (MDOC_Std == n->args->argv[0].arg)
- return(1);
+ return;
- mdoc_nmsg(mdoc, n, MANDOCERR_NOARGV);
- return(1);
+ mandoc_msg(MANDOCERR_ARG_STD, mdoc->parse,
+ n->line, n->pos, mdoc_macronames[n->tok]);
}
-static int
-pre_dt(PRE_ARGS)
+static void
+pre_obsolete(PRE_ARGS)
{
- if (NULL == mdoc->meta.date || mdoc->meta.os)
- mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO);
+ if (MDOC_ELEM == n->type || MDOC_BLOCK == n->type)
+ mandoc_msg(MANDOCERR_MACRO_OBS, mdoc->parse,
+ n->line, n->pos, mdoc_macronames[n->tok]);
+}
- if (mdoc->meta.title)
- mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP);
+static void
+pre_dt(PRE_ARGS)
+{
- return(1);
+ if (mdoc->meta.title != NULL)
+ mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
+ n->line, n->pos, "Dt");
+ else if (mdoc->meta.os != NULL)
+ mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
+ n->line, n->pos, "Dt after Os");
}
-static int
+static void
pre_os(PRE_ARGS)
{
- if (NULL == mdoc->meta.title || NULL == mdoc->meta.date)
- mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO);
-
- if (mdoc->meta.os)
- mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP);
-
- return(1);
+ if (mdoc->meta.os != NULL)
+ mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
+ n->line, n->pos, "Os");
+ else if (mdoc->flags & MDOC_PBODY)
+ mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse,
+ n->line, n->pos, "Os");
}
-static int
+static void
pre_dd(PRE_ARGS)
{
- if (mdoc->meta.title || mdoc->meta.os)
- mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO);
-
- if (mdoc->meta.date)
- mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP);
-
- return(1);
+ if (mdoc->meta.date != NULL)
+ mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
+ n->line, n->pos, "Dd");
+ else if (mdoc->flags & MDOC_PBODY)
+ mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse,
+ n->line, n->pos, "Dd");
+ else if (mdoc->meta.title != NULL)
+ mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
+ n->line, n->pos, "Dd after Dt");
+ else if (mdoc->meta.os != NULL)
+ mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
+ n->line, n->pos, "Dd after Os");
}
-
-static int
+static void
post_bf(POST_ARGS)
{
- struct mdoc_node *np;
+ struct mdoc_node *np, *nch;
enum mdocargt arg;
/*
@@ -989,40 +776,30 @@ post_bf(POST_ARGS)
* element, which contains the goods.
*/
- if (MDOC_HEAD != mdoc->last->type) {
- if (ENDBODY_NOT != mdoc->last->end) {
- assert(mdoc->last->pending);
- np = mdoc->last->pending->parent->head;
- } else if (MDOC_BLOCK != mdoc->last->type) {
- np = mdoc->last->parent->head;
- } else
- np = mdoc->last->head;
-
- assert(np);
- assert(MDOC_HEAD == np->type);
- assert(MDOC_Bf == np->tok);
- return(1);
- }
-
np = mdoc->last;
+ if (MDOC_HEAD != np->type)
+ return;
+
assert(MDOC_BLOCK == np->parent->type);
assert(MDOC_Bf == np->parent->tok);
- /*
- * Cannot have both argument and parameter.
- * If neither is specified, let it through with a warning.
- */
+ /* Check the number of arguments. */
- if (np->parent->args && np->child) {
- mdoc_nmsg(mdoc, np, MANDOCERR_SYNTARGVCOUNT);
- return(0);
- } else if (NULL == np->parent->args && NULL == np->child) {
- mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE);
- return(1);
+ nch = np->child;
+ if (NULL == np->parent->args) {
+ if (NULL == nch) {
+ mandoc_msg(MANDOCERR_BF_NOFONT, mdoc->parse,
+ np->line, np->pos, "Bf");
+ return;
+ }
+ nch = nch->next;
}
+ if (NULL != nch)
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
+ nch->line, nch->pos, "Bf ... %s", nch->string);
/* Extract argument into data. */
-
+
if (np->parent->args) {
arg = np->parent->args->argv[0].arg;
if (MDOC_Emphasis == arg)
@@ -1033,7 +810,7 @@ post_bf(POST_ARGS)
np->norm->Bf.font = FONT_Sy;
else
abort();
- return(1);
+ return;
}
/* Extract parameter into data. */
@@ -1044,57 +821,116 @@ post_bf(POST_ARGS)
np->norm->Bf.font = FONT_Li;
else if (0 == strcmp(np->child->string, "Sy"))
np->norm->Bf.font = FONT_Sy;
- else
- mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE);
-
- return(1);
+ else
+ mandoc_vmsg(MANDOCERR_BF_BADFONT, mdoc->parse,
+ np->child->line, np->child->pos,
+ "Bf %s", np->child->string);
}
-static int
+static void
post_lb(POST_ARGS)
{
- const char *p;
- char *buf;
- size_t sz;
+ struct mdoc_node *n;
+ const char *stdlibname;
+ char *libname;
- check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
+ n = mdoc->last->child;
+ assert(MDOC_TEXT == n->type);
- assert(mdoc->last->child);
- assert(MDOC_TEXT == mdoc->last->child->type);
+ if (NULL == (stdlibname = mdoc_a2lib(n->string)))
+ mandoc_asprintf(&libname,
+ "library \\(Lq%s\\(Rq", n->string);
+ else
+ libname = mandoc_strdup(stdlibname);
- p = mdoc_a2lib(mdoc->last->child->string);
+ free(n->string);
+ n->string = libname;
+}
- /* If lookup ok, replace with table value. */
+static void
+post_eoln(POST_ARGS)
+{
+ const struct mdoc_node *n;
- if (p) {
- free(mdoc->last->child->string);
- mdoc->last->child->string = mandoc_strdup(p);
- return(1);
- }
+ n = mdoc->last;
+ if (n->child)
+ mandoc_vmsg(MANDOCERR_ARG_SKIP,
+ mdoc->parse, n->line, n->pos,
+ "%s %s", mdoc_macronames[n->tok],
+ n->child->string);
+}
- /* If not, use "library ``xxxx''. */
+static void
+post_fname(POST_ARGS)
+{
+ const struct mdoc_node *n;
+ const char *cp;
+ size_t pos;
- sz = strlen(mdoc->last->child->string) +
- 2 + strlen("\\(lqlibrary\\(rq");
- buf = mandoc_malloc(sz);
- snprintf(buf, sz, "library \\(lq%s\\(rq",
- mdoc->last->child->string);
- free(mdoc->last->child->string);
- mdoc->last->child->string = buf;
- return(1);
+ n = mdoc->last->child;
+ pos = strcspn(n->string, "()");
+ cp = n->string + pos;
+ if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*')))
+ mandoc_msg(MANDOCERR_FN_PAREN, mdoc->parse,
+ n->line, n->pos + pos, n->string);
}
-static int
-post_eoln(POST_ARGS)
+static void
+post_fn(POST_ARGS)
{
- if (mdoc->last->child)
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST);
- return(1);
+ post_fname(mdoc);
+ post_fa(mdoc);
}
+static void
+post_fo(POST_ARGS)
+{
+ const struct mdoc_node *n;
-static int
+ n = mdoc->last;
+
+ if (n->type != MDOC_HEAD)
+ return;
+
+ if (n->child == NULL) {
+ mandoc_msg(MANDOCERR_FO_NOHEAD, mdoc->parse,
+ n->line, n->pos, "Fo");
+ return;
+ }
+ if (n->child != n->last) {
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
+ n->child->next->line, n->child->next->pos,
+ "Fo ... %s", n->child->next->string);
+ while (n->child != n->last)
+ mdoc_node_delete(mdoc, n->last);
+ }
+
+ post_fname(mdoc);
+}
+
+static void
+post_fa(POST_ARGS)
+{
+ const struct mdoc_node *n;
+ const char *cp;
+
+ for (n = mdoc->last->child; n != NULL; n = n->next) {
+ for (cp = n->string; *cp != '\0'; cp++) {
+ /* Ignore callbacks and alterations. */
+ if (*cp == '(' || *cp == '{')
+ break;
+ if (*cp != ',')
+ continue;
+ mandoc_msg(MANDOCERR_FA_COMMA, mdoc->parse,
+ n->line, n->pos + (cp - n->string),
+ n->string);
+ break;
+ }
+ }
+}
+
+static void
post_vt(POST_ARGS)
{
const struct mdoc_node *n;
@@ -1108,66 +944,93 @@ post_vt(POST_ARGS)
*/
if (MDOC_BODY != mdoc->last->type)
- return(1);
-
- for (n = mdoc->last->child; n; n = n->next)
- if (MDOC_TEXT != n->type)
- mdoc_nmsg(mdoc, n, MANDOCERR_CHILD);
+ return;
- return(1);
+ for (n = mdoc->last->child; n; n = n->next)
+ if (MDOC_TEXT != n->type)
+ mandoc_msg(MANDOCERR_VT_CHILD, mdoc->parse,
+ n->line, n->pos, mdoc_macronames[n->tok]);
}
-
-static int
+static void
post_nm(POST_ARGS)
{
- char buf[BUFSIZ];
- int c;
+ struct mdoc_node *n;
+
+ n = mdoc->last;
+
+ if (n->last != NULL &&
+ (n->last->tok == MDOC_Pp ||
+ n->last->tok == MDOC_Lp))
+ mdoc_node_relink(mdoc, n->last);
if (NULL != mdoc->meta.name)
- return(1);
+ return;
- /* Try to use our children for setting the meta name. */
+ mdoc_deroff(&mdoc->meta.name, n);
- if (NULL != mdoc->last->child) {
- buf[0] = '\0';
- c = concat(buf, mdoc->last->child, BUFSIZ);
- } else
- c = 0;
-
- switch (c) {
- case (-1):
- mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
- return(0);
- case (0):
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME);
- mdoc->meta.name = mandoc_strdup("UNKNOWN");
- break;
- default:
- mdoc->meta.name = mandoc_strdup(buf);
- break;
- }
- return(1);
+ if (NULL == mdoc->meta.name)
+ mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse,
+ n->line, n->pos, "Nm");
}
-static int
+static void
+post_nd(POST_ARGS)
+{
+ struct mdoc_node *n;
+
+ n = mdoc->last;
+
+ if (n->type != MDOC_BODY)
+ return;
+
+ if (n->child == NULL)
+ mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse,
+ n->line, n->pos, "Nd");
+
+ post_hyph(mdoc);
+}
+
+static void
+post_d1(POST_ARGS)
+{
+ struct mdoc_node *n;
+
+ n = mdoc->last;
+
+ if (n->type != MDOC_BODY)
+ return;
+
+ if (n->child == NULL)
+ mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
+ n->line, n->pos, "D1");
+
+ post_hyph(mdoc);
+}
+
+static void
post_literal(POST_ARGS)
{
-
- /*
- * The `Dl' (note "el" not "one") and `Bd' macros unset the
- * MDOC_LITERAL flag as they leave. Note that `Bd' only sets
- * this in literal mode, but it doesn't hurt to just switch it
- * off in general since displays can't be nested.
- */
+ struct mdoc_node *n;
+
+ n = mdoc->last;
+
+ if (n->type != MDOC_BODY)
+ return;
+
+ if (n->child == NULL)
+ mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
+ n->line, n->pos, mdoc_macronames[n->tok]);
- if (MDOC_BODY == mdoc->last->type)
- mdoc->flags &= ~MDOC_LITERAL;
+ if (n->tok == MDOC_Bd &&
+ n->norm->Bd.type != DISP_literal &&
+ n->norm->Bd.type != DISP_unfilled)
+ return;
- return(1);
+ mdoc->flags &= ~MDOC_LITERAL;
}
-static int
+static void
post_defaults(POST_ARGS)
{
struct mdoc_node *nn;
@@ -1179,178 +1042,163 @@ post_defaults(POST_ARGS)
*/
if (mdoc->last->child)
- return(1);
-
+ return;
+
nn = mdoc->last;
mdoc->next = MDOC_NEXT_CHILD;
switch (nn->tok) {
- case (MDOC_Ar):
- if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "file"))
- return(0);
- if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "..."))
- return(0);
- break;
- case (MDOC_At):
- if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "AT&T"))
- return(0);
- if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "UNIX"))
- return(0);
+ case MDOC_Ar:
+ mdoc_word_alloc(mdoc, nn->line, nn->pos, "file");
+ mdoc_word_alloc(mdoc, nn->line, nn->pos, "...");
break;
- case (MDOC_Li):
- if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, ""))
- return(0);
- break;
- case (MDOC_Pa):
+ case MDOC_Pa:
/* FALLTHROUGH */
- case (MDOC_Mt):
- if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "~"))
- return(0);
+ case MDOC_Mt:
+ mdoc_word_alloc(mdoc, nn->line, nn->pos, "~");
break;
default:
abort();
/* NOTREACHED */
- }
-
+ }
mdoc->last = nn;
- return(1);
}
-static int
+static void
post_at(POST_ARGS)
{
- const char *p, *q;
- char *buf;
- size_t sz;
+ struct mdoc_node *n;
+ const char *std_att;
+ char *att;
+
+ n = mdoc->last;
+ if (n->child == NULL) {
+ mdoc->next = MDOC_NEXT_CHILD;
+ mdoc_word_alloc(mdoc, n->line, n->pos, "AT&T UNIX");
+ mdoc->last = n;
+ return;
+ }
/*
* If we have a child, look it up in the standard keys. If a
* key exist, use that instead of the child; if it doesn't,
* prefix "AT&T UNIX " to the existing data.
*/
-
- if (NULL == mdoc->last->child)
- return(1);
- assert(MDOC_TEXT == mdoc->last->child->type);
- p = mdoc_a2att(mdoc->last->child->string);
-
- if (p) {
- free(mdoc->last->child->string);
- mdoc->last->child->string = mandoc_strdup(p);
- } else {
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADATT);
- p = "AT&T UNIX ";
- q = mdoc->last->child->string;
- sz = strlen(p) + strlen(q) + 1;
- buf = mandoc_malloc(sz);
- strlcpy(buf, p, sz);
- strlcat(buf, q, sz);
- free(mdoc->last->child->string);
- mdoc->last->child->string = buf;
- }
+ n = n->child;
+ assert(MDOC_TEXT == n->type);
+ if (NULL == (std_att = mdoc_a2att(n->string))) {
+ mandoc_vmsg(MANDOCERR_AT_BAD, mdoc->parse,
+ n->line, n->pos, "At %s", n->string);
+ mandoc_asprintf(&att, "AT&T UNIX %s", n->string);
+ } else
+ att = mandoc_strdup(std_att);
- return(1);
+ free(n->string);
+ n->string = att;
}
-static int
+static void
post_an(POST_ARGS)
{
- struct mdoc_node *np;
+ struct mdoc_node *np, *nch;
np = mdoc->last;
- if (AUTH__NONE == np->norm->An.auth) {
- if (0 == np->child)
- check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0);
- } else if (np->child)
- check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0);
+ nch = np->child;
+ if (np->norm->An.auth == AUTH__NONE) {
+ if (nch == NULL)
+ mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
+ np->line, np->pos, "An");
+ } else if (nch != NULL)
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
+ nch->line, nch->pos, "An ... %s", nch->string);
+}
+
+static void
+post_en(POST_ARGS)
+{
- return(1);
+ if (MDOC_BLOCK == mdoc->last->type)
+ mdoc->last->norm->Es = mdoc->last_es;
}
+static void
+post_es(POST_ARGS)
+{
-static int
+ mdoc->last_es = mdoc->last;
+}
+
+static void
post_it(POST_ARGS)
{
int i, cols;
enum mdoc_list lt;
- struct mdoc_node *n, *c;
- enum mandocerr er;
+ struct mdoc_node *nbl, *nit, *nch;
- if (MDOC_BLOCK != mdoc->last->type)
- return(1);
+ nit = mdoc->last;
+ if (nit->type != MDOC_BLOCK)
+ return;
- n = mdoc->last->parent->parent;
- lt = n->norm->Bl.type;
-
- if (LIST__NONE == lt) {
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_LISTTYPE);
- return(1);
- }
+ nbl = nit->parent->parent;
+ lt = nbl->norm->Bl.type;
switch (lt) {
- case (LIST_tag):
- if (mdoc->last->head->child)
- break;
- /* FIXME: give this a dummy value. */
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS);
- break;
- case (LIST_hang):
+ case LIST_tag:
+ /* FALLTHROUGH */
+ case LIST_hang:
/* FALLTHROUGH */
- case (LIST_ohang):
+ case LIST_ohang:
/* FALLTHROUGH */
- case (LIST_inset):
+ case LIST_inset:
/* FALLTHROUGH */
- case (LIST_diag):
- if (NULL == mdoc->last->head->child)
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS);
+ case LIST_diag:
+ if (nit->head->child == NULL)
+ mandoc_vmsg(MANDOCERR_IT_NOHEAD,
+ mdoc->parse, nit->line, nit->pos,
+ "Bl -%s It",
+ mdoc_argnames[nbl->args->argv[0].arg]);
break;
- case (LIST_bullet):
+ case LIST_bullet:
/* FALLTHROUGH */
- case (LIST_dash):
+ case LIST_dash:
/* FALLTHROUGH */
- case (LIST_enum):
+ case LIST_enum:
/* FALLTHROUGH */
- case (LIST_hyphen):
- if (NULL == mdoc->last->body->child)
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY);
+ case LIST_hyphen:
+ if (nit->body == NULL || nit->body->child == NULL)
+ mandoc_vmsg(MANDOCERR_IT_NOBODY,
+ mdoc->parse, nit->line, nit->pos,
+ "Bl -%s It",
+ mdoc_argnames[nbl->args->argv[0].arg]);
/* FALLTHROUGH */
- case (LIST_item):
- if (mdoc->last->head->child)
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST);
+ case LIST_item:
+ if (nit->head->child != NULL)
+ mandoc_vmsg(MANDOCERR_ARG_SKIP,
+ mdoc->parse, nit->line, nit->pos,
+ "It %s", nit->head->child->string);
break;
- case (LIST_column):
- cols = (int)n->norm->Bl.ncols;
-
- assert(NULL == mdoc->last->head->child);
+ case LIST_column:
+ cols = (int)nbl->norm->Bl.ncols;
- if (NULL == mdoc->last->body->child)
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY);
+ assert(nit->head->child == NULL);
- for (i = 0, c = mdoc->last->child; c; c = c->next)
- if (MDOC_BODY == c->type)
+ for (i = 0, nch = nit->child; nch; nch = nch->next)
+ if (nch->type == MDOC_BODY)
i++;
- if (i < cols)
- er = MANDOCERR_ARGCOUNT;
- else if (i == cols || i == cols + 1)
- break;
- else
- er = MANDOCERR_SYNTARGCOUNT;
-
- mandoc_vmsg(er, mdoc->parse, mdoc->last->line,
- mdoc->last->pos,
- "columns == %d (have %d)", cols, i);
- return(MANDOCERR_ARGCOUNT == er);
- default:
+ if (i < cols || i > cols + 1)
+ mandoc_vmsg(MANDOCERR_BL_COL,
+ mdoc->parse, nit->line, nit->pos,
+ "%d columns, %d cells", cols, i);
break;
+ default:
+ abort();
}
-
- return(1);
}
-static int
-post_bl_block(POST_ARGS)
+static void
+post_bl_block(POST_ARGS)
{
struct mdoc_node *n, *ni, *nc;
@@ -1364,14 +1212,9 @@ post_bl_block(POST_ARGS)
n = mdoc->last;
- if (LIST_tag == n->norm->Bl.type &&
- NULL == n->norm->Bl.width) {
- if ( ! post_bl_block_tag(mdoc))
- return(0);
- assert(n->norm->Bl.width);
- } else if (NULL != n->norm->Bl.width) {
- if ( ! post_bl_block_width(mdoc))
- return(0);
+ if (LIST_tag == n->norm->Bl.type &&
+ NULL == n->norm->Bl.width) {
+ post_bl_block_tag(mdoc);
assert(n->norm->Bl.width);
}
@@ -1381,93 +1224,71 @@ post_bl_block(POST_ARGS)
nc = ni->body->last;
while (NULL != nc) {
switch (nc->tok) {
- case (MDOC_Pp):
+ case MDOC_Pp:
/* FALLTHROUGH */
- case (MDOC_Lp):
+ case MDOC_Lp:
/* FALLTHROUGH */
- case (MDOC_br):
+ case MDOC_br:
break;
default:
nc = NULL;
continue;
}
if (NULL == ni->next) {
- mdoc_nmsg(mdoc, nc, MANDOCERR_MOVEPAR);
- if ( ! mdoc_node_relink(mdoc, nc))
- return(0);
+ mandoc_msg(MANDOCERR_PAR_MOVE,
+ mdoc->parse, nc->line, nc->pos,
+ mdoc_macronames[nc->tok]);
+ mdoc_node_relink(mdoc, nc);
} else if (0 == n->norm->Bl.comp &&
LIST_column != n->norm->Bl.type) {
- mdoc_nmsg(mdoc, nc, MANDOCERR_IGNPAR);
+ mandoc_vmsg(MANDOCERR_PAR_SKIP,
+ mdoc->parse, nc->line, nc->pos,
+ "%s before It",
+ mdoc_macronames[nc->tok]);
mdoc_node_delete(mdoc, nc);
} else
break;
nc = ni->body->last;
}
}
- return(1);
}
-static int
-post_bl_block_width(POST_ARGS)
+/*
+ * If the argument of -offset or -width is a macro,
+ * replace it with the associated default width.
+ */
+void
+rewrite_macro2len(char **arg)
{
size_t width;
- int i;
enum mdoct tok;
- struct mdoc_node *n;
- char buf[NUMSIZ];
-
- n = mdoc->last;
- /*
- * Calculate the real width of a list from the -width string,
- * which may contain a macro (with a known default width), a
- * literal string, or a scaling width.
- *
- * If the value to -width is a macro, then we re-write it to be
- * the macro's width as set in share/tmac/mdoc/doc-common.
- */
-
- if (0 == strcmp(n->norm->Bl.width, "Ds"))
+ if (*arg == NULL)
+ return;
+ else if ( ! strcmp(*arg, "Ds"))
width = 6;
- else if (MDOC_MAX == (tok = mdoc_hash_find(n->norm->Bl.width)))
- return(1);
- else if (0 == (width = macro2len(tok))) {
- mdoc_nmsg(mdoc, n, MANDOCERR_BADWIDTH);
- return(1);
- }
-
- /* The value already exists: free and reallocate it. */
-
- assert(n->args);
-
- for (i = 0; i < (int)n->args->argc; i++)
- if (MDOC_Width == n->args->argv[i].arg)
- break;
-
- assert(i < (int)n->args->argc);
-
- snprintf(buf, NUMSIZ, "%un", (unsigned int)width);
- free(n->args->argv[i].value[0]);
- n->args->argv[i].value[0] = mandoc_strdup(buf);
+ else if ((tok = mdoc_hash_find(*arg)) == MDOC_MAX)
+ return;
+ else
+ width = macro2len(tok);
- /* Set our width! */
- n->norm->Bl.width = n->args->argv[i].value[0];
- return(1);
+ free(*arg);
+ mandoc_asprintf(arg, "%zun", width);
}
-static int
+static void
post_bl_block_tag(POST_ARGS)
{
struct mdoc_node *n, *nn;
size_t sz, ssz;
int i;
- char buf[NUMSIZ];
+ char buf[24];
/*
* Calculate the -width for a `Bl -tag' list if it hasn't been
* provided. Uses the first head macro. NOTE AGAIN: this is
* ONLY if the -width argument has NOT been provided. See
- * post_bl_block_width() for converting the -width string.
+ * rewrite_macro2len() for converting the -width string.
*/
sz = 10;
@@ -1492,11 +1313,11 @@ post_bl_block_tag(POST_ARGS)
sz = ssz;
break;
- }
+ }
/* Defaults to ten ens. */
- snprintf(buf, NUMSIZ, "%un", (unsigned int)sz);
+ (void)snprintf(buf, sizeof(buf), "%un", (unsigned int)sz);
/*
* We have to dynamically add this to the macro's argument list.
@@ -1506,8 +1327,8 @@ post_bl_block_tag(POST_ARGS)
assert(n->args);
i = (int)(n->args->argc)++;
- n->args->argv = mandoc_realloc(n->args->argv,
- n->args->argc * sizeof(struct mdoc_argv));
+ n->args->argv = mandoc_reallocarray(n->args->argv,
+ n->args->argc, sizeof(struct mdoc_argv));
n->args->argv[i].arg = MDOC_Width;
n->args->argv[i].line = n->line;
@@ -1518,48 +1339,44 @@ post_bl_block_tag(POST_ARGS)
/* Set our width! */
n->norm->Bl.width = n->args->argv[i].value[0];
- return(1);
}
-
-static int
-post_bl_head(POST_ARGS)
+static void
+post_bl_head(POST_ARGS)
{
- struct mdoc_node *np, *nn, *nnp;
+ struct mdoc_node *nbl, *nh, *nch, *nnext;
+ struct mdoc_argv *argv;
int i, j;
- if (LIST_column != mdoc->last->norm->Bl.type)
- /* FIXME: this should be ERROR class... */
- return(hwarn_eq0(mdoc));
+ nh = mdoc->last;
+
+ if (nh->norm->Bl.type != LIST_column) {
+ if ((nch = nh->child) == NULL)
+ return;
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
+ nch->line, nch->pos, "Bl ... %s", nch->string);
+ while (nch != NULL) {
+ mdoc_node_delete(mdoc, nch);
+ nch = nh->child;
+ }
+ return;
+ }
/*
- * Convert old-style lists, where the column width specifiers
+ * Append old-style lists, where the column width specifiers
* trail as macro parameters, to the new-style ("normal-form")
* lists where they're argument values following -column.
*/
- /* First, disallow both types and allow normal-form. */
-
- /*
- * TODO: technically, we can accept both and just merge the two
- * lists, but I'll leave that for another day.
- */
-
- if (mdoc->last->norm->Bl.ncols && mdoc->last->nchild) {
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_COLUMNS);
- return(0);
- } else if (NULL == mdoc->last->child)
- return(1);
-
- np = mdoc->last->parent;
- assert(np->args);
+ if (nh->child == NULL)
+ return;
- for (j = 0; j < (int)np->args->argc; j++)
- if (MDOC_Column == np->args->argv[j].arg)
+ nbl = nh->parent;
+ for (j = 0; j < (int)nbl->args->argc; j++)
+ if (nbl->args->argv[j].arg == MDOC_Column)
break;
- assert(j < (int)np->args->argc);
- assert(0 == np->args->argv[j].sz);
+ assert(j < (int)nbl->args->argc);
/*
* Accommodate for new-style groff column syntax. Shuffle the
@@ -1567,28 +1384,26 @@ post_bl_head(POST_ARGS)
* column field. Then, delete the head children.
*/
- np->args->argv[j].sz = (size_t)mdoc->last->nchild;
- np->args->argv[j].value = mandoc_malloc
- ((size_t)mdoc->last->nchild * sizeof(char *));
+ argv = nbl->args->argv + j;
+ i = argv->sz;
+ argv->sz += nh->nchild;
+ argv->value = mandoc_reallocarray(argv->value,
+ argv->sz, sizeof(char *));
- mdoc->last->norm->Bl.ncols = np->args->argv[j].sz;
- mdoc->last->norm->Bl.cols = (void *)np->args->argv[j].value;
+ nh->norm->Bl.ncols = argv->sz;
+ nh->norm->Bl.cols = (void *)argv->value;
- for (i = 0, nn = mdoc->last->child; nn; i++) {
- np->args->argv[j].value[i] = nn->string;
- nn->string = NULL;
- nnp = nn;
- nn = nn->next;
- mdoc_node_delete(NULL, nnp);
+ for (nch = nh->child; nch != NULL; nch = nnext) {
+ argv->value[i++] = nch->string;
+ nch->string = NULL;
+ nnext = nch->next;
+ mdoc_node_delete(NULL, nch);
}
-
- mdoc->last->nchild = 0;
- mdoc->last->child = NULL;
-
- return(1);
+ nh->nchild = 0;
+ nh->child = NULL;
}
-static int
+static void
post_bl(POST_ARGS)
{
struct mdoc_node *nparent, *nprev; /* of the Bl block */
@@ -1597,24 +1412,36 @@ post_bl(POST_ARGS)
nbody = mdoc->last;
switch (nbody->type) {
- case (MDOC_BLOCK):
- return(post_bl_block(mdoc));
- case (MDOC_HEAD):
- return(post_bl_head(mdoc));
- case (MDOC_BODY):
+ case MDOC_BLOCK:
+ post_bl_block(mdoc);
+ return;
+ case MDOC_HEAD:
+ post_bl_head(mdoc);
+ return;
+ case MDOC_BODY:
break;
default:
- return(1);
+ return;
}
nchild = nbody->child;
- while (NULL != nchild) {
- if (MDOC_It == nchild->tok || MDOC_Sm == nchild->tok) {
+ if (nchild == NULL) {
+ mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
+ nbody->line, nbody->pos, "Bl");
+ return;
+ }
+ while (nchild != NULL) {
+ if (nchild->tok == MDOC_It ||
+ (nchild->tok == MDOC_Sm &&
+ nchild->next != NULL &&
+ nchild->next->tok == MDOC_It)) {
nchild = nchild->next;
continue;
}
- mdoc_nmsg(mdoc, nchild, MANDOCERR_CHILD);
+ mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse,
+ nchild->line, nchild->pos,
+ mdoc_macronames[nchild->tok]);
/*
* Move the node out of the Bl block.
@@ -1657,178 +1484,169 @@ post_bl(POST_ARGS)
nchild = nnext;
}
+}
- return(1);
+static void
+post_bk(POST_ARGS)
+{
+ struct mdoc_node *n;
+
+ n = mdoc->last;
+
+ if (n->type == MDOC_BLOCK && n->body->child == NULL) {
+ mandoc_msg(MANDOCERR_BLK_EMPTY,
+ mdoc->parse, n->line, n->pos, "Bk");
+ mdoc_node_delete(mdoc, n);
+ }
}
-static int
-ebool(struct mdoc *mdoc)
+static void
+post_sm(struct mdoc *mdoc)
{
+ struct mdoc_node *nch;
+
+ nch = mdoc->last->child;
- if (NULL == mdoc->last->child) {
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY);
- mdoc_node_delete(mdoc, mdoc->last);
- return(1);
+ if (nch == NULL) {
+ mdoc->flags ^= MDOC_SMOFF;
+ return;
}
- check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
- assert(MDOC_TEXT == mdoc->last->child->type);
+ assert(nch->type == MDOC_TEXT);
- if (0 == strcmp(mdoc->last->child->string, "on")) {
- if (MDOC_Sm == mdoc->last->tok)
- mdoc->flags &= ~MDOC_SMOFF;
- return(1);
+ if ( ! strcmp(nch->string, "on")) {
+ mdoc->flags &= ~MDOC_SMOFF;
+ return;
}
- if (0 == strcmp(mdoc->last->child->string, "off")) {
- if (MDOC_Sm == mdoc->last->tok)
- mdoc->flags |= MDOC_SMOFF;
- return(1);
+ if ( ! strcmp(nch->string, "off")) {
+ mdoc->flags |= MDOC_SMOFF;
+ return;
}
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL);
- return(1);
+ mandoc_vmsg(MANDOCERR_SM_BAD,
+ mdoc->parse, nch->line, nch->pos,
+ "%s %s", mdoc_macronames[mdoc->last->tok], nch->string);
+ mdoc_node_relink(mdoc, nch);
+ return;
}
-static int
+static void
post_root(POST_ARGS)
{
- int erc;
struct mdoc_node *n;
- erc = 0;
+ /* Add missing prologue data. */
- /* Check that we have a finished prologue. */
+ if (mdoc->meta.date == NULL)
+ mdoc->meta.date = mdoc->quick ?
+ mandoc_strdup("") :
+ mandoc_normdate(mdoc->parse, NULL, 0, 0);
- if ( ! (MDOC_PBODY & mdoc->flags)) {
- erc++;
- mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCPROLOG);
+ if (mdoc->meta.title == NULL) {
+ mandoc_msg(MANDOCERR_DT_NOTITLE,
+ mdoc->parse, 0, 0, "EOF");
+ mdoc->meta.title = mandoc_strdup("UNTITLED");
}
- n = mdoc->first;
- assert(n);
-
- /* Check that we begin with a proper `Sh'. */
+ if (mdoc->meta.vol == NULL)
+ mdoc->meta.vol = mandoc_strdup("LOCAL");
- if (NULL == n->child) {
- erc++;
- mdoc_nmsg(mdoc, n, MANDOCERR_NODOCBODY);
- } else if (MDOC_BLOCK != n->child->type ||
- MDOC_Sh != n->child->tok) {
- erc++;
- /* Can this be lifted? See rxdebug.1 for example. */
- mdoc_nmsg(mdoc, n, MANDOCERR_NODOCBODY);
+ if (mdoc->meta.os == NULL) {
+ mandoc_msg(MANDOCERR_OS_MISSING,
+ mdoc->parse, 0, 0, NULL);
+ mdoc->meta.os = mandoc_strdup("");
}
- return(erc ? 0 : 1);
+ /* Check that we begin with a proper `Sh'. */
+
+ n = mdoc->first->child;
+ while (n != NULL && mdoc_macros[n->tok].flags & MDOC_PROLOGUE)
+ n = n->next;
+
+ if (n == NULL)
+ 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]);
}
-static int
+static void
post_st(POST_ARGS)
{
- struct mdoc_node *ch;
+ struct mdoc_node *n, *nch;
const char *p;
- if (NULL == (ch = mdoc->last->child)) {
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY);
- mdoc_node_delete(mdoc, mdoc->last);
- return(1);
- }
+ n = mdoc->last;
+ nch = n->child;
- assert(MDOC_TEXT == ch->type);
+ assert(MDOC_TEXT == nch->type);
- if (NULL == (p = mdoc_a2st(ch->string))) {
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADSTANDARD);
- mdoc_node_delete(mdoc, mdoc->last);
+ if (NULL == (p = mdoc_a2st(nch->string))) {
+ mandoc_vmsg(MANDOCERR_ST_BAD, mdoc->parse,
+ nch->line, nch->pos, "St %s", nch->string);
+ mdoc_node_delete(mdoc, n);
} else {
- free(ch->string);
- ch->string = mandoc_strdup(p);
+ free(nch->string);
+ nch->string = mandoc_strdup(p);
}
-
- return(1);
}
-static int
+static void
post_rs(POST_ARGS)
{
- struct mdoc_node *nn, *next, *prev;
+ struct mdoc_node *np, *nch, *next, *prev;
int i, j;
- switch (mdoc->last->type) {
- case (MDOC_HEAD):
- check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0);
- return(1);
- case (MDOC_BODY):
- if (mdoc->last->child)
- break;
- check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0);
- return(1);
- default:
- return(1);
- }
-
- /*
- * Make sure only certain types of nodes are allowed within the
- * the `Rs' body. Delete offending nodes and raise a warning.
- * Do this before re-ordering for the sake of clarity.
- */
-
- next = NULL;
- for (nn = mdoc->last->child; nn; nn = next) {
- for (i = 0; i < RSORD_MAX; i++)
- if (nn->tok == rsord[i])
- break;
+ np = mdoc->last;
- if (i < RSORD_MAX) {
- if (MDOC__J == rsord[i] || MDOC__B == rsord[i])
- mdoc->last->norm->Rs.quote_T++;
- next = nn->next;
- continue;
- }
+ if (np->type != MDOC_BODY)
+ return;
- next = nn->next;
- mdoc_nmsg(mdoc, nn, MANDOCERR_CHILD);
- mdoc_node_delete(mdoc, nn);
+ if (np->child == NULL) {
+ mandoc_msg(MANDOCERR_RS_EMPTY, mdoc->parse,
+ np->line, np->pos, "Rs");
+ return;
}
/*
- * Nothing to sort if only invalid nodes were found
- * inside the `Rs' body.
- */
-
- if (NULL == mdoc->last->child)
- return(1);
-
- /*
* The full `Rs' block needs special handling to order the
* sub-elements according to `rsord'. Pick through each element
- * and correctly order it. This is a insertion sort.
+ * and correctly order it. This is an insertion sort.
*/
next = NULL;
- for (nn = mdoc->last->child->next; nn; nn = next) {
- /* Determine order of `nn'. */
+ for (nch = np->child->next; nch != NULL; nch = next) {
+ /* Determine order number of this child. */
for (i = 0; i < RSORD_MAX; i++)
- if (rsord[i] == nn->tok)
+ if (rsord[i] == nch->tok)
break;
- /*
- * Remove `nn' from the chain. This somewhat
+ if (i == RSORD_MAX) {
+ mandoc_msg(MANDOCERR_RS_BAD,
+ mdoc->parse, nch->line, nch->pos,
+ mdoc_macronames[nch->tok]);
+ i = -1;
+ } else if (nch->tok == MDOC__J || nch->tok == MDOC__B)
+ np->norm->Rs.quote_T++;
+
+ /*
+ * Remove this child from the chain. This somewhat
* repeats mdoc_node_unlink(), but since we're
* just re-ordering, there's no need for the
* full unlink process.
*/
-
- if (NULL != (next = nn->next))
- next->prev = nn->prev;
- if (NULL != (prev = nn->prev))
- prev->next = nn->next;
+ if ((next = nch->next) != NULL)
+ next->prev = nch->prev;
- nn->prev = nn->next = NULL;
+ if ((prev = nch->prev) != NULL)
+ prev->next = nch->next;
- /*
+ nch->prev = nch->next = NULL;
+
+ /*
* Scan back until we reach a node that's
- * ordered before `nn'.
+ * to be ordered before this child.
*/
for ( ; prev ; prev = prev->prev) {
@@ -1836,137 +1654,222 @@ post_rs(POST_ARGS)
for (j = 0; j < RSORD_MAX; j++)
if (rsord[j] == prev->tok)
break;
+ if (j == RSORD_MAX)
+ j = -1;
if (j <= i)
break;
}
/*
- * Set `nn' back into its correct place in front
- * of the `prev' node.
+ * Set this child back into its correct place
+ * in front of the `prev' node.
*/
- nn->prev = prev;
+ nch->prev = prev;
- if (prev) {
- if (prev->next)
- prev->next->prev = nn;
- nn->next = prev->next;
- prev->next = nn;
+ if (prev == NULL) {
+ np->child->prev = nch;
+ nch->next = np->child;
+ np->child = nch;
} else {
- mdoc->last->child->prev = nn;
- nn->next = mdoc->last->child;
- mdoc->last->child = nn;
+ if (prev->next)
+ prev->next->prev = nch;
+ nch->next = prev->next;
+ prev->next = nch;
}
}
-
- return(1);
}
/*
* For some arguments of some macros,
* convert all breakable hyphens into ASCII_HYPH.
*/
-static int
+static void
post_hyph(POST_ARGS)
{
- struct mdoc_node *n, *nch;
+ struct mdoc_node *nch;
char *cp;
- n = mdoc->last;
- switch (n->type) {
- case (MDOC_HEAD):
- if (MDOC_Sh == n->tok || MDOC_Ss == n->tok)
- break;
- return(1);
- case (MDOC_BODY):
- if (MDOC_D1 == n->tok || MDOC_Nd == n->tok)
- break;
- return(1);
- case (MDOC_ELEM):
- break;
- default:
- return(1);
- }
-
- for (nch = n->child; nch; nch = nch->next) {
- if (MDOC_TEXT != nch->type)
+ for (nch = mdoc->last->child; nch != NULL; nch = nch->next) {
+ if (nch->type != MDOC_TEXT)
continue;
cp = nch->string;
- if (3 > strnlen(cp, 3))
+ if (*cp == '\0')
continue;
- while ('\0' != *(++cp))
- if ('-' == *cp &&
+ while (*(++cp) != '\0')
+ if (*cp == '-' &&
isalpha((unsigned char)cp[-1]) &&
isalpha((unsigned char)cp[1]))
*cp = ASCII_HYPH;
}
- return(1);
}
-static int
+static void
post_ns(POST_ARGS)
{
if (MDOC_LINE & mdoc->last->flags)
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNNS);
- return(1);
+ mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse,
+ mdoc->last->line, mdoc->last->pos, NULL);
}
-static int
+static void
post_sh(POST_ARGS)
{
- if (MDOC_HEAD == mdoc->last->type)
- return(post_sh_head(mdoc));
- if (MDOC_BODY == mdoc->last->type)
- return(post_sh_body(mdoc));
+ post_ignpar(mdoc);
- return(1);
+ switch (mdoc->last->type) {
+ case MDOC_HEAD:
+ post_sh_head(mdoc);
+ break;
+ case MDOC_BODY:
+ switch (mdoc->lastsec) {
+ case SEC_NAME:
+ post_sh_name(mdoc);
+ break;
+ case SEC_SEE_ALSO:
+ post_sh_see_also(mdoc);
+ break;
+ case SEC_AUTHORS:
+ post_sh_authors(mdoc);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
}
-static int
-post_sh_body(POST_ARGS)
+static void
+post_sh_name(POST_ARGS)
{
struct mdoc_node *n;
+ int hasnm, hasnd;
- if (SEC_NAME != mdoc->lastsec)
- return(1);
-
- /*
- * Warn if the NAME section doesn't contain the `Nm' and `Nd'
- * macros (can have multiple `Nm' and one `Nd'). Note that the
- * children of the BODY declaration can also be "text".
- */
+ hasnm = hasnd = 0;
- if (NULL == (n = mdoc->last->child)) {
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC);
- return(1);
+ for (n = mdoc->last->child; n != NULL; n = n->next) {
+ switch (n->tok) {
+ case MDOC_Nm:
+ hasnm = 1;
+ break;
+ case MDOC_Nd:
+ hasnd = 1;
+ if (n->next != NULL)
+ mandoc_msg(MANDOCERR_NAMESEC_ND,
+ mdoc->parse, n->line, n->pos, NULL);
+ break;
+ case MDOC_MAX:
+ if (hasnm)
+ break;
+ /* FALLTHROUGH */
+ default:
+ mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
+ n->line, n->pos, mdoc_macronames[n->tok]);
+ break;
+ }
}
- for ( ; n && n->next; n = n->next) {
- if (MDOC_ELEM == n->type && MDOC_Nm == n->tok)
- continue;
- if (MDOC_TEXT == n->type)
+ if ( ! hasnm)
+ mandoc_msg(MANDOCERR_NAMESEC_NONM, mdoc->parse,
+ mdoc->last->line, mdoc->last->pos, NULL);
+ if ( ! hasnd)
+ mandoc_msg(MANDOCERR_NAMESEC_NOND, mdoc->parse,
+ mdoc->last->line, mdoc->last->pos, NULL);
+}
+
+static void
+post_sh_see_also(POST_ARGS)
+{
+ const struct mdoc_node *n;
+ const char *name, *sec;
+ const char *lastname, *lastsec, *lastpunct;
+ int cmp;
+
+ n = mdoc->last->child;
+ lastname = lastsec = lastpunct = NULL;
+ while (n != NULL) {
+ if (n->tok != MDOC_Xr || n->nchild < 2)
+ break;
+
+ /* Process one .Xr node. */
+
+ name = n->child->string;
+ sec = n->child->next->string;
+ if (lastsec != NULL) {
+ if (lastpunct[0] != ',' || lastpunct[1] != '\0')
+ mandoc_vmsg(MANDOCERR_XR_PUNCT,
+ mdoc->parse, n->line, n->pos,
+ "%s before %s(%s)", lastpunct,
+ name, sec);
+ cmp = strcmp(lastsec, sec);
+ if (cmp > 0)
+ mandoc_vmsg(MANDOCERR_XR_ORDER,
+ mdoc->parse, n->line, n->pos,
+ "%s(%s) after %s(%s)", name,
+ sec, lastname, lastsec);
+ else if (cmp == 0 &&
+ strcasecmp(lastname, name) > 0)
+ mandoc_vmsg(MANDOCERR_XR_ORDER,
+ mdoc->parse, n->line, n->pos,
+ "%s after %s", name, lastname);
+ }
+ lastname = name;
+ lastsec = sec;
+
+ /* Process the following node. */
+
+ n = n->next;
+ if (n == NULL)
+ break;
+ if (n->tok == MDOC_Xr) {
+ lastpunct = "none";
continue;
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC);
+ }
+ if (n->type != MDOC_TEXT)
+ break;
+ for (name = n->string; *name != '\0'; name++)
+ if (isalpha((const unsigned char)*name))
+ return;
+ lastpunct = n->string;
+ if (n->next == NULL)
+ mandoc_vmsg(MANDOCERR_XR_PUNCT, mdoc->parse,
+ n->line, n->pos, "%s after %s(%s)",
+ lastpunct, lastname, lastsec);
+ n = n->next;
}
+}
- assert(n);
- if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok)
- return(1);
+static int
+child_an(const struct mdoc_node *n)
+{
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC);
- return(1);
+ for (n = n->child; n != NULL; n = n->next)
+ if ((n->tok == MDOC_An && n->nchild) || child_an(n))
+ return(1);
+ return(0);
}
-static int
+static void
+post_sh_authors(POST_ARGS)
+{
+
+ if ( ! child_an(mdoc->last))
+ mandoc_msg(MANDOCERR_AN_MISSING, mdoc->parse,
+ mdoc->last->line, mdoc->last->pos, NULL);
+}
+
+static void
post_sh_head(POST_ARGS)
{
- char buf[BUFSIZ];
struct mdoc_node *n;
+ const char *goodsec;
+ char *secname;
enum mdoc_sec sec;
- int c;
/*
* Process a new section. Sections are either "named" or
@@ -1975,18 +1878,17 @@ post_sh_head(POST_ARGS)
* manual sections.
*/
+ secname = NULL;
sec = SEC_CUSTOM;
- buf[0] = '\0';
- if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) {
- mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
- return(0);
- } else if (1 == c)
- sec = a2sec(buf);
+ mdoc_deroff(&secname, mdoc->last);
+ sec = NULL == secname ? SEC_CUSTOM : a2sec(secname);
/* The NAME should be first. */
if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NAMESECFIRST);
+ mandoc_vmsg(MANDOCERR_NAMESEC_FIRST, mdoc->parse,
+ mdoc->last->line, mdoc->last->pos,
+ "Sh %s", secname);
/* The SYNOPSIS gets special attention in other areas. */
@@ -2018,8 +1920,10 @@ post_sh_head(POST_ARGS)
/* We don't care about custom sections after this. */
- if (SEC_CUSTOM == sec)
- return(1);
+ if (SEC_CUSTOM == sec) {
+ free(secname);
+ return;
+ }
/*
* Check whether our non-custom section is being repeated or is
@@ -2027,10 +1931,14 @@ post_sh_head(POST_ARGS)
*/
if (sec == mdoc->lastnamed)
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECREP);
+ mandoc_vmsg(MANDOCERR_SEC_REP, mdoc->parse,
+ mdoc->last->line, mdoc->last->pos,
+ "Sh %s", secname);
if (sec < mdoc->lastnamed)
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECOOO);
+ mandoc_vmsg(MANDOCERR_SEC_ORDER, mdoc->parse,
+ mdoc->last->line, mdoc->last->pos,
+ "Sh %s", secname);
/* Mark the last named section. */
@@ -2038,63 +1946,87 @@ post_sh_head(POST_ARGS)
/* Check particular section/manual conventions. */
- assert(mdoc->meta.msec);
+ if (mdoc->meta.msec == NULL) {
+ free(secname);
+ return;
+ }
+ goodsec = NULL;
switch (sec) {
- case (SEC_RETURN_VALUES):
+ case SEC_ERRORS:
+ if (*mdoc->meta.msec == '4')
+ break;
+ goodsec = "2, 3, 4, 9";
/* FALLTHROUGH */
- case (SEC_ERRORS):
+ case SEC_RETURN_VALUES:
/* FALLTHROUGH */
- case (SEC_LIBRARY):
+ case SEC_LIBRARY:
if (*mdoc->meta.msec == '2')
break;
if (*mdoc->meta.msec == '3')
break;
+ if (NULL == goodsec)
+ goodsec = "2, 3, 9";
+ /* FALLTHROUGH */
+ case SEC_CONTEXT:
if (*mdoc->meta.msec == '9')
break;
- mandoc_msg(MANDOCERR_SECMSEC, mdoc->parse,
- mdoc->last->line, mdoc->last->pos, buf);
+ if (NULL == goodsec)
+ goodsec = "9";
+ mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse,
+ mdoc->last->line, mdoc->last->pos,
+ "Sh %s for %s only", secname, goodsec);
break;
default:
break;
}
-
- return(1);
+ free(secname);
}
-static int
+static void
post_ignpar(POST_ARGS)
{
struct mdoc_node *np;
- if (MDOC_BODY != mdoc->last->type)
- return(1);
+ switch (mdoc->last->type) {
+ case MDOC_HEAD:
+ post_hyph(mdoc);
+ return;
+ case MDOC_BODY:
+ break;
+ default:
+ return;
+ }
if (NULL != (np = mdoc->last->child))
if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
- mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR);
+ mandoc_vmsg(MANDOCERR_PAR_SKIP,
+ mdoc->parse, np->line, np->pos,
+ "%s after %s", mdoc_macronames[np->tok],
+ mdoc_macronames[mdoc->last->tok]);
mdoc_node_delete(mdoc, np);
}
if (NULL != (np = mdoc->last->last))
if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
- mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR);
+ 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]);
mdoc_node_delete(mdoc, np);
}
-
- return(1);
}
-static int
+static void
pre_par(PRE_ARGS)
{
if (NULL == mdoc->last)
- return(1);
+ return;
if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type)
- return(1);
+ return;
- /*
+ /*
* Don't allow prior `Lp' or `Pp' prior to a paragraph-type
* block: `Lp', `Pp', or non-compact `Bd' or `Bl'.
*/
@@ -2102,51 +2034,62 @@ pre_par(PRE_ARGS)
if (MDOC_Pp != mdoc->last->tok &&
MDOC_Lp != mdoc->last->tok &&
MDOC_br != mdoc->last->tok)
- return(1);
+ return;
if (MDOC_Bl == n->tok && n->norm->Bl.comp)
- return(1);
+ return;
if (MDOC_Bd == n->tok && n->norm->Bd.comp)
- return(1);
+ return;
if (MDOC_It == n->tok && n->parent->norm->Bl.comp)
- return(1);
+ return;
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR);
+ mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
+ mdoc->last->line, mdoc->last->pos,
+ "%s before %s", mdoc_macronames[mdoc->last->tok],
+ mdoc_macronames[n->tok]);
mdoc_node_delete(mdoc, mdoc->last);
- return(1);
}
-static int
+static void
post_par(POST_ARGS)
{
+ struct mdoc_node *np;
- if (MDOC_ELEM != mdoc->last->type &&
- MDOC_BLOCK != mdoc->last->type)
- return(1);
+ np = mdoc->last;
- if (NULL == mdoc->last->prev) {
- if (MDOC_Sh != mdoc->last->parent->tok &&
- MDOC_Ss != mdoc->last->parent->tok)
- return(1);
- } else {
- if (MDOC_Pp != mdoc->last->prev->tok &&
- MDOC_Lp != mdoc->last->prev->tok &&
- (MDOC_br != mdoc->last->tok ||
- (MDOC_sp != mdoc->last->prev->tok &&
- MDOC_br != mdoc->last->prev->tok)))
- return(1);
- }
+ if (np->tok == MDOC_sp) {
+ if (np->nchild > 1)
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
+ np->child->next->line, np->child->next->pos,
+ "sp ... %s", np->child->next->string);
+ } 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);
+
+ if (NULL == (np = mdoc->last->prev)) {
+ np = mdoc->last->parent;
+ if (MDOC_Sh != np->tok && MDOC_Ss != np->tok)
+ return;
+ } else if (MDOC_Pp != np->tok && MDOC_Lp != np->tok &&
+ (MDOC_br != mdoc->last->tok ||
+ (MDOC_sp != np->tok && MDOC_br != np->tok)))
+ return;
- mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR);
+ 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_node_delete(mdoc, mdoc->last);
- return(1);
}
-static int
+static void
pre_literal(PRE_ARGS)
{
+ pre_display(mdoc, n);
+
if (MDOC_BODY != n->type)
- return(1);
+ return;
/*
* The `Dl' (note "el" not "one") and `Bd -literal' and `Bd
@@ -2154,10 +2097,10 @@ pre_literal(PRE_ARGS)
*/
switch (n->tok) {
- case (MDOC_Dl):
+ case MDOC_Dl:
mdoc->flags |= MDOC_LITERAL;
break;
- case (MDOC_Bd):
+ case MDOC_Bd:
if (DISP_literal == n->norm->Bd.type)
mdoc->flags |= MDOC_LITERAL;
if (DISP_unfilled == n->norm->Bd.type)
@@ -2167,41 +2110,38 @@ pre_literal(PRE_ARGS)
abort();
/* NOTREACHED */
}
-
- return(1);
}
-static int
+static void
post_dd(POST_ARGS)
{
- char buf[DATESIZE];
struct mdoc_node *n;
- int c;
+ char *datestr;
if (mdoc->meta.date)
free(mdoc->meta.date);
n = mdoc->last;
if (NULL == n->child || '\0' == n->child->string[0]) {
- mdoc->meta.date = mandoc_normdate
- (mdoc->parse, NULL, n->line, n->pos);
- return(1);
+ mdoc->meta.date = mdoc->quick ? mandoc_strdup("") :
+ mandoc_normdate(mdoc->parse, NULL, n->line, n->pos);
+ goto out;
}
- buf[0] = '\0';
- if (-1 == (c = concat(buf, n->child, DATESIZE))) {
- mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM);
- return(0);
+ datestr = NULL;
+ mdoc_deroff(&datestr, n);
+ if (mdoc->quick)
+ mdoc->meta.date = datestr;
+ else {
+ mdoc->meta.date = mandoc_normdate(mdoc->parse,
+ datestr, n->line, n->pos);
+ free(datestr);
}
-
- assert(c);
- mdoc->meta.date = mandoc_normdate
- (mdoc->parse, buf, n->line, n->pos);
-
- return(1);
+out:
+ mdoc_node_delete(mdoc, n);
}
-static int
+static void
post_dt(POST_ARGS)
{
struct mdoc_node *nn, *n;
@@ -2210,127 +2150,88 @@ post_dt(POST_ARGS)
n = mdoc->last;
- if (mdoc->meta.title)
- free(mdoc->meta.title);
- if (mdoc->meta.vol)
- free(mdoc->meta.vol);
- if (mdoc->meta.arch)
- free(mdoc->meta.arch);
+ free(mdoc->meta.title);
+ free(mdoc->meta.msec);
+ free(mdoc->meta.vol);
+ free(mdoc->meta.arch);
- mdoc->meta.title = mdoc->meta.vol = mdoc->meta.arch = NULL;
+ mdoc->meta.title = NULL;
+ mdoc->meta.msec = NULL;
+ mdoc->meta.vol = NULL;
+ mdoc->meta.arch = NULL;
- /* First make all characters uppercase. */
+ /* Mandatory first argument: title. */
- if (NULL != (nn = n->child))
- for (p = nn->string; *p; p++) {
- if (toupper((unsigned char)*p) == *p)
- continue;
-
- /*
- * FIXME: don't be lazy: have this make all
- * characters be uppercase and just warn once.
- */
- mdoc_nmsg(mdoc, nn, MANDOCERR_UPPERCASE);
- break;
- }
+ nn = n->child;
+ if (nn == NULL || *nn->string == '\0') {
+ mandoc_msg(MANDOCERR_DT_NOTITLE,
+ mdoc->parse, n->line, n->pos, "Dt");
+ mdoc->meta.title = mandoc_strdup("UNTITLED");
+ } else {
+ mdoc->meta.title = mandoc_strdup(nn->string);
- /* Handles: `.Dt'
- * --> title = unknown, volume = local, msec = 0, arch = NULL
- */
+ /* Check that all characters are uppercase. */
- if (NULL == (nn = n->child)) {
- /* XXX: make these macro values. */
- /* FIXME: warn about missing values. */
- mdoc->meta.title = mandoc_strdup("UNKNOWN");
- mdoc->meta.vol = mandoc_strdup("LOCAL");
- mdoc->meta.msec = mandoc_strdup("1");
- return(1);
+ for (p = nn->string; *p != '\0'; p++)
+ if (islower((unsigned char)*p)) {
+ mandoc_vmsg(MANDOCERR_TITLE_CASE,
+ mdoc->parse, nn->line,
+ nn->pos + (p - nn->string),
+ "Dt %s", nn->string);
+ break;
+ }
}
- /* Handles: `.Dt TITLE'
- * --> title = TITLE, volume = local, msec = 0, arch = NULL
- */
+ /* Mandatory second argument: section. */
- mdoc->meta.title = mandoc_strdup
- ('\0' == nn->string[0] ? "UNKNOWN" : nn->string);
+ if (nn != NULL)
+ nn = nn->next;
- if (NULL == (nn = nn->next)) {
- /* FIXME: warn about missing msec. */
- /* XXX: make this a macro value. */
+ if (nn == NULL) {
+ mandoc_vmsg(MANDOCERR_MSEC_MISSING,
+ mdoc->parse, n->line, n->pos,
+ "Dt %s", mdoc->meta.title);
mdoc->meta.vol = mandoc_strdup("LOCAL");
- mdoc->meta.msec = mandoc_strdup("1");
- return(1);
+ goto out; /* msec and arch remain NULL. */
}
- /* Handles: `.Dt TITLE SEC'
- * --> title = TITLE, volume = SEC is msec ?
- * format(msec) : SEC,
- * msec = SEC is msec ? atoi(msec) : 0,
- * arch = NULL
- */
+ mdoc->meta.msec = mandoc_strdup(nn->string);
+
+ /* Infer volume title from section number. */
cp = mandoc_a2msec(nn->string);
- if (cp) {
- mdoc->meta.vol = mandoc_strdup(cp);
- mdoc->meta.msec = mandoc_strdup(nn->string);
- } else {
- mdoc_nmsg(mdoc, n, MANDOCERR_BADMSEC);
+ if (cp == NULL) {
+ mandoc_vmsg(MANDOCERR_MSEC_BAD, mdoc->parse,
+ nn->line, nn->pos, "Dt ... %s", nn->string);
mdoc->meta.vol = mandoc_strdup(nn->string);
- mdoc->meta.msec = mandoc_strdup(nn->string);
- }
+ } else
+ mdoc->meta.vol = mandoc_strdup(cp);
- if (NULL == (nn = nn->next))
- return(1);
+ /* Optional third argument: architecture. */
- /* Handles: `.Dt TITLE SEC VOL'
- * --> title = TITLE, volume = VOL is vol ?
- * format(VOL) :
- * VOL is arch ? format(arch) :
- * VOL
- */
+ if ((nn = nn->next) == NULL)
+ goto out;
- cp = mdoc_a2vol(nn->string);
- if (cp) {
- free(mdoc->meta.vol);
- mdoc->meta.vol = mandoc_strdup(cp);
- } else {
- cp = mdoc_a2arch(nn->string);
- if (NULL == cp) {
- mdoc_nmsg(mdoc, nn, MANDOCERR_BADVOLARCH);
- free(mdoc->meta.vol);
- mdoc->meta.vol = mandoc_strdup(nn->string);
- } else
- mdoc->meta.arch = mandoc_strdup(cp);
- }
-
- /* Ignore any subsequent parameters... */
- /* FIXME: warn about subsequent parameters. */
-
- return(1);
-}
+ for (p = nn->string; *p != '\0'; p++)
+ *p = tolower((unsigned char)*p);
+ mdoc->meta.arch = mandoc_strdup(nn->string);
-static int
-post_prol(POST_ARGS)
-{
- /*
- * Remove prologue macros from the document after they're
- * processed. The final document uses mdoc_meta for these
- * values and discards the originals.
- */
+ /* Ignore fourth and later arguments. */
- mdoc_node_delete(mdoc, mdoc->last);
- if (mdoc->meta.title && mdoc->meta.date && mdoc->meta.os)
- mdoc->flags |= MDOC_PBODY;
+ if ((nn = nn->next) != NULL)
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
+ nn->line, nn->pos, "Dt ... %s", nn->string);
- return(1);
+out:
+ mdoc_node_delete(mdoc, n);
}
-static int
+static void
post_bx(POST_ARGS)
{
struct mdoc_node *n;
- /*
+ /*
* Make `Bx's second argument always start with an uppercase
* letter. Groff checks if it's an "accepted" term, but we just
* uppercase blindly.
@@ -2338,21 +2239,17 @@ post_bx(POST_ARGS)
n = mdoc->last->child;
if (n && NULL != (n = n->next))
- *n->string = (char)toupper
- ((unsigned char)*n->string);
-
- return(1);
+ *n->string = (char)toupper((unsigned char)*n->string);
}
-static int
+static void
post_os(POST_ARGS)
{
- struct mdoc_node *n;
- char buf[BUFSIZ];
- int c;
#ifndef OSNAME
struct utsname utsname;
+ static char *defbuf;
#endif
+ struct mdoc_node *n;
n = mdoc->last;
@@ -2363,112 +2260,69 @@ post_os(POST_ARGS)
* 2. the -Ios=foo command line argument, if provided
* 3. -DOSNAME="\"foo\"", if provided during compilation
* 4. "sysname release" from uname(3)
- */
+ */
free(mdoc->meta.os);
+ mdoc->meta.os = NULL;
+ mdoc_deroff(&mdoc->meta.os, n);
+ if (mdoc->meta.os)
+ goto out;
- buf[0] = '\0';
- if (-1 == (c = concat(buf, n->child, BUFSIZ))) {
- mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM);
- return(0);
+ if (mdoc->defos) {
+ mdoc->meta.os = mandoc_strdup(mdoc->defos);
+ goto out;
}
- assert(c);
-
- if ('\0' == buf[0]) {
- if (mdoc->defos) {
- mdoc->meta.os = mandoc_strdup(mdoc->defos);
- return(1);
- }
#ifdef OSNAME
- if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) {
- mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
- return(0);
- }
+ mdoc->meta.os = mandoc_strdup(OSNAME);
#else /*!OSNAME */
+ if (NULL == defbuf) {
if (-1 == uname(&utsname)) {
- mdoc_nmsg(mdoc, n, MANDOCERR_UNAME);
- mdoc->meta.os = mandoc_strdup("UNKNOWN");
- return(post_prol(mdoc));
- }
-
- if (strlcat(buf, utsname.sysname, BUFSIZ) >= BUFSIZ) {
- mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
- return(0);
- }
- if (strlcat(buf, " ", BUFSIZ) >= BUFSIZ) {
- mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
- return(0);
- }
- if (strlcat(buf, utsname.release, BUFSIZ) >= BUFSIZ) {
- mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
- return(0);
- }
-#endif /*!OSNAME*/
+ mandoc_msg(MANDOCERR_OS_UNAME, mdoc->parse,
+ n->line, n->pos, "Os");
+ defbuf = mandoc_strdup("UNKNOWN");
+ } else
+ mandoc_asprintf(&defbuf, "%s %s",
+ utsname.sysname, utsname.release);
}
+ mdoc->meta.os = mandoc_strdup(defbuf);
+#endif /*!OSNAME*/
- mdoc->meta.os = mandoc_strdup(buf);
- return(1);
+out:
+ mdoc_node_delete(mdoc, n);
}
-static int
-post_std(POST_ARGS)
+/*
+ * If no argument is provided,
+ * fill in the name of the current manual page.
+ */
+static void
+post_ex(POST_ARGS)
{
- struct mdoc_node *nn, *n;
+ struct mdoc_node *n;
n = mdoc->last;
- /*
- * Macros accepting `-std' as an argument have the name of the
- * current document (`Nm') filled in as the argument if it's not
- * provided.
- */
-
if (n->child)
- return(1);
-
- if (NULL == mdoc->meta.name)
- return(1);
-
- nn = n;
- mdoc->next = MDOC_NEXT_CHILD;
-
- if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name))
- return(0);
-
- mdoc->last = nn;
- return(1);
-}
-
-/*
- * Concatenate a node, stopping at the first non-text.
- * Concatenation is separated by a single whitespace.
- * Returns -1 on fatal (string overrun) error, 0 if child nodes were
- * encountered, 1 otherwise.
- */
-static int
-concat(char *p, const struct mdoc_node *n, size_t sz)
-{
+ return;
- for ( ; NULL != n; n = n->next) {
- if (MDOC_TEXT != n->type)
- return(0);
- if ('\0' != p[0] && strlcat(p, " ", sz) >= sz)
- return(-1);
- if (strlcat(p, n->string, sz) >= sz)
- return(-1);
- concat(p, n->child, sz);
+ if (mdoc->meta.name == NULL) {
+ mandoc_msg(MANDOCERR_EX_NONAME, mdoc->parse,
+ n->line, n->pos, "Ex");
+ return;
}
- return(1);
+ mdoc->next = MDOC_NEXT_CHILD;
+ mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name);
+ mdoc->last = n;
}
-static enum mdoc_sec
+static enum mdoc_sec
a2sec(const char *p)
{
int i;
- for (i = 0; i < (int)SEC__MAX; i++)
+ for (i = 0; i < (int)SEC__MAX; i++)
if (secnames[i] && 0 == strcmp(p, secnames[i]))
return((enum mdoc_sec)i);
@@ -2480,87 +2334,87 @@ macro2len(enum mdoct macro)
{
switch (macro) {
- case(MDOC_Ad):
+ case MDOC_Ad:
return(12);
- case(MDOC_Ao):
+ case MDOC_Ao:
return(12);
- case(MDOC_An):
+ case MDOC_An:
return(12);
- case(MDOC_Aq):
+ case MDOC_Aq:
return(12);
- case(MDOC_Ar):
+ case MDOC_Ar:
return(12);
- case(MDOC_Bo):
+ case MDOC_Bo:
return(12);
- case(MDOC_Bq):
+ case MDOC_Bq:
return(12);
- case(MDOC_Cd):
+ case MDOC_Cd:
return(12);
- case(MDOC_Cm):
+ case MDOC_Cm:
return(10);
- case(MDOC_Do):
+ case MDOC_Do:
return(10);
- case(MDOC_Dq):
+ case MDOC_Dq:
return(12);
- case(MDOC_Dv):
+ case MDOC_Dv:
return(12);
- case(MDOC_Eo):
+ case MDOC_Eo:
return(12);
- case(MDOC_Em):
+ case MDOC_Em:
return(10);
- case(MDOC_Er):
+ case MDOC_Er:
return(17);
- case(MDOC_Ev):
+ case MDOC_Ev:
return(15);
- case(MDOC_Fa):
+ case MDOC_Fa:
return(12);
- case(MDOC_Fl):
+ case MDOC_Fl:
return(10);
- case(MDOC_Fo):
+ case MDOC_Fo:
return(16);
- case(MDOC_Fn):
+ case MDOC_Fn:
return(16);
- case(MDOC_Ic):
+ case MDOC_Ic:
return(10);
- case(MDOC_Li):
+ case MDOC_Li:
return(16);
- case(MDOC_Ms):
+ case MDOC_Ms:
return(6);
- case(MDOC_Nm):
+ case MDOC_Nm:
return(10);
- case(MDOC_No):
+ case MDOC_No:
return(12);
- case(MDOC_Oo):
+ case MDOC_Oo:
return(10);
- case(MDOC_Op):
+ case MDOC_Op:
return(14);
- case(MDOC_Pa):
+ case MDOC_Pa:
return(32);
- case(MDOC_Pf):
+ case MDOC_Pf:
return(12);
- case(MDOC_Po):
+ case MDOC_Po:
return(12);
- case(MDOC_Pq):
+ case MDOC_Pq:
return(12);
- case(MDOC_Ql):
+ case MDOC_Ql:
return(16);
- case(MDOC_Qo):
+ case MDOC_Qo:
return(12);
- case(MDOC_So):
+ case MDOC_So:
return(12);
- case(MDOC_Sq):
+ case MDOC_Sq:
return(12);
- case(MDOC_Sy):
+ case MDOC_Sy:
return(6);
- case(MDOC_Sx):
+ case MDOC_Sx:
return(16);
- case(MDOC_Tn):
+ case MDOC_Tn:
return(10);
- case(MDOC_Va):
+ case MDOC_Va:
return(12);
- case(MDOC_Vt):
+ case MDOC_Vt:
return(12);
- case(MDOC_Xr):
+ case MDOC_Xr:
return(10);
default:
break;
diff --git a/usr/src/cmd/mandoc/msec.c b/usr/src/cmd/mandoc/msec.c
index dd7d11c650..d49d2975b6 100644
--- a/usr/src/cmd/mandoc/msec.c
+++ b/usr/src/cmd/mandoc/msec.c
@@ -1,4 +1,4 @@
-/* $Id: msec.c,v 1.10 2011/12/02 01:37:14 schwarze Exp $ */
+/* $Id: msec.c,v 1.14 2014/12/21 14:14:35 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -14,11 +14,10 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
-#include <stdlib.h>
+#include <sys/types.h>
+
#include <string.h>
#include "mandoc.h"
diff --git a/usr/src/cmd/mandoc/out.c b/usr/src/cmd/mandoc/out.c
index c931664977..53b93fbe00 100644
--- a/usr/src/cmd/mandoc/out.c
+++ b/usr/src/cmd/mandoc/out.c
@@ -1,7 +1,7 @@
-/* $Id: out.c,v 1.46 2013/10/05 20:30:05 schwarze Exp $ */
+/* $Id: out.c,v 1.59 2015/01/30 04:11:50 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 2014, 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
@@ -15,19 +15,16 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#include <sys/types.h>
#include <assert.h>
-#include <ctype.h>
-#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
+#include "mandoc_aux.h"
#include "mandoc.h"
#include "out.h"
@@ -38,98 +35,66 @@ static void tblcalc_literal(struct rofftbl *, struct roffcol *,
static void tblcalc_number(struct rofftbl *, struct roffcol *,
const struct tbl_opts *, const struct tbl_dat *);
-/*
- * Convert a `scaling unit' to a consistent form, or fail. Scaling
- * units are documented in groff.7, mdoc.7, man.7.
+
+/*
+ * 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.
*/
int
a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
{
- char buf[BUFSIZ], hasd;
- int i;
- enum roffscale unit;
+ char *endptr;
- if ('\0' == *src)
+ dst->unit = def == SCALE_MAX ? SCALE_BU : def;
+ dst->scale = strtod(src, &endptr);
+ if (endptr == src)
return(0);
- i = hasd = 0;
-
- switch (*src) {
- case ('+'):
- src++;
+ switch (*endptr++) {
+ case 'c':
+ dst->unit = SCALE_CM;
break;
- case ('-'):
- buf[i++] = *src++;
+ case 'i':
+ dst->unit = SCALE_IN;
break;
- default:
+ case 'f':
+ dst->unit = SCALE_FS;
break;
- }
-
- if ('\0' == *src)
- return(0);
-
- while (i < BUFSIZ) {
- if ( ! isdigit((unsigned char)*src)) {
- if ('.' != *src)
- break;
- else if (hasd)
- break;
- else
- hasd = 1;
- }
- buf[i++] = *src++;
- }
-
- if (BUFSIZ == i || (*src && *(src + 1)))
- return(0);
-
- buf[i] = '\0';
-
- switch (*src) {
- case ('c'):
- unit = SCALE_CM;
+ case 'M':
+ dst->unit = SCALE_MM;
break;
- case ('i'):
- unit = SCALE_IN;
+ case 'm':
+ dst->unit = SCALE_EM;
break;
- case ('P'):
- unit = SCALE_PC;
+ case 'n':
+ dst->unit = SCALE_EN;
break;
- case ('p'):
- unit = SCALE_PT;
+ case 'P':
+ dst->unit = SCALE_PC;
break;
- case ('f'):
- unit = SCALE_FS;
+ case 'p':
+ dst->unit = SCALE_PT;
break;
- case ('v'):
- unit = SCALE_VS;
+ case 'u':
+ dst->unit = SCALE_BU;
break;
- case ('m'):
- unit = SCALE_EM;
+ case 'v':
+ dst->unit = SCALE_VS;
break;
- case ('\0'):
+ case '\0':
+ endptr--;
+ /* FALLTHROUGH */
+ default:
if (SCALE_MAX == def)
return(0);
- unit = SCALE_BU;
- break;
- case ('u'):
- unit = SCALE_BU;
- break;
- case ('M'):
- unit = SCALE_MM;
+ dst->unit = def;
break;
- case ('n'):
- unit = SCALE_EN;
- break;
- default:
- return(0);
}
- /* FIXME: do this in the caller. */
- if ((dst->scale = atof(buf)) < 0)
- dst->scale = 0;
- dst->unit = unit;
- return(1);
+ return(*endptr == '\0' ? 2 : 1);
}
/*
@@ -139,11 +104,15 @@ a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
* used for the actual width calculations.
*/
void
-tblcalc(struct rofftbl *tbl, const struct tbl_span *sp)
+tblcalc(struct rofftbl *tbl, const struct tbl_span *sp,
+ size_t totalwidth)
{
+ const struct tbl_opts *opts;
const struct tbl_dat *dp;
struct roffcol *col;
+ size_t ewidth, xwidth;
int spans;
+ int icol, maxcol, necol, nxcol, quirkcol;
/*
* Allocate the master column specifiers. These will hold the
@@ -152,10 +121,11 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp)
*/
assert(NULL == tbl->cols);
- tbl->cols = mandoc_calloc
- ((size_t)sp->opts->cols, sizeof(struct roffcol));
+ tbl->cols = mandoc_calloc((size_t)sp->opts->cols,
+ sizeof(struct roffcol));
+ opts = sp->opts;
- for ( ; sp; sp = sp->next) {
+ for (maxcol = -1; sp; sp = sp->next) {
if (TBL_SPAN_DATA != sp->pos)
continue;
spans = 1;
@@ -170,9 +140,92 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp)
spans = dp->spans;
if (1 < spans)
continue;
- assert(dp->layout);
- col = &tbl->cols[dp->layout->head->ident];
- tblcalc_data(tbl, col, sp->opts, dp);
+ icol = dp->layout->col;
+ if (maxcol < icol)
+ maxcol = icol;
+ col = tbl->cols + icol;
+ col->flags |= dp->layout->flags;
+ if (dp->layout->flags & TBL_CELL_WIGN)
+ continue;
+ tblcalc_data(tbl, col, opts, dp);
+ }
+ }
+
+ /*
+ * Count columns to equalize and columns to maximize.
+ * Find maximum width of the columns to equalize.
+ * Find total width of the columns *not* to maximize.
+ */
+
+ necol = nxcol = 0;
+ ewidth = xwidth = 0;
+ for (icol = 0; icol <= maxcol; icol++) {
+ col = tbl->cols + icol;
+ if (col->flags & TBL_CELL_EQUAL) {
+ necol++;
+ if (ewidth < col->width)
+ ewidth = col->width;
+ }
+ if (col->flags & TBL_CELL_WMAX)
+ nxcol++;
+ else
+ xwidth += col->width;
+ }
+
+ /*
+ * Equalize columns, if requested for any of them.
+ * Update total width of the columns not to maximize.
+ */
+
+ if (necol) {
+ for (icol = 0; icol <= maxcol; icol++) {
+ col = tbl->cols + icol;
+ if ( ! (col->flags & TBL_CELL_EQUAL))
+ continue;
+ if (col->width == ewidth)
+ continue;
+ if (nxcol && totalwidth)
+ xwidth += ewidth - col->width;
+ col->width = ewidth;
+ }
+ }
+
+ /*
+ * If there are any columns to maximize, find the total
+ * available width, deducting 3n margins between columns.
+ * Distribute the available width evenly.
+ */
+
+ if (nxcol && totalwidth) {
+ xwidth = totalwidth - xwidth - 3*maxcol -
+ (opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX) ?
+ 2 : !!opts->lvert + !!opts->rvert);
+
+ /*
+ * Emulate a bug in GNU tbl width calculation that
+ * manifests itself for large numbers of x-columns.
+ * Emulating it for 5 x-columns gives identical
+ * behaviour for up to 6 x-columns.
+ */
+
+ if (nxcol == 5) {
+ quirkcol = xwidth % nxcol + 2;
+ if (quirkcol != 3 && quirkcol != 4)
+ quirkcol = -1;
+ } else
+ quirkcol = -1;
+
+ necol = 0;
+ ewidth = 0;
+ for (icol = 0; icol <= maxcol; icol++) {
+ col = tbl->cols + icol;
+ if ( ! (col->flags & TBL_CELL_WMAX))
+ continue;
+ col->width = (double)xwidth * ++necol / nxcol
+ - ewidth + 0.4995;
+ if (necol == quirkcol)
+ col->width--;
+ ewidth += col->width;
}
}
}
@@ -186,26 +239,26 @@ tblcalc_data(struct rofftbl *tbl, struct roffcol *col,
/* Branch down into data sub-types. */
switch (dp->layout->pos) {
- case (TBL_CELL_HORIZ):
+ case TBL_CELL_HORIZ:
/* FALLTHROUGH */
- case (TBL_CELL_DHORIZ):
+ case TBL_CELL_DHORIZ:
sz = (*tbl->len)(1, tbl->arg);
if (col->width < sz)
col->width = sz;
break;
- case (TBL_CELL_LONG):
+ case TBL_CELL_LONG:
/* FALLTHROUGH */
- case (TBL_CELL_CENTRE):
+ case TBL_CELL_CENTRE:
/* FALLTHROUGH */
- case (TBL_CELL_LEFT):
+ case TBL_CELL_LEFT:
/* FALLTHROUGH */
- case (TBL_CELL_RIGHT):
+ case TBL_CELL_RIGHT:
tblcalc_literal(tbl, col, dp);
break;
- case (TBL_CELL_NUMBER):
+ case TBL_CELL_NUMBER:
tblcalc_number(tbl, col, opts, dp);
break;
- case (TBL_CELL_DOWN):
+ case TBL_CELL_DOWN:
break;
default:
abort();
@@ -231,7 +284,7 @@ static void
tblcalc_number(struct rofftbl *tbl, struct roffcol *col,
const struct tbl_opts *opts, const struct tbl_dat *dp)
{
- int i;
+ int i;
size_t sz, psz, ssz, d;
const char *str;
char *cp;
diff --git a/usr/src/cmd/mandoc/out.h b/usr/src/cmd/mandoc/out.h
index 1c18c6c314..cc218f4fec 100644
--- a/usr/src/cmd/mandoc/out.h
+++ b/usr/src/cmd/mandoc/out.h
@@ -1,4 +1,4 @@
-/* $Id: out.h,v 1.21 2011/07/17 15:24:25 kristaps Exp $ */
+/* $Id: out.h,v 1.26 2014/12/01 08:05:52 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -14,8 +14,6 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef OUT_H
-#define OUT_H
enum roffscale {
SCALE_CM, /* centimeters (c) */
@@ -34,6 +32,7 @@ enum roffscale {
struct roffcol {
size_t width; /* width of cell */
size_t decimal; /* decimal position in cell */
+ int flags; /* layout flags, see tbl_cell */
};
struct roffsu {
@@ -51,21 +50,22 @@ struct rofftbl {
void *arg; /* passed to slen and len */
};
-__BEGIN_DECLS
-
#define SCALE_VS_INIT(p, v) \
do { (p)->unit = SCALE_VS; \
(p)->scale = (v); } \
while (/* CONSTCOND */ 0)
#define SCALE_HS_INIT(p, v) \
- do { (p)->unit = SCALE_BU; \
+ do { (p)->unit = SCALE_EN; \
(p)->scale = (v); } \
while (/* CONSTCOND */ 0)
-int a2roffsu(const char *, struct roffsu *, enum roffscale);
-void tblcalc(struct rofftbl *tbl, const struct tbl_span *);
+__BEGIN_DECLS
+
+struct tbl_span;
-__END_DECLS
+int a2roffsu(const char *, struct roffsu *, enum roffscale);
+void tblcalc(struct rofftbl *tbl,
+ const struct tbl_span *, size_t);
-#endif /*!OUT_H*/
+__END_DECLS
diff --git a/usr/src/cmd/mandoc/preconv.c b/usr/src/cmd/mandoc/preconv.c
index 7595887dd2..87e65ea0c6 100644
--- a/usr/src/cmd/mandoc/preconv.c
+++ b/usr/src/cmd/mandoc/preconv.c
@@ -1,6 +1,7 @@
-/* $Id: preconv.c,v 1.6 2013/06/02 03:52:21 schwarze Exp $ */
+/* $Id: preconv.c,v 1.14 2015/03/06 09:24:59 kristaps Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014 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,325 +15,115 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
-#ifdef HAVE_MMAP
-#include <sys/stat.h>
-#include <sys/mman.h>
-#endif
+#include <sys/types.h>
#include <assert.h>
-#include <fcntl.h>
#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
+#include "mandoc.h"
+#include "libmandoc.h"
-/*
- * The read_whole_file() and resize_buf() functions are copied from
- * read.c, including all dependency code.
- */
-
-enum enc {
- ENC_UTF_8, /* UTF-8 */
- ENC_US_ASCII, /* US-ASCII */
- ENC_LATIN_1, /* Latin-1 */
- ENC__MAX
-};
-
-struct buf {
- char *buf; /* binary input buffer */
- size_t sz; /* size of binary buffer */
- size_t offs; /* starting buffer offset */
-};
-
-struct encode {
- const char *name;
- int (*conv)(const struct buf *);
-};
-
-static int cue_enc(const struct buf *, size_t *, enum enc *);
-static int conv_latin_1(const struct buf *);
-static int conv_us_ascii(const struct buf *);
-static int conv_utf_8(const struct buf *);
-static int read_whole_file(const char *, int,
- struct buf *, int *);
-static void resize_buf(struct buf *, size_t);
-static void usage(void);
-
-static const struct encode encs[ENC__MAX] = {
- { "utf-8", conv_utf_8 }, /* ENC_UTF_8 */
- { "us-ascii", conv_us_ascii }, /* ENC_US_ASCII */
- { "latin-1", conv_latin_1 }, /* ENC_LATIN_1 */
-};
-
-static const char *progname;
-
-static void
-usage(void)
-{
-
- fprintf(stderr, "usage: %s "
- "[-D enc] "
- "[-e ENC] "
- "[file]\n", progname);
-}
-
-static int
-conv_latin_1(const struct buf *b)
-{
- size_t i;
- unsigned char cu;
- const char *cp;
-
- cp = b->buf + (int)b->offs;
-
- /*
- * Latin-1 falls into the first 256 code-points of Unicode, so
- * there's no need for any sort of translation. Just make the
- * 8-bit characters use the Unicode escape.
- * Note that binary values 128 < v < 160 are passed through
- * unmodified to mandoc.
- */
-
- for (i = b->offs; i < b->sz; i++) {
- cu = (unsigned char)*cp++;
- cu < 160U ? putchar(cu) : printf("\\[u%.4X]", cu);
- }
-
- return(1);
-}
-
-static int
-conv_us_ascii(const struct buf *b)
-{
-
- /*
- * US-ASCII has no conversion since it falls into the first 128
- * bytes of Unicode.
- */
-
- fwrite(b->buf, 1, b->sz, stdout);
- return(1);
-}
-
-static int
-conv_utf_8(const struct buf *b)
+int
+preconv_encode(struct buf *ib, size_t *ii, struct buf *ob, size_t *oi,
+ int *filenc)
{
- int state, be;
+ unsigned char *cu;
+ int nby;
unsigned int accum;
- size_t i;
- unsigned char cu;
- const char *cp;
- const long one = 1L;
-
- cp = b->buf + (int)b->offs;
- state = 0;
- accum = 0U;
- be = 0;
-
- /* Quick test for big-endian value. */
-
- if ( ! (*((const char *)(&one))))
- be = 1;
-
- for (i = b->offs; i < b->sz; i++) {
- cu = (unsigned char)*cp++;
- if (state) {
- if ( ! (cu & 128) || (cu & 64)) {
- /* Bad sequence header. */
- return(0);
- }
-
- /* Accept only legitimate bit patterns. */
-
- if (cu > 191 || cu < 128) {
- /* Bad in-sequence bits. */
- return(0);
- }
-
- accum |= (cu & 63) << --state * 6;
-
- /*
- * Accum is held in little-endian order as
- * stipulated by the UTF-8 sequence coding. We
- * need to convert to a native big-endian if our
- * architecture requires it.
- */
-
- if (0 == state && be)
- accum = (accum >> 24) |
- ((accum << 8) & 0x00FF0000) |
- ((accum >> 8) & 0x0000FF00) |
- (accum << 24);
-
- if (0 == state) {
- accum < 128U ? putchar(accum) :
- printf("\\[u%.4X]", accum);
- accum = 0U;
- }
- } else if (cu & (1 << 7)) {
- /*
- * Entering a UTF-8 state: if we encounter a
- * UTF-8 bitmask, calculate the expected UTF-8
- * state from it.
- */
- for (state = 0; state < 7; state++)
- if ( ! (cu & (1 << (7 - state))))
- break;
-
- /* Accept only legitimate bit patterns. */
- switch (state) {
- case (4):
- if (cu <= 244 && cu >= 240) {
- accum = (cu & 7) << 18;
- break;
- }
- /* Bad 4-sequence start bits. */
- return(0);
- case (3):
- if (cu <= 239 && cu >= 224) {
- accum = (cu & 15) << 12;
- break;
- }
- /* Bad 3-sequence start bits. */
- return(0);
- case (2):
- if (cu <= 223 && cu >= 194) {
- accum = (cu & 31) << 6;
- break;
- }
- /* Bad 2-sequence start bits. */
- return(0);
- default:
- /* Bad sequence bit mask. */
- return(0);
- }
- state--;
- } else
- putchar(cu);
+ cu = (unsigned char *)ib->buf + *ii;
+ assert(*cu & 0x80);
+
+ if ( ! (*filenc & MPARSE_UTF8))
+ goto latin;
+
+ nby = 1;
+ while (nby < 5 && *cu & (1 << (7 - nby)))
+ nby++;
+
+ switch (nby) {
+ case 2:
+ accum = *cu & 0x1f;
+ if (accum < 0x02) /* Obfuscated ASCII. */
+ goto latin;
+ break;
+ case 3:
+ accum = *cu & 0x0f;
+ break;
+ case 4:
+ accum = *cu & 0x07;
+ if (accum > 0x04) /* Beyond Unicode. */
+ goto latin;
+ break;
+ default: /* Bad sequence header. */
+ goto latin;
}
- if (0 != state) {
- /* Bad trailing bits. */
- return(0);
+ cu++;
+ switch (nby) {
+ case 3:
+ if ((accum == 0x00 && ! (*cu & 0x20)) || /* Use 2-byte. */
+ (accum == 0x0d && *cu & 0x20)) /* Surrogates. */
+ goto latin;
+ break;
+ case 4:
+ if ((accum == 0x00 && ! (*cu & 0x30)) || /* Use 3-byte. */
+ (accum == 0x04 && *cu & 0x30)) /* Beyond Unicode. */
+ goto latin;
+ break;
+ default:
+ break;
}
- return(1);
-}
-
-static void
-resize_buf(struct buf *buf, size_t initial)
-{
-
- buf->sz = buf->sz > initial / 2 ?
- 2 * buf->sz : initial;
-
- buf->buf = realloc(buf->buf, buf->sz);
- if (NULL == buf->buf) {
- perror(NULL);
- exit(EXIT_FAILURE);
+ while (--nby) {
+ if ((*cu & 0xc0) != 0x80) /* Invalid continuation. */
+ goto latin;
+ accum <<= 6;
+ accum += *cu & 0x3f;
+ cu++;
}
-}
-
-static int
-read_whole_file(const char *f, int fd,
- struct buf *fb, int *with_mmap)
-{
- size_t off;
- ssize_t ssz;
-#ifdef HAVE_MMAP
- struct stat st;
- if (-1 == fstat(fd, &st)) {
- perror(f);
- return(0);
- }
+ assert(accum > 0x7f);
+ assert(accum < 0x110000);
+ assert(accum < 0xd800 || accum > 0xdfff);
- /*
- * If we're a regular file, try just reading in the whole entry
- * via mmap(). This is faster than reading it into blocks, and
- * since each file is only a few bytes to begin with, I'm not
- * concerned that this is going to tank any machines.
- */
+ *oi += snprintf(ob->buf + *oi, 11, "\\[u%.4X]", accum);
+ *ii = (char *)cu - ib->buf;
+ *filenc &= ~MPARSE_LATIN1;
+ return(1);
- if (S_ISREG(st.st_mode) && st.st_size >= (1U << 31)) {
- fprintf(stderr, "%s: input too large\n", f);
+latin:
+ if ( ! (*filenc & MPARSE_LATIN1))
return(0);
- }
-
- if (S_ISREG(st.st_mode)) {
- *with_mmap = 1;
- fb->sz = (size_t)st.st_size;
- fb->buf = mmap(NULL, fb->sz, PROT_READ, MAP_SHARED, fd, 0);
- if (fb->buf != MAP_FAILED)
- return(1);
- }
-#endif
- /*
- * If this isn't a regular file (like, say, stdin), then we must
- * go the old way and just read things in bit by bit.
- */
-
- *with_mmap = 0;
- off = 0;
- fb->sz = 0;
- fb->buf = NULL;
- for (;;) {
- if (off == fb->sz && fb->sz == (1U << 31)) {
- fprintf(stderr, "%s: input too large\n", f);
- break;
- }
-
- if (off == fb->sz)
- resize_buf(fb, 65536);
+ *oi += snprintf(ob->buf + *oi, 11,
+ "\\[u%.4X]", (unsigned char)ib->buf[(*ii)++]);
- ssz = read(fd, fb->buf + (int)off, fb->sz - off);
- if (ssz == 0) {
- fb->sz = off;
- return(1);
- }
- if (ssz == -1) {
- perror(f);
- break;
- }
- off += (size_t)ssz;
- }
-
- free(fb->buf);
- fb->buf = NULL;
- return(0);
+ *filenc &= ~MPARSE_UTF8;
+ return(1);
}
-static int
-cue_enc(const struct buf *b, size_t *offs, enum enc *enc)
+int
+preconv_cue(const struct buf *b, size_t offset)
{
const char *ln, *eoln, *eoph;
- size_t sz, phsz, nsz;
- int i;
+ size_t sz, phsz;
- ln = b->buf + (int)*offs;
- sz = b->sz - *offs;
+ ln = b->buf + offset;
+ sz = b->sz - offset;
/* Look for the end-of-line. */
if (NULL == (eoln = memchr(ln, '\n', sz)))
- return(-1);
-
- /* Set next-line marker. */
-
- *offs = (size_t)((eoln + 1) - b->buf);
+ eoln = ln + sz;
/* Check if we have the correct header/trailer. */
- if ((sz = (size_t)(eoln - ln)) < 10 ||
- memcmp(ln, ".\\\" -*-", 7) ||
- memcmp(eoln - 3, "-*-", 3))
- return(0);
+ if ((sz = (size_t)(eoln - ln)) < 10 ||
+ memcmp(ln, ".\\\" -*-", 7) || memcmp(eoln - 3, "-*-", 3))
+ return(MPARSE_UTF8 | MPARSE_LATIN1);
/* Move after the header and adjust for the trailer. */
@@ -356,12 +147,12 @@ cue_enc(const struct buf *b, size_t *offs, enum enc *enc)
/* Only account for the "coding" phrase. */
- if ((phsz = (size_t)(eoph - ln)) < 7 ||
- strncasecmp(ln, "coding:", 7)) {
+ if ((phsz = eoph - ln) < 7 ||
+ strncasecmp(ln, "coding:", 7)) {
sz -= phsz;
ln += phsz;
continue;
- }
+ }
sz -= 7;
ln += 7;
@@ -371,153 +162,15 @@ cue_enc(const struct buf *b, size_t *offs, enum enc *enc)
sz--;
}
if (0 == sz)
- break;
+ return(0);
/* Check us against known encodings. */
- for (i = 0; i < (int)ENC__MAX; i++) {
- nsz = strlen(encs[i].name);
- if (phsz < nsz)
- continue;
- if (strncasecmp(ln, encs[i].name, nsz))
- continue;
-
- *enc = (enum enc)i;
- return(1);
- }
-
- /* Unknown encoding. */
-
- *enc = ENC__MAX;
- return(1);
- }
-
- return(0);
-}
-
-int
-main(int argc, char *argv[])
-{
- int i, ch, map, fd, rc;
- struct buf b;
- const char *fn;
- enum enc enc, def;
- unsigned char bom[3] = { 0xEF, 0xBB, 0xBF };
- size_t offs;
- extern int optind;
- extern char *optarg;
-
- progname = strrchr(argv[0], '/');
- if (progname == NULL)
- progname = argv[0];
- else
- ++progname;
-
- fn = "<stdin>";
- fd = STDIN_FILENO;
- rc = EXIT_FAILURE;
- enc = def = ENC__MAX;
- map = 0;
-
- memset(&b, 0, sizeof(struct buf));
-
- while (-1 != (ch = getopt(argc, argv, "D:e:rdvh")))
- switch (ch) {
- case ('D'):
- /* FALLTHROUGH */
- case ('e'):
- for (i = 0; i < (int)ENC__MAX; i++) {
- if (strcasecmp(optarg, encs[i].name))
- continue;
- break;
- }
- if (i < (int)ENC__MAX) {
- if ('D' == ch)
- def = (enum enc)i;
- else
- enc = (enum enc)i;
- break;
- }
-
- fprintf(stderr, "%s: Bad encoding\n", optarg);
- return(EXIT_FAILURE);
- case ('r'):
- /* FALLTHROUGH */
- case ('d'):
- /* FALLTHROUGH */
- case ('v'):
- /* Compatibility with GNU preconv. */
- break;
- case ('h'):
- /* Compatibility with GNU preconv. */
- /* FALLTHROUGH */
- default:
- usage();
- return(EXIT_FAILURE);
- }
-
- argc -= optind;
- argv += optind;
-
- /*
- * Open and read the first argument on the command-line.
- * If we don't have one, we default to stdin.
- */
-
- if (argc > 0) {
- fn = *argv;
- fd = open(fn, O_RDONLY, 0);
- if (-1 == fd) {
- perror(fn);
- return(EXIT_FAILURE);
- }
- }
-
- if ( ! read_whole_file(fn, fd, &b, &map))
- goto out;
-
- /* Try to read the UTF-8 BOM. */
-
- if (ENC__MAX == enc)
- if (b.sz > 3 && 0 == memcmp(b.buf, bom, 3)) {
- b.offs = 3;
- enc = ENC_UTF_8;
- }
-
- /* Try reading from the "-*-" cue. */
-
- if (ENC__MAX == enc) {
- offs = b.offs;
- ch = cue_enc(&b, &offs, &enc);
- if (0 == ch)
- ch = cue_enc(&b, &offs, &enc);
- }
-
- /*
- * No encoding has been detected.
- * Thus, we either fall into our default encoder, if specified,
- * or use Latin-1 if all else fails.
- */
-
- if (ENC__MAX == enc)
- enc = ENC__MAX == def ? ENC_LATIN_1 : def;
-
- if ( ! (*encs[(int)enc].conv)(&b)) {
- fprintf(stderr, "%s: Bad encoding\n", fn);
- goto out;
+ if (phsz > 4 && !strncasecmp(ln, "utf-8", 5))
+ return(MPARSE_UTF8);
+ if (phsz > 10 && !strncasecmp(ln, "iso-latin-1", 11))
+ return(MPARSE_LATIN1);
+ return(0);
}
-
- rc = EXIT_SUCCESS;
-out:
-#ifdef HAVE_MMAP
- if (map)
- munmap(b.buf, b.sz);
- else
-#endif
- free(b.buf);
-
- if (fd > STDIN_FILENO)
- close(fd);
-
- return(rc);
+ return(MPARSE_UTF8 | MPARSE_LATIN1);
}
diff --git a/usr/src/cmd/mandoc/read.c b/usr/src/cmd/mandoc/read.c
index 511ba7dc46..471d415019 100644
--- a/usr/src/cmd/mandoc/read.c
+++ b/usr/src/cmd/mandoc/read.c
@@ -1,7 +1,8 @@
-/* $Id: read.c,v 1.39 2013/09/16 00:25:07 schwarze Exp $ */
+/* $Id: read.c,v 1.131 2015/03/11 13:05:20 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012 Joerg Sonnenberger <joerg@netbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -15,17 +16,18 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
-#ifdef HAVE_MMAP
-# include <sys/stat.h>
-# include <sys/mman.h>
+#include <sys/types.h>
+#if HAVE_MMAP
+#include <sys/mman.h>
+#include <sys/stat.h>
#endif
+#include <sys/wait.h>
#include <assert.h>
#include <ctype.h>
+#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdint.h>
@@ -35,40 +37,40 @@
#include <unistd.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libmandoc.h"
#include "mdoc.h"
#include "man.h"
-#include "main.h"
#define REPARSE_LIMIT 1000
-struct buf {
- char *buf; /* binary input buffer */
- size_t sz; /* size of binary buffer */
-};
-
struct mparse {
- enum mandoclevel file_status; /* status of current parse */
- enum mandoclevel wlevel; /* ignore messages below this */
- int line; /* line number in the file */
- enum mparset inttype; /* which parser to use */
struct man *pman; /* persistent man parser */
struct mdoc *pmdoc; /* persistent mdoc parser */
struct man *man; /* man parser */
struct mdoc *mdoc; /* mdoc parser */
struct roff *roff; /* roff parser (!NULL) */
- int reparse_count; /* finite interp. stack */
+ const struct mchars *mchars; /* character table */
+ char *sodest; /* filename pointed to by .so */
+ const char *file; /* filename of current input file */
+ struct buf *primary; /* buffer currently being parsed */
+ struct buf *secondary; /* preprocessed copy of input */
+ const char *defos; /* default operating system */
mandocmsg mmsg; /* warning/error message handler */
- void *arg; /* argument to mmsg */
- const char *file;
- struct buf *secondary;
- char *defos; /* default operating system */
+ enum mandoclevel file_status; /* status of current parse */
+ enum mandoclevel wlevel; /* ignore messages below this */
+ int options; /* parser options */
+ int filenc; /* encoding of the current file */
+ int reparse_count; /* finite interp. stack */
+ int line; /* line number in the file */
+ pid_t child; /* the gunzip(1) process */
};
+static void choose_parser(struct mparse *);
static void resize_buf(struct buf *, size_t);
-static void mparse_buf_r(struct mparse *, struct buf, int);
-static void pset(const char *, int, struct mparse *);
-static int read_whole_file(const char *, int, struct buf *, int *);
+static void 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 *);
static void mparse_parse_buffer(struct mparse *, struct buf,
const char *);
@@ -78,7 +80,7 @@ static const enum mandocerr mandoclimits[MANDOCLEVEL_MAX] = {
MANDOCERR_WARNING,
MANDOCERR_WARNING,
MANDOCERR_ERROR,
- MANDOCERR_FATAL,
+ MANDOCERR_UNSUPP,
MANDOCERR_MAX,
MANDOCERR_MAX
};
@@ -89,119 +91,150 @@ static const char * const mandocerrs[MANDOCERR_MAX] = {
"generic warning",
/* related to the prologue */
- "no title in document",
- "document title should be all caps",
+ "missing manual title, using UNTITLED",
+ "missing manual title, using \"\"",
+ "lower case character in document title",
+ "missing manual section, using \"\"",
"unknown manual section",
- "unknown manual volume or arch",
- "date missing, using today's date",
+ "missing date, using today's date",
"cannot parse date, using it verbatim",
- "prologue macros out of order",
+ "missing Os macro, using \"\"",
"duplicate prologue macro",
- "macro not allowed in prologue",
- "macro not allowed in body",
+ "late prologue macro",
+ "skipping late title macro",
+ "prologue macros out of order",
/* related to document structure */
".so is fragile, better use ln(1)",
- "NAME section must come first",
- "bad NAME section contents",
+ "no document body",
+ "content before first section header",
+ "first section is not \"NAME\"",
+ "NAME section without name",
+ "NAME section without description",
+ "description not at the end of NAME",
+ "bad NAME section content",
+ "missing description line, using \"\"",
"sections out of conventional order",
- "duplicate section name",
- "section header suited to sections 2, 3, and 9 only",
+ "duplicate section title",
+ "unexpected section",
+ "unusual Xr order",
+ "unusual Xr punctuation",
+ "AUTHORS section without An macro",
/* related to macros and nesting */
- "skipping obsolete macro",
+ "obsolete macro",
+ "macro neither callable nor escaped",
"skipping paragraph macro",
"moving paragraph macro out of list",
"skipping no-space macro",
"blocks badly nested",
- "child violates parent syntax",
"nested displays are not portable",
- "already in literal mode",
+ "moving content out of list",
+ ".Vt block has child macro",
+ "fill mode already enabled, skipping",
+ "fill mode already disabled, skipping",
"line scope broken",
/* related to missing macro arguments */
+ "skipping empty request",
+ "conditional request controls empty scope",
"skipping empty macro",
- "argument count wrong",
- "missing display type",
- "list type must come first",
- "tag lists require a width argument",
- "missing font type",
- "skipping end of block that is not open",
+ "empty block",
+ "empty argument, using 0n",
+ "missing display type, using -ragged",
+ "list type is not the first argument",
+ "missing -width in -tag list, using 8n",
+ "missing utility name, using \"\"",
+ "missing function name, using \"\"",
+ "empty head in list item",
+ "empty list item",
+ "missing font type, using \\fR",
+ "unknown font type, using \\fR",
+ "nothing follows prefix",
+ "empty reference block",
+ "missing -std argument, adding it",
+ "missing option string, using \"\"",
+ "missing resource identifier, using \"\"",
+ "missing eqn box, using \"\"",
/* related to bad macro arguments */
- "skipping argument",
+ "unterminated quoted argument",
"duplicate argument",
- "duplicate display type",
- "duplicate list type",
+ "skipping duplicate argument",
+ "skipping duplicate display type",
+ "skipping duplicate list type",
+ "skipping -width argument",
+ "wrong number of cells",
"unknown AT&T UNIX version",
- "bad Boolean value",
- "unknown font",
- "unknown standard specifier",
- "bad width argument",
+ "comma in function argument",
+ "parenthesis in function name",
+ "invalid content in Rs block",
+ "invalid Boolean argument",
+ "unknown font, skipping request",
+ "odd number of characters in request",
/* related to plain text */
- "blank line in non-literal context",
- "tab in non-literal context",
- "end of line whitespace",
+ "blank line in fill mode, using .sp",
+ "tab in filled text",
+ "whitespace at end of input line",
"bad comment style",
- "bad escape sequence",
- "unterminated quoted string",
+ "invalid escape sequence",
+ "undefined string, using \"\"",
- /* related to equations */
- "unexpected literal in equation",
-
- "generic error",
+ /* related to tables */
+ "tbl line starts with span",
+ "tbl column starts with span",
+ "skipping vertical bar in tbl layout",
- /* related to equations */
- "unexpected equation scope closure",
- "equation scope open on exit",
- "overlapping equation scopes",
- "unexpected end of equation",
- "equation syntax error",
+ "generic error",
/* related to tables */
- "bad table syntax",
- "bad table option",
- "bad table layout",
- "no table layout cells specified",
- "no table data cells specified",
- "ignore data in cell",
- "data block still open",
- "ignoring extra data cells",
-
+ "non-alphabetic character in tbl options",
+ "skipping unknown tbl option",
+ "missing tbl option argument",
+ "wrong tbl option argument size",
+ "empty tbl layout",
+ "invalid character in tbl layout",
+ "unmatched parenthesis in tbl layout",
+ "tbl without any data cells",
+ "ignoring data in spanned tbl cell",
+ "ignoring extra tbl data cells",
+ "data block open at end of tbl",
+
+ /* related to document structure and macros */
+ NULL,
"input stack limit exceeded, infinite loop?",
"skipping bad character",
- "escaped character not allowed in a name",
- "manual name not yet set",
- "skipping text before the first section header",
"skipping unknown macro",
- "NOT IMPLEMENTED, please use groff: skipping request",
- "argument count wrong",
+ "skipping insecure request",
+ "skipping item outside list",
"skipping column outside column list",
"skipping end of block that is not open",
- "missing end of block",
- "scope open on exit",
- "uname(3) system call failed",
- "macro requires line argument(s)",
- "macro requires body argument(s)",
- "macro requires argument(s)",
- "request requires a numeric argument",
- "missing list type",
- "line argument(s) will be lost",
- "body argument(s) will be lost",
-
- "generic fatal error",
-
- "not a manual",
- "column syntax is inconsistent",
- "NOT IMPLEMENTED: .Bd -file",
- "argument count wrong, violates syntax",
- "child violates parent syntax",
- "argument count wrong, violates syntax",
+ "fewer RS blocks open, skipping",
+ "inserting missing end of block",
+ "appending missing end of block",
+
+ /* related to request and macro arguments */
+ "escaped character not allowed in a name",
+ "NOT IMPLEMENTED: Bd -file",
+ "missing list type, using -item",
+ "missing manual name, using \"\"",
+ "uname(3) system call failed, using UNKNOWN",
+ "unknown standard specifier",
+ "skipping request without numeric argument",
"NOT IMPLEMENTED: .so with absolute path or \"..\"",
- "no document body",
- "no document prologue",
- "static buffer exhausted",
+ ".so request failed",
+ "skipping all arguments",
+ "skipping excess arguments",
+ "divide by zero",
+
+ "unsupported feature",
+ "input too large",
+ "unsupported control character",
+ "unsupported roff request",
+ "eqn delim option in tbl",
+ "unsupported tbl layout modifier",
+ "ignoring macro in table",
};
static const char * const mandoclevels[MANDOCLEVEL_MAX] = {
@@ -209,11 +242,12 @@ static const char * const mandoclevels[MANDOCLEVEL_MAX] = {
"RESERVED",
"WARNING",
"ERROR",
- "FATAL",
+ "UNSUPP",
"BADARG",
"SYSERR"
};
+
static void
resize_buf(struct buf *buf, size_t initial)
{
@@ -223,93 +257,101 @@ resize_buf(struct buf *buf, size_t initial)
}
static void
-pset(const char *buf, int pos, struct mparse *curp)
+choose_parser(struct mparse *curp)
{
- int i;
+ char *cp, *ep;
+ int format;
/*
- * Try to intuit which kind of manual parser should be used. If
- * passed in by command-line (-man, -mdoc), then use that
- * explicitly. If passed as -mandoc, then try to guess from the
- * line: either skip dot-lines, use -mdoc when finding `.Dt', or
- * default to -man, which is more lenient.
- *
- * Separate out pmdoc/pman from mdoc/man: the first persists
- * through all parsers, while the latter is used per-parse.
+ * If neither command line arguments -mdoc or -man select
+ * a parser nor the roff parser found a .Dd or .TH macro
+ * yet, look ahead in the main input buffer.
*/
- if ('.' == buf[0] || '\'' == buf[0]) {
- for (i = 1; buf[i]; i++)
- if (' ' != buf[i] && '\t' != buf[i])
+ if ((format = roff_getformat(curp->roff)) == 0) {
+ cp = curp->primary->buf;
+ ep = cp + curp->primary->sz;
+ while (cp < ep) {
+ if (*cp == '.' || *cp == '\'') {
+ cp++;
+ if (cp[0] == 'D' && cp[1] == 'd') {
+ format = MPARSE_MDOC;
+ break;
+ }
+ if (cp[0] == 'T' && cp[1] == 'H') {
+ format = MPARSE_MAN;
+ break;
+ }
+ }
+ cp = memchr(cp, '\n', ep - cp);
+ if (cp == NULL)
break;
- if ('\0' == buf[i])
- return;
+ cp++;
+ }
}
- switch (curp->inttype) {
- case (MPARSE_MDOC):
- if (NULL == curp->pmdoc)
- curp->pmdoc = mdoc_alloc(curp->roff, curp,
- curp->defos);
+ if (format == MPARSE_MDOC) {
+ if (NULL == curp->pmdoc)
+ curp->pmdoc = mdoc_alloc(
+ curp->roff, curp, curp->defos,
+ MPARSE_QUICK & curp->options ? 1 : 0);
assert(curp->pmdoc);
curp->mdoc = curp->pmdoc;
return;
- case (MPARSE_MAN):
- if (NULL == curp->pman)
- curp->pman = man_alloc(curp->roff, curp);
- assert(curp->pman);
- curp->man = curp->pman;
- return;
- default:
- break;
}
- if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3)) {
- if (NULL == curp->pmdoc)
- curp->pmdoc = mdoc_alloc(curp->roff, curp,
- curp->defos);
- assert(curp->pmdoc);
- curp->mdoc = curp->pmdoc;
- return;
- }
+ /* Fall back to man(7) as a last resort. */
- if (NULL == curp->pman)
- curp->pman = man_alloc(curp->roff, curp);
+ if (NULL == curp->pman)
+ curp->pman = man_alloc(
+ curp->roff, curp, curp->defos,
+ MPARSE_QUICK & curp->options ? 1 : 0);
assert(curp->pman);
curp->man = curp->pman;
}
/*
- * Main parse routine for an opened file. This is called for each
- * opened file and simply loops around the full input file, possibly
- * nesting (i.e., with `so').
+ * Main parse routine for a buffer.
+ * It assumes encoding and line numbering are already set up.
+ * It can recurse directly (for invocations of user-defined
+ * macros, inline equations, and input line traps)
+ * and indirectly (for .so file inclusion).
*/
static void
-mparse_buf_r(struct mparse *curp, struct buf blk, int start)
+mparse_buf_r(struct mparse *curp, struct buf blk, size_t i, int start)
{
const struct tbl_span *span;
struct buf ln;
+ const char *save_file;
+ char *cp;
+ size_t pos; /* byte number in the ln buffer */
enum rofferr rr;
- int i, of, rc;
- int pos; /* byte number in the ln buffer */
+ int of;
int lnn; /* line number in the real file */
+ int fd;
+ pid_t save_child;
unsigned char c;
- memset(&ln, 0, sizeof(struct buf));
+ memset(&ln, 0, sizeof(ln));
- lnn = curp->line;
- pos = 0;
+ lnn = curp->line;
+ pos = 0;
- for (i = 0; i < (int)blk.sz; ) {
+ while (i < blk.sz) {
if (0 == pos && '\0' == blk.buf[i])
break;
if (start) {
curp->line = lnn;
curp->reparse_count = 0;
+
+ if (lnn < 3 &&
+ curp->filenc & MPARSE_UTF8 &&
+ curp->filenc & MPARSE_LATIN1)
+ curp->filenc = preconv_cue(&blk, i);
}
- while (i < (int)blk.sz && (start || '\0' != blk.buf[i])) {
+ while (i < blk.sz && (start || blk.buf[i] != '\0')) {
/*
* When finding an unescaped newline character,
@@ -317,7 +359,7 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
* Skip a preceding carriage return, if any.
*/
- if ('\r' == blk.buf[i] && i + 1 < (int)blk.sz &&
+ if ('\r' == blk.buf[i] && i + 1 < blk.sz &&
'\n' == blk.buf[i + 1])
++i;
if ('\n' == blk.buf[i]) {
@@ -327,37 +369,47 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
}
/*
- * Make sure we have space for at least
- * one backslash and one other character
- * and the trailing NUL byte.
+ * Make sure we have space for the worst
+ * case of 11 bytes: "\\[u10ffff]\0"
*/
- if (pos + 2 >= (int)ln.sz)
+ if (pos + 11 > ln.sz)
resize_buf(&ln, 256);
- /*
- * Warn about bogus characters. If you're using
- * non-ASCII encoding, you're screwing your
- * readers. Since I'd rather this not happen,
- * I'll be helpful and replace these characters
- * with "?", so we don't display gibberish.
- * Note to manual writers: use special characters.
+ /*
+ * Encode 8-bit input.
*/
- c = (unsigned char) blk.buf[i];
+ c = blk.buf[i];
+ if (c & 0x80) {
+ if ( ! (curp->filenc && preconv_encode(
+ &blk, &i, &ln, &pos, &curp->filenc))) {
+ mandoc_vmsg(MANDOCERR_CHAR_BAD, curp,
+ curp->line, pos, "0x%x", c);
+ ln.buf[pos++] = '?';
+ i++;
+ }
+ continue;
+ }
- if ( ! (isascii(c) &&
- (isgraph(c) || isblank(c)))) {
- mandoc_msg(MANDOCERR_BADCHAR, curp,
- curp->line, pos, NULL);
+ /*
+ * Exclude control characters.
+ */
+
+ if (c == 0x7f || (c < 0x20 && c != 0x09)) {
+ mandoc_vmsg(c == 0x00 || c == 0x04 ||
+ c > 0x0a ? MANDOCERR_CHAR_BAD :
+ MANDOCERR_CHAR_UNSUPP,
+ curp, curp->line, pos, "0x%x", c);
i++;
- ln.buf[pos++] = '?';
+ if (c != '\r')
+ ln.buf[pos++] = '?';
continue;
}
/* Trailing backslash = a plain char. */
- if ('\\' != blk.buf[i] || i + 1 == (int)blk.sz) {
+ if (blk.buf[i] != '\\' || i + 1 == blk.sz) {
ln.buf[pos++] = blk.buf[i++];
continue;
}
@@ -369,7 +421,7 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
* skip that one as well.
*/
- if ('\r' == blk.buf[i + 1] && i + 2 < (int)blk.sz &&
+ if ('\r' == blk.buf[i + 1] && i + 2 < blk.sz &&
'\n' == blk.buf[i + 2])
++i;
if ('\n' == blk.buf[i + 1]) {
@@ -381,7 +433,7 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
if ('"' == blk.buf[i + 1] || '#' == blk.buf[i + 1]) {
i += 2;
/* Comment, skip to end of line */
- for (; i < (int)blk.sz; ++i) {
+ for (; i < blk.sz; ++i) {
if ('\n' == blk.buf[i]) {
++i;
++lnn;
@@ -403,10 +455,10 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
c = (unsigned char) blk.buf[i+1];
- if ( ! (isascii(c) &&
- (isgraph(c) || isblank(c)))) {
- mandoc_msg(MANDOCERR_BADCHAR, curp,
- curp->line, pos, NULL);
+ 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;
@@ -418,7 +470,7 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
ln.buf[pos++] = blk.buf[i++];
}
- if (pos >= (int)ln.sz)
+ if (pos >= ln.sz)
resize_buf(&ln, 256);
ln.buf[pos] = '\0';
@@ -441,13 +493,12 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
*/
if (curp->secondary) {
- curp->secondary->buf =
- mandoc_realloc
- (curp->secondary->buf,
- curp->secondary->sz + pos + 2);
- memcpy(curp->secondary->buf +
- curp->secondary->sz,
- ln.buf, pos);
+ curp->secondary->buf = mandoc_realloc(
+ curp->secondary->buf,
+ curp->secondary->sz + pos + 2);
+ memcpy(curp->secondary->buf +
+ curp->secondary->sz,
+ ln.buf, pos);
curp->secondary->sz += pos;
curp->secondary->buf
[curp->secondary->sz] = '\n';
@@ -456,41 +507,59 @@ mparse_buf_r(struct mparse *curp, struct buf blk, int start)
[curp->secondary->sz] = '\0';
}
rerun:
- rr = roff_parseln
- (curp->roff, curp->line,
- &ln.buf, &ln.sz, of, &of);
+ rr = roff_parseln(curp->roff, curp->line, &ln, &of);
switch (rr) {
- case (ROFF_REPARSE):
+ case ROFF_REPARSE:
if (REPARSE_LIMIT >= ++curp->reparse_count)
- mparse_buf_r(curp, ln, 0);
+ mparse_buf_r(curp, ln, of, 0);
else
mandoc_msg(MANDOCERR_ROFFLOOP, curp,
- curp->line, pos, NULL);
+ curp->line, pos, NULL);
pos = 0;
continue;
- case (ROFF_APPEND):
- pos = (int)strlen(ln.buf);
+ case ROFF_APPEND:
+ pos = strlen(ln.buf);
continue;
- case (ROFF_RERUN):
+ case ROFF_RERUN:
goto rerun;
- case (ROFF_IGN):
+ case ROFF_IGN:
pos = 0;
continue;
- case (ROFF_ERR):
- assert(MANDOCLEVEL_FATAL <= curp->file_status);
- break;
- case (ROFF_SO):
+ case ROFF_SO:
+ if ( ! (curp->options & MPARSE_SO) &&
+ (i >= blk.sz || blk.buf[i] == '\0')) {
+ curp->sodest = mandoc_strdup(ln.buf + of);
+ free(ln.buf);
+ return;
+ }
/*
* We remove `so' clauses from our lookaside
* buffer because we're going to descend into
* the file recursively.
*/
- if (curp->secondary)
+ if (curp->secondary)
curp->secondary->sz -= pos + 1;
- mparse_readfd(curp, -1, ln.buf + of);
- if (MANDOCLEVEL_FATAL <= curp->file_status)
- break;
+ save_file = curp->file;
+ save_child = curp->child;
+ if (mparse_open(curp, &fd, ln.buf + of) ==
+ MANDOCLEVEL_OK) {
+ mparse_readfd(curp, fd, ln.buf + of);
+ curp->file = save_file;
+ } else {
+ curp->file = save_file;
+ mandoc_vmsg(MANDOCERR_SO_FAIL,
+ curp, curp->line, pos,
+ ".so %s", ln.buf + of);
+ ln.sz = mandoc_asprintf(&cp,
+ ".sp\nSee the file %s.\n.sp",
+ ln.buf + of);
+ free(ln.buf);
+ ln.buf = cp;
+ of = 0;
+ mparse_buf_r(curp, ln, of, 0);
+ }
+ curp->child = save_child;
pos = 0;
continue;
default:
@@ -498,14 +567,6 @@ rerun:
}
/*
- * If we encounter errors in the recursive parse, make
- * sure we don't continue parsing.
- */
-
- if (MANDOCLEVEL_FATAL <= curp->file_status)
- break;
-
- /*
* If input parsers have not been allocated, do so now.
* We keep these instanced between parsers, but set them
* locally per parse routine since we can use different
@@ -513,12 +574,10 @@ rerun:
*/
if ( ! (curp->man || curp->mdoc))
- pset(ln.buf + of, pos - of, curp);
+ choose_parser(curp);
- /*
- * Lastly, push down into the parsers themselves. One
- * of these will have already been set in the pset()
- * routine.
+ /*
+ * Lastly, push down into the parsers themselves.
* If libroff returns ROFF_TBL, then add it to the
* currently open parse. Since we only get here if
* there does exist data (see tbl_data.c), we're
@@ -526,33 +585,21 @@ rerun:
* Do the same for ROFF_EQN.
*/
- rc = -1;
-
- if (ROFF_TBL == rr)
- while (NULL != (span = roff_span(curp->roff))) {
- rc = curp->man ?
- man_addspan(curp->man, span) :
+ if (rr == ROFF_TBL) {
+ while ((span = roff_span(curp->roff)) != NULL)
+ if (curp->man == NULL)
mdoc_addspan(curp->mdoc, span);
- if (0 == rc)
- break;
- }
- else if (ROFF_EQN == rr)
- rc = curp->mdoc ?
- mdoc_addeqn(curp->mdoc,
- roff_eqn(curp->roff)) :
- man_addeqn(curp->man,
- roff_eqn(curp->roff));
- else if (curp->man || curp->mdoc)
- rc = curp->man ?
- man_parseln(curp->man,
- curp->line, ln.buf, of) :
- mdoc_parseln(curp->mdoc,
- curp->line, ln.buf, of);
-
- if (0 == rc) {
- assert(MANDOCLEVEL_FATAL <= curp->file_status);
- break;
- }
+ else
+ man_addspan(curp->man, span);
+ } else if (rr == ROFF_EQN) {
+ if (curp->man == NULL)
+ mdoc_addeqn(curp->mdoc, roff_eqn(curp->roff));
+ else
+ man_addeqn(curp->man, roff_eqn(curp->roff));
+ } else if ((curp->man == NULL ?
+ mdoc_parseln(curp->mdoc, curp->line, ln.buf, of) :
+ man_parseln(curp->man, curp->line, ln.buf, of)) == 2)
+ break;
/* Temporary buffers typically are not full. */
@@ -568,16 +615,17 @@ rerun:
}
static int
-read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
+read_whole_file(struct mparse *curp, const char *file, int fd,
+ struct buf *fb, int *with_mmap)
{
size_t off;
ssize_t ssz;
-#ifdef HAVE_MMAP
+#if HAVE_MMAP
struct stat st;
if (-1 == fstat(fd, &st)) {
perror(file);
- return(0);
+ exit((int)MANDOCLEVEL_SYSERR);
}
/*
@@ -588,8 +636,8 @@ read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
*/
if (S_ISREG(st.st_mode)) {
- if (st.st_size >= (1U << 31)) {
- fprintf(stderr, "%s: input too large\n", file);
+ if (st.st_size > 0x7fffffff) {
+ mandoc_msg(MANDOCERR_TOOLARGE, curp, 0, 0, NULL);
return(0);
}
*with_mmap = 1;
@@ -612,7 +660,8 @@ read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
for (;;) {
if (off == fb->sz) {
if (fb->sz == (1U << 31)) {
- fprintf(stderr, "%s: input too large\n", file);
+ mandoc_msg(MANDOCERR_TOOLARGE, curp,
+ 0, 0, NULL);
break;
}
resize_buf(fb, 65536);
@@ -624,7 +673,7 @@ read_whole_file(const char *file, int fd, struct buf *fb, int *with_mmap)
}
if (ssz == -1) {
perror(file);
- break;
+ exit((int)MANDOCLEVEL_SYSERR);
}
off += (size_t)ssz;
}
@@ -638,32 +687,32 @@ static void
mparse_end(struct mparse *curp)
{
- if (MANDOCLEVEL_FATAL <= curp->file_status)
- return;
-
- if (curp->mdoc && ! mdoc_endparse(curp->mdoc)) {
- assert(MANDOCLEVEL_FATAL <= curp->file_status);
- return;
- }
-
- if (curp->man && ! man_endparse(curp->man)) {
- assert(MANDOCLEVEL_FATAL <= curp->file_status);
- return;
- }
-
- if ( ! (curp->man || curp->mdoc)) {
- mandoc_msg(MANDOCERR_NOTMANUAL, curp, 1, 0, NULL);
- curp->file_status = MANDOCLEVEL_FATAL;
- return;
+ if (curp->mdoc == NULL &&
+ curp->man == NULL &&
+ curp->sodest == NULL) {
+ if (curp->options & MPARSE_MDOC)
+ curp->mdoc = curp->pmdoc;
+ else {
+ if (curp->pman == NULL)
+ curp->pman = man_alloc(
+ curp->roff, curp, curp->defos,
+ curp->options & MPARSE_QUICK ? 1 : 0);
+ curp->man = curp->pman;
+ }
}
-
+ if (curp->mdoc)
+ mdoc_endparse(curp->mdoc);
+ if (curp->man)
+ man_endparse(curp->man);
roff_endparse(curp->roff);
}
static void
mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file)
{
+ struct buf *svprimary;
const char *svfile;
+ size_t offset;
static int recursion_depth;
if (64 < recursion_depth) {
@@ -674,86 +723,189 @@ mparse_parse_buffer(struct mparse *curp, struct buf blk, const char *file)
/* Line number is per-file. */
svfile = curp->file;
curp->file = file;
+ svprimary = curp->primary;
+ curp->primary = &blk;
curp->line = 1;
recursion_depth++;
- mparse_buf_r(curp, blk, 1);
+ /* Skip an UTF-8 byte order mark. */
+ if (curp->filenc & MPARSE_UTF8 && blk.sz > 2 &&
+ (unsigned char)blk.buf[0] == 0xef &&
+ (unsigned char)blk.buf[1] == 0xbb &&
+ (unsigned char)blk.buf[2] == 0xbf) {
+ offset = 3;
+ curp->filenc &= ~MPARSE_LATIN1;
+ } else
+ offset = 0;
- if (0 == --recursion_depth && MANDOCLEVEL_FATAL > curp->file_status)
+ mparse_buf_r(curp, blk, offset, 1);
+
+ if (--recursion_depth == 0)
mparse_end(curp);
+ curp->primary = svprimary;
curp->file = svfile;
}
enum mandoclevel
-mparse_readmem(struct mparse *curp, const void *buf, size_t len,
+mparse_readmem(struct mparse *curp, void *buf, size_t len,
const char *file)
{
struct buf blk;
- blk.buf = UNCONST(buf);
+ blk.buf = buf;
blk.sz = len;
mparse_parse_buffer(curp, blk, file);
return(curp->file_status);
}
+/*
+ * Read the whole file into memory and call the parsers.
+ * Called recursively when an .so request is encountered.
+ */
enum mandoclevel
mparse_readfd(struct mparse *curp, int fd, const char *file)
{
struct buf blk;
int with_mmap;
+ int save_filenc;
+
+ if (read_whole_file(curp, file, fd, &blk, &with_mmap)) {
+ save_filenc = curp->filenc;
+ curp->filenc = curp->options &
+ (MPARSE_UTF8 | MPARSE_LATIN1);
+ mparse_parse_buffer(curp, blk, file);
+ curp->filenc = save_filenc;
+#if HAVE_MMAP
+ if (with_mmap)
+ munmap(blk.buf, blk.sz);
+ else
+#endif
+ free(blk.buf);
+ }
- if (-1 == fd)
- if (-1 == (fd = open(file, O_RDONLY, 0))) {
- perror(file);
- curp->file_status = MANDOCLEVEL_SYSERR;
- goto out;
- }
- /*
- * Run for each opened file; may be called more than once for
- * each full parse sequence if the opened file is nested (i.e.,
- * from `so'). Simply sucks in the whole file and moves into
- * the parse phase for the file.
- */
+ if (fd != STDIN_FILENO && close(fd) == -1)
+ perror(file);
- if ( ! read_whole_file(file, fd, &blk, &with_mmap)) {
- curp->file_status = MANDOCLEVEL_SYSERR;
- goto out;
+ mparse_wait(curp);
+ return(curp->file_status);
+}
+
+enum mandoclevel
+mparse_open(struct mparse *curp, int *fd, const char *file)
+{
+ int pfd[2];
+ int save_errno;
+ char *cp;
+
+ curp->file = file;
+
+ /* Unless zipped, try to just open the file. */
+
+ if ((cp = strrchr(file, '.')) == NULL ||
+ strcmp(cp + 1, "gz")) {
+ curp->child = 0;
+ if ((*fd = open(file, O_RDONLY)) != -1)
+ return(MANDOCLEVEL_OK);
+
+ /* Open failed; try to append ".gz". */
+
+ mandoc_asprintf(&cp, "%s.gz", file);
+ file = cp;
+ } else
+ cp = NULL;
+
+ /* Before forking, make sure the file can be read. */
+
+ save_errno = errno;
+ if (access(file, R_OK) == -1) {
+ if (cp != NULL)
+ errno = save_errno;
+ free(cp);
+ *fd = -1;
+ curp->child = 0;
+ mandoc_msg(MANDOCERR_FILE, curp, 0, 0, strerror(errno));
+ return(MANDOCLEVEL_ERROR);
}
- mparse_parse_buffer(curp, blk, file);
+ /* Run gunzip(1). */
-#ifdef HAVE_MMAP
- if (with_mmap)
- munmap(blk.buf, blk.sz);
- else
-#endif
- free(blk.buf);
+ if (pipe(pfd) == -1) {
+ perror("pipe");
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
- if (STDIN_FILENO != fd && -1 == close(fd))
- perror(file);
-out:
- return(curp->file_status);
+ switch (curp->child = fork()) {
+ case -1:
+ perror("fork");
+ exit((int)MANDOCLEVEL_SYSERR);
+ case 0:
+ close(pfd[0]);
+ if (dup2(pfd[1], STDOUT_FILENO) == -1) {
+ perror("dup");
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+ execlp("gunzip", "gunzip", "-c", file, NULL);
+ perror("exec");
+ exit((int)MANDOCLEVEL_SYSERR);
+ default:
+ close(pfd[1]);
+ *fd = pfd[0];
+ return(MANDOCLEVEL_OK);
+ }
+}
+
+enum mandoclevel
+mparse_wait(struct mparse *curp)
+{
+ int status;
+
+ if (curp->child == 0)
+ return(MANDOCLEVEL_OK);
+
+ if (waitpid(curp->child, &status, 0) == -1) {
+ perror("wait");
+ exit((int)MANDOCLEVEL_SYSERR);
+ }
+ curp->child = 0;
+ if (WIFSIGNALED(status)) {
+ mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
+ "gunzip died from signal %d", WTERMSIG(status));
+ return(MANDOCLEVEL_ERROR);
+ }
+ if (WEXITSTATUS(status)) {
+ mandoc_vmsg(MANDOCERR_FILE, curp, 0, 0,
+ "gunzip failed with code %d", WEXITSTATUS(status));
+ return(MANDOCLEVEL_ERROR);
+ }
+ return(MANDOCLEVEL_OK);
}
struct mparse *
-mparse_alloc(enum mparset inttype, enum mandoclevel wlevel,
- mandocmsg mmsg, void *arg, char *defos)
+mparse_alloc(int options, enum mandoclevel wlevel, mandocmsg mmsg,
+ const struct mchars *mchars, const char *defos)
{
struct mparse *curp;
- assert(wlevel <= MANDOCLEVEL_FATAL);
-
curp = mandoc_calloc(1, sizeof(struct mparse));
+ curp->options = options;
curp->wlevel = wlevel;
curp->mmsg = mmsg;
- curp->arg = arg;
- curp->inttype = inttype;
curp->defos = defos;
- curp->roff = roff_alloc(inttype, curp);
+ curp->mchars = mchars;
+ curp->roff = roff_alloc(curp, curp->mchars, options);
+ if (curp->options & MPARSE_MDOC)
+ curp->pmdoc = mdoc_alloc(
+ curp->roff, curp, curp->defos,
+ curp->options & MPARSE_QUICK ? 1 : 0);
+ if (curp->options & MPARSE_MAN)
+ curp->pman = man_alloc(
+ curp->roff, curp, curp->defos,
+ curp->options & MPARSE_QUICK ? 1 : 0);
+
return(curp);
}
@@ -773,6 +925,9 @@ mparse_reset(struct mparse *curp)
curp->file_status = MANDOCLEVEL_OK;
curp->mdoc = NULL;
curp->man = NULL;
+
+ free(curp->sodest);
+ curp->sodest = NULL;
}
void
@@ -789,13 +944,20 @@ mparse_free(struct mparse *curp)
free(curp->secondary->buf);
free(curp->secondary);
+ free(curp->sodest);
free(curp);
}
void
-mparse_result(struct mparse *curp, struct mdoc **mdoc, struct man **man)
+mparse_result(struct mparse *curp,
+ struct mdoc **mdoc, struct man **man, char **sodest)
{
+ if (sodest && NULL != (*sodest = curp->sodest)) {
+ *mdoc = NULL;
+ *man = NULL;
+ return;
+ }
if (mdoc)
*mdoc = curp->mdoc;
if (man)
@@ -810,23 +972,23 @@ mandoc_vmsg(enum mandocerr t, struct mparse *m,
va_list ap;
va_start(ap, fmt);
- vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
+ (void)vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
mandoc_msg(t, m, ln, pos, buf);
}
void
-mandoc_msg(enum mandocerr er, struct mparse *m,
+mandoc_msg(enum mandocerr er, struct mparse *m,
int ln, int col, const char *msg)
{
enum mandoclevel level;
- level = MANDOCLEVEL_FATAL;
+ level = MANDOCLEVEL_UNSUPP;
while (er < mandoclimits[level])
level--;
- if (level < m->wlevel)
+ if (level < m->wlevel && er != MANDOCERR_FILE)
return;
if (m->mmsg)
diff --git a/usr/src/cmd/mandoc/roff.c b/usr/src/cmd/mandoc/roff.c
index 42240d21fe..3c920137ea 100644
--- a/usr/src/cmd/mandoc/roff.c
+++ b/usr/src/cmd/mandoc/roff.c
@@ -1,7 +1,7 @@
-/* $Id: roff.c,v 1.189 2013/12/30 18:44:06 schwarze Exp $ */
+/* $Id: roff.c,v 1.263 2015/02/21 14:46:58 schwarze Exp $ */
/*
- * Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2011, 2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2010-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
@@ -15,19 +15,21 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
+
+#include <sys/types.h>
#include <assert.h>
#include <ctype.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mandoc.h"
-#include "libroff.h"
+#include "mandoc_aux.h"
#include "libmandoc.h"
+#include "libroff.h"
/* Maximum number of nested if-else conditionals. */
#define RSTACK_MAX 128
@@ -36,50 +38,252 @@
#define EXPAND_LIMIT 1000
enum rofft {
+ ROFF_ab,
ROFF_ad,
+ ROFF_af,
+ ROFF_aln,
+ ROFF_als,
ROFF_am,
- ROFF_ami,
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,
+ /* MAN_br, MDOC_br */
+ ROFF_break,
+ ROFF_breakchar,
+ ROFF_brnl,
+ ROFF_brp,
+ ROFF_brpnl,
+ ROFF_c2,
ROFF_cc,
+ ROFF_ce,
+ 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_dei,
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,
+ /* MAN_ft; ignored in mdoc(7) */
+ 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,
+ /* MAN_ll, MDOC_ll */
+ ROFF_lnr,
+ ROFF_lnrf,
+ ROFF_lpfx,
+ ROFF_ls,
+ ROFF_lsm,
+ ROFF_lt,
+ ROFF_mc,
+ 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,
+ /* MAN_sp, MDOC_sp */
+ ROFF_spacewidth,
+ ROFF_special,
+ ROFF_spreadwarn,
+ ROFF_ss,
+ ROFF_sty,
+ ROFF_substring,
+ ROFF_sv,
+ ROFF_sy,
+ ROFF_T_,
ROFF_ta,
- ROFF_tr,
- ROFF_Dd,
+ ROFF_tc,
+ ROFF_TE,
ROFF_TH,
+ ROFF_ti,
+ 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_TE,
- ROFF_T_,
- ROFF_EQ,
- ROFF_EN,
+ 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_ccond,
ROFF_USERDEF,
ROFF_MAX
};
-enum roffrule {
- ROFFRULE_DENY,
- ROFFRULE_ALLOW
-};
-
/*
* An incredibly-simple string buffer.
*/
@@ -107,12 +311,10 @@ struct roffreg {
};
struct roff {
- enum mparset parsetype; /* requested parse type */
struct mparse *parse; /* parse point */
+ const struct mchars *mchars; /* character table */
struct roffnode *last; /* leaf of stack */
- enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */
- char control; /* control character */
- int rstackpos; /* position in rstack */
+ int *rstack; /* stack of inverted `ie' values */
struct roffreg *regtab; /* number registers */
struct roffkv *strtab; /* user-defined strings & macros */
struct roffkv *xmbtab; /* multi-byte trans table (`tr') */
@@ -124,6 +326,12 @@ struct roff {
struct eqn_node *last_eqn; /* last equation parsed */
struct eqn_node *first_eqn; /* first equation parsed */
struct eqn_node *eqn; /* current equation being parsed */
+ int eqn_inline; /* current equation is inline */
+ int options; /* parse options */
+ int rstacksz; /* current size limit of rstack */
+ int rstackpos; /* position in rstack */
+ int format; /* current file in mdoc or man format */
+ char control; /* control character */
};
struct roffnode {
@@ -134,13 +342,12 @@ struct roffnode {
char *name; /* node name, e.g. macro name */
char *end; /* end-rules: custom token */
int endspan; /* end-rules: next-line or infty */
- enum roffrule rule; /* current evaluation rule */
+ int rule; /* current evaluation rule */
};
#define ROFF_ARGS struct roff *r, /* parse ctx */ \
enum rofft tok, /* tok of macro */ \
- char **bufp, /* input buffer */ \
- size_t *szp, /* size of input buffer */ \
+ struct buf *buf, /* input buffer */ \
int ln, /* parse line */ \
int ppos, /* original pos in buffer */ \
int pos, /* current pos in buffer */ \
@@ -175,37 +382,46 @@ static void roffnode_push(struct roff *, enum rofft,
static enum rofferr roff_block(ROFF_ARGS);
static enum rofferr roff_block_text(ROFF_ARGS);
static enum rofferr roff_block_sub(ROFF_ARGS);
+static enum rofferr roff_brp(ROFF_ARGS);
static enum rofferr roff_cblock(ROFF_ARGS);
static enum rofferr roff_cc(ROFF_ARGS);
-static enum rofferr roff_ccond(ROFF_ARGS);
+static void roff_ccond(struct roff *, int, int);
static enum rofferr roff_cond(ROFF_ARGS);
static enum rofferr roff_cond_text(ROFF_ARGS);
static enum rofferr roff_cond_sub(ROFF_ARGS);
static enum rofferr roff_ds(ROFF_ARGS);
-static enum roffrule roff_evalcond(const char *, int *);
+static enum rofferr roff_eqndelim(struct roff *, struct buf *, int);
+static int roff_evalcond(struct roff *r, int,
+ const char *, int *);
+static int roff_evalnum(struct roff *, int,
+ const char *, int *, int *, int);
+static int roff_evalpar(struct roff *, int,
+ const char *, int *, int *, int);
+static int roff_evalstrcond(const char *, int *);
static void roff_free1(struct roff *);
static void roff_freereg(struct roffreg *);
static void roff_freestr(struct roffkv *);
-static char *roff_getname(struct roff *, char **, int, int);
-static int roff_getnum(const char *, int *, int *);
+static size_t roff_getname(struct roff *, char **, int, int);
+static int roff_getnum(const char *, int *, int *, int);
static int roff_getop(const char *, int *, char *);
static int roff_getregn(const struct roff *,
const char *, size_t);
-static const char *roff_getstrn(const struct roff *,
+static int roff_getregro(const char *name);
+static const char *roff_getstrn(const struct roff *,
const char *, size_t);
+static enum rofferr roff_insec(ROFF_ARGS);
static enum rofferr roff_it(ROFF_ARGS);
static enum rofferr roff_line_ignore(ROFF_ARGS);
static enum rofferr roff_nr(ROFF_ARGS);
-static void roff_openeqn(struct roff *, const char *,
- int, int, const char *);
-static enum rofft roff_parse(struct roff *, const char *, int *);
-static enum rofferr roff_parsetext(char **, size_t *, int, int *);
-static enum rofferr roff_res(struct roff *,
- char **, size_t *, int, int);
+static enum rofft roff_parse(struct roff *, char *, int *,
+ int, int);
+static enum rofferr roff_parsetext(struct buf *, int, int *);
+static enum rofferr roff_res(struct roff *, struct buf *, int, int);
static enum rofferr roff_rm(ROFF_ARGS);
+static enum rofferr roff_rr(ROFF_ARGS);
static void roff_setstr(struct roff *,
const char *, const char *, int);
-static void roff_setstrn(struct roffkv **, const char *,
+static void roff_setstrn(struct roffkv **, const char *,
size_t, const char *, size_t, int);
static enum rofferr roff_so(ROFF_ARGS);
static enum rofferr roff_tr(ROFF_ARGS);
@@ -216,6 +432,7 @@ static enum rofferr roff_TS(ROFF_ARGS);
static enum rofferr roff_EQ(ROFF_ARGS);
static enum rofferr roff_EN(ROFF_ARGS);
static enum rofferr roff_T_(ROFF_ARGS);
+static enum rofferr roff_unsupp(ROFF_ARGS);
static enum rofferr roff_userdef(ROFF_ARGS);
/* See roffhash_find() */
@@ -224,75 +441,280 @@ static enum rofferr roff_userdef(ROFF_ARGS);
#define ASCII_LO 33
#define HASHWIDTH (ASCII_HI - ASCII_LO + 1)
+#define ROFFNUM_SCALE (1 << 0) /* Honour scaling in roff_getnum(). */
+#define ROFFNUM_WHITE (1 << 1) /* Skip whitespace in roff_evalnum(). */
+
static struct roffmac *hash[HASHWIDTH];
static struct roffmac roffs[ROFF_MAX] = {
+ { "ab", roff_unsupp, NULL, NULL, 0, NULL },
{ "ad", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "af", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "aln", roff_unsupp, NULL, NULL, 0, NULL },
+ { "als", roff_unsupp, NULL, NULL, 0, NULL },
{ "am", roff_block, roff_block_text, roff_block_sub, 0, NULL },
- { "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
+ { "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },
+ { "ami1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
+ { "as", roff_ds, NULL, NULL, 0, NULL },
+ { "as1", roff_ds, NULL, NULL, 0, NULL },
+ { "asciify", roff_unsupp, NULL, NULL, 0, NULL },
+ { "backtrace", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "bd", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "bleedat", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "blm", roff_unsupp, NULL, NULL, 0, NULL },
+ { "box", roff_unsupp, NULL, NULL, 0, NULL },
+ { "boxa", roff_unsupp, NULL, NULL, 0, NULL },
+ { "bp", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "BP", roff_unsupp, NULL, NULL, 0, NULL },
+ { "break", roff_unsupp, NULL, NULL, 0, NULL },
+ { "breakchar", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "brnl", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "brp", roff_brp, NULL, NULL, 0, NULL },
+ { "brpnl", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "c2", roff_unsupp, NULL, NULL, 0, NULL },
{ "cc", roff_cc, NULL, NULL, 0, NULL },
+ { "ce", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "cf", roff_insec, NULL, NULL, 0, NULL },
+ { "cflags", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "ch", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "char", roff_unsupp, NULL, NULL, 0, NULL },
+ { "chop", roff_unsupp, NULL, NULL, 0, NULL },
+ { "class", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "close", roff_insec, NULL, NULL, 0, NULL },
+ { "CL", roff_unsupp, NULL, NULL, 0, NULL },
+ { "color", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "composite", roff_unsupp, NULL, NULL, 0, NULL },
+ { "continue", roff_unsupp, NULL, NULL, 0, NULL },
+ { "cp", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "cropat", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "cs", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "cu", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "da", roff_unsupp, NULL, NULL, 0, NULL },
+ { "dch", roff_unsupp, NULL, NULL, 0, NULL },
+ { "Dd", roff_Dd, NULL, NULL, 0, NULL },
{ "de", roff_block, roff_block_text, roff_block_sub, 0, NULL },
- { "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
+ { "defcolor", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },
+ { "dei1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
+ { "device", roff_unsupp, NULL, NULL, 0, NULL },
+ { "devicem", roff_unsupp, NULL, NULL, 0, NULL },
+ { "di", roff_unsupp, NULL, NULL, 0, NULL },
+ { "do", roff_unsupp, NULL, NULL, 0, NULL },
{ "ds", roff_ds, NULL, NULL, 0, NULL },
+ { "ds1", roff_ds, NULL, NULL, 0, NULL },
+ { "dwh", roff_unsupp, NULL, NULL, 0, NULL },
+ { "dt", roff_unsupp, NULL, NULL, 0, NULL },
+ { "ec", roff_unsupp, NULL, NULL, 0, NULL },
+ { "ecr", roff_unsupp, NULL, NULL, 0, NULL },
+ { "ecs", roff_unsupp, NULL, NULL, 0, NULL },
{ "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
+ { "em", roff_unsupp, NULL, NULL, 0, NULL },
+ { "EN", roff_EN, NULL, NULL, 0, NULL },
+ { "eo", roff_unsupp, NULL, NULL, 0, NULL },
+ { "EP", roff_unsupp, NULL, NULL, 0, NULL },
+ { "EQ", roff_EQ, NULL, NULL, 0, NULL },
+ { "errprint", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "ev", roff_unsupp, NULL, NULL, 0, NULL },
+ { "evc", roff_unsupp, NULL, NULL, 0, NULL },
+ { "ex", roff_unsupp, NULL, NULL, 0, NULL },
+ { "fallback", roff_line_ignore, NULL, NULL, 0, NULL },
{ "fam", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "fc", roff_unsupp, NULL, NULL, 0, NULL },
+ { "fchar", roff_unsupp, NULL, NULL, 0, NULL },
+ { "fcolor", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "fdeferlig", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "feature", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "fkern", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "fl", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "flig", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "fp", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "fps", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "fschar", roff_unsupp, NULL, NULL, 0, NULL },
+ { "fspacewidth", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "fspecial", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "ftr", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "fzoom", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "gcolor", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hc", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hcode", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hidechar", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hla", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hlm", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hpf", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hpfa", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hpfcode", roff_line_ignore, NULL, NULL, 0, NULL },
{ "hw", roff_line_ignore, NULL, NULL, 0, NULL },
{ "hy", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hylang", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hylen", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hym", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hypp", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "hys", roff_line_ignore, NULL, NULL, 0, NULL },
{ "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
{ "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
{ "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL },
+ { "index", roff_unsupp, NULL, NULL, 0, NULL },
{ "it", roff_it, NULL, NULL, 0, NULL },
+ { "itc", roff_unsupp, NULL, NULL, 0, NULL },
+ { "IX", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "kern", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "kernafter", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "kernbefore", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "kernpair", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "lc", roff_unsupp, NULL, NULL, 0, NULL },
+ { "lc_ctype", roff_unsupp, NULL, NULL, 0, NULL },
+ { "lds", roff_unsupp, NULL, NULL, 0, NULL },
+ { "length", roff_unsupp, NULL, NULL, 0, NULL },
+ { "letadj", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "lf", roff_insec, NULL, NULL, 0, NULL },
+ { "lg", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "lhang", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "linetabs", roff_unsupp, NULL, NULL, 0, NULL },
+ { "lnr", roff_unsupp, NULL, NULL, 0, NULL },
+ { "lnrf", roff_unsupp, NULL, NULL, 0, NULL },
+ { "lpfx", roff_unsupp, NULL, NULL, 0, NULL },
+ { "ls", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "lsm", roff_unsupp, NULL, NULL, 0, NULL },
+ { "lt", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "mc", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "mediasize", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "minss", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "mk", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "mso", roff_insec, NULL, NULL, 0, NULL },
+ { "na", roff_line_ignore, NULL, NULL, 0, NULL },
{ "ne", roff_line_ignore, NULL, NULL, 0, NULL },
{ "nh", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "nhychar", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "nm", roff_unsupp, NULL, NULL, 0, NULL },
+ { "nn", roff_unsupp, NULL, NULL, 0, NULL },
+ { "nop", roff_unsupp, NULL, NULL, 0, NULL },
{ "nr", roff_nr, NULL, NULL, 0, NULL },
+ { "nrf", roff_unsupp, NULL, NULL, 0, NULL },
+ { "nroff", roff_line_ignore, NULL, NULL, 0, NULL },
{ "ns", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "nx", roff_insec, NULL, NULL, 0, NULL },
+ { "open", roff_insec, NULL, NULL, 0, NULL },
+ { "opena", roff_insec, NULL, NULL, 0, NULL },
+ { "os", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "output", roff_unsupp, NULL, NULL, 0, NULL },
+ { "padj", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "papersize", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "pc", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "pev", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "pi", roff_insec, NULL, NULL, 0, NULL },
+ { "PI", roff_unsupp, NULL, NULL, 0, NULL },
+ { "pl", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "pm", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "pn", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "pnr", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "po", roff_line_ignore, NULL, NULL, 0, NULL },
{ "ps", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "psbb", roff_unsupp, NULL, NULL, 0, NULL },
+ { "pshape", roff_unsupp, NULL, NULL, 0, NULL },
+ { "pso", roff_insec, NULL, NULL, 0, NULL },
+ { "ptr", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "pvs", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "rchar", roff_unsupp, NULL, NULL, 0, NULL },
+ { "rd", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "recursionlimit", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "return", roff_unsupp, NULL, NULL, 0, NULL },
+ { "rfschar", roff_unsupp, NULL, NULL, 0, NULL },
+ { "rhang", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "rj", roff_line_ignore, NULL, NULL, 0, NULL },
{ "rm", roff_rm, NULL, NULL, 0, NULL },
+ { "rn", roff_unsupp, NULL, NULL, 0, NULL },
+ { "rnn", roff_unsupp, NULL, NULL, 0, NULL },
+ { "rr", roff_rr, NULL, NULL, 0, NULL },
+ { "rs", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "rt", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "schar", roff_unsupp, NULL, NULL, 0, NULL },
+ { "sentchar", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "shc", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "shift", roff_unsupp, NULL, NULL, 0, NULL },
+ { "sizes", roff_line_ignore, NULL, NULL, 0, NULL },
{ "so", roff_so, NULL, NULL, 0, NULL },
- { "ta", roff_line_ignore, NULL, NULL, 0, NULL },
- { "tr", roff_tr, NULL, NULL, 0, NULL },
- { "Dd", roff_Dd, NULL, NULL, 0, NULL },
+ { "spacewidth", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "special", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "spreadwarn", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "ss", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "sty", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "substring", roff_unsupp, NULL, NULL, 0, NULL },
+ { "sv", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "sy", roff_insec, NULL, NULL, 0, NULL },
+ { "T&", roff_T_, NULL, NULL, 0, NULL },
+ { "ta", roff_unsupp, NULL, NULL, 0, NULL },
+ { "tc", roff_unsupp, NULL, NULL, 0, NULL },
+ { "TE", roff_TE, NULL, NULL, 0, NULL },
{ "TH", roff_TH, NULL, NULL, 0, NULL },
+ { "ti", roff_unsupp, NULL, NULL, 0, NULL },
+ { "tkf", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "tl", roff_unsupp, NULL, NULL, 0, NULL },
+ { "tm", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "tm1", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "tmc", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "tr", roff_tr, NULL, NULL, 0, NULL },
+ { "track", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "transchar", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "trf", roff_insec, NULL, NULL, 0, NULL },
+ { "trimat", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "trin", roff_unsupp, NULL, NULL, 0, NULL },
+ { "trnt", roff_unsupp, NULL, NULL, 0, NULL },
+ { "troff", roff_line_ignore, NULL, NULL, 0, NULL },
{ "TS", roff_TS, NULL, NULL, 0, NULL },
- { "TE", roff_TE, NULL, NULL, 0, NULL },
- { "T&", roff_T_, NULL, NULL, 0, NULL },
- { "EQ", roff_EQ, NULL, NULL, 0, NULL },
- { "EN", roff_EN, NULL, NULL, 0, NULL },
+ { "uf", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "ul", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "unformat", roff_unsupp, NULL, NULL, 0, NULL },
+ { "unwatch", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "unwatchn", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "vpt", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "vs", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "warn", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "warnscale", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "watch", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "watchlength", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "watchn", roff_line_ignore, NULL, NULL, 0, NULL },
+ { "wh", roff_unsupp, NULL, NULL, 0, NULL },
+ { "while", roff_unsupp, NULL, NULL, 0, NULL },
+ { "write", roff_insec, NULL, NULL, 0, NULL },
+ { "writec", roff_insec, NULL, NULL, 0, NULL },
+ { "writem", roff_insec, NULL, NULL, 0, NULL },
+ { "xflag", roff_line_ignore, NULL, NULL, 0, NULL },
{ ".", roff_cblock, NULL, NULL, 0, NULL },
- { "\\}", roff_ccond, NULL, NULL, 0, NULL },
{ NULL, roff_userdef, NULL, NULL, 0, NULL },
};
+/* not currently implemented: Ds em Eq LP Me PP pp Or Rd Sf SH */
const char *const __mdoc_reserved[] = {
"Ac", "Ad", "An", "Ao", "Ap", "Aq", "Ar", "At",
"Bc", "Bd", "Bf", "Bk", "Bl", "Bo", "Bq",
"Brc", "Bro", "Brq", "Bsx", "Bt", "Bx",
"Cd", "Cm", "Db", "Dc", "Dd", "Dl", "Do", "Dq",
- "Ds", "Dt", "Dv", "Dx", "D1",
- "Ec", "Ed", "Ef", "Ek", "El", "Em", "em",
- "En", "Eo", "Eq", "Er", "Es", "Ev", "Ex",
+ "Dt", "Dv", "Dx", "D1",
+ "Ec", "Ed", "Ef", "Ek", "El", "Em",
+ "En", "Eo", "Er", "Es", "Ev", "Ex",
"Fa", "Fc", "Fd", "Fl", "Fn", "Fo", "Fr", "Ft", "Fx",
- "Hf", "Ic", "In", "It", "Lb", "Li", "Lk", "Lp", "LP",
- "Me", "Ms", "Mt", "Nd", "Nm", "No", "Ns", "Nx",
+ "Hf", "Ic", "In", "It", "Lb", "Li", "Lk", "Lp",
+ "Ms", "Mt", "Nd", "Nm", "No", "Ns", "Nx",
"Oc", "Oo", "Op", "Os", "Ot", "Ox",
- "Pa", "Pc", "Pf", "Po", "Pp", "PP", "pp", "Pq",
- "Qc", "Ql", "Qo", "Qq", "Or", "Rd", "Re", "Rs", "Rv",
- "Sc", "Sf", "Sh", "SH", "Sm", "So", "Sq",
+ "Pa", "Pc", "Pf", "Po", "Pp", "Pq",
+ "Qc", "Ql", "Qo", "Qq", "Re", "Rs", "Rv",
+ "Sc", "Sh", "Sm", "So", "Sq",
"Ss", "St", "Sx", "Sy",
"Ta", "Tn", "Ud", "Ux", "Va", "Vt", "Xc", "Xo", "Xr",
- "%A", "%B", "%D", "%I", "%J", "%N", "%O",
+ "%A", "%B", "%C", "%D", "%I", "%J", "%N", "%O",
"%P", "%Q", "%R", "%T", "%U", "%V",
NULL
};
+/* not currently implemented: BT DE DS ME MT PT SY TQ YS */
const char *const __man_reserved[] = {
- "AT", "B", "BI", "BR", "BT", "DE", "DS", "DT",
- "EE", "EN", "EQ", "EX", "HF", "HP", "I", "IB", "IP", "IR",
- "LP", "ME", "MT", "OP", "P", "PD", "PP", "PT",
- "R", "RB", "RE", "RI", "RS", "SB", "SH", "SM", "SS", "SY",
- "TE", "TH", "TP", "TQ", "TS", "T&", "UC", "UE", "UR", "YS",
+ "AT", "B", "BI", "BR", "DT",
+ "EE", "EN", "EQ", "EX", "HP", "I", "IB", "IP", "IR",
+ "LP", "OP", "P", "PD", "PP",
+ "R", "RB", "RE", "RI", "RS", "SB", "SH", "SM", "SS",
+ "TE", "TH", "TP", "TS", "T&", "UC", "UE", "UR",
NULL
};
@@ -308,6 +730,7 @@ static const struct predef predefs[PREDEFS_MAX] = {
static int roffit_lines; /* number of lines to delay */
static char *roffit_macro; /* nil-terminated macro line */
+
static void
roffhash_init(void)
{
@@ -360,7 +783,6 @@ roffhash_find(const char *p, size_t s)
return(ROFF_MAX);
}
-
/*
* Pop the current node off of the stack of roff instructions currently
* pending.
@@ -371,7 +793,7 @@ roffnode_pop(struct roff *r)
struct roffnode *p;
assert(r->last);
- p = r->last;
+ p = r->last;
r->last = r->last->parent;
free(p->name);
@@ -379,7 +801,6 @@ roffnode_pop(struct roff *r)
free(p);
}
-
/*
* Push a roff node onto the instruction stack. This must later be
* removed with roffnode_pop().
@@ -397,12 +818,11 @@ roffnode_push(struct roff *r, enum rofft tok, const char *name,
p->parent = r->last;
p->line = line;
p->col = col;
- p->rule = p->parent ? p->parent->rule : ROFFRULE_DENY;
+ p->rule = p->parent ? p->parent->rule : 0;
r->last = p;
}
-
static void
roff_free1(struct roff *r)
{
@@ -414,32 +834,32 @@ roff_free1(struct roff *r)
r->first_tbl = tbl->next;
tbl_free(tbl);
}
-
r->first_tbl = r->last_tbl = r->tbl = NULL;
while (NULL != (e = r->first_eqn)) {
r->first_eqn = e->next;
eqn_free(e);
}
-
r->first_eqn = r->last_eqn = r->eqn = NULL;
while (r->last)
roffnode_pop(r);
- roff_freestr(r->strtab);
- roff_freestr(r->xmbtab);
-
- r->strtab = r->xmbtab = NULL;
+ free (r->rstack);
+ r->rstack = NULL;
+ r->rstacksz = 0;
+ r->rstackpos = -1;
roff_freereg(r->regtab);
-
r->regtab = NULL;
+ roff_freestr(r->strtab);
+ roff_freestr(r->xmbtab);
+ r->strtab = r->xmbtab = NULL;
+
if (r->xtab)
for (i = 0; i < 128; i++)
free(r->xtab[i].p);
-
free(r->xtab);
r->xtab = NULL;
}
@@ -447,17 +867,12 @@ roff_free1(struct roff *r)
void
roff_reset(struct roff *r)
{
- int i;
roff_free1(r);
-
+ r->format = r->options & (MPARSE_MDOC | MPARSE_MAN);
r->control = 0;
-
- for (i = 0; i < PREDEFS_MAX; i++)
- roff_setstr(r, predefs[i].name, predefs[i].str, 0);
}
-
void
roff_free(struct roff *r)
{
@@ -466,78 +881,100 @@ roff_free(struct roff *r)
free(r);
}
-
struct roff *
-roff_alloc(enum mparset type, struct mparse *parse)
+roff_alloc(struct mparse *parse, const struct mchars *mchars, int options)
{
struct roff *r;
- int i;
r = mandoc_calloc(1, sizeof(struct roff));
- r->parsetype = type;
r->parse = parse;
+ r->mchars = mchars;
+ r->options = options;
+ r->format = options & (MPARSE_MDOC | MPARSE_MAN);
r->rstackpos = -1;
-
- roffhash_init();
- for (i = 0; i < PREDEFS_MAX; i++)
- roff_setstr(r, predefs[i].name, predefs[i].str, 0);
+ roffhash_init();
return(r);
}
/*
- * In the current line, expand user-defined strings ("\*")
- * and references to number registers ("\n").
- * Also check the syntax of other escape sequences.
+ * In the current line, expand escape sequences that tend to get
+ * used in numerical expressions and conditional requests.
+ * Also check the syntax of the remaining escape sequences.
*/
static enum rofferr
-roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
+roff_res(struct roff *r, struct buf *buf, int ln, int pos)
{
- char ubuf[12]; /* buffer to print the number */
- const char *stesc; /* start of an escape sequence ('\\') */
+ char ubuf[24]; /* buffer to print the number */
+ const char *start; /* start of the string to process */
+ char *stesc; /* start of an escape sequence ('\\') */
const char *stnam; /* start of the name, after "[(*" */
const char *cp; /* end of the name, e.g. before ']' */
const char *res; /* the string to be substituted */
- char *nbuf; /* new buffer to copy bufp to */
- size_t nsz; /* size of the new buffer */
+ char *nbuf; /* new buffer to copy buf->buf to */
size_t maxl; /* expected length of the escape name */
size_t naml; /* actual length of the escape name */
+ enum mandoc_esc esc; /* type of the escape sequence */
+ int inaml; /* length returned from mandoc_escape() */
int expand_count; /* to avoid infinite loops */
+ int npos; /* position in numeric expression */
+ int arg_complete; /* argument not interrupted by eol */
+ char term; /* character terminating the escape */
expand_count = 0;
+ start = buf->buf + pos;
+ stesc = strchr(start, '\0') - 1;
+ while (stesc-- > start) {
-again:
- cp = *bufp + pos;
- while (NULL != (cp = strchr(cp, '\\'))) {
- stesc = cp++;
+ /* Search backwards for the next backslash. */
- /*
- * The second character must be an asterisk or an n.
- * If it isn't, skip it anyway: It is escaped,
- * so it can't start another escape sequence.
- */
+ if (*stesc != '\\')
+ continue;
+
+ /* If it is escaped, skip it. */
- if ('\0' == *cp)
- return(ROFF_CONT);
+ for (cp = stesc - 1; cp >= start; cp--)
+ if (*cp != '\\')
+ break;
+
+ if ((stesc - cp) % 2 == 0) {
+ stesc = (char *)cp;
+ continue;
+ }
+ /* Decide whether to expand or to check only. */
+
+ term = '\0';
+ cp = stesc + 1;
switch (*cp) {
- case ('*'):
+ case '*':
res = NULL;
break;
- case ('n'):
+ case 'B':
+ /* FALLTHROUGH */
+ case 'w':
+ term = cp[1];
+ /* FALLTHROUGH */
+ case 'n':
res = ubuf;
break;
default:
- if (ESCAPE_ERROR != mandoc_escape(&cp, NULL, NULL))
- continue;
- mandoc_msg
- (MANDOCERR_BADESCAPE, r->parse,
- ln, (int)(stesc - *bufp), NULL);
- return(ROFF_CONT);
+ esc = mandoc_escape(&cp, &stnam, &inaml);
+ if (esc == ESCAPE_ERROR ||
+ (esc == ESCAPE_SPECIAL &&
+ mchars_spec2cp(r->mchars, stnam, inaml) < 0))
+ mandoc_vmsg(MANDOCERR_ESC_BAD,
+ r->parse, ln, (int)(stesc - buf->buf),
+ "%.*s", (int)(cp - stesc), stesc);
+ continue;
}
- cp++;
+ if (EXPAND_LIMIT < ++expand_count) {
+ mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
+ ln, (int)(stesc - buf->buf), NULL);
+ return(ROFF_IGN);
+ }
/*
* The third character decides the length
@@ -545,35 +982,62 @@ again:
* Save a pointer to the name.
*/
- switch (*cp) {
- case ('\0'):
- return(ROFF_CONT);
- case ('('):
- cp++;
- maxl = 2;
- break;
- case ('['):
- cp++;
+ if (term == '\0') {
+ switch (*++cp) {
+ case '\0':
+ maxl = 0;
+ break;
+ case '(':
+ cp++;
+ maxl = 2;
+ break;
+ case '[':
+ cp++;
+ term = ']';
+ maxl = 0;
+ break;
+ default:
+ maxl = 1;
+ break;
+ }
+ } else {
+ cp += 2;
maxl = 0;
- break;
- default:
- maxl = 1;
- break;
}
stnam = cp;
/* Advance to the end of the name. */
- for (naml = 0; 0 == maxl || naml < maxl; naml++, cp++) {
- if ('\0' == *cp) {
- mandoc_msg
- (MANDOCERR_BADESCAPE,
- r->parse, ln,
- (int)(stesc - *bufp), NULL);
- return(ROFF_CONT);
+ naml = 0;
+ arg_complete = 1;
+ while (maxl == 0 || naml < maxl) {
+ if (*cp == '\0') {
+ mandoc_msg(MANDOCERR_ESC_BAD, r->parse,
+ ln, (int)(stesc - buf->buf), stesc);
+ arg_complete = 0;
+ break;
+ }
+ if (maxl == 0 && *cp == term) {
+ cp++;
+ break;
}
- if (0 == maxl && ']' == *cp)
+ if (*cp++ != '\\' || stesc[1] != 'w') {
+ naml++;
+ continue;
+ }
+ switch (mandoc_escape(&cp, NULL, NULL)) {
+ case ESCAPE_SPECIAL:
+ /* FALLTHROUGH */
+ case ESCAPE_UNICODE:
+ /* FALLTHROUGH */
+ case ESCAPE_NUMBERED:
+ /* FALLTHROUGH */
+ case ESCAPE_OVERSTRIKE:
+ naml++;
break;
+ default:
+ break;
+ }
}
/*
@@ -581,41 +1045,56 @@ again:
* undefined, resume searching for escapes.
*/
- if (NULL == res)
- res = roff_getstrn(r, stnam, naml);
- else
- snprintf(ubuf, sizeof(ubuf), "%d",
- roff_getregn(r, stnam, naml));
-
- if (NULL == res) {
- mandoc_msg
- (MANDOCERR_BADESCAPE, r->parse,
- ln, (int)(stesc - *bufp), NULL);
+ switch (stesc[1]) {
+ case '*':
+ if (arg_complete)
+ res = roff_getstrn(r, stnam, naml);
+ break;
+ case 'B':
+ npos = 0;
+ ubuf[0] = arg_complete &&
+ roff_evalnum(r, ln, stnam, &npos,
+ NULL, ROFFNUM_SCALE) &&
+ stnam + npos + 1 == cp ? '1' : '0';
+ ubuf[1] = '\0';
+ break;
+ case 'n':
+ if (arg_complete)
+ (void)snprintf(ubuf, sizeof(ubuf), "%d",
+ roff_getregn(r, stnam, naml));
+ else
+ ubuf[0] = '\0';
+ break;
+ case 'w':
+ /* use even incomplete args */
+ (void)snprintf(ubuf, sizeof(ubuf), "%d",
+ 24 * (int)naml);
+ break;
+ }
+
+ if (res == NULL) {
+ mandoc_vmsg(MANDOCERR_STR_UNDEF,
+ r->parse, ln, (int)(stesc - buf->buf),
+ "%.*s", (int)naml, stnam);
res = "";
+ } else if (buf->sz + strlen(res) > SHRT_MAX) {
+ mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
+ ln, (int)(stesc - buf->buf), NULL);
+ return(ROFF_IGN);
}
/* Replace the escape sequence by the string. */
- pos = stesc - *bufp;
+ *stesc = '\0';
+ buf->sz = mandoc_asprintf(&nbuf, "%s%s%s",
+ buf->buf, res, cp) + 1;
- nsz = *szp + strlen(res) + 1;
- nbuf = mandoc_malloc(nsz);
+ /* Prepare for the next replacement. */
- strlcpy(nbuf, *bufp, (size_t)(stesc - *bufp + 1));
- strlcat(nbuf, res, nsz);
- strlcat(nbuf, cp + (maxl ? 0 : 1), nsz);
-
- free(*bufp);
-
- *bufp = nbuf;
- *szp = nsz;
-
- if (EXPAND_LIMIT >= ++expand_count)
- goto again;
-
- /* Just leave the string unexpanded. */
- mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, ln, pos, NULL);
- return(ROFF_IGN);
+ start = nbuf + pos;
+ stesc = nbuf + (stesc - buf->buf) + strlen(res);
+ free(buf->buf);
+ buf->buf = nbuf;
}
return(ROFF_CONT);
}
@@ -626,7 +1105,7 @@ again:
* Decrement and spring input line trap.
*/
static enum rofferr
-roff_parsetext(char **bufp, size_t *szp, int pos, int *offs)
+roff_parsetext(struct buf *buf, int pos, int *offs)
{
size_t sz;
const char *start;
@@ -634,20 +1113,20 @@ roff_parsetext(char **bufp, size_t *szp, int pos, int *offs)
int isz;
enum mandoc_esc esc;
- start = p = *bufp + pos;
+ start = p = buf->buf + pos;
- while ('\0' != *p) {
+ while (*p != '\0') {
sz = strcspn(p, "-\\");
p += sz;
- if ('\0' == *p)
+ if (*p == '\0')
break;
- if ('\\' == *p) {
+ if (*p == '\\') {
/* Skip over escapes. */
p++;
esc = mandoc_escape((const char **)&p, NULL, NULL);
- if (ESCAPE_ERROR == esc)
+ if (esc == ESCAPE_ERROR)
break;
continue;
} else if (p == start) {
@@ -662,69 +1141,83 @@ roff_parsetext(char **bufp, size_t *szp, int pos, int *offs)
}
/* Spring the input line trap. */
- if (1 == roffit_lines) {
- isz = asprintf(&p, "%s\n.%s", *bufp, roffit_macro);
- if (-1 == isz) {
- perror(NULL);
- exit((int)MANDOCLEVEL_SYSERR);
- }
- free(*bufp);
- *bufp = p;
- *szp = isz + 1;
+ if (roffit_lines == 1) {
+ isz = mandoc_asprintf(&p, "%s\n.%s", buf->buf, roffit_macro);
+ free(buf->buf);
+ buf->buf = p;
+ buf->sz = isz + 1;
*offs = 0;
free(roffit_macro);
roffit_lines = 0;
return(ROFF_REPARSE);
- } else if (1 < roffit_lines)
+ } else if (roffit_lines > 1)
--roffit_lines;
return(ROFF_CONT);
}
enum rofferr
-roff_parseln(struct roff *r, int ln, char **bufp,
- size_t *szp, int pos, int *offs)
+roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
{
enum rofft t;
enum rofferr e;
- int ppos, ctl;
+ int pos; /* parse point */
+ int spos; /* saved parse point for messages */
+ int ppos; /* original offset in buf->buf */
+ int ctl; /* macro line (boolean) */
- /*
- * Run the reserved-word filter only if we have some reserved
- * words to fill in.
- */
+ ppos = pos = *offs;
+
+ /* Handle in-line equation delimiters. */
+
+ if (r->tbl == NULL &&
+ r->last_eqn != NULL && r->last_eqn->delim &&
+ (r->eqn == NULL || r->eqn_inline)) {
+ e = roff_eqndelim(r, buf, pos);
+ if (e == ROFF_REPARSE)
+ return(e);
+ assert(e == ROFF_CONT);
+ }
+
+ /* Expand some escape sequences. */
- e = roff_res(r, bufp, szp, ln, pos);
- if (ROFF_IGN == e)
+ e = roff_res(r, buf, ln, pos);
+ if (e == ROFF_IGN)
return(e);
- assert(ROFF_CONT == e);
+ assert(e == ROFF_CONT);
- ppos = pos;
- ctl = roff_getcontrol(r, *bufp, &pos);
+ ctl = roff_getcontrol(r, buf->buf, &pos);
/*
* First, if a scope is open and we're not a macro, pass the
- * text through the macro's filter. If a scope isn't open and
- * we're not a macro, just let it through.
- * Finally, if there's an equation scope open, divert it into it
- * no matter our state.
+ * text through the macro's filter.
+ * Equations process all content themselves.
+ * Tables process almost all content themselves, but we want
+ * to warn about macros before passing it there.
*/
- if (r->last && ! ctl) {
+ if (r->last != NULL && ! ctl) {
t = r->last->tok;
assert(roffs[t].text);
- e = (*roffs[t].text)
- (r, t, bufp, szp, ln, pos, pos, offs);
- assert(ROFF_IGN == e || ROFF_CONT == e);
- if (ROFF_CONT != e)
+ e = (*roffs[t].text)(r, t, buf, ln, pos, pos, offs);
+ assert(e == ROFF_IGN || e == ROFF_CONT);
+ if (e != ROFF_CONT)
return(e);
}
- if (r->eqn)
- return(eqn_read(&r->eqn, ln, *bufp, ppos, offs));
- if ( ! ctl) {
- if (r->tbl)
- return(tbl_read(r->tbl, ln, *bufp, pos));
- return(roff_parsetext(bufp, szp, pos, offs));
- }
+ if (r->eqn != NULL)
+ return(eqn_read(&r->eqn, ln, buf->buf, ppos, offs));
+ if (r->tbl != NULL && ( ! ctl || buf->buf[pos] == '\0'))
+ return(tbl_read(r->tbl, ln, buf->buf, ppos));
+ if ( ! ctl)
+ return(roff_parsetext(buf, pos, offs));
+
+ /* Skip empty request lines. */
+
+ if (buf->buf[pos] == '"') {
+ mandoc_msg(MANDOCERR_COMMENT_BAD, r->parse,
+ ln, pos, NULL);
+ return(ROFF_IGN);
+ } else if (buf->buf[pos] == '\0')
+ return(ROFF_IGN);
/*
* If a scope is open, go to the child handler for that macro,
@@ -735,44 +1228,60 @@ roff_parseln(struct roff *r, int ln, char **bufp,
if (r->last) {
t = r->last->tok;
assert(roffs[t].sub);
- return((*roffs[t].sub)
- (r, t, bufp, szp,
- ln, ppos, pos, offs));
+ return((*roffs[t].sub)(r, t, buf, ln, ppos, pos, offs));
+ }
+
+ /* No scope is open. This is a new request or macro. */
+
+ spos = pos;
+ t = roff_parse(r, buf->buf, &pos, ln, ppos);
+
+ /* Tables ignore most macros. */
+
+ if (r->tbl != NULL && (t == ROFF_MAX || t == ROFF_TS)) {
+ mandoc_msg(MANDOCERR_TBLMACRO, r->parse,
+ ln, pos, buf->buf + spos);
+ if (t == ROFF_TS)
+ return(ROFF_IGN);
+ while (buf->buf[pos] != '\0' && buf->buf[pos] != ' ')
+ pos++;
+ while (buf->buf[pos] != '\0' && buf->buf[pos] == ' ')
+ pos++;
+ return(tbl_read(r->tbl, ln, buf->buf, pos));
}
/*
- * Lastly, as we've no scope open, try to look up and execute
- * the new macro. If no macro is found, simply return and let
- * the compilers handle it.
+ * This is neither a roff request nor a user-defined macro.
+ * Let the standard macro set parsers handle it.
*/
- if (ROFF_MAX == (t = roff_parse(r, *bufp, &pos)))
+ if (t == ROFF_MAX)
return(ROFF_CONT);
+ /* Execute a roff request or a user defined macro. */
+
assert(roffs[t].proc);
- return((*roffs[t].proc)
- (r, t, bufp, szp,
- ln, ppos, pos, offs));
+ return((*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs));
}
-
void
roff_endparse(struct roff *r)
{
if (r->last)
- mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
- r->last->line, r->last->col, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOEND, r->parse,
+ r->last->line, r->last->col,
+ roffs[r->last->tok].name);
if (r->eqn) {
- mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
- r->eqn->eqn.ln, r->eqn->eqn.pos, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOEND, r->parse,
+ r->eqn->eqn.ln, r->eqn->eqn.pos, "EQ");
eqn_end(&r->eqn);
}
if (r->tbl) {
- mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse,
- r->tbl->line, r->tbl->pos, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOEND, r->parse,
+ r->tbl->line, r->tbl->pos, "TS");
tbl_end(&r->tbl);
}
}
@@ -782,37 +1291,30 @@ roff_endparse(struct roff *r)
* form of ".foo xxx" in the usual way.
*/
static enum rofft
-roff_parse(struct roff *r, const char *buf, int *pos)
+roff_parse(struct roff *r, char *buf, int *pos, int ln, int ppos)
{
+ char *cp;
const char *mac;
size_t maclen;
enum rofft t;
- if ('\0' == buf[*pos] || '"' == buf[*pos] ||
- '\t' == buf[*pos] || ' ' == buf[*pos])
- return(ROFF_MAX);
+ cp = buf + *pos;
- /*
- * We stop the macro parse at an escape, tab, space, or nil.
- * However, `\}' is also a valid macro, so make sure we don't
- * clobber it by seeing the `\' as the end of token.
- */
+ if ('\0' == *cp || '"' == *cp || '\t' == *cp || ' ' == *cp)
+ return(ROFF_MAX);
- mac = buf + *pos;
- maclen = strcspn(mac + 1, " \\\t\0") + 1;
+ mac = cp;
+ maclen = roff_getname(r, &cp, ln, ppos);
t = (r->current_string = roff_getstrn(r, mac, maclen))
? ROFF_USERDEF : roffhash_find(mac, maclen);
- *pos += (int)maclen;
-
- while (buf[*pos] && ' ' == buf[*pos])
- (*pos)++;
+ if (ROFF_MAX != t)
+ *pos = cp - buf;
return(t);
}
-/* ARGSUSED */
static enum rofferr
roff_cblock(ROFF_ARGS)
{
@@ -822,32 +1324,34 @@ roff_cblock(ROFF_ARGS)
* ignore macro, otherwise raise a warning and just ignore it.
*/
- if (NULL == r->last) {
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+ if (r->last == NULL) {
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+ ln, ppos, "..");
return(ROFF_IGN);
}
switch (r->last->tok) {
- case (ROFF_am):
+ case ROFF_am:
+ /* ROFF_am1 is remapped to ROFF_am in roff_block(). */
/* FALLTHROUGH */
- case (ROFF_ami):
+ case ROFF_ami:
/* FALLTHROUGH */
- case (ROFF_am1):
- /* FALLTHROUGH */
- case (ROFF_de):
+ case ROFF_de:
/* ROFF_de1 is remapped to ROFF_de in roff_block(). */
/* FALLTHROUGH */
- case (ROFF_dei):
+ case ROFF_dei:
/* FALLTHROUGH */
- case (ROFF_ig):
+ case ROFF_ig:
break;
default:
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+ ln, ppos, "..");
return(ROFF_IGN);
}
- if ((*bufp)[pos])
- mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
+ if (buf->buf[pos] != '\0')
+ mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos,
+ ".. %s", buf->buf + pos);
roffnode_pop(r);
roffnode_cleanscope(r);
@@ -855,7 +1359,6 @@ roff_cblock(ROFF_ARGS)
}
-
static void
roffnode_cleanscope(struct roff *r)
{
@@ -867,77 +1370,87 @@ roffnode_cleanscope(struct roff *r)
}
}
-
-/* ARGSUSED */
-static enum rofferr
-roff_ccond(ROFF_ARGS)
+static void
+roff_ccond(struct roff *r, int ln, int ppos)
{
if (NULL == r->last) {
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
- return(ROFF_IGN);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+ ln, ppos, "\\}");
+ return;
}
switch (r->last->tok) {
- case (ROFF_el):
+ case ROFF_el:
/* FALLTHROUGH */
- case (ROFF_ie):
+ case ROFF_ie:
/* FALLTHROUGH */
- case (ROFF_if):
+ case ROFF_if:
break;
default:
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
- return(ROFF_IGN);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+ ln, ppos, "\\}");
+ return;
}
if (r->last->endspan > -1) {
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
- return(ROFF_IGN);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+ ln, ppos, "\\}");
+ return;
}
- if ((*bufp)[pos])
- mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
-
roffnode_pop(r);
roffnode_cleanscope(r);
- return(ROFF_IGN);
+ return;
}
-
-/* ARGSUSED */
static enum rofferr
roff_block(ROFF_ARGS)
{
- int sv;
- size_t sz;
- char *name;
-
- name = NULL;
-
- if (ROFF_ig != tok) {
- if ('\0' == (*bufp)[pos]) {
- mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL);
- return(ROFF_IGN);
- }
-
- /*
- * Re-write `de1', since we don't really care about
- * groff's strange compatibility mode, into `de'.
- */
+ const char *name;
+ char *iname, *cp;
+ size_t namesz;
+
+ /* Ignore groff compatibility mode for now. */
+
+ if (tok == ROFF_de1)
+ tok = ROFF_de;
+ else if (tok == ROFF_dei1)
+ tok = ROFF_dei;
+ else if (tok == ROFF_am1)
+ tok = ROFF_am;
+ else if (tok == ROFF_ami1)
+ tok = ROFF_ami;
+
+ /* Parse the macro name argument. */
+
+ cp = buf->buf + pos;
+ if (tok == ROFF_ig) {
+ iname = NULL;
+ namesz = 0;
+ } else {
+ iname = cp;
+ namesz = roff_getname(r, &cp, ln, ppos);
+ iname[namesz] = '\0';
+ }
- if (ROFF_de1 == tok)
- tok = ROFF_de;
- if (ROFF_de == tok)
- name = *bufp + pos;
- else
- mandoc_msg(MANDOCERR_REQUEST, r->parse, ln, ppos,
- roffs[tok].name);
+ /* Resolve the macro name argument if it is indirect. */
- while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos]))
- pos++;
+ if (namesz && (tok == ROFF_dei || tok == ROFF_ami)) {
+ if ((name = roff_getstrn(r, iname, namesz)) == NULL) {
+ mandoc_vmsg(MANDOCERR_STR_UNDEF,
+ r->parse, ln, (int)(iname - buf->buf),
+ "%.*s", (int)namesz, iname);
+ namesz = 0;
+ } else
+ namesz = strlen(name);
+ } else
+ name = iname;
- while (isspace((unsigned char)(*bufp)[pos]))
- (*bufp)[pos++] = '\0';
+ if (namesz == 0 && tok != ROFF_ig) {
+ mandoc_msg(MANDOCERR_REQ_EMPTY, r->parse,
+ ln, ppos, roffs[tok].name);
+ return(ROFF_IGN);
}
roffnode_push(r, tok, name, ln, ppos);
@@ -945,46 +1458,43 @@ roff_block(ROFF_ARGS)
/*
* At the beginning of a `de' macro, clear the existing string
* with the same name, if there is one. New content will be
- * added from roff_block_text() in multiline mode.
+ * appended from roff_block_text() in multiline mode.
*/
- if (ROFF_de == tok)
- roff_setstr(r, name, "", 0);
+ if (tok == ROFF_de || tok == ROFF_dei)
+ roff_setstrn(&r->strtab, name, namesz, "", 0, 0);
- if ('\0' == (*bufp)[pos])
+ if (*cp == '\0')
return(ROFF_IGN);
- /* If present, process the custom end-of-line marker. */
+ /* Get the custom end marker. */
- sv = pos;
- while ((*bufp)[pos] && ! isspace((unsigned char)(*bufp)[pos]))
- pos++;
+ iname = cp;
+ namesz = roff_getname(r, &cp, ln, ppos);
- /*
- * Note: groff does NOT like escape characters in the input.
- * Instead of detecting this, we're just going to let it fly and
- * to hell with it.
- */
+ /* Resolve the end marker if it is indirect. */
- assert(pos > sv);
- sz = (size_t)(pos - sv);
-
- if (1 == sz && '.' == (*bufp)[sv])
- return(ROFF_IGN);
-
- r->last->end = mandoc_malloc(sz + 1);
+ if (namesz && (tok == ROFF_dei || tok == ROFF_ami)) {
+ if ((name = roff_getstrn(r, iname, namesz)) == NULL) {
+ mandoc_vmsg(MANDOCERR_STR_UNDEF,
+ r->parse, ln, (int)(iname - buf->buf),
+ "%.*s", (int)namesz, iname);
+ namesz = 0;
+ } else
+ namesz = strlen(name);
+ } else
+ name = iname;
- memcpy(r->last->end, *bufp + sv, sz);
- r->last->end[(int)sz] = '\0';
+ if (namesz)
+ r->last->end = mandoc_strndup(name, namesz);
- if ((*bufp)[pos])
- mandoc_msg(MANDOCERR_ARGSLOST, r->parse, ln, pos, NULL);
+ if (*cp != '\0')
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse,
+ ln, pos, ".%s ... %s", roffs[tok].name, cp);
return(ROFF_IGN);
}
-
-/* ARGSUSED */
static enum rofferr
roff_block_sub(ROFF_ARGS)
{
@@ -1002,21 +1512,22 @@ roff_block_sub(ROFF_ARGS)
if (r->last->end) {
for (i = pos, j = 0; r->last->end[j]; j++, i++)
- if ((*bufp)[i] != r->last->end[j])
+ if (buf->buf[i] != r->last->end[j])
break;
- if ('\0' == r->last->end[j] &&
- ('\0' == (*bufp)[i] ||
- ' ' == (*bufp)[i] ||
- '\t' == (*bufp)[i])) {
+ if (r->last->end[j] == '\0' &&
+ (buf->buf[i] == '\0' ||
+ buf->buf[i] == ' ' ||
+ buf->buf[i] == '\t')) {
roffnode_pop(r);
roffnode_cleanscope(r);
- while (' ' == (*bufp)[i] || '\t' == (*bufp)[i])
+ while (buf->buf[i] == ' ' || buf->buf[i] == '\t')
i++;
pos = i;
- if (ROFF_MAX != roff_parse(r, *bufp, &pos))
+ if (roff_parse(r, buf->buf, &pos, ln, ppos) !=
+ ROFF_MAX)
return(ROFF_RERUN);
return(ROFF_IGN);
}
@@ -1027,220 +1538,259 @@ roff_block_sub(ROFF_ARGS)
* pulling it out of the hashtable.
*/
- t = roff_parse(r, *bufp, &pos);
+ t = roff_parse(r, buf->buf, &pos, ln, ppos);
- /*
- * Macros other than block-end are only significant
- * in `de' blocks; elsewhere, simply throw them away.
- */
- if (ROFF_cblock != t) {
- if (ROFF_de == tok)
- roff_setstr(r, r->last->name, *bufp + ppos, 1);
+ if (t != ROFF_cblock) {
+ if (tok != ROFF_ig)
+ roff_setstr(r, r->last->name, buf->buf + ppos, 2);
return(ROFF_IGN);
}
assert(roffs[t].proc);
- return((*roffs[t].proc)(r, t, bufp, szp,
- ln, ppos, pos, offs));
+ return((*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs));
}
-
-/* ARGSUSED */
static enum rofferr
roff_block_text(ROFF_ARGS)
{
- if (ROFF_de == tok)
- roff_setstr(r, r->last->name, *bufp + pos, 1);
+ if (tok != ROFF_ig)
+ roff_setstr(r, r->last->name, buf->buf + pos, 2);
return(ROFF_IGN);
}
-
-/* ARGSUSED */
static enum rofferr
roff_cond_sub(ROFF_ARGS)
{
enum rofft t;
- enum roffrule rr;
char *ep;
+ int rr;
rr = r->last->rule;
roffnode_cleanscope(r);
- t = roff_parse(r, *bufp, &pos);
+ t = roff_parse(r, buf->buf, &pos, ln, ppos);
/*
* Fully handle known macros when they are structurally
* required or when the conditional evaluated to true.
*/
- if ((ROFF_MAX != t) &&
- (ROFF_ccond == t || ROFFRULE_ALLOW == rr ||
- ROFFMAC_STRUCT & roffs[t].flags)) {
+ if ((t != ROFF_MAX) &&
+ (rr || roffs[t].flags & ROFFMAC_STRUCT)) {
assert(roffs[t].proc);
- return((*roffs[t].proc)(r, t, bufp, szp,
- ln, ppos, pos, offs));
+ return((*roffs[t].proc)(r, t, buf, ln, ppos, pos, offs));
}
- /* Always check for the closing delimiter `\}'. */
-
- ep = &(*bufp)[pos];
- while (NULL != (ep = strchr(ep, '\\'))) {
- if ('}' != *(++ep))
- continue;
+ /*
+ * If `\}' occurs on a macro line without a preceding macro,
+ * drop the line completely.
+ */
- /*
- * If we're at the end of line, then just chop
- * off the \} and resize the buffer.
- * If we aren't, then convert it to spaces.
- */
+ ep = buf->buf + pos;
+ if (ep[0] == '\\' && ep[1] == '}')
+ rr = 0;
- if ('\0' == *(ep + 1)) {
- *--ep = '\0';
- *szp -= 2;
- } else
- *(ep - 1) = *ep = ' ';
+ /* Always check for the closing delimiter `\}'. */
- roff_ccond(r, ROFF_ccond, bufp, szp,
- ln, pos, pos + 2, offs);
- break;
+ while ((ep = strchr(ep, '\\')) != NULL) {
+ if (*(++ep) == '}') {
+ *ep = '&';
+ roff_ccond(r, ln, ep - buf->buf - 1);
+ }
+ if (*ep != '\0')
+ ++ep;
}
- return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
+ return(rr ? ROFF_CONT : ROFF_IGN);
}
-/* ARGSUSED */
static enum rofferr
roff_cond_text(ROFF_ARGS)
{
char *ep;
- enum roffrule rr;
+ int rr;
rr = r->last->rule;
roffnode_cleanscope(r);
- ep = &(*bufp)[pos];
- for ( ; NULL != (ep = strchr(ep, '\\')); ep++) {
- ep++;
- if ('}' != *ep)
- continue;
- *ep = '&';
- roff_ccond(r, ROFF_ccond, bufp, szp,
- ln, pos, pos + 2, offs);
+ ep = buf->buf + pos;
+ while ((ep = strchr(ep, '\\')) != NULL) {
+ if (*(++ep) == '}') {
+ *ep = '&';
+ roff_ccond(r, ln, ep - buf->buf - 1);
+ }
+ if (*ep != '\0')
+ ++ep;
}
- return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
+ return(rr ? ROFF_CONT : ROFF_IGN);
}
+/*
+ * Parse a single signed integer number. Stop at the first non-digit.
+ * If there is at least one digit, return success and advance the
+ * parse point, else return failure and let the parse point unchanged.
+ * Ignore overflows, treat them just like the C language.
+ */
static int
-roff_getnum(const char *v, int *pos, int *res)
+roff_getnum(const char *v, int *pos, int *res, int flags)
{
- int p, n;
+ int myres, scaled, n, p;
+
+ if (NULL == res)
+ res = &myres;
p = *pos;
n = v[p] == '-';
- if (n)
+ if (n || v[p] == '+')
p++;
+ if (flags & ROFFNUM_WHITE)
+ while (isspace((unsigned char)v[p]))
+ p++;
+
for (*res = 0; isdigit((unsigned char)v[p]); p++)
- *res += 10 * *res + v[p] - '0';
+ *res = 10 * *res + v[p] - '0';
if (p == *pos + n)
return 0;
if (n)
*res = -*res;
- *pos = p;
- return 1;
-}
-
-static int
-roff_getop(const char *v, int *pos, char *res)
-{
- int e;
-
- *res = v[*pos];
- e = v[*pos + 1] == '=';
+ /* Each number may be followed by one optional scaling unit. */
- switch (*res) {
- case '=':
+ switch (v[p]) {
+ case 'f':
+ scaled = *res * 65536;
break;
- case '>':
- if (e)
- *res = 'g';
+ case 'i':
+ scaled = *res * 240;
break;
- case '<':
- if (e)
- *res = 'l';
+ case 'c':
+ scaled = *res * 240 / 2.54;
+ break;
+ case 'v':
+ /* FALLTROUGH */
+ case 'P':
+ scaled = *res * 40;
+ break;
+ case 'm':
+ /* FALLTROUGH */
+ case 'n':
+ scaled = *res * 24;
+ break;
+ case 'p':
+ scaled = *res * 10 / 3;
+ break;
+ case 'u':
+ scaled = *res;
+ break;
+ case 'M':
+ scaled = *res * 6 / 25;
break;
default:
- return(0);
+ scaled = *res;
+ p--;
+ break;
}
+ if (flags & ROFFNUM_SCALE)
+ *res = scaled;
- *pos += 1 + e;
+ *pos = p + 1;
+ return(1);
+}
- return(*res);
+/*
+ * Evaluate a string comparison condition.
+ * The first character is the delimiter.
+ * Succeed if the string up to its second occurrence
+ * matches the string up to its third occurence.
+ * Advance the cursor after the third occurrence
+ * or lacking that, to the end of the line.
+ */
+static int
+roff_evalstrcond(const char *v, int *pos)
+{
+ const char *s1, *s2, *s3;
+ int match;
+
+ match = 0;
+ s1 = v + *pos; /* initial delimiter */
+ s2 = s1 + 1; /* for scanning the first string */
+ s3 = strchr(s2, *s1); /* for scanning the second string */
+
+ if (NULL == s3) /* found no middle delimiter */
+ goto out;
+
+ while ('\0' != *++s3) {
+ if (*s2 != *s3) { /* mismatch */
+ s3 = strchr(s3, *s1);
+ break;
+ }
+ if (*s3 == *s1) { /* found the final delimiter */
+ match = 1;
+ break;
+ }
+ s2++;
+ }
+
+out:
+ if (NULL == s3)
+ s3 = strchr(s2, '\0');
+ else if (*s3 != '\0')
+ s3++;
+ *pos = s3 - v;
+ return(match);
}
-static enum roffrule
-roff_evalcond(const char *v, int *pos)
+/*
+ * Evaluate an optionally negated single character, numerical,
+ * or string condition.
+ */
+static int
+roff_evalcond(struct roff *r, int ln, const char *v, int *pos)
{
- int not, lh, rh;
- char op;
+ int number, savepos, wanttrue;
+
+ if ('!' == v[*pos]) {
+ wanttrue = 0;
+ (*pos)++;
+ } else
+ wanttrue = 1;
switch (v[*pos]) {
- case ('n'):
+ case '\0':
+ return(0);
+ case 'n':
+ /* FALLTHROUGH */
+ case 'o':
(*pos)++;
- return(ROFFRULE_ALLOW);
- case ('e'):
+ return(wanttrue);
+ case 'c':
/* FALLTHROUGH */
- case ('o'):
+ case 'd':
/* FALLTHROUGH */
- case ('t'):
- (*pos)++;
- return(ROFFRULE_DENY);
- case ('!'):
+ case 'e':
+ /* FALLTHROUGH */
+ case 'r':
+ /* FALLTHROUGH */
+ case 't':
+ /* FALLTHROUGH */
+ case 'v':
(*pos)++;
- not = 1;
- break;
+ return(!wanttrue);
default:
- not = 0;
break;
}
- if (!roff_getnum(v, pos, &lh))
- return ROFFRULE_DENY;
- if (!roff_getop(v, pos, &op)) {
- if (lh < 0)
- lh = 0;
- goto out;
- }
- if (!roff_getnum(v, pos, &rh))
- return ROFFRULE_DENY;
- switch (op) {
- case 'g':
- lh = lh >= rh;
- break;
- case 'l':
- lh = lh <= rh;
- break;
- case '=':
- lh = lh == rh;
- break;
- case '>':
- lh = lh > rh;
- break;
- case '<':
- lh = lh < rh;
- break;
- default:
- return ROFFRULE_DENY;
- }
-out:
- if (not)
- lh = !lh;
- return lh ? ROFFRULE_ALLOW : ROFFRULE_DENY;
+ savepos = *pos;
+ if (roff_evalnum(r, ln, v, pos, &number, ROFFNUM_SCALE))
+ return((number > 0) == wanttrue);
+ else if (*pos == savepos)
+ return(roff_evalstrcond(v, pos) == wanttrue);
+ else
+ return (0);
}
-/* ARGSUSED */
static enum rofferr
roff_line_ignore(ROFF_ARGS)
{
@@ -1248,46 +1798,60 @@ roff_line_ignore(ROFF_ARGS)
return(ROFF_IGN);
}
-/* ARGSUSED */
+static enum rofferr
+roff_insec(ROFF_ARGS)
+{
+
+ mandoc_msg(MANDOCERR_REQ_INSEC, r->parse,
+ ln, ppos, roffs[tok].name);
+ return(ROFF_IGN);
+}
+
+static enum rofferr
+roff_unsupp(ROFF_ARGS)
+{
+
+ mandoc_msg(MANDOCERR_REQ_UNSUPP, r->parse,
+ ln, ppos, roffs[tok].name);
+ return(ROFF_IGN);
+}
+
static enum rofferr
roff_cond(ROFF_ARGS)
{
roffnode_push(r, tok, NULL, ln, ppos);
- /*
+ /*
* An `.el' has no conditional body: it will consume the value
* of the current rstack entry set in prior `ie' calls or
- * defaults to DENY.
+ * defaults to DENY.
*
* If we're not an `el', however, then evaluate the conditional.
*/
- r->last->rule = ROFF_el == tok ?
- (r->rstackpos < 0 ?
- ROFFRULE_DENY : r->rstack[r->rstackpos--]) :
- roff_evalcond(*bufp, &pos);
+ r->last->rule = tok == ROFF_el ?
+ (r->rstackpos < 0 ? 0 : r->rstack[r->rstackpos--]) :
+ roff_evalcond(r, ln, buf->buf, &pos);
/*
* An if-else will put the NEGATION of the current evaluated
* conditional into the stack of rules.
*/
- if (ROFF_ie == tok) {
- if (r->rstackpos == RSTACK_MAX - 1) {
- mandoc_msg(MANDOCERR_MEM,
- r->parse, ln, ppos, NULL);
- return(ROFF_ERR);
+ if (tok == ROFF_ie) {
+ if (r->rstackpos + 1 == r->rstacksz) {
+ r->rstacksz += 16;
+ r->rstack = mandoc_reallocarray(r->rstack,
+ r->rstacksz, sizeof(int));
}
- r->rstack[++r->rstackpos] =
- ROFFRULE_DENY == r->last->rule ?
- ROFFRULE_ALLOW : ROFFRULE_DENY;
+ r->rstack[++r->rstackpos] = !r->last->rule;
}
/* If the parent has false as its rule, then so do we. */
- if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule)
- r->last->rule = ROFFRULE_DENY;
+ if (r->last->parent && !r->last->parent->rule)
+ r->last->rule = 0;
/*
* Determine scope.
@@ -1295,21 +1859,21 @@ roff_cond(ROFF_ARGS)
* not even whitespace, use next-line scope.
*/
- if ('\0' == (*bufp)[pos]) {
+ if (buf->buf[pos] == '\0') {
r->last->endspan = 2;
goto out;
}
- while (' ' == (*bufp)[pos])
+ while (buf->buf[pos] == ' ')
pos++;
/* An opening brace requests multiline scope. */
- if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) {
+ if (buf->buf[pos] == '\\' && buf->buf[pos + 1] == '{') {
r->last->endspan = -1;
pos += 2;
goto out;
- }
+ }
/*
* Anything else following the conditional causes
@@ -1317,8 +1881,9 @@ roff_cond(ROFF_ARGS)
* nothing but trailing whitespace.
*/
- if ('\0' == (*bufp)[pos])
- mandoc_msg(MANDOCERR_NOARGS, r->parse, ln, ppos, NULL);
+ if (buf->buf[pos] == '\0')
+ mandoc_msg(MANDOCERR_COND_EMPTY, r->parse,
+ ln, ppos, roffs[tok].name);
r->last->endspan = 1;
@@ -1327,37 +1892,256 @@ out:
return(ROFF_RERUN);
}
-
-/* ARGSUSED */
static enum rofferr
roff_ds(ROFF_ARGS)
{
- char *name, *string;
+ char *string;
+ const char *name;
+ size_t namesz;
+
+ /* Ignore groff compatibility mode for now. */
+
+ if (tok == ROFF_ds1)
+ tok = ROFF_ds;
+ else if (tok == ROFF_as1)
+ tok = ROFF_as;
/*
- * A symbol is named by the first word following the macro
- * invocation up to a space. Its value is anything after the
- * name's trailing whitespace and optional double-quote. Thus,
- *
- * [.ds foo "bar " ]
- *
- * will have `bar " ' as its value.
+ * The first word is the name of the string.
+ * If it is empty or terminated by an escape sequence,
+ * abort the `ds' request without defining anything.
*/
- string = *bufp + pos;
- name = roff_getname(r, &string, ln, pos);
- if ('\0' == *name)
+ name = string = buf->buf + pos;
+ if (*name == '\0')
return(ROFF_IGN);
- /* Read past initial double-quote. */
- if ('"' == *string)
+ namesz = roff_getname(r, &string, ln, pos);
+ if (name[namesz] == '\\')
+ return(ROFF_IGN);
+
+ /* Read past the initial double-quote, if any. */
+ if (*string == '"')
string++;
/* The rest is the value. */
- roff_setstr(r, name, string, 0);
+ roff_setstrn(&r->strtab, name, namesz, string, strlen(string),
+ ROFF_as == tok);
return(ROFF_IGN);
}
+/*
+ * Parse a single operator, one or two characters long.
+ * If the operator is recognized, return success and advance the
+ * parse point, else return failure and let the parse point unchanged.
+ */
+static int
+roff_getop(const char *v, int *pos, char *res)
+{
+
+ *res = v[*pos];
+
+ switch (*res) {
+ case '+':
+ /* FALLTHROUGH */
+ case '-':
+ /* FALLTHROUGH */
+ case '*':
+ /* FALLTHROUGH */
+ case '/':
+ /* FALLTHROUGH */
+ case '%':
+ /* FALLTHROUGH */
+ case '&':
+ /* FALLTHROUGH */
+ case ':':
+ break;
+ case '<':
+ switch (v[*pos + 1]) {
+ case '=':
+ *res = 'l';
+ (*pos)++;
+ break;
+ case '>':
+ *res = '!';
+ (*pos)++;
+ break;
+ case '?':
+ *res = 'i';
+ (*pos)++;
+ break;
+ default:
+ break;
+ }
+ break;
+ case '>':
+ switch (v[*pos + 1]) {
+ case '=':
+ *res = 'g';
+ (*pos)++;
+ break;
+ case '?':
+ *res = 'a';
+ (*pos)++;
+ break;
+ default:
+ break;
+ }
+ break;
+ case '=':
+ if ('=' == v[*pos + 1])
+ (*pos)++;
+ break;
+ default:
+ return(0);
+ }
+ (*pos)++;
+
+ return(*res);
+}
+
+/*
+ * Evaluate either a parenthesized numeric expression
+ * or a single signed integer number.
+ */
+static int
+roff_evalpar(struct roff *r, int ln,
+ const char *v, int *pos, int *res, int flags)
+{
+
+ if ('(' != v[*pos])
+ return(roff_getnum(v, pos, res, flags));
+
+ (*pos)++;
+ if ( ! roff_evalnum(r, ln, v, pos, res, flags | ROFFNUM_WHITE))
+ return(0);
+
+ /*
+ * Omission of the closing parenthesis
+ * is an error in validation mode,
+ * but ignored in evaluation mode.
+ */
+
+ if (')' == v[*pos])
+ (*pos)++;
+ else if (NULL == res)
+ return(0);
+
+ return(1);
+}
+
+/*
+ * Evaluate a complete numeric expression.
+ * Proceed left to right, there is no concept of precedence.
+ */
+static int
+roff_evalnum(struct roff *r, int ln, const char *v,
+ int *pos, int *res, int flags)
+{
+ int mypos, operand2;
+ char operator;
+
+ if (NULL == pos) {
+ mypos = 0;
+ pos = &mypos;
+ }
+
+ if (flags & ROFFNUM_WHITE)
+ while (isspace((unsigned char)v[*pos]))
+ (*pos)++;
+
+ if ( ! roff_evalpar(r, ln, v, pos, res, flags))
+ return(0);
+
+ while (1) {
+ if (flags & ROFFNUM_WHITE)
+ while (isspace((unsigned char)v[*pos]))
+ (*pos)++;
+
+ if ( ! roff_getop(v, pos, &operator))
+ break;
+
+ if (flags & ROFFNUM_WHITE)
+ while (isspace((unsigned char)v[*pos]))
+ (*pos)++;
+
+ if ( ! roff_evalpar(r, ln, v, pos, &operand2, flags))
+ return(0);
+
+ if (flags & ROFFNUM_WHITE)
+ while (isspace((unsigned char)v[*pos]))
+ (*pos)++;
+
+ if (NULL == res)
+ continue;
+
+ switch (operator) {
+ case '+':
+ *res += operand2;
+ break;
+ case '-':
+ *res -= operand2;
+ break;
+ case '*':
+ *res *= operand2;
+ break;
+ case '/':
+ if (operand2 == 0) {
+ mandoc_msg(MANDOCERR_DIVZERO,
+ r->parse, ln, *pos, v);
+ *res = 0;
+ break;
+ }
+ *res /= operand2;
+ break;
+ case '%':
+ if (operand2 == 0) {
+ mandoc_msg(MANDOCERR_DIVZERO,
+ r->parse, ln, *pos, v);
+ *res = 0;
+ break;
+ }
+ *res %= operand2;
+ break;
+ case '<':
+ *res = *res < operand2;
+ break;
+ case '>':
+ *res = *res > operand2;
+ break;
+ case 'l':
+ *res = *res <= operand2;
+ break;
+ case 'g':
+ *res = *res >= operand2;
+ break;
+ case '=':
+ *res = *res == operand2;
+ break;
+ case '!':
+ *res = *res != operand2;
+ break;
+ case '&':
+ *res = *res && operand2;
+ break;
+ case ':':
+ *res = *res || operand2;
+ break;
+ case 'i':
+ if (operand2 < *res)
+ *res = operand2;
+ break;
+ case 'a':
+ if (operand2 > *res)
+ *res = operand2;
+ break;
+ default:
+ abort();
+ }
+ }
+ return(1);
+}
+
void
roff_setreg(struct roff *r, const char *name, int val, char sign)
{
@@ -1387,10 +2171,45 @@ roff_setreg(struct roff *r, const char *name, int val, char sign)
reg->val = val;
}
+/*
+ * Handle some predefined read-only number registers.
+ * For now, return -1 if the requested register is not predefined;
+ * in case a predefined read-only register having the value -1
+ * were to turn up, another special value would have to be chosen.
+ */
+static int
+roff_getregro(const char *name)
+{
+
+ switch (*name) {
+ case 'A': /* ASCII approximation mode is always off. */
+ return(0);
+ case 'g': /* Groff compatibility mode is always on. */
+ return(1);
+ case 'H': /* Fixed horizontal resolution. */
+ return (24);
+ case 'j': /* Always adjust left margin only. */
+ return(0);
+ case 'T': /* Some output device is always defined. */
+ return(1);
+ case 'V': /* Fixed vertical resolution. */
+ return (40);
+ default:
+ return (-1);
+ }
+}
+
int
roff_getreg(const struct roff *r, const char *name)
{
struct roffreg *reg;
+ int val;
+
+ if ('.' == name[0] && '\0' != name[1] && '\0' == name[2]) {
+ val = roff_getregro(name + 1);
+ if (-1 != val)
+ return (val);
+ }
for (reg = r->regtab; reg; reg = reg->next)
if (0 == strcmp(name, reg->key.p))
@@ -1403,6 +2222,13 @@ static int
roff_getregn(const struct roff *r, const char *name, size_t len)
{
struct roffreg *reg;
+ int val;
+
+ if ('.' == name[0] && 2 == len) {
+ val = roff_getregro(name + 1);
+ if (-1 != val)
+ return (val);
+ }
for (reg = r->regtab; reg; reg = reg->next)
if (len == reg->key.sz &&
@@ -1425,182 +2251,274 @@ roff_freereg(struct roffreg *reg)
}
}
-/* ARGSUSED */
static enum rofferr
roff_nr(ROFF_ARGS)
{
- const char *key;
- char *val;
- size_t sz;
+ char *key, *val;
+ size_t keysz;
int iv;
char sign;
- val = *bufp + pos;
- key = roff_getname(r, &val, ln, pos);
+ key = val = buf->buf + pos;
+ if (*key == '\0')
+ return(ROFF_IGN);
+
+ keysz = roff_getname(r, &val, ln, pos);
+ if (key[keysz] == '\\')
+ return(ROFF_IGN);
+ key[keysz] = '\0';
sign = *val;
- if ('+' == sign || '-' == sign)
+ if (sign == '+' || sign == '-')
val++;
- sz = strspn(val, "0123456789");
- iv = sz ? mandoc_strntoi(val, sz, 10) : 0;
+ if (roff_evalnum(r, ln, val, NULL, &iv, ROFFNUM_SCALE))
+ roff_setreg(r, key, iv, sign);
- roff_setreg(r, key, iv, sign);
+ return(ROFF_IGN);
+}
+
+static enum rofferr
+roff_rr(ROFF_ARGS)
+{
+ struct roffreg *reg, **prev;
+ char *name, *cp;
+ size_t namesz;
+ name = cp = buf->buf + pos;
+ if (*name == '\0')
+ return(ROFF_IGN);
+ namesz = roff_getname(r, &cp, ln, pos);
+ name[namesz] = '\0';
+
+ prev = &r->regtab;
+ while (1) {
+ reg = *prev;
+ if (reg == NULL || !strcmp(name, reg->key.p))
+ break;
+ prev = &reg->next;
+ }
+ if (reg != NULL) {
+ *prev = reg->next;
+ free(reg->key.p);
+ free(reg);
+ }
return(ROFF_IGN);
}
-/* ARGSUSED */
static enum rofferr
roff_rm(ROFF_ARGS)
{
const char *name;
char *cp;
+ size_t namesz;
- cp = *bufp + pos;
- while ('\0' != *cp) {
- name = roff_getname(r, &cp, ln, (int)(cp - *bufp));
- if ('\0' != *name)
- roff_setstr(r, name, NULL, 0);
+ cp = buf->buf + pos;
+ while (*cp != '\0') {
+ name = cp;
+ namesz = roff_getname(r, &cp, ln, (int)(cp - buf->buf));
+ roff_setstrn(&r->strtab, name, namesz, NULL, 0, 0);
+ if (name[namesz] == '\\')
+ break;
}
return(ROFF_IGN);
}
-/* ARGSUSED */
static enum rofferr
roff_it(ROFF_ARGS)
{
- char *cp;
- size_t len;
int iv;
/* Parse the number of lines. */
- cp = *bufp + pos;
- len = strcspn(cp, " \t");
- cp[len] = '\0';
- if ((iv = mandoc_strntoi(cp, len, 10)) <= 0) {
- mandoc_msg(MANDOCERR_NUMERIC, r->parse,
- ln, ppos, *bufp + 1);
+
+ if ( ! roff_evalnum(r, ln, buf->buf, &pos, &iv, 0)) {
+ mandoc_msg(MANDOCERR_IT_NONUM, r->parse,
+ ln, ppos, buf->buf + 1);
return(ROFF_IGN);
}
- cp += len + 1;
- /* Arm the input line trap. */
+ while (isspace((unsigned char)buf->buf[pos]))
+ pos++;
+
+ /*
+ * Arm the input line trap.
+ * Special-casing "an-trap" is an ugly workaround to cope
+ * with DocBook stupidly fiddling with man(7) internals.
+ */
+
roffit_lines = iv;
- roffit_macro = mandoc_strdup(cp);
+ roffit_macro = mandoc_strdup(iv != 1 ||
+ strcmp(buf->buf + pos, "an-trap") ?
+ buf->buf + pos : "br");
return(ROFF_IGN);
}
-/* ARGSUSED */
static enum rofferr
roff_Dd(ROFF_ARGS)
{
const char *const *cp;
- if (MPARSE_MDOC != r->parsetype)
+ if ((r->options & (MPARSE_MDOC | MPARSE_QUICK)) == 0)
for (cp = __mdoc_reserved; *cp; cp++)
roff_setstr(r, *cp, NULL, 0);
+ if (r->format == 0)
+ r->format = MPARSE_MDOC;
+
return(ROFF_CONT);
}
-/* ARGSUSED */
static enum rofferr
roff_TH(ROFF_ARGS)
{
const char *const *cp;
- if (MPARSE_MDOC != r->parsetype)
+ if ((r->options & MPARSE_QUICK) == 0)
for (cp = __man_reserved; *cp; cp++)
roff_setstr(r, *cp, NULL, 0);
+ if (r->format == 0)
+ r->format = MPARSE_MAN;
+
return(ROFF_CONT);
}
-/* ARGSUSED */
static enum rofferr
roff_TE(ROFF_ARGS)
{
if (NULL == r->tbl)
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
- else
- tbl_end(&r->tbl);
-
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+ ln, ppos, "TE");
+ else if ( ! tbl_end(&r->tbl)) {
+ free(buf->buf);
+ buf->buf = mandoc_strdup(".sp");
+ buf->sz = 4;
+ return(ROFF_REPARSE);
+ }
return(ROFF_IGN);
}
-/* ARGSUSED */
static enum rofferr
roff_T_(ROFF_ARGS)
{
if (NULL == r->tbl)
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse,
+ ln, ppos, "T&");
else
tbl_restart(ppos, ln, r->tbl);
return(ROFF_IGN);
}
-#if 0
-static int
-roff_closeeqn(struct roff *r)
+/*
+ * Handle in-line equation delimiters.
+ */
+static enum rofferr
+roff_eqndelim(struct roff *r, struct buf *buf, int pos)
{
+ char *cp1, *cp2;
+ const char *bef_pr, *bef_nl, *mac, *aft_nl, *aft_pr;
- return(r->eqn && ROFF_EQN == eqn_end(&r->eqn) ? 1 : 0);
-}
-#endif
+ /*
+ * Outside equations, look for an opening delimiter.
+ * If we are inside an equation, we already know it is
+ * in-line, or this function wouldn't have been called;
+ * so look for a closing delimiter.
+ */
-static void
-roff_openeqn(struct roff *r, const char *name, int line,
- int offs, const char *buf)
-{
- struct eqn_node *e;
- int poff;
+ cp1 = buf->buf + pos;
+ cp2 = strchr(cp1, r->eqn == NULL ?
+ r->last_eqn->odelim : r->last_eqn->cdelim);
+ if (cp2 == NULL)
+ return(ROFF_CONT);
- assert(NULL == r->eqn);
- e = eqn_alloc(name, offs, line, r->parse);
+ *cp2++ = '\0';
+ bef_pr = bef_nl = aft_nl = aft_pr = "";
- if (r->last_eqn)
- r->last_eqn->next = e;
- else
- r->first_eqn = r->last_eqn = e;
+ /* Handle preceding text, protecting whitespace. */
- r->eqn = r->last_eqn = e;
+ if (*buf->buf != '\0') {
+ if (r->eqn == NULL)
+ bef_pr = "\\&";
+ bef_nl = "\n";
+ }
+
+ /*
+ * Prepare replacing the delimiter with an equation macro
+ * and drop leading white space from the equation.
+ */
+
+ if (r->eqn == NULL) {
+ while (*cp2 == ' ')
+ cp2++;
+ mac = ".EQ";
+ } else
+ mac = ".EN";
- if (buf) {
- poff = 0;
- eqn_read(&r->eqn, line, buf, offs, &poff);
+ /* Handle following text, protecting whitespace. */
+
+ if (*cp2 != '\0') {
+ aft_nl = "\n";
+ if (r->eqn != NULL)
+ aft_pr = "\\&";
}
+
+ /* Do the actual replacement. */
+
+ buf->sz = mandoc_asprintf(&cp1, "%s%s%s%s%s%s%s", buf->buf,
+ bef_pr, bef_nl, mac, aft_nl, aft_pr, cp2) + 1;
+ free(buf->buf);
+ buf->buf = cp1;
+
+ /* Toggle the in-line state of the eqn subsystem. */
+
+ r->eqn_inline = r->eqn == NULL;
+ return(ROFF_REPARSE);
}
-/* ARGSUSED */
static enum rofferr
roff_EQ(ROFF_ARGS)
{
+ struct eqn_node *e;
+
+ assert(r->eqn == NULL);
+ e = eqn_alloc(ppos, ln, r->parse);
+
+ if (r->last_eqn) {
+ r->last_eqn->next = e;
+ e->delim = r->last_eqn->delim;
+ e->odelim = r->last_eqn->odelim;
+ e->cdelim = r->last_eqn->cdelim;
+ } else
+ r->first_eqn = r->last_eqn = e;
+
+ r->eqn = r->last_eqn = e;
+
+ if (buf->buf[pos] != '\0')
+ mandoc_vmsg(MANDOCERR_ARG_SKIP, r->parse, ln, pos,
+ ".EQ %s", buf->buf + pos);
- roff_openeqn(r, *bufp + pos, ln, ppos, NULL);
return(ROFF_IGN);
}
-/* ARGSUSED */
static enum rofferr
roff_EN(ROFF_ARGS)
{
- mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
+ mandoc_msg(MANDOCERR_BLK_NOTOPEN, r->parse, ln, ppos, "EN");
return(ROFF_IGN);
}
-/* ARGSUSED */
static enum rofferr
roff_TS(ROFF_ARGS)
{
struct tbl_node *tbl;
if (r->tbl) {
- mandoc_msg(MANDOCERR_SCOPEBROKEN, r->parse, ln, ppos, NULL);
+ mandoc_msg(MANDOCERR_BLK_BROKEN, r->parse,
+ ln, ppos, "TS breaks TS");
tbl_end(&r->tbl);
}
@@ -1615,24 +2533,31 @@ roff_TS(ROFF_ARGS)
return(ROFF_IGN);
}
-/* ARGSUSED */
+static enum rofferr
+roff_brp(ROFF_ARGS)
+{
+
+ buf->buf[pos - 1] = '\0';
+ return(ROFF_CONT);
+}
+
static enum rofferr
roff_cc(ROFF_ARGS)
{
const char *p;
- p = *bufp + pos;
+ p = buf->buf + pos;
- if ('\0' == *p || '.' == (r->control = *p++))
+ if (*p == '\0' || (r->control = *p++) == '.')
r->control = 0;
- if ('\0' != *p)
- mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, ln, ppos, NULL);
+ if (*p != '\0')
+ mandoc_vmsg(MANDOCERR_ARG_EXCESS, r->parse,
+ ln, p - buf->buf, "cc ... %s", p);
return(ROFF_IGN);
}
-/* ARGSUSED */
static enum rofferr
roff_tr(ROFF_ARGS)
{
@@ -1640,54 +2565,52 @@ roff_tr(ROFF_ARGS)
size_t fsz, ssz;
enum mandoc_esc esc;
- p = *bufp + pos;
+ p = buf->buf + pos;
- if ('\0' == *p) {
- mandoc_msg(MANDOCERR_ARGCOUNT, r->parse, ln, ppos, NULL);
+ if (*p == '\0') {
+ mandoc_msg(MANDOCERR_REQ_EMPTY, r->parse, ln, ppos, "tr");
return(ROFF_IGN);
}
- while ('\0' != *p) {
+ while (*p != '\0') {
fsz = ssz = 1;
first = p++;
- if ('\\' == *first) {
+ if (*first == '\\') {
esc = mandoc_escape(&p, NULL, NULL);
- if (ESCAPE_ERROR == esc) {
- mandoc_msg
- (MANDOCERR_BADESCAPE, r->parse,
- ln, (int)(p - *bufp), NULL);
+ if (esc == ESCAPE_ERROR) {
+ mandoc_msg(MANDOCERR_ESC_BAD, r->parse,
+ ln, (int)(p - buf->buf), first);
return(ROFF_IGN);
}
fsz = (size_t)(p - first);
}
second = p++;
- if ('\\' == *second) {
+ if (*second == '\\') {
esc = mandoc_escape(&p, NULL, NULL);
- if (ESCAPE_ERROR == esc) {
- mandoc_msg
- (MANDOCERR_BADESCAPE, r->parse,
- ln, (int)(p - *bufp), NULL);
+ if (esc == ESCAPE_ERROR) {
+ mandoc_msg(MANDOCERR_ESC_BAD, r->parse,
+ ln, (int)(p - buf->buf), second);
return(ROFF_IGN);
}
ssz = (size_t)(p - second);
- } else if ('\0' == *second) {
- mandoc_msg(MANDOCERR_ARGCOUNT, r->parse,
- ln, (int)(p - *bufp), NULL);
+ } else if (*second == '\0') {
+ mandoc_vmsg(MANDOCERR_TR_ODD, r->parse,
+ ln, first - buf->buf, "tr %s", first);
second = " ";
p--;
}
if (fsz > 1) {
- roff_setstrn(&r->xmbtab, first,
- fsz, second, ssz, 0);
+ roff_setstrn(&r->xmbtab, first, fsz,
+ second, ssz, 0);
continue;
}
- if (NULL == r->xtab)
- r->xtab = mandoc_calloc
- (128, sizeof(struct roffstr));
+ if (r->xtab == NULL)
+ r->xtab = mandoc_calloc(128,
+ sizeof(struct roffstr));
free(r->xtab[(int)*first].p);
r->xtab[(int)*first].p = mandoc_strndup(second, ssz);
@@ -1697,13 +2620,13 @@ roff_tr(ROFF_ARGS)
return(ROFF_IGN);
}
-/* ARGSUSED */
static enum rofferr
roff_so(ROFF_ARGS)
{
- char *name;
+ char *name, *cp;
- mandoc_msg(MANDOCERR_SO, r->parse, ln, ppos, NULL);
+ name = buf->buf + pos;
+ mandoc_vmsg(MANDOCERR_SO, r->parse, ln, ppos, "so %s", name);
/*
* Handle `so'. Be EXTREMELY careful, as we shouldn't be
@@ -1712,122 +2635,188 @@ roff_so(ROFF_ARGS)
* or using absolute paths.
*/
- name = *bufp + pos;
- if ('/' == *name || strstr(name, "../") || strstr(name, "/..")) {
- mandoc_msg(MANDOCERR_SOPATH, r->parse, ln, pos, NULL);
- return(ROFF_ERR);
+ if (*name == '/' || strstr(name, "../") || strstr(name, "/..")) {
+ mandoc_vmsg(MANDOCERR_SO_PATH, r->parse, ln, ppos,
+ ".so %s", name);
+ buf->sz = mandoc_asprintf(&cp,
+ ".sp\nSee the file %s.\n.sp", name) + 1;
+ free(buf->buf);
+ buf->buf = cp;
+ *offs = 0;
+ return(ROFF_REPARSE);
}
*offs = pos;
return(ROFF_SO);
}
-/* ARGSUSED */
static enum rofferr
roff_userdef(ROFF_ARGS)
{
- const char *arg[9];
+ const char *arg[9], *ap;
char *cp, *n1, *n2;
int i;
+ size_t asz, rsz;
/*
* Collect pointers to macro argument strings
* and NUL-terminate them.
*/
- cp = *bufp + pos;
+
+ cp = buf->buf + pos;
for (i = 0; i < 9; i++)
- arg[i] = '\0' == *cp ? "" :
+ arg[i] = *cp == '\0' ? "" :
mandoc_getarg(r->parse, &cp, ln, &pos);
/*
* Expand macro arguments.
*/
- *szp = 0;
- n1 = cp = mandoc_strdup(r->current_string);
- while (NULL != (cp = strstr(cp, "\\$"))) {
- i = cp[2] - '1';
- if (0 > i || 8 < i) {
- /* Not an argument invocation. */
- cp += 2;
+
+ buf->sz = strlen(r->current_string) + 1;
+ n1 = cp = mandoc_malloc(buf->sz);
+ memcpy(n1, r->current_string, buf->sz);
+ while (*cp != '\0') {
+
+ /* Scan ahead for the next argument invocation. */
+
+ if (*cp++ != '\\')
continue;
+ if (*cp++ != '$')
+ continue;
+ i = *cp - '1';
+ if (0 > i || 8 < i)
+ continue;
+ cp -= 2;
+
+ /*
+ * Determine the size of the expanded argument,
+ * taking escaping of quotes into account.
+ */
+
+ asz = 0;
+ for (ap = arg[i]; *ap != '\0'; ap++) {
+ asz++;
+ if (*ap == '"')
+ asz += 3;
}
+ if (asz != 3) {
- *szp = strlen(n1) - 3 + strlen(arg[i]) + 1;
- n2 = mandoc_malloc(*szp);
+ /*
+ * Determine the size of the rest of the
+ * unexpanded macro, including the NUL.
+ */
- strlcpy(n2, n1, (size_t)(cp - n1 + 1));
- strlcat(n2, arg[i], *szp);
- strlcat(n2, cp + 3, *szp);
+ rsz = buf->sz - (cp - n1) - 3;
- cp = n2 + (cp - n1);
- free(n1);
- n1 = n2;
+ /*
+ * When shrinking, move before
+ * releasing the storage.
+ */
+
+ if (asz < 3)
+ memmove(cp + asz, cp + 3, rsz);
+
+ /*
+ * Resize the storage for the macro
+ * and readjust the parse pointer.
+ */
+
+ buf->sz += asz - 3;
+ n2 = mandoc_realloc(n1, buf->sz);
+ cp = n2 + (cp - n1);
+ n1 = n2;
+
+ /*
+ * When growing, make room
+ * for the expanded argument.
+ */
+
+ if (asz > 3)
+ memmove(cp + asz, cp + 3, rsz);
+ }
+
+ /* Copy the expanded argument, escaping quotes. */
+
+ n2 = cp;
+ for (ap = arg[i]; *ap != '\0'; ap++) {
+ if (*ap == '"') {
+ memcpy(n2, "\\(dq", 4);
+ n2 += 4;
+ } else
+ *n2++ = *ap;
+ }
}
/*
* Replace the macro invocation
* by the expanded macro.
*/
- free(*bufp);
- *bufp = n1;
- if (0 == *szp)
- *szp = strlen(*bufp) + 1;
- return(*szp > 1 && '\n' == (*bufp)[(int)*szp - 2] ?
+ free(buf->buf);
+ buf->buf = n1;
+ *offs = 0;
+
+ return(buf->sz > 1 && buf->buf[buf->sz - 2] == '\n' ?
ROFF_REPARSE : ROFF_APPEND);
}
-static char *
+static size_t
roff_getname(struct roff *r, char **cpp, int ln, int pos)
{
char *name, *cp;
+ size_t namesz;
name = *cpp;
if ('\0' == *name)
- return(name);
+ return(0);
- /* Read until end of name. */
- for (cp = name; '\0' != *cp && ' ' != *cp; cp++) {
+ /* Read until end of name and terminate it with NUL. */
+ for (cp = name; 1; cp++) {
+ if ('\0' == *cp || ' ' == *cp) {
+ namesz = cp - name;
+ break;
+ }
if ('\\' != *cp)
continue;
+ namesz = cp - name;
+ if ('{' == cp[1] || '}' == cp[1])
+ break;
cp++;
if ('\\' == *cp)
continue;
- mandoc_msg(MANDOCERR_NAMESC, r->parse, ln, pos, NULL);
- *cp = '\0';
- name = cp;
+ mandoc_vmsg(MANDOCERR_NAMESC, r->parse, ln, pos,
+ "%.*s", (int)(cp - name + 1), name);
+ mandoc_escape((const char **)&cp, NULL, NULL);
+ break;
}
- /* Nil-terminate name. */
- if ('\0' != *cp)
- *(cp++) = '\0';
-
/* Read past spaces. */
while (' ' == *cp)
cp++;
*cpp = cp;
- return(name);
+ return(namesz);
}
/*
* Store *string into the user-defined string called *name.
- * In multiline mode, append to an existing entry and append '\n';
- * else replace the existing entry, if there is one.
* To clear an existing entry, call with (*r, *name, NULL, 0).
+ * append == 0: replace mode
+ * append == 1: single-line append mode
+ * append == 2: multiline append mode, append '\n' after each call
*/
static void
roff_setstr(struct roff *r, const char *name, const char *string,
- int multiline)
+ int append)
{
roff_setstrn(&r->strtab, name, strlen(name), string,
- string ? strlen(string) : 0, multiline);
+ string ? strlen(string) : 0, append);
}
static void
roff_setstrn(struct roffkv **r, const char *name, size_t namesz,
- const char *string, size_t stringsz, int multiline)
+ const char *string, size_t stringsz, int append)
{
struct roffkv *n;
char *c;
@@ -1837,7 +2826,8 @@ roff_setstrn(struct roffkv **r, const char *name, size_t namesz,
/* Search for an existing string with the same name. */
n = *r;
- while (n && strcmp(name, n->key.p))
+ while (n && (namesz != n->key.sz ||
+ strncmp(n->key.p, name, namesz)))
n = n->next;
if (NULL == n) {
@@ -1849,8 +2839,7 @@ roff_setstrn(struct roffkv **r, const char *name, size_t namesz,
n->val.sz = 0;
n->next = *r;
*r = n;
- } else if (0 == multiline) {
- /* In multiline mode, append; else replace. */
+ } else if (0 == append) {
free(n->val.p);
n->val.p = NULL;
n->val.sz = 0;
@@ -1863,7 +2852,7 @@ roff_setstrn(struct roffkv **r, const char *name, size_t namesz,
* One additional byte for the '\n' in multiline mode,
* and one for the terminating '\0'.
*/
- newch = stringsz + (multiline ? 2u : 1u);
+ newch = stringsz + (1 < append ? 2u : 1u);
if (NULL == n->val.p) {
n->val.p = mandoc_malloc(newch);
@@ -1890,7 +2879,7 @@ roff_setstrn(struct roffkv **r, const char *name, size_t namesz,
}
/* Append terminating bytes. */
- if (multiline)
+ if (1 < append)
*c++ = '\n';
*c = '\0';
@@ -1901,12 +2890,18 @@ static const char *
roff_getstrn(const struct roff *r, const char *name, size_t len)
{
const struct roffkv *n;
+ int i;
for (n = r->strtab; n; n = n->next)
- if (0 == strncmp(name, n->key.p, len) &&
- '\0' == n->key.p[(int)len])
+ if (0 == strncmp(name, n->key.p, len) &&
+ '\0' == n->key.p[(int)len])
return(n->val.p);
+ for (i = 0; i < PREDEFS_MAX; i++)
+ if (0 == strncmp(name, predefs[i].name, len) &&
+ '\0' == predefs[i].name[(int)len])
+ return(predefs[i].str);
+
return(NULL);
}
@@ -1926,14 +2921,14 @@ roff_freestr(struct roffkv *r)
const struct tbl_span *
roff_span(const struct roff *r)
{
-
+
return(r->tbl ? tbl_span(r->tbl) : NULL);
}
const struct eqn *
roff_eqn(const struct roff *r)
{
-
+
return(r->last_eqn ? &r->last_eqn->eqn : NULL);
}
@@ -1992,8 +2987,8 @@ roff_strdup(const struct roff *r, const char *p)
* Append the match to the array and move
* forward by its keysize.
*/
- res = mandoc_realloc
- (res, ssz + cp->val.sz + 1);
+ res = mandoc_realloc(res,
+ ssz + cp->val.sz + 1);
memcpy(res + ssz, cp->val.p, cp->val.sz);
ssz += cp->val.sz;
p += (int)cp->key.sz;
@@ -2014,8 +3009,8 @@ roff_strdup(const struct roff *r, const char *p)
memcpy(res + ssz, pp, sz);
break;
}
- /*
- * We bail out on bad escapes.
+ /*
+ * We bail out on bad escapes.
* No need to warn: we already did so when
* roff_res() was called.
*/
@@ -2029,8 +3024,15 @@ roff_strdup(const struct roff *r, const char *p)
return(res);
}
+int
+roff_getformat(const struct roff *r)
+{
+
+ return(r->format);
+}
+
/*
- * Find out whether a line is a macro line or not.
+ * Find out whether a line is a macro line or not.
* If it is, adjust the current position and return one; if it isn't,
* return zero and don't change the current position.
* If the control character has been set with `.cc', then let that grain
diff --git a/usr/src/cmd/mandoc/st.c b/usr/src/cmd/mandoc/st.c
index 70c21a269e..172403ad18 100644
--- a/usr/src/cmd/mandoc/st.c
+++ b/usr/src/cmd/mandoc/st.c
@@ -1,4 +1,4 @@
-/* $Id: st.c,v 1.9 2011/03/22 14:33:05 kristaps Exp $ */
+/* $Id: st.c,v 1.11 2014/08/10 23:54:41 schwarze Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -14,16 +14,13 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
-#include <stdlib.h>
+#include <sys/types.h>
+
#include <string.h>
-#include <time.h>
#include "mdoc.h"
-#include "mandoc.h"
#include "libmdoc.h"
#define LINE(x, y) \
diff --git a/usr/src/cmd/mandoc/st.in b/usr/src/cmd/mandoc/st.in
index c52ddab9ba..e70680f3ab 100644
--- a/usr/src/cmd/mandoc/st.in
+++ b/usr/src/cmd/mandoc/st.in
@@ -1,4 +1,4 @@
-/* $Id: st.in,v 1.22 2013/12/25 14:09:32 schwarze Exp $ */
+/* $Id: st.in,v 1.28 2015/02/17 20:37:17 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -22,61 +22,56 @@
* the formatted output string.
*
* Be sure to escape strings.
- * The non-breaking blanks prevent ending an output line right before
+ * The non-breaking blanks prevent ending an output line right before
* a number. Groff prevent line breaks at the same places.
*
* REMEMBER TO ADD NEW STANDARDS TO MDOC.7!
*/
-LINE("-p1003.1-88", "IEEE Std 1003.1-1988 (\\(lqPOSIX.1\\(rq)")
-LINE("-p1003.1-90", "IEEE Std 1003.1-1990 (\\(lqPOSIX.1\\(rq)")
-LINE("-p1003.1-96", "ISO/IEC 9945-1:1996 (\\(lqPOSIX.1\\(rq)")
-LINE("-p1003.1-2001", "IEEE Std 1003.1-2001 (\\(lqPOSIX.1\\(rq)")
-LINE("-p1003.1-2004", "IEEE Std 1003.1-2004 (\\(lqPOSIX.1\\(rq)")
-LINE("-p1003.1-2008", "IEEE Std 1003.1-2008 (\\(lqPOSIX.1\\(rq)")
-LINE("-p1003.1", "IEEE Std 1003.1 (\\(lqPOSIX.1\\(rq)")
-LINE("-p1003.1b", "IEEE Std 1003.1b (\\(lqPOSIX.1b\\(rq)")
-LINE("-p1003.1b-93", "IEEE Std 1003.1b-1993 (\\(lqPOSIX.1b\\(rq)")
-LINE("-p1003.1c-95", "IEEE Std 1003.1c-1995 (\\(lqPOSIX.1c\\(rq)")
-LINE("-p1003.1d-99", "IEEE Std 1003.1d-1999 (\\(lqPOSIX.1d\\(rq)")
-LINE("-p1003.1g-2000", "IEEE Std 1003.1g-2000 (\\(lqPOSIX.1g\\(rq)")
-LINE("-p1003.1i-95", "IEEE Std 1003.1i-1995 (\\(lqPOSIX.1i\\(rq)")
-LINE("-p1003.1j-2000", "IEEE Std 1003.1j-2000 (\\(lqPOSIX.1j\\(rq)")
-LINE("-p1003.1q-2000", "IEEE Std 1003.1q-2000 (\\(lqPOSIX.1q\\(rq)")
-LINE("-p1003.2", "IEEE Std 1003.2 (\\(lqPOSIX.2\\(rq)")
-LINE("-p1003.2-92", "IEEE Std 1003.2-1992 (\\(lqPOSIX.2\\(rq)")
-LINE("-p1003.2a-92", "IEEE Std 1003.2a-1992 (\\(lqPOSIX.2\\(rq)")
-LINE("-p1387.2", "IEEE Std 1387.2 (\\(lqPOSIX.7.2\\(rq)")
-LINE("-p1387.2-95", "IEEE Std 1387.2-1995 (\\(lqPOSIX.7.2\\(rq)")
-LINE("-isoC", "ISO/IEC 9899:1990 (\\(lqISO\\~C90\\(rq)")
-LINE("-isoC-90", "ISO/IEC 9899:1990 (\\(lqISO\\~C90\\(rq)")
-LINE("-isoC-amd1", "ISO/IEC 9899/AMD1:1995 (\\(lqISO\\~C90, Amendment 1\\(rq)")
-LINE("-isoC-tcor1", "ISO/IEC 9899/TCOR1:1994 (\\(lqISO\\~C90, Technical Corrigendum 1\\(rq)")
-LINE("-isoC-tcor2", "ISO/IEC 9899/TCOR2:1995 (\\(lqISO\\~C90, Technical Corrigendum 2\\(rq)")
-LINE("-isoC-99", "ISO/IEC 9899:1999 (\\(lqISO\\~C99\\(rq)")
-LINE("-isoC-2011", "ISO/IEC 9899:2011 (\\(lqISO\\~C11\\(rq)")
-LINE("-iso9945-1-90", "ISO/IEC 9945-1:1990 (\\(lqPOSIX.1\\(rq)")
-LINE("-iso9945-1-96", "ISO/IEC 9945-1:1996 (\\(lqPOSIX.1\\(rq)")
-LINE("-iso9945-2-93", "ISO/IEC 9945-2:1993 (\\(lqPOSIX.2\\(rq)")
-LINE("-ansiC", "ANSI X3.159-1989 (\\(lqANSI\\~C89\\(rq)")
-LINE("-ansiC-89", "ANSI X3.159-1989 (\\(lqANSI\\~C89\\(rq)")
-LINE("-ansiC-99", "ANSI/ISO/IEC 9899-1999 (\\(lqANSI\\~C99\\(rq)")
+LINE("-p1003.1-88", "IEEE Std 1003.1-1988 (\\(LqPOSIX.1\\(Rq)")
+LINE("-p1003.1-90", "IEEE Std 1003.1-1990 (\\(LqPOSIX.1\\(Rq)")
+LINE("-p1003.1-96", "ISO/IEC 9945-1:1996 (\\(LqPOSIX.1\\(Rq)")
+LINE("-p1003.1-2001", "IEEE Std 1003.1-2001 (\\(LqPOSIX.1\\(Rq)")
+LINE("-p1003.1-2004", "IEEE Std 1003.1-2004 (\\(LqPOSIX.1\\(Rq)")
+LINE("-p1003.1-2008", "IEEE Std 1003.1-2008 (\\(LqPOSIX.1\\(Rq)")
+LINE("-p1003.1-2013", "IEEE Std 1003.1-2008/Cor 1-2013 (\\(LqPOSIX.1\\(Rq)")
+LINE("-p1003.1", "IEEE Std 1003.1 (\\(LqPOSIX.1\\(Rq)")
+LINE("-p1003.1b", "IEEE Std 1003.1b (\\(LqPOSIX.1b\\(Rq)")
+LINE("-p1003.1b-93", "IEEE Std 1003.1b-1993 (\\(LqPOSIX.1b\\(Rq)")
+LINE("-p1003.1c-95", "IEEE Std 1003.1c-1995 (\\(LqPOSIX.1c\\(Rq)")
+LINE("-p1003.1g-2000", "IEEE Std 1003.1g-2000 (\\(LqPOSIX.1g\\(Rq)")
+LINE("-p1003.1i-95", "IEEE Std 1003.1i-1995 (\\(LqPOSIX.1i\\(Rq)")
+LINE("-p1003.2", "IEEE Std 1003.2 (\\(LqPOSIX.2\\(Rq)")
+LINE("-p1003.2-92", "IEEE Std 1003.2-1992 (\\(LqPOSIX.2\\(Rq)")
+LINE("-p1003.2a-92", "IEEE Std 1003.2a-1992 (\\(LqPOSIX.2\\(Rq)")
+LINE("-isoC", "ISO/IEC 9899:1990 (\\(LqISO\\~C90\\(Rq)")
+LINE("-isoC-90", "ISO/IEC 9899:1990 (\\(LqISO\\~C90\\(Rq)")
+LINE("-isoC-amd1", "ISO/IEC 9899/AMD1:1995 (\\(LqISO\\~C90, Amendment 1\\(Rq)")
+LINE("-isoC-tcor1", "ISO/IEC 9899/TCOR1:1994 (\\(LqISO\\~C90, Technical Corrigendum 1\\(Rq)")
+LINE("-isoC-tcor2", "ISO/IEC 9899/TCOR2:1995 (\\(LqISO\\~C90, Technical Corrigendum 2\\(Rq)")
+LINE("-isoC-99", "ISO/IEC 9899:1999 (\\(LqISO\\~C99\\(Rq)")
+LINE("-isoC-2011", "ISO/IEC 9899:2011 (\\(LqISO\\~C11\\(Rq)")
+LINE("-iso9945-1-90", "ISO/IEC 9945-1:1990 (\\(LqPOSIX.1\\(Rq)")
+LINE("-iso9945-1-96", "ISO/IEC 9945-1:1996 (\\(LqPOSIX.1\\(Rq)")
+LINE("-iso9945-2-93", "ISO/IEC 9945-2:1993 (\\(LqPOSIX.2\\(Rq)")
+LINE("-ansiC", "ANSI X3.159-1989 (\\(LqANSI\\~C89\\(Rq)")
+LINE("-ansiC-89", "ANSI X3.159-1989 (\\(LqANSI\\~C89\\(Rq)")
LINE("-ieee754", "IEEE Std 754-1985")
LINE("-iso8802-3", "ISO 8802-3: 1989")
LINE("-iso8601", "ISO 8601")
-LINE("-ieee1275-94", "IEEE Std 1275-1994 (\\(lqOpen Firmware\\(rq)")
-LINE("-xpg3", "X/Open Portability Guide Issue\\~3 (\\(lqXPG3\\(rq)")
-LINE("-xpg4", "X/Open Portability Guide Issue\\~4 (\\(lqXPG4\\(rq)")
-LINE("-xpg4.2", "X/Open Portability Guide Issue\\~4, Version\\~2 (\\(lqXPG4.2\\(rq)")
-LINE("-xpg4.3", "X/Open Portability Guide Issue\\~4, Version\\~3 (\\(lqXPG4.3\\(rq)")
-LINE("-xbd5", "X/Open Base Definitions Issue\\~5 (\\(lqXBD5\\(rq)")
-LINE("-xcu5", "X/Open Commands and Utilities Issue\\~5 (\\(lqXCU5\\(rq)")
-LINE("-xsh4.2", "X/Open System Interfaces and Headers Issue\\~4, Version\\~2 (\\(lqXSH4.2\\(rq)")
-LINE("-xsh5", "X/Open System Interfaces and Headers Issue\\~5 (\\(lqXSH5\\(rq)")
-LINE("-xns5", "X/Open Networking Services Issue\\~5 (\\(lqXNS5\\(rq)")
-LINE("-xns5.2", "X/Open Networking Services Issue\\~5.2 (\\(lqXNS5.2\\(rq)")
-LINE("-xns5.2d2.0", "X/Open Networking Services Issue\\~5.2 Draft\\~2.0 (\\(lqXNS5.2D2.0\\(rq)")
-LINE("-xcurses4.2", "X/Open Curses Issue\\~4, Version\\~2 (\\(lqXCURSES4.2\\(rq)")
-LINE("-susv2", "Version\\~2 of the Single UNIX Specification (\\(lqSUSv2\\(rq)")
-LINE("-susv3", "Version\\~3 of the Single UNIX Specification (\\(lqSUSv3\\(rq)")
-LINE("-svid4", "System\\~V Interface Definition, Fourth Edition (\\(lqSVID4\\(rq)")
+LINE("-ieee1275-94", "IEEE Std 1275-1994 (\\(LqOpen Firmware\\(Rq)")
+LINE("-xpg3", "X/Open Portability Guide Issue\\~3 (\\(LqXPG3\\(Rq)")
+LINE("-xpg4", "X/Open Portability Guide Issue\\~4 (\\(LqXPG4\\(Rq)")
+LINE("-xpg4.2", "X/Open Portability Guide Issue\\~4, Version\\~2 (\\(LqXPG4.2\\(Rq)")
+LINE("-xbd5", "X/Open Base Definitions Issue\\~5 (\\(LqXBD5\\(Rq)")
+LINE("-xcu5", "X/Open Commands and Utilities Issue\\~5 (\\(LqXCU5\\(Rq)")
+LINE("-xsh4.2", "X/Open System Interfaces and Headers Issue\\~4, Version\\~2 (\\(LqXSH4.2\\(Rq)")
+LINE("-xsh5", "X/Open System Interfaces and Headers Issue\\~5 (\\(LqXSH5\\(Rq)")
+LINE("-xns5", "X/Open Networking Services Issue\\~5 (\\(LqXNS5\\(Rq)")
+LINE("-xns5.2", "X/Open Networking Services Issue\\~5.2 (\\(LqXNS5.2\\(Rq)")
+LINE("-xcurses4.2", "X/Open Curses Issue\\~4, Version\\~2 (\\(LqXCURSES4.2\\(Rq)")
+LINE("-susv1", "Version\\~1 of the Single UNIX Specification (\\(LqSUSv1\\(Rq)")
+LINE("-susv2", "Version\\~2 of the Single UNIX Specification (\\(LqSUSv2\\(Rq)")
+LINE("-susv3", "Version\\~3 of the Single UNIX Specification (\\(LqSUSv3\\(Rq)")
+LINE("-susv4", "Version\\~4 of the Single UNIX Specification (\\(LqSUSv4\\(Rq)")
+LINE("-svid4", "System\\~V Interface Definition, Fourth Edition (\\(LqSVID4\\(Rq)")
diff --git a/usr/src/cmd/mandoc/tbl.c b/usr/src/cmd/mandoc/tbl.c
index b244ac80ac..00ee466125 100644
--- a/usr/src/cmd/mandoc/tbl.c
+++ b/usr/src/cmd/mandoc/tbl.c
@@ -1,7 +1,7 @@
-/* $Id: tbl.c,v 1.27 2013/05/31 22:08:09 schwarze Exp $ */
+/* $Id: tbl.c,v 1.39 2015/01/30 17:32:16 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 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
@@ -15,9 +15,9 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
+
+#include <sys/types.h>
#include <assert.h>
#include <stdio.h>
@@ -26,47 +26,64 @@
#include <time.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libmandoc.h"
#include "libroff.h"
+
enum rofferr
-tbl_read(struct tbl_node *tbl, int ln, const char *p, int offs)
+tbl_read(struct tbl_node *tbl, int ln, const char *p, int pos)
{
- int len;
const char *cp;
-
- cp = &p[offs];
- len = (int)strlen(cp);
+ int active;
/*
- * If we're in the options section and we don't have a
- * terminating semicolon, assume we've moved directly into the
- * layout section. No need to report a warning: this is,
- * apparently, standard behaviour.
+ * In the options section, proceed to the layout section
+ * after a semicolon, or right away if there is no semicolon.
+ * Ignore semicolons in arguments.
*/
- if (TBL_PART_OPTS == tbl->part && len)
- if (';' != cp[len - 1])
- tbl->part = TBL_PART_LAYOUT;
+ if (tbl->part == TBL_PART_OPTS) {
+ tbl->part = TBL_PART_LAYOUT;
+ active = 1;
+ for (cp = p + pos; *cp != '\0'; cp++) {
+ switch (*cp) {
+ case '(':
+ active = 0;
+ continue;
+ case ')':
+ active = 1;
+ continue;
+ case ';':
+ if (active)
+ break;
+ continue;
+ default:
+ continue;
+ }
+ break;
+ }
+ if (*cp == ';') {
+ tbl_option(tbl, ln, p, &pos);
+ if (p[pos] == '\0')
+ return(ROFF_IGN);
+ }
+ }
- /* Now process each logical section of the table. */
+ /* Process the other section types. */
switch (tbl->part) {
- case (TBL_PART_OPTS):
- return(tbl_option(tbl, ln, p) ? ROFF_IGN : ROFF_ERR);
- case (TBL_PART_LAYOUT):
- return(tbl_layout(tbl, ln, p) ? ROFF_IGN : ROFF_ERR);
- case (TBL_PART_CDATA):
- return(tbl_cdata(tbl, ln, p) ? ROFF_TBL : ROFF_IGN);
+ case TBL_PART_LAYOUT:
+ tbl_layout(tbl, ln, p, pos);
+ return(ROFF_IGN);
+ case TBL_PART_CDATA:
+ return(tbl_cdata(tbl, ln, p, pos) ? ROFF_TBL : ROFF_IGN);
default:
break;
}
- /*
- * This only returns zero if the line is empty, so we ignore it
- * and continue on.
- */
- return(tbl_data(tbl, ln, p) ? ROFF_TBL : ROFF_IGN);
+ tbl_data(tbl, ln, p, pos);
+ return(ROFF_TBL);
}
struct tbl_node *
@@ -74,13 +91,12 @@ tbl_alloc(int pos, int line, struct mparse *parse)
{
struct tbl_node *tbl;
- tbl = mandoc_calloc(1, sizeof(struct tbl_node));
+ tbl = mandoc_calloc(1, sizeof(*tbl));
tbl->line = line;
tbl->pos = pos;
tbl->parse = parse;
tbl->part = TBL_PART_OPTS;
tbl->opts.tab = '\t';
- tbl->opts.linesize = 12;
tbl->opts.decimal = '.';
return(tbl);
}
@@ -92,11 +108,10 @@ tbl_free(struct tbl_node *tbl)
struct tbl_cell *cp;
struct tbl_span *sp;
struct tbl_dat *dp;
- struct tbl_head *hp;
- while (NULL != (rp = tbl->first_row)) {
+ while ((rp = tbl->first_row) != NULL) {
tbl->first_row = rp->next;
- while (rp->first) {
+ while (rp->first != NULL) {
cp = rp->first;
rp->first = cp->next;
free(cp);
@@ -104,40 +119,30 @@ tbl_free(struct tbl_node *tbl)
free(rp);
}
- while (NULL != (sp = tbl->first_span)) {
+ while ((sp = tbl->first_span) != NULL) {
tbl->first_span = sp->next;
- while (sp->first) {
+ while (sp->first != NULL) {
dp = sp->first;
sp->first = dp->next;
- if (dp->string)
- free(dp->string);
+ free(dp->string);
free(dp);
}
free(sp);
}
- while (NULL != (hp = tbl->first_head)) {
- tbl->first_head = hp->next;
- free(hp);
- }
-
free(tbl);
}
void
tbl_restart(int line, int pos, struct tbl_node *tbl)
{
- if (TBL_PART_CDATA == tbl->part)
- mandoc_msg(MANDOCERR_TBLBLOCK, tbl->parse,
- tbl->line, tbl->pos, NULL);
+ if (tbl->part == TBL_PART_CDATA)
+ mandoc_msg(MANDOCERR_TBLDATA_BLK, tbl->parse,
+ line, pos, "T&");
tbl->part = TBL_PART_LAYOUT;
tbl->line = line;
tbl->pos = pos;
-
- if (NULL == tbl->first_span || NULL == tbl->first_span->first)
- mandoc_msg(MANDOCERR_TBLNODATA, tbl->parse,
- tbl->line, tbl->pos, NULL);
}
const struct tbl_span *
@@ -153,23 +158,26 @@ tbl_span(struct tbl_node *tbl)
return(span);
}
-void
+int
tbl_end(struct tbl_node **tblp)
{
struct tbl_node *tbl;
+ struct tbl_span *sp;
tbl = *tblp;
*tblp = NULL;
- if (NULL == tbl->first_span || NULL == tbl->first_span->first)
- mandoc_msg(MANDOCERR_TBLNODATA, tbl->parse,
- tbl->line, tbl->pos, NULL);
-
- if (tbl->last_span)
- tbl->last_span->flags |= TBL_SPAN_LAST;
-
- if (TBL_PART_CDATA == tbl->part)
- mandoc_msg(MANDOCERR_TBLBLOCK, tbl->parse,
- tbl->line, tbl->pos, NULL);
+ if (tbl->part == TBL_PART_CDATA)
+ mandoc_msg(MANDOCERR_TBLDATA_BLK, tbl->parse,
+ tbl->line, tbl->pos, "TE");
+
+ sp = tbl->first_span;
+ while (sp != NULL && sp->first == NULL)
+ sp = sp->next;
+ if (sp == NULL) {
+ mandoc_msg(MANDOCERR_TBLDATA_NONE, tbl->parse,
+ tbl->line, tbl->pos, NULL);
+ return(0);
+ }
+ return(1);
}
-
diff --git a/usr/src/cmd/mandoc/tbl_data.c b/usr/src/cmd/mandoc/tbl_data.c
index 7413aa2d83..e2be64eb81 100644
--- a/usr/src/cmd/mandoc/tbl_data.c
+++ b/usr/src/cmd/mandoc/tbl_data.c
@@ -1,7 +1,7 @@
-/* $Id: tbl_data.c,v 1.27 2013/06/01 04:56:50 schwarze Exp $ */
+/* $Id: tbl_data.c,v 1.39 2015/01/30 17:32:16 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 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
@@ -15,9 +15,9 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
+
+#include <sys/types.h>
#include <assert.h>
#include <ctype.h>
@@ -26,34 +26,28 @@
#include <time.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libmandoc.h"
#include "libroff.h"
-static int data(struct tbl_node *, struct tbl_span *,
+static void getdata(struct tbl_node *, struct tbl_span *,
int, const char *, int *);
-static struct tbl_span *newspan(struct tbl_node *, int,
+static struct tbl_span *newspan(struct tbl_node *, int,
struct tbl_row *);
-static int
-data(struct tbl_node *tbl, struct tbl_span *dp,
+
+static void
+getdata(struct tbl_node *tbl, struct tbl_span *dp,
int ln, const char *p, int *pos)
{
struct tbl_dat *dat;
struct tbl_cell *cp;
- int sv, spans;
-
- cp = NULL;
- if (dp->last && dp->last->layout)
- cp = dp->last->layout->next;
- else if (NULL == dp->last)
- cp = dp->layout->first;
+ int sv;
- /*
- * Skip over spanners, since
- * we want to match data with data layout cells in the header.
- */
+ /* Advance to the next layout cell, skipping spanners. */
- while (cp && TBL_CELL_SPAN == cp->pos)
+ cp = dp->last == NULL ? dp->layout->first : dp->last->layout->next;
+ while (cp != NULL && cp->pos == TBL_CELL_SPAN)
cp = cp->next;
/*
@@ -61,34 +55,30 @@ data(struct tbl_node *tbl, struct tbl_span *dp,
* cells. This means that we have extra input.
*/
- if (NULL == cp) {
- mandoc_msg(MANDOCERR_TBLEXTRADAT,
- tbl->parse, ln, *pos, NULL);
+ if (cp == NULL) {
+ mandoc_msg(MANDOCERR_TBLDATA_EXTRA, tbl->parse,
+ ln, *pos, p + *pos);
/* Skip to the end... */
while (p[*pos])
(*pos)++;
- return(1);
+ return;
}
- dat = mandoc_calloc(1, sizeof(struct tbl_dat));
+ dat = mandoc_calloc(1, sizeof(*dat));
dat->layout = cp;
dat->pos = TBL_DATA_NONE;
-
- assert(TBL_CELL_SPAN != cp->pos);
-
- for (spans = 0, cp = cp->next; cp; cp = cp->next)
- if (TBL_CELL_SPAN == cp->pos)
- spans++;
+ dat->spans = 0;
+ for (cp = cp->next; cp != NULL; cp = cp->next)
+ if (cp->pos == TBL_CELL_SPAN)
+ dat->spans++;
else
break;
-
- dat->spans = spans;
- if (dp->last) {
+ if (dp->last == NULL)
+ dp->first = dat;
+ else
dp->last->next = dat;
- dp->last = dat;
- } else
- dp->last = dp->first = dat;
+ dp->last = dat;
sv = *pos;
while (p[*pos] && p[*pos] != tbl->opts.tab)
@@ -100,16 +90,12 @@ data(struct tbl_node *tbl, struct tbl_span *dp,
* until a standalone `T}', are included in our cell.
*/
- if (*pos - sv == 2 && 'T' == p[sv] && '{' == p[sv + 1]) {
+ if (*pos - sv == 2 && p[sv] == 'T' && p[sv + 1] == '{') {
tbl->part = TBL_PART_CDATA;
- return(1);
+ return;
}
- assert(*pos - sv >= 0);
-
- dat->string = mandoc_malloc((size_t)(*pos - sv + 1));
- memcpy(dat->string, &p[sv], (size_t)(*pos - sv));
- dat->string[*pos - sv] = '\0';
+ dat->string = mandoc_strndup(p + sv, *pos - sv);
if (p[*pos])
(*pos)++;
@@ -125,25 +111,19 @@ data(struct tbl_node *tbl, struct tbl_span *dp,
else
dat->pos = TBL_DATA_DATA;
- if (TBL_CELL_HORIZ == dat->layout->pos ||
- TBL_CELL_DHORIZ == dat->layout->pos ||
- TBL_CELL_DOWN == dat->layout->pos)
- if (TBL_DATA_DATA == dat->pos && '\0' != *dat->string)
- mandoc_msg(MANDOCERR_TBLIGNDATA,
- tbl->parse, ln, sv, NULL);
-
- return(1);
+ if ((dat->layout->pos == TBL_CELL_HORIZ ||
+ dat->layout->pos == TBL_CELL_DHORIZ ||
+ dat->layout->pos == TBL_CELL_DOWN) &&
+ dat->pos == TBL_DATA_DATA && *dat->string != '\0')
+ mandoc_msg(MANDOCERR_TBLDATA_SPAN,
+ tbl->parse, ln, sv, dat->string);
}
-/* ARGSUSED */
int
-tbl_cdata(struct tbl_node *tbl, int ln, const char *p)
+tbl_cdata(struct tbl_node *tbl, int ln, const char *p, int pos)
{
struct tbl_dat *dat;
- size_t sz;
- int pos;
-
- pos = 0;
+ size_t sz;
dat = tbl->last_span->last;
@@ -152,8 +132,9 @@ tbl_cdata(struct tbl_node *tbl, int ln, const char *p)
if (p[pos] == tbl->opts.tab) {
tbl->part = TBL_PART_DATA;
pos++;
- return(data(tbl, tbl->last_span, ln, p, &pos));
- } else if ('\0' == p[pos]) {
+ getdata(tbl, tbl->last_span, ln, p, &pos);
+ return(1);
+ } else if (p[pos] == '\0') {
tbl->part = TBL_PART_DATA;
return(1);
}
@@ -163,17 +144,17 @@ tbl_cdata(struct tbl_node *tbl, int ln, const char *p)
dat->pos = TBL_DATA_DATA;
- if (dat->string) {
- sz = strlen(p) + strlen(dat->string) + 2;
+ if (dat->string != NULL) {
+ sz = strlen(p + pos) + strlen(dat->string) + 2;
dat->string = mandoc_realloc(dat->string, sz);
- strlcat(dat->string, " ", sz);
- strlcat(dat->string, p, sz);
+ (void)strlcat(dat->string, " ", sz);
+ (void)strlcat(dat->string, p + pos, sz);
} else
- dat->string = mandoc_strdup(p);
+ dat->string = mandoc_strdup(p + pos);
- if (TBL_CELL_DOWN == dat->layout->pos)
- mandoc_msg(MANDOCERR_TBLIGNDATA,
- tbl->parse, ln, pos, NULL);
+ if (dat->layout->pos == TBL_CELL_DOWN)
+ mandoc_msg(MANDOCERR_TBLDATA_SPAN, tbl->parse,
+ ln, pos, dat->string);
return(0);
}
@@ -183,39 +164,29 @@ newspan(struct tbl_node *tbl, int line, struct tbl_row *rp)
{
struct tbl_span *dp;
- dp = mandoc_calloc(1, sizeof(struct tbl_span));
+ dp = mandoc_calloc(1, sizeof(*dp));
dp->line = line;
dp->opts = &tbl->opts;
dp->layout = rp;
- dp->head = tbl->first_head;
+ dp->prev = tbl->last_span;
- if (tbl->last_span) {
- tbl->last_span->next = dp;
- tbl->last_span = dp;
- } else {
- tbl->last_span = tbl->first_span = dp;
+ if (dp->prev == NULL) {
+ tbl->first_span = dp;
tbl->current_span = NULL;
- dp->flags |= TBL_SPAN_FIRST;
- }
+ } else
+ dp->prev->next = dp;
+ tbl->last_span = dp;
return(dp);
}
-int
-tbl_data(struct tbl_node *tbl, int ln, const char *p)
+void
+tbl_data(struct tbl_node *tbl, int ln, const char *p, int pos)
{
struct tbl_span *dp;
struct tbl_row *rp;
- int pos;
-
- pos = 0;
- if ('\0' == p[pos]) {
- mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, pos, NULL);
- return(0);
- }
-
- /*
+ /*
* Choose a layout row: take the one following the last parsed
* span's. If that doesn't exist, use the last parsed span's.
* If there's no last parsed span, use the first row. Lastly,
@@ -223,17 +194,17 @@ tbl_data(struct tbl_node *tbl, int ln, const char *p)
* (it doesn't "consume" the layout).
*/
- if (tbl->last_span) {
- assert(tbl->last_span->layout);
+ if (tbl->last_span != NULL) {
if (tbl->last_span->pos == TBL_SPAN_DATA) {
for (rp = tbl->last_span->layout->next;
- rp && rp->first; rp = rp->next) {
+ rp != NULL && rp->first != NULL;
+ rp = rp->next) {
switch (rp->first->pos) {
- case (TBL_CELL_HORIZ):
+ case TBL_CELL_HORIZ:
dp = newspan(tbl, ln, rp);
dp->pos = TBL_SPAN_HORIZ;
continue;
- case (TBL_CELL_DHORIZ):
+ case TBL_CELL_DHORIZ:
dp = newspan(tbl, ln, rp);
dp->pos = TBL_SPAN_DHORIZ;
continue;
@@ -245,7 +216,7 @@ tbl_data(struct tbl_node *tbl, int ln, const char *p)
} else
rp = tbl->last_span->layout;
- if (NULL == rp)
+ if (rp == NULL)
rp = tbl->last_span->layout;
} else
rp = tbl->first_row;
@@ -256,19 +227,14 @@ tbl_data(struct tbl_node *tbl, int ln, const char *p)
if ( ! strcmp(p, "_")) {
dp->pos = TBL_SPAN_HORIZ;
- return(1);
+ return;
} else if ( ! strcmp(p, "=")) {
dp->pos = TBL_SPAN_DHORIZ;
- return(1);
+ return;
}
dp->pos = TBL_SPAN_DATA;
- /* This returns 0 when TBL_PART_CDATA is entered. */
-
- while ('\0' != p[pos])
- if ( ! data(tbl, dp, ln, p, &pos))
- return(0);
-
- return(1);
+ while (p[pos] != '\0')
+ getdata(tbl, dp, ln, p, &pos);
}
diff --git a/usr/src/cmd/mandoc/tbl_html.c b/usr/src/cmd/mandoc/tbl_html.c
index 6b8ced716b..e7940381d2 100644
--- a/usr/src/cmd/mandoc/tbl_html.c
+++ b/usr/src/cmd/mandoc/tbl_html.c
@@ -1,4 +1,4 @@
-/* $Id: tbl_html.c,v 1.10 2012/05/27 17:54:54 schwarze Exp $ */
+/* $Id: tbl_html.c,v 1.16 2015/01/30 17:32:16 schwarze Exp $ */
/*
* Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -14,9 +14,9 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
+
+#include <sys/types.h>
#include <assert.h>
#include <stdio.h>
@@ -31,15 +31,14 @@ 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 *);
-/* ARGSUSED */
+
static size_t
html_tbl_len(size_t sz, void *arg)
{
-
+
return(sz);
}
-/* ARGSUSED */
static size_t
html_tbl_strlen(const char *p, void *arg)
{
@@ -50,24 +49,24 @@ html_tbl_strlen(const char *p, void *arg)
static void
html_tblopen(struct html *h, const struct tbl_span *sp)
{
- const struct tbl_head *hp;
struct htmlpair tag;
struct roffsu su;
struct roffcol *col;
+ int ic;
- if (TBL_SPAN_FIRST & sp->flags) {
+ if (h->tbl.cols == NULL) {
h->tbl.len = html_tbl_len;
h->tbl.slen = html_tbl_strlen;
- tblcalc(&h->tbl, sp);
+ tblcalc(&h->tbl, sp, 0);
}
assert(NULL == h->tblt);
PAIR_CLASS_INIT(&tag, "tbl");
h->tblt = print_otag(h, TAG_TABLE, 1, &tag);
- for (hp = sp->head; hp; hp = hp->next) {
+ for (ic = 0; ic < sp->opts->cols; ic++) {
bufinit(h);
- col = &h->tbl.cols[hp->ident];
+ col = h->tbl.cols + ic;
SCALE_HS_INIT(&su, col->width);
bufcat_su(h, "width", &su);
PAIR_STYLE_INIT(&tag, h);
@@ -89,14 +88,14 @@ print_tblclose(struct html *h)
void
print_tbl(struct html *h, const struct tbl_span *sp)
{
- const struct tbl_head *hp;
const struct tbl_dat *dp;
struct htmlpair tag;
struct tag *tt;
+ int ic;
/* Inhibit printing of spaces: we do padding ourselves. */
- if (NULL == h->tblt)
+ if (h->tblt == NULL)
html_tblopen(h, sp);
assert(h->tblt);
@@ -107,22 +106,22 @@ print_tbl(struct html *h, const struct tbl_span *sp)
tt = print_otag(h, TAG_TR, 0, NULL);
switch (sp->pos) {
- case (TBL_SPAN_HORIZ):
+ case TBL_SPAN_HORIZ:
/* FALLTHROUGH */
- case (TBL_SPAN_DHORIZ):
+ case TBL_SPAN_DHORIZ:
PAIR_INIT(&tag, ATTR_COLSPAN, "0");
print_otag(h, TAG_TD, 1, &tag);
break;
default:
dp = sp->first;
- for (hp = sp->head; hp; hp = hp->next) {
+ for (ic = 0; ic < sp->opts->cols; ic++) {
print_stagq(h, tt);
print_otag(h, TAG_TD, 0, NULL);
- if (NULL == dp)
- break;
- if (TBL_CELL_DOWN != dp->layout->pos)
- if (dp->string)
+ if (dp == NULL || dp->layout->col > ic)
+ continue;
+ if (dp->layout->pos != TBL_CELL_DOWN)
+ if (dp->string != NULL)
print_text(h, dp->string);
dp = dp->next;
}
@@ -133,7 +132,7 @@ print_tbl(struct html *h, const struct tbl_span *sp)
h->flags &= ~HTML_NONOSPACE;
- if (TBL_SPAN_LAST & sp->flags) {
+ if (sp->next == NULL) {
assert(h->tbl.cols);
free(h->tbl.cols);
h->tbl.cols = NULL;
diff --git a/usr/src/cmd/mandoc/tbl_layout.c b/usr/src/cmd/mandoc/tbl_layout.c
index 6cce977fa2..ed9acc9c0a 100644
--- a/usr/src/cmd/mandoc/tbl_layout.c
+++ b/usr/src/cmd/mandoc/tbl_layout.c
@@ -1,7 +1,7 @@
-/* $Id: tbl_layout.c,v 1.23 2012/05/27 17:54:54 schwarze Exp $ */
+/* $Id: tbl_layout.c,v 1.38 2015/02/10 11:03:13 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2012 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2012, 2014, 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
@@ -15,17 +15,17 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
-#include <assert.h>
+#include <sys/types.h>
+
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "libmandoc.h"
#include "libroff.h"
@@ -34,15 +34,7 @@ struct tbl_phrase {
enum tbl_cellt key;
};
-/*
- * FIXME: we can make this parse a lot nicer by, when an error is
- * encountered in a layout key, bailing to the next key (i.e. to the
- * next whitespace then continuing).
- */
-
-#define KEYS_MAX 11
-
-static const struct tbl_phrase keys[KEYS_MAX] = {
+static const struct tbl_phrase keys[] = {
{ 'c', TBL_CELL_CENTRE },
{ 'r', TBL_CELL_RIGHT },
{ 'l', TBL_CELL_LEFT },
@@ -55,55 +47,30 @@ static const struct tbl_phrase keys[KEYS_MAX] = {
{ '=', TBL_CELL_DHORIZ }
};
-static int mods(struct tbl_node *, struct tbl_cell *,
+#define KEYS_MAX ((int)(sizeof(keys)/sizeof(keys[0])))
+
+static void mods(struct tbl_node *, struct tbl_cell *,
int, const char *, int *);
-static int cell(struct tbl_node *, struct tbl_row *,
+static void cell(struct tbl_node *, struct tbl_row *,
int, const char *, int *);
-static void row(struct tbl_node *, int, const char *, int *);
static struct tbl_cell *cell_alloc(struct tbl_node *, struct tbl_row *,
- enum tbl_cellt, int vert);
+ enum tbl_cellt);
-static int
-mods(struct tbl_node *tbl, struct tbl_cell *cp,
+
+static void
+mods(struct tbl_node *tbl, struct tbl_cell *cp,
int ln, const char *p, int *pos)
{
- char buf[5];
- int i;
+ char *endptr;
- /* Not all types accept modifiers. */
+mod:
+ while (p[*pos] == ' ' || p[*pos] == '\t')
+ (*pos)++;
- switch (cp->pos) {
- case (TBL_CELL_DOWN):
- /* FALLTHROUGH */
- case (TBL_CELL_HORIZ):
- /* FALLTHROUGH */
- case (TBL_CELL_DHORIZ):
- return(1);
- default:
- break;
- }
+ /* Row delimiters and cell specifiers end modifier lists. */
-mod:
- /*
- * XXX: since, at least for now, modifiers are non-conflicting
- * (are separable by value, regardless of position), we let
- * modifiers come in any order. The existing tbl doesn't let
- * this happen.
- */
- switch (p[*pos]) {
- case ('\0'):
- /* FALLTHROUGH */
- case (' '):
- /* FALLTHROUGH */
- case ('\t'):
- /* FALLTHROUGH */
- case (','):
- /* FALLTHROUGH */
- case ('.'):
- return(1);
- default:
- break;
- }
+ if (strchr(".,-=^_ACLNRSaclnrs", p[*pos]) != NULL)
+ return;
/* Throw away parenthesised expression. */
@@ -115,276 +82,277 @@ mod:
(*pos)++;
goto mod;
}
- mandoc_msg(MANDOCERR_TBLLAYOUT,
- tbl->parse, ln, *pos, NULL);
- return(0);
+ mandoc_msg(MANDOCERR_TBLLAYOUT_PAR, tbl->parse,
+ ln, *pos, NULL);
+ return;
}
/* Parse numerical spacing from modifier string. */
if (isdigit((unsigned char)p[*pos])) {
- for (i = 0; i < 4; i++) {
- if ( ! isdigit((unsigned char)p[*pos + i]))
- break;
- buf[i] = p[*pos + i];
- }
- buf[i] = '\0';
-
- /* No greater than 4 digits. */
-
- if (4 == i) {
- mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
- ln, *pos, NULL);
- return(0);
- }
-
- *pos += i;
- cp->spacing = (size_t)atoi(buf);
-
+ cp->spacing = strtoull(p + *pos, &endptr, 10);
+ *pos = endptr - p;
goto mod;
- /* NOTREACHED */
- }
-
- /* TODO: GNU has many more extensions. */
+ }
switch (tolower((unsigned char)p[(*pos)++])) {
- case ('z'):
- cp->flags |= TBL_CELL_WIGN;
+ case 'b':
+ cp->flags |= TBL_CELL_BOLD;
goto mod;
- case ('u'):
- cp->flags |= TBL_CELL_UP;
+ case 'd':
+ cp->flags |= TBL_CELL_BALIGN;
goto mod;
- case ('e'):
+ case 'e':
cp->flags |= TBL_CELL_EQUAL;
goto mod;
- case ('t'):
+ case 'f':
+ break;
+ case 'i':
+ cp->flags |= TBL_CELL_ITALIC;
+ goto mod;
+ case 'm':
+ mandoc_msg(MANDOCERR_TBLLAYOUT_MOD, tbl->parse,
+ ln, *pos, "m");
+ goto mod;
+ case 'p':
+ /* FALLTHROUGH */
+ case 'v':
+ if (p[*pos] == '-' || p[*pos] == '+')
+ (*pos)++;
+ while (isdigit((unsigned char)p[*pos]))
+ (*pos)++;
+ goto mod;
+ case 't':
cp->flags |= TBL_CELL_TALIGN;
goto mod;
- case ('d'):
- cp->flags |= TBL_CELL_BALIGN;
+ case 'u':
+ cp->flags |= TBL_CELL_UP;
goto mod;
- case ('w'): /* XXX for now, ignore minimal column width */
+ case 'w': /* XXX for now, ignore minimal column width */
+ goto mod;
+ case 'x':
+ cp->flags |= TBL_CELL_WMAX;
+ goto mod;
+ case 'z':
+ cp->flags |= TBL_CELL_WIGN;
+ goto mod;
+ case '|':
+ if (cp->vert < 2)
+ cp->vert++;
+ else
+ mandoc_msg(MANDOCERR_TBLLAYOUT_VERT,
+ tbl->parse, ln, *pos - 1, NULL);
goto mod;
- case ('f'):
- break;
- case ('r'):
- /* FALLTHROUGH */
- case ('b'):
- /* FALLTHROUGH */
- case ('i'):
- (*pos)--;
- break;
default:
- mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
- ln, *pos - 1, NULL);
- return(0);
+ mandoc_vmsg(MANDOCERR_TBLLAYOUT_CHAR, tbl->parse,
+ ln, *pos - 1, "%c", p[*pos - 1]);
+ goto mod;
}
- switch (tolower((unsigned char)p[(*pos)++])) {
- case ('3'):
+ /* Ignore parenthised font names for now. */
+
+ if (p[*pos] == '(')
+ goto mod;
+
+ /* Support only one-character font-names for now. */
+
+ if (p[*pos] == '\0' || (p[*pos + 1] != ' ' && p[*pos + 1] != '.')) {
+ mandoc_vmsg(MANDOCERR_FT_BAD, tbl->parse,
+ ln, *pos, "TS %s", p + *pos - 1);
+ if (p[*pos] != '\0')
+ (*pos)++;
+ if (p[*pos] != '\0')
+ (*pos)++;
+ goto mod;
+ }
+
+ switch (p[(*pos)++]) {
+ case '3':
/* FALLTHROUGH */
- case ('b'):
+ case 'B':
cp->flags |= TBL_CELL_BOLD;
goto mod;
- case ('2'):
+ case '2':
/* FALLTHROUGH */
- case ('i'):
+ case 'I':
cp->flags |= TBL_CELL_ITALIC;
goto mod;
- case ('1'):
+ case '1':
/* FALLTHROUGH */
- case ('r'):
+ case 'R':
goto mod;
default:
- break;
+ mandoc_vmsg(MANDOCERR_FT_BAD, tbl->parse,
+ ln, *pos - 1, "TS f%c", p[*pos - 1]);
+ goto mod;
}
-
- mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
- ln, *pos - 1, NULL);
- return(0);
}
-static int
-cell(struct tbl_node *tbl, struct tbl_row *rp,
+static void
+cell(struct tbl_node *tbl, struct tbl_row *rp,
int ln, const char *p, int *pos)
{
- int vert, i;
+ int i;
enum tbl_cellt c;
- /* Handle vertical lines. */
+ /* Handle leading vertical lines */
+
+ while (p[*pos] == ' ' || p[*pos] == '\t' || p[*pos] == '|') {
+ if (p[*pos] == '|') {
+ if (rp->vert < 2)
+ rp->vert++;
+ else
+ mandoc_msg(MANDOCERR_TBLLAYOUT_VERT,
+ tbl->parse, ln, *pos, NULL);
+ }
+ (*pos)++;
+ }
- for (vert = 0; '|' == p[*pos]; ++*pos)
- vert++;
- while (' ' == p[*pos])
+again:
+ while (p[*pos] == ' ' || p[*pos] == '\t')
(*pos)++;
+ if (p[*pos] == '.' || p[*pos] == '\0')
+ return;
+
/* Parse the column position (`c', `l', `r', ...). */
for (i = 0; i < KEYS_MAX; i++)
if (tolower((unsigned char)p[*pos]) == keys[i].name)
break;
- if (KEYS_MAX == i) {
- mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
- ln, *pos, NULL);
- return(0);
+ if (i == KEYS_MAX) {
+ mandoc_vmsg(MANDOCERR_TBLLAYOUT_CHAR, tbl->parse,
+ ln, *pos, "%c", p[*pos]);
+ (*pos)++;
+ goto again;
}
-
c = keys[i].key;
- /*
- * If a span cell is found first, raise a warning and abort the
- * parse. If a span cell is found and the last layout element
- * isn't a "normal" layout, bail.
- *
- * FIXME: recover from this somehow?
- */
-
- if (TBL_CELL_SPAN == c) {
- if (NULL == rp->first) {
- mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
- ln, *pos, NULL);
- return(0);
- } else if (rp->last)
- switch (rp->last->pos) {
- case (TBL_CELL_HORIZ):
- case (TBL_CELL_DHORIZ):
- mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse,
- ln, *pos, NULL);
- return(0);
- default:
- break;
- }
- }
+ /* Special cases of spanners. */
- /*
- * If a vertical spanner is found, we may not be in the first
- * row.
- */
-
- if (TBL_CELL_DOWN == c && rp == tbl->first_row) {
- mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, ln, *pos, NULL);
- return(0);
- }
+ if (c == TBL_CELL_SPAN) {
+ if (rp->last == NULL)
+ mandoc_msg(MANDOCERR_TBLLAYOUT_SPAN,
+ tbl->parse, ln, *pos, NULL);
+ else if (rp->last->pos == TBL_CELL_HORIZ ||
+ rp->last->pos == TBL_CELL_DHORIZ)
+ c = rp->last->pos;
+ } else if (c == TBL_CELL_DOWN && rp == tbl->first_row)
+ mandoc_msg(MANDOCERR_TBLLAYOUT_DOWN,
+ tbl->parse, ln, *pos, NULL);
(*pos)++;
- /* Disallow adjacent spacers. */
-
- if (vert > 2) {
- mandoc_msg(MANDOCERR_TBLLAYOUT, tbl->parse, ln, *pos - 1, NULL);
- return(0);
- }
-
/* Allocate cell then parse its modifiers. */
- return(mods(tbl, cell_alloc(tbl, rp, c, vert), ln, p, pos));
+ mods(tbl, cell_alloc(tbl, rp, c), ln, p, pos);
}
-
-static void
-row(struct tbl_node *tbl, int ln, const char *p, int *pos)
+void
+tbl_layout(struct tbl_node *tbl, int ln, const char *p, int pos)
{
struct tbl_row *rp;
-row: /*
- * EBNF describing this section:
- *
- * row ::= row_list [:space:]* [.]?[\n]
- * row_list ::= [:space:]* row_elem row_tail
- * row_tail ::= [:space:]*[,] row_list |
- * epsilon
- * row_elem ::= [\t\ ]*[:alpha:]+
- */
-
- rp = mandoc_calloc(1, sizeof(struct tbl_row));
- if (tbl->last_row)
- tbl->last_row->next = rp;
- else
- tbl->first_row = rp;
- tbl->last_row = rp;
-
-cell:
- while (isspace((unsigned char)p[*pos]))
- (*pos)++;
+ rp = NULL;
+ for (;;) {
+ /* Skip whitespace before and after each cell. */
+
+ while (p[pos] == ' ' || p[pos] == '\t')
+ pos++;
+
+ switch (p[pos]) {
+ case ',': /* Next row on this input line. */
+ pos++;
+ rp = NULL;
+ continue;
+ case '\0': /* Next row on next input line. */
+ return;
+ case '.': /* End of layout. */
+ pos++;
+ tbl->part = TBL_PART_DATA;
+
+ /*
+ * When the layout is completely empty,
+ * default to one left-justified column.
+ */
+
+ if (tbl->first_row == NULL) {
+ tbl->first_row = tbl->last_row =
+ mandoc_calloc(1, sizeof(*rp));
+ }
+ if (tbl->first_row->first == NULL) {
+ mandoc_msg(MANDOCERR_TBLLAYOUT_NONE,
+ tbl->parse, ln, pos, NULL);
+ cell_alloc(tbl, tbl->first_row,
+ TBL_CELL_LEFT);
+ return;
+ }
- /* Safely exit layout context. */
+ /*
+ * Search for the widest line
+ * along the left and right margins.
+ */
+
+ for (rp = tbl->first_row; rp; rp = rp->next) {
+ if (tbl->opts.lvert < rp->vert)
+ tbl->opts.lvert = rp->vert;
+ if (rp->last != NULL &&
+ rp->last->col + 1 == tbl->opts.cols &&
+ tbl->opts.rvert < rp->last->vert)
+ tbl->opts.rvert = rp->last->vert;
+
+ /* If the last line is empty, drop it. */
+
+ if (rp->next != NULL &&
+ rp->next->first == NULL) {
+ free(rp->next);
+ rp->next = NULL;
+ }
+ }
+ return;
+ default: /* Cell. */
+ break;
+ }
- if ('.' == p[*pos]) {
- tbl->part = TBL_PART_DATA;
- if (NULL == tbl->first_row)
- mandoc_msg(MANDOCERR_TBLNOLAYOUT, tbl->parse,
- ln, *pos, NULL);
- (*pos)++;
- return;
+ /*
+ * If the last line had at least one cell,
+ * start a new one; otherwise, continue it.
+ */
+
+ if (rp == NULL) {
+ if (tbl->last_row == NULL ||
+ tbl->last_row->first != NULL) {
+ rp = mandoc_calloc(1, sizeof(*rp));
+ if (tbl->last_row)
+ tbl->last_row->next = rp;
+ else
+ tbl->first_row = rp;
+ tbl->last_row = rp;
+ } else
+ rp = tbl->last_row;
+ }
+ cell(tbl, rp, ln, p, &pos);
}
-
- /* End (and possibly restart) a row. */
-
- if (',' == p[*pos]) {
- (*pos)++;
- goto row;
- } else if ('\0' == p[*pos])
- return;
-
- if ( ! cell(tbl, rp, ln, p, pos))
- return;
-
- goto cell;
- /* NOTREACHED */
-}
-
-int
-tbl_layout(struct tbl_node *tbl, int ln, const char *p)
-{
- int pos;
-
- pos = 0;
- row(tbl, ln, p, &pos);
-
- /* Always succeed. */
- return(1);
}
static struct tbl_cell *
-cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos,
- int vert)
+cell_alloc(struct tbl_node *tbl, struct tbl_row *rp, enum tbl_cellt pos)
{
struct tbl_cell *p, *pp;
- struct tbl_head *h, *hp;
- p = mandoc_calloc(1, sizeof(struct tbl_cell));
+ p = mandoc_calloc(1, sizeof(*p));
+ p->pos = pos;
- if (NULL != (pp = rp->last)) {
+ if ((pp = rp->last) != NULL) {
pp->next = p;
- h = pp->head->next;
- } else {
+ p->col = pp->col + 1;
+ } else
rp->first = p;
- h = tbl->first_head;
- }
rp->last = p;
- p->pos = pos;
- p->vert = vert;
-
- /* Re-use header. */
-
- if (h) {
- p->head = h;
- return(p);
- }
-
- hp = mandoc_calloc(1, sizeof(struct tbl_head));
- hp->ident = tbl->opts.cols++;
- hp->vert = vert;
-
- if (tbl->last_head) {
- hp->prev = tbl->last_head;
- tbl->last_head->next = hp;
- } else
- tbl->first_head = hp;
- tbl->last_head = hp;
+ if (tbl->opts.cols <= p->col)
+ tbl->opts.cols = p->col + 1;
- p->head = hp;
return(p);
}
diff --git a/usr/src/cmd/mandoc/tbl_opts.c b/usr/src/cmd/mandoc/tbl_opts.c
index 5bd67f80ee..c012a3c885 100644
--- a/usr/src/cmd/mandoc/tbl_opts.c
+++ b/usr/src/cmd/mandoc/tbl_opts.c
@@ -1,6 +1,7 @@
-/* $Id: tbl_opts.c,v 1.12 2011/09/18 14:14:15 schwarze Exp $ */
+/* $Id: tbl_opts.c,v 1.20 2015/01/28 17:32:07 schwarze Exp $ */
/*
* Copyright (c) 2009, 2010, 2011 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
@@ -14,9 +15,9 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
+
+#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
@@ -27,244 +28,147 @@
#include "libmandoc.h"
#include "libroff.h"
-enum tbl_ident {
- KEY_CENTRE = 0,
- KEY_DELIM,
- KEY_EXPAND,
- KEY_BOX,
- KEY_DBOX,
- KEY_ALLBOX,
- KEY_TAB,
- KEY_LINESIZE,
- KEY_NOKEEP,
- KEY_DPOINT,
- KEY_NOSPACE,
- KEY_FRAME,
- KEY_DFRAME,
- KEY_MAX
-};
+#define KEY_DPOINT 0
+#define KEY_DELIM 1
+#define KEY_LINESIZE 2
+#define KEY_TAB 3
struct tbl_phrase {
const char *name;
int key;
- enum tbl_ident ident;
};
-/* Handle Commonwealth/American spellings. */
-#define KEY_MAXKEYS 14
+static const struct tbl_phrase keys[] = {
+ {"decimalpoint", 0},
+ {"delim", 0},
+ {"linesize", 0},
+ {"tab", 0},
+ {"allbox", TBL_OPT_ALLBOX | TBL_OPT_BOX},
+ {"box", TBL_OPT_BOX},
+ {"frame", TBL_OPT_BOX},
+ {"center", TBL_OPT_CENTRE},
+ {"centre", TBL_OPT_CENTRE},
+ {"doublebox", TBL_OPT_DBOX},
+ {"doubleframe", TBL_OPT_DBOX},
+ {"expand", TBL_OPT_EXPAND},
+ {"nokeep", TBL_OPT_NOKEEP},
+ {"nospaces", TBL_OPT_NOSPACE},
+ {"nowarn", TBL_OPT_NOWARN},
+};
-/* Maximum length of key name string. */
-#define KEY_MAXNAME 13
+#define KEY_MAXKEYS ((int)(sizeof(keys)/sizeof(keys[0])))
-/* Maximum length of key number size. */
-#define KEY_MAXNUMSZ 10
+static void arg(struct tbl_node *, int, const char *, int *, int);
-static const struct tbl_phrase keys[KEY_MAXKEYS] = {
- { "center", TBL_OPT_CENTRE, KEY_CENTRE},
- { "centre", TBL_OPT_CENTRE, KEY_CENTRE},
- { "delim", 0, KEY_DELIM},
- { "expand", TBL_OPT_EXPAND, KEY_EXPAND},
- { "box", TBL_OPT_BOX, KEY_BOX},
- { "doublebox", TBL_OPT_DBOX, KEY_DBOX},
- { "allbox", TBL_OPT_ALLBOX, KEY_ALLBOX},
- { "frame", TBL_OPT_BOX, KEY_FRAME},
- { "doubleframe", TBL_OPT_DBOX, KEY_DFRAME},
- { "tab", 0, KEY_TAB},
- { "linesize", 0, KEY_LINESIZE},
- { "nokeep", TBL_OPT_NOKEEP, KEY_NOKEEP},
- { "decimalpoint", 0, KEY_DPOINT},
- { "nospaces", TBL_OPT_NOSPACE, KEY_NOSPACE},
-};
-static int arg(struct tbl_node *, int,
- const char *, int *, enum tbl_ident);
-static void opt(struct tbl_node *, int,
- const char *, int *);
-
-static int
-arg(struct tbl_node *tbl, int ln, const char *p, int *pos, enum tbl_ident key)
+static void
+arg(struct tbl_node *tbl, int ln, const char *p, int *pos, int key)
{
- int i;
- char buf[KEY_MAXNUMSZ];
+ int len, want;
- while (isspace((unsigned char)p[*pos]))
+ while (p[*pos] == ' ' || p[*pos] == '\t')
(*pos)++;
- /* Arguments always begin with a parenthesis. */
+ /* Arguments are enclosed in parentheses. */
- if ('(' != p[*pos]) {
- mandoc_msg(MANDOCERR_TBL, tbl->parse,
- ln, *pos, NULL);
- return(0);
+ len = 0;
+ if (p[*pos] == '(') {
+ (*pos)++;
+ while (p[*pos + len] != ')')
+ len++;
}
- (*pos)++;
-
- /*
- * The arguments can be ANY value, so we can't just stop at the
- * next close parenthesis (the argument can be a closed
- * parenthesis itself).
- */
-
switch (key) {
- case (KEY_DELIM):
- if ('\0' == p[(*pos)++]) {
- mandoc_msg(MANDOCERR_TBL, tbl->parse,
- ln, *pos - 1, NULL);
- return(0);
- }
-
- if ('\0' == p[(*pos)++]) {
- mandoc_msg(MANDOCERR_TBL, tbl->parse,
- ln, *pos - 1, NULL);
- return(0);
- }
+ case KEY_DELIM:
+ mandoc_vmsg(MANDOCERR_TBLOPT_EQN, tbl->parse,
+ ln, *pos, "%.*s", len, p + *pos);
+ want = 2;
+ break;
+ case KEY_TAB:
+ want = 1;
+ if (len == want)
+ tbl->opts.tab = p[*pos];
+ break;
+ case KEY_LINESIZE:
+ want = 0;
+ break;
+ case KEY_DPOINT:
+ want = 1;
+ if (len == want)
+ tbl->opts.decimal = p[*pos];
break;
- case (KEY_TAB):
- if ('\0' != (tbl->opts.tab = p[(*pos)++]))
- break;
-
- mandoc_msg(MANDOCERR_TBL, tbl->parse,
- ln, *pos - 1, NULL);
- return(0);
- case (KEY_LINESIZE):
- for (i = 0; i < KEY_MAXNUMSZ && p[*pos]; i++, (*pos)++) {
- buf[i] = p[*pos];
- if ( ! isdigit((unsigned char)buf[i]))
- break;
- }
-
- if (i < KEY_MAXNUMSZ) {
- buf[i] = '\0';
- tbl->opts.linesize = atoi(buf);
- break;
- }
-
- mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos, NULL);
- return(0);
- case (KEY_DPOINT):
- if ('\0' != (tbl->opts.decimal = p[(*pos)++]))
- break;
-
- mandoc_msg(MANDOCERR_TBL, tbl->parse,
- ln, *pos - 1, NULL);
- return(0);
default:
abort();
/* NOTREACHED */
}
- /* End with a close parenthesis. */
+ if (len == 0)
+ mandoc_msg(MANDOCERR_TBLOPT_NOARG,
+ tbl->parse, ln, *pos, keys[key].name);
+ else if (want && len != want)
+ mandoc_vmsg(MANDOCERR_TBLOPT_ARGSZ,
+ tbl->parse, ln, *pos, "%s want %d have %d",
+ keys[key].name, want, len);
- if (')' == p[(*pos)++])
- return(1);
-
- mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos - 1, NULL);
- return(0);
+ *pos += len;
+ if (p[*pos] == ')')
+ (*pos)++;
}
-static void
-opt(struct tbl_node *tbl, int ln, const char *p, int *pos)
+/*
+ * Parse one line of options up to the semicolon.
+ * Each option can be preceded by blanks and/or commas,
+ * and some options are followed by arguments.
+ */
+void
+tbl_option(struct tbl_node *tbl, int ln, const char *p, int *offs)
{
- int i, sv;
- char buf[KEY_MAXNAME];
-
- /*
- * Parse individual options from the stream as surrounded by
- * this goto. Each pass through the routine parses out a single
- * option and registers it. Option arguments are processed in
- * the arg() function.
- */
+ int i, pos, len;
-again: /*
- * EBNF describing this section:
- *
- * options ::= option_list [:space:]* [;][\n]
- * option_list ::= option option_tail
- * option_tail ::= [:space:]+ option_list |
- * ::= epsilon
- * option ::= [:alpha:]+ args
- * args ::= [:space:]* [(] [:alpha:]+ [)]
- */
+ pos = *offs;
+ for (;;) {
+ while (p[pos] == ' ' || p[pos] == '\t' || p[pos] == ',')
+ pos++;
- while (isspace((unsigned char)p[*pos]))
- (*pos)++;
-
- /* Safe exit point. */
-
- if (';' == p[*pos])
- return;
-
- /* Copy up to first non-alpha character. */
-
- for (sv = *pos, i = 0; i < KEY_MAXNAME; i++, (*pos)++) {
- buf[i] = (char)tolower((unsigned char)p[*pos]);
- if ( ! isalpha((unsigned char)buf[i]))
- break;
- }
+ if (p[pos] == ';') {
+ *offs = pos + 1;
+ return;
+ }
- /* Exit if buffer is empty (or overrun). */
+ /* Parse one option name. */
- if (KEY_MAXNAME == i || 0 == i) {
- mandoc_msg(MANDOCERR_TBL, tbl->parse, ln, *pos, NULL);
- return;
- }
+ len = 0;
+ while (isalpha((unsigned char)p[pos + len]))
+ len++;
- buf[i] = '\0';
+ if (len == 0) {
+ mandoc_vmsg(MANDOCERR_TBLOPT_ALPHA,
+ tbl->parse, ln, pos, "%c", p[pos]);
+ pos++;
+ continue;
+ }
- while (isspace((unsigned char)p[*pos]))
- (*pos)++;
+ /* Look up the option name. */
- /*
- * Look through all of the available keys to find one that
- * matches the input. FIXME: hashtable this.
- */
+ i = 0;
+ while (i < KEY_MAXKEYS &&
+ (strncasecmp(p + pos, keys[i].name, len) ||
+ keys[i].name[len] != '\0'))
+ i++;
- for (i = 0; i < KEY_MAXKEYS; i++) {
- if (strcmp(buf, keys[i].name))
+ if (i == KEY_MAXKEYS) {
+ mandoc_vmsg(MANDOCERR_TBLOPT_BAD, tbl->parse,
+ ln, pos, "%.*s", len, p + pos);
+ pos += len;
continue;
+ }
- /*
- * Note: this is more difficult to recover from, as we
- * can be anywhere in the option sequence and it's
- * harder to jump to the next. Meanwhile, just bail out
- * of the sequence altogether.
- */
+ /* Handle the option. */
- if (keys[i].key)
+ pos += len;
+ if (keys[i].key)
tbl->opts.opts |= keys[i].key;
- else if ( ! arg(tbl, ln, p, pos, keys[i].ident))
- return;
-
- break;
+ else
+ arg(tbl, ln, p, &pos, i);
}
-
- /*
- * Allow us to recover from bad options by continuing to another
- * parse sequence.
- */
-
- if (KEY_MAXKEYS == i)
- mandoc_msg(MANDOCERR_TBLOPT, tbl->parse, ln, sv, NULL);
-
- goto again;
- /* NOTREACHED */
-}
-
-int
-tbl_option(struct tbl_node *tbl, int ln, const char *p)
-{
- int pos;
-
- /*
- * Table options are always on just one line, so automatically
- * switch into the next input mode here.
- */
- tbl->part = TBL_PART_LAYOUT;
-
- pos = 0;
- opt(tbl, ln, p, &pos);
-
- /* Always succeed. */
- return(1);
}
diff --git a/usr/src/cmd/mandoc/tbl_term.c b/usr/src/cmd/mandoc/tbl_term.c
index e8411ffece..1276776668 100644
--- a/usr/src/cmd/mandoc/tbl_term.c
+++ b/usr/src/cmd/mandoc/tbl_term.c
@@ -1,7 +1,7 @@
-/* $Id: tbl_term.c,v 1.25 2013/05/31 21:37:17 schwarze Exp $ */
+/* $Id: tbl_term.c,v 1.40 2015/03/06 15:48:53 schwarze Exp $ */
/*
* Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011, 2012 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 2012, 2014, 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
@@ -15,9 +15,9 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
+
+#include <sys/types.h>
#include <assert.h>
#include <stdio.h>
@@ -32,17 +32,15 @@ static size_t term_tbl_len(size_t, void *);
static size_t term_tbl_strlen(const char *, void *);
static void tbl_char(struct termp *, char, size_t);
static void tbl_data(struct termp *, const struct tbl_opts *,
- const struct tbl_dat *,
+ const struct tbl_dat *,
const struct roffcol *);
-static size_t tbl_rulewidth(struct termp *, const struct tbl_head *);
-static void tbl_hframe(struct termp *, const struct tbl_span *, int);
-static void tbl_literal(struct termp *, const struct tbl_dat *,
+static void tbl_literal(struct termp *, const struct tbl_dat *,
const struct roffcol *);
-static void tbl_number(struct termp *, const struct tbl_opts *,
- const struct tbl_dat *,
+static void tbl_number(struct termp *, const struct tbl_opts *,
+ const struct tbl_dat *,
const struct roffcol *);
-static void tbl_hrule(struct termp *, const struct tbl_span *);
-static void tbl_vrule(struct termp *, const struct tbl_head *);
+static void tbl_hrule(struct termp *, const struct tbl_span *, int);
+static void tbl_word(struct termp *, const struct tbl_dat *);
static size_t
@@ -62,11 +60,11 @@ term_tbl_len(size_t sz, void *arg)
void
term_tbl(struct termp *tp, const struct tbl_span *sp)
{
- const struct tbl_head *hp;
+ const struct tbl_cell *cp;
const struct tbl_dat *dp;
- struct roffcol *col;
- int spans;
- size_t rmargin, maxrmargin;
+ static size_t offset;
+ size_t rmargin, maxrmargin, tsz;
+ int ic, horiz, spans, vert;
rmargin = tp->rmargin;
maxrmargin = tp->maxrmargin;
@@ -83,85 +81,105 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
* calculate the table widths and decimal positions.
*/
- if (TBL_SPAN_FIRST & sp->flags) {
- term_flushln(tp);
-
+ if (tp->tbl.cols == NULL) {
tp->tbl.len = term_tbl_len;
tp->tbl.slen = term_tbl_strlen;
tp->tbl.arg = tp;
- tblcalc(&tp->tbl, sp);
- }
+ tblcalc(&tp->tbl, sp, rmargin - tp->offset);
+
+ /* Center the table as a whole. */
+
+ offset = tp->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)
+ tsz -= 1;
+ tp->offset = (offset + rmargin > tsz) ?
+ (offset + rmargin - tsz) / 2 : 0;
+ }
- /* Horizontal frame at the start of boxed tables. */
+ /* Horizontal frame at the start of boxed tables. */
- if (TBL_SPAN_FIRST & sp->flags) {
- if (TBL_OPT_DBOX & sp->opts->opts)
- tbl_hframe(tp, sp, 1);
- if (TBL_OPT_DBOX & sp->opts->opts ||
- TBL_OPT_BOX & sp->opts->opts)
- tbl_hframe(tp, sp, 0);
+ if (sp->opts->opts & TBL_OPT_DBOX)
+ tbl_hrule(tp, sp, 2);
+ if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX))
+ tbl_hrule(tp, sp, 1);
}
/* Vertical frame at the start of each row. */
- if (TBL_OPT_BOX & sp->opts->opts || TBL_OPT_DBOX & sp->opts->opts)
- term_word(tp, TBL_SPAN_HORIZ == sp->pos ||
- TBL_SPAN_DHORIZ == sp->pos ? "+" : "|");
+ horiz = sp->pos == TBL_SPAN_HORIZ || sp->pos == TBL_SPAN_DHORIZ;
+
+ if (sp->layout->vert ||
+ (sp->prev != NULL && sp->prev->layout->vert) ||
+ sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX))
+ term_word(tp, horiz ? "+" : "|");
+ else if (sp->opts->lvert)
+ tbl_char(tp, horiz ? '-' : ASCII_NBRSP, 1);
/*
* Now print the actual data itself depending on the span type.
- * Spanner spans get a horizontal rule; data spanners have their
- * data printed by matching data to header.
+ * Match data cells to column numbers.
*/
- switch (sp->pos) {
- case (TBL_SPAN_HORIZ):
- /* FALLTHROUGH */
- case (TBL_SPAN_DHORIZ):
- tbl_hrule(tp, sp);
- break;
- case (TBL_SPAN_DATA):
- /* Iterate over template headers. */
+ if (sp->pos == TBL_SPAN_DATA) {
+ cp = sp->layout->first;
dp = sp->first;
spans = 0;
- for (hp = sp->head; hp; hp = hp->next) {
+ for (ic = 0; ic < sp->opts->cols; ic++) {
- /*
- * If the current data header is invoked during
- * a spanner ("spans" > 0), don't emit anything
- * at all.
+ /*
+ * Remeber whether we need a vertical bar
+ * after this cell.
*/
- if (--spans >= 0)
- continue;
-
- /* Separate columns. */
+ vert = cp == NULL ? 0 : cp->vert;
- if (NULL != hp->prev)
- tbl_vrule(tp, hp);
-
- col = &tp->tbl.cols[hp->ident];
- tbl_data(tp, sp->opts, dp, col);
+ /*
+ * Print the data and advance to the next cell.
+ */
- /*
- * Go to the next data cell and assign the
- * number of subsequent spans, if applicable.
+ if (spans == 0) {
+ tbl_data(tp, sp->opts, dp, tp->tbl.cols + ic);
+ if (dp != NULL) {
+ spans = dp->spans;
+ dp = dp->next;
+ }
+ } else
+ spans--;
+ if (cp != NULL)
+ cp = cp->next;
+
+ /*
+ * Separate columns, except in the middle
+ * of spans and after the last cell.
*/
- if (dp) {
- spans = dp->spans;
- dp = dp->next;
- }
+ if (ic + 1 == sp->opts->cols || spans)
+ continue;
+
+ tbl_char(tp, ASCII_NBRSP, 1);
+ if (vert > 0)
+ tbl_char(tp, '|', vert);
+ if (vert < 2)
+ tbl_char(tp, ASCII_NBRSP, 2 - vert);
}
- break;
- }
+ } else if (horiz)
+ tbl_hrule(tp, sp, 0);
/* Vertical frame at the end of each row. */
- if (TBL_OPT_BOX & sp->opts->opts || TBL_OPT_DBOX & sp->opts->opts)
- term_word(tp, TBL_SPAN_HORIZ == sp->pos ||
- TBL_SPAN_DHORIZ == sp->pos ? "+" : " |");
+ if (sp->layout->last->vert ||
+ (sp->prev != NULL && sp->prev->layout->last->vert) ||
+ (sp->opts->opts & (TBL_OPT_BOX | TBL_OPT_DBOX)))
+ term_word(tp, horiz ? "+" : " |");
+ else if (sp->opts->rvert)
+ tbl_char(tp, horiz ? '-' : ASCII_NBRSP, 1);
term_flushln(tp);
/*
@@ -169,140 +187,118 @@ term_tbl(struct termp *tp, const struct tbl_span *sp)
* existing table configuration and set it to NULL.
*/
- if (TBL_SPAN_LAST & sp->flags) {
- if (TBL_OPT_DBOX & sp->opts->opts ||
- TBL_OPT_BOX & sp->opts->opts) {
- tbl_hframe(tp, sp, 0);
+ if (sp->next == NULL) {
+ if (sp->opts->opts & (TBL_OPT_DBOX | TBL_OPT_BOX)) {
+ tbl_hrule(tp, sp, 1);
tp->skipvsp = 1;
}
- if (TBL_OPT_DBOX & sp->opts->opts) {
- tbl_hframe(tp, sp, 1);
+ if (sp->opts->opts & TBL_OPT_DBOX) {
+ tbl_hrule(tp, sp, 2);
tp->skipvsp = 2;
}
assert(tp->tbl.cols);
free(tp->tbl.cols);
tp->tbl.cols = NULL;
+ tp->offset = offset;
}
tp->flags &= ~TERMP_NONOSPACE;
tp->rmargin = rmargin;
tp->maxrmargin = maxrmargin;
-
}
/*
- * Horizontal rules extend across the entire table.
- * Calculate the width by iterating over columns.
- */
-static size_t
-tbl_rulewidth(struct termp *tp, const struct tbl_head *hp)
-{
- size_t width;
-
- width = tp->tbl.cols[hp->ident].width;
-
- /* Account for leading blanks. */
- if (hp->prev)
- width += 2 - hp->vert;
-
- /* Account for trailing blank. */
- width++;
-
- return(width);
-}
-
-/*
- * Rules inside the table can be single or double
- * and have crossings with vertical rules marked with pluses.
+ * Kinds of horizontal rulers:
+ * 0: inside the table (single or double line with crossings)
+ * 1: inner frame (single line with crossings and ends)
+ * 2: outer frame (single line without crossings with ends)
*/
static void
-tbl_hrule(struct termp *tp, const struct tbl_span *sp)
+tbl_hrule(struct termp *tp, const struct tbl_span *sp, int kind)
{
- const struct tbl_head *hp;
- char c;
-
- c = '-';
- if (TBL_SPAN_DHORIZ == sp->pos)
- c = '=';
-
- for (hp = sp->head; hp; hp = hp->next) {
- if (hp->prev && hp->vert)
- tbl_char(tp, '+', hp->vert);
- tbl_char(tp, c, tbl_rulewidth(tp, hp));
+ const struct tbl_cell *c1, *c2;
+ int vert;
+ char line, cross;
+
+ line = (kind == 0 && TBL_SPAN_DHORIZ == sp->pos) ? '=' : '-';
+ cross = (kind < 2) ? '+' : '-';
+
+ if (kind)
+ term_word(tp, "+");
+ c1 = sp->layout->first;
+ c2 = sp->prev == NULL ? NULL : sp->prev->layout->first;
+ if (c2 == c1)
+ c2 = NULL;
+ for (;;) {
+ tbl_char(tp, line, tp->tbl.cols[c1->col].width + 1);
+ vert = c1->vert;
+ if ((c1 = c1->next) == NULL)
+ break;
+ if (c2 != NULL) {
+ if (vert < c2->vert)
+ vert = c2->vert;
+ c2 = c2->next;
+ }
+ if (vert)
+ tbl_char(tp, cross, vert);
+ if (vert < 2)
+ tbl_char(tp, line, 2 - vert);
}
-}
-
-/*
- * Rules above and below the table are always single
- * and have an additional plus at the beginning and end.
- * For double frames, this function is called twice,
- * and the outer one does not have crossings.
- */
-static void
-tbl_hframe(struct termp *tp, const struct tbl_span *sp, int outer)
-{
- const struct tbl_head *hp;
-
- term_word(tp, "+");
- for (hp = sp->head; hp; hp = hp->next) {
- if (hp->prev && hp->vert)
- tbl_char(tp, (outer ? '-' : '+'), hp->vert);
- tbl_char(tp, '-', tbl_rulewidth(tp, hp));
+ if (kind) {
+ term_word(tp, "+");
+ term_flushln(tp);
}
- term_word(tp, "+");
- term_flushln(tp);
}
static void
tbl_data(struct termp *tp, const struct tbl_opts *opts,
- const struct tbl_dat *dp,
- const struct roffcol *col)
+ const struct tbl_dat *dp,
+ const struct roffcol *col)
{
- if (NULL == dp) {
+ if (dp == NULL) {
tbl_char(tp, ASCII_NBRSP, col->width);
return;
}
- assert(dp->layout);
switch (dp->pos) {
- case (TBL_DATA_NONE):
+ case TBL_DATA_NONE:
tbl_char(tp, ASCII_NBRSP, col->width);
return;
- case (TBL_DATA_HORIZ):
+ case TBL_DATA_HORIZ:
/* FALLTHROUGH */
- case (TBL_DATA_NHORIZ):
+ case TBL_DATA_NHORIZ:
tbl_char(tp, '-', col->width);
return;
- case (TBL_DATA_NDHORIZ):
+ case TBL_DATA_NDHORIZ:
/* FALLTHROUGH */
- case (TBL_DATA_DHORIZ):
+ case TBL_DATA_DHORIZ:
tbl_char(tp, '=', col->width);
return;
default:
break;
}
-
+
switch (dp->layout->pos) {
- case (TBL_CELL_HORIZ):
+ case TBL_CELL_HORIZ:
tbl_char(tp, '-', col->width);
break;
- case (TBL_CELL_DHORIZ):
+ case TBL_CELL_DHORIZ:
tbl_char(tp, '=', col->width);
break;
- case (TBL_CELL_LONG):
+ case TBL_CELL_LONG:
/* FALLTHROUGH */
- case (TBL_CELL_CENTRE):
+ case TBL_CELL_CENTRE:
/* FALLTHROUGH */
- case (TBL_CELL_LEFT):
+ case TBL_CELL_LEFT:
/* FALLTHROUGH */
- case (TBL_CELL_RIGHT):
+ case TBL_CELL_RIGHT:
tbl_literal(tp, dp, col);
break;
- case (TBL_CELL_NUMBER):
+ case TBL_CELL_NUMBER:
tbl_number(tp, opts, dp, col);
break;
- case (TBL_CELL_DOWN):
+ case TBL_CELL_DOWN:
tbl_char(tp, ASCII_NBRSP, col->width);
break;
default:
@@ -312,17 +308,6 @@ tbl_data(struct termp *tp, const struct tbl_opts *opts,
}
static void
-tbl_vrule(struct termp *tp, const struct tbl_head *hp)
-{
-
- tbl_char(tp, ASCII_NBRSP, 1);
- if (0 < hp->vert)
- tbl_char(tp, '|', hp->vert);
- if (2 > hp->vert)
- tbl_char(tp, ASCII_NBRSP, 2 - hp->vert);
-}
-
-static void
tbl_char(struct termp *tp, char c, size_t len)
{
size_t i, sz;
@@ -338,36 +323,35 @@ tbl_char(struct termp *tp, char c, size_t len)
}
static void
-tbl_literal(struct termp *tp, const struct tbl_dat *dp,
+tbl_literal(struct termp *tp, const struct tbl_dat *dp,
const struct roffcol *col)
{
- struct tbl_head *hp;
- size_t width, len, padl, padr;
- int spans;
+ size_t len, padl, padr, width;
+ int ic, spans;
assert(dp->string);
len = term_strlen(tp, dp->string);
-
- hp = dp->layout->head->next;
width = col->width;
- for (spans = dp->spans; spans--; hp = hp->next)
- width += tp->tbl.cols[hp->ident].width + 3;
+ ic = dp->layout->col;
+ spans = dp->spans;
+ while (spans--)
+ width += tp->tbl.cols[++ic].width + 3;
padr = width > len ? width - len : 0;
padl = 0;
switch (dp->layout->pos) {
- case (TBL_CELL_LONG):
+ case TBL_CELL_LONG:
padl = term_len(tp, 1);
padr = padr > padl ? padr - padl : 0;
break;
- case (TBL_CELL_CENTRE):
+ case TBL_CELL_CENTRE:
if (2 > padr)
break;
padl = padr / 2;
padr -= padl;
break;
- case (TBL_CELL_RIGHT):
+ case TBL_CELL_RIGHT:
padl = padr;
padr = 0;
break;
@@ -376,7 +360,7 @@ tbl_literal(struct termp *tp, const struct tbl_dat *dp,
}
tbl_char(tp, ASCII_NBRSP, padl);
- term_word(tp, dp->string);
+ tbl_word(tp, dp);
tbl_char(tp, ASCII_NBRSP, padr);
}
@@ -404,8 +388,7 @@ tbl_number(struct termp *tp, const struct tbl_opts *opts,
psz = term_strlen(tp, buf);
- if (NULL != (cp = strrchr(dp->string, opts->decimal))) {
- buf[1] = '\0';
+ if ((cp = strrchr(dp->string, opts->decimal)) != NULL) {
for (ssz = 0, i = 0; cp != &dp->string[i]; i++) {
buf[0] = dp->string[i];
ssz += term_strlen(tp, buf);
@@ -414,11 +397,30 @@ tbl_number(struct termp *tp, const struct tbl_opts *opts,
} else
d = sz + psz;
- padl = col->decimal - d;
-
- tbl_char(tp, ASCII_NBRSP, padl);
- term_word(tp, dp->string);
+ if (col->decimal > d && col->width > sz) {
+ padl = col->decimal - d;
+ if (padl + sz > col->width)
+ padl = col->width - sz;
+ tbl_char(tp, ASCII_NBRSP, padl);
+ } else
+ padl = 0;
+ tbl_word(tp, dp);
if (col->width > sz + padl)
tbl_char(tp, ASCII_NBRSP, col->width - sz - padl);
}
+static void
+tbl_word(struct termp *tp, const struct tbl_dat *dp)
+{
+ int prev_font;
+
+ prev_font = tp->fonti;
+ if (dp->layout->flags & TBL_CELL_BOLD)
+ term_fontpush(tp, TERMFONT_BOLD);
+ else if (dp->layout->flags & TBL_CELL_ITALIC)
+ term_fontpush(tp, TERMFONT_UNDER);
+
+ term_word(tp, dp->string);
+
+ term_fontpopq(tp, prev_font);
+}
diff --git a/usr/src/cmd/mandoc/term.c b/usr/src/cmd/mandoc/term.c
index e7b9557875..ee2af9e625 100644
--- a/usr/src/cmd/mandoc/term.c
+++ b/usr/src/cmd/mandoc/term.c
@@ -1,7 +1,7 @@
-/* $Id: term.c,v 1.214 2013/12/25 00:39:31 schwarze Exp $ */
+/* $Id: term.c,v 1.245 2015/03/06 13:02:43 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-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
@@ -15,20 +15,18 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#include <sys/types.h>
#include <assert.h>
#include <ctype.h>
-#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "out.h"
#include "term.h"
#include "main.h"
@@ -39,21 +37,18 @@ static void bufferc(struct termp *, char);
static void encode(struct termp *, const char *, size_t);
static void encode1(struct termp *, int);
+
void
term_free(struct termp *p)
{
- if (p->buf)
- free(p->buf);
- if (p->symtab)
- mchars_free(p->symtab);
-
+ free(p->buf);
+ free(p->fontq);
free(p);
}
-
void
-term_begin(struct termp *p, term_margin head,
+term_begin(struct termp *p, term_margin head,
term_margin foot, const void *arg)
{
@@ -63,7 +58,6 @@ term_begin(struct termp *p, term_margin head,
(*p->begin)(p);
}
-
void
term_end(struct termp *p)
{
@@ -72,34 +66,27 @@ term_end(struct termp *p)
}
/*
- * Flush a line of text. A "line" is loosely defined as being something
- * that should be followed by a newline, regardless of whether it's
- * broken apart by newlines getting there. A line can also be a
- * fragment of a columnar list (`Bl -tag' or `Bl -column'), which does
- * not have a trailing newline.
- *
+ * Flush a chunk of text. By default, break the output line each time
+ * the right margin is reached, and continue output on the next line
+ * at the same offset as the chunk itself. By default, also break the
+ * output line at the end of the chunk.
* The following flags may be specified:
*
- * - TERMP_NOBREAK: this is the most important and is used when making
- * columns. In short: don't print a newline and instead expect the
- * next call to do the padding up to the start of the next column.
- * p->trailspace may be set to 0, 1, or 2, depending on how many
- * space characters are required at the end of the column.
- *
- * - TERMP_DANGLE: don't newline when TERMP_NOBREAK is specified and
- * the line is overrun, and don't pad-right if it's underrun.
- *
- * - TERMP_HANG: like TERMP_DANGLE, but doesn't newline when
- * overrunning, instead save the position and continue at that point
- * when the next invocation.
- *
- * In-line line breaking:
- *
- * If TERMP_NOBREAK is specified and the line overruns the right
- * margin, it will break and pad-right to the right margin after
- * writing. If maxrmargin is violated, it will break and continue
- * writing from the right-margin, which will lead to the above scenario
- * upon exit. Otherwise, the line will break at the right margin.
+ * - TERMP_NOBREAK: Do not break the output line at the right margin,
+ * but only at the max right margin. Also, do not break the output
+ * line at the end of the chunk, such that the next call can pad to
+ * the next column. However, if less than p->trailspace blanks,
+ * which can be 0, 1, or 2, remain to the right margin, the line
+ * will be broken.
+ * - TERMP_BRIND: If the chunk does not fit and the output line has
+ * to be broken, start the next line at the right margin instead
+ * of at the offset. Used together with TERMP_NOBREAK for the tags
+ * in various kinds of tagged lists.
+ * - TERMP_DANGLE: 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.
*/
void
term_flushln(struct termp *p)
@@ -114,7 +101,6 @@ term_flushln(struct termp *p)
size_t j; /* temporary loop index for p->buf */
size_t jhy; /* last hyph before overflow w/r/t j */
size_t maxvis; /* output position of visible boundary */
- size_t mmax; /* used in calculating bp */
/*
* First, establish the maximum columns of "visible" content.
@@ -127,13 +113,16 @@ term_flushln(struct termp *p)
* is negative, it gets sign extended. Subtracting that
* very large size_t effectively adds a small number to dv.
*/
- assert (p->rmargin >= p->offset);
- dv = p->rmargin - p->offset;
+ dv = p->rmargin > p->offset ? p->rmargin - p->offset : 0;
maxvis = (int)dv > p->overstep ? dv - (size_t)p->overstep : 0;
- dv = p->maxrmargin - p->offset;
- mmax = (int)dv > p->overstep ? dv - (size_t)p->overstep : 0;
- bp = TERMP_NOBREAK & p->flags ? mmax : maxvis;
+ 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.
@@ -178,10 +167,18 @@ term_flushln(struct termp *p)
/* Regular word. */
/* Break at the hyphen point if we overrun. */
- if (vend > vis && vend < bp &&
- ASCII_HYPH == p->buf[j])
+ if (vend > vis && vend < bp &&
+ (ASCII_HYPH == p->buf[j] ||
+ ASCII_BREAK == p->buf[j]))
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] = '-';
+
vend += (*p->width)(p, p->buf[j]);
}
@@ -193,9 +190,10 @@ term_flushln(struct termp *p)
vend -= vis;
(*p->endline)(p);
p->viscol = 0;
- if (TERMP_NOBREAK & p->flags) {
+ if (TERMP_BRIND & p->flags) {
vbl = p->rmargin;
- vend += p->rmargin - p->offset;
+ vend += p->rmargin;
+ vend -= p->offset;
} else
vbl = p->offset;
@@ -222,7 +220,7 @@ term_flushln(struct termp *p)
break;
if (' ' == p->buf[i]) {
j = i;
- while (' ' == p->buf[i])
+ while (i < p->col && ' ' == p->buf[i])
i++;
dv = (i - j) * (*p->width)(p, ' ');
vbl += dv;
@@ -233,6 +231,8 @@ term_flushln(struct termp *p)
vbl += (*p->width)(p, ' ');
continue;
}
+ if (ASCII_BREAK == p->buf[i])
+ continue;
/*
* Now we definitely know there will be
@@ -245,16 +245,10 @@ term_flushln(struct termp *p)
vbl = 0;
}
- if (ASCII_HYPH == p->buf[i]) {
- (*p->letter)(p, '-');
- p->viscol += (*p->width)(p, '-');
- continue;
- }
-
(*p->letter)(p, p->buf[i]);
if (8 == p->buf[i])
p->viscol -= (*p->width)(p, p->buf[i-1]);
- else
+ else
p->viscol += (*p->width)(p, p->buf[i]);
}
vis = vend;
@@ -264,8 +258,10 @@ term_flushln(struct termp *p)
* If there was trailing white space, it was not printed;
* so reset the cursor position accordingly.
*/
- if (vis)
+ if (vis > vbl)
vis -= vbl;
+ else
+ vis = 0;
p->col = 0;
p->overstep = 0;
@@ -277,8 +273,8 @@ term_flushln(struct termp *p)
}
if (TERMP_HANG & p->flags) {
- p->overstep = (int)(vis - maxvis +
- p->trailspace * (*p->width)(p, ' '));
+ p->overstep += (int)(p->offset + vis - p->rmargin +
+ p->trailspace * (*p->width)(p, ' '));
/*
* If we have overstepped the margin, temporarily move
@@ -301,8 +297,7 @@ term_flushln(struct termp *p)
}
}
-
-/*
+/*
* A newline only breaks an existing line; it won't assert vertical
* space. All data in the output buffer is flushed prior to the newline
* assertion.
@@ -316,7 +311,6 @@ term_newln(struct termp *p)
term_flushln(p);
}
-
/*
* Asserts a vertical space (a full, empty line-break between lines).
* Note that if used twice, this will cause two blank spaces and so on.
@@ -335,6 +329,7 @@ term_vspace(struct termp *p)
(*p->endline)(p);
}
+/* Swap current and previous font; for \fP and .ft P */
void
term_fontlast(struct termp *p)
{
@@ -345,7 +340,7 @@ term_fontlast(struct termp *p)
p->fontq[p->fonti] = f;
}
-
+/* Set font, save current, discard previous; for \f, .ft, .B etc. */
void
term_fontrepl(struct termp *p, enum termfont f)
{
@@ -354,43 +349,31 @@ term_fontrepl(struct termp *p, enum termfont f)
p->fontq[p->fonti] = f;
}
-
+/* Set font, save previous. */
void
term_fontpush(struct termp *p, enum termfont f)
{
- assert(p->fonti + 1 < 10);
p->fontl = p->fontq[p->fonti];
- p->fontq[++p->fonti] = f;
-}
-
-
-const void *
-term_fontq(struct termp *p)
-{
-
- return(&p->fontq[p->fonti]);
-}
-
-
-enum termfont
-term_fonttop(struct termp *p)
-{
-
- return(p->fontq[p->fonti]);
+ if (++p->fonti == p->fontsz) {
+ p->fontsz += 8;
+ p->fontq = mandoc_reallocarray(p->fontq,
+ p->fontsz, sizeof(enum termfont *));
+ }
+ p->fontq[p->fonti] = f;
}
-
+/* Flush to make the saved pointer current again. */
void
-term_fontpopq(struct termp *p, const void *key)
+term_fontpopq(struct termp *p, int i)
{
- while (p->fonti >= 0 && key < (void *)(p->fontq + p->fonti))
- p->fonti--;
- assert(p->fonti >= 0);
+ assert(i >= 0);
+ if (p->fonti > i)
+ p->fonti = i;
}
-
+/* Pop one font off the stack. */
void
term_fontpop(struct termp *p)
{
@@ -409,7 +392,6 @@ term_word(struct termp *p, const char *word)
{
const char nbrsp[2] = { ASCII_NBRSP, 0 };
const char *seq, *cp;
- char c;
int sz, uc;
size_t ssz;
enum mandoc_esc esc;
@@ -430,7 +412,8 @@ term_word(struct termp *p, const char *word)
else
p->flags |= TERMP_NOSPACE;
- p->flags &= ~TERMP_SENTENCE;
+ p->flags &= ~(TERMP_SENTENCE | TERMP_NONEWLINE);
+ p->skipvsp = 0;
while ('\0' != *word) {
if ('\\' != *word) {
@@ -456,70 +439,83 @@ term_word(struct termp *p, const char *word)
word++;
esc = mandoc_escape(&word, &seq, &sz);
if (ESCAPE_ERROR == esc)
- break;
-
- if (TERMENC_ASCII != p->enc)
- switch (esc) {
- case (ESCAPE_UNICODE):
- uc = mchars_num2uc(seq + 1, sz - 1);
- if ('\0' == uc)
- break;
- encode1(p, uc);
- continue;
- case (ESCAPE_SPECIAL):
- uc = mchars_spec2cp(p->symtab, seq, sz);
- if (uc <= 0)
- break;
- encode1(p, uc);
- continue;
- default:
- break;
- }
+ continue;
switch (esc) {
- case (ESCAPE_UNICODE):
- encode1(p, '?');
+ case ESCAPE_UNICODE:
+ uc = mchars_num2uc(seq + 1, sz - 1);
break;
- case (ESCAPE_NUMBERED):
- c = mchars_num2char(seq, sz);
- if ('\0' != c)
- encode(p, &c, 1);
- break;
- case (ESCAPE_SPECIAL):
- cp = mchars_spec2str(p->symtab, seq, sz, &ssz);
- if (NULL != cp)
- encode(p, cp, ssz);
- else if (1 == ssz)
- encode(p, seq, sz);
+ case ESCAPE_NUMBERED:
+ uc = mchars_num2char(seq, sz);
+ if (uc < 0)
+ continue;
break;
- case (ESCAPE_FONTBOLD):
+ case ESCAPE_SPECIAL:
+ if (p->enc == TERMENC_ASCII) {
+ cp = mchars_spec2str(p->symtab,
+ seq, sz, &ssz);
+ if (cp != NULL)
+ encode(p, cp, ssz);
+ } else {
+ uc = mchars_spec2cp(p->symtab, seq, sz);
+ if (uc > 0)
+ encode1(p, uc);
+ }
+ continue;
+ case ESCAPE_FONTBOLD:
term_fontrepl(p, TERMFONT_BOLD);
- break;
- case (ESCAPE_FONTITALIC):
+ continue;
+ case ESCAPE_FONTITALIC:
term_fontrepl(p, TERMFONT_UNDER);
- break;
- case (ESCAPE_FONTBI):
+ continue;
+ case ESCAPE_FONTBI:
term_fontrepl(p, TERMFONT_BI);
- break;
- case (ESCAPE_FONT):
+ continue;
+ case ESCAPE_FONT:
/* FALLTHROUGH */
- case (ESCAPE_FONTROMAN):
+ case ESCAPE_FONTROMAN:
term_fontrepl(p, TERMFONT_NONE);
- break;
- case (ESCAPE_FONTPREV):
+ continue;
+ case ESCAPE_FONTPREV:
term_fontlast(p);
- break;
- case (ESCAPE_NOSPACE):
+ continue;
+ case ESCAPE_NOSPACE:
if (TERMP_SKIPCHAR & p->flags)
p->flags &= ~TERMP_SKIPCHAR;
else if ('\0' == *word)
- p->flags |= TERMP_NOSPACE;
- break;
- case (ESCAPE_SKIPCHAR):
+ p->flags |= (TERMP_NOSPACE | TERMP_NONEWLINE);
+ continue;
+ case ESCAPE_SKIPCHAR:
p->flags |= TERMP_SKIPCHAR;
- break;
+ continue;
+ case ESCAPE_OVERSTRIKE:
+ cp = seq + sz;
+ while (seq < cp) {
+ if (*seq == '\\') {
+ mandoc_escape(&seq, NULL, NULL);
+ continue;
+ }
+ encode1(p, *seq++);
+ if (seq < cp)
+ encode(p, "\b", 1);
+ }
default:
- break;
+ continue;
+ }
+
+ /*
+ * Common handling for Unicode and numbered
+ * character escape sequences.
+ */
+
+ if (p->enc == TERMENC_ASCII) {
+ cp = ascii_uc2str(uc);
+ encode(p, cp, strlen(cp));
+ } else {
+ if ((uc < 0x20 && uc != 0x09) ||
+ (uc > 0x7E && uc < 0xA0))
+ uc = 0xFFFD;
+ encode1(p, uc);
}
}
p->flags &= ~TERMP_NBRWORD;
@@ -534,7 +530,7 @@ adjbuf(struct termp *p, size_t sz)
while (sz >= p->maxcols)
p->maxcols <<= 2;
- p->buf = mandoc_realloc(p->buf, sizeof(int) * p->maxcols);
+ p->buf = mandoc_reallocarray(p->buf, p->maxcols, sizeof(int));
}
static void
@@ -565,7 +561,7 @@ encode1(struct termp *p, int c)
if (p->col + 6 >= p->maxcols)
adjbuf(p, p->col + 6);
- f = term_fonttop(p);
+ f = p->fontq[p->fonti];
if (TERMFONT_UNDER == f || TERMFONT_BI == f) {
p->buf[p->col++] = '_';
@@ -597,8 +593,8 @@ encode(struct termp *p, const char *word, size_t sz)
* character by character.
*/
- if (TERMFONT_NONE == term_fonttop(p)) {
- if (p->col + sz >= p->maxcols)
+ if (p->fontq[p->fonti] == TERMFONT_NONE) {
+ if (p->col + sz >= p->maxcols)
adjbuf(p, p->col + sz);
for (i = 0; i < sz; i++)
p->buf[p->col++] = word[i];
@@ -619,6 +615,36 @@ encode(struct termp *p, const char *word, size_t sz)
}
}
+void
+term_setwidth(struct termp *p, const char *wstr)
+{
+ struct roffsu su;
+ size_t width;
+ int iop;
+
+ iop = 0;
+ width = 0;
+ if (NULL != wstr) {
+ switch (*wstr) {
+ case '+':
+ iop = 1;
+ wstr++;
+ break;
+ case '-':
+ iop = -1;
+ wstr++;
+ break;
+ default:
+ break;
+ }
+ if (a2roffsu(wstr, &su, SCALE_MAX))
+ width = term_hspan(p, &su);
+ else
+ iop = 0;
+ }
+ (*p->setwidth)(p, iop, width);
+}
+
size_t
term_len(const struct termp *p, size_t sz)
{
@@ -641,10 +667,11 @@ size_t
term_strlen(const struct termp *p, const char *cp)
{
size_t sz, rsz, i;
- int ssz, skip, c;
+ int ssz, skip, uc;
const char *seq, *rhs;
enum mandoc_esc esc;
- static const char rej[] = { '\\', ASCII_HYPH, ASCII_NBRSP, '\0' };
+ static const char rej[] = { '\\', ASCII_NBRSP, ASCII_HYPH,
+ ASCII_BREAK, '\0' };
/*
* Account for escaped sequences within string length
@@ -659,80 +686,98 @@ term_strlen(const struct termp *p, const char *cp)
for (i = 0; i < rsz; i++)
sz += cond_width(p, *cp++, &skip);
- c = 0;
switch (*cp) {
- case ('\\'):
+ case '\\':
cp++;
esc = mandoc_escape(&cp, &seq, &ssz);
if (ESCAPE_ERROR == esc)
- return(sz);
-
- if (TERMENC_ASCII != p->enc)
- switch (esc) {
- case (ESCAPE_UNICODE):
- c = mchars_num2uc
- (seq + 1, ssz - 1);
- if ('\0' == c)
- break;
- sz += cond_width(p, c, &skip);
- continue;
- case (ESCAPE_SPECIAL):
- c = mchars_spec2cp
- (p->symtab, seq, ssz);
- if (c <= 0)
- break;
- sz += cond_width(p, c, &skip);
- continue;
- default:
- break;
- }
+ continue;
rhs = NULL;
switch (esc) {
- case (ESCAPE_UNICODE):
- sz += cond_width(p, '?', &skip);
+ case ESCAPE_UNICODE:
+ uc = mchars_num2uc(seq + 1, ssz - 1);
break;
- case (ESCAPE_NUMBERED):
- c = mchars_num2char(seq, ssz);
- if ('\0' != c)
- sz += cond_width(p, c, &skip);
- break;
- case (ESCAPE_SPECIAL):
- rhs = mchars_spec2str
- (p->symtab, seq, ssz, &rsz);
-
- if (ssz != 1 || rhs)
- break;
-
- rhs = seq;
- rsz = ssz;
+ case ESCAPE_NUMBERED:
+ uc = mchars_num2char(seq, ssz);
+ if (uc < 0)
+ continue;
break;
- case (ESCAPE_SKIPCHAR):
+ case ESCAPE_SPECIAL:
+ if (p->enc == TERMENC_ASCII) {
+ rhs = mchars_spec2str(p->symtab,
+ seq, ssz, &rsz);
+ if (rhs != NULL)
+ break;
+ } else {
+ uc = mchars_spec2cp(p->symtab,
+ seq, ssz);
+ if (uc > 0)
+ sz += cond_width(p, uc, &skip);
+ }
+ continue;
+ case ESCAPE_SKIPCHAR:
skip = 1;
- break;
+ continue;
+ case ESCAPE_OVERSTRIKE:
+ rsz = 0;
+ rhs = seq + ssz;
+ while (seq < rhs) {
+ if (*seq == '\\') {
+ mandoc_escape(&seq, NULL, NULL);
+ continue;
+ }
+ i = (*p->width)(p, *seq++);
+ if (rsz < i)
+ rsz = i;
+ }
+ sz += rsz;
+ continue;
default:
- break;
+ continue;
}
- if (NULL == rhs)
- break;
+ /*
+ * Common handling for Unicode and numbered
+ * character escape sequences.
+ */
+
+ if (rhs == NULL) {
+ if (p->enc == TERMENC_ASCII) {
+ rhs = ascii_uc2str(uc);
+ rsz = strlen(rhs);
+ } else {
+ if ((uc < 0x20 && uc != 0x09) ||
+ (uc > 0x7E && uc < 0xA0))
+ uc = 0xFFFD;
+ sz += cond_width(p, uc, &skip);
+ continue;
+ }
+ }
if (skip) {
skip = 0;
break;
}
+ /*
+ * Common handling for all escape sequences
+ * printing more than one character.
+ */
+
for (i = 0; i < rsz; i++)
sz += (*p->width)(p, *rhs++);
break;
- case (ASCII_NBRSP):
+ case ASCII_NBRSP:
sz += cond_width(p, ' ', &skip);
cp++;
break;
- case (ASCII_HYPH):
+ case ASCII_HYPH:
sz += cond_width(p, '-', &skip);
cp++;
+ /* FALLTHROUGH */
+ case ASCII_BREAK:
break;
default:
break;
@@ -742,50 +787,55 @@ term_strlen(const struct termp *p, const char *cp)
return(sz);
}
-/* ARGSUSED */
-size_t
+int
term_vspan(const struct termp *p, const struct roffsu *su)
{
double r;
+ int ri;
switch (su->unit) {
- case (SCALE_CM):
- r = su->scale * 2;
+ case SCALE_BU:
+ r = su->scale / 40.0;
+ break;
+ case SCALE_CM:
+ r = su->scale * 6.0 / 2.54;
+ break;
+ case SCALE_FS:
+ r = su->scale * 65536.0 / 40.0;
+ break;
+ case SCALE_IN:
+ r = su->scale * 6.0;
break;
- case (SCALE_IN):
- r = su->scale * 6;
+ case SCALE_MM:
+ r = su->scale * 0.006;
break;
- case (SCALE_PC):
+ case SCALE_PC:
r = su->scale;
break;
- case (SCALE_PT):
- r = su->scale / 8;
+ case SCALE_PT:
+ r = su->scale / 12.0;
break;
- case (SCALE_MM):
- r = su->scale / 1000;
+ case SCALE_EN:
+ /* FALLTHROUGH */
+ case SCALE_EM:
+ r = su->scale * 0.6;
break;
- case (SCALE_VS):
+ case SCALE_VS:
r = su->scale;
break;
default:
- r = su->scale - 1;
- break;
+ abort();
+ /* NOTREACHED */
}
-
- if (r < 0.0)
- r = 0.0;
- return(/* LINTED */(size_t)
- r);
+ ri = r > 0.0 ? r + 0.4995 : r - 0.4995;
+ return(ri < 66 ? ri : 1);
}
-size_t
+int
term_hspan(const struct termp *p, const struct roffsu *su)
{
double v;
- v = ((*p->hspan)(p, su));
- if (v < 0.0)
- v = 0.0;
- return((size_t) /* LINTED */
- v);
+ v = (*p->hspan)(p, su);
+ return(v > 0.0 ? v + 0.0005 : v - 0.0005);
}
diff --git a/usr/src/cmd/mandoc/term.h b/usr/src/cmd/mandoc/term.h
index 8cad4be838..b65524b610 100644
--- a/usr/src/cmd/mandoc/term.h
+++ b/usr/src/cmd/mandoc/term.h
@@ -1,7 +1,7 @@
-/* $Id: term.h,v 1.97 2013/12/25 00:39:31 schwarze Exp $ */
+/* $Id: term.h,v 1.111 2015/01/31 00:12:41 schwarze Exp $ */
/*
* Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011, 2012, 2013, 2014 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,12 +15,6 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef TERM_H
-#define TERM_H
-
-__BEGIN_DECLS
-
-struct termp;
enum termenc {
TERMENC_ASCII,
@@ -44,6 +38,8 @@ enum termfont {
#define TERM_MAXMARGIN 100000 /* FIXME */
+struct termp;
+
typedef void (*term_margin)(struct termp *, const void *);
struct termp_tbl {
@@ -54,9 +50,11 @@ struct termp_tbl {
struct termp {
enum termtype type;
struct rofftbl tbl; /* table configuration */
+ int synopsisonly; /* print the synopsis only */
int mdocstyle; /* imitate mdoc(7) output */
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. */
@@ -76,16 +74,18 @@ struct termp {
#define TERMP_PREKEEP (1 << 6) /* ...starting with the next one. */
#define TERMP_SKIPCHAR (1 << 7) /* Skip the next character. */
#define TERMP_NOBREAK (1 << 8) /* See term_flushln(). */
-#define TERMP_DANGLE (1 << 9) /* See term_flushln(). */
-#define TERMP_HANG (1 << 10) /* See term_flushln(). */
-#define TERMP_NOSPLIT (1 << 11) /* See termp_an_pre/post(). */
-#define TERMP_SPLIT (1 << 12) /* See termp_an_pre/post(). */
-#define TERMP_ANPREC (1 << 13) /* See termp_an_pre(). */
+#define TERMP_BRIND (1 << 9) /* See term_flushln(). */
+#define TERMP_DANGLE (1 << 10) /* See term_flushln(). */
+#define TERMP_HANG (1 << 11) /* See term_flushln(). */
+#define TERMP_NOSPLIT (1 << 12) /* Do not break line before .An. */
+#define TERMP_SPLIT (1 << 13) /* Break line before .An. */
+#define TERMP_NONEWLINE (1 << 14) /* No line break in nofill mode. */
int *buf; /* Output buffer. */
enum termenc enc; /* Type of encoding. */
- struct mchars *symtab; /* Encoded-symbol table. */
+ const struct mchars *symtab; /* Character table. */
enum termfont fontl; /* Last font set. */
- enum termfont fontq[10]; /* Symmetric fonts. */
+ enum termfont *fontq; /* Symmetric fonts. */
+ int fontsz; /* Allocated size of font stack */
int fonti; /* Index of font stack. */
term_margin headf; /* invoked to print head */
term_margin footf; /* invoked to print foot */
@@ -94,6 +94,7 @@ struct termp {
void (*end)(struct termp *);
void (*endline)(struct termp *);
void (*advance)(struct termp *, size_t);
+ void (*setwidth)(struct termp *, int, size_t);
size_t (*width)(const struct termp *, int);
double (*hspan)(const struct termp *,
const struct roffsu *);
@@ -101,6 +102,13 @@ struct termp {
struct termp_ps *ps;
};
+__BEGIN_DECLS
+
+struct tbl_span;
+struct eqn;
+
+const char *ascii_uc2str(int);
+
void term_eqn(struct termp *, const struct eqn *);
void term_tbl(struct termp *, const struct tbl_span *);
void term_free(struct termp *);
@@ -108,25 +116,20 @@ void term_newln(struct termp *);
void term_vspace(struct termp *);
void term_word(struct termp *, const char *);
void term_flushln(struct termp *);
-void term_begin(struct termp *, term_margin,
+void term_begin(struct termp *, term_margin,
term_margin, const void *);
void term_end(struct termp *);
-size_t term_hspan(const struct termp *,
- const struct roffsu *);
-size_t term_vspan(const struct termp *,
- const struct roffsu *);
+void term_setwidth(struct termp *, const char *);
+int term_hspan(const struct termp *, const struct roffsu *);
+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);
-enum termfont term_fonttop(struct termp *);
-const void *term_fontq(struct termp *);
void term_fontpush(struct termp *, enum termfont);
void term_fontpop(struct termp *);
-void term_fontpopq(struct termp *, const void *);
+void term_fontpopq(struct termp *, int);
void term_fontrepl(struct termp *, enum termfont);
void term_fontlast(struct termp *);
__END_DECLS
-
-#endif /*!TERM_H*/
diff --git a/usr/src/cmd/mandoc/term_ascii.c b/usr/src/cmd/mandoc/term_ascii.c
index cb7ac29405..4ce4b686c4 100644
--- a/usr/src/cmd/mandoc/term_ascii.c
+++ b/usr/src/cmd/mandoc/term_ascii.c
@@ -1,6 +1,7 @@
-/* $Id: term_ascii.c,v 1.21 2013/06/01 14:27:20 schwarze Exp $ */
+/* $Id: term_ascii.c,v 1.43 2015/02/16 14:11:41 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014 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,41 +15,30 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#include <sys/types.h>
#include <assert.h>
-#ifdef USE_WCHAR
-# include <locale.h>
+#if HAVE_WCHAR
+#include <locale.h>
#endif
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
-#ifdef USE_WCHAR
-# include <wchar.h>
+#if HAVE_WCHAR
+#include <wchar.h>
#endif
#include "mandoc.h"
+#include "mandoc_aux.h"
#include "out.h"
#include "term.h"
#include "main.h"
-/*
- * Sadly, this doesn't seem to be defined on systems even when they
- * support it. For the time being, remove it and let those compiling
- * the software decide for themselves what to use.
- */
-#if 0
-#if ! defined(__STDC_ISO_10646__)
-# undef USE_WCHAR
-#endif
-#endif
-
-static struct termp *ascii_init(enum termenc, char *);
+static struct termp *ascii_init(enum termenc,
+ const struct mchars *, char *);
static double ascii_hspan(const struct termp *,
const struct roffsu *);
static size_t ascii_width(const struct termp *, int);
@@ -57,25 +47,33 @@ static void ascii_begin(struct termp *);
static void ascii_end(struct termp *);
static void ascii_endline(struct termp *);
static void ascii_letter(struct termp *, int);
+static void ascii_setwidth(struct termp *, int, size_t);
-#ifdef USE_WCHAR
+#if HAVE_WCHAR
static void locale_advance(struct termp *, size_t);
static void locale_endline(struct termp *);
static void locale_letter(struct termp *, int);
static size_t locale_width(const struct termp *, int);
#endif
+
static struct termp *
-ascii_init(enum termenc enc, char *outopts)
+ascii_init(enum termenc enc, const struct mchars *mchars, char *outopts)
{
- const char *toks[4];
+ const char *toks[5];
char *v;
struct termp *p;
+ const char *errstr;
+ int num;
p = mandoc_calloc(1, sizeof(struct termp));
+ p->symtab = mchars;
p->tabwidth = 5;
- p->defrmargin = 78;
+ p->defrmargin = p->lastrmargin = 78;
+ p->fontq = mandoc_reallocarray(NULL,
+ (p->fontsz = 8), sizeof(enum termfont));
+ p->fontq[0] = p->fontl = TERMFONT_NONE;
p->begin = ascii_begin;
p->end = ascii_end;
@@ -86,13 +84,14 @@ ascii_init(enum termenc enc, char *outopts)
p->advance = ascii_advance;
p->endline = ascii_endline;
p->letter = ascii_letter;
+ p->setwidth = ascii_setwidth;
p->width = ascii_width;
-#ifdef USE_WCHAR
+#if HAVE_WCHAR
if (TERMENC_ASCII != enc) {
v = TERMENC_LOCALE == enc ?
- setlocale(LC_ALL, "") :
- setlocale(LC_CTYPE, "en_US.UTF-8");
+ setlocale(LC_ALL, "") :
+ setlocale(LC_CTYPE, "en_US.UTF-8");
if (NULL != v && MB_CUR_MAX > 1) {
p->enc = enc;
p->advance = locale_advance;
@@ -106,17 +105,22 @@ ascii_init(enum termenc enc, char *outopts)
toks[0] = "indent";
toks[1] = "width";
toks[2] = "mdoc";
- toks[3] = NULL;
+ toks[3] = "synopsis";
+ toks[4] = NULL;
while (outopts && *outopts)
switch (getsubopt(&outopts, UNCONST(toks), &v)) {
- case (0):
- p->defindent = (size_t)atoi(v);
+ case 0:
+ num = strtonum(v, 0, 1000, &errstr);
+ if (!errstr)
+ p->defindent = num;
break;
- case (1):
- p->defrmargin = (size_t)atoi(v);
+ case 1:
+ num = strtonum(v, 0, 1000, &errstr);
+ if (!errstr)
+ p->defrmargin = num;
break;
- case (2):
+ case 2:
/*
* Temporary, undocumented mode
* to imitate mdoc(7) output style.
@@ -124,6 +128,9 @@ ascii_init(enum termenc enc, char *outopts)
p->mdocstyle = 1;
p->defindent = 5;
break;
+ case 3:
+ p->synopsisonly = 1;
+ break;
default:
break;
}
@@ -136,28 +143,57 @@ ascii_init(enum termenc enc, char *outopts)
}
void *
-ascii_alloc(char *outopts)
+ascii_alloc(const struct mchars *mchars, char *outopts)
{
- return(ascii_init(TERMENC_ASCII, outopts));
+ return(ascii_init(TERMENC_ASCII, mchars, outopts));
}
void *
-utf8_alloc(char *outopts)
+utf8_alloc(const struct mchars *mchars, char *outopts)
{
- return(ascii_init(TERMENC_UTF8, outopts));
+ return(ascii_init(TERMENC_UTF8, mchars, outopts));
}
-
void *
-locale_alloc(char *outopts)
+locale_alloc(const struct mchars *mchars, char *outopts)
+{
+
+ return(ascii_init(TERMENC_LOCALE, mchars, outopts));
+}
+
+static void
+ascii_setwidth(struct termp *p, int iop, size_t width)
+{
+
+ p->rmargin = p->defrmargin;
+ if (iop > 0)
+ p->defrmargin += width;
+ else if (iop == 0)
+ p->defrmargin = width ? width : p->lastrmargin;
+ else if (p->defrmargin > width)
+ p->defrmargin -= width;
+ else
+ p->defrmargin = 0;
+ p->lastrmargin = p->rmargin;
+ p->rmargin = p->maxrmargin = p->defrmargin;
+}
+
+void
+ascii_sepline(void *arg)
{
+ struct termp *p;
+ size_t i;
- return(ascii_init(TERMENC_LOCALE, outopts));
+ p = (struct termp *)arg;
+ putchar('\n');
+ for (i = 0; i < p->defrmargin; i++)
+ putchar('-');
+ putchar('\n');
+ putchar('\n');
}
-/* ARGSUSED */
static size_t
ascii_width(const struct termp *p, int c)
{
@@ -172,11 +208,10 @@ ascii_free(void *arg)
term_free((struct termp *)arg);
}
-/* ARGSUSED */
static void
ascii_letter(struct termp *p, int c)
{
-
+
putchar(c);
}
@@ -194,7 +229,6 @@ ascii_end(struct termp *p)
(*p->footf)(p, p->argf);
}
-/* ARGSUSED */
static void
ascii_endline(struct termp *p)
{
@@ -202,75 +236,162 @@ ascii_endline(struct termp *p)
putchar('\n');
}
-/* ARGSUSED */
static void
ascii_advance(struct termp *p, size_t len)
{
- size_t i;
+ size_t i;
for (i = 0; i < len; i++)
putchar(' ');
}
-/* ARGSUSED */
static double
ascii_hspan(const struct termp *p, const struct roffsu *su)
{
double r;
/*
- * Approximate based on character width. These are generated
- * entirely by eyeballing the screen, but appear to be correct.
+ * Approximate based on character width.
+ * None of these will be actually correct given that an inch on
+ * the screen depends on character size, terminal, etc., etc.
*/
-
switch (su->unit) {
- case (SCALE_CM):
- r = 4 * su->scale;
+ case SCALE_BU:
+ r = su->scale * 10.0 / 240.0;
break;
- case (SCALE_IN):
- r = 10 * su->scale;
+ case SCALE_CM:
+ r = su->scale * 10.0 / 2.54;
break;
- case (SCALE_PC):
- r = (10 * su->scale) / 6;
+ case SCALE_FS:
+ r = su->scale * 2730.666;
break;
- case (SCALE_PT):
- r = (10 * su->scale) / 72;
+ case SCALE_IN:
+ r = su->scale * 10.0;
break;
- case (SCALE_MM):
- r = su->scale / 1000;
+ case SCALE_MM:
+ r = su->scale / 100.0;
break;
- case (SCALE_VS):
- r = su->scale * 2 - 1;
+ case SCALE_PC:
+ r = su->scale * 10.0 / 6.0;
break;
- default:
+ case SCALE_PT:
+ r = su->scale * 10.0 / 72.0;
+ break;
+ case SCALE_VS:
+ r = su->scale * 2.0 - 1.0;
+ break;
+ case SCALE_EN:
+ /* FALLTHROUGH */
+ case SCALE_EM:
r = su->scale;
break;
+ default:
+ abort();
+ /* NOTREACHED */
}
return(r);
}
-#ifdef USE_WCHAR
-/* ARGSUSED */
+const char *
+ascii_uc2str(int uc)
+{
+ static const char nbrsp[2] = { ASCII_NBRSP, '\0' };
+ static const char *tab[] = {
+ "<NUL>","<SOH>","<STX>","<ETX>","<EOT>","<ENQ>","<ACK>","<BEL>",
+ "<BS>", "\t", "<LF>", "<VT>", "<FF>", "<CR>", "<SO>", "<SI>",
+ "<DLE>","<DC1>","<DC2>","<DC3>","<DC4>","<NAK>","<SYN>","<ETB>",
+ "<CAN>","<EM>", "<SUB>","<ESC>","<FS>", "<GS>", "<RS>", "<US>",
+ " ", "!", "\"", "#", "$", "%", "&", "'",
+ "(", ")", "*", "+", ",", "-", ".", "/",
+ "0", "1", "2", "3", "4", "5", "6", "7",
+ "8", "9", ":", ";", "<", "=", ">", "?",
+ "@", "A", "B", "C", "D", "E", "F", "G",
+ "H", "I", "J", "K", "L", "M", "N", "O",
+ "P", "Q", "R", "S", "T", "U", "V", "W",
+ "X", "Y", "Z", "[", "\\", "]", "^", "_",
+ "`", "a", "b", "c", "d", "e", "f", "g",
+ "h", "i", "j", "k", "l", "m", "n", "o",
+ "p", "q", "r", "s", "t", "u", "v", "w",
+ "x", "y", "z", "{", "|", "}", "~", "<DEL>",
+ "<80>", "<81>", "<82>", "<83>", "<84>", "<85>", "<86>", "<87>",
+ "<88>", "<89>", "<8A>", "<8B>", "<8C>", "<8D>", "<8E>", "<8F>",
+ "<90>", "<91>", "<92>", "<93>", "<94>", "<95>", "<96>", "<97>",
+ "<99>", "<99>", "<9A>", "<9B>", "<9C>", "<9D>", "<9E>", "<9F>",
+ nbrsp, "!", "/\bc", "GBP", "o\bx", "=\bY", "|", "<sec>",
+ "\"", "(C)", "_\ba", "<<", "~", "", "(R)", "-",
+ "<deg>","+-", "2", "3", "'", ",\bu", "<par>",".",
+ ",", "1", "_\bo", ">>", "1/4", "1/2", "3/4", "?",
+ "`\bA", "'\bA", "^\bA", "~\bA", "\"\bA","o\bA", "AE", ",\bC",
+ "`\bE", "'\bE", "^\bE", "\"\bE","`\bI", "'\bI", "^\bI", "\"\bI",
+ "-\bD", "~\bN", "`\bO", "'\bO", "^\bO", "~\bO", "\"\bO","x",
+ "/\bO", "`\bU", "'\bU", "^\bU", "\"\bU","'\bY", "Th", "ss",
+ "`\ba", "'\ba", "^\ba", "~\ba", "\"\ba","o\ba", "ae", ",\bc",
+ "`\be", "'\be", "^\be", "\"\be","`\bi", "'\bi", "^\bi", "\"\bi",
+ "d", "~\bn", "`\bo", "'\bo", "^\bo", "~\bo", "\"\bo","-:-",
+ "/\bo", "`\bu", "'\bu", "^\bu", "\"\bu","'\by", "th", "\"\by",
+ "A", "a", "A", "a", "A", "a", "'\bC", "'\bc",
+ "^\bC", "^\bc", "C", "c", "C", "c", "D", "d",
+ "/\bD", "/\bd", "E", "e", "E", "e", "E", "e",
+ "E", "e", "E", "e", "^\bG", "^\bg", "G", "g",
+ "G", "g", ",\bG", ",\bg", "^\bH", "^\bh", "/\bH", "/\bh",
+ "~\bI", "~\bi", "I", "i", "I", "i", "I", "i",
+ "I", "i", "IJ", "ij", "^\bJ", "^\bj", ",\bK", ",\bk",
+ "q", "'\bL", "'\bl", ",\bL", ",\bl", "L", "l", "L",
+ "l", "/\bL", "/\bl", "'\bN", "'\bn", ",\bN", ",\bn", "N",
+ "n", "'n", "Ng", "ng", "O", "o", "O", "o",
+ "O", "o", "OE", "oe", "'\bR", "'\br", ",\bR", ",\br",
+ "R", "r", "'\bS", "'\bs", "^\bS", "^\bs", ",\bS", ",\bs",
+ "S", "s", ",\bT", ",\bt", "T", "t", "/\bT", "/\bt",
+ "~\bU", "~\bu", "U", "u", "U", "u", "U", "u",
+ "U", "u", "U", "u", "^\bW", "^\bw", "^\bY", "^\by",
+ "\"\bY","'\bZ", "'\bz", "Z", "z", "Z", "z", "s",
+ "b", "B", "B", "b", "6", "6", "O", "C",
+ "c", "D", "D", "D", "d", "d", "3", "@",
+ "E", "F", ",\bf", "G", "G", "hv", "I", "/\bI",
+ "K", "k", "/\bl", "l", "W", "N", "n", "~\bO",
+ "O", "o", "OI", "oi", "P", "p", "YR", "2",
+ "2", "SH", "sh", "t", "T", "t", "T", "U",
+ "u", "Y", "V", "Y", "y", "/\bZ", "/\bz", "ZH",
+ "ZH", "zh", "zh", "/\b2", "5", "5", "ts", "w",
+ "|", "||", "|=", "!", "DZ", "Dz", "dz", "LJ",
+ "Lj", "lj", "NJ", "Nj", "nj", "A", "a", "I",
+ "i", "O", "o", "U", "u", "U", "u", "U",
+ "u", "U", "u", "U", "u", "@", "A", "a",
+ "A", "a", "AE", "ae", "/\bG", "/\bg", "G", "g",
+ "K", "k", "O", "o", "O", "o", "ZH", "zh",
+ "j", "DZ", "Dz", "dz", "'\bG", "'\bg", "HV", "W",
+ "`\bN", "`\bn", "A", "a", "'\bAE","'\bae","O", "o"};
+
+ assert(uc >= 0);
+ if ((size_t)uc < sizeof(tab)/sizeof(tab[0]))
+ return(tab[uc]);
+ return(mchars_uc2str(uc));
+}
+
+#if HAVE_WCHAR
static size_t
locale_width(const struct termp *p, int c)
{
int rc;
- return((rc = wcwidth(c)) < 0 ? 0 : rc);
+ if (c == ASCII_NBRSP)
+ c = ' ';
+ rc = wcwidth(c);
+ if (rc < 0)
+ rc = 0;
+ return(rc);
}
-/* ARGSUSED */
static void
locale_advance(struct termp *p, size_t len)
{
- size_t i;
+ size_t i;
for (i = 0; i < len; i++)
putwchar(L' ');
}
-/* ARGSUSED */
static void
locale_endline(struct termp *p)
{
@@ -278,11 +399,10 @@ locale_endline(struct termp *p)
putwchar(L'\n');
}
-/* ARGSUSED */
static void
locale_letter(struct termp *p, int c)
{
-
+
putwchar(c);
}
#endif
diff --git a/usr/src/cmd/mandoc/term_ps.c b/usr/src/cmd/mandoc/term_ps.c
index e8a906858a..12ca7d6716 100644
--- a/usr/src/cmd/mandoc/term_ps.c
+++ b/usr/src/cmd/mandoc/term_ps.c
@@ -1,6 +1,7 @@
-/* $Id: term_ps.c,v 1.54 2011/10/16 12:20:34 schwarze Exp $ */
+/* $Id: term_ps.c,v 1.72 2015/01/21 19:40:54 schwarze Exp $ */
/*
* Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014, 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
@@ -14,9 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
#include <sys/types.h>
@@ -26,23 +25,22 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <time.h>
#include <unistd.h>
-#include "mandoc.h"
+#include "mandoc_aux.h"
#include "out.h"
-#include "main.h"
#include "term.h"
+#include "main.h"
/* These work the buffer used by the header and footer. */
#define PS_BUFSLOP 128
/* Convert PostScript point "x" to an AFM unit. */
-#define PNT2AFM(p, x) /* LINTED */ \
+#define PNT2AFM(p, x) \
(size_t)((double)(x) * (1000.0 / (double)(p)->ps->scale))
/* Convert an AFM unit "x" to a PostScript points */
-#define AFM2PNT(p, x) /* LINTED */ \
+#define AFM2PNT(p, x) \
((double)(x) / (1000.0 / (double)(p)->ps->scale))
struct glyph {
@@ -60,13 +58,16 @@ struct termp_ps {
#define PS_INLINE (1 << 0) /* we're in a word */
#define PS_MARGINS (1 << 1) /* we're in the margins */
#define PS_NEWPAGE (1 << 2) /* new page, no words yet */
+#define PS_BACKSP (1 << 3) /* last character was backspace */
size_t pscol; /* visible column (AFM units) */
+ size_t pscolnext; /* used for overstrike */
size_t psrow; /* visible row (AFM units) */
char *psmarg; /* margin buf */
size_t psmargsz; /* margin buf size */
size_t psmargcur; /* cur index in margin buf */
- char last; /* character buffer */
+ char last; /* last non-backspace seen */
enum termfont lastf; /* last set font */
+ enum termfont nextf; /* building next font here */
size_t scale; /* font scaling factor */
size_t pages; /* number of pages shown */
size_t lineheight; /* line height (AFM units) */
@@ -74,10 +75,11 @@ struct termp_ps {
size_t bottom; /* body bottom (AFM units) */
size_t height; /* page height (AFM units */
size_t width; /* page width (AFM units) */
+ size_t lastwidth; /* page width before last ll */
size_t left; /* body left (AFM units) */
size_t header; /* header pos (AFM units) */
size_t footer; /* footer pos (AFM units) */
- size_t pdfbytes; /* current output byte */
+ size_t pdfbytes; /* current output byte */
size_t pdflastpg; /* byte of last page mark */
size_t pdfbody; /* start of body object */
size_t *pdfobjs; /* table of object offsets */
@@ -97,10 +99,14 @@ static void ps_growbuf(struct termp *, size_t);
static void ps_letter(struct termp *, int);
static void ps_pclose(struct termp *);
static void ps_pletter(struct termp *, int);
+#if __GNUC__ - 0 >= 4
+__attribute__((__format__ (__printf__, 2, 3)))
+#endif
static void ps_printf(struct termp *, const char *, ...);
static void ps_putchar(struct termp *, char);
static void ps_setfont(struct termp *, enum termfont);
-static struct termp *pspdf_alloc(char *);
+static void ps_setwidth(struct termp *, int, size_t);
+static struct termp *pspdf_alloc(const struct mchars *, char *);
static void pdf_obj(struct termp *, size_t);
/*
@@ -401,32 +407,129 @@ static const struct font fonts[TERMFONT__MAX] = {
{ 400 },
{ 541 },
} },
+ { "Times-BoldItalic", {
+ { 250 },
+ { 389 },
+ { 555 },
+ { 500 },
+ { 500 },
+ { 833 },
+ { 778 },
+ { 333 },
+ { 333 },
+ { 333 },
+ { 500 },
+ { 570 },
+ { 250 },
+ { 333 },
+ { 250 },
+ { 278 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 333 },
+ { 333 },
+ { 570 },
+ { 570 },
+ { 570 },
+ { 500 },
+ { 832 },
+ { 667 },
+ { 667 },
+ { 667 },
+ { 722 },
+ { 667 },
+ { 667 },
+ { 722 },
+ { 778 },
+ { 389 },
+ { 500 },
+ { 667 },
+ { 611 },
+ { 889 },
+ { 722 },
+ { 722 },
+ { 611 },
+ { 722 },
+ { 667 },
+ { 556 },
+ { 611 },
+ { 722 },
+ { 667 },
+ { 889 },
+ { 667 },
+ { 611 },
+ { 611 },
+ { 333 },
+ { 278 },
+ { 333 },
+ { 570 },
+ { 500 },
+ { 333 },
+ { 500 },
+ { 500 },
+ { 444 },
+ { 500 },
+ { 444 },
+ { 333 },
+ { 500 },
+ { 556 },
+ { 278 },
+ { 278 },
+ { 500 },
+ { 278 },
+ { 778 },
+ { 556 },
+ { 500 },
+ { 500 },
+ { 500 },
+ { 389 },
+ { 389 },
+ { 278 },
+ { 556 },
+ { 444 },
+ { 667 },
+ { 500 },
+ { 444 },
+ { 389 },
+ { 348 },
+ { 220 },
+ { 348 },
+ { 570 },
+ } },
};
void *
-pdf_alloc(char *outopts)
+pdf_alloc(const struct mchars *mchars, char *outopts)
{
struct termp *p;
- if (NULL != (p = pspdf_alloc(outopts)))
+ if (NULL != (p = pspdf_alloc(mchars, outopts)))
p->type = TERMTYPE_PDF;
return(p);
}
void *
-ps_alloc(char *outopts)
+ps_alloc(const struct mchars *mchars, char *outopts)
{
struct termp *p;
- if (NULL != (p = pspdf_alloc(outopts)))
+ if (NULL != (p = pspdf_alloc(mchars, outopts)))
p->type = TERMTYPE_PS;
return(p);
}
static struct termp *
-pspdf_alloc(char *outopts)
+pspdf_alloc(const struct mchars *mchars, char *outopts)
{
struct termp *p;
unsigned int pagex, pagey;
@@ -436,7 +539,11 @@ pspdf_alloc(char *outopts)
char *v;
p = mandoc_calloc(1, sizeof(struct termp));
+ p->symtab = mchars;
p->enc = TERMENC_ASCII;
+ p->fontq = mandoc_reallocarray(NULL,
+ (p->fontsz = 8), sizeof(enum termfont));
+ p->fontq[0] = p->fontl = TERMFONT_NONE;
p->ps = mandoc_calloc(1, sizeof(struct termp_ps));
p->advance = ps_advance;
@@ -445,8 +552,9 @@ pspdf_alloc(char *outopts)
p->endline = ps_endline;
p->hspan = ps_hspan;
p->letter = ps_letter;
+ p->setwidth = ps_setwidth;
p->width = ps_width;
-
+
toks[0] = "paper";
toks[1] = NULL;
@@ -454,7 +562,7 @@ pspdf_alloc(char *outopts)
while (outopts && *outopts)
switch (getsubopt(&outopts, UNCONST(toks), &v)) {
- case (0):
+ case 0:
pp = v;
break;
default:
@@ -490,7 +598,7 @@ pspdf_alloc(char *outopts)
fprintf(stderr, "%s: Unknown paper\n", pp);
}
- /*
+ /*
* This MUST be defined before any PNT2AFM or AFM2PNT
* calculations occur.
*/
@@ -504,16 +612,14 @@ pspdf_alloc(char *outopts)
/* Margins are 1/9 the page x and y. */
- marginx = /* LINTED */
- (size_t)((double)pagex / 9.0);
- marginy = /* LINTED */
- (size_t)((double)pagey / 9.0);
+ marginx = (size_t)((double)pagex / 9.0);
+ marginy = (size_t)((double)pagey / 9.0);
/* Line-height is 1.4em. */
lineheight = PNT2AFM(p, ((double)p->ps->scale * 1.4));
- p->ps->width = (size_t)pagex;
+ p->ps->width = p->ps->lastwidth = (size_t)pagex;
p->ps->height = (size_t)pagey;
p->ps->header = pagey - (marginy / 2) - (lineheight / 2);
p->ps->top = pagey - marginy;
@@ -526,6 +632,22 @@ pspdf_alloc(char *outopts)
return(p);
}
+static void
+ps_setwidth(struct termp *p, int iop, size_t width)
+{
+ size_t lastwidth;
+
+ lastwidth = p->ps->width;
+ if (iop > 0)
+ p->ps->width += width;
+ else if (iop == 0)
+ p->ps->width = width ? width : p->ps->lastwidth;
+ else if (p->ps->width > width)
+ p->ps->width -= width;
+ else
+ p->ps->width = 0;
+ p->ps->lastwidth = lastwidth;
+}
void
pspdf_free(void *arg)
@@ -543,7 +665,6 @@ pspdf_free(void *arg)
term_free(p);
}
-
static void
ps_printf(struct termp *p, const char *fmt, ...)
{
@@ -561,12 +682,11 @@ ps_printf(struct termp *p, const char *fmt, ...)
if ( ! (PS_MARGINS & p->ps->flags)) {
len = vprintf(fmt, ap);
va_end(ap);
- p->ps->pdfbytes += /* LINTED */
- len < 0 ? 0 : (size_t)len;
+ p->ps->pdfbytes += len < 0 ? 0 : (size_t)len;
return;
}
- /*
+ /*
* XXX: I assume that the in-margin print won't exceed
* PS_BUFSLOP (128 bytes), which is reasonable but still an
* assumption that will cause pukeage if it's not the case.
@@ -582,7 +702,6 @@ ps_printf(struct termp *p, const char *fmt, ...)
p->ps->psmargcur = strlen(p->ps->psmarg);
}
-
static void
ps_putchar(struct termp *p, char c)
{
@@ -591,7 +710,6 @@ ps_putchar(struct termp *p, char c)
/* See ps_printf(). */
if ( ! (PS_MARGINS & p->ps->flags)) {
- /* LINTED */
putchar(c);
p->ps->pdfbytes++;
return;
@@ -604,7 +722,6 @@ ps_putchar(struct termp *p, char c)
p->ps->psmarg[pos] = '\0';
}
-
static void
pdf_obj(struct termp *p, size_t obj)
{
@@ -613,20 +730,14 @@ pdf_obj(struct termp *p, size_t obj)
if ((obj - 1) >= p->ps->pdfobjsz) {
p->ps->pdfobjsz = obj + 128;
- p->ps->pdfobjs = realloc
- (p->ps->pdfobjs,
- p->ps->pdfobjsz * sizeof(size_t));
- if (NULL == p->ps->pdfobjs) {
- perror(NULL);
- exit((int)MANDOCLEVEL_SYSERR);
- }
+ p->ps->pdfobjs = mandoc_reallocarray(p->ps->pdfobjs,
+ p->ps->pdfobjsz, sizeof(size_t));
}
p->ps->pdfobjs[(int)obj - 1] = p->ps->pdfbytes;
ps_printf(p, "%zu 0 obj\n", obj);
}
-
static void
ps_closepage(struct termp *p)
{
@@ -659,7 +770,7 @@ ps_closepage(struct termp *p)
pdf_obj(p, base + 2);
ps_printf(p, "<<\n/ProcSet [/PDF /Text]\n");
ps_printf(p, "/Font <<\n");
- for (i = 0; i < (int)TERMFONT__MAX; i++)
+ for (i = 0; i < (int)TERMFONT__MAX; i++)
ps_printf(p, "/F%d %d 0 R\n", i, 3 + i);
ps_printf(p, ">>\n>>\n");
@@ -680,8 +791,6 @@ ps_closepage(struct termp *p)
p->ps->flags |= PS_NEWPAGE;
}
-
-/* ARGSUSED */
static void
ps_end(struct termp *p)
{
@@ -704,7 +813,7 @@ ps_end(struct termp *p)
ps_printf(p, "%%%%Pages: %zu\n", p->ps->pages);
ps_printf(p, "%%%%EOF\n");
return;
- }
+ }
pdf_obj(p, 2);
ps_printf(p, "<<\n/Type /Pages\n");
@@ -716,11 +825,9 @@ ps_end(struct termp *p)
ps_printf(p, "/Kids [");
for (i = 0; i < p->ps->pages; i++)
- ps_printf(p, " %zu 0 R", i * 4 +
- p->ps->pdfbody + 3);
+ ps_printf(p, " %zu 0 R", i * 4 + p->ps->pdfbody + 3);
- base = (p->ps->pages - 1) * 4 +
- p->ps->pdfbody + 4;
+ base = (p->ps->pages - 1) * 4 + p->ps->pdfbody + 4;
ps_printf(p, "]\n>>\nendobj\n");
pdf_obj(p, base);
@@ -734,8 +841,8 @@ ps_end(struct termp *p)
ps_printf(p, "0000000000 65535 f \n");
for (i = 0; i < base; i++)
- ps_printf(p, "%.10zu 00000 n \n",
- p->ps->pdfobjs[(int)i]);
+ ps_printf(p, "%.10zu 00000 n \n",
+ p->ps->pdfobjs[(int)i]);
ps_printf(p, "trailer\n");
ps_printf(p, "<<\n");
@@ -748,14 +855,12 @@ ps_end(struct termp *p)
ps_printf(p, "%%%%EOF\n");
}
-
static void
ps_begin(struct termp *p)
{
- time_t t;
int i;
- /*
+ /*
* Print margins into margin buffer. Nothing gets output to the
* screen yet, so we don't need to initialise the primary state.
*/
@@ -788,24 +893,21 @@ ps_begin(struct termp *p)
assert(p->ps->psmarg);
assert('\0' != p->ps->psmarg[0]);
- /*
+ /*
* Print header and initialise page state. Following this,
* stuff gets printed to the screen, so make sure we're sane.
*/
- t = time(NULL);
-
if (TERMTYPE_PS == p->type) {
ps_printf(p, "%%!PS-Adobe-3.0\n");
- ps_printf(p, "%%%%CreationDate: %s", ctime(&t));
ps_printf(p, "%%%%DocumentData: Clean7Bit\n");
ps_printf(p, "%%%%Orientation: Portrait\n");
ps_printf(p, "%%%%Pages: (atend)\n");
ps_printf(p, "%%%%PageOrder: Ascend\n");
ps_printf(p, "%%%%DocumentMedia: "
- "Default %zu %zu 0 () ()\n",
- (size_t)AFM2PNT(p, p->ps->width),
- (size_t)AFM2PNT(p, p->ps->height));
+ "Default %zu %zu 0 () ()\n",
+ (size_t)AFM2PNT(p, p->ps->width),
+ (size_t)AFM2PNT(p, p->ps->height));
ps_printf(p, "%%%%DocumentNeededResources: font");
for (i = 0; i < (int)TERMFONT__MAX; i++)
@@ -824,7 +926,7 @@ ps_begin(struct termp *p)
ps_printf(p, "<<\n");
ps_printf(p, "/Type /Font\n");
ps_printf(p, "/Subtype /Type1\n");
- ps_printf(p, "/Name /F%zu\n", i);
+ ps_printf(p, "/Name /F%d\n", i);
ps_printf(p, "/BaseFont /%s\n", fonts[i].name);
ps_printf(p, ">>\n");
}
@@ -837,7 +939,6 @@ ps_begin(struct termp *p)
ps_setfont(p, TERMFONT_NONE);
}
-
static void
ps_pletter(struct termp *p, int c)
{
@@ -850,25 +951,23 @@ ps_pletter(struct termp *p, int c)
if (PS_NEWPAGE & p->ps->flags) {
if (TERMTYPE_PS == p->type) {
- ps_printf(p, "%%%%Page: %zu %zu\n",
- p->ps->pages + 1,
- p->ps->pages + 1);
- ps_printf(p, "/%s %zu selectfont\n",
- fonts[(int)p->ps->lastf].name,
- p->ps->scale);
+ ps_printf(p, "%%%%Page: %zu %zu\n",
+ p->ps->pages + 1, p->ps->pages + 1);
+ ps_printf(p, "/%s %zu selectfont\n",
+ fonts[(int)p->ps->lastf].name,
+ p->ps->scale);
} else {
- pdf_obj(p, p->ps->pdfbody +
- p->ps->pages * 4);
+ pdf_obj(p, p->ps->pdfbody +
+ p->ps->pages * 4);
ps_printf(p, "<<\n");
- ps_printf(p, "/Length %zu 0 R\n",
- p->ps->pdfbody + 1 +
- p->ps->pages * 4);
+ ps_printf(p, "/Length %zu 0 R\n",
+ p->ps->pdfbody + 1 + p->ps->pages * 4);
ps_printf(p, ">>\nstream\n");
}
p->ps->pdflastpg = p->ps->pdfbytes;
p->ps->flags &= ~PS_NEWPAGE;
}
-
+
/*
* If we're not in a PostScript "word" context, then open one
* now at the current cursor.
@@ -876,16 +975,15 @@ ps_pletter(struct termp *p, int c)
if ( ! (PS_INLINE & p->ps->flags)) {
if (TERMTYPE_PS != p->type) {
- ps_printf(p, "BT\n/F%d %zu Tf\n",
- (int)p->ps->lastf,
- p->ps->scale);
+ ps_printf(p, "BT\n/F%d %zu Tf\n",
+ (int)p->ps->lastf, p->ps->scale);
ps_printf(p, "%.3f %.3f Td\n(",
- AFM2PNT(p, p->ps->pscol),
- AFM2PNT(p, p->ps->psrow));
+ AFM2PNT(p, p->ps->pscol),
+ AFM2PNT(p, p->ps->psrow));
} else
- ps_printf(p, "%.3f %.3f moveto\n(",
- AFM2PNT(p, p->ps->pscol),
- AFM2PNT(p, p->ps->psrow));
+ ps_printf(p, "%.3f %.3f moveto\n(",
+ AFM2PNT(p, p->ps->pscol),
+ AFM2PNT(p, p->ps->psrow));
p->ps->flags |= PS_INLINE;
}
@@ -899,11 +997,11 @@ ps_pletter(struct termp *p, int c)
*/
switch (c) {
- case ('('):
+ case '(':
/* FALLTHROUGH */
- case (')'):
+ case ')':
/* FALLTHROUGH */
- case ('\\'):
+ case '\\':
ps_putchar(p, '\\');
break;
default:
@@ -914,23 +1012,19 @@ ps_pletter(struct termp *p, int c)
f = (int)p->ps->lastf;
- if (c <= 32 || (c - 32 >= MAXCHAR)) {
- ps_putchar(p, ' ');
- p->ps->pscol += (size_t)fonts[f].gly[0].wx;
- return;
- }
+ if (c <= 32 || c - 32 >= MAXCHAR)
+ c = 32;
ps_putchar(p, (char)c);
c -= 32;
p->ps->pscol += (size_t)fonts[f].gly[c].wx;
}
-
static void
ps_pclose(struct termp *p)
{
- /*
+ /*
* Spit out that we're exiting a word context (this is a
* "partial close" because we don't check the last-char buffer
* or anything).
@@ -938,7 +1032,7 @@ ps_pclose(struct termp *p)
if ( ! (PS_INLINE & p->ps->flags))
return;
-
+
if (TERMTYPE_PS != p->type) {
ps_printf(p, ") Tj\nET\n");
} else
@@ -947,7 +1041,6 @@ ps_pclose(struct termp *p)
p->ps->flags &= ~PS_INLINE;
}
-
static void
ps_fclose(struct termp *p)
{
@@ -960,11 +1053,13 @@ ps_fclose(struct termp *p)
* Following this, close out any scope that's open.
*/
- if ('\0' != p->ps->last) {
- if (p->ps->lastf != TERMFONT_NONE) {
+ if (p->ps->last != '\0') {
+ assert( ! (p->ps->flags & PS_BACKSP));
+ if (p->ps->nextf != p->ps->lastf) {
ps_pclose(p);
- ps_setfont(p, TERMFONT_NONE);
+ ps_setfont(p, p->ps->nextf);
}
+ p->ps->nextf = TERMFONT_NONE;
ps_pletter(p, p->ps->last);
p->ps->last = '\0';
}
@@ -975,57 +1070,132 @@ ps_fclose(struct termp *p)
ps_pclose(p);
}
-
static void
ps_letter(struct termp *p, int arg)
{
- char cc, c;
+ size_t savecol, wx;
+ char c;
- /* LINTED */
c = arg >= 128 || arg <= 0 ? '?' : arg;
/*
- * State machine dictates whether to buffer the last character
- * or not. Basically, encoded words are detected by checking if
- * we're an "8" and switching on the buffer. Then we put "8" in
- * our buffer, and on the next charater, flush both character
- * and buffer. Thus, "regular" words are detected by having a
- * regular character and a regular buffer character.
+ * When receiving a backspace, merely flag it.
+ * We don't know yet whether it is
+ * a font instruction or an overstrike.
*/
- if ('\0' == p->ps->last) {
- assert(8 != c);
- p->ps->last = c;
+ if (c == '\b') {
+ assert(p->ps->last != '\0');
+ assert( ! (p->ps->flags & PS_BACKSP));
+ p->ps->flags |= PS_BACKSP;
return;
- } else if (8 == p->ps->last) {
- assert(8 != c);
- p->ps->last = '\0';
- } else if (8 == c) {
- assert(8 != p->ps->last);
- if ('_' == p->ps->last) {
- if (p->ps->lastf != TERMFONT_UNDER) {
- ps_pclose(p);
- ps_setfont(p, TERMFONT_UNDER);
+ }
+
+ /*
+ * Decode font instructions.
+ */
+
+ if (p->ps->flags & PS_BACKSP) {
+ if (p->ps->last == '_') {
+ switch (p->ps->nextf) {
+ case TERMFONT_BI:
+ break;
+ case TERMFONT_BOLD:
+ p->ps->nextf = TERMFONT_BI;
+ break;
+ default:
+ p->ps->nextf = TERMFONT_UNDER;
+ }
+ p->ps->last = c;
+ p->ps->flags &= ~PS_BACKSP;
+ return;
+ }
+ if (p->ps->last == c) {
+ switch (p->ps->nextf) {
+ case TERMFONT_BI:
+ break;
+ case TERMFONT_UNDER:
+ p->ps->nextf = TERMFONT_BI;
+ break;
+ default:
+ p->ps->nextf = TERMFONT_BOLD;
}
- } else if (p->ps->lastf != TERMFONT_BOLD) {
+ p->ps->flags &= ~PS_BACKSP;
+ return;
+ }
+
+ /*
+ * This is not a font instruction, but rather
+ * the next character. Prepare for overstrike.
+ */
+
+ savecol = p->ps->pscol;
+ } else
+ savecol = SIZE_MAX;
+
+ /*
+ * We found the next character, so the font instructions
+ * for the previous one are complete.
+ * Use them and print it.
+ */
+
+ if (p->ps->last != '\0') {
+ if (p->ps->nextf != p->ps->lastf) {
ps_pclose(p);
- ps_setfont(p, TERMFONT_BOLD);
+ ps_setfont(p, p->ps->nextf);
}
- p->ps->last = c;
- return;
- } else {
- if (p->ps->lastf != TERMFONT_NONE) {
+ p->ps->nextf = TERMFONT_NONE;
+
+ /*
+ * For an overstrike, if a previous character
+ * was wider, advance to center the new one.
+ */
+
+ if (p->ps->pscolnext) {
+ wx = fonts[p->ps->lastf].gly[(int)p->ps->last-32].wx;
+ if (p->ps->pscol + wx < p->ps->pscolnext)
+ p->ps->pscol = (p->ps->pscol +
+ p->ps->pscolnext - wx) / 2;
+ }
+
+ ps_pletter(p, p->ps->last);
+
+ /*
+ * For an overstrike, if a previous character
+ * was wider, advance to the end of the old one.
+ */
+
+ if (p->ps->pscol < p->ps->pscolnext) {
ps_pclose(p);
- ps_setfont(p, TERMFONT_NONE);
+ p->ps->pscol = p->ps->pscolnext;
}
- cc = p->ps->last;
- p->ps->last = c;
- c = cc;
}
- ps_pletter(p, c);
-}
+ /*
+ * Do not print the current character yet because font
+ * instructions might follow; only remember it.
+ * For the first character, nothing else is done.
+ * The final character will get printed from ps_fclose().
+ */
+
+ p->ps->last = c;
+
+ /*
+ * For an overstrike, back up to the previous position.
+ * If the previous character is wider than any it overstrikes,
+ * remember the current position, because it might also be
+ * wider than all that will overstrike it.
+ */
+ if (savecol != SIZE_MAX) {
+ if (p->ps->pscolnext < p->ps->pscol)
+ p->ps->pscolnext = p->ps->pscol;
+ ps_pclose(p);
+ p->ps->pscol = savecol;
+ p->ps->flags &= ~PS_BACKSP;
+ } else
+ p->ps->pscolnext = 0;
+}
static void
ps_advance(struct termp *p, size_t len)
@@ -1042,7 +1212,6 @@ ps_advance(struct termp *p, size_t len)
p->ps->pscol += len;
}
-
static void
ps_endline(struct termp *p)
{
@@ -1054,7 +1223,7 @@ ps_endline(struct termp *p)
/*
* If we're in the margin, don't try to recalculate our current
* row. XXX: if the column tries to be fancy with multiple
- * lines, we'll do nasty stuff.
+ * lines, we'll do nasty stuff.
*/
if (PS_MARGINS & p->ps->flags)
@@ -1074,8 +1243,7 @@ ps_endline(struct termp *p)
* showpage and restart our row.
*/
- if (p->ps->psrow >= p->ps->lineheight +
- p->ps->bottom) {
+ if (p->ps->psrow >= p->ps->lineheight + p->ps->bottom) {
p->ps->psrow -= p->ps->lineheight;
return;
}
@@ -1083,14 +1251,13 @@ ps_endline(struct termp *p)
ps_closepage(p);
}
-
static void
ps_setfont(struct termp *p, enum termfont f)
{
assert(f < TERMFONT__MAX);
p->ps->lastf = f;
-
+
/*
* If we're still at the top of the page, let the font-setting
* be delayed until we actually have stuff to print.
@@ -1100,64 +1267,70 @@ ps_setfont(struct termp *p, enum termfont f)
return;
if (TERMTYPE_PS == p->type)
- ps_printf(p, "/%s %zu selectfont\n",
- fonts[(int)f].name,
- p->ps->scale);
+ ps_printf(p, "/%s %zu selectfont\n",
+ fonts[(int)f].name, p->ps->scale);
else
- ps_printf(p, "/F%d %zu Tf\n",
- (int)f,
- p->ps->scale);
+ ps_printf(p, "/F%d %zu Tf\n",
+ (int)f, p->ps->scale);
}
-
-/* ARGSUSED */
static size_t
ps_width(const struct termp *p, int c)
{
if (c <= 32 || c - 32 >= MAXCHAR)
- return((size_t)fonts[(int)TERMFONT_NONE].gly[0].wx);
+ c = 0;
+ else
+ c -= 32;
- c -= 32;
return((size_t)fonts[(int)TERMFONT_NONE].gly[c].wx);
}
-
static double
ps_hspan(const struct termp *p, const struct roffsu *su)
{
double r;
-
+
/*
* All of these measurements are derived by converting from the
* native measurement to AFM units.
*/
-
switch (su->unit) {
- case (SCALE_CM):
- r = PNT2AFM(p, su->scale * 28.34);
+ case SCALE_BU:
+ /*
+ * Traditionally, the default unit is fixed to the
+ * output media. So this would refer to the point. In
+ * mandoc(1), however, we stick to the default terminal
+ * scaling unit so that output is the same regardless
+ * the media.
+ */
+ r = PNT2AFM(p, su->scale * 72.0 / 240.0);
break;
- case (SCALE_IN):
- r = PNT2AFM(p, su->scale * 72);
+ case SCALE_CM:
+ r = PNT2AFM(p, su->scale * 72.0 / 2.54);
break;
- case (SCALE_PC):
- r = PNT2AFM(p, su->scale * 12);
- break;
- case (SCALE_PT):
- r = PNT2AFM(p, su->scale * 100);
+ case SCALE_EM:
+ r = su->scale *
+ fonts[(int)TERMFONT_NONE].gly[109 - 32].wx;
break;
- case (SCALE_EM):
+ case SCALE_EN:
r = su->scale *
- fonts[(int)TERMFONT_NONE].gly[109 - 32].wx;
+ fonts[(int)TERMFONT_NONE].gly[110 - 32].wx;
break;
- case (SCALE_MM):
- r = PNT2AFM(p, su->scale * 2.834);
+ case SCALE_IN:
+ r = PNT2AFM(p, su->scale * 72.0);
break;
- case (SCALE_EN):
+ case SCALE_MM:
r = su->scale *
- fonts[(int)TERMFONT_NONE].gly[110 - 32].wx;
+ fonts[(int)TERMFONT_NONE].gly[109 - 32].wx / 100.0;
break;
- case (SCALE_VS):
+ case SCALE_PC:
+ r = PNT2AFM(p, su->scale * 12.0);
+ break;
+ case SCALE_PT:
+ r = PNT2AFM(p, su->scale * 1.0);
+ break;
+ case SCALE_VS:
r = su->scale * p->ps->lineheight;
break;
default:
@@ -1178,8 +1351,5 @@ ps_growbuf(struct termp *p, size_t sz)
sz = PS_BUFSLOP;
p->ps->psmargsz += sz;
-
- p->ps->psmarg = mandoc_realloc
- (p->ps->psmarg, p->ps->psmargsz);
+ p->ps->psmarg = mandoc_realloc(p->ps->psmarg, p->ps->psmargsz);
}
-
diff --git a/usr/src/cmd/mandoc/tree.c b/usr/src/cmd/mandoc/tree.c
index fdb70e1b93..a5a7f2c7d2 100644
--- a/usr/src/cmd/mandoc/tree.c
+++ b/usr/src/cmd/mandoc/tree.c
@@ -1,7 +1,7 @@
-/* $Id: tree.c,v 1.50 2013/12/24 19:11:46 schwarze Exp $ */
+/* $Id: tree.c,v 1.62 2015/02/05 00:14:13 schwarze Exp $ */
/*
- * Copyright (c) 2008, 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2008, 2009, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2013, 2014, 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
@@ -15,9 +15,9 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
+
+#include <sys/types.h>
#include <assert.h>
#include <limits.h>
@@ -36,24 +36,20 @@ static void print_mdoc(const struct mdoc_node *, int);
static void print_span(const struct tbl_span *, int);
-/* ARGSUSED */
void
tree_mdoc(void *arg, const struct mdoc *mdoc)
{
- print_mdoc(mdoc_node(mdoc), 0);
+ print_mdoc(mdoc_node(mdoc)->child, 0);
}
-
-/* ARGSUSED */
void
tree_man(void *arg, const struct man *man)
{
- print_man(man_node(man), 0);
+ print_man(man_node(man)->child, 0);
}
-
static void
print_mdoc(const struct mdoc_node *n, int indent)
{
@@ -62,38 +58,42 @@ print_mdoc(const struct mdoc_node *n, int indent)
size_t argc;
struct mdoc_argv *argv;
+ if (n == NULL)
+ return;
+
argv = NULL;
argc = 0;
t = p = NULL;
switch (n->type) {
- case (MDOC_ROOT):
+ case MDOC_ROOT:
t = "root";
break;
- case (MDOC_BLOCK):
+ case MDOC_BLOCK:
t = "block";
break;
- case (MDOC_HEAD):
+ case MDOC_HEAD:
t = "block-head";
break;
- case (MDOC_BODY):
+ case MDOC_BODY:
if (n->end)
t = "body-end";
else
t = "block-body";
break;
- case (MDOC_TAIL):
+ case MDOC_TAIL:
t = "block-tail";
break;
- case (MDOC_ELEM):
+ case MDOC_ELEM:
t = "elem";
break;
- case (MDOC_TEXT):
+ case MDOC_TEXT:
t = "text";
break;
- case (MDOC_TBL):
- /* FALLTHROUGH */
- case (MDOC_EQN):
+ case MDOC_TBL:
+ break;
+ case MDOC_EQN:
+ t = "eqn";
break;
default:
abort();
@@ -101,37 +101,38 @@ print_mdoc(const struct mdoc_node *n, int indent)
}
switch (n->type) {
- case (MDOC_TEXT):
+ case MDOC_TEXT:
p = n->string;
break;
- case (MDOC_BODY):
+ case MDOC_BODY:
p = mdoc_macronames[n->tok];
break;
- case (MDOC_HEAD):
+ case MDOC_HEAD:
p = mdoc_macronames[n->tok];
break;
- case (MDOC_TAIL):
+ case MDOC_TAIL:
p = mdoc_macronames[n->tok];
break;
- case (MDOC_ELEM):
+ case MDOC_ELEM:
p = mdoc_macronames[n->tok];
if (n->args) {
argv = n->args->argv;
argc = n->args->argc;
}
break;
- case (MDOC_BLOCK):
+ case MDOC_BLOCK:
p = mdoc_macronames[n->tok];
if (n->args) {
argv = n->args->argv;
argc = n->args->argc;
}
break;
- case (MDOC_TBL):
- /* FALLTHROUGH */
- case (MDOC_EQN):
+ case MDOC_TBL:
+ break;
+ case MDOC_EQN:
+ p = "EQ";
break;
- case (MDOC_ROOT):
+ case MDOC_ROOT:
p = "root";
break;
default:
@@ -142,12 +143,9 @@ print_mdoc(const struct mdoc_node *n, int indent)
if (n->span) {
assert(NULL == p && NULL == t);
print_span(n->span, indent);
- } else if (n->eqn) {
- assert(NULL == p && NULL == t);
- print_box(n->eqn->root, indent);
} else {
for (i = 0; i < indent; i++)
- putchar('\t');
+ putchar(' ');
printf("%s (%s)", p, t);
@@ -164,52 +162,52 @@ print_mdoc(const struct mdoc_node *n, int indent)
putchar(' ');
if (MDOC_LINE & n->flags)
putchar('*');
- printf("%d:%d", n->line, n->pos);
- if (n->lastline != n->line)
- printf("-%d", n->lastline);
- putchar('\n');
+ printf("%d:%d\n", n->line, n->pos + 1);
}
+ if (n->eqn)
+ print_box(n->eqn->root->first, indent + 4);
if (n->child)
- print_mdoc(n->child, indent + 1);
+ print_mdoc(n->child, indent +
+ (n->type == MDOC_BLOCK ? 2 : 4));
if (n->next)
print_mdoc(n->next, indent);
}
-
static void
print_man(const struct man_node *n, int indent)
{
const char *p, *t;
int i;
+ if (n == NULL)
+ return;
+
t = p = NULL;
switch (n->type) {
- case (MAN_ROOT):
+ case MAN_ROOT:
t = "root";
break;
- case (MAN_ELEM):
+ case MAN_ELEM:
t = "elem";
break;
- case (MAN_TEXT):
+ case MAN_TEXT:
t = "text";
break;
- case (MAN_BLOCK):
+ case MAN_BLOCK:
t = "block";
break;
- case (MAN_HEAD):
+ case MAN_HEAD:
t = "block-head";
break;
- case (MAN_BODY):
+ case MAN_BODY:
t = "block-body";
break;
- case (MAN_TAIL):
- t = "block-tail";
+ case MAN_TBL:
break;
- case (MAN_TBL):
- /* FALLTHROUGH */
- case (MAN_EQN):
+ case MAN_EQN:
+ t = "eqn";
break;
default:
abort();
@@ -217,26 +215,25 @@ print_man(const struct man_node *n, int indent)
}
switch (n->type) {
- case (MAN_TEXT):
+ case MAN_TEXT:
p = n->string;
break;
- case (MAN_ELEM):
- /* FALLTHROUGH */
- case (MAN_BLOCK):
+ case MAN_ELEM:
/* FALLTHROUGH */
- case (MAN_HEAD):
+ case MAN_BLOCK:
/* FALLTHROUGH */
- case (MAN_TAIL):
+ case MAN_HEAD:
/* FALLTHROUGH */
- case (MAN_BODY):
+ case MAN_BODY:
p = man_macronames[n->tok];
break;
- case (MAN_ROOT):
+ case MAN_ROOT:
p = "root";
break;
- case (MAN_TBL):
- /* FALLTHROUGH */
- case (MAN_EQN):
+ case MAN_TBL:
+ break;
+ case MAN_EQN:
+ p = "EQ";
break;
default:
abort();
@@ -246,17 +243,20 @@ print_man(const struct man_node *n, int indent)
if (n->span) {
assert(NULL == p && NULL == t);
print_span(n->span, indent);
- } else if (n->eqn) {
- assert(NULL == p && NULL == t);
- print_box(n->eqn->root, indent);
} else {
for (i = 0; i < indent; i++)
- putchar('\t');
- printf("%s (%s) %d:%d\n", p, t, n->line, n->pos);
+ putchar(' ');
+ printf("%s (%s) ", p, t);
+ if (MAN_LINE & n->flags)
+ putchar('*');
+ printf("%d:%d\n", n->line, n->pos + 1);
}
+ if (n->eqn)
+ print_box(n->eqn->root->first, indent + 4);
if (n->child)
- print_man(n->child, indent + 1);
+ print_man(n->child, indent +
+ (n->type == MAN_BLOCK ? 2 : 4));
if (n->next)
print_man(n->next, indent);
}
@@ -267,39 +267,63 @@ print_box(const struct eqn_box *ep, int indent)
int i;
const char *t;
+ static const char *posnames[] = {
+ NULL, "sup", "subsup", "sub",
+ "to", "from", "fromto",
+ "over", "sqrt", NULL };
+
if (NULL == ep)
return;
for (i = 0; i < indent; i++)
- putchar('\t');
+ putchar(' ');
t = NULL;
switch (ep->type) {
- case (EQN_ROOT):
+ case EQN_ROOT:
t = "eqn-root";
break;
- case (EQN_LIST):
+ case EQN_LISTONE:
+ case EQN_LIST:
t = "eqn-list";
break;
- case (EQN_SUBEXPR):
+ case EQN_SUBEXPR:
t = "eqn-expr";
break;
- case (EQN_TEXT):
+ case EQN_TEXT:
t = "eqn-text";
break;
- case (EQN_MATRIX):
+ case EQN_PILE:
+ t = "eqn-pile";
+ break;
+ case EQN_MATRIX:
t = "eqn-matrix";
break;
}
- assert(t);
- printf("%s(%d, %d, %d, %d, %d, \"%s\", \"%s\") %s\n",
- t, EQN_DEFSIZE == ep->size ? 0 : ep->size,
- ep->pos, ep->font, ep->mark, ep->pile,
- ep->left ? ep->left : "",
- ep->right ? ep->right : "",
- ep->text ? ep->text : "");
-
- print_box(ep->first, indent + 1);
+ fputs(t, stdout);
+ if (ep->pos)
+ printf(" pos=%s", posnames[ep->pos]);
+ if (ep->left)
+ printf(" left=\"%s\"", ep->left);
+ if (ep->right)
+ printf(" right=\"%s\"", ep->right);
+ if (ep->top)
+ printf(" top=\"%s\"", ep->top);
+ if (ep->bottom)
+ printf(" bottom=\"%s\"", ep->bottom);
+ if (ep->text)
+ printf(" text=\"%s\"", ep->text);
+ if (ep->font)
+ printf(" font=%d", ep->font);
+ if (ep->size != EQN_DEFSIZE)
+ printf(" size=%d", ep->size);
+ if (ep->expectargs != UINT_MAX && ep->expectargs != ep->args)
+ printf(" badargs=%zu(%zu)", ep->args, ep->expectargs);
+ else if (ep->args)
+ printf(" args=%zu", ep->args);
+ putchar('\n');
+
+ print_box(ep->first, indent + 4);
print_box(ep->next, indent);
}
@@ -310,13 +334,13 @@ print_span(const struct tbl_span *sp, int indent)
int i;
for (i = 0; i < indent; i++)
- putchar('\t');
+ putchar(' ');
switch (sp->pos) {
- case (TBL_SPAN_HORIZ):
+ case TBL_SPAN_HORIZ:
putchar('-');
return;
- case (TBL_SPAN_DHORIZ):
+ case TBL_SPAN_DHORIZ:
putchar('=');
return;
default:
@@ -325,14 +349,14 @@ print_span(const struct tbl_span *sp, int indent)
for (dp = sp->first; dp; dp = dp->next) {
switch (dp->pos) {
- case (TBL_DATA_HORIZ):
+ case TBL_DATA_HORIZ:
/* FALLTHROUGH */
- case (TBL_DATA_NHORIZ):
+ case TBL_DATA_NHORIZ:
putchar('-');
continue;
- case (TBL_DATA_DHORIZ):
+ case TBL_DATA_DHORIZ:
/* FALLTHROUGH */
- case (TBL_DATA_NDHORIZ):
+ case TBL_DATA_NDHORIZ:
putchar('=');
continue;
default:
diff --git a/usr/src/cmd/mandoc/vol.in b/usr/src/cmd/mandoc/vol.in
deleted file mode 100644
index 7650b57a14..0000000000
--- a/usr/src/cmd/mandoc/vol.in
+++ /dev/null
@@ -1,35 +0,0 @@
-/* $Id: vol.in,v 1.6 2010/06/19 20:46:28 kristaps Exp $ */
-/*
- * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/*
- * This file defines volume titles for .Dt.
- *
- * Be sure to escape strings.
- */
-
-LINE("USD", "User\'s Supplementary Documents")
-LINE("PS1", "Programmer\'s Supplementary Documents")
-LINE("AMD", "Ancestral Manual Documents")
-LINE("SMM", "System Manager\'s Manual")
-LINE("URM", "User\'s Reference Manual")
-LINE("PRM", "Programmer\'s Manual")
-LINE("KM", "Kernel Manual")
-LINE("IND", "Manual Master Index")
-LINE("MMI", "Manual Master Index")
-LINE("LOCAL", "Local Manual")
-LINE("LOC", "Local Manual")
-LINE("CON", "Contributed Software Manual")
diff --git a/usr/src/man/man1/mandoc.1 b/usr/src/man/man1/mandoc.1
index 8f2f8b5e84..c60353d2e0 100644
--- a/usr/src/man/man1/mandoc.1
+++ b/usr/src/man/man1/mandoc.1
@@ -1,3 +1,7 @@
+.\" $Id: mandoc.1,v 1.155 2015/02/23 13:31:03 schwarze Exp $
+.\"
+.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+.\" Copyright (c) 2012, 2014, 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
@@ -11,12 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.\"
-.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright 2012 Nexenta Systems, Inc. All rights reserved.
-.\" Copyright 2014 Garrett D'Amore <garrett@damore.org>
-.\"
-.Dd Jul 30, 2014
+.Dd $Mdocdate: February 23 2015 $
.Dt MANDOC 1
.Os
.Sh NAME
@@ -24,7 +23,11 @@
.Nd format and display UNIX manuals
.Sh SYNOPSIS
.Nm mandoc
-.Op Fl V
+.Op Fl acfhkl
+.Sm off
+.Op Fl I Cm os Li = Ar name
+.Sm on
+.Op Fl K Ns Ar encoding
.Op Fl m Ns Ar format
.Op Fl O Ns Ar option
.Op Fl T Ns Ar output
@@ -46,11 +49,78 @@ or
text from stdin, implying
.Fl m Ns Cm andoc ,
and produces
-.Fl T Ns Cm ascii
+.Fl T Ns Cm locale
output.
.Pp
-The arguments are as follows:
+The options are as follows:
.Bl -tag -width Ds
+.It Fl a
+If the standard output is a terminal device and
+.Fl c
+is not specified, use
+.Xr more 1
+to paginate the output, just like
+.Xr man 1
+would.
+.It Fl c
+Copy the formatted manual pages to the standard output without using
+.Xr more 1
+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.
+.Sm off
+.It Fl I Cm os Li = Ar name
+.Sm on
+Override the default operating system
+.Ar name
+for the
+.Xr mdoc 5
+.Sq \&Os
+and for the
+.Xr man 5
+.Sq \&TH
+macro.
+.It Fl h
+Display only the SYNOPSIS lines.
+Implies
+.Fl c .
+.It Fl K Ns Ar encoding
+Specify the input encoding.
+The supported
+.Ar encoding
+arguments are
+.Cm us-ascii ,
+.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
+.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
+.El
+.It Fl l
+A synonym for
+.Fl a .
.It Fl m Ns Ar format
Input format.
See
@@ -66,9 +136,7 @@ See
.Sx Output Formats
for available formats.
Defaults to
-.Fl T Ns Cm ascii .
-.It Fl V
-Print version and exit.
+.Fl T Ns Cm locale .
.It Fl W Ns Ar level
Specify the minimum message
.Ar level
@@ -79,12 +147,13 @@ can be
.Cm warning ,
.Cm error ,
or
-.Cm fatal .
-The default is
-.Fl W Ns Cm fatal ;
-.Fl W Ns Cm all
+.Cm unsupp ;
+.Cm all
is an alias for
-.Fl W Ns Cm warning .
+.Cm warning .
+By default,
+.Nm
+is silent.
See
.Sx EXIT STATUS
and
@@ -163,11 +232,10 @@ arguments, which correspond to output modes:
.Bl -tag -width "-Tlocale"
.It Fl T Ns Cm ascii
Produce 7-bit ASCII output.
-This is the default.
See
.Sx ASCII Output .
.It Fl T Ns Cm html
-Produce strict CSS1/HTML-4.01 output.
+Produce HTML5, CSS1, and MathML output.
See
.Sx HTML Output .
.It Fl T Ns Cm lint
@@ -176,6 +244,7 @@ Implies
.Fl W Ns Cm warning .
.It Fl T Ns Cm locale
Encode output using the current locale.
+This is the default.
See
.Sx Locale Output .
.It Fl T Ns Cm man
@@ -199,17 +268,16 @@ Encode output in the UTF\-8 multi-byte format.
See
.Sx UTF\-8 Output .
.It Fl T Ns Cm xhtml
-Produce strict CSS1/XHTML-1.0 output.
-See
-.Sx XHTML Output .
+This is a synonym for
+.Fl T Ns Cm html .
.El
.Pp
If multiple input files are specified, these will be processed by the
corresponding filter in-order.
.Ss ASCII Output
Output produced by
-.Fl T Ns Cm ascii ,
-which is the default, is rendered in standard 7-bit ASCII documented in
+.Fl T Ns Cm ascii
+is rendered in standard 7-bit ASCII documented in
.Xr ascii 5 .
.Pp
Font styles are applied by using back-spaced encoding such that an
@@ -226,9 +294,6 @@ Emboldened characters are rendered as
The special characters documented in
.Xr mandoc_char 5
are rendered best-effort in an ASCII equivalent.
-If no equivalent is found,
-.Sq \&?
-is used instead.
.Pp
Output width is limited to 78 visible columns unless literal input lines
exceed this limit.
@@ -249,12 +314,16 @@ for example overfull lines or ugly line breaks.
.It Cm width Ns = Ns Ar width
The output width is set to
.Ar width ,
-which will normalise to \(>=60.
+which will normalise to \(>=58.
.El
.Ss HTML Output
Output produced by
.Fl T Ns Cm html
-conforms to HTML-4.01 strict.
+conforms to HTML5 using optional self-closing tags.
+Default styles use only CSS1.
+Equations rendered from
+.Xr eqn 5
+blocks use MathML.
.Pp
The
.Pa example.style.css
@@ -262,7 +331,8 @@ file documents style-sheet classes available for customising output.
If a style-sheet is not specified with
.Fl O Ns Ar style ,
.Fl T Ns Cm html
-defaults to simple output readable in any graphical or text-based web
+defaults to simple output (via an embedded style-sheet)
+readable in any graphical or text-based web
browser.
.Pp
Special characters are rendered in decimal-encoded UTF\-8.
@@ -272,16 +342,8 @@ The following
arguments are accepted:
.Bl -tag -width Ds
.It Cm fragment
-Omit the
-.Aq !DOCTYPE
-declaration and the
-.Aq html ,
-.Aq head ,
-and
-.Aq body
-elements and only emit the subtree below the
-.Aq body
-element.
+Omit the <!DOCTYPE> declaration and the <html>, <head>, and <body>
+elements and only emit the subtree below the <body> element.
The
.Cm style
argument will be ignored.
@@ -325,13 +387,7 @@ relative URI.
.Ss Locale Output
Locale-depending output encoding is triggered with
.Fl T Ns Cm locale .
-This option is not available on all systems: systems without locale
-support, or those whose internal representation is not natively UCS-4,
-will fall back to
-.Fl T Ns Cm ascii .
-See
-.Sx ASCII Output
-for font style specification and available command-line arguments.
+This is the default.
.Ss Man Output
Translate input format into
.Xr man 5
@@ -405,15 +461,6 @@ to force a UTF\-8 locale.
See
.Sx Locale Output
for details and options.
-.Ss XHTML Output
-Output produced by
-.Fl T Ns Cm xhtml
-conforms to XHTML-1.0 strict.
-.Pp
-See
-.Sx HTML Output
-for details; beyond generating XHTML tags instead of HTML tags, these
-output modes are identical.
.Sh EXIT STATUS
The
.Nm
@@ -433,19 +480,25 @@ At least one warning occurred, but no error, and
.Fl W Ns Cm warning
was specified.
.It 3
-At least one parsing error occurred, but no fatal error, and
+At least one parsing error occurred,
+but no unsupported feature was encountered, and
.Fl W Ns Cm error
or
.Fl W Ns Cm warning
was specified.
.It 4
-A fatal parsing error occurred.
+At least one unsupported feature was encountered, and
+.Fl W Ns Cm unsupp ,
+.Fl W Ns Cm error
+or
+.Fl W Ns Cm warning
+was specified.
.It 5
Invalid command line arguments were specified.
No input files have been read.
.It 6
-An operating system error occurred, for example memory exhaustion or an
-error accessing input files.
+An operating system error occurred, for example exhaustion
+of memory, file descriptors, or process table entries.
Such errors cause
.Nm
to exit at once, possibly in the middle of parsing or formatting a file.
@@ -459,7 +512,7 @@ output mode implies
To page manuals to the terminal:
.Pp
.Dl $ mandoc \-Wall,stop mandoc.1 2\*(Gt&1 | less
-.Dl $ mandoc mandoc.1 mdoc.5 | less
+.Dl $ mandoc mandoc.1 mdoc.3 mdoc.5 | less
.Pp
To produce HTML manuals with
.Ar style.css
@@ -485,43 +538,53 @@ parser:
.Pp
.Dl $ mandoc \-Tman foo.mdoc \*(Gt foo.man
.Sh DIAGNOSTICS
-Standard error messages reporting parsing errors are prefixed by
+Messages displayed by
+.Nm
+follow this format:
.Pp
-.Sm off
-.D1 Ar file : line : column : \ level :
-.Sm on
+.D1 Nm Ns : Ar file : Ns Ar line : Ns Ar column : level : message : macro args
.Pp
-where the fields have the following meanings:
-.Bl -tag -width "column"
-.It Ar file
-The name of the input file causing the message.
-.It Ar line
-The line number in that input file.
-Line numbering starts at 1.
-.It Ar column
-The column number in that input file.
-Column numbering starts at 1.
-If the issue is caused by a word, the column number usually
-points to the first character of the word.
-.It Ar level
-The message level, printed in capital letters.
-.El
+Line and column numbers start at 1.
+Both are omitted for messages referring to an input file as a whole.
+Macro names and arguments are omitted where meaningless.
+Fatal messages about invalid command line arguments
+or operating system errors, for example when memory is exhausted,
+may also omit the
+.Ar file
+and
+.Ar level
+fields.
.Pp
Message levels have the following meanings:
.Bl -tag -width "warning"
-.It Cm fatal
-The parser is unable to parse a given input file at all.
-No formatted output is produced from that input file.
-.It Cm error
-An input file contains syntax that cannot be safely interpreted,
-either because it is invalid or because
+.It Cm unsupp
+An input file uses unsupported low-level
+.Xr mandoc_roff 5
+features.
+The output may be incomplete and/or misformatted,
+so using GNU troff instead of
.Nm
-does not implement it yet.
+to process the file may be preferable.
+.It Cm error
+An input file contains invalid syntax that cannot be safely interpreted.
By discarding part of the input or inserting missing tokens,
the parser is able to continue, and the error does not prevent
generation of formatted output, but typically, preparing that
output involves information loss, broken document structure
-or unintended formatting.
+or unintended formatting, no matter whether
+.Nm
+or GNU troff is used.
+In many cases, the output of
+.Nm
+and GNU troff is identical, but in some,
+.Nm
+is more resilient than GNU troff with respect to malformed input.
+.Pp
+Non-existent or unreadable input files are also reported on the
+.Cm error
+level.
+In that case, the parser cannot even be started and no output
+is produced from those input files.
.It Cm warning
An input file uses obsolete, discouraged or non-portable syntax.
All the same, the meaning of the input is unambiguous and a correct
@@ -532,147 +595,1140 @@ formatting tools instead of
.El
.Pp
Messages of the
-.Cm warning
+.Cm warning ,
+.Cm error ,
and
-.Cm error
-levels are hidden unless their level, or a lower level, is requested using a
+.Cm unsupp
+levels except those about non-existent or unreadable input files
+are hidden unless their level, or a lower level, is requested using a
.Fl W
option or
.Fl T Ns Cm lint
output mode.
-.Pp
-The
-.Nm
-utility may also print messages related to invalid command line arguments
-or operating system errors, for example when memory is exhausted or
-input files cannot be read.
-Such messages do not carry the prefix described above.
-.Sh COMPATIBILITY
-This section summarises
-.Nm
-compatibility with GNU troff.
-Each input and output format is separately noted.
-.Ss ASCII Compatibility
-.Bl -bullet -compact
-.It
-Unrenderable unicode codepoints specified with
-.Sq \e[uNNNN]
-escapes are printed as
-.Sq \&?
-in mandoc.
-In GNU troff, these raise an error.
-.It
+.Ss Warnings related to the document prologue
+.Bl -ohang
+.It Sy "missing manual title, using UNTITLED"
+.Pq mdoc
+A
+.Ic \&Dt
+macro has no arguments, or there is no
+.Ic \&Dt
+macro before the first non-prologue macro.
+.It Sy "missing manual title, using \(dq\(dq"
+.Pq man
+There is no
+.Ic \&TH
+macro, or it has no arguments.
+.It Sy "lower case character in document title"
+.Pq mdoc , man
+The title is still used as given in the
+.Ic \&Dt
+or
+.Ic \&TH
+macro.
+.It Sy "missing manual section, using \(dq\(dq"
+.Pq mdoc , man
+A
+.Ic \&Dt
+or
+.Ic \&TH
+macro lacks the mandatory section argument.
+.It Sy "unknown manual section"
+.Pq mdoc
+The section number in a
+.Ic \&Dt
+line is invalid, but still used.
+.It Sy "missing date, using today's date"
+.Pq mdoc, man
+The document was parsed as
+.Xr mdoc 5
+and it has no
+.Ic \&Dd
+macro, or the
+.Ic \&Dd
+macro has no arguments or only empty arguments;
+or the document was parsed as
+.Xr man 5
+and it has no
+.Ic \&TH
+macro, or the
+.Ic \&TH
+macro has less than three arguments or its third argument is empty.
+.It Sy "cannot parse date, using it verbatim"
+.Pq mdoc , man
+The date given in a
+.Ic \&Dd
+or
+.Ic \&TH
+macro does not follow the conventional format.
+.It Sy "missing Os macro, using \(dq\(dq"
+.Pq mdoc
+The default or current system is not shown in this case.
+.It Sy "duplicate prologue macro"
+.Pq mdoc
+One of the prologue macros occurs more than once.
+The last instance overrides all previous ones.
+.It Sy "late prologue macro"
+.Pq mdoc
+A
+.Ic \&Dd
+or
+.Ic \&Os
+macro occurs after some non-prologue macro, but still takes effect.
+.It Sy "skipping late title macro"
+.Pq mdoc
The
-.Sq \&Bd \-literal
+.Ic \&Dt
+macro appears after the first non-prologue macro.
+Traditional formatters cannot handle this because
+they write the page header before parsing the document body.
+Even though this technical restriction does not apply to
+.Nm ,
+traditional semantics is preserved.
+The late macro is discarded including its arguments.
+.It Sy "prologue macros out of order"
+.Pq mdoc
+The prologue macros are not given in the conventional order
+.Ic \&Dd ,
+.Ic \&Dt ,
+.Ic \&Os .
+All three macros are used even when given in another order.
+.El
+.Ss Warnings regarding document structure
+.Bl -ohang
+.It Sy ".so is fragile, better use ln(1)"
+.Pq roff
+Including files only works when the parser program runs with the correct
+current working directory.
+.It Sy "no document body"
+.Pq mdoc , man
+The document body contains neither text nor macros.
+An empty document is shown, consisting only of a header and a footer line.
+.It Sy "content before first section header"
+.Pq mdoc , man
+Some macros or text precede the first
+.Ic \&Sh
+or
+.Ic \&SH
+section header.
+The offending macros and text are parsed and added to the top level
+of the syntax tree, outside any section block.
+.It Sy "first section is not NAME"
+.Pq mdoc
+The argument of the first
+.Ic \&Sh
+macro is not
+.Sq NAME .
+This may confuse
+.Xr makewhatis 8
+and
+.Xr apropos 1 .
+.It Sy "NAME section without name"
+.Pq mdoc
+The NAME section does not contain any
+.Ic \&Nm
+child macro.
+.It Sy "NAME section without description"
+.Pq mdoc
+The NAME section lacks the mandatory
+.Ic \&Nd
+child macro.
+.It Sy "description not at the end of NAME"
+.Pq mdoc
+The NAME section does contain an
+.Ic \&Nd
+child macro, but other content follows it.
+.It Sy "bad NAME section content"
+.Pq mdoc
+The NAME section contains plain text or macros other than
+.Ic \&Nm
and
-.Sq \&Bd \-unfilled
-macros of
+.Ic \&Nd .
+.It Sy "missing description line, using \(dq\(dq"
+.Pq mdoc
+The
+.Ic \&Nd
+macro lacks the required argument.
+The title line of the manual will end after the dash.
+.It Sy "sections out of conventional order"
+.Pq mdoc
+A standard section occurs after another section it usually precedes.
+All section titles are used as given,
+and the order of sections is not changed.
+.It Sy "duplicate section title"
+.Pq mdoc
+The same standard section title occurs more than once.
+.It Sy "unexpected section"
+.Pq mdoc
+A standard section header occurs in a section of the manual
+where it normally isn't useful.
+.It Sy "unusual Xr order"
+.Pq mdoc
+In the SEE ALSO section, an
+.Ic \&Xr
+macro with a lower section number follows one with a higher number,
+or two
+.Ic \&Xr
+macros refering to the same section are out of alphabetical order.
+.It Sy "unusual Xr punctuation"
+.Pq mdoc
+In the SEE ALSO section, punctuation between two
+.Ic \&Xr
+macros differs from a single comma, or there is trailing punctuation
+after the last
+.Ic \&Xr
+macro.
+.It Sy "AUTHORS section without An macro"
+.Pq mdoc
+An AUTHORS sections contains no
+.Ic \&An
+macros, or only empty ones.
+Probably, there are author names lacking markup.
+.El
+.Ss "Warnings related to macros and nesting"
+.Bl -ohang
+.It Sy "obsolete macro"
+.Pq mdoc
+See the
.Xr mdoc 5
-in
-.Fl T Ns Cm ascii
-are synonyms, as are \-filled and \-ragged.
-.It
-In historic GNU troff, the
-.Sq \&Pa
+manual for replacements.
+.It Sy "macro neither callable nor escaped"
+.Pq mdoc
+The name of a macro that is not callable appears on a macro line.
+It is printed verbatim.
+If the intention is to call it, move it to its own input line;
+otherwise, escape it by prepending
+.Sq \e& .
+.It Sy "skipping paragraph macro"
+In
.Xr mdoc 5
-macro does not underline when scoped under an
-.Sq \&It
-in the FILES section.
-This behaves correctly in
-.Nm .
+documents, this happens
+.Bl -dash -compact
.It
-A list or display following the
-.Sq \&Ss
-.Xr mdoc 5
-macro in
-.Fl T Ns Cm ascii
-does not assert a prior vertical break, just as it doesn't with
-.Sq \&Sh .
+at the beginning and end of sections and subsections
.It
-The
-.Sq \&na
+right before non-compact lists and displays
+.It
+at the end of items in non-column, non-compact lists
+.It
+and for multiple consecutive paragraph macros.
+.El
+In
.Xr man 5
-macro in
-.Fl T Ns Cm ascii
-has no effect.
+documents, it happens
+.Bl -dash -compact
+.It
+for empty
+.Ic \&P ,
+.Ic \&PP ,
+and
+.Ic \&LP
+macros
+.It
+for
+.Ic \&IP
+macros having neither head nor body arguments
.It
-Words aren't hyphenated.
+for
+.Ic \&br
+or
+.Ic \&sp
+right after
+.Ic \&SH
+or
+.Ic \&SS
+.El
+.It Sy "moving paragraph macro out of list"
+.Pq mdoc
+A list item in a
+.Ic \&Bl
+list contains a trailing paragraph macro.
+The paragraph macro is moved after the end of the list.
+.It Sy "skipping no-space macro"
+.Pq mdoc
+An input line begins with an
+.Ic \&Ns
+macro.
+The macro is ignored.
+.It Sy "blocks badly nested"
+.Pq mdoc
+If two blocks intersect, one should completely contain the other.
+Otherwise, rendered output is likely to look strange in any output
+format, and rendering in SGML-based output formats is likely to be
+outright wrong because such languages do not support badly nested
+blocks at all.
+Typical examples of badly nested blocks are
+.Qq Ic \&Ao \&Bo \&Ac \&Bc
+and
+.Qq Ic \&Ao \&Bq \&Ac .
+In these examples,
+.Ic \&Ac
+breaks
+.Ic \&Bo
+and
+.Ic \&Bq ,
+respectively.
+.It Sy "nested displays are not portable"
+.Pq mdoc
+A
+.Ic \&Bd ,
+.Ic \&D1 ,
+or
+.Ic \&Dl
+display occurs nested inside another
+.Ic \&Bd
+display.
+This works with
+.Nm ,
+but fails with most other implementations.
+.It Sy "moving content out of list"
+.Pq mdoc
+A
+.Ic \&Bl
+list block contains text or macros before the first
+.Ic \&It
+macro.
+The offending children are moved before the beginning of the list.
+.It Sy ".Vt block has child macro"
+.Pq mdoc
+The
+.Ic \&Vt
+macro supports plain text arguments only.
+Formatting may be ugly and semantic searching
+for the affected content might not work.
+.It Sy "fill mode already enabled, skipping"
+.Pq man
+A
+.Ic \&fi
+request occurs even though the document is still in fill mode,
+or already switched back to fill mode.
+It has no effect.
+.It Sy "fill mode already disabled, skipping"
+.Pq man
+An
+.Ic \&nf
+request occurs even though the document already switched to no-fill mode
+and did not switch back to fill mode yet.
+It has no effect.
+.It Sy "line scope broken"
+.Pq man
+While parsing the next-line scope of the previous macro,
+another macro is found that prematurely terminates the previous one.
+The previous, interrupted macro is deleted from the parse tree.
.El
-.Ss HTML/XHTML Compatibility
-.Bl -bullet -compact
+.Ss "Warnings related to missing arguments"
+.Bl -ohang
+.It Sy "skipping empty request"
+.Pq roff , eqn
+The macro name is missing from a macro definition request,
+or an
+.Xr eqn 5
+control statement or operation keyword lacks its required argument.
+.It Sy "conditional request controls empty scope"
+.Pq roff
+A conditional request is only useful if any of the following
+follows it on the same logical input line:
+.Bl -dash -compact
.It
The
-.Sq \efP
-escape will revert the font to the previous
-.Sq \ef
-escape, not to the last rendered decoration, which is now dictated by
-CSS instead of hard-coded.
-It also will not span past the current scope,
-for the same reason.
-Note that in
-.Sx ASCII Output
-mode, this will work fine.
+.Sq \e{
+keyword to open a multi-line scope.
.It
+A request or macro or some text, resulting in a single-line scope.
+.It
+The immediate end of the logical line without any intervening whitespace,
+resulting in next-line scope.
+.El
+Here, a conditional request is followed by trailing whitespace only,
+and there is no other content on its logical input line.
+Note that it doesn't matter whether the logical input line is split
+across multiple physical input lines using
+.Sq \e
+line continuation characters.
+This is one of the rare cases
+where trailing whitespace is syntactically significant.
+The conditional request controls a scope containing whitespace only,
+so it is unlikely to have a significant effect,
+except that it may control a following
+.Ic \&el
+clause.
+.It Sy "skipping empty macro"
+.Pq mdoc
+The indicated macro has no arguments and hence no effect.
+.It Sy "empty block"
+.Pq mdoc , man
+A
+.Ic \&Bd ,
+.Ic \&Bk ,
+.Ic \&Bl ,
+.Ic \&D1 ,
+.Ic \&Dl ,
+.Ic \&RS ,
+or
+.Ic \&UR
+block contains nothing in its body and will produce no output.
+.It Sy "empty argument, using 0n"
+.Pq mdoc
+The required width is missing after
+.Ic \&Bd
+or
+.Ic \&Bl
+.Fl offset
+or
+.Fl width.
+.It Sy "missing display type, using -ragged"
+.Pq mdoc
+The
+.Ic \&Bd
+macro is invoked without the required display type.
+.It Sy "list type is not the first argument"
+.Pq mdoc
+In a
+.Ic \&Bl
+macro, at least one other argument precedes the type argument.
The
+.Nm
+utility copes with any argument order, but some other
.Xr mdoc 5
-.Sq \&Bl \-hang
+implementations do not.
+.It Sy "missing -width in -tag list, using 8n"
+.Pq mdoc
+Every
+.Ic \&Bl
+macro having the
+.Fl tag
+argument requires
+.Fl width ,
+too.
+.It Sy "missing utility name, using \(dq\(dq"
+.Pq mdoc
+The
+.Ic \&Ex Fl std
+macro is called without an argument before
+.Ic \&Nm
+has first been called with an argument.
+.It Sy "missing function name, using \(dq\(dq"
+.Pq mdoc
+The
+.Ic \&Fo
+macro is called without an argument.
+No function name is printed.
+.It Sy "empty head in list item"
+.Pq mdoc
+In a
+.Ic \&Bl
+.Fl diag ,
+.Fl hang ,
+.Fl inset ,
+.Fl ohang ,
+or
+.Fl tag
+list, an
+.Ic \&It
+macro lacks the required argument.
+The item head is left empty.
+.It Sy "empty list item"
+.Pq mdoc
+In a
+.Ic \&Bl
+.Fl bullet ,
+.Fl dash ,
+.Fl enum ,
+or
+.Fl hyphen
+list, an
+.Ic \&It
+block is empty.
+An empty list item is shown.
+.It Sy "missing font type, using \efR"
+.Pq mdoc
+A
+.Ic \&Bf
+macro has no argument.
+It switches to the default font.
+.It Sy "unknown font type, using \efR"
+.Pq mdoc
+The
+.Ic \&Bf
+argument is invalid.
+The default font is used instead.
+.It Sy "nothing follows prefix"
+.Pq mdoc
+A
+.Ic \&Pf
+macro has no argument, or only one argument and no macro follows
+on the same input line.
+This defeats its purpose; in particular, spacing is not suppressed
+before the text or macros following on the next input line.
+.It Sy "empty reference block"
+.Pq mdoc
+An
+.Ic \&Rs
+macro is immediately followed by an
+.Ic \&Re
+macro on the next input line.
+Such an empty block does not produce any output.
+.It Sy "missing -std argument, adding it"
+.Pq mdoc
+An
+.Ic \&Ex
+or
+.Ic \&Rv
+macro lacks the required
+.Fl std
+argument.
+The
+.Nm
+utility assumes
+.Fl std
+even when it is not specified, but other implementations may not.
+.It Sy "missing option string, using \(dq\(dq"
+.Pq man
+The
+.Ic \&OP
+macro is invoked without any argument.
+An empty pair of square brackets is shown.
+.It Sy "missing resource identifier, using \(dq\(dq"
+.Pq man
+The
+.Ic \&UR
+macro is invoked without any argument.
+An empty pair of angle brackets is shown.
+.It Sy "missing eqn box, using \(dq\(dq"
+.Pq eqn
+A diacritic mark or a binary operator is found,
+but there is nothing to the left of it.
+An empty box is inserted.
+.El
+.Ss "Warnings related to bad macro arguments"
+.Bl -ohang
+.It Sy "unterminated quoted argument"
+.Pq roff
+Macro arguments can be enclosed in double quote characters
+such that space characters and macro names contained in the quoted
+argument need not be escaped.
+The closing quote of the last argument of a macro can be omitted.
+However, omitting it is not recommended because it makes the code
+harder to read.
+.It Sy "duplicate argument"
+.Pq mdoc
+A
+.Ic \&Bd
+or
+.Ic \&Bl
+macro has more than one
+.Fl compact ,
+more than one
+.Fl offset ,
+or more than one
+.Fl width
+argument.
+All but the last instances of these arguments are ignored.
+.It Sy "skipping duplicate argument"
+.Pq mdoc
+An
+.Ic \&An
+macro has more than one
+.Fl split
+or
+.Fl nosplit
+argument.
+All but the first of these arguments are ignored.
+.It Sy "skipping duplicate display type"
+.Pq mdoc
+A
+.Ic \&Bd
+macro has more than one type argument; the first one is used.
+.It Sy "skipping duplicate list type"
+.Pq mdoc
+A
+.Ic \&Bl
+macro has more than one type argument; the first one is used.
+.It Sy "skipping -width argument"
+.Pq mdoc
+A
+.Ic \&Bl
+.Fl column ,
+.Fl diag ,
+.Fl ohang ,
+.Fl inset ,
+or
+.Fl item
+list has a
+.Fl width
+argument.
+That has no effect.
+.It Sy "wrong number of cells"
+In a line of a
+.Ic \&Bl Fl column
+list, the number of tabs or
+.Ic \&Ta
+macros is less than the number expected from the list header line
+or exceeds the expected number by more than one.
+Missing cells remain empty, and all cells exceeding the number of
+columns are joined into one single cell.
+.It Sy "unknown AT&T UNIX version"
+.Pq mdoc
+An
+.Ic \&At
+macro has an invalid argument.
+It is used verbatim, with
+.Qq "AT&T UNIX "
+prefixed to it.
+.It Sy "comma in function argument"
+.Pq mdoc
+An argument of an
+.Ic \&Fa
+or
+.Ic \&Fn
+macro contains a comma; it should probably be split into two arguments.
+.It Sy "parenthesis in function name"
+.Pq mdoc
+The first argument of an
+.Ic \&Fc
+or
+.Ic \&Fn
+macro contains an opening or closing parenthesis; that's probably wrong,
+parentheses are added automatically.
+.It Sy "invalid content in Rs block"
+.Pq mdoc
+An
+.Ic \&Rs
+block contains plain text or non-% macros.
+The bogus content is left in the syntax tree.
+Formatting may be poor.
+.It Sy "invalid Boolean argument"
+.Pq mdoc
+An
+.Ic \&Sm
+macro has an argument other than
+.Cm on
+or
+.Cm off .
+The invalid argument is moved out of the macro, which leaves the macro
+empty, causing it to toggle the spacing mode.
+.It Sy "unknown font, skipping request"
+.Pq man , tbl
+A
+.Xr mandoc_roff 5
+.Ic \&ft
+request or a
+.Xr tbl 5
+.Ic \&f
+layout modifier has an unknown
+.Ar font
+argument.
+.It Sy "odd number of characters in request"
+.Pq roff
+A
+.Ic \&tr
+request contains an odd number of characters.
+The last character is mapped to the blank character.
+.El
+.Ss "Warnings related to plain text"
+.Bl -ohang
+.It Sy "blank line in fill mode, using .sp"
+.Pq mdoc
+The meaning of blank input lines is only well-defined in non-fill mode:
+In fill mode, line breaks of text input lines are not supposed to be
+significant.
+However, for compatibility with groff, blank lines in fill mode
+are replaced with
+.Ic \&sp
+requests.
+.It Sy "tab in filled text"
+.Pq mdoc , man
+The meaning of tab characters is only well-defined in non-fill mode:
+In fill mode, whitespace is not supposed to be significant
+on text input lines.
+As an implementation dependent choice, tab characters on text lines
+are passed through to the formatters in any case.
+Given that the text before the tab character will be filled,
+it is hard to predict which tab stop position the tab will advance to.
+.It Sy "whitespace at end of input line"
+.Pq mdoc , man , roff
+Whitespace at the end of input lines is almost never semantically
+significant \(em but in the odd case where it might be, it is
+extremely confusing when reviewing and maintaining documents.
+.It Sy "bad comment style"
+.Pq roff
+Comment lines start with a dot, a backslash, and a double-quote character.
+The
+.Nm
+utility treats the line as a comment line even without the backslash,
+but leaving out the backslash might not be portable.
+.It Sy "invalid escape sequence"
+.Pq roff
+An escape sequence has an invalid opening argument delimiter, lacks the
+closing argument delimiter, or the argument has too few characters.
+If the argument is incomplete,
+.Ic \e*
+and
+.Ic \en
+expand to an empty string,
+.Ic \eB
+to the digit
+.Sq 0 ,
and
-.Sq \&Bl \-tag
-list types render similarly (no break following overreached left-hand
-side) due to the expressive constraints of HTML.
+.Ic \ew
+to the length of the incomplete argument.
+All other invalid escape sequences are ignored.
+.It Sy "undefined string, using \(dq\(dq"
+.Pq roff
+If a string is used without being defined before,
+its value is implicitly set to the empty string.
+However, defining strings explicitly before use
+keeps the code more readable.
+.El
+.Ss "Warnings related to tables"
+.Bl -ohang
+.It Sy "tbl line starts with span"
+.Pq tbl
+The first cell in a table layout line is a horizontal span
+.Pq Sq Cm s .
+Data provided for this cell is ignored, and nothing is printed in the cell.
+.It Sy "tbl column starts with span"
+.Pq tbl
+The first line of a table layout specification
+requests a vertical span
+.Pq Sq Cm ^ .
+Data provided for this cell is ignored, and nothing is printed in the cell.
+.It Sy "skipping vertical bar in tbl layout"
+.Pq tbl
+A table layout specification contains more than two consecutive vertical bars.
+A double bar is printed, all additional bars are discarded.
+.El
+.Ss "Errors related to tables"
+.Bl -ohang
+.It Sy "non-alphabetic character in tbl options"
+.Pq tbl
+The table options line contains a character other than a letter,
+blank, or comma where the beginning of an option name is expected.
+The character is ignored.
+.It Sy "skipping unknown tbl option"
+.Pq tbl
+The table options line contains a string of letters that does not
+match any known option name.
+The word is ignored.
+.It Sy "missing tbl option argument"
+.Pq tbl
+A table option that requires an argument is not followed by an
+opening parenthesis, or the opening parenthesis is immediately
+followed by a closing parenthesis.
+The option is ignored.
+.It Sy "wrong tbl option argument size"
+.Pq tbl
+A table option argument contains an invalid number of characters.
+Both the option and the argument are ignored.
+.It Sy "empty tbl layout"
+.Pq tbl
+A table layout specification is completely empty,
+specifying zero lines and zero columns.
+As a fallback, a single left-justified column is used.
+.It Sy "invalid character in tbl layout"
+.Pq tbl
+A table layout specification contains a character that can neither
+be interpreted as a layout key character nor as a layout modifier,
+or a modifier precedes the first key.
+The invalid character is discarded.
+.It Sy "unmatched parenthesis in tbl layout"
+.Pq tbl
+A table layout specification contains an opening parenthesis,
+but no matching closing parenthesis.
+The rest of the input line, starting from the parenthesis, has no effect.
+.It Sy "tbl without any data cells"
+.Pq tbl
+A table does not contain any data cells.
+It will probably produce no output.
+.It Sy "ignoring data in spanned tbl cell"
+.Pq tbl
+A table cell is marked as a horizontal span
+.Pq Sq Cm s
+or vertical span
+.Pq Sq Cm ^
+in the table layout, but it contains data.
+The data is ignored.
+.It Sy "ignoring extra tbl data cells"
+.Pq tbl
+A data line contains more cells than the corresponding layout line.
+The data in the extra cells is ignored.
+.It Sy "data block open at end of tbl"
+.Pq tbl
+A data block is opened with
+.Cm T{ ,
+but never closed with a matching
+.Cm T} .
+The remaining data lines of the table are all put into one cell,
+and any remaining cells stay empty.
+.El
+.Ss "Errors related to roff, mdoc, and man code"
+.Bl -ohang
+.It Sy "input stack limit exceeded, infinite loop?"
+.Pq roff
+Explicit recursion limits are implemented for the following features,
+in order to prevent infinite loops:
+.Bl -dash -compact
.It
+expansion of nested escape sequences
+including expansion of strings and number registers,
+.It
+expansion of nested user-defined macros,
+.It
+and
+.Ic \&so
+file inclusion.
+.El
+When a limit is hit, the output is incorrect, typically losing
+some content, but the parser can continue.
+.It Sy "skipping bad character"
+.Pq mdoc , man , roff
+The input file contains a byte that is not a printable
+.Xr ascii 5
+character.
+The message mentions the character number.
+The offending byte is replaced with a question mark
+.Pq Sq \&? .
+Consider editing the input file to replace the byte with an ASCII
+transliteration of the intended character.
+.It Sy "skipping unknown macro"
+.Pq mdoc , man , roff
+The first identifier on a request or macro line is neither recognized as a
+.Xr mandoc_roff 5
+request, nor as a user-defined macro, nor, respectively, as an
+.Xr mdoc 5
+or
+.Xr man 5
+macro.
+It may be mistyped or unsupported.
+The request or macro is discarded including its arguments.
+.It Sy "skipping insecure request"
+.Pq roff
+An input file attempted to run a shell command
+or to read or write an external file.
+Such attempts are denied for security reasons.
+.It Sy "skipping item outside list"
+.Pq mdoc , eqn
+An
+.Ic \&It
+macro occurs outside any
+.Ic \&Bl
+list, or an
+.Xr eqn 5
+.Ic above
+delimiter occurs outside any pile.
+It is discarded including its arguments.
+.It Sy "skipping column outside column list"
+.Pq mdoc
+A
+.Ic \&Ta
+macro occurs outside any
+.Ic \&Bl Fl column
+block.
+It is discarded including its arguments.
+.It Sy "skipping end of block that is not open"
+.Pq mdoc , man , eqn , tbl , roff
+Various syntax elements can only be used to explicitly close blocks
+that have previously been opened.
+An
+.Xr mdoc 5
+block closing macro, a
+.Xr man 5
+.Ic \&RE
+or
+.Ic \&UE
+macro, an
+.Xr eqn 5
+right delimiter or closing brace, or the end of an equation, table, or
+.Xr mandoc_roff 5
+conditional request is encountered but no matching block is open.
+The offending request or macro is discarded.
+.It Sy "fewer RS blocks open, skipping"
+.Pq man
The
+.Ic \&RE
+macro is invoked with an argument, but less than the specified number of
+.Ic \&RS
+blocks is open.
+The
+.Ic \&RE
+macro is discarded.
+.It Sy "inserting missing end of block"
+.Pq mdoc , tbl
+Various
+.Xr mdoc 5
+macros as well as tables require explicit closing by dedicated macros.
+A block that doesn't support bad nesting
+ends before all of its children are properly closed.
+The open child nodes are closed implicitly.
+.It Sy "appending missing end of block"
+.Pq mdoc , man , eqn , tbl , roff
+At the end of the document, an explicit
+.Xr mdoc 5
+block, a
.Xr man 5
-.Sq IP
+next-line scope or
+.Ic \&RS
+or
+.Ic \&UR
+block, an equation, table, or
+.Xr mandoc_roff 5
+conditional or ignore block is still open.
+The open block is closed implicitly.
+.It Sy "escaped character not allowed in a name"
+.Pq roff
+Macro, string and register identifiers consist of printable,
+non-whitespace ASCII characters.
+Escape sequences and characters and strings expressed in terms of them
+cannot form part of a name.
+The first argument of an
+.Ic \&am ,
+.Ic \&as ,
+.Ic \&de ,
+.Ic \&ds ,
+.Ic \&nr ,
+or
+.Ic \&rr
+request, or any argument of an
+.Ic \&rm
+request, or the name of a request or user defined macro being called,
+is terminated by an escape sequence.
+In the cases of
+.Ic \&as ,
+.Ic \&ds ,
and
-.Sq TP
-lists render similarly.
-.El
-.Sh INTERFACE STABILITY
+.Ic \&nr ,
+the request has no effect at all.
+In the cases of
+.Ic \&am ,
+.Ic \&de ,
+.Ic \&rr ,
+and
+.Ic \&rm ,
+what was parsed up to this point is used as the arguments to the request,
+and the rest of the input line is discarded including the escape sequence.
+When parsing for a request or a user-defined macro name to be called,
+only the escape sequence is discarded.
+The characters preceding it are used as the request or macro name,
+the characters following it are used as the arguments to the request or macro.
+.It Sy "NOT IMPLEMENTED: Bd -file"
+.Pq mdoc
+For security reasons, the
+.Ic \&Bd
+macro does not support the
+.Fl file
+argument.
+By requesting the inclusion of a sensitive file, a malicious document
+might otherwise trick a privileged user into inadvertently displaying
+the file on the screen, revealing the file content to bystanders.
+The argument is ignored including the file name following it.
+.It Sy "missing list type, using -item"
+.Pq mdoc
+A
+.Ic \&Bl
+macro fails to specify the list type.
+.It Sy "missing manual name, using \(dq\(dq"
+.Pq mdoc
+The first call to
+.Ic \&Nm
+lacks the required argument.
+.It Sy "uname(3) system call failed, using UNKNOWN"
+.Pq mdoc
The
+.Ic \&Os
+macro is called without arguments, and the
+.Xr uname 3
+system call failed.
+As a workaround,
+.Nm
+can be compiled with
+.Sm off
+.Fl D Cm OSNAME=\(dq\e\(dq Ar string Cm \e\(dq\(dq .
+.Sm on
+.It Sy "unknown standard specifier"
+.Pq mdoc
+An
+.Ic \&St
+macro has an unknown argument and is discarded.
+.It Sy "skipping request without numeric argument"
+.Pq roff , eqn
+An
+.Ic \&it
+request or an
+.Xr eqn 5
+.Ic \&size
+or
+.Ic \&gsize
+statement has a non-numeric or negative argument or no argument at all.
+The invalid request or statement is ignored.
+.It Sy "NOT IMPLEMENTED: .so with absolute path or \(dq..\(dq"
+.Pq roff
+For security reasons,
+.Nm
+allows
+.Ic \&so
+file inclusion requests only with relative paths
+and only without ascending to any parent directory.
+By requesting the inclusion of a sensitive file, a malicious document
+might otherwise trick a privileged user into inadvertently displaying
+the file on the screen, revealing the file content to bystanders.
+.Nm
+only shows the path as it appears behind
+.Ic \&so .
+.It Sy ".so request failed"
+.Pq roff
+Servicing a
+.Ic \&so
+request requires reading an external file, but the file could not be
+opened.
+.Nm
+only shows the path as it appears behind
+.Ic \&so .
+.It Sy "skipping all arguments"
+.Pq mdoc , man , eqn , roff
+An
+.Xr mdoc 5
+.Ic \&Bt ,
+.Ic \&Ed ,
+.Ic \&Ef ,
+.Ic \&Ek ,
+.Ic \&El ,
+.Ic \&Lp ,
+.Ic \&Pp ,
+.Ic \&Re ,
+.Ic \&Rs ,
+or
+.Ic \&Ud
+macro, an
+.Ic \&It
+macro in a list that don't support item heads, a
+.Xr man 5
+.Ic \&LP ,
+.Ic \&P ,
+or
+.Ic \&PP
+macro, an
+.Xr eqn 5
+.Ic \&EQ
+or
+.Ic \&EN
+macro, or a
+.Xr mandoc_roff 5
+.Ic \&br ,
+.Ic \&fi ,
+or
+.Ic \&nf
+request or
+.Sq \&..
+block closing request is invoked with at least one argument.
+All arguments are ignored.
+.It Sy "skipping excess arguments"
+.Pq mdoc , man , roff
+A macro or request is invoked with too many arguments:
+.Bl -dash -offset 2n -width 2n -compact
+.It
+.Ic \&Fo ,
+.Ic \&PD ,
+.Ic \&RS ,
+.Ic \&UR ,
+.Ic \&ft ,
+or
+.Ic \&sp
+with more than one argument
+.It
+.Ic \&An
+with another argument after
+.Fl split
+or
+.Fl nosplit
+.It
+.Ic \&RE
+with more than one argument or with a non-integer argument
+.It
+.Ic \&OP
+or a request of the
+.Ic \&de
+family with more than two arguments
+.It
+.Ic \&Dt
+with more than three arguments
+.It
+.Ic \&TH
+with more than five arguments
+.It
+.Ic \&Bd ,
+.Ic \&Bk ,
+or
+.Ic \&Bl
+with invalid arguments
+.El
+The excess arguments are ignored.
+.El
+.Ss Unsupported features
+.Bl -ohang
+.It Sy "input too large"
+.Pq mdoc , man
+Currently,
+.Nm
+cannot handle input files larger than its arbitrary size limit
+of 2^31 bytes (2 Gigabytes).
+Since useful manuals are always small, this is not a problem in practice.
+Parsing is aborted as soon as the condition is detected.
+.It Sy "unsupported control character"
+.Pq roff
+An ASCII control character supported by other
+.Xr mandoc_roff 5
+implementations but not by
.Nm
-utility is
-.Sy Committed ,
-but the details of specific output formats other than ASCII are
-.Nm Uncommitted .
+was found in an input file.
+It is replaced by a question mark.
+.It Sy "unsupported roff request"
+.Pq roff
+An input file contains a
+.Xr mandoc_roff 5
+request supported by GNU troff or Heirloom troff but not by
+.Nm ,
+and it is likely that this will cause information loss
+or considerable misformatting.
+.It Sy "eqn delim option in tbl"
+.Pq eqn , tbl
+The options line of a table defines equation delimiters.
+Any equation source code contained in the table will be printed unformatted.
+.It Sy "unsupported table layout modifier"
+.Pq tbl
+A table layout specification contains an
+.Sq Cm m
+modifier.
+The modifier is discarded.
+.It Sy "ignoring macro in table"
+.Pq tbl , mdoc , man
+A table contains an invocation of an
+.Xr mdoc 5
+or
+.Xr man 5
+macro or of an undefined macro.
+The macro is ignored, and its arguments are handled
+as if they were a text line.
+.El
.Sh SEE ALSO
.Xr eqn 5 ,
.Xr man 5 ,
.Xr mandoc_char 5 ,
-.Xr mdoc 5 ,
.Xr mandoc_roff 5 ,
+.Xr mdoc 5 ,
.Xr tbl 5
.Sh AUTHORS
The
.Nm
utility was written by
-.An Kristaps Dzonsons ,
-.Mt kristaps@bsd.lv .
-.Sh CAVEATS
+.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
+and is maintained by
+.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
+.Sh BUGS
In
-.Fl T Ns Cm html
-and
-.Fl T Ns Cm xhtml ,
+.Fl T Ns Cm html ,
the maximum size of an element attribute is determined by
.Dv BUFSIZ ,
which is usually 1024 bytes.
Be aware of this when setting long link
formats such as
.Fl O Ns Cm style Ns = Ns Ar really/long/link .
-.Pp
-Nesting elements within next-line element scopes of
-.Fl m Ns Cm an ,
-such as
-.Sq br
-within an empty
-.Sq B ,
-will confuse
-.Fl T Ns Cm html
-and
-.Fl T Ns Cm xhtml
-and cause them to forget the formatting of the prior next-line scope.
-.Pp
-The
-.Sq \(aq
-control character is an alias for the standard macro control character
-and does not emit a line-break as stipulated in GNU troff.
diff --git a/usr/src/man/man5/eqn.5 b/usr/src/man/man5/eqn.5
index cb25ee2759..bfdb0cd58c 100644
--- a/usr/src/man/man5/eqn.5
+++ b/usr/src/man/man5/eqn.5
@@ -1,3 +1,7 @@
+.\" $Id: eqn.7,v 1.34 2015/03/09 20:17:23 schwarze Exp $
+.\"
+.\" Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+.\" Copyright (c) 2014 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
@@ -11,11 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.\"
-.\" Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright 2012 Nexenta Systems, Inc. All rights reserved.
-.\"
-.Dd Jul 19, 2014
+.Dd $Mdocdate: March 9 2015 $
.Dt EQN 5
.Os
.Sh NAME
@@ -38,7 +38,9 @@ This manual describes the
.Nm
language accepted by the
.Xr mandoc 1
-utility, which corresponds to the Second Edition eqn specification (see
+utility, which corresponds to the Second Edition
+.Nm
+specification (see
.Sx SEE ALSO
for references).
.Pp
@@ -61,7 +63,7 @@ and
strings.
.Em Note :
these are not the same as
-.Xr roff 5
+.Xr mandoc_roff 5
macros, and may only be invoked as
.Sq \&.EQ .
.Pp
@@ -70,37 +72,49 @@ case-sensitive literals in the input:
.Bd -literal -offset indent
eqn : box | eqn box
box : text
- | \*q{\*q eqn \*q}\*q
- | \*qdefine\*q text text
- | \*qndefine\*q text text
- | \*qtdefine\*q text text
- | \*qgfont\*q text
- | \*qgsize\*q text
- | \*qset\*q text text
- | \*qundef\*q text
+ | \(dq{\(dq eqn \(dq}\(dq
+ | \(dqdefine\(dq text text
+ | \(dqndefine\(dq text text
+ | \(dqtdefine\(dq text text
+ | \(dqgfont\(dq text
+ | \(dqgsize\(dq text
+ | \(dqset\(dq text text
+ | \(dqundef\(dq text
+ | \(dqsqrt\(dq box
| box pos box
| box mark
- | \*qmatrix\*q \*q{\*q [col \*q{\*q list \*q}\*q ]*
- | pile \*q{\*q list \*q}\*q
+ | \(dqmatrix\(dq \(dq{\(dq [col \(dq{\(dq list \(dq}\(dq ]*
+ | pile \(dq{\(dq list \(dq}\(dq
| font box
- | \*qsize\*q text box
- | \*qleft\*q text eqn [\*qright\*q text]
-col : \*qlcol\*q | \*qrcol\*q | \*qccol\*q | \*qcol\*q
-text : [^space\e\*q]+ | \e\*q.*\e\*q
-pile : \*qlpile\*q | \*qcpile\*q | \*qrpile\*q | \*qpile\*q
-pos : \*qover\*q | \*qsup\*q | \*qsub\*q | \*qto\*q | \*qfrom\*q
-mark : \*qdot\*q | \*qdotdot\*q | \*qhat\*q | \*qtilde\*q | \*qvec\*q
- | \*qdyad\*q | \*qbar\*q | \*qunder\*q
-font : \*qroman\*q | \*qitalic\*q | \*qbold\*q | \*qfat\*q
+ | \(dqsize\(dq text box
+ | \(dqleft\(dq text eqn [\(dqright\(dq text]
+col : \(dqlcol\(dq | \(dqrcol\(dq | \(dqccol\(dq | \(dqcol\(dq
+text : [^space\e\(dq]+ | \e\(dq.*\e\(dq
+pile : \(dqlpile\(dq | \(dqcpile\(dq | \(dqrpile\(dq | \(dqpile\(dq
+pos : \(dqover\(dq | \(dqsup\(dq | \(dqsub\(dq | \(dqto\(dq | \(dqfrom\(dq
+mark : \(dqdot\(dq | \(dqdotdot\(dq | \(dqhat\(dq | \(dqtilde\(dq | \(dqvec\(dq
+ | \(dqdyad\(dq | \(dqbar\(dq | \(dqunder\(dq
+font : \(dqroman\(dq | \(dqitalic\(dq | \(dqbold\(dq | \(dqfat\(dq
list : eqn
- | list \*qabove\*q eqn
+ | list \(dqabove\(dq eqn
space : [\e^~ \et]
.Ed
.Pp
White-space consists of the space, tab, circumflex, and tilde
characters.
+It is required to delimit tokens consisting of alphabetic characters
+and it is ignored at other places.
+Braces and quotes also delimit tokens.
If within a quoted string, these space characters are retained.
-Quoted strings are also not scanned for replacement definitions.
+Quoted strings are also not scanned for keywords, glyph names,
+and expansion of definitions.
+To print a literal quote character, it can be prepended with a
+backslash or expressed with the \e(dq escape sequence.
+.Pp
+Subequations can be enclosed in braces to pass them as arguments
+to operation keywords, overriding standard operation precedence.
+Braces can be nested.
+To set a brace verbatim, it needs to be enclosed in quotes.
.Pp
The following text terms are translated into a rendered glyph, if
available: alpha, beta, chi, delta, epsilon, eta, gamma, iota, kappa,
@@ -108,12 +122,15 @@ lambda, mu, nu, omega, omicron, phi, pi, psi, rho, sigma, tau, theta,
upsilon, xi, zeta, DELTA, GAMMA, LAMBDA, OMEGA, PHI, PI, PSI, SIGMA,
THETA, UPSILON, XI, inter (intersection), union (union), prod (product),
int (integral), sum (summation), grad (gradient), del (vector
-differential), times (multiply), cdot (centre-dot), nothing (zero-width
+differential), times (multiply), cdot (center-dot), nothing (zero-width
space), approx (approximately equals), prime (prime), half (one-half),
partial (partial differential), inf (infinity), >> (much greater), <<
-(much less), \-> (left arrow), <\- (right arrow), += (plus-minus), !=
+(much less), \-> (left arrow), <\- (right arrow), +\- (plus-minus), !=
(not equal), == (equivalence), <= (less-than-equal), and >=
(more-than-equal).
+The character escape sequences documented in
+.Xr mandoc_char 5
+can be used, too.
.Pp
The following control statements are available:
.Bl -tag -width Ds
@@ -121,7 +138,7 @@ The following control statements are available:
Replace all occurrences of a key with a value.
Its syntax is as follows:
.Pp
-.D1 define Ar key cvalc
+.D1 Cm define Ar key cvalc
.Pp
The first character of the value string,
.Ar c ,
@@ -129,8 +146,8 @@ is used as the delimiter for the value
.Ar val .
This allows for arbitrary enclosure of terms (not just quotes), such as
.Pp
-.D1 define Ar foo 'bar baz'
-.D1 define Ar foo cbar bazc
+.D1 Cm define Ar foo 'bar baz'
+.D1 Cm define Ar foo cbar bazc
.Pp
It is an error to have an empty
.Ar key
@@ -165,28 +182,26 @@ is discarded.
Set the default font of subsequent output.
Its syntax is as follows:
.Pp
-.D1 gfont Ar font
+.D1 Cm gfont Ar font
.Pp
-In
-.Xr mandoc 1 ,
-this value is discarded.
+In mandoc, this value is discarded.
.It Cm gsize
Set the default size of subsequent output.
Its syntax is as follows:
.Pp
-.D1 gsize Ar size
+.D1 Cm gsize Oo +|\- Oc Ns Ar size
.Pp
The
.Ar size
value should be an integer.
+If prepended by a sign,
+the font size is changed relative to the current size.
.It Cm set
Set an equation mode.
-In
-.Xr mandoc 1 ,
-both arguments are thrown away.
+In mandoc, both arguments are thrown away.
Its syntax is as follows:
.Pp
-.D1 set Ar key val
+.D1 Cm set Ar key val
.Pp
The
.Ar key
@@ -198,7 +213,7 @@ This statement is a GNU extension.
Unset a previously-defined key.
Its syntax is as follows:
.Pp
-.D1 define Ar key
+.D1 Cm define Ar key
.Pp
Once invoked, the definition for
.Ar key
@@ -208,44 +223,233 @@ The
is not expanded for replacements.
This statement is a GNU extension.
.El
-.Sh COMPATIBILITY
-This section documents the compatibility of
+.Pp
+Operation keywords have the following semantics:
+.Bl -tag -width Ds
+.It Cm above
+See
+.Cm pile .
+.It Cm bar
+Draw a line over the preceding box.
+.It Cm bold
+Set the following box using bold font.
+.It Cm ccol
+Like
+.Cm cpile ,
+but for use in
+.Cm matrix .
+.It Cm cpile
+Like
+.Cm pile ,
+but with slightly increased vertical spacing.
+.It Cm dot
+Set a single dot over the preceding box.
+.It Cm dotdot
+Set two dots (dieresis) over the preceding box.
+.It Cm dyad
+Set a dyad symbol (left-right arrow) over the preceding box.
+.It Cm fat
+A synonym for
+.Cm bold .
+.It Cm font
+Set the second argument using the font specified by the first argument;
+currently not recognized by the
.Xr mandoc 1
.Nm
-and the
-.Xr troff 1
+parser.
+.It Cm from
+Set the following box below the preceding box,
+using a slightly smaller font.
+Used for sums, integrals, limits, and the like.
+.It Cm hat
+Set a hat (circumflex) over the preceding box.
+.It Cm italic
+Set the following box using italic font.
+.It Cm lcol
+Like
+.Cm lpile ,
+but for use in
+.Cm matrix .
+.It Cm left
+Set the first argument as a big left delimiter before the second argument.
+As an optional third argument,
+.Cm right
+can follow.
+In that case, the fourth argument is set as a big right delimiter after
+the second argument.
+.It Cm lpile
+Like
+.Cm cpile ,
+but subequations are left-justified.
+.It Cm matrix
+Followed by a list of columns enclosed in braces.
+All columns need to have the same number of subequations.
+The columns are set as a matrix.
+The difference compared to multiple subsequent
+.Cm pile
+operators is that in a
+.Cm matrix ,
+corresponding subequations in all columns line up horizontally,
+while each
+.Cm pile
+does vertical spacing independently.
+.It Cm over
+Set a fraction.
+The preceding box is the numerator, the following box is the denominator.
+.It Cm pile
+Followed by a list of subequations enclosed in braces,
+the subequations being separated by
+.Cm above
+keywords.
+Sets the subequations one above the other, each of them centered.
+Typically used to represent vectors in coordinate representation.
+.It Cm rcol
+Like
+.Cm rpile ,
+but for use in
+.Cm matrix .
+.It Cm right
+See
+.Cm left ;
+.Cm right
+cannot be used without
+.Cm left .
+To set a big right delimiter without a big left delimiter, the following
+construction can be used:
+.Pp
+.D1 Cm left No \(dq\(dq Ar box Cm right Ar delimiter
+.It Cm roman
+Set the following box using the default font.
+.It Cm rpile
+Like
+.Cm cpile ,
+but subequations are right-justified.
+.It Cm size
+Set the second argument with the font size specified by the first
+argument; currently ignored by
+.Xr mandoc 1 .
+By prepending a plus or minus sign to the first argument,
+the font size can be selected relative to the current size.
+.It Cm sqrt
+Set the square root of the following box.
+.It Cm sub
+Set the following box as a subscript to the preceding box.
+.It Cm sup
+Set the following box as a superscript to the preceding box.
+As a special case, if a
+.Cm sup
+clause immediately follows a
+.Cm sub
+clause as in
+.Pp
+.D1 Ar mainbox Cm sub Ar subbox Cm sup Ar supbox
+.Pp
+both are set with respect to the same
+.Ar mainbox ,
+that is,
+.Ar supbox
+is set above
+.Ar subbox .
+.It Cm tilde
+Set a tilde over the preceding box.
+.It Cm to
+Set the following box above the preceding box,
+using a slightly smaller font.
+Used for sums and integrals and the like.
+As a special case, if a
+.Cm to
+clause immediately follows a
+.Cm from
+clause as in
+.Pp
+.D1 Ar mainbox Cm from Ar frombox Cm to Ar tobox
+.Pp
+both are set below and above the same
+.Ar mainbox .
+.It Cm under
+Underline the preceding box.
+.It Cm vec
+Set a vector symbol (right arrow) over the preceding box.
+.El
+.Pp
+The binary operations
+.Cm from ,
+.Cm to ,
+.Cm sub ,
+and
+.Cm sup
+group to the right, that is,
+.Pp
+.D1 Ar mainbox Cm sup Ar supbox Cm sub Ar subbox
+.Pp
+is the same as
+.Pp
+.D1 Ar mainbox Cm sup Brq Ar supbox Cm sub Ar subbox
+.Pp
+and different from
+.Pp
+.D1 Bro Ar mainbox Cm sup Ar supbox Brc Cm sub Ar subbox .
+.Pp
+By contrast,
+.Cm over
+groups to the left.
+.Pp
+In the following list, earlier operations bind more tightly than
+later operations:
+.Pp
+.Bl -enum -compact
+.It
+.Cm dyad ,
+.Cm vec ,
+.Cm under ,
+.Cm bar ,
+.Cm tilde ,
+.Cm hat ,
+.Cm dot ,
+.Cm dotdot
+.It
+.Cm fat ,
+.Cm roman ,
+.Cm italic ,
+.Cm bold ,
+.Cm size
+.It
+.Cm sub ,
+.Cm sup
+.It
+.Cm sqrt
+.It
+.Cm over
+.It
+.Cm from ,
+.Cm to
+.El
+.Sh COMPATIBILITY
+This section documents the compatibility of mandoc
+.Nm
+and the troff
.Nm
implementation (including GNU troff).
.Pp
.Bl -dash -compact
.It
The text string
-.Sq \e\*q
-is interpreted as a literal quote in
-.Xr troff 1 .
-In
-.Xr mandoc 1 ,
-this is interpreted as a comment.
+.Sq \e\(dq
+is interpreted as a literal quote in troff.
+In mandoc, this is interpreted as a comment.
.It
-In
-.Xr troff 1 ,
-The circumflex and tilde white-space symbols map to
+In troff, The circumflex and tilde white-space symbols map to
fixed-width spaces.
-In
-.Xr mandoc 1 ,
-these characters are synonyms for the space character.
+In mandoc, these characters are synonyms for the space character.
.It
-The
-.Xr troff 1 ,
-implementation of
+The troff implementation of
.Nm
allows for equation alignment with the
.Cm mark
and
.Cm lineup
tokens.
-.Xr mandoc 1
-discards these tokens.
+mandoc discards these tokens.
The
.Cm back Ar n ,
.Cm fwd Ar n ,
@@ -258,8 +462,8 @@ commands are also ignored.
.Xr mandoc 1 ,
.Xr man 5 ,
.Xr mandoc_char 5 ,
-.Xr mdoc 5 ,
-.Xr roff 5
+.Xr mandoc_roff 5 ,
+.Xr mdoc 5
.Rs
.%A Brian W. Kernighan
.%A Lorinda L. Cherry
@@ -293,5 +497,4 @@ was added in 2011.
This
.Nm
reference was written by
-.An Kristaps Dzonsons ,
-.Mt kristaps@bsd.lv .
+.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
diff --git a/usr/src/man/man5/mandoc_char.5 b/usr/src/man/man5/mandoc_char.5
index 15b421474d..48f8348c8e 100644
--- a/usr/src/man/man5/mandoc_char.5
+++ b/usr/src/man/man5/mandoc_char.5
@@ -1,3 +1,8 @@
+.\" $Id: mandoc_char.7,v 1.59 2015/01/20 19:39:34 schwarze Exp $
+.\"
+.\" Copyright (c) 2003 Jason McIntyre <jmc@openbsd.org>
+.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+.\" Copyright (c) 2011 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
@@ -11,13 +16,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.\"
-.\" Copyright (c) 2003 Jason McIntyre <jmc@openbsd.org>
-.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
-.\" Copyright 2012 Nexenta Systems, Inc. All rights reserved.
-.\"
-.Dd Nov 23, 2011
+.Dd $Mdocdate: January 20 2015 $
.Dt MANDOC_CHAR 5
.Os
.Sh NAME
@@ -25,7 +24,7 @@
.Nd mandoc special characters
.Sh DESCRIPTION
This page documents the
-.Xr roff 5
+.Xr mandoc_roff 5
escape sequences accepted by
.Xr mandoc 1
to represent special characters in
@@ -99,26 +98,27 @@ in literal context, and when none of the following special cases apply,
just use the normal space character
.Pq Sq \ .
.Pp
-When filling text, lines may be broken between words, i.e. at space
+When filling text, output lines may be broken between words, i.e. at space
characters.
To prevent a line break between two particular words,
-use the non-breaking space escape sequence
-.Pq Sq \e~
+use the unpaddable non-breaking space escape sequence
+.Pq Sq \e\ \&
instead of the normal space character.
For example, the input string
-.Dq number\e~1
+.Dq number\e\ 1
will be kept together as
-.Dq number\~1
+.Dq number\ 1
on the same output line.
.Pp
On request and macro lines, the normal space character serves as an
argument delimiter.
-To include whitespace into arguments, quoting is usually the best choice.
-In some cases, using either the non-breaking
-.Pq Sq \e~
-or the breaking
+To include whitespace into arguments, quoting is usually the best choice;
+see the MACRO SYNTAX section in
+.Xr mandoc_roff 5 .
+In some cases, using the non-breaking space escape sequence
.Pq Sq \e\ \&
-space escape sequence may be preferable.
+may be preferable.
+.Pp
To escape macro names and to protect whitespace at the end
of input lines, the zero-width space
.Pq Sq \e&
@@ -147,7 +147,7 @@ The period
.Pq Sq \&.
is handled specially at the beginning of an input line,
where it introduces a
-.Xr roff 5
+.Xr mandoc_roff 5
request or a macro, and when appearing alone as a macro argument in
.Xr mdoc 5 .
In such situations, prepend a zero-width space
@@ -171,11 +171,11 @@ is not the right way to output a backslash.
Because
.Xr mandoc 1
does not implement full
-.Xr roff 5
+.Xr mandoc_roff 5
functionality, it may work with
.Xr mandoc 1 ,
but it may have weird effects on complete
-.Xr roff 5
+.Xr mandoc_roff 5
implementations.
.Sh SPECIAL CHARACTERS
Special characters are encoded as
@@ -189,20 +189,19 @@ and
For details, see the
.Em Special Characters
subsection of the
-.Xr roff 5
+.Xr mandoc_roff 5
manual.
.Pp
Spacing:
.Bl -column "Input" "Description" -offset indent -compact
.It Em Input Ta Em Description
-.It \e~ Ta non-breaking, non-collapsing space
-.It \e Ta breaking, non-collapsing n-width space
-.It \e^ Ta zero-width space
-.It \e% Ta zero-width space
+.It Sq \e\ \& Ta unpaddable non-breaking space
+.It \e~ Ta paddable non-breaking space
+.It \e0 Ta unpaddable, breaking digit-width space
+.It \e| Ta one-sixth \e(em narrow space, zero width in nroff mode
+.It \e^ Ta one-twelfth \e(em half-narrow space, zero width in nroff
.It \e& Ta zero-width space
-.It \e| Ta zero-width space
-.It \e0 Ta breaking, non-collapsing digit-width space
-.It \ec Ta removes any trailing space (if applicable)
+.It \e% Ta zero-width space allowing hyphenation
.El
.Pp
Lines:
@@ -211,7 +210,7 @@ Lines:
.It \e(ba Ta \(ba Ta bar
.It \e(br Ta \(br Ta box rule
.It \e(ul Ta \(ul Ta underscore
-.It \e(rl Ta \(rl Ta overline
+.It \e(rn Ta \(rn Ta overline
.It \e(bb Ta \(bb Ta broken bar
.It \e(sl Ta \(sl Ta forward slash
.It \e(rs Ta \(rs Ta backward slash
@@ -274,7 +273,7 @@ Quotes:
.El
.Pp
Brackets:
-.Bl -column "xxbracketrightbpx" Rendered Description -offset indent -compact
+.Bl -column "xxbracketrightbtx" Rendered Description -offset indent -compact
.It Em Input Ta Em Rendered Ta Em Description
.It \e(lB Ta \(lB Ta left bracket
.It \e(rB Ta \(rB Ta right bracket
@@ -285,30 +284,30 @@ Brackets:
.It \e(bv Ta \(bv Ta brace extension
.It \e[braceex] Ta \[braceex] Ta brace extension
.It \e[bracketlefttp] Ta \[bracketlefttp] Ta top-left hooked bracket
-.It \e[bracketleftbp] Ta \[bracketleftbp] Ta bottom-left hooked bracket
+.It \e[bracketleftbt] Ta \[bracketleftbt] Ta bottom-left hooked bracket
.It \e[bracketleftex] Ta \[bracketleftex] Ta left hooked bracket extension
.It \e[bracketrighttp] Ta \[bracketrighttp] Ta top-right hooked bracket
-.It \e[bracketrightbp] Ta \[bracketrightbp] Ta bottom-right hooked bracket
+.It \e[bracketrightbt] Ta \[bracketrightbt] Ta bottom-right hooked bracket
.It \e[bracketrightex] Ta \[bracketrightex] Ta right hooked bracket extension
.It \e(lt Ta \(lt Ta top-left hooked brace
.It \e[bracelefttp] Ta \[bracelefttp] Ta top-left hooked brace
.It \e(lk Ta \(lk Ta mid-left hooked brace
.It \e[braceleftmid] Ta \[braceleftmid] Ta mid-left hooked brace
.It \e(lb Ta \(lb Ta bottom-left hooked brace
-.It \e[braceleftbp] Ta \[braceleftbp] Ta bottom-left hooked brace
+.It \e[braceleftbt] Ta \[braceleftbt] Ta bottom-left hooked brace
.It \e[braceleftex] Ta \[braceleftex] Ta left hooked brace extension
.It \e(rt Ta \(rt Ta top-left hooked brace
.It \e[bracerighttp] Ta \[bracerighttp] Ta top-right hooked brace
.It \e(rk Ta \(rk Ta mid-right hooked brace
.It \e[bracerightmid] Ta \[bracerightmid] Ta mid-right hooked brace
.It \e(rb Ta \(rb Ta bottom-right hooked brace
-.It \e[bracerightbp] Ta \[bracerightbp] Ta bottom-right hooked brace
+.It \e[bracerightbt] Ta \[bracerightbt] Ta bottom-right hooked brace
.It \e[bracerightex] Ta \[bracerightex] Ta right hooked brace extension
.It \e[parenlefttp] Ta \[parenlefttp] Ta top-left hooked parenthesis
-.It \e[parenleftbp] Ta \[parenleftbp] Ta bottom-left hooked parenthesis
+.It \e[parenleftbt] Ta \[parenleftbt] Ta bottom-left hooked parenthesis
.It \e[parenleftex] Ta \[parenleftex] Ta left hooked parenthesis extension
.It \e[parenrighttp] Ta \[parenrighttp] Ta top-right hooked parenthesis
-.It \e[parenrightbp] Ta \[parenrightbp] Ta bottom-right hooked parenthesis
+.It \e[parenrightbt] Ta \[parenrightbt] Ta bottom-right hooked parenthesis
.It \e[parenrightex] Ta \[parenrightex] Ta right hooked parenthesis extension
.El
.Pp
@@ -353,7 +352,7 @@ Mathematical:
.It \e(-+ Ta \(-+ Ta minus-plus
.It \e(+- Ta \(+- Ta plus-minus
.It \e[t+-] Ta \[t+-] Ta plus-minus (text)
-.It \e(pc Ta \(pc Ta centre-dot
+.It \e(pc Ta \(pc Ta center-dot
.It \e(mu Ta \(mu Ta multiply
.It \e[tmu] Ta \[tmu] Ta multiply (text)
.It \e(c* Ta \(c* Ta circle-multiply
@@ -370,11 +369,11 @@ Mathematical:
.It \e(!= Ta \(!= Ta not equal
.It \e(== Ta \(== Ta equivalent
.It \e(ne Ta \(ne Ta not equivalent
-.It \e(=~ Ta \(=~ Ta congruent
-.It \e(-~ Ta \(-~ Ta asymptotically congruent
-.It \e(ap Ta \(ap Ta asymptotically similar
-.It \e(~~ Ta \(~~ Ta approximately similar
-.It \e(~= Ta \(~= Ta approximately equal
+.It \e(ap Ta \(ap Ta tilde operator
+.It \e(|= Ta \(|= Ta asymptotically equal
+.It \e(=~ Ta \(=~ Ta approximately equal
+.It \e(~~ Ta \(~~ Ta almost equal
+.It \e(~= Ta \(~= Ta almost equal
.It \e(pt Ta \(pt Ta proportionate
.It \e(es Ta \(es Ta empty set
.It \e(mo Ta \(mo Ta element
@@ -622,7 +621,7 @@ and
For details, see the
.Em Predefined Strings
subsection of the
-.Xr roff 5
+.Xr mandoc_roff 5
manual.
.Bl -column "Input" "Rendered" "Description" -offset indent
.It Em Input Ta Em Rendered Ta Em Description
@@ -656,13 +655,18 @@ manual.
.It \e*(Ai Ta \*(Ai Ta ANSI standard name
.El
.Sh UNICODE CHARACTERS
-The escape sequence
+The escape sequences
.Pp
-.Dl \e[uXXXX]
+.Dl \e[uXXXX] and \eC'uXXXX'
.Pp
-is interpreted as a Unicode codepoint.
+are interpreted as Unicode codepoints.
The codepoint must be in the range above U+0080 and less than U+10FFFF.
-For compatibility, points must be zero-padded to four characters; if
+For compatibility, the hexadecimal digits
+.Sq A
+to
+.Sq F
+must be given as uppercase characters,
+and points must be zero-padded to four characters; if
greater than four characters, no zero padding is allowed.
Unicode surrogates are not allowed.
.\" .Pp
@@ -685,7 +689,7 @@ For example, do not use \eN'34', use \e(dq, or even the plain
.Sq \(dq
character where possible.
.Sh COMPATIBILITY
-This section documents compatibility between mandoc and other other
+This section documents compatibility between mandoc and other
troff implementations, at this time limited to GNU troff
.Pq Qq groff .
.Pp
@@ -723,18 +727,17 @@ known representation.
.Sh SEE ALSO
.Xr mandoc 1 ,
.Xr man 5 ,
-.Xr mdoc 5 ,
-.Xr roff 5
+.Xr mandoc_roff 5 ,
+.Xr mdoc 5
.Sh AUTHORS
The
.Nm
manual page was written by
-.An Kristaps Dzonsons ,
-.Mt kristaps@bsd.lv .
+.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
.Sh CAVEATS
-The
+The predefined string
.Sq \e*(Ba
-escape mimics the behaviour of the
+mimics the behaviour of the
.Sq \&|
character in
.Xr mdoc 5 ;
diff --git a/usr/src/man/man5/mandoc_roff.5 b/usr/src/man/man5/mandoc_roff.5
index 731f93e134..bef11f27cf 100644
--- a/usr/src/man/man5/mandoc_roff.5
+++ b/usr/src/man/man5/mandoc_roff.5
@@ -1,3 +1,7 @@
+.\" $Id: roff.7,v 1.70 2015/02/17 17:16:52 schwarze Exp $
+.\"
+.\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
+.\" Copyright (c) 2010, 2011, 2013, 2014 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
@@ -11,17 +15,11 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.\"
-.\" Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
-.\" Copyright 2012 Nexenta Systems, Inc. All rights reserved.
-.\" Copyright 2014 Garrett D'Amore <garrett@damore.org>
-.\"
-.Dd Jul 13, 2014
+.Dd $Mdocdate: February 17 2015 $
.Dt MANDOC_ROFF 5
.Os
.Sh NAME
-.Nm mandoc_roff
+.Nm roff
.Nd roff language reference for mandoc
.Sh DESCRIPTION
The
@@ -34,7 +32,7 @@ and
manual formatting languages are based on it,
many real-world manuals use small numbers of
.Nm
-requests intermixed with their
+requests and escape sequences intermixed with their
.Xr mdoc 5
or
.Xr man 5
@@ -43,8 +41,8 @@ To properly format such manuals, the
.Xr mandoc 1
utility supports a tiny subset of
.Nm
-requests.
-Only these requests supported by
+requests and escapes.
+Only these requests and escapes supported by
.Xr mandoc 1
are documented in the present manual,
together with the basic language syntax shared by
@@ -82,12 +80,12 @@ Lines not beginning with control characters are called
They provide free-form text to be printed; the formatting of the text
depends on the respective processing context.
.Sh LANGUAGE SYNTAX
-.Nm
+.Nm roff
documents may contain only graphable 7-bit ASCII characters, the space
character, and, in certain circumstances, the tab character.
-The back-space character
+The backslash character
.Sq \e
-indicates the start of an escape sequence for
+indicates the start of an escape sequence, used for example for
.Sx Comments ,
.Sx Special Characters ,
.Sx Predefined Strings ,
@@ -95,6 +93,9 @@ and
user-defined strings defined using the
.Sx ds
request.
+For a listing of escape sequences, consult the
+.Sx ESCAPE SEQUENCE REFERENCE
+below.
.Ss Comments
Text following an escaped double-quote
.Sq \e\(dq ,
@@ -148,12 +149,19 @@ respectively) may be used instead.
The indicator or numerical representative may be preceded by C
(constant-width), which is ignored.
.Pp
+The two-character indicator
+.Sq BI
+requests a font that is both bold and italic.
+It may not be portable to old roff implementations.
+.Pp
Examples:
.Bl -tag -width Ds -offset indent -compact
.It Li \efBbold\efR
-Write in bold, then switch to regular font mode.
+Write in \fBbold\fP, then switch to regular font mode.
.It Li \efIitalic\efP
-Write in italic, then return to previous font mode.
+Write in \fIitalic\fP, then return to previous font mode.
+.It Li \ef(BIbold italic\efP
+Write in \f(BIbold italic\fP, then return to previous font mode.
.El
.Pp
Text decoration is
@@ -231,8 +239,9 @@ pica (~1/6 inch)
.It p
point (~1/72 inch)
.It f
-synonym for
+scale
.Sq u
+by 65536
.It v
default vertical span
.It m
@@ -246,7 +255,7 @@ width of rendered
.Pq en
character
.It u
-default horizontal span
+default horizontal span for the terminal
.It M
mini-em (~1/100 em)
.El
@@ -254,7 +263,6 @@ mini-em (~1/100 em)
Using anything other than
.Sq m ,
.Sq n ,
-.Sq u ,
or
.Sq v
is necessarily non-portable across output media.
@@ -387,38 +395,199 @@ The
.Xr mandoc 1
.Nm
parser recognises the following requests.
-Note that the
-.Nm
-language defines many more requests not implemented in
-.Xr mandoc 1 .
+For requests marked as "ignored" or "unsupported", any arguments are
+ignored, and the number of arguments is not checked.
+.Ss \&ab
+Abort processing.
+Currently unsupported.
.Ss \&ad
Set line adjustment mode.
-This line-scoped request is intended to have one argument to select
-normal, left, right, or centre adjustment for subsequent text.
-Currently, it is ignored including its arguments,
-and the number of arguments is not checked.
+It takes one argument to select normal, left, right,
+or center adjustment for subsequent text.
+Currently ignored.
+.Ss \&af
+Assign an output format to a number register.
+Currently ignored.
+.Ss \&aln
+Create an alias for a number register.
+Currently unsupported.
+.Ss \&als
+Create an alias for a request, string, macro, or diversion.
+Currently unsupported.
.Ss \&am
Append to a macro definition.
The syntax of this request is the same as that of
.Sx \&de .
-It is currently ignored by
-.Xr mandoc 1 ,
-as are its children.
-.Ss \&ami
-Append to a macro definition, specifying the macro name indirectly.
-The syntax of this request is the same as that of
-.Sx \&dei .
-It is currently ignored by
-.Xr mandoc 1 ,
-as are its children.
.Ss \&am1
Append to a macro definition, switching roff compatibility mode off
-during macro execution.
+during macro execution (groff extension).
The syntax of this request is the same as that of
.Sx \&de1 .
-It is currently ignored by
-.Xr mandoc 1 ,
-as are its children.
+Since
+.Xr mandoc 1
+does not implement
+.Nm
+compatibility mode at all, it handles this request as an alias for
+.Sx \&am .
+.Ss \&ami
+Append to a macro definition, specifying the macro name indirectly
+(groff extension).
+The syntax of this request is the same as that of
+.Sx \&dei .
+.Ss \&ami1
+Append to a macro definition, specifying the macro name indirectly
+and switching roff compatibility mode off during macro execution
+(groff extension).
+The syntax of this request is the same as that of
+.Sx \&dei1 .
+Since
+.Xr mandoc 1
+does not implement
+.Nm
+compatibility mode at all, it handles this request as an alias for
+.Sx \&ami .
+.Ss \&as
+Append to a user-defined string.
+The syntax of this request is the same as that of
+.Sx \&ds .
+If a user-defined string with the specified name does not yet exist,
+it is set to the empty string before appending.
+.Ss \&as1
+Append to a user-defined string, switching roff compatibility mode off
+during macro execution (groff extension).
+The syntax of this request is the same as that of
+.Sx \&ds1 .
+Since
+.Xr mandoc 1
+does not implement
+.Nm
+compatibility mode at all, it handles this request as an alias for
+.Sx \&as .
+.Ss \&asciify
+Fully unformat a diversion.
+Currently unsupported.
+.Ss \&backtrace
+Print a backtrace of the input stack.
+This is a groff extension and currently ignored.
+.Ss \&bd
+Artificially embolden by repeated printing with small shifts.
+Currently ignored.
+.Ss \&bleedat
+Set the BleedBox page parameter for PDF generation.
+This is a Heirloom extension and currently ignored.
+.Ss \&blm
+Set a blank line trap.
+Currently unsupported.
+.Ss \&box
+Begin a diversion without including a partially filled line.
+Currently unsupported.
+.Ss \&boxa
+Add to a diversion without including a partially filled line.
+Currently unsupported.
+.Ss \&bp
+Begin new page.
+Currently ignored.
+.Ss \&BP
+Define a frame and place a picture in it.
+This is a Heirloom extension and currently unsupported.
+.Ss \&br
+Break the output line.
+See
+.Xr man 5
+and
+.Xr mdoc 5 .
+.Ss \&break
+Break out of a
+.Sx \&while
+loop.
+Currently unsupported.
+.Ss \&breakchar
+Optional line break characters.
+This is a Heirloom extension and currently ignored.
+.Ss \&brnl
+Break output line after next N input lines.
+This is a Heirloom extension and currently ignored.
+.Ss \&brp
+Break and spread output line.
+Currently, this is implemented as an alias for
+.Sx \&br .
+.Ss \&brpnl
+Break and spread output line after next N input lines.
+This is a Heirloom extension and currently ignored.
+.Ss \&c2
+Change the no-break control character.
+Currently unsupported.
+.Ss \&cc
+Change the control character.
+Its syntax is as follows:
+.Bd -literal -offset indent
+.Pf . Cm \&cc Op Ar c
+.Ed
+.Pp
+If
+.Ar c
+is not specified, the control character is reset to
+.Sq \&. .
+Trailing characters are ignored.
+.Ss \&ce
+Center some lines.
+It takes one integer argument, specifying how many lines to center.
+Currently ignored.
+.Ss \&cf
+Output the contents of a file.
+Ignored because insecure.
+.Ss \&cflags
+Set character flags.
+This is a groff extension and currently ignored.
+.Ss \&ch
+Change a trap location.
+Currently ignored.
+.Ss \&char
+Define a new glyph.
+Currently unsupported.
+.Ss \&chop
+Remove the last character from a macro, string, or diversion.
+Currently unsupported.
+.Ss \&class
+Define a character class.
+This is a groff extension and currently ignored.
+.Ss \&close
+Close an open file.
+Ignored because insecure.
+.Ss \&CL
+Print text in color.
+This is a Heirloom extension and currently unsupported.
+.Ss \&color
+Activate or deactivate colors.
+This is a groff extension and currently ignored.
+.Ss \&composite
+Define a name component for composite glyph names.
+This is a groff extension and currently unsupported.
+.Ss \&continue
+Immediately start the next iteration of a
+.Sx \&while
+loop.
+Currently unsupported.
+.Ss \&cp
+Switch
+.Nm
+compatibility mode on or off.
+Currently ignored.
+.Ss \&cropat
+Set the CropBox page parameter for PDF generation.
+This is a Heirloom extension and currently ignored.
+.Ss \&cs
+Constant character spacing mode.
+Currently ignored.
+.Ss \&cu
+Underline including whitespace.
+Currently ignored.
+.Ss \&da
+Append to a diversion.
+Currently unsupported.
+.Ss \&dch
+Change a trap location in the current diversion.
+This is a Heirloom extension and currently unsupported.
.Ss \&de
Define a
.Nm
@@ -514,32 +683,66 @@ one explicit newline character.
In order to prevent endless recursion, both groff and
.Xr mandoc 1
limit the stack depth for expanding macros and strings
-to a large, but finite number.
-Do not rely on the exact value of this limit.
+to a large, but finite number, and
+.Xr mandoc 1
+also limits the length of the expanded input line.
+Do not rely on the exact values of these limits.
+.Ss \&de1
+Define a
+.Nm
+macro that will be executed with
+.Nm
+compatibility mode switched off during macro execution.
+This is a groff extension.
+Since
+.Xr mandoc 1
+does not implement
+.Nm
+compatibility mode at all, it handles this request as an alias for
+.Sx \&de .
+.Ss \&defcolor
+Define a color name.
+This is a groff extension and currently ignored.
.Ss \&dei
Define a
.Nm
-macro, specifying the macro name indirectly.
+macro, specifying the macro name indirectly (groff extension).
The syntax of this request is the same as that of
.Sx \&de .
-It is currently ignored by
-.Xr mandoc 1 ,
-as are its children.
-.Ss \&de1
+The request
+.Pp
+.D1 Pf . Cm \&dei Ar name Op Ar end
+.Pp
+has the same effect as:
+.Pp
+.D1 Pf . Cm \&de No \e* Ns Bo Ar name Bc Op \e* Ns Bq Ar end
+.Ss \&dei1
Define a
.Nm
macro that will be executed with
.Nm
-compatibility mode switched off during macro execution.
-This is a GNU extension not available in traditional
-.Nm
-implementations and not even in older versions of groff.
+compatibility mode switched off during macro execution,
+specifying the macro name indirectly (groff extension).
Since
.Xr mandoc 1
does not implement
.Nm
compatibility mode at all, it handles this request as an alias for
-.Sx \&de .
+.Sx \&dei .
+.Ss \&device
+This request only makes sense with the groff-specific intermediate
+output format and is unsupported.
+.Ss \&devicem
+This request only makes sense with the groff-specific intermediate
+output format and is unsupported.
+.Ss \&di
+Begin a diversion.
+Currently unsupported.
+.Ss \&do
+Execute
+.Nm
+request or macro line with compatibility mode disabled.
+Currently unsupported.
.Ss \&ds
Define a user-defined string.
Its syntax is as follows:
@@ -598,6 +801,32 @@ macro when used in a
.Xr man 5
document.
Such abuse is of course strongly discouraged.
+.Ss \&ds1
+Define a user-defined string that will be expanded with
+.Nm
+compatibility mode switched off during string expansion.
+This is a groff extension.
+Since
+.Xr mandoc 1
+does not implement
+.Nm
+compatibility mode at all, it handles this request as an alias for
+.Sx \&ds .
+.Ss \&dwh
+Set a location trap in the current diversion.
+This is a Heirloom extension and currently unsupported.
+.Ss \&dt
+Set a trap within a diversion.
+Currently unsupported.
+.Ss \&ec
+Change the escape character.
+Currently unsupported.
+.Ss \&ecs
+Restore the escape character.
+Currently unsupported.
+.Ss \&ecr
+Save the escape character.
+Currently unsupported.
.Ss \&el
The
.Qq else
@@ -612,18 +841,171 @@ then false is assumed.
The syntax of this request is similar to
.Sx \&if
except that the conditional is missing.
+.Ss \&em
+Set a trap at the end of input.
+Currently unsupported.
.Ss \&EN
End an equation block.
See
.Sx \&EQ .
+.Ss \&eo
+Disable the escape mechanism completely.
+Currently unsupported.
+.Ss \&EP
+End a picture started by
+.Sx \&BP .
+This is a Heirloom extension and currently unsupported.
.Ss \&EQ
Begin an equation block.
See
.Xr eqn 5
for a description of the equation language.
+.Ss \&errprint
+Print a string like an error message.
+This is a Heirloom extension and currently ignored.
+.Ss \&ev
+Switch to another environment.
+Currently unsupported.
+.Ss \&evc
+Copy an environment into the current environment.
+Currently unsupported.
+.Ss \&ex
+Abort processing and exit.
+Currently unsupported.
+.Ss \&fallback
+Select the fallback sequence for a font.
+This is a Heirloom extension and currently ignored.
+.Ss \&fam
+Change the font family.
+Takes one argument specifying the font family to be selected.
+It is a groff extension and currently ignored.
+.Ss \&fc
+Define a delimiting and a padding character for fields.
+Currently unsupported.
+.Ss \&fchar
+Define a fallback glyph.
+Currently unsupported.
+.Ss \&fcolor
+Set the fill color for \eD objects.
+This is a groff extension and currently ignored.
+.Ss \&fdeferlig
+Defer ligature building.
+This is a Heirloom extension and currently ignored.
+.Ss \&feature
+Enable or disable an OpenType feature.
+This is a Heirloom extension and currently ignored.
+.Ss \&fi
+Switch to fill mode.
+See
+.Xr man 5 .
+Ignored in
+.Xr mdoc 5 .
+.Ss \&fkern
+Control the use of kerning tables for a font.
+This is a Heirloom extension and currently ignored.
+.Ss \&fl
+Flush output.
+Currently ignored.
+.Ss \&flig
+Define ligatures.
+This is a Heirloom extension and currently ignored.
+.Ss \&fp
+Assign font position.
+Currently ignored.
+.Ss \&fps
+Mount a font with a special character map.
+This is a Heirloom extension and currently ignored.
+.Ss \&fschar
+Define a font-specific fallback glyph.
+This is a groff extension and currently unsupported.
+.Ss \&fspacewidth
+Set a font-specific width for the space character.
+This is a Heirloom extension and currently ignored.
+.Ss \&fspecial
+Conditionally define a special font.
+This is a groff extension and currently ignored.
+.Ss \&ft
+Change the font.
+Its syntax is as follows:
+.Pp
+.D1 Pf . Cm \&ft Op Ar font
+.Pp
+The following
+.Ar font
+arguments are supported:
+.Bl -tag -width 4n -offset indent
+.It Cm B , BI , 3 , 4
+switches to
+.Sy bold
+font
+.It Cm I , 2
+switches to
+.Em underlined
+font
+.It Cm R , CW , 1
+switches to normal font
+.It Cm P No "or no argument"
+switches back to the previous font
+.El
+.Pp
+This request takes effect only locally, may be overridden by macros
+and escape sequences, and is only supported in
+.Xr man 5
+for now.
+.Ss \&ftr
+Translate font name.
+This is a groff extension and currently ignored.
+.Ss \&fzoom
+Zoom font size.
+Currently ignored.
+.Ss \&gcolor
+Set glyph color.
+This is a groff extension and currently ignored.
+.Ss \&hc
+Set the hyphenation character.
+Currently ignored.
+.Ss \&hcode
+Set hyphenation codes of characters.
+Currently ignored.
+.Ss \&hidechar
+Hide characters in a font.
+This is a Heirloom extension and currently ignored.
+.Ss \&hla
+Set hyphenation language.
+This is a groff extension and currently ignored.
+.Ss \&hlm
+Set maximum number of consecutive hyphenated lines.
+Currently ignored.
+.Ss \&hpf
+Load hyphenation pattern file.
+This is a groff extension and currently ignored.
+.Ss \&hpfa
+Load hyphenation pattern file, appending to the current patterns.
+This is a groff extension and currently ignored.
+.Ss \&hpfcode
+Define mapping values for character codes in hyphenation patterns.
+This is a groff extension and currently ignored.
+.Ss \&hw
+Specify hyphenation points in words.
+Currently ignored.
.Ss \&hy
Set automatic hyphenation mode.
-This line-scoped request is currently ignored.
+Currently ignored.
+.Ss \&hylang
+Set hyphenation language.
+This is a Heirloom extension and currently ignored.
+.Ss \&hylen
+Minimum word length for hyphenation.
+This is a Heirloom extension and currently ignored.
+.Ss \&hym
+Set hyphenation margin.
+This is a groff extension and currently ignored.
+.Ss \&hypp
+Define hyphenation penalties.
+This is a Heirloom extension and currently ignored.
+.Ss \&hys
+Set hyphenation space.
+This is a groff extension and currently ignored.
.Ss \&ie
The
.Qq if
@@ -636,10 +1018,69 @@ Its syntax is equivalent to
.Sx \&if .
.Ss \&if
Begins a conditional.
-Right now, the conditional evaluates to true
-if and only if it starts with the letter
-.Sy n ,
-indicating processing in nroff style as opposed to troff style.
+This request has the following syntax:
+.Bd -literal -offset indent
+\&.if COND BODY
+.Ed
+.Bd -literal -offset indent
+\&.if COND \e{BODY
+BODY...\e}
+.Ed
+.Bd -literal -offset indent
+\&.if COND \e{\e
+BODY...
+\&.\e}
+.Ed
+.Pp
+COND is a conditional statement.
+Currently,
+.Xr mandoc 1
+supports the following subset of roff conditionals:
+.Bl -bullet
+.It
+If
+.Sq \&!
+is prefixed to COND, the condition is logically inverted.
+.It
+If the first character of COND is
+.Sq n
+.Pq nroff mode
+or
+.Sq o
+.Pq odd page ,
+COND evaluates to true.
+.It
+If the first character of COND is
+.Sq c
+.Pq character available ,
+.Sq d
+.Pq string defined ,
+.Sq e
+.Pq even page ,
+.Sq r
+.Pq register accessed ,
+.Sq t
+.Pq troff mode ,
+or
+.Sq v
+.Pq vroff mode ,
+COND evaluates to false.
+.It
+If COND starts with a parenthesis or with an optionally signed
+integer number, it is evaluated according to the rules of
+.Sx Numerical expressions
+explained below.
+It evaluates to true if the result is positive,
+or to false if the result is zero or negative.
+.It
+Otherwise, the first character of COND is regarded as a delimiter
+and COND evaluates to true if the string extending from its first
+to its second occurrence is equal to the string extending from its
+second to its third occurrence.
+.It
+If COND cannot be parsed, it evaluates to false.
+.El
+.Pp
If a conditional is false, its children are not processed, but are
syntactically interpreted to preserve the integrity of the input
document.
@@ -657,44 +1098,12 @@ will continue to syntactically interpret to the block close of the final
conditional.
Sub-conditionals, in this case, obviously inherit the truth value of
the parent.
-This request has the following syntax:
-.Bd -literal -offset indent
-\&.if COND \e{\e
-BODY...
-\&.\e}
-.Ed
-.Bd -literal -offset indent
-\&.if COND \e{ BODY
-BODY... \e}
-.Ed
-.Bd -literal -offset indent
-\&.if COND \e{ BODY
-BODY...
-\&.\e}
-.Ed
-.Bd -literal -offset indent
-\&.if COND \e
-BODY
-.Ed
-.Pp
-COND is a conditional statement.
-roff allows for complicated conditionals; mandoc is much simpler.
-At this time, mandoc supports only
-.Sq n ,
-evaluating to true;
-and
-.Sq t ,
-.Sq e ,
-and
-.Sq o ,
-evaluating to false.
-All other invocations are read up to the next end of line or space and
-evaluate as false.
.Pp
If the BODY section is begun by an escaped brace
.Sq \e{ ,
-scope continues until a closing-brace escape sequence
-.Sq \.\e} .
+scope continues until the end of the input line containing the
+matching closing-brace escape sequence
+.Sq \e} .
If the BODY is not enclosed in braces, scope continues until
the end of the line.
If the COND is followed by a BODY on the same line, whether after a
@@ -774,33 +1183,181 @@ Otherwise, it only terminates the
and arguments following it or the
.Sq \&..
request are discarded.
+.Ss \&in
+Change indentation.
+See
+.Xr man 5 .
+Ignored in
+.Xr mdoc 5 .
+.Ss \&index
+Find a substring in a string.
+This is a Heirloom extension and currently unsupported.
+.Ss \&it
+Set an input line trap.
+Its syntax is as follows:
+.Pp
+.D1 Pf . Cm it Ar expression macro
+.Pp
+The named
+.Ar macro
+will be invoked after processing the number of input text lines
+specified by the numerical
+.Ar expression .
+While evaluating the
+.Ar expression ,
+the unit suffixes described below
+.Sx Scaling Widths
+are ignored.
+.Ss \&itc
+Set an input line trap, not counting lines ending with \ec.
+Currently unsupported.
+.Ss \&IX
+To support the generation of a table of contents,
+.Xr pod2man 1
+emits this user-defined macro, usually without defining it.
+To avoid reporting large numbers of spurious errors,
+.Xr mandoc 1
+ignores it.
+.Ss \&kern
+Switch kerning on or off.
+Currently ignored.
+.Ss \&kernafter
+Increase kerning after some characters.
+This is a Heirloom extension and currently ignored.
+.Ss \&kernbefore
+Increase kerning before some characters.
+This is a Heirloom extension and currently ignored.
+.Ss \&kernpair
+Add a kerning pair to the kerning table.
+This is a Heirloom extension and currently ignored.
+.Ss \&lc
+Define a leader repetition character.
+Currently unsupported.
+.Ss \&lc_ctype
+Set the
+.Dv LC_CTYPE
+locale.
+This is a Heirloom extension and currently unsupported.
+.Ss \&lds
+Define a local string.
+This is a Heirloom extension and currently unsupported.
+.Ss \&length
+Count the number of input characters in a user-defined string.
+Currently unsupported.
+.Ss \&letadj
+Dynamic letter spacing and reshaping.
+This is a Heirloom extension and currently ignored.
+.Ss \&lf
+Change the line number for error messages.
+Ignored because insecure.
+.Ss \&lg
+Switch the ligature mechanism on or off.
+Currently ignored.
+.Ss \&lhang
+Hang characters at left margin.
+This is a Heirloom extension and currently ignored.
+.Ss \&linetabs
+Enable or disable line-tabs mode.
+This is a groff extension and currently unsupported.
+.Ss \&ll
+Change the output line length.
+Its syntax is as follows:
+.Pp
+.D1 Pf . Cm \&ll Op Oo +|- Oc Ns Ar width
+.Pp
+If the
+.Ar width
+argument is omitted, the line length is reset to its previous value.
+The default setting for terminal output is 58n.
+If a sign is given, the line length is added to or subtracted from;
+otherwise, it is set to the provided value.
+Using this request in new manuals is discouraged for several reasons,
+among others because it overrides the
+.Xr mandoc 1
+.Fl O Cm width
+command line option.
+.Ss \&lnr
+Set local number register.
+This is a Heirloom extension and currently unsupported.
+.Ss \&lnrf
+Set local floating-point register.
+This is a Heirloom extension and currently unsupported.
+.Ss \&lpfx
+Set a line prefix.
+This is a Heirloom extension and currently unsupported.
+.Ss \&ls
+Set line spacing.
+It takes one integer argument specifying the vertical distance of
+subsequent output text lines measured in v units.
+Currently ignored.
+.Ss \&lsm
+Set a leading spaces trap.
+This is a groff extension and currently unsupported.
+.Ss \&lt
+Set title line length.
+Currently ignored.
+.Ss \&mc
+Print margin character in the right margin.
+Currently ignored.
+.Ss \&mediasize
+Set the device media size.
+This is a Heirloom extension and currently ignored.
+.Ss \&minss
+Set minimum word space.
+This is a Heirloom extension and currently ignored.
+.Ss \&mk
+Mark vertical position.
+Currently ignored.
+.Ss \&mso
+Load a macro file.
+Ignored because insecure.
+.Ss \&na
+Disable adjusting without changing the adjustment mode.
+Currently ignored.
.Ss \&ne
Declare the need for the specified minimum vertical space
before the next trap or the bottom of the page.
-This line-scoped request is currently ignored.
+Currently ignored.
+.Ss \&nf
+Switch to no-fill mode.
+See
+.Xr man 5 .
+Ignored by
+.Xr mdoc 5 .
.Ss \&nh
Turn off automatic hyphenation mode.
-This line-scoped request is currently ignored.
-.Ss \&rm
-Remove a request, macro or string.
-This request is intended to have one argument,
-the name of the request, macro or string to be undefined.
-Currently, it is ignored including its arguments,
-and the number of arguments is not checked.
+Currently ignored.
+.Ss \&nhychar
+Define hyphenation-inhibiting characters.
+This is a Heirloom extension and currently ignored.
+.Ss \&nm
+Print line numbers.
+Currently unsupported.
+.Ss \&nn
+Temporarily turn off line numbering.
+Currently unsupported.
+.Ss \&nop
+Exexute the rest of the input line as a request or macro line.
+Currently unsupported.
.Ss \&nr
-Define a register.
+Define or change a register.
A register is an arbitrary string value that defines some sort of state,
which influences parsing and/or formatting.
Its syntax is as follows:
.Pp
-.D1 Pf \. Cm \&nr Ar name Ar value
+.D1 Pf \. Cm \&nr Ar name Oo +|- Oc Ns Ar expression
.Pp
-The
-.Ar value
-may, at the moment, only be an integer.
-So far, only the following register
+For the syntax of
+.Ar expression ,
+see
+.Sx Numerical expressions
+below.
+If it is prefixed by a sign, the register will be
+incremented or decremented instead of assigned to.
+.Pp
+The following register
.Ar name
-is recognised:
+is handled specially:
.Bl -tag -width Ds
.It Cm nS
If set to a positive integer value, certain
@@ -819,16 +1376,142 @@ section with the
.Cm \&Sh
macro will reset this register.
.El
+.Ss \&nrf
+Define or change a floating-point register.
+This is a Heirloom extension and currently unsupported.
+.Ss \&nroff
+Force nroff mode.
+This is a groff extension and currently ignored.
.Ss \&ns
Turn on no-space mode.
-This line-scoped request is intended to take no arguments.
-Currently, it is ignored including its arguments,
-and the number of arguments is not checked.
+Currently ignored.
+.Ss \&nx
+Abort processing of the current input file and process another one.
+Ignored because insecure.
+.Ss \&open
+Open a file for writing.
+Ignored because insecure.
+.Ss \&opena
+Open a file for appending.
+Ignored because insecure.
+.Ss \&os
+Output saved vertical space.
+Currently ignored.
+.Ss \&output
+Output directly to intermediate output.
+Not supported.
+.Ss \&padj
+Globally control paragraph-at-once adjustment.
+This is a Heirloom extension and currently ignored.
+.Ss \&papersize
+Set the paper size.
+This is a Heirloom extension and currently ignored.
+.Ss \&pc
+Change the page number character.
+Currently ignored.
+.Ss \&pev
+Print environments.
+This is a groff extension and currently ignored.
+.Ss \&pi
+Pipe output to a shell command.
+Ignored because insecure.
+.Ss \&PI
+Low-level request used by
+.Sx \&BP .
+This is a Heirloom extension and currently unsupported.
+.Ss \&pl
+Change page length.
+Takes one height argument.
+Currently ignored.
+.Ss \&pm
+Print names and sizes of macros, strings, and diversions.
+Currently ignored.
+.Ss \&pn
+Change page number of the next page.
+Currently ignored.
+.Ss \&pnr
+Print all number registers.
+Currently ignored.
+.Ss \&po
+Set horizontal page offset.
+Currently ignored.
.Ss \&ps
Change point size.
-This line-scoped request is intended to take one numerical argument.
-Currently, it is ignored including its arguments,
-and the number of arguments is not checked.
+Takes one numerical argument.
+Currently ignored.
+.Ss \&psbb
+Retrieve the bounding box of a PostScript file.
+Currently unsupported.
+.Ss \&pshape
+Set a special shape for the current paragraph.
+This is a Heirloom extension and currently unsupported.
+.Ss \&pso
+Include output of a shell command.
+Ignored because insecure.
+.Ss \&ptr
+Print the names and positions of all traps.
+This is a groff extension and currently ignored.
+.Ss \&pvs
+Change post-vertical spacing.
+This is a groff extension and currently ignored.
+.Ss \&rchar
+Remove glyph definitions.
+Currently unsupported.
+.Ss \&rd
+Read from standard input.
+Currently ignored.
+.Ss \&recursionlimit
+Set the maximum stack depth for recursive macros.
+This is a Heirloom extension and currently ignored.
+.Ss \&return
+Exit a macro and return to the caller.
+Currently unsupported.
+.Ss \&rfschar
+Remove font-specific fallback glyph definitions.
+Currently unsupported.
+.Ss \&rhang
+Hang characters at right margin.
+This is a Heirloom extension and currently ignored.
+.Ss \&rj
+Justify unfilled text to the right margin.
+Currently ignored.
+.Ss \&rm
+Remove a request, macro or string.
+Its syntax is as follows:
+.Pp
+.D1 Pf \. Cm \&rm Ar name
+.Ss \&rn
+Rename a request, macro, diversion, or string.
+Currently unsupported.
+.Ss \&rnn
+Rename a number register.
+Currently unsupported.
+.Ss \&rr
+Remove a register.
+Its syntax is as follows:
+.Pp
+.D1 Pf \. Cm \&rr Ar name
+.Ss \&rs
+End no-space mode.
+Currently ignored.
+.Ss \&rt
+Return to marked vertical position.
+Currently ignored.
+.Ss \&schar
+Define global fallback glyph.
+This is a groff extension and currently unsupported.
+.Ss \&sentchar
+Define sentence-ending characters.
+This is a Heirloom extension and currently ignored.
+.Ss \&shc
+Change the soft hyphen character.
+Currently ignored.
+.Ss \&shift
+Shift macro arguments.
+Currently unsupported.
+.Ss \&sizes
+Define permissible point sizes.
+This is a groff extension and currently ignored.
.Ss \&so
Include a source file.
Its syntax is as follows:
@@ -862,10 +1545,64 @@ is discouraged.
Use
.Xr ln 1
instead.
+.Ss \&spacewidth
+Set the space width from the font metrics file.
+This is a Heirloom extension and currently ignored.
+.Ss \&special
+Define a special font.
+This is a groff extension and currently ignored.
+.Ss \&spreadwarn
+Warn about wide spacing between words.
+Currently ignored.
+.Ss \&ss
+Set space character size.
+Currently ignored.
+.Ss \&sty
+Associate style with a font position.
+This is a groff extension and currently ignored.
+.Ss \&substring
+Replace a user-defined string with a substring.
+Currently unsupported.
+.Ss \&sv
+Save vertical space.
+Currently ignored.
+.Ss \&sy
+Execute shell command.
+Ignored because insecure.
+.Ss \&T&
+Re-start a table layout, retaining the options of the prior table
+invocation.
+See
+.Sx \&TS .
.Ss \&ta
Set tab stops.
-This line-scoped request can take an arbitrary number of arguments.
-Currently, it is ignored including its arguments.
+Takes an arbitrary number of arguments.
+Currently unsupported.
+.Ss \&tc
+Change tab repetion character.
+Currently unsupported.
+.Ss \&TE
+End a table context.
+See
+.Sx \&TS .
+.Ss \&ti
+Temporary indent.
+Currently unsupported.
+.Ss \&tkf
+Enable track kerning for a font.
+Currently ignored.
+.Ss \&tl
+Print a title line.
+Currently unsupported.
+.Ss \&tm
+Print to standard error output.
+Currently ignored.
+.Ss \&tm1
+Print to standard error output, allowing leading blanks.
+This is a groff extension and currently ignored.
+.Ss \&tmc
+Print to standard error output without a trailing newline.
+This is a groff extension and currently ignored.
.Ss \&tr
Output character translation.
Its syntax is as follows:
@@ -883,59 +1620,479 @@ Replacement (or origin) characters may also be character escapes; thus,
.Dl tr \e(xx\e(yy
.Pp
replaces all invocations of \e(xx with \e(yy.
-.Ss \&T&
-Re-start a table layout, retaining the options of the prior table
-invocation.
-See
-.Sx \&TS .
-.Ss \&TE
-End a table context.
-See
-.Sx \&TS .
+.Ss \&track
+Static letter space tracking.
+This is a Heirloom extension and currently ignored.
+.Ss \&transchar
+Define transparent characters for sentence-ending.
+This is a Heirloom extension and currently ignored.
+.Ss \&trf
+Output the contents of a file, disallowing invalid characters.
+This is a groff extension and ignored because insecure.
+.Ss \&trimat
+Set the TrimBox page parameter for PDF generation.
+This is a Heirloom extension and currently ignored.
+.Ss \&trin
+Output character translation, ignored by
+.Cm \&asciify .
+Currently unsupported.
+.Ss \&trnt
+Output character translation, ignored by \e!.
+Currently unsupported.
+.Ss \&troff
+Force troff mode.
+This is a groff extension and currently ignored.
.Ss \&TS
Begin a table, which formats input in aligned rows and columns.
See
.Xr tbl 5
for a description of the tbl language.
+.Ss \&uf
+Globally set the underline font.
+Currently ignored.
+.Ss \&ul
+Underline.
+Currently ignored.
+.Ss \&unformat
+Unformat spaces and tabs in a diversion.
+Currently unsupported.
+.Ss \&unwatch
+Disable notification for string or macro.
+This is a Heirloom extension and currently ignored.
+.Ss \&unwatchn
+Disable notification for register.
+This is a Heirloom extension and currently ignored.
+.Ss \&vpt
+Enable or disable vertical position traps.
+This is a groff extension and currently ignored.
+.Ss \&vs
+Change vertical spacing.
+Currently ignored.
+.Ss \&warn
+Set warning level.
+Currently ignored.
+.Ss \&warnscale
+Set the scaling indicator used in warnings.
+This is a groff extension and currently ignored.
+.Ss \&watch
+Notify on change of string or macro.
+This is a Heirloom extension and currently ignored.
+.Ss \&watchlength
+On change, report the contents of macros and strings
+up to the sepcified length.
+This is a Heirloom extension and currently ignored.
+.Ss \&watchn
+Notify on change of register.
+This is a Heirloom extension and currently ignored.
+.Ss \&wh
+Set a page location trap.
+Currently unsupported.
+.Ss \&while
+Repeated execution while a condition is true.
+Currently unsupported.
+.Ss \&write
+Write to an open file.
+Ignored because insecure.
+.Ss \&writec
+Write to an open file without appending a newline.
+Ignored because insecure.
+.Ss \&writem
+Write macro or string to an open file.
+Ignored because insecure.
+.Ss \&xflag
+Set the extension level.
+This is a Heirloom extension and currently ignored.
+.Ss Numerical expressions
+The
+.Sx \&nr ,
+.Sx \&if ,
+and
+.Sx \&ie
+requests accept integer numerical expressions as arguments.
+These are always evaluated using the C
+.Vt int
+type; integer overflow works the same way as in the C language.
+Numbers consist of an arbitrary number of digits
+.Sq 0
+to
+.Sq 9
+prefixed by an optional sign
+.Sq +
+or
+.Sq - .
+Each number may be followed by one optional scaling unit described below
+.Sx Scaling Widths .
+The following equations hold:
+.Bd -literal -offset indent
+1i = 6v = 6P = 10m = 10n = 52p = 1000M = 240u = 240
+254c = 100i = 24000u = 24000
+1f = 65536u = 65536
+.Ed
+.Pp
+The following binary operators are implemented.
+Unless otherwise stated, they behave as in the C language:
+.Pp
+.Bl -tag -width 2n -compact
+.It Ic +
+addition
+.It Ic -
+subtraction
+.It Ic *
+multiplication
+.It Ic /
+division
+.It Ic %
+remainder of division
+.It Ic <
+less than
+.It Ic >
+greater than
+.It Ic ==
+equal to
+.It Ic =
+equal to, same effect as
+.Ic ==
+(this differs from C)
+.It Ic <=
+less than or equal to
+.It Ic >=
+greater than or equal to
+.It Ic <>
+not equal to (corresponds to C
+.Ic != ;
+this one is of limited portability, it is supported by Heirloom roff,
+but not by groff)
+.It Ic &
+logical and (corresponds to C
+.Ic && )
+.It Ic \&:
+logical or (corresponds to C
+.Ic \&|| )
+.It Ic <?
+minimum (not available in C)
+.It Ic >?
+maximum (not available in C)
+.El
+.Pp
+There is no concept of precendence; evaluation proceeds from left to right,
+except when subexpressions are enclosed in parantheses.
+Inside parentheses, whitespace is ignored.
+.Sh ESCAPE SEQUENCE REFERENCE
+The
+.Xr mandoc 1
+.Nm
+parser recognises the following escape sequences.
+Note that the
+.Nm
+language defines more escape sequences not implemented in
+.Xr mandoc 1 .
+In
+.Xr mdoc 5
+and
+.Xr man 5
+documents, using escape sequences is discouraged except for those
+described in the
+.Sx LANGUAGE SYNTAX
+section above.
+.Pp
+A backslash followed by any character not listed here
+simply prints that character itself.
+.Ss \e<newline>
+A backslash at the end of an input line can be used to continue the
+logical input line on the next physical input line, joining the text
+on both lines together as if it were on a single input line.
+.Ss \e<space>
+The escape sequence backslash-space
+.Pq Sq \e\ \&
+is an unpaddable space-sized non-breaking space character; see
+.Sx Whitespace .
+.Ss \e\(dq
+The rest of the input line is treated as
+.Sx Comments .
+.Ss \e%
+Hyphenation allowed at this point of the word; ignored by
+.Xr mandoc 1 .
+.Ss \e&
+Non-printing zero-width character; see
+.Sx Whitespace .
+.Ss \e\(aq
+Acute accent special character; use
+.Sq \e(aa
+instead.
+.Ss \e( Ns Ar cc
+.Sx Special Characters
+with two-letter names, see
+.Xr mandoc_char 5 .
+.Ss \e*[ Ns Ar name ]
+Interpolate the string with the
+.Ar name ;
+see
+.Sx Predefined Strings
+and
+.Sx ds .
+For short names, there are variants
+.No \e* Ns Ar c
+and
+.No \e*( Ns Ar cc .
+.Ss \e-
+Special character
+.Dq mathematical minus sign .
+.Ss \e[ Ns Ar name ]
+.Sx Special Characters
+with names of arbitrary length, see
+.Xr mandoc_char 5 .
+.Ss \e^
+One-twelfth em half-narrow space character, effectively zero-width in
+.Xr mandoc 1 .
+.Ss \e`
+Grave accent special character; use
+.Sq \e(ga
+instead.
+.Ss \e{
+Begin conditional input; see
+.Sx if .
+.Ss \e\(ba
+One-sixth em narrow space character, effectively zero-width in
+.Xr mandoc 1 .
+.Ss \e}
+End conditional input; see
+.Sx if .
+.Ss \e~
+Paddable non-breaking space character.
+.Ss \e0
+Digit width space character.
+.Ss \eA\(aq Ns Ar string Ns \(aq
+Anchor definition; ignored by
+.Xr mandoc 1 .
+.Ss \eB\(aq Ns Ar string Ns \(aq
+Interpolate
+.Sq 1
+if
+.Ar string
+conforms to the syntax of
+.Sx Numerical expressions
+explained above and
+.Sq 0
+otherwise.
+.Ss \eb\(aq Ns Ar string Ns \(aq
+Bracket building function; ignored by
+.Xr mandoc 1 .
+.Ss \eC\(aq Ns Ar name Ns \(aq
+.Sx Special Characters
+with names of arbitrary length.
+.Ss \ec
+When encountered at the end of an input text line,
+the next input text line is considered to continue that line,
+even if there are request or macro lines in between.
+No whitespace is inserted.
+.Ss \eD\(aq Ns Ar string Ns \(aq
+Draw graphics function; ignored by
+.Xr mandoc 1 .
+.Ss \ed
+Move down by half a line; ignored by
+.Xr mandoc 1 .
+.Ss \ee
+Backslash special character.
+.Ss \eF[ Ns Ar name ]
+Switch font family (groff extension); ignored by
+.Xr mandoc 1 .
+For short names, there are variants
+.No \eF Ns Ar c
+and
+.No \eF( Ns Ar cc .
+.Ss \ef[ Ns Ar name ]
+Switch to the font
+.Ar name ,
+see
+.Sx Text Decoration .
+For short names, there are variants
+.No \ef Ns Ar c
+and
+.No \ef( Ns Ar cc .
+.Ss \eg[ Ns Ar name ]
+Interpolate the format of a number register; ignored by
+.Xr mandoc 1 .
+For short names, there are variants
+.No \eg Ns Ar c
+and
+.No \eg( Ns Ar cc .
+.Ss \eH\(aq Ns Oo +|- Oc Ns Ar number Ns \(aq
+Set the height of the current font; ignored by
+.Xr mandoc 1 .
+.Ss \eh\(aq Ns Ar number Ns \(aq
+Horizontal motion; ignored by
+.Xr mandoc 1 .
+.Ss \ek[ Ns Ar name ]
+Mark horizontal input place in register; ignored by
+.Xr mandoc 1 .
+For short names, there are variants
+.No \ek Ns Ar c
+and
+.No \ek( Ns Ar cc .
+.Ss \eL\(aq Ns Ar number Ns Oo Ar c Oc Ns \(aq
+Vertical line drawing function; ignored by
+.Xr mandoc 1 .
+.Ss \el\(aq Ns Ar number Ns Oo Ar c Oc Ns \(aq
+Horizontal line drawing function; ignored by
+.Xr mandoc 1 .
+.Ss \eM[ Ns Ar name ]
+Set fill (background) color (groff extension); ignored by
+.Xr mandoc 1 .
+For short names, there are variants
+.No \eM Ns Ar c
+and
+.No \eM( Ns Ar cc .
+.Ss \em[ Ns Ar name ]
+Set glyph drawing color (groff extension); ignored by
+.Xr mandoc 1 .
+For short names, there are variants
+.No \em Ns Ar c
+and
+.No \em( Ns Ar cc .
+.Ss \eN\(aq Ns Ar number Ns \(aq
+Character
+.Ar number
+on the current font.
+.Ss \en[ Ns Ar name ]
+Interpolate the number register
+.Ar name .
+For short names, there are variants
+.No \en Ns Ar c
+and
+.No \en( Ns Ar cc .
+.Ss \eo\(aq Ns Ar string Ns \(aq
+Overstrike, writing all the characters contained in the
+.Ar string
+to the same output position.
+In terminal and HTML output modes,
+only the last one of the characters is visible.
+.Ss \eR\(aq Ns Ar name Oo +|- Oc Ns Ar number Ns \(aq
+Set number register; ignored by
+.Xr mandoc 1 .
+.Ss \eS\(aq Ns Ar number Ns \(aq
+Slant output; ignored by
+.Xr mandoc 1 .
+.Ss \es\(aq Ns Oo +|- Oc Ns Ar number Ns \(aq
+Change point size; ignored by
+.Xr mandoc 1 .
+Alternative forms
+.No \es Ns Oo +|- Oc Ns Ar n ,
+.No \es Ns Oo +|- Oc Ns \(aq Ns Ar number Ns \(aq ,
+.No \es Ns [ Oo +|- Oc Ns Ar number ] ,
+and
+.No \es Ns Oo +|- Oc Ns [ Ar number Ns ]
+are also parsed and ignored.
+.Ss \et
+Horizontal tab; ignored by
+.Xr mandoc 1 .
+.Ss \eu
+Move up by half a line; ignored by
+.Xr mandoc 1 .
+.Ss \eV[ Ns Ar name ]
+Interpolate an environment variable; ignored by
+.Xr mandoc 1 .
+For short names, there are variants
+.No \eV Ns Ar c
+and
+.No \eV( Ns Ar cc .
+.Ss \ev\(aq Ns Ar number Ns \(aq
+Vertical motion; ignored by
+.Xr mandoc 1 .
+.Ss \ew\(aq Ns Ar string Ns \(aq
+Interpolate the width of the
+.Ar string .
+The
+.Xr mandoc 1
+implementation assumes that after expansion of user-defined strings, the
+.Ar string
+only contains normal characters, no escape sequences, and that each
+character has a width of 24 basic units.
+.Ss \eX\(aq Ns Ar string Ns \(aq
+Output
+.Ar string
+as device control function; ignored in nroff mode and by
+.Xr mandoc 1 .
+.Ss \ex\(aq Ns Ar number Ns \(aq
+Extra line space function; ignored by
+.Xr mandoc 1 .
+.Ss \eY[ Ns Ar name ]
+Output a string as a device control function; ignored in nroff mode and by
+.Xr mandoc 1 .
+For short names, there are variants
+.No \eY Ns Ar c
+and
+.No \eY( Ns Ar cc .
+.Ss \eZ\(aq Ns Ar string Ns \(aq
+Print
+.Ar string
+with zero width and height; ignored by
+.Xr mandoc 1 .
+.Ss \ez
+Output the next character without advancing the cursor position;
+approximated in
+.Xr mandoc 1
+by simply skipping the next character.
.Sh COMPATIBILITY
-This section documents compatibility between mandoc and other other
+The
+.Xr mandoc 1
+implementation of the
.Nm
-implementations, at this time limited to GNU troff
-.Pq Qq groff .
-The term
-.Qq historic groff
-refers to groff version 1.15.
+language is intentionally incomplete.
+Unimplemented features include:
.Pp
.Bl -dash -compact
.It
-In mandoc, the
-.Sx \&EQ ,
-.Sx \&TE ,
-.Sx \&TS ,
-and
-.Sx \&T& ,
-macros are considered regular macros.
-In all other
-.Nm
-implementations, these are special macros that must be specified without
-spacing between the control character (which must be a period) and the
-macro name.
+For security reasons,
+.Xr mandoc 1
+never reads or writes external files except via
+.Sx \&so
+requests with safe relative paths.
+.It
+There is no automatic hyphenation, no adjustment to the right margin,
+and no centering; the output is always set flush-left.
+.It
+Support for setting tabulator positions
+and tabulator and leader characters is missing,
+and support for manually changing indentation is limited.
.It
The
-.Cm nS
-register is only compatible with OpenBSD's groff-1.15.
+.Sq u
+scaling unit is the default terminal unit.
+In traditional troff systems, this unit changes depending on the
+output media.
.It
-Historic groff did not accept white-space before a custom
-.Ar end
-macro for the
-.Sx \&ig
-request.
+Width measurements are implemented in a crude way
+and often yield wrong results.
+Explicit movement requests and escapes are ignored.
+.It
+There is no concept of output pages, no support for floats,
+graphics drawing, and picture inclusion;
+terminal output is always continuous.
+.It
+Requests regarding color, font families, and glyph manipulation
+are ignored.
+Font support is very limited.
+Kerning is not implemented, and no ligatures are produced.
.It
The
-.Sx \&if
-and family would print funny white-spaces with historic groff when
-using the next-line syntax.
+.Qq \(aq
+macro control character does not suppress output line breaks.
+.It
+Diversions are not implemented,
+and support for traps is very incomplete.
+.It
+While recursion is supported,
+.Sx \&while
+loops are not.
.El
+.Pp
+The special semantics of the
+.Cm nS
+number register is an idiosyncracy of
+.Ox
+manuals and not supported by other
+.Xr mdoc 5
+implementations.
.Sh SEE ALSO
.Xr mandoc 1 ,
.Xr eqn 5 ,
@@ -984,8 +2141,6 @@ In 1989, James Clarke re-implemented troff in C++, naming it groff.
This
.Nm
reference was written by
-.An Kristaps Dzonsons ,
-.Mt kristaps@bsd.lv ;
+.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv
and
-.An Ingo Schwarze ,
-.Mt schwarze@openbsd.org .
+.An Ingo Schwarze Aq Mt schwarze@openbsd.org .
diff --git a/usr/src/man/man5/mdoc.5 b/usr/src/man/man5/mdoc.5
index 901a2848cd..a981edd5ff 100644
--- a/usr/src/man/man5/mdoc.5
+++ b/usr/src/man/man5/mdoc.5
@@ -1,3 +1,7 @@
+.\" $Id: mdoc.7,v 1.252 2015/02/23 13:31:04 schwarze Exp $
+.\"
+.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+.\" Copyright (c) 2010, 2011, 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
@@ -12,12 +16,10 @@
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.\"
-.\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
-.\" Copyright 2012 Nexenta Systems, Inc. All rights reserved.
.\" Copyright 2014 Garrett D'Amore <garrett@dmaore.org>
+.\" Copyright 2015 Nexenta Systems, Inc. All rights reserved.
.\"
-.Dd Jul 19, 2014
+.Dd Oct 18, 2015
.Dt MDOC 5
.Os
.Sh NAME
@@ -73,17 +75,17 @@ Text lines are interpreted within the current state.
Many aspects of the basic syntax of the
.Nm
language are based on the
-.Xr roff 5
+.Xr mandoc_roff 5
language; see the
.Em LANGUAGE SYNTAX
and
.Em MACRO SYNTAX
sections in the
-.Xr roff 5
+.Xr mandoc_roff 5
manual for details, in particular regarding
comments, escape sequences, whitespace, and quoting.
However, using
-.Xr roff 5
+.Xr mandoc_roff 5
requests in
.Nm
documents is discouraged;
@@ -125,9 +127,9 @@ file for a utility
\&.Os
\&.Sh NAME
\&.Nm progname
-\&.Nd one line description
+\&.Nd one line about what it does
\&.\e\(dq .Sh LIBRARY
-\&.\e\(dq For sections 2, 3, & 9 only.
+\&.\e\(dq For sections 2, 3, and 9 only.
\&.Sh SYNOPSIS
\&.Nm progname
\&.Op Fl options
@@ -138,7 +140,9 @@ The
utility processes files ...
\&.\e\(dq .Sh IMPLEMENTATION NOTES
\&.\e\(dq .Sh RETURN VALUES
-\&.\e\(dq For sections 2, 3, & 9 only.
+\&.\e\(dq For sections 2, 3, and 9 only.
+\&.\e\(dq .Sh CONTEXT
+\&.\e\(dq For section 9 functions only.
\&.\e\(dq .Sh ENVIRONMENT
\&.\e\(dq For sections 1, 1M, and 5.
\&.\e\(dq .Sh FILES
@@ -147,13 +151,13 @@ utility processes files ...
\&.\e\(dq .Sh EXAMPLES
\&.\e\(dq .Sh DIAGNOSTICS
\&.\e\(dq .Sh ERRORS
-\&.\e\(dq For sections 2, 3, & 9 only.
+\&.\e\(dq For sections 2, 3, and 9 only.
\&.\e\(dq .Sh ARCHITECTURE
\&.\e\(dq .Sh CODE SET INDEPENDENCE
-\&.\e\(dq For sections 1, 1M, & 3 only.
+\&.\e\(dq For sections 1, 1M, and 3 only.
\&.\e\(dq .Sh INTERFACE STABILITY
\&.\e\(dq .Sh MT-LEVEL
-\&.\e\(dq For sections 2 & 3 only.
+\&.\e\(dq For sections 2 and 3 only.
\&.\e\(dq .Sh SECURITY
\&.\e\(dq .Sh SEE ALSO
\&.\e\(dq .Xr foobar 1
@@ -331,6 +335,9 @@ return values of functions in sections 2, 3, and 9.
.Pp
See
.Sx \&Rv .
+.It Em CONTEXT
+This section lists the contexts in which functions can be called in section 9.
+The contexts are user, kernel, or interrupt.
.It Em ENVIRONMENT
Lists the environment variables used by the utility,
and explains the syntax and semantics of their values.
@@ -495,7 +502,7 @@ Documents any security precautions that operators should consider.
References other manuals with related topics.
This section should exist for most manuals.
Cross-references should conventionally be ordered first by section, then
-alphabetically.
+alphabetically (ignoring case).
.Pp
References to other documentation concerning the topic of the manual page,
for example authoritative books or journal articles, may also be
@@ -538,7 +545,7 @@ in the alphabetical
.Ss Document preamble and NAME section macros
.Bl -column "Brq, Bro, Brc" description
.It Sx \&Dd Ta document date: Ar month day , year
-.It Sx \&Dt Ta document title: Ar TITLE SECTION Op Ar volume | arch
+.It Sx \&Dt Ta document title: Ar TITLE SECTION Op Ar arch
.It Sx \&Os Ta operating system version: Op Ar system Op Ar version
.It Sx \&Nm Ta document name (one argument)
.It Sx \&Nd Ta document description (one line)
@@ -559,6 +566,7 @@ in the alphabetical
.Op Fl compact
.It Sx \&D1 Ta indented display (one line)
.It Sx \&Dl Ta indented literal display (one line)
+.It Sx \&Ql Ta in-line literal display: Ql text
.It Sx \&Bl , \&El Ta list block:
.Fl Ar type
.Op Fl width Ar val
@@ -573,7 +581,7 @@ in the alphabetical
.It Sx \&Pf Ta prefix, no following horizontal space (one argument)
.It Sx \&Ns Ta roman font, no preceding horizontal space (no arguments)
.It Sx \&Ap Ta apostrophe without surrounding whitespace (no arguments)
-.It Sx \&Sm Ta switch horizontal spacing mode: Cm on | off
+.It Sx \&Sm Ta switch horizontal spacing mode: Op Cm on | off
.It Sx \&Bk , \&Ek Ta keep block: Fl words
.It Sx \&br Ta force output line break in text mode (no arguments)
.It Sx \&sp Ta force vertical space: Op Ar height
@@ -593,6 +601,7 @@ in the alphabetical
.Bl -column "Brq, Bro, Brc" description
.It Sx \&Lb Ta function library (one argument)
.It Sx \&In Ta include file (one argument)
+.It Sx \&Fd Ta other preprocessor directive (>0 arguments)
.It Sx \&Ft Ta function type (>0 arguments)
.It Sx \&Fo , \&Fc Ta function block: Ar funcname
.It Sx \&Fn Ta function name:
@@ -617,7 +626,6 @@ in the alphabetical
.It Sx \&Cd Ta kernel configuration declaration (>0 arguments)
.It Sx \&Ad Ta memory address (>0 arguments)
.It Sx \&Ms Ta mathematical symbol (>0 arguments)
-.It Sx \&Tn Ta tradename (>0 arguments)
.El
.Ss Physical markup
.Bl -column "Brq, Bro, Brc" description
@@ -633,7 +641,6 @@ in the alphabetical
.It Sx \&Dq , \&Do , \&Dc Ta enclose in typographic double quotes: Dq text
.It Sx \&Qq , \&Qo , \&Qc Ta enclose in typewriter double quotes: Qq text
.It Sx \&Sq , \&So , \&Sc Ta enclose in single quotes: Sq text
-.It Sx \&Ql Ta single-quoted literal text: Ql text
.It Sx \&Pq , \&Po , \&Pc Ta enclose in parentheses: Pq text
.It Sx \&Bq , \&Bo , \&Bc Ta enclose in square brackets: Bq text
.It Sx \&Brq , \&Bro , \&Brc Ta enclose in curly braces: Brq text
@@ -645,7 +652,6 @@ in the alphabetical
.It Sx \&Ex Fl std Ta standard command exit values: Op Ar utility ...
.It Sx \&Rv Fl std Ta standard function return values: Op Ar function ...
.It Sx \&St Ta reference to a standards document (one argument)
-.It Sx \&Ux Ta Ux
.It Sx \&At Ta At
.It Sx \&Bx Ta Bx
.It Sx \&Bsx Ta Bsx
@@ -773,7 +779,7 @@ for all other author listings.
.Pp
Examples:
.Dl \&.An -nosplit
-.Dl \&.An Kristaps Dzonsons \&Aq kristaps@bsd.lv
+.Dl \&.An Kristaps Dzonsons \&Aq \&Mt kristaps@bsd.lv
.Ss \&Ao
Begin a block enclosed by angle brackets.
Does not have any head arguments.
@@ -827,7 +833,9 @@ for fixed strings to be passed verbatim as arguments, use
or
.Sx \&Cm .
.Ss \&At
-Formats an AT&T version.
+Formats an
+.At
+version.
Accepts one optional argument:
.Pp
.Bl -tag -width "v[1-7] | 32vX" -offset indent -compact
@@ -854,9 +862,8 @@ See also
.Sx \&Dx ,
.Sx \&Fx ,
.Sx \&Nx ,
-.Sx \&Ox ,
and
-.Sx \&Ux .
+.Sx \&Ox .
.Ss \&Bc
Close a
.Sx \&Bo
@@ -882,7 +889,7 @@ The
must be one of the following:
.Bl -tag -width 13n -offset indent
.It Fl centered
-Produce one output line from each input line, and centre-justify each line.
+Produce one output line from each input line, and center-justify each line.
Using this display type is not recommended; many
.Nm
implementations render it poorly.
@@ -927,7 +934,7 @@ which has no effect;
.Cm right ,
which justifies to the right margin; or
.Cm center ,
-which aligns around an imagined centre axis.
+which aligns around an imagined center axis.
.It
A macro invocation, which selects a predefined width
associated with that macro.
@@ -936,8 +943,8 @@ The most popular is the imaginary macro
which resolves to
.Sy 6n .
.It
-A width using the syntax described in
-.Sx Scaling Widths .
+A scaling width as described in
+.Xr mandoc_roff 5 .
.It
An arbitrary string, which indents by the length of this string.
.El
@@ -1042,8 +1049,11 @@ The
.Fl width
and
.Fl offset
-arguments accept
-.Sx Scaling Widths
+arguments accept macro names as described for
+.Sx \&Bd
+.Fl offset ,
+scaling widths as described in
+.Xr mandoc_roff 5 ,
or use the length of the given string.
The
.Fl offset
@@ -1072,9 +1082,9 @@ A columnated list.
The
.Fl width
argument has no effect; instead, each argument specifies the width
-of one column, using either the
-.Sx Scaling Widths
-syntax or the string length of the argument.
+of one column, using either the scaling width syntax described in
+.Xr mandoc_roff 5
+or the string length of the argument.
If the first line of the body of a
.Fl column
list is not an
@@ -1205,7 +1215,9 @@ Examples:
See also
.Sx \&Bro .
.Ss \&Bsx
-Format the BSD/OS version provided as an argument, or a default value if
+Format the
+.Bsx
+version provided as an argument, or a default value if
no argument is provided.
.Pp
Examples:
@@ -1218,14 +1230,16 @@ See also
.Sx \&Dx ,
.Sx \&Fx ,
.Sx \&Nx ,
-.Sx \&Ox ,
and
-.Sx \&Ux .
+.Sx \&Ox .
.Ss \&Bt
+Supported only for compatibility, do not use this in new manuals.
Prints
.Dq is currently in beta test.
.Ss \&Bx
-Format the BSD version provided as an argument, or a default value if no
+Format the
+.Bx
+version provided as an argument, or a default value if no
argument is provided.
.Pp
Examples:
@@ -1239,9 +1253,8 @@ See also
.Sx \&Dx ,
.Sx \&Fx ,
.Sx \&Nx ,
-.Sx \&Ox ,
and
-.Sx \&Ux .
+.Sx \&Ox .
.Ss \&Cd
Kernel configuration declaration. It is found in pages for
.Bx
@@ -1283,20 +1296,19 @@ See also
and
.Sx \&Dl .
.Ss \&Db
-Switch debugging mode.
-Its syntax is as follows:
-.Pp
-.D1 Pf \. Sx \&Db Cm on | off
-.Pp
-This macro is ignored by
-.Xr mandoc 1 .
+This macro is obsolete.
+No replacement is needed.
+It is ignored by
+.Xr mandoc 1
+and groff including its arguments.
+It was formerly used to toggle a debugging mode.
.Ss \&Dc
Close a
.Sx \&Do
block.
Does not have any tail arguments.
.Ss \&Dd
-Document date.
+Document date for display in the page footer.
This is the mandatory first macro of any
.Nm
manual.
@@ -1325,8 +1337,11 @@ the special string
.Dq $\&Mdocdate$
can be given as an argument.
.It
-A few alternative date formats are accepted as well
-and converted to the standard form.
+The traditional, purely numeric
+.Xr man 5
+format
+.Ar year Ns \(en Ns Ar month Ns \(en Ns Ar day
+is accepted, too.
.It
If a date string cannot be parsed, it is used verbatim.
.It
@@ -1343,7 +1358,7 @@ See also
and
.Sx \&Os .
.Ss \&Dl
-One-line intended display.
+One-line indented display.
This is formatted as literal text and is useful for commands and
invocations.
It is followed by a newline.
@@ -1352,7 +1367,9 @@ Examples:
.Dl \&.Dl % mandoc mdoc.5 \e(ba less
.Pp
See also
+.Sx \&Ql ,
.Sx \&Bd
+.Fl literal ,
and
.Sx \&D1 .
.Ss \&Do
@@ -1386,39 +1403,33 @@ See also
and
.Sx \&Do .
.Ss \&Dt
-Document title.
+Document title for display in the page header.
This is the mandatory second macro of any
.Nm
file.
Its syntax is as follows:
.Bd -ragged -offset indent
.Pf \. Sx \&Dt
-.Oo
-.Ar title
-.Oo
+.Ar TITLE
.Ar section
-.Op Ar volume
.Op Ar arch
-.Oc
-.Oc
.Ed
.Pp
Its arguments are as follows:
-.Bl -tag -width Ds -offset Ds
-.It Ar title
+.Bl -tag -width section -offset 2n
+.It Ar TITLE
The document's title (name), defaulting to
-.Dq UNKNOWN
-if unspecified.
-It should be capitalised.
-.It Ar section
-The manual section. It should correspond to the manual's filename suffix
-and defaults to
-.Dq 1
+.Dq UNTITLED
if unspecified.
-.It Ar volume
-This overrides the volume inferred from
-.Ar section .
+To achieve a uniform appearance of page header lines,
+it should by convention be all caps.
+.It Ar SECTION
+The manual section.
+It should correspond to the manual's filename suffix and defaults to
+the empty string if unspecified.
This field is optional.
+To achieve a uniform appearance of page header lines,
+it should by convention be all caps.
.It Ar arch
This specifies the machine architecture a manual page applies to,
where relevant.
@@ -1436,11 +1447,16 @@ See also
.Sx \&Er
and
.Sx \&Ev
-for special-purpose constants and
+for special-purpose constants,
.Sx \&Va
-for variable symbols.
+for variable symbols, and
+.Sx \&Fd
+for listing preprocessor variable definitions in the
+.Em SYNOPSIS .
.Ss \&Dx
-Format the DragonFly BSD version provided as an argument, or a default
+Format the
+.Dx
+version provided as an argument, or a default
value if no argument is provided.
.Pp
Examples:
@@ -1453,9 +1469,8 @@ See also
.Sx \&Bx ,
.Sx \&Fx ,
.Sx \&Nx ,
-.Sx \&Ox ,
and
-.Sx \&Ux .
+.Sx \&Ox .
.Ss \&Ec
Close a scope started by
.Sx \&Eo .
@@ -1486,16 +1501,29 @@ See also
and
.Sx \&It .
.Ss \&Em
-Denotes text that should be
-.Em emphasised .
-Note that this is a presentation term and should not be used for
-stylistically decorating technical terms.
-Depending on the output device, this is usually represented
-using an italic font or underlined characters.
+Request an italic font.
+If the output device does not provide that, underline.
+.Pp
+This is most often used for stress emphasis (not to be confused with
+importance, see
+.Sx \&Sy ) .
+In the rare cases where none of the semantic markup macros fit,
+it can also be used for technical terms and placeholders, except
+that for syntax elements,
+.Sx \&Sy
+and
+.Sx \&Ar
+are preferred, respectively.
.Pp
Examples:
-.Dl \&.Em Warnings!
-.Dl \&.Em Remarks :
+.Bd -literal -compact -offset indent
+Selected lines are those
+\&.Em not
+matching any of the specified patterns.
+Some of the functions use a
+\&.Em hold space
+to save the pattern space for subsequent retrieval.
+.Ed
.Pp
See also
.Sx \&Bf ,
@@ -1504,8 +1532,14 @@ See also
and
.Sx \&Sy .
.Ss \&En
-This macro is obsolete and not implemented in
-.Xr mandoc 1 .
+This macro is obsolete.
+Use
+.Sx \&Eo
+or any of the other enclosure macros.
+.Pp
+It encloses its argument in the delimiters specified by the last
+.Sx \&Es
+macro.
.Ss \&Eo
An arbitrary enclosure.
Its syntax is as follows:
@@ -1531,7 +1565,14 @@ See also
.Sx \&Dv
for general constants.
.Ss \&Es
-This macro is obsolete and not implemented.
+This macro is obsolete.
+Use
+.Sx \&Eo
+or any of the other enclosure macros.
+.Pp
+It takes two arguments, defining the delimiters to be used by subsequent
+.Sx \&En
+macros.
.Ss \&Ev
Environmental variables such as those specified in
.Xr environ 5 .
@@ -1563,23 +1604,35 @@ arguments are treated as separate utilities.
See also
.Sx \&Rv .
.Ss \&Fa
-Function argument.
+Function argument or parameter.
Its syntax is as follows:
.Bd -ragged -offset indent
.Pf \. Sx \&Fa
-.Op Cm argtype
-.Cm argname
+.Qo
+.Op Ar argtype
+.Op Ar argname
+.Qc Ar \&...
.Ed
.Pp
-This may be invoked for names with or without the corresponding type.
-It is also used to specify the field name of a structure.
+Each argument may be a name and a type (recommended for the
+.Em SYNOPSIS
+section), a name alone (for function invocations),
+or a type alone (for function prototypes).
+If both a type and a name are given or if the type consists of multiple
+words, all words belonging to the same function argument have to be
+given in a single argument to the
+.Sx \&Fa
+macro.
+.Pp
+This macro is also used to specify the field name of a structure.
+.Pp
Most often, the
.Sx \&Fa
macro is used in the
.Em SYNOPSIS
within
.Sx \&Fo
-section when documenting multi-line function prototypes.
+blocks when documenting multi-line function prototypes.
If invoked with multiple arguments, the arguments are separated by a
comma.
Furthermore, if the following macro is another
@@ -1589,7 +1642,7 @@ the last argument will also have a trailing comma.
Examples:
.Dl \&.Fa \(dqconst char *p\(dq
.Dl \&.Fa \(dqint a\(dq \(dqint b\(dq \(dqint c\(dq
-.Dl \&.Fa foo
+.Dl \&.Fa \(dqchar *\(dq size_t
.Pp
See also
.Sx \&Fo .
@@ -1597,15 +1650,32 @@ See also
End a function context started by
.Sx \&Fo .
.Ss \&Fd
-Historically used to document include files.
-This usage has been deprecated in favour of
+Preprocessor directive, in particular for listing it in the
+.Em SYNOPSIS .
+Historically, it was also used to document include files.
+The latter usage has been deprecated in favour of
.Sx \&In .
-Do not use this macro.
+.Pp
+Its syntax is as follows:
+.Bd -ragged -offset indent
+.Pf \. Sx \&Fd
+.Li # Ns Ar directive
+.Op Ar argument ...
+.Ed
+.Pp
+Examples:
+.Dl \&.Fd #define sa_handler __sigaction_u.__sa_handler
+.Dl \&.Fd #define SIO_MAXNFDS
+.Dl \&.Fd #ifdef FS_DEBUG
+.Dl \&.Ft void
+.Dl \&.Fn dbg_open \(dqconst char *\(dq
+.Dl \&.Fd #endif
.Pp
See also
-.Sx MANUAL STRUCTURE
+.Sx MANUAL STRUCTURE ,
+.Sx \&In ,
and
-.Sx \&In .
+.Sx \&Dv .
.Ss \&Fl
Command-line flag or option.
Used when listing arguments to command-line utilities.
@@ -1675,7 +1745,7 @@ Invocations usually occur in the following context:
.br
.Pf \. Sx \&Fo Ar funcname
.br
-.Pf \. Sx \&Fa Oo Ar argtype Oc Ar argname
+.Pf \. Sx \&Fa Qq Ar argtype Ar argname
.br
\&.\.\.
.br
@@ -1694,13 +1764,10 @@ See also
and
.Sx \&Ft .
.Ss \&Fr
-This macro is obsolete and not implemented in
-.Xr mandoc 1 .
-.Pp
-It was used to show function return values.
-The syntax was:
+This macro is obsolete.
+No replacement markup is needed.
.Pp
-.Dl Pf . Sx \&Fr Ar value
+It was used to show numerical function return values in an italic font.
.Ss \&Ft
A function type.
Its syntax is as follows:
@@ -1739,9 +1806,8 @@ See also
.Sx \&Bx ,
.Sx \&Dx ,
.Sx \&Nx ,
-.Sx \&Ox ,
and
-.Sx \&Ux .
+.Sx \&Ox .
.Ss \&Hf
This macro is not implemented in
.Xr mandoc 1 .
@@ -1769,17 +1835,18 @@ is preferred for displaying code; the
.Sx \&Ic
macro is used when referring to specific instructions.
.Ss \&In
-An
-.Dq include
-file.
+The name of an include file.
+This macro is most often used in section 2, 3, and 9 manual pages.
+.Pp
When invoked as the first macro on an input line in the
.Em SYNOPSIS
section, the argument is displayed in angle brackets
and preceded by
-.Dq #include ,
+.Qq #include ,
and a blank line is inserted in front if there is a preceding
function declaration.
-This is most often used in section 2, 3, and 9 manual pages.
+In other sections, it only encloses its argument in angle brackets
+and causes no line break.
.Pp
Examples:
.Dl \&.In sys/types.h
@@ -1937,13 +2004,12 @@ Its syntax is as follows:
.Pp
Examples:
.Dl \&.Mt discuss@manpages.bsd.lv
+.Dl \&.An Kristaps Dzonsons \&Aq \&Mt kristaps@bsd.lv
.Ss \&Nd
A one line description of the manual's content.
-This may only be invoked in the
-.Em SYNOPSIS
-section subsequent the
-.Sx \&Nm
-macro.
+This is the mandatory last macro of the
+.Em NAME
+section and not appropriate for other sections.
.Pp
Examples:
.Dl Pf . Sx \&Nd mdoc language reference
@@ -1963,7 +2029,7 @@ See also
.Sx \&Nm .
.Ss \&Nm
The name of the manual page, or \(em in particular in section 1
-and 1M pages \(em of an additional command or feature documented in
+pages \(em of an additional command or feature documented in
the manual page.
When first invoked, the
.Sx \&Nm
@@ -2058,9 +2124,8 @@ See also
.Sx \&Bx ,
.Sx \&Dx ,
.Sx \&Fx ,
-.Sx \&Ox ,
and
-.Sx \&Ux .
+.Sx \&Ox .
.Ss \&Oc
Close multi-line
.Sx \&Oo
@@ -2089,7 +2154,7 @@ Examples:
See also
.Sx \&Oo .
.Ss \&Os
-Document operating system version.
+Operating system version for display in the page footer.
This is the mandatory third macro of
any
.Nm
@@ -2101,8 +2166,16 @@ Its syntax is as follows:
The optional
.Ar system
parameter specifies the relevant operating system or environment.
-Left unspecified, it defaults to the local operating system version.
-This is the suggested form.
+It is suggested to leave it unspecified, in which case
+.Xr mandoc 1
+uses its
+.Fl Ios
+argument, or, if that isn't specified either,
+.Fa sysname
+and
+.Fa release
+as returned by
+.Xr uname 3 .
.Pp
Examples:
.Dl \&.Os
@@ -2114,11 +2187,15 @@ See also
and
.Sx \&Dt .
.Ss \&Ot
-This macro is obsolete and not implemented in
-.Xr mandoc 1 .
+This macro is obsolete.
+Use
+.Sx \&Ft
+instead; with
+.Xr mandoc 1 ,
+both have the same effect.
.Pp
Historical
-.Xr mdoc 5
+.Nm
packages described it as
.Dq "old function type (FORTRAN)" .
.Ss \&Ox
@@ -2137,9 +2214,8 @@ See also
.Sx \&Bx ,
.Sx \&Dx ,
.Sx \&Fx ,
-.Sx \&Nx ,
and
-.Sx \&Ux .
+.Sx \&Nx .
.Ss \&Pa
An absolute or relative file system path, or a file or directory name.
If an argument is not provided, the character
@@ -2203,11 +2279,21 @@ See also
Close quoted context opened by
.Sx \&Qo .
.Ss \&Ql
-Format a single-quoted literal.
+In-line literal display.
+This can for example be used for complete command invocations and
+for multi-word code fragments when more specific markup is not
+appropriate and an indented display is not desired.
+While
+.Xr mandoc 1
+always encloses the arguments in single quotes, other formatters
+usually omit the quotes on non-terminal output devices when the
+arguments have three or more characters.
+.Pp
See also
-.Sx \&Qq
+.Sx \&Dl
and
-.Sx \&Sq .
+.Sx \&Bd
+.Fl literal .
.Ss \&Qo
Multi-line version of
.Sx \&Qq .
@@ -2313,7 +2399,7 @@ and
Switches the spacing mode for output generated from macros.
Its syntax is as follows:
.Pp
-.D1 Pf \. Sx \&Sm Cm on | off
+.D1 Pf \. Sx \&Sm Op Cm on | off
.Pp
By default, spacing is
.Cm on .
@@ -2322,6 +2408,11 @@ When switched
no white space is inserted between macro arguments and between the
output generated from adjacent macros, but text lines
still get normal spacing between words and sentences.
+.Pp
+When called without an argument, the
+.Sx \&Sm
+macro toggles the spacing mode.
+Using this is not recommended because it makes the code harder to read.
.Ss \&So
Multi-line version of
.Sx \&Sq .
@@ -2359,105 +2450,218 @@ and
.Sx \&Sx .
.Ss \&St
Replace an abbreviation for a standard with the full form.
-The following standards are recognised:
-.Pp
-.Bl -tag -width "-p1003.1g-2000X" -compact
-.It \-p1003.1-88
-.St -p1003.1-88
-.It \-p1003.1-90
-.St -p1003.1-90
-.It \-p1003.1-96
-.St -p1003.1-96
-.It \-p1003.1-2001
-.St -p1003.1-2001
-.It \-p1003.1-2004
-.St -p1003.1-2004
-.It \-p1003.1-2008
-.St -p1003.1-2008
-.It \-p1003.1
-.St -p1003.1
-.It \-p1003.1b
-.St -p1003.1b
-.It \-p1003.1b-93
-.St -p1003.1b-93
-.It \-p1003.1c-95
-.St -p1003.1c-95
-.It \-p1003.1g-2000
-.St -p1003.1g-2000
-.It \-p1003.1i-95
-.St -p1003.1i-95
-.It \-p1003.2-92
-.St -p1003.2-92
-.It \-p1003.2a-92
-.St -p1003.2a-92
-.It \-p1387.2-95
-.St -p1387.2-95
-.It \-p1003.2
-.St -p1003.2
-.It \-p1387.2
-.St -p1387.2
+The following standards are recognised.
+Where multiple lines are given without a blank line in between,
+they all refer to the same standard, and using the first form
+is recommended.
+.Bl -tag -width 1n
+.It C language standards
+.Pp
+.Bl -tag -width "-p1003.1g-2000" -compact
+.It \-ansiC
+.St -ansiC
+.It \-ansiC-89
+.St -ansiC-89
.It \-isoC
.St -isoC
.It \-isoC-90
.St -isoC-90
+.br
+The original C standard.
+.Pp
.It \-isoC-amd1
.St -isoC-amd1
+.Pp
.It \-isoC-tcor1
.St -isoC-tcor1
+.Pp
.It \-isoC-tcor2
.St -isoC-tcor2
+.Pp
.It \-isoC-99
.St -isoC-99
+.br
+The second major version of the C language standard.
+.Pp
.It \-isoC-2011
.St -isoC-2011
+.br
+The third major version of the C language standard.
+.El
+.It POSIX.1 before the Single UNIX Specification
+.Pp
+.Bl -tag -width "-p1003.1g-2000" -compact
+.It \-p1003.1-88
+.St -p1003.1-88
+.It \-p1003.1
+.St -p1003.1
+.br
+The original POSIX standard, based on ANSI C.
+.Pp
+.It \-p1003.1-90
+.St -p1003.1-90
.It \-iso9945-1-90
.St -iso9945-1-90
+.br
+The first update of POSIX.1.
+.Pp
+.It \-p1003.1b-93
+.St -p1003.1b-93
+.It \-p1003.1b
+.St -p1003.1b
+.br
+Real-time extensions.
+.Pp
+.It \-p1003.1c-95
+.St -p1003.1c-95
+.br
+POSIX thread interfaces.
+.Pp
+.It \-p1003.1i-95
+.St -p1003.1i-95
+.br
+Technical Corrigendum.
+.Pp
+.It \-p1003.1-96
+.St -p1003.1-96
.It \-iso9945-1-96
.St -iso9945-1-96
-.It \-iso9945-2-93
-.St -iso9945-2-93
-.It \-ansiC
-.St -ansiC
-.It \-ansiC-89
-.St -ansiC-89
-.It \-ansiC-99
-.St -ansiC-99
-.It \-ieee754
-.St -ieee754
-.It \-iso8802-3
-.St -iso8802-3
-.It \-iso8601
-.St -iso8601
-.It \-ieee1275-94
-.St -ieee1275-94
+.br
+Includes POSIX.1-1990, 1b, 1c, and 1i.
+.El
+.It X/Open Portability Guide version 4 and related standards
+.Pp
+.Bl -tag -width "-p1003.1g-2000" -compact
.It \-xpg3
.St -xpg3
+.br
+An XPG4 precursor, published in 1989.
+.Pp
+.It \-p1003.2
+.St -p1003.2
+.It \-p1003.2-92
+.St -p1003.2-92
+.It \-iso9945-2-93
+.St -iso9945-2-93
+.br
+An XCU4 precursor.
+.Pp
+.It \-p1003.2a-92
+.St -p1003.2a-92
+.br
+Updates to POSIX.2.
+.Pp
.It \-xpg4
.St -xpg4
+.br
+Based on POSIX.1 and POSIX.2, published in 1992.
+.El
+.It Single UNIX Specification version 1 and related standards
+.Pp
+.Bl -tag -width "-p1003.1g-2000" -compact
+.It \-susv1
+.St -susv1
.It \-xpg4.2
.St -xpg4.2
-.It \-xpg4.3
-.St -xpg4.3
+.br
+This standard was published in 1994.
+It was used as the basis for UNIX 95 certification.
+The following three refer to parts of it.
+.Pp
+.It \-xsh4.2
+.St -xsh4.2
+.Pp
+.It \-xcurses4.2
+.St -xcurses4.2
+.Pp
+.It \-p1003.1g-2000
+.St -p1003.1g-2000
+.br
+Networking APIs, including sockets.
+.Pp
+.It \-svid4
+.St -svid4 ,
+.br
+Published in 1995.
+.El
+.It Single UNIX Specification version 2 and related standards
+.Pp
+.Bl -tag -width "-p1003.1g-2000" -compact
+.It \-susv2
+.St -susv2
+This Standard was published in 1997
+and is also called X/Open Portability Guide version 5.
+It was used as the basis for UNIX 98 certification.
+The following refer to parts of it.
+.Pp
.It \-xbd5
.St -xbd5
-.It \-xcu5
-.St -xcu5
+.Pp
.It \-xsh5
.St -xsh5
+.Pp
+.It \-xcu5
+.St -xcu5
+.Pp
.It \-xns5
.St -xns5
.It \-xns5.2
.St -xns5.2
-.It \-xns5.2d2.0
-.St -xns5.2d2.0
-.It \-xcurses4.2
-.St -xcurses4.2
-.It \-susv2
-.St -susv2
+.El
+.It Single UNIX Specification version 3
+.Pp
+.Bl -tag -width "-p1003.1-2001" -compact
+.It \-p1003.1-2001
+.St -p1003.1-2001
.It \-susv3
.St -susv3
-.It \-svid4
-.St -svid4
+.br
+This standard is based on C99, SUSv2, POSIX.1-1996, 1d, and 1j.
+It is also called X/Open Portability Guide version 6.
+It is used as the basis for UNIX 03 certification.
+.Pp
+.It \-p1003.1-2004
+.St -p1003.1-2004
+.br
+The second and last Technical Corrigendum.
+.El
+.It Single UNIX Specification version 4
+.Pp
+.Bl -tag -width "-p1003.1g-2000" -compact
+.It \-p1003.1-2008
+.St -p1003.1-2008
+.It \-susv4
+.St -susv4
+.br
+This standard is also called
+X/Open Portability Guide version 7.
+.Pp
+.It \-p1003.1-2013
+.St -p1003.1-2013
+.br
+This is the first Technical Corrigendum.
+.El
+.It Other standards
+.Pp
+.Bl -tag -width "-p1003.1g-2000" -compact
+.It \-ieee754
+.St -ieee754
+.br
+Floating-point arithmetic.
+.Pp
+.It \-iso8601
+.St -iso8601
+.br
+Representation of dates and times, published in 1988.
+.Pp
+.It \-iso8802-3
+.St -iso8802-3
+.br
+Ethernet local area networks.
+.Pp
+.It \-ieee1275-94
+.St -ieee1275-94
+.El
.El
.Ss \&Sx
Reference a section or subsection in the same manual page.
@@ -2472,10 +2676,24 @@ See also
and
.Sx \&Ss .
.Ss \&Sy
-Format enclosed arguments in symbolic
-.Pq Dq boldface .
-Note that this is a presentation term and should not be used for
-stylistically decorating technical terms.
+Request a boldface font.
+.Pp
+This is most often used to indicate importance or seriousness (not to be
+confused with stress emphasis, see
+.Sx \&Em ) .
+When none of the semantic macros fit, it is also adequate for syntax
+elements that have to be given or that appear verbatim.
+.Pp
+Examples:
+.Bd -literal -compact -offset indent
+\&.Sy Warning :
+If
+\&.Sy s
+appears in the owner permissions, set-user-ID mode is set.
+This utility replaces the former
+\&.Sy dumpdir
+program.
+.Ed
.Pp
See also
.Sx \&Bf ,
@@ -2489,42 +2707,36 @@ Table cell separator in
lists; can only be used below
.Sx \&It .
.Ss \&Tn
-Format a tradename.
-.Pp
-Since this macro is often implemented to use a small caps font,
-it has historically been used for acronyms (like ASCII) as well.
-Such usage is not recommended because it would use the same macro
-sometimes for semantical annotation, sometimes for physical formatting.
-.Pp
-Examples:
-.Dl \&.Tn IBM
+Supported only for compatibility, do not use this in new manuals.
+Even though the macro name
+.Pq Dq tradename
+suggests a semantic function, historic usage is inconsistent, mostly
+using it as a presentation-level macro to request a small caps font.
.Ss \&Ud
+Supported only for compatibility, do not use this in new manuals.
Prints out
.Dq currently under development.
.Ss \&Ux
-Format the UNIX name.
-Accepts no argument.
-.Pp
-Examples:
-.Dl \&.Ux
-.Pp
-See also
-.Sx \&At ,
-.Sx \&Bsx ,
-.Sx \&Bx ,
-.Sx \&Dx ,
-.Sx \&Fx ,
-.Sx \&Nx ,
-and
-.Sx \&Ox .
+Supported only for compatibility, do not use this in new manuals.
+Prints out
+.Dq Ux .
.Ss \&Va
A variable name.
.Pp
Examples:
.Dl \&.Va foo
.Dl \&.Va const char *bar ;
+.Pp
+For function arguments and parameters, use
+.Sx \&Fa
+instead.
+For declarations of global variables in the
+.Em SYNOPSIS
+section, use
+.Sx \&Vt .
.Ss \&Vt
A variable type.
+.Pp
This is also used for indicating global variables in the
.Em SYNOPSIS
section, in which case a variable name is also specified.
@@ -2539,18 +2751,21 @@ In the former case, this macro starts a new output line,
and a blank line is inserted in front if there is a preceding
function definition or include directive.
.Pp
-Note that this should not be confused with
-.Sx \&Ft ,
-which is used for function return types.
-.Pp
Examples:
.Dl \&.Vt unsigned char
.Dl \&.Vt extern const char * const sys_signame[] \&;
.Pp
+For parameters in function prototypes, use
+.Sx \&Fa
+instead, for function return types
+.Sx \&Ft ,
+and for variable names outside the
+.Em SYNOPSIS
+section
+.Sx \&Va ,
+even when including a type with the name.
See also
-.Sx MANUAL STRUCTURE
-and
-.Sx \&Va .
+.Sx MANUAL STRUCTURE .
.Ss \&Xc
Close a scope opened by
.Sx \&Xo .
@@ -2561,26 +2776,20 @@ macro or the body of a partial-implicit block macro
beyond the end of the input line.
This macro originally existed to work around the 9-argument limit
of historic
-.Xr roff 5 .
+.Xr mandoc_roff 5 .
.Ss \&Xr
Link to another manual
.Pq Qq cross-reference .
Its syntax is as follows:
.Pp
-.D1 Pf \. Sx \&Xr Ar name section
+.D1 Pf \. Sx \&Xr Ar name Op section
.Pp
-The
+Cross reference the
.Ar name
and
.Ar section
-are the name and section of the linked manual.
-If
-.Ar section
-is followed by non-punctuation, an
-.Sx \&Ns
-is inserted into the token stream.
-This behaviour is for compatibility with
-GNU troff.
+number of another man page;
+omitting the section number is rarely useful.
.Pp
Examples:
.Dl \&.Xr mandoc 1
@@ -2604,8 +2813,8 @@ Its syntax is as follows:
.Pp
The
.Ar height
-argument must be formatted as described in
-.Sx Scaling Widths .
+argument is a scaling width as described in
+.Xr mandoc_roff 5 .
If unspecified,
.Sx \&sp
asserts a single vertical space.
@@ -2774,6 +2983,7 @@ end of the line.
.It Sx \&D1 Ta \&No Ta \&Yes
.It Sx \&Dl Ta \&No Ta Yes
.It Sx \&Dq Ta Yes Ta Yes
+.It Sx \&En Ta Yes Ta Yes
.It Sx \&Op Ta Yes Ta Yes
.It Sx \&Pq Ta Yes Ta Yes
.It Sx \&Ql Ta Yes Ta Yes
@@ -2851,16 +3061,15 @@ then the macro accepts an arbitrary number of arguments.
.It Sx \&Dv Ta Yes Ta Yes Ta >0
.It Sx \&Dx Ta Yes Ta Yes Ta n
.It Sx \&Em Ta Yes Ta Yes Ta >0
-.It Sx \&En Ta \&No Ta \&No Ta 0
.It Sx \&Er Ta Yes Ta Yes Ta >0
-.It Sx \&Es Ta \&No Ta \&No Ta 0
+.It Sx \&Es Ta Yes Ta Yes Ta 2
.It Sx \&Ev Ta Yes Ta Yes Ta >0
.It Sx \&Ex Ta \&No Ta \&No Ta n
.It Sx \&Fa Ta Yes Ta Yes Ta >0
.It Sx \&Fd Ta \&No Ta \&No Ta >0
.It Sx \&Fl Ta Yes Ta Yes Ta n
.It Sx \&Fn Ta Yes Ta Yes Ta >0
-.It Sx \&Fr Ta \&No Ta \&No Ta n
+.It Sx \&Fr Ta Yes Ta Yes Ta >0
.It Sx \&Ft Ta Yes Ta Yes Ta >0
.It Sx \&Fx Ta Yes Ta Yes Ta n
.It Sx \&Hf Ta \&No Ta \&No Ta n
@@ -2877,13 +3086,13 @@ then the macro accepts an arbitrary number of arguments.
.It Sx \&Ns Ta Yes Ta Yes Ta 0
.It Sx \&Nx Ta Yes Ta Yes Ta n
.It Sx \&Os Ta \&No Ta \&No Ta n
-.It Sx \&Ot Ta \&No Ta \&No Ta n
+.It Sx \&Ot Ta Yes Ta Yes Ta >0
.It Sx \&Ox Ta Yes Ta Yes Ta n
.It Sx \&Pa Ta Yes Ta Yes Ta n
.It Sx \&Pf Ta Yes Ta Yes Ta 1
.It Sx \&Pp Ta \&No Ta \&No Ta 0
.It Sx \&Rv Ta \&No Ta \&No Ta n
-.It Sx \&Sm Ta \&No Ta \&No Ta 1
+.It Sx \&Sm Ta \&No Ta \&No Ta <2
.It Sx \&St Ta \&No Ta Yes Ta 1
.It Sx \&Sx Ta Yes Ta Yes Ta >0
.It Sx \&Sy Ta Yes Ta Yes Ta >0
@@ -2991,58 +3200,22 @@ macros.
Whenever any
.Nm
macro switches the
-.Xr roff 5
+.Xr mandoc_roff 5
font mode, it will automatically restore the previous font when exiting
its scope.
Manually switching the font using the
-.Xr roff 5
+.Xr mandoc_roff 5
.Ql \ef
font escape sequences is never required.
.Sh COMPATIBILITY
-This section documents compatibility between mandoc and other other
-troff implementations, at this time limited to GNU troff
+This section provides an incomplete list of compatibility issues
+between mandoc and GNU troff
.Pq Qq groff .
-The term
-.Qq historic groff
-refers to groff versions before 1.17,
-which featured a significant update of the
-.Pa doc.tmac
-file.
-.Pp
-Heirloom troff, the other significant troff implementation accepting
-\-mdoc, is similar to historic groff.
.Pp
The following problematic behaviour is found in groff:
-.ds hist (Historic groff only.)
.Pp
.Bl -dash -compact
.It
-Display macros
-.Po
-.Sx \&Bd ,
-.Sx \&Dl ,
-and
-.Sx \&D1
-.Pc
-may not be nested.
-\*[hist]
-.It
-.Sx \&At
-with unknown arguments produces no output at all.
-\*[hist]
-Newer groff and mandoc print
-.Qq AT&T UNIX
-and the arguments.
-.It
-.Sx \&Bl Fl column
-does not recognise trailing punctuation characters when they immediately
-precede tabulator characters, but treats them as normal text and
-outputs a space before them.
-.It
-.Sx \&Bd Fl ragged compact
-does not start a new line.
-\*[hist]
-.It
.Sx \&Dd
with non-standard arguments behaves very strangely.
When there are three arguments, they are printed verbatim.
@@ -3051,53 +3224,6 @@ but without any arguments the string
.Dq Epoch
is printed.
.It
-.Sx \&Fl
-does not print a dash for an empty argument.
-\*[hist]
-.It
-.Sx \&Fn
-does not start a new line unless invoked as the line macro in the
-.Em SYNOPSIS
-section.
-\*[hist]
-.It
-.Sx \&Fo
-with
-.Pf non- Sx \&Fa
-children causes inconsistent spacing between arguments.
-In mandoc, a single space is always inserted between arguments.
-.It
-.Sx \&Ft
-in the
-.Em SYNOPSIS
-causes inconsistent vertical spacing, depending on whether a prior
-.Sx \&Fn
-has been invoked.
-See
-.Sx \&Ft
-and
-.Sx \&Fn
-for the normalised behaviour in mandoc.
-.It
-.Sx \&In
-ignores additional arguments and is not treated specially in the
-.Em SYNOPSIS .
-\*[hist]
-.It
-.Sx \&It
-sometimes requires a
-.Fl nested
-flag.
-\*[hist]
-In new groff and mandoc, any list may be nested by default and
-.Fl enum
-lists will restart the sequence only for the sub-list.
-.It
-.Sx \&Li
-followed by a delimiter is incorrectly used in some manuals
-instead of properly quoting that character, which sometimes works with
-historic groff.
-.It
.Sx \&Lk
only accepts a single link-name argument; the remainder is misformatted.
.It
@@ -3109,25 +3235,12 @@ certain list types.
can only be called by other macros, but not at the beginning of a line.
.It
.Sx \&%C
-is not implemented.
-.It
-Historic groff only allows up to eight or nine arguments per macro input
-line, depending on the exact situation.
-Providing more arguments causes garbled output.
-The number of arguments on one input line is not limited with mandoc.
-.It
-Historic groff has many un-callable macros.
-Most of these (excluding some block-level macros) are callable
-in new groff and mandoc.
-.It
-.Sq \(ba
-(vertical bar) is not fully supported as a delimiter.
-\*[hist]
+is not implemented (up to and including groff-1.22.2).
.It
.Sq \ef
.Pq font face
and
-.Sq \ef
+.Sq \eF
.Pq font family face
.Sx Text Decoration
escapes behave irregularly when specified within line-macro scopes.
@@ -3141,44 +3254,28 @@ The following features are unimplemented in mandoc:
.Bl -dash -compact
.It
.Sx \&Bd
-.Fl file Ar file .
+.Fl file Ar file
+is unsupported for security reasons.
.It
.Sx \&Bd
-.Fl offset Ar center
-and
-.Fl offset Ar right .
-Groff does not implement centred and flush-right rendering either,
-but produces large indentations.
-.It
-The
-.Sq \eh
-.Pq horizontal position ,
-.Sq \ev
-.Pq vertical position ,
-.Sq \em
-.Pq text colour ,
-.Sq \eM
-.Pq text filling colour ,
-.Sq \ez
-.Pq zero-length character ,
-.Sq \ew
-.Pq string length ,
-.Sq \ek
-.Pq horizontal position marker ,
-.Sq \eo
-.Pq text overstrike ,
-and
-.Sq \es
-.Pq text size
-escape sequences are all discarded in mandoc.
+.Fl filled
+does not adjust the right margin, but is an alias for
+.Sx \&Bd
+.Fl ragged .
.It
-The
-.Sq \ef
-scaling unit is accepted by mandoc, but rendered as the default unit.
+.Sx \&Bd
+.Fl literal
+does not use a literal font, but is an alias for
+.Sx \&Bd
+.Fl unfilled .
.It
-In quoted literals, groff allows pairwise double-quotes to produce a
-standalone double-quote in formatted output.
-This is not supported by mandoc.
+.Sx \&Bd
+.Fl offset Cm center
+and
+.Fl offset Cm right
+don't work.
+Groff does not implement centered and flush-right rendering either,
+but produces large indentations.
.El
.Sh SEE ALSO
.Xr man 1 ,
@@ -3186,7 +3283,7 @@ This is not supported by mandoc.
.Xr eqn 5 ,
.Xr man 5 ,
.Xr mandoc_char 5 ,
-.Xr roff 5 ,
+.Xr mandoc_roff 5 ,
.Xr tbl 5
.Sh HISTORY
The
@@ -3203,5 +3300,4 @@ utility written by Kristaps Dzonsons appeared in
The
.Nm
reference was written by
-.An Kristaps Dzonsons ,
-.Mt kristaps@bsd.lv .
+.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
diff --git a/usr/src/man/man5/tbl.5 b/usr/src/man/man5/tbl.5
index fe142208e8..d0238e4154 100644
--- a/usr/src/man/man5/tbl.5
+++ b/usr/src/man/man5/tbl.5
@@ -1,3 +1,7 @@
+.\" $Id: tbl.7,v 1.26 2015/01/29 00:33:57 schwarze Exp $
+.\"
+.\" Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+.\" Copyright (c) 2014, 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
@@ -11,11 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.\"
-.\" Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright 2012 Nexenta Systems, Inc. All rights reserved.
-.\"
-.Dd Sep 3, 2011
+.Dd $Mdocdate: January 29 2015 $
.Dt TBL 5
.Os
.Sh NAME
@@ -46,11 +46,11 @@ are enclosed by the
and
.Sq TE
macro tags, whose precise syntax is documented in
-.Xr roff 5 .
+.Xr mandoc_roff 5 .
Tables consist of a series of options on a single line, followed by the
table layout, followed by data.
.Pp
-For example, the following creates a boxed table with digits centred in
+For example, the following creates a boxed table with digits centered in
the cells.
.Bd -literal -offset indent
\&.TS
@@ -70,19 +70,12 @@ c5 c5 c5.
4:5:6
.TE
.Ed
-.Pp
-The
-.Nm
-implementation in
-.Xr mandoc 1
-is
-.Ud
.Sh TABLE STRUCTURE
Tables are enclosed by the
.Sq TS
and
.Sq TE
-.Xr roff 5
+.Xr mandoc_roff 5
macros.
A table consists of an optional single line of table
.Sx Options
@@ -107,7 +100,7 @@ Table data is
that is, data rows are parsed then inserted into the underlying stream
of input data.
This allows data rows to be interspersed by arbitrary
-.Xr roff 5 ,
+.Xr mandoc_roff 5 ,
.Xr mdoc 5 ,
and
.Xr man 5
@@ -140,57 +133,59 @@ c c c.
in the case of
.Xr man 5 .
.Ss Options
-The first line of a table consists of space-separated option keys and
-modifiers terminated by a semicolon.
+The first line of a table may contain options separated by spaces, tabs,
+or commas and terminated by a semicolon.
If the first line does not have a terminating semicolon, it is assumed
that no options are specified and instead a
.Sx Layout
is processed.
-Some options accept arguments enclosed by parenthesis.
+Some options require arguments enclosed by parentheses.
The following case-insensitive options are available:
.Bl -tag -width Ds
-.It Cm center
-This option is not supported by
-.Xr mandoc 1 .
-This may also be invoked with
-.Cm centre .
-.It Cm delim
-Accepts a two-character argument.
-This option is not supported by
-.Xr mandoc 1 .
-.It Cm expand
-This option is not supported by
-.Xr mandoc 1 .
+.It Cm allbox
+Draw a single-line box around each table cell.
+Currently treated as a synonym for
+.Cm box .
.It Cm box
Draw a single-line box around the table.
-This may also be invoked with
+For GNU compatibility, this may also be invoked with
.Cm frame .
+.It Cm center
+Center the table instead of left-adjusting it.
+For GNU compatibility, this may also be invoked with
+.Cm centre .
+.It Cm decimalpoint
+Use the single-character argument as the decimal point with the
+.Cm n
+layout key.
+This is a GNU extension.
+.It Cm delim
+Use the two characters of the argument as
+.Xr eqn 5
+delimiters.
+Currently unsupported.
.It Cm doublebox
Draw a double-line box around the table.
-This may also be invoked with
+For GNU compatibility, this may also be invoked with
.Cm doubleframe .
-.It Cm allbox
-This option is not supported by
-.Xr mandoc 1 .
-.It Cm tab
-Accepts a single-character argument.
-This character is used as a delimiter between data cells, which otherwise
-defaults to the tab character.
+.It Cm expand
+Increase the width of the table to the current line length.
+Currently ignored.
.It Cm linesize
-Accepts a natural number (all digits).
-This option is not supported by
-.Xr mandoc 1 .
+Draw lines with the point size given by the unsigned integer argument.
+Currently ignored.
.It Cm nokeep
-This option is not supported by
-.Xr mandoc 1 .
-.It Cm decimalpoint
-Accepts a single-character argument.
-This character will be used as the decimal point with the
-.Cm n
-layout key.
+Allow page breaks within the table.
+This is a GNU extension and currently ignored.
.It Cm nospaces
-This option is not supported by
-.Xr mandoc 1 .
+Ignore leading and trailing spaces in data cells.
+This is a GNU extension and currently ignored.
+.It Cm nowarn
+Suppress warnings about tables exceeding the current line length.
+This is a GNU extension and currently ignored.
+.It Cm tab
+Use the single-character argument as a delimiter between data cells.
+By default, the tab character is used.
.El
.Ss Layout
The table layout follows
@@ -203,9 +198,9 @@ Each layout line corresponds to a line of data; the last layout line
applies to all remaining data lines.
Layout lines may also be separated by a comma.
Each layout cell consists of one of the following case-insensitive keys:
-.Bl -tag -width Ds
+.Bl -tag -width 2n
.It Cm c
-Centre a literal string within its column.
+Center a literal string within its column.
.It Cm r
Right-justify a literal string within its column.
.It Cm l
@@ -252,35 +247,60 @@ 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 following case-insensitive modifier keys are available:
-.Cm z ,
-.Cm u ,
-.Cm e ,
-.Cm t ,
-.Cm d ,
-.Cm b ,
-.Cm i ,
-.Cm r ,
-and
-.Cm f
-.Po
-followed by
-.Cm b ,
-.Cm i ,
-.Cm r ,
-.Cm 3 ,
-.Cm 2 ,
-or
-.Cm 1
-.Pc .
-All of these are ignored by
-.Xr mandoc 1 .
+.Bl -tag -width 2n
+.It Cm b
+Use a bold font for the contents of this column.
+.It Cm d
+Move cell content down to the last cell of a vertical span.
+Currently ignored.
+.It Cm e
+Make this column wider to match the maximum width
+of any other column also having the
+.Cm e
+modifier.
+.It Cm f
+The next character selects the font to use for this column.
+See the
+.Xr mandoc_roff 5
+manual for supported one-character font names.
+.It Cm i
+Use an italic font for the contents of this column.
+.It Cm m
+Specify a cell start macro.
+This is a GNU extension and currently unsupported.
+.It Cm p
+Set the point size to the following unsigned argument,
+or change it by the following signed argument.
+Currently ignored.
+.It Cm v
+Set the vertical line spacing to the following unsigned argument,
+or change it by the following signed argument.
+Currently ignored.
+.It Cm t
+Do not vertically center cell content in the vertical span,
+leave it at the top.
+Currently ignored.
+.It Cm u
+Move cell content up by half a table line.
+Currently ignored.
+.It Cm w
+Specify minimum column width.
+Currently ignored.
+.It Cm x
+After determining the width of all other columns, distribute the
+rest of the line length among all columns having the
+.Cm x
+modifier.
+.It Cm z
+Do not use this cell for determining the width of this column.
+.El
.Pp
-For example, the following layout specifies a centre-justified column of
+For example, the following layout specifies a center-justified column of
minimum width 10, followed by vertical bar, followed by a left-justified
-column of minimum width 10, another vertical bar, then a column
-justified about the decimal point in numbers:
+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 | n
+.Dl c10 | l10 | nfB
.Ss Data
The data section follows the last layout row.
By default, cells in a data section are delimited by a tab.
@@ -308,24 +328,23 @@ It may then be followed by a tab
.Pq or as designated by Cm tab
or an end-of-line to terminate the row.
.Sh COMPATIBILITY
-This section documents compatibility between mandoc and other
-.Nm
-implementations, at this time limited to GNU tbl.
-.Pp
-.Bl -dash -compact
-.It
-In GNU tbl, comments and macros are disallowed prior to the data block
-of a table.
The
.Xr mandoc 1
-implementation allows them.
-.El
+implementation of
+.Nm
+doesn't support
+.Xr mdoc 5
+and
+.Xr man 5
+macros and
+.Xr eqn 5
+equations inside tables.
.Sh SEE ALSO
.Xr mandoc 1 ,
.Xr man 5 ,
.Xr mandoc_char 5 ,
-.Xr mdoc 5 ,
-.Xr roff 5
+.Xr mandoc_roff 5 ,
+.Xr mdoc 5
.Rs
.%A M. E. Lesk
.%T Tbl\(emA Program to Format Tables
@@ -345,5 +364,4 @@ utility.
This
.Nm
reference was written by
-.An Kristaps Dzonsons ,
-.Mt kristaps@bsd.lv .
+.An Kristaps Dzonsons Aq Mt kristaps@bsd.lv .
diff --git a/usr/src/pkg/manifests/system-man.mf b/usr/src/pkg/manifests/system-man.mf
index 619ed4496e..31bccf54db 100644
--- a/usr/src/pkg/manifests/system-man.mf
+++ b/usr/src/pkg/manifests/system-man.mf
@@ -10,8 +10,8 @@
#
#
-# Copyright 2012 Nexenta Systems, Inc. All rights reserved.
# Copyright 2014 Garrett D'Amore <garrett@damore.org>
+# Copyright 2015 Nexenta Systems, Inc. All rights reserved.
#
set name=pkg.fmri value=pkg:/system/man@$(PKGVERS)
@@ -22,7 +22,6 @@ set name=info.classification \
value="org.opensolaris.category.2008:System/Text Tools"
set name=variant.arch value=$(ARCH)
dir path=usr/bin
-dir path=usr/lib
dir path=usr/share
dir path=usr/share/man
dir path=usr/share/man/man1
@@ -30,7 +29,6 @@ dir path=usr/share/man/man1m
dir path=usr/share/man/man5
file path=usr/bin/man mode=0555
file path=usr/bin/mandoc mode=0555
-file path=usr/lib/mandoc_preconv mode=0555
file path=usr/share/man/man1/apropos.1
file path=usr/share/man/man1/man.1
file path=usr/share/man/man1/mandoc.1
@@ -53,7 +51,7 @@ license usr/src/cmd/mandoc/THIRDPARTYLICENSE \
link path=usr/man target=./share/man
link path=usr/share/man/man1/whatis.1 target=apropos.1
# arguably we also need lp, for man -t support, but really we don't
-# want to make this mandatory, so we don't express teh dependency here.
+# want to make this mandatory, so we don't express the dependency here.
# gzcat/bzcat are used for displaying compressed manpages. However,
# as we don't format such pages this way by default, lets leave the
# dependency out.
diff --git a/usr/src/tools/mandoc/Makefile b/usr/src/tools/mandoc/Makefile
index 36cd11b462..eba26e75ba 100644
--- a/usr/src/tools/mandoc/Makefile
+++ b/usr/src/tools/mandoc/Makefile
@@ -10,42 +10,28 @@
#
#
-# Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+# Copyright 2015 Nexenta Systems, Inc. All rights reserved.
#
+CMDDIR= $(SRC)/cmd/mandoc
-PROG= mandoc
+include ../Makefile.tools
+include $(CMDDIR)/Makefile.common
-CMDDIR= $(SRC)/cmd/mandoc
-
-include ../Makefile.tools
+.KEEP_STATE:
-include $(SRC)/cmd/mandoc/Makefile.common
+all: $(PROG)
-SRCS= $(mandoc_OBJS:%.o=$(CMDDIR)/%.c)
-CLEANFILES= $(PROG) $(OBJS)
-OBJS= $(mandoc_OBJS)
-PROG= mandoc
+install: all .WAIT $(ROOTONBLDMACHPROG)
-.KEEP_STATE:
-
-install: all .WAIT $(ROOTONBLDMACHPROG)
+clean:
+ $(RM) $(PROG) $(OBJS)
$(PROG): $(OBJS)
- $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
$(POST_PROCESS)
-all: $(PROG)
-
-
%.o: $(CMDDIR)/%.c
$(COMPILE.c) -o $@ $<
-%.o: $(LIBDIR)/%.c
- $(COMPILE.c) -o $@ $<
-
-clean:
- $(RM) $(CLEANFILES)
-
-include ../Makefile.targ
-
+include ../Makefile.targ