Import mdocml-1.12.3 vendor/MDOCML
authorFranco Fichtner <franco@lastsummer.de>
Tue, 31 Dec 2013 13:10:20 +0000 (14:10 +0100)
committerFranco Fichtner <franco@lastsummer.de>
Tue, 31 Dec 2013 13:10:20 +0000 (14:10 +0100)
39 files changed:
contrib/mdocml/Makefile
contrib/mdocml/NEWS
contrib/mdocml/TODO
contrib/mdocml/apropos_db.c
contrib/mdocml/catman.c
contrib/mdocml/cgi.c
contrib/mdocml/config.h.post
contrib/mdocml/index.sgml
contrib/mdocml/lib.in
contrib/mdocml/libmandoc.h
contrib/mdocml/libmdoc.h
contrib/mdocml/man.c
contrib/mdocml/man.h
contrib/mdocml/man_html.c
contrib/mdocml/man_macro.c
contrib/mdocml/man_term.c
contrib/mdocml/man_validate.c
contrib/mdocml/mandoc.3
contrib/mdocml/mandoc.c
contrib/mdocml/mandoc.h
contrib/mdocml/mandoc_char.7
contrib/mdocml/mandocdb.c
contrib/mdocml/manpath.c
contrib/mdocml/mdoc.7
contrib/mdocml/mdoc.c
contrib/mdocml/mdoc.h
contrib/mdocml/mdoc_argv.c
contrib/mdocml/mdoc_html.c
contrib/mdocml/mdoc_macro.c
contrib/mdocml/mdoc_man.c
contrib/mdocml/mdoc_term.c
contrib/mdocml/mdoc_validate.c
contrib/mdocml/out.c
contrib/mdocml/roff.7
contrib/mdocml/roff.c
contrib/mdocml/st.in
contrib/mdocml/term.c
contrib/mdocml/term.h
contrib/mdocml/tree.c

index 044d087..20b9fea 100644 (file)
@@ -8,8 +8,8 @@
 #
 # CFLAGS       += -DOSNAME="\"OpenBSD 5.4\""
 
-VERSION                 = 1.12.2
-VDATE           = 05 October 2013
+VERSION                 = 1.12.3
+VDATE           = 31 December 2013
 
 # IFF your system supports multi-byte functions (setlocale(), wcwidth(),
 # putwchar()) AND has __STDC_ISO_10646__ (that is, wchar_t is simply a
@@ -31,7 +31,7 @@ STATIC                 = -static
 # Linux requires -pthread to statically link with libdb.
 #STATIC                += -pthread
 
-CFLAGS         += -g -DHAVE_CONFIG_H -DVERSION="\"$(VERSION)\""
+CFLAGS         += -g -DHAVE_CONFIG_H
 CFLAGS         += -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings
 PREFIX          = /usr/local
 WWWPREFIX       = /var/www
@@ -390,31 +390,32 @@ config.h: config.h.pre config.h.post
        rm -f config.log
        ( cat config.h.pre; \
          echo; \
-         if $(CC) $(CFLAGS) -Werror -o test-fgetln test-fgetln.c >> config.log 2>&1; then \
+         echo '#define VERSION "$(VERSION)"'; \
+         if $(CC) $(CFLAGS) -Werror -Wno-unused -o test-fgetln test-fgetln.c >> config.log 2>&1; then \
                echo '#define HAVE_FGETLN'; \
                rm test-fgetln; \
          fi; \
-         if $(CC) $(CFLAGS) -Werror -o test-strptime test-strptime.c >> config.log 2>&1; then \
+         if $(CC) $(CFLAGS) -Werror -Wno-unused -o test-strptime test-strptime.c >> config.log 2>&1; then \
                echo '#define HAVE_STRPTIME'; \
                rm test-strptime; \
          fi; \
-         if $(CC) $(CFLAGS) -Werror -o test-getsubopt test-getsubopt.c >> config.log 2>&1; then \
+         if $(CC) $(CFLAGS) -Werror -Wno-unused -o test-getsubopt test-getsubopt.c >> config.log 2>&1; then \
                echo '#define HAVE_GETSUBOPT'; \
                rm test-getsubopt; \
          fi; \
-         if $(CC) $(CFLAGS) -Werror -o test-strlcat test-strlcat.c >> config.log 2>&1; then \
+         if $(CC) $(CFLAGS) -Werror -Wno-unused -o test-strlcat test-strlcat.c >> config.log 2>&1; then \
                echo '#define HAVE_STRLCAT'; \
                rm test-strlcat; \
          fi; \
-         if $(CC) $(CFLAGS) -Werror -o test-mmap test-mmap.c >> config.log 2>&1; then \
+         if $(CC) $(CFLAGS) -Werror -Wno-unused -o test-mmap test-mmap.c >> config.log 2>&1; then \
                echo '#define HAVE_MMAP'; \
                rm test-mmap; \
          fi; \
-         if $(CC) $(CFLAGS) -Werror -o test-strlcpy test-strlcpy.c >> config.log 2>&1; then \
+         if $(CC) $(CFLAGS) -Werror -Wno-unused -o test-strlcpy test-strlcpy.c >> config.log 2>&1; then \
                echo '#define HAVE_STRLCPY'; \
                rm test-strlcpy; \
          fi; \
-         if $(CC) $(CFLAGS) -Werror -o test-betoh64 test-betoh64.c >> config.log 2>&1; then \
+         if $(CC) $(CFLAGS) -Werror -Wno-unused -o test-betoh64 test-betoh64.c >> config.log 2>&1; then \
                echo '#define HAVE_BETOH64'; \
                rm test-betoh64; \
          fi; \
index 784b89b..6f21a38 100644 (file)
@@ -1,7 +1,35 @@
-$Id: NEWS,v 1.2 2013/10/05 13:15:51 schwarze Exp $
+$Id: NEWS,v 1.3 2013/10/13 16:06:50 schwarze Exp $
 
 This file lists the most important changes in the mdocml.bsd.lv distribution.
 
+Changes in version 1.12.3, released on December 31, 2013
+
+ * In the mdoc(7) SYNOPSIS, line breaks and hanging indentation
+   now work correctly for .Fo/.Fa/.Fc and .Fn blocks.
+   Thanks to Franco Fichtner for doing part of the work.
+ * The mdoc(7) .Bk macro got some addititonal bugfixes.
+ * In mdoc(7) macro arguments, double quotes can now be quoted
+   by doubling them, just like in man(7).
+   Thanks to Tsugutomo ENAMI for the patch.
+ * At the end of man(7) macro lines, end-of-sentence spacing
+   now works.  Thanks to Franco Fichtner for the patch.
+ * For backward compatibility, the man(7) parser now supports the
+   man-ext .UR/.UE (uniform resource identifier) block macros.
+ * The man(7) parser now handles closing blocks that are not open
+   more gracefully.
+ * The man(7) parser now ignores blank lines right after .SH and .SS.
+ * In the man(7) formatter, reset indentation when leaving a block,
+   not just when entering the next one.
+ * The roff(7) .nr request now supports incrementing and decrementing
+   number registers and stops parsing the number right before the
+   first non-digit character.
+ * The roff(7) parser now supports the alternative escape sequence
+   syntax \C'uXXXX' for Unicode characters.
+ * The roff(7) parser now parses and ignores the .fam (font family)
+   and .hw (hyphenation points) requests and the \d and \u escape
+   sequences.
+ * The roff(7) manual got a new ESCAPE SEQUENCE REFERENCE.
+
 Changes in version 1.12.2, released on Oktober 5, 2013
 
  * The mdoc(7) to man(7) converter, to be called as mandoc -Tman,
@@ -130,13 +158,16 @@ Changes in version 1.11.1, released on April 4, 2011
  * The earlier libroff, libmdoc, and libman soup have been merged into
    a single library, libmandoc, which manages all aspects of parsing
    real manuals, from line-handling to tbl(7) parsing.
- * Beyond this structural change, initial eqn(7) functionality is in
-   place.  For the time being, this is limited to the recognition of
-   equation blocks; future version of mdocml will expand upon this
-   framework.
  * As usual, many general fixes and improvements have also occurred.
    In particular, a great deal of redundancy and superfluous code has
    been removed with the merging of the backend libraries.
+ * see also the changes in 1.10.10
+
+Changes in version 1.10.10, March 20, 2011, NOT released
+
+ * Initial eqn(7) functionality is in place.  For the time being,
+   this is limited to the recognition of equation blocks;
+   future version of mdocml will expand upon this framework.
 
 Changes in version 1.10.9, released on January 7, 2011
 
@@ -150,19 +181,23 @@ Changes in version 1.10.9, released on January 7, 2011
 
 Changes in version 1.10.8, released on December 24, 2010
 
- * Significant improvements merged from OpenBSD downstream, including
-    - many new roff(7) components,
-    - in-line implementation of troff's soelim(1),
-    - broken-block handling,
-    - overhauled error classifications, and
-    - cleaned up handling of error conditions.
- * Also overhauled the -Thtml and -Txhtml output modes.  They now display
+ * Overhauled the -Thtml and -Txhtml output modes.  They now display
    readable output in arbitrary browsers, including text-based ones like
    lynx(1).  See HTML and XHTML manuals in the DOCUMENTATION section
    for examples.  Attention: available style-sheet classes have been
    considerably changed!  See the example.style.css file for details.
    Lastly, libmdoc and libman have been cleaned up and reduced in size
    and complexity.
+ * see also the changes in 1.10.7
+
+Changes in version 1.10.7, December 6, 2010, NOT released
+
+ Significant improvements merged from OpenBSD downstream, including:
+ * many new roff(7) components,
+ * in-line implementation of troff's soelim(1),
+ * broken-block handling,
+ * overhauled error classifications, and
+ * cleaned up handling of error conditions.
 
 Changes in version 1.10.6, released on September 27, 2010
 
@@ -194,12 +229,16 @@ Changes in version 1.10.4, released on July 12, 2010
  * Lots of features developed during both "Summer of Code" and the
    OpenBSD c2k10 hackathon:
  * minimal "ds" roff(7) symbols are supported
- * "Bk" mdoc(7) support
  * beautified SYNOPSIS section output
- * variable font-width and paper-size support in mandoc(1) -Tps output
  * acceptance of scope-block breakage in mdoc(7)
  * clarify error message status
  * many minor bug-fixes and formatting issues resolved
+ * see also changes in 1.10.3
+
+Changes in version 1.10.3, June 29, 2010, NOT released
+
+ * variable font-width and paper-size support in mandoc(1) -Tps output
+ * "Bk" mdoc(7) support
 
 Changes in version 1.10.2, released on June 19, 2010
 
index 0aebbd3..26f42c2 100644 (file)
@@ -1,19 +1,13 @@
 ************************************************************************
 * Official mandoc TODO.
-* $Id: TODO,v 1.157 2013/09/27 21:12:34 schwarze Exp $
+* $Id: TODO,v 1.162 2013/12/25 14:40:34 schwarze Exp $
 ************************************************************************
 
 ************************************************************************
 * crashes
 ************************************************************************
 
-- .Bl -tag followed by a text node preceding the first .It should not
-  throw a FATAL error, but only a normal ERROR.  Putting this into the
-  HEAD of an implicit .It might be cleanest, inserting an implicit .Pp
-  or just dumping the orphan stuff directly into the BODY of the .Bl
-  might be easier to implement, and all options can no doubt be made
-  to yield correct (i.e. groff bug-compatible) rendering.
-  Anthony J. Bentley on discuss@  Sun, 22 Sep 2013 16:33:21 -0600
+None known.
 
 ************************************************************************
 * missing features
 - .fc (field control)
   found by naddy@ in xloadimage(1)
   
+- .ll (line length)
+  found by naddy@ in textproc/enchant(1)  Sat, 12 Oct 2013 03:27:10 +0200
+
+- .nr third argument (auto-increment step size, requires \n+)
+  found by bentley@ in sbcl(1)  Mon, 9 Dec 2013 18:36:57 -0700
+
 - .ns (no-space mode) occurs in xine-config(1)
   reported by brad@  Sat, 15 Jan 2011 15:45:23 -0500
 
@@ -67,6 +67,9 @@
   found in cclive(1) DocBook output
   Anthony J. Bentley on discuss@  Sat, 21 Sep 2013 22:29:34 -0600
 
+- \n+ and \n- numerical register increment and decrement
+  found by bentley@ in sbcl(1)  Mon, 9 Dec 2013 18:36:57 -0700
+
 - using undefined strings or macros defines them to be empty
   wl@  Mon, 14 Nov 2011 14:37:01 +0000
 
 
 --- missing misc features ----------------------------------------------
 
+- italic correction (\/) in PostScript mode
+  Werner LEMBERG on groff at gnu dot org  Sun, 10 Nov 2013 12:47:46
+
 - The whatis(1) utility looks for whole words in Nm.
   If the file name of a page does not agree with the contents of any
   of its Nm macros (e.g. pool(9)), add the file name as an Nm entry
   noted by stsp@  Sat, 24 Apr 2010 09:17:55 +0200
   reminded by nicm@  Mon, 3 May 2010 09:52:41 +0100
 
+- look at pages generated from Texinfo source by yat2m, e.g. security/gnupg
+  First impression is not that bad.
+
 - check compatibility with Plan9:
   http://swtch.com/usr/local/plan9/tmac/tmac.an
   http://swtch.com/plan9port/man/man7/man.html
 - a column list with blank `Ta' cells triggers a spurrious
   start-with-whitespace printing of a newline
 
-- double quotes inside double quotes are escaped by doubling them
-  implement this in mdoc(7), too
-  so far, we only have it in roff(7) and man(7)
-  reminded by millert@  Thu, 09 Dec 2010 17:29:52 -0500
-
 - In .Bl -column,
   .It Em Authentication<tab>Key Length
   ought to render "Key Length" with emphasis, too,
   That is, when it is alone on a line between two .Pp,
   we want three blank lines, not two as in mandoc.
 
-- When .Fn arguments exceed one output line, all but the first
-  should be indented, see e.g. rpc(3);
-  reported by jmc@ on discuss@  Fri, 29 Oct 2010 13:48:33 +0100
-  reported again by Nicolas Joly via wiz@  Sun, 18 Sep 2011 18:24:40 +0200
-  Also, we don't want to break the line within the argument of:
-  .Fa "chtype tl"
-
 - Header lines of excessive length:
   Port OpenBSD man_term.c rev. 1.25 to mdoc_term.c
   and document it in mdoc(7) and man(7) COMPATIBILITY
index 61002ee..786fc7b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: apropos_db.c,v 1.32.2.1 2013/10/02 21:03:26 schwarze Exp $ */
+/*     $Id: apropos_db.c,v 1.32.2.3 2013/10/10 23:43:04 schwarze Exp $ */
 /*
  * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
 #include <string.h>
 #include <unistd.h>
 
-#if defined(__linux__)
-# include <endian.h>
-# include <db_185.h>
-#elif defined(__APPLE__)
+#if defined(__APPLE__)
 # include <libkern/OSByteOrder.h>
-# include <db.h>
+#elif defined(__linux__)
+# include <endian.h>
+#elif defined(__sun)
+# include <sys/byteorder.h>
 #else
 # include <sys/endian.h>
+#endif
+
+#if defined(__linux__) || defined(__sun)
+# include <db_185.h>
+#else
 # include <db.h>
 #endif
 
@@ -414,11 +419,10 @@ apropos_search(int pathsz, char **paths, const struct opts *opts,
 {
        struct rectree   tree;
        struct mchars   *mc;
-       int              i, rc;
+       int              i;
 
        memset(&tree, 0, sizeof(struct rectree));
 
-       rc = 0;
        mc = mchars_alloc();
        *sz = 0;
        *resp = NULL;
index c755d27..8767e5e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: catman.c,v 1.11 2012/06/08 10:33:48 kristaps Exp $ */
+/*     $Id: catman.c,v 1.11.2.2 2013/10/11 00:06:48 schwarze Exp $ */
 /*
  * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -31,7 +31,7 @@
 #include <string.h>
 #include <unistd.h>
 
-#ifdef __linux__
+#if defined(__linux__) || defined(__sun)
 # include <db_185.h>
 #else
 # include <db.h>
@@ -212,9 +212,6 @@ indexhtml(char *src, size_t ssz, char *dst, size_t dsz)
        const char      *f;
        char            *d;
        char             fname[MAXPATHLEN];
-       pid_t            pid;
-
-       pid = -1;
 
        xstrlcpy(fname, dst, MAXPATHLEN);
        xstrlcat(fname, "/", MAXPATHLEN);
index 6d40fcd..64bde45 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: cgi.c,v 1.45 2013/06/05 02:00:26 schwarze Exp $ */
+/*     $Id: cgi.c,v 1.46 2013/10/11 00:06:48 schwarze Exp $ */
 /*
  * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
  *
 #include <string.h>
 #include <unistd.h>
 
+#if defined(__sun)
+/* for stat() */
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+
 #include "apropos_db.h"
 #include "mandoc.h"
 #include "mdoc.h"
@@ -42,7 +49,7 @@
 #include "manpath.h"
 #include "mandocdb.h"
 
-#ifdef __linux__
+#if defined(__linux__) || defined(__sun)
 # include <db_185.h>
 #else
 # include <db.h>
@@ -1097,11 +1104,20 @@ static int
 pathstop(DIR *dir)
 {
        struct dirent   *d;
+#if defined(__sun)
+       struct stat      sb;
+#endif
 
-       while (NULL != (d = readdir(dir)))
+       while (NULL != (d = readdir(dir))) {
+#if defined(__sun)
+               stat(d->d_name, &sb);
+               if (S_IFREG & sb.st_mode)
+#else
                if (DT_REG == d->d_type)
+#endif
                        if (0 == strcmp(d->d_name, "catman.conf"))
                                return(1);
+  }
 
        return(0);
 }
@@ -1118,6 +1134,9 @@ pathgen(DIR *dir, char *path, struct req *req)
        DIR             *cd;
        int              rc;
        size_t           sz, ssz;
+#if defined(__sun)
+       struct stat      sb;
+#endif
 
        sz = strlcat(path, "/", PATH_MAX);
        if (sz >= PATH_MAX) {
@@ -1133,7 +1152,13 @@ pathgen(DIR *dir, char *path, struct req *req)
 
        rc = 0;
        while (0 == rc && NULL != (d = readdir(dir))) {
-               if (DT_DIR != d->d_type || strcmp(d->d_name, "etc"))
+#if defined(__sun)
+               stat(d->d_name, &sb);
+               if (!(S_IFDIR & sb.st_mode)
+#else
+               if (DT_DIR != d->d_type
+#endif
+        || strcmp(d->d_name, "etc"))
                        continue;
 
                path[(int)sz] = '\0';
@@ -1182,7 +1207,13 @@ pathgen(DIR *dir, char *path, struct req *req)
 
        rewinddir(dir);
        while (NULL != (d = readdir(dir))) {
-               if (DT_DIR != d->d_type || '.' == d->d_name[0])
+#if defined(__sun)
+               stat(d->d_name, &sb);
+               if (!(S_IFDIR & sb.st_mode)
+#else
+               if (DT_DIR != d->d_type
+#endif
+        || '.' == d->d_name[0])
                        continue;
 
                path[(int)sz] = '\0';
index cee82aa..9a33671 100644 (file)
@@ -19,6 +19,9 @@
 #  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
index e716635..83a43a7 100644 (file)
@@ -7,6 +7,7 @@
        </HEAD>
        <BODY>
                <P CLASS="head">
+                       <A HREF="http://www.openbsd.org/"><IMG SRC="puffy.gif" ALT="Puffy" WIDTH="100" HEIGHT="91" STYLE="float: right"></A>
                        <B>mdocml</B> &#8211; UNIX manpage compiler, current version @VERSION@ (@VDATE@)
                </P>
                <P CLASS="subhead">
                <P>
                        <SPAN CLASS="nm">mdocml</SPAN> is a suite of tools compiling <I><A HREF="mdoc.7.html">mdoc</A></I>, the roff macro
                        package of choice for BSD manual pages, and <I><A HREF="man.7.html">man</A></I>, the predominant historical package for
-                       UNIX manuals.  The mission of <SPAN CLASS="nm">mdocml</SPAN> is to deprecate <A
-                       HREF="http://www.gnu.org/software/groff/" CLASS="external">groff</A>, the GNU troff implementation, for displaying <I>mdoc</I>
-                       pages whilst providing token support for <I>man</I>.
+                       UNIX manuals.
+                       It is small, ISO C, <A CLASS="external" HREF="http://www.isc.org/software/license">ISC</A>-licensed, and quite fast.
                </P>
                <P>
-                       Why?  groff amounts to over 5 MB of source code, most of which is C++ and GPL version 3.  It runs slowly, produces
-                       uncertain output, and varies in operation from system to system.  mdocml strives to fix this (respectively small, C, <A
-                       CLASS="external" HREF="http://www.isc.org/software/license">ISC</A>-licensed, fast and regular).
-               </P>
-               <P>
-                       <SPAN CLASS="nm">mdocml</SPAN> consists of the <A HREF="mandoc.3.html">libmandoc</A> validating compiler and <A
-                       HREF="mandoc.1.html">mandoc</A>, which interfaces with the compiler library to format output for UNIX terminals (with
+                       The tool set features <A HREF="mandoc.1.html">mandoc</A>,
+                       based on the <A HREF="mandoc.3.html">libmandoc</A> validating compiler,
+                       to format output for UNIX terminals (with
                        support for wide-character locales), XHTML, HTML, PostScript, and PDF.  
                        It also includes <A HREF="preconv.1.html">preconv</A>, for recoding multibyte manuals; 
                        <A HREF="demandoc.1.html">demandoc</A>, for emitting only text parts of manuals;
                        <A HREF="mandocdb.8.html">mandocdb</A>, for indexing manuals; and
                        <A HREF="apropos.1.html">apropos</A>, <A HREF="whatis.1.html">whatis</A>, and
                        <A HREF="man.cgi.7.html">man.cgi</A> (via <A HREF="catman.8.html">catman</A>) for semantic search of manual content.
-                       It is a <A CLASS="external" HREF="http://bsd.lv/">BSD.lv</A> project.  
+               </P>
+               <P>
+                       <SPAN CLASS="nm">mdocml</SPAN> has predominantly been developed on OpenBSD
+                       and is both an <A CLASS="external" HREF="http://www.openbsd.org/">OpenBSD</A>
+                       and a <A CLASS="external" HREF="http://bsd.lv/">BSD.lv</A> project.  
+                       We strive to support all interested free operating systems, in particular
+                       <A CLASS="external" HREF="http://www.dragonflybsd.org/">DragonFly</A>,
+                       <A CLASS="external" HREF="http://www.netbsd.org/">NetBSD</A>,
+                       <A CLASS="external" HREF="http://www.freebsd.org/">FreeBSD</A>,
+                       <A CLASS="external" HREF="http://www.minix3.org/">Minix 3</A>,
+                       and <A CLASS="external" HREF="http://www.gnu.org/">GNU</A>/Linux,
+                       as well as all systems running the <A CLASS="external" HREF="http://www.pkgsrc.org/">pkgsrc</A> portable package build system.
+                       All of these projects have helped to make <SPAN CLASS="nm">mdocml</SPAN> better, by providing feedback and advice,
+                       bug reports, and patches.
                </P>
                <P>
                        <I>Disambiguation</I>: <SPAN CLASS="nm">mdocml</SPAN> is often referred to by its installed binary, <Q>mandoc</Q>.
                        <A NAME="sources">Sources</A>
                </H2>
                <P>
-                       <SPAN CLASS="nm">mdocml</SPAN> is in plain-old ANSI C and should build and run on any modern system; however, you'll
-                       need <A HREF="http://www.oracle.com/technetwork/database/berkeleydb/overview/index.html">libdb</A> to build <A
-                       HREF="apropos.1.html">apropos</A>, <A HREF="whatis.1.html">whatis</A>, <A HREF="man.cgi.7.html">man.cgi</A>, <A
-                       HREF="catman.8.html">catman</A>, and <A HREF="mandocdb.8.html">mandocdb</A> (this is installed by default on BSD UNIX
-                       systems &mdash; see the <I>Makefile</I> if you're running Linux).  To build and install into <I>/usr/local/</I>, just
-                       run <CODE>make install</CODE>.  Be careful: the <B>preconv</B>, <B>apropos</B>, and <B>whatis</B> binary names are
-                       usually taken by existing utilities.
+                       <SPAN CLASS="nm">mdocml</SPAN> should build and run on any modern system with
+                       <A HREF="http://www.oracle.com/technetwork/database/berkeleydb/overview/index.html">libdb</A>
+                       (this is installed by default on BSD UNIX systems &mdash; see the <I>Makefile</I> if you're running Linux).
+                       To build and install into <I>/usr/local/</I>, just run <CODE>make install</CODE>.
+                       Be careful: the <B>preconv</B>, <B>apropos</B>, and <B>whatis</B> installed binary names
+                       may be taken by existing utilities.
                </P>
                <H2>
                        Downstream
@@ -61,8 +69,7 @@
                <P>
                        Several systems come bundled with <SPAN CLASS="nm">mdocml</SPAN> utilities.
                        If your system does not appear below, the maintainers have not contacted me and it should not be considered
-                       <Q>official</Q>.
-                       Please <A HREF="#contact">contact us</A> if you plan on maintaining a downstream version!
+                       <Q>official</Q>, so please <A HREF="#contact">contact us</A> if you plan on maintaining a downstream version!
                </P>
                <TABLE WIDTH="100%" SUMMARY="Downstream Sources">
                        <COL WIDTH="175">
@@ -71,7 +78,7 @@
                                <TR>
                                        <TD>DragonFly BSD</TD>
                                        <TD>
-                                       <A HREF="http://gitweb.dragonflybsd.org/dragonfly.git/tree/HEAD:/contrib/mdocml" CLASS="external">contrib/mdocml</A> (1.12.1 sources)
+                                       <A HREF="http://gitweb.dragonflybsd.org/dragonfly.git/tree/HEAD:/contrib/mdocml" CLASS="external">contrib/mdocml</A> (1.12.3 sources)
                                        <A HREF="http://gitweb.dragonflybsd.org/dragonfly.git/tree/HEAD:/lib/libmandoc" CLASS="external">lib/libmandoc</A>
                                        <A HREF="http://gitweb.dragonflybsd.org/dragonfly.git/tree/HEAD:/usr.bin/mandoc" CLASS="external">usr.bin/mandoc</A> (build system)
                                        </TD>
@@ -86,7 +93,7 @@
                                <TR>
                                        <TD>FreeBSD 9.x, 8.x</TD>
                                        <TD>
-                                       <A HREF="http://svnweb.freebsd.org/ports/textproc/mdocml/" CLASS="external">ports/textproc/mdocml</A> (1.12.1 port)
+                                       <A HREF="http://svnweb.freebsd.org/ports/head/textproc/mdocml/" CLASS="external">ports/textproc/mdocml</A> (1.12.2 port)
                                        </TD>
                                </TR>
                                <TR>
                                <TR>
                                        <TD>OpenBSD</TD>
                                        <TD>
-                                       <A HREF="http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/mandoc/" CLASS="external">src/usr.bin/mandoc</A> (1.12.2 sources and build system)
+                                       <A HREF="http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/mandoc/" CLASS="external">src/usr.bin/mandoc</A> (1.12.3 sources under active development and build system)
                                        </TD>
                                </TR>
                                <TR>
                                        <TD>pkgsrc</TD>
                                        <TD>
-                                       <A HREF="http://pkgsrc.se/textproc/mdocml" CLASS="external">textproc/mdocml</A> (1.12.0 port)
+                                       <A HREF="http://pkgsrc.se/textproc/mdocml" CLASS="external">textproc/mdocml</A> (1.12.2 port)
                                        </TD>
                                </TR>
                                <TR>
                                <TR>
                                        <TD>Alpine Linux</TD>
                                        <TD>
-                                       <A HREF="http://git.alpinelinux.org/cgit/aports/tree/main/mdocml" CLASS="external">aports/main/mdocml</A> (1.12.1 port)
+                                       <A HREF="http://git.alpinelinux.org/cgit/aports/tree/main/mdocml" CLASS="external">aports/main/mdocml</A> (1.12.2 port)
                                        </TD>
                                </TR>
                        </TBODY>
                                </TR>
                        </TBODY>
                </TABLE>
+               <H2>
+                       <A NAME="links">Supplementary Information</A>
+               </H2>
+               <UL>
+                       <LI>
+                               <A HREF="http://manpages.bsd.lv/">Practical UNIX Manuals</A>: mdoc tutorial by Kristaps Dzonsons
+                       </LI>
+                       <LI>
+                               <A HREF="http://www.openbsd.org/faq/ports/specialtopics.html#Mandoc" CLASS="external">OpenBSD porting guide</A>
+                               chapter regarding manual pages
+                       </LI>
+                       <LI>
+                               <A HREF="press.html">Publications and media coverage</A>
+                               concerning mdocml and mandoc
+                       </LI>
+                       <LI>
+                               <A HREF="http://manpages.bsd.lv/history.html">History of UNIX Manpages</A>: a comprehensive overview by Kristaps Dzonsons
+                       </LI>
+               </UL>
                <H1>
                        <A NAME="contact">Contact</A>
                </H1>
                        <A NAME="news">News</A>
                </H1>
                <P CLASS="news">
-                       02-10-2013: version 1.12.2
+                       31-12-2013: version 1.12.3
+               </P>
+               <P>
+                       In the <A HREF="mdoc.7.html">mdoc(7)</A> SYNOPSIS, line breaks and hanging indentation
+                       now work correctly for .Fo/.Fa/.Fc and .Fn blocks.
+                       Thanks to Franco Fichtner for doing part of the work.
+               </P>
+               <P>
+                       The <A HREF="mdoc.7.html">mdoc(7)</A> .Bk macro got some addititonal bugfixes.
+               </P>
+               <P>
+                       In <A HREF="mdoc.7.html">mdoc(7)</A> macro arguments, double quotes can now be quoted 
+                       by doubling them, just like in <A HREF="man.7.html">man(7)</A>.  
+                       Thanks to Tsugutomo ENAMI for the patch.
+               </P>
+               <P>
+                       At the end of <A HREF="man.7.html">man(7)</A> macro lines, end-of-sentence spacing
+                       now works.  Thanks to Franco Fichtner for the patch.
+               </P>
+               <P>
+                       For backward compatibility, the <A HREF="man.7.html">man(7)</A> parser now supports the
+                       man-ext .UR/.UE (uniform resource identifier) block macros.
+               </P>
+               <P>
+                       The <A HREF="man.7.html">man(7)</A> parser now handles closing blocks that are not open
+                       more gracefully.
+               </P>
+               <P>
+                       The <A HREF="man.7.html">man(7)</A> parser now ignores blank lines right after .SH and .SS.
+               </P>
+               <P>
+                       In the <A HREF="man.7.html">man(7)</A> formatter, reset indentation when leaving a block,
+                       not just when entering the next one.
+               </P>
+               <P>
+                       The <A HREF="roff.7.html">roff(7)</A> .nr request now supports incrementing and decrementing
+                       number registers and stops parsing the number right before the first non-digit character.
+               </P>
+               <P>
+                       The <A HREF="roff.7.html">roff(7)</A> parser now supports the alternative escape sequence
+                       syntax \C'uXXXX' for Unicode characters.
+               </P>
+               <P>
+                       The <A HREF="roff.7.html">roff(7)</A> parser now parses and ignores the .fam (font family) 
+                       and .hw (hyphenation points) requests and the \d and \u escape sequences.                  
+               </P>
+               <P>
+                       The <A HREF="roff.7.html">roff(7)</A> manual got a new ESCAPE SEQUENCE REFERENCE.
+               </P>
+               <P CLASS="news">
+                       05-10-2013: version 1.12.2
                </P>
                <P>
                        The <A HREF="mdoc.7.html">mdoc(7)</A> to <A HREF="man.7.html">man(7)</A> converter,
                        For mandoc developers, we now provide a <A HREF="tbl.3.html">tbl(3)</A> library manual and <CODE>gmdiff</CODE>,
                        a very small, very simplistic groff-versus-mandoc output comparison tool.
                </P>
-               <P>
-                       See <A HREF="NEWS">NEWS</A> for historical notes.
-               </P>
-               <P CLASS="news">
-                       23-03-2011: version 1.12.1
-               </P>
-               <P>
-                       Significant work on <A HREF="apropos.1.html">apropos</A> and <A HREF="mandocdb.8.html">mandocdb</A>.  These tools are
-                       now much more robust.  
-                       A <A HREF="whatis.1.html">whatis</A> implementation is now handled as an <A HREF="apropos.1.html">apropos</A> mode.
-                       These tools are also able to minimally handle pre-formatted pages, that is, those already formatted by another utility
-                       such as GNU troff.
-               </P>
-               <P>
-                       The <A HREF="man.cgi.7.html">man.cgi</A> script is also now available for wider testing.  It interfaces with <A
-                       HREF="mandocdb.8.html">mandocdb</A> manuals cached by <A HREF="catman.8.html">catman</A>.  HTML output is generated
-                       on-the-fly by <A HREF="mandoc.3.html">libmandoc</A> or internal methods to convert pre-formatted pages.
-               </P>
-               <P>
-                       The mailing list archive for the discuss and tech lists are being hosted by <A CLASS="external"
-                       HREF="http://www.gmane.org">Gmane</A> at <A HREF="http://dir.gmane.org/gmane.comp.tools.mdocml.user"
-                       CLASS="external">gmane.comp.tools.mdocml.user</A> and <A HREF="http://dir.gmane.org/gmane.comp.tools.mdocml.devel"
-                       CLASS="external">gmane.comp.tools.mdocml.devel</A>, respectively.
-               </P>
-               <P>
-                       Lastly, I'm no longer providing binaries, as nobody has asked for them.
-               </P>
-               <P>
-                       See <A HREF="http://mdocml.bsd.lv/cgi-bin/cvsweb/index.sgml?cvsroot=mdocml">cvsweb</A> for
-                       historical notes.
-               </P>
+               <H2>
+                       <A>History</A>
+               </H2>
+               <UL>
+                       <LI>
+                               <A HREF="NEWS">Release notes</A> going back to release 1.9.15, February 18, 2010.
+                               Briefly explaining the most important changes in each release in relatively easy terms.
+                               Very many changes are not mentioned here.
+                       </LI>
+                       <LI>
+                               <A HREF="history.html">Development history</A> going back to the beginning of the project, November 22, 2008.
+                               One-line entries for important commits, releases, merges, hackathons and talks.
+                               Makes it easy to find out who did what, and when, and when it became available where.
+                               However, this is still incomplete, mentioning only a small fraction of all commits,
+                               and to keep the size down, the individual entries are extremely terse and technical.
+                               Feel free to look up more details and longer explanations about individual entries
+                               in the ChangeLog or in CVS.
+                       </LI>
+                       <LI>
+                               <A HREF="ChangeLog">CVS ChangeLog</A> going back to the beginning of the project.
+                               Very technical information of varying quality, strictly chronological.
+                               All commits are mentioned, but some messages neglect to mention some changes.
+                               Partly terse, partly detailed and verbose.  In any case, the ChangeLog is very long -
+                               more than 25,000 lines, more than 700 kB.
+                       </LI>
+                       <LI>
+                               <A HREF="/cgi-bin/cvsweb/?cvsroot=mdocml">CVS</A> web interface, going back to the beginning of the project.
+                               Source code, diffs and commit messages for each source file.  The real thing.
+                       </LI>
+               </UL>
                <P CLASS="foot">
                        <SMALL>
                                Copyright &#169; 2008&#8211;2011 
                                <A CLASS="external" HREF="http://kristaps.bsd.lv">Kristaps Dzonsons</A>, 
                                &#169; 2013 Ingo Schwarze,
-                               $Date: 2013/10/05 14:05:09 $
+                               $Date: 2013/12/31 $
                        </SMALL>
                </P>
        </BODY>
index 230a465..334e093 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: lib.in,v 1.13 2012/01/28 23:46:28 joerg Exp $ */
+/*     $Id: lib.in,v 1.17 2013/10/13 15:24:03 schwarze Exp $ */
 /*
  * Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
  *
  * Be sure to escape strings.
  */
 
-LINE("libarchive",     "Reading and Writing Streaming Archives Library (libarchive, \\-larchive)")
+LINE("libalias",       "Packet Aliasing Library (libalias, \\-lalias)")
+LINE("libarchive",     "Streaming Archive Library (libarchive, \\-larchive)")
 LINE("libarm",         "ARM Architecture Library (libarm, \\-larm)")
 LINE("libarm32",       "ARM32 Architecture Library (libarm32, \\-larm32)")
 LINE("libbluetooth",   "Bluetooth Library (libbluetooth, \\-lbluetooth)")
+LINE("libbsdxml",      "eXpat XML parser library (libbsdxml, \\-lbsdxml)")
 LINE("libbsm",         "Basic Security Module User Library (libbsm, \\-lbsm)")
 LINE("libc",           "Standard C Library (libc, \\-lc)")
 LINE("libc_r",         "Reentrant C\\~Library (libc_r, \\-lc_r)")
@@ -37,17 +39,24 @@ LINE("libcipher",   "FreeSec Crypt Library (libcipher, \\-lcipher)")
 LINE("libcompat",      "Compatibility Library (libcompat, \\-lcompat)")
 LINE("libcrypt",       "Crypt Library (libcrypt, \\-lcrypt)")
 LINE("libcurses",      "Curses Library (libcurses, \\-lcurses)")
+LINE("libdevattr",     "Device attribute and event library (libdevattr, \\-ldevattr)")
 LINE("libdevinfo",     "Device and Resource Information Utility Library (libdevinfo, \\-ldevinfo)")
 LINE("libdevstat",     "Device Statistics Library (libdevstat, \\-ldevstat)")
 LINE("libdisk",                "Interface to Slice and Partition Labels Library (libdisk, \\-ldisk)")
+LINE("libdm",          "Device Mapper Library (libdm, \\-ldm)")
 LINE("libdwarf",       "DWARF Access Library (libdwarf, \\-ldwarf)")
 LINE("libedit",                "Command Line Editor Library (libedit, \\-ledit)")
+LINE("libefi",         "EFI Runtime Services Library (libefi, \\-lefi)")
 LINE("libelf",         "ELF Access Library (libelf, \\-lelf)")
 LINE("libevent",       "Event Notification Library (libevent, \\-levent)")
-LINE("libfetch",       "File Transfer Library for URLs (libfetch, \\-lfetch)")
+LINE("libexecinfo",    "Backtrace Information Library (libexecinfo, \\-lexecinfo)")
+LINE("libfetch",       "File Transfer Library (libfetch, \\-lfetch)")
+LINE("libfsid",                "Filesystem Identification Library (libfsid, \\-lfsid)")
+LINE("libftpio",       "FTP Connection Management Library (libftpio, \\-lftpio)")
 LINE("libform",                "Curses Form Library (libform, \\-lform)")
-LINE("libgeom",                "Userland API Library for kernel GEOM subsystem (libgeom, \\-lgeom)")
+LINE("libgeom",                "Userland API Library for Kernel GEOM subsystem (libgeom, \\-lgeom)")
 LINE("libgpib",                "General-Purpose Instrument Bus (GPIB) library (libgpib, \\-lgpib)")
+LINE("libhammer",      "HAMMER Filesystem Userland Library (libhammer, \\-lhammer)")
 LINE("libi386",                "i386 Architecture Library (libi386, \\-li386)")
 LINE("libintl",                "Internationalized Message Handling Library (libintl, \\-lintl)")
 LINE("libipsec",       "IPsec Policy Control Library (libipsec, \\-lipsec)")
@@ -55,37 +64,49 @@ LINE("libipx",              "IPX Address Conversion Support Library (libipx, \\-lipx)")
 LINE("libiscsi",       "iSCSI protocol library (libiscsi, \\-liscsi)")
 LINE("libisns",                "Internet Storage Name Service Library (libisns, \\-lisns)")
 LINE("libjail",                "Jail Library (libjail, \\-ljail)")
-LINE("libkiconv",      "Kernel side iconv library (libkiconv, \\-lkiconv)")
+LINE("libkcore",       "Kernel Memory Core Access Library (libkcore, \\-lkcore)")
+LINE("libkiconv",      "Kernel-side iconv Library (libkiconv, \\-lkiconv)")
 LINE("libkse",         "N:M Threading Library (libkse, \\-lkse)")
 LINE("libkvm",         "Kernel Data Access Library (libkvm, \\-lkvm)")
 LINE("libm",           "Math Library (libm, \\-lm)")
 LINE("libm68k",                "m68k Architecture Library (libm68k, \\-lm68k)")
 LINE("libmagic",       "Magic Number Recognition Library (libmagic, \\-lmagic)")
+LINE("libmandoc",      "Mandoc Macro Compiler Library (libmandoc, \\-lmandoc)")
 LINE("libmd",          "Message Digest (MD4, MD5, etc.) Support Library (libmd, \\-lmd)")
 LINE("libmemstat",     "Kernel Memory Allocator Statistics Library (libmemstat, \\-lmemstat)")
 LINE("libmenu",                "Curses Menu Library (libmenu, \\-lmenu)")
+LINE("libmj",          "Minimalist JSON library (libmj, \\-lmj)")
 LINE("libnetgraph",    "Netgraph User Library (libnetgraph, \\-lnetgraph)")
-LINE("libnetpgp",      "Netpgp signing, verification, encryption and decryption (libnetpgp, \\-lnetpgp)")
+LINE("libnetpgp",      "Netpgp Signing, Verification, Encryption and Decryption (libnetpgp, \\-lnetpgp)")
+LINE("libnetpgpverify",        "Netpgp Verification (libnetpgpverify, \\-lnetpgpverify)")
+LINE("libnpf",         "NPF Packet Filter Library (libnpf, \\-lnpf)")
 LINE("libossaudio",    "OSS Audio Emulation Library (libossaudio, \\-lossaudio)")
 LINE("libpam",         "Pluggable Authentication Module Library (libpam, \\-lpam)")
 LINE("libpcap",                "Capture Library (libpcap, \\-lpcap)")
 LINE("libpci",         "PCI Bus Access Library (libpci, \\-lpci)")
 LINE("libpmc",         "Performance Counters Library (libpmc, \\-lpmc)")
+LINE("libppath",       "Property-List Paths Library (libppath, \\-lppath)")
 LINE("libposix",       "POSIX Compatibility Library (libposix, \\-lposix)")
+LINE("libposix1e",     "POSIX.1e Security API Library (libposix1e, \\-lposix1e)")
 LINE("libppath",       "Property-List Paths Library (libppath, \\-lppath)")
 LINE("libprop",                "Property Container Object Library (libprop, \\-lprop)")
 LINE("libpthread",     "POSIX Threads Library (libpthread, \\-lpthread)")
 LINE("libpuffs",       "puffs Convenience Library (libpuffs, \\-lpuffs)")
 LINE("libquota",       "Disk Quota Access and Control Library (libquota, \\-lquota)")
+LINE("libradius",      "RADIUS Client Library (libradius, \\-lradius)")
 LINE("librefuse",      "File System in Userspace Convenience Library (librefuse, \\-lrefuse)")
 LINE("libresolv",      "DNS Resolver Library (libresolv, \\-lresolv)")
 LINE("librpcsec_gss",  "RPC GSS-API Authentication Library (librpcsec_gss, \\-lrpcsec_gss)")
 LINE("librpcsvc",      "RPC Service Library (librpcsvc, \\-lrpcsvc)")
 LINE("librt",          "POSIX Real\\-time Library (librt, \\-lrt)")
+LINE("librumpclient",  "Clientside Stubs for rump Kernel Remote Protocols (librumpclient, \\-lrumpclient)")
 LINE("libsaslc",       "Simple Authentication and Security Layer client library (libsaslc, \\-lsaslc)")
 LINE("libsdp",         "Bluetooth Service Discovery Protocol User Library (libsdp, \\-lsdp)")
 LINE("libssp",         "Buffer Overflow Protection Library (libssp, \\-lssp)")
+LINE("libstand",       "Standalone Applications Library (libstand, \\-lstand)")
 LINE("libSystem",      "System Library (libSystem, \\-lSystem)")
+LINE("libtacplus",     "TACACS+ Client Library (libtacplus, \\-ltacplus)")
+LINE("libtcplay",      "TrueCrypt-compatible API library (libtcplay, \\-ltcplay)")
 LINE("libtermcap",     "Termcap Access Library (libtermcap, \\-ltermcap)")
 LINE("libterminfo",    "Terminal Information Library (libterminfo, \\-lterminfo)")
 LINE("libthr",         "1:1 Threading Library (libthr, \\-lthr)")
index 9b3ffee..3c005e1 100644 (file)
@@ -1,6 +1,7 @@
-/*     $Id: libmandoc.h,v 1.32 2012/11/19 17:57:23 schwarze Exp $ */
+/*     $Id: libmandoc.h,v 1.35 2013/12/15 21:23:52 schwarze Exp $ */
 /*
  * Copyright (c) 2009, 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -29,11 +30,6 @@ enum rofferr {
        ROFF_ERR /* badness: puke and stop */
 };
 
-enum   regs {
-       REG_nS = 0, /* nS register */
-       REG__MAX
-};
-
 __BEGIN_DECLS
 
 struct roff;
@@ -72,9 +68,8 @@ void           roff_reset(struct roff *);
 enum rofferr    roff_parseln(struct roff *, int, 
                        char **, size_t *, int, int *);
 void            roff_endparse(struct roff *);
-int             roff_regisset(const struct roff *, enum regs);
-unsigned int    roff_regget(const struct roff *, enum regs);
-void            roff_regunset(struct roff *, enum regs);
+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 *, 
                        const char *, int *);
index 8a389a4..3f14519 100644 (file)
@@ -1,6 +1,7 @@
-/*     $Id: libmdoc.h,v 1.81 2012/11/17 00:26:33 schwarze Exp $ */
+/*     $Id: libmdoc.h,v 1.82 2013/10/21 23:47:58 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -34,6 +35,8 @@ struct        mdoc {
 #define        MDOC_PPHRASE     (1 << 5) /* within a partial phrase */
 #define        MDOC_FREECOL     (1 << 6) /* `It' invocation should close */
 #define        MDOC_SYNOPSIS    (1 << 7) /* SYNOPSIS-style formatting */
+#define        MDOC_KEEP        (1 << 8) /* in a word keep */
+#define        MDOC_SMOFF       (1 << 9) /* spacing is off */
        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 */
@@ -57,8 +60,8 @@ struct        mdoc_macro {
 #define        MDOC_PARSED      (1 << 1)
 #define        MDOC_EXPLICIT    (1 << 2)
 #define        MDOC_PROLOGUE    (1 << 3)
-#define        MDOC_IGNDELIM    (1 << 4) 
-       /* Reserved words in arguments treated as text. */
+#define        MDOC_IGNDELIM    (1 << 4)
+#define        MDOC_JOIN        (1 << 5)
 };
 
 enum   margserr {
@@ -107,6 +110,7 @@ __BEGIN_DECLS
 int              mdoc_macro(MACRO_PROT_ARGS);
 int              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, 
                        enum mdoct, struct mdoc_arg *);
 int              mdoc_block_alloc(struct mdoc *, int, int, 
index 24ffc63..e6e1c28 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: man.c,v 1.119 2012/11/17 00:26:33 schwarze Exp $ */
+/*     $Id: man.c,v 1.121 2013/11/10 22:54:40 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -40,7 +40,8 @@ const char *const __man_macronames[MAN_MAX] = {
        "RI",           "na",           "sp",           "nf",
        "fi",           "RE",           "RS",           "DT",
        "UC",           "PD",           "AT",           "in",
-       "ft",           "OP",           "EX",           "EE"
+       "ft",           "OP",           "EX",           "EE",
+       "UR",           "UE"
        };
 
 const  char * const *man_macronames = __man_macronames;
@@ -428,16 +429,22 @@ man_ptext(struct man *man, int line, char *buf, int offs)
                return(man_descope(man, line, offs));
        }
 
-       /* Pump blank lines directly into the backend. */
-
        for (i = offs; ' ' == buf[i]; i++)
                /* Skip leading whitespace. */ ;
 
+       /*
+        * Blank lines are ignored right after headings
+        * but add a single vertical space elsewhere.
+        */
+
        if ('\0' == buf[i]) {
                /* Allocate a blank entry. */
-               if ( ! man_elem_alloc(man, line, offs, MAN_sp))
-                       return(0);
-               man->next = MAN_NEXT_SIBLING;
+               if (MAN_SH != man->last->tok &&
+                   MAN_SS != man->last->tok) {
+                       if ( ! man_elem_alloc(man, line, offs, MAN_sp))
+                               return(0);
+                       man->next = MAN_NEXT_SIBLING;
+               }
                return(1);
        }
 
index e85da9a..ef9480f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: man.h,v 1.61 2012/06/02 20:16:23 schwarze Exp $ */
+/*     $Id: man.h,v 1.62 2013/10/17 20:54:58 schwarze Exp $ */
 /*
  * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -54,6 +54,8 @@ enum  mant {
        MAN_OP,
        MAN_EX,
        MAN_EE,
+       MAN_UR,
+       MAN_UE,
        MAN_MAX
 };
 
index 100188b..2c4e220 100644 (file)
@@ -1,6 +1,7 @@
-/*     $Id: man_html.c,v 1.89 2012/11/17 00:26:33 schwarze Exp $ */
+/*     $Id: man_html.c,v 1.90 2013/10/17 20:54:58 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -70,6 +71,7 @@ static        int               man_RS_pre(MAN_ARGS);
 static int               man_SH_pre(MAN_ARGS);
 static int               man_SM_pre(MAN_ARGS);
 static int               man_SS_pre(MAN_ARGS);
+static int               man_UR_pre(MAN_ARGS);
 static int               man_alt_pre(MAN_ARGS);
 static int               man_br_pre(MAN_ARGS);
 static int               man_ign_pre(MAN_ARGS);
@@ -115,6 +117,8 @@ static      const struct htmlman mans[MAN_MAX] = {
        { man_OP_pre, NULL }, /* OP */
        { man_literal_pre, NULL }, /* EX */
        { man_literal_pre, NULL }, /* EE */
+       { man_UR_pre, NULL }, /* UR */
+       { NULL, NULL }, /* UE */
 };
 
 /*
@@ -688,3 +692,27 @@ man_RS_pre(MAN_ARGS)
        print_otag(h, TAG_DIV, 1, &tag);
        return(1);
 }
+
+/* ARGSUSED */
+static int
+man_UR_pre(MAN_ARGS)
+{
+       struct htmlpair          tag[2];
+
+       n = n->child;
+       assert(MAN_HEAD == n->type);
+       if (n->nchild) {
+               assert(MAN_TEXT == n->child->type);
+               PAIR_CLASS_INIT(&tag[0], "link-ext");
+               PAIR_HREF_INIT(&tag[1], n->child->string);
+               print_otag(h, TAG_A, 2, tag);
+       }
+
+       assert(MAN_BODY == n->next->type);
+       if (n->next->nchild)
+               n = n->next;
+
+       print_man_nodelist(man, n->child, mh, h);
+
+       return(0);
+}
index 6631f14..479d048 100644 (file)
@@ -1,7 +1,8 @@
-/*     $Id: man_macro.c,v 1.75 2012/11/17 00:26:33 schwarze Exp $ */
+/*     $Id: man_macro.c,v 1.79 2013/12/25 00:50:05 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2012 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -88,6 +89,8 @@ const struct man_macro __man_macros[MAN_MAX] = {
        { in_line_eoln, 0 }, /* OP */
        { in_line_eoln, MAN_BSCOPE }, /* EX */
        { in_line_eoln, MAN_BSCOPE }, /* EE */
+       { blk_exp, MAN_BSCOPE | MAN_EXPLICIT }, /* UR */
+       { blk_close, 0 }, /* UE */
 };
 
 const  struct man_macro * const man_macros = __man_macros;
@@ -284,6 +287,9 @@ blk_close(MACRO_PROT_ARGS)
        case (MAN_RE):
                ntok = MAN_RS;
                break;
+       case (MAN_UE):
+               ntok = MAN_UR;
+               break;
        default:
                abort();
                /* NOTREACHED */
@@ -293,10 +299,12 @@ blk_close(MACRO_PROT_ARGS)
                if (ntok == nn->tok && MAN_BLOCK == nn->type)
                        break;
 
-       if (NULL != nn)
-               man_unscope(man, nn, MANDOCERR_MAX);
-       else
+       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);
 }
@@ -425,6 +433,15 @@ in_line_eoln(MACRO_PROT_ARGS)
        }
 
        /*
+        * Append MAN_EOS in case the last snipped argument
+        * ends with a dot, e.g. `.IR syslog (3).'
+        */
+
+       if (n != man->last &&
+           mandoc_eos(man->last->string, strlen(man->last->string), 0))
+               man->last->flags |= MAN_EOS;
+
+       /*
         * If no arguments are specified and this is MAN_SCOPED (i.e.,
         * next-line scoped), then set our mode to indicate that we're
         * waiting for terms to load into our context.
index db5719c..4bd6244 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: man_term.c,v 1.136 2013/01/05 22:19:12 schwarze Exp $ */
+/*     $Id: man_term.c,v 1.139 2013/12/22 23:34:13 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
@@ -78,6 +78,7 @@ static        int               pre_RS(DECL_ARGS);
 static int               pre_SH(DECL_ARGS);
 static int               pre_SS(DECL_ARGS);
 static int               pre_TP(DECL_ARGS);
+static int               pre_UR(DECL_ARGS);
 static int               pre_alternate(DECL_ARGS);
 static int               pre_ft(DECL_ARGS);
 static int               pre_ign(DECL_ARGS);
@@ -91,6 +92,7 @@ static        void              post_RS(DECL_ARGS);
 static void              post_SH(DECL_ARGS);
 static void              post_SS(DECL_ARGS);
 static void              post_TP(DECL_ARGS);
+static void              post_UR(DECL_ARGS);
 
 static const struct termact termacts[MAN_MAX] = {
        { pre_sp, NULL, MAN_NOTEXT }, /* br */
@@ -129,6 +131,8 @@ static      const struct termact termacts[MAN_MAX] = {
        { pre_OP, NULL, 0 }, /* OP */
        { pre_literal, NULL, 0 }, /* EX */
        { pre_literal, NULL, 0 }, /* EE */
+       { pre_UR, post_UR, 0 }, /* UR */
+       { NULL, NULL, 0 }, /* UE */
 };
 
 
@@ -261,7 +265,8 @@ pre_literal(DECL_ARGS)
        if (MAN_HP == n->parent->tok && p->rmargin < p->maxrmargin) {
                p->offset = p->rmargin;
                p->rmargin = p->maxrmargin;
-               p->flags &= ~(TERMP_NOBREAK | TERMP_TWOSPACE);
+               p->trailspace = 0;
+               p->flags &= ~TERMP_NOBREAK;
                p->flags |= TERMP_NOSPACE;
        }
 
@@ -531,7 +536,7 @@ pre_HP(DECL_ARGS)
 
        if ( ! (MANT_LITERAL & mt->fl)) {
                p->flags |= TERMP_NOBREAK;
-               p->flags |= TERMP_TWOSPACE;
+               p->trailspace = 2;
        }
 
        len = mt->lmargin[mt->lmargincur];
@@ -566,7 +571,7 @@ post_HP(DECL_ARGS)
        case (MAN_BODY):
                term_newln(p);
                p->flags &= ~TERMP_NOBREAK;
-               p->flags &= ~TERMP_TWOSPACE;
+               p->trailspace = 0;
                p->offset = mt->offset;
                p->rmargin = p->maxrmargin;
                break;
@@ -609,6 +614,7 @@ pre_IP(DECL_ARGS)
                break;
        case (MAN_HEAD):
                p->flags |= TERMP_NOBREAK;
+               p->trailspace = 1;
                break;
        case (MAN_BLOCK):
                print_bvspace(p, n, mt->pardist);
@@ -671,10 +677,12 @@ post_IP(DECL_ARGS)
        case (MAN_HEAD):
                term_flushln(p);
                p->flags &= ~TERMP_NOBREAK;
+               p->trailspace = 0;
                p->rmargin = p->maxrmargin;
                break;
        case (MAN_BODY):
                term_newln(p);
+               p->offset = mt->offset;
                break;
        default:
                break;
@@ -693,6 +701,7 @@ pre_TP(DECL_ARGS)
        switch (n->type) {
        case (MAN_HEAD):
                p->flags |= TERMP_NOBREAK;
+               p->trailspace = 1;
                break;
        case (MAN_BODY):
                p->flags |= TERMP_NOSPACE;
@@ -740,8 +749,8 @@ pre_TP(DECL_ARGS)
        case (MAN_BODY):
                p->offset = mt->offset + len;
                p->rmargin = p->maxrmargin;
+               p->trailspace = 0;
                p->flags &= ~TERMP_NOBREAK;
-               p->flags &= ~TERMP_TWOSPACE;
                break;
        default:
                break;
@@ -762,6 +771,7 @@ post_TP(DECL_ARGS)
                break;
        case (MAN_BODY):
                term_newln(p);
+               p->offset = mt->offset;
                break;
        default:
                break;
@@ -939,6 +949,32 @@ post_RS(DECL_ARGS)
                mt->lmargincur = mt->lmarginsz;
 }
 
+/* ARGSUSED */
+static int
+pre_UR(DECL_ARGS)
+{
+
+       return (MAN_HEAD != n->type);
+}
+
+/* ARGSUSED */
+static void
+post_UR(DECL_ARGS)
+{
+
+       if (MAN_BLOCK != n->type)
+               return;
+
+       term_word(p, "<");
+       p->flags |= TERMP_NOSPACE;
+
+       if (NULL != n->child->child)
+               print_man_node(p, mt, n->child->child, meta);
+
+       p->flags |= TERMP_NOSPACE;
+       term_word(p, ">");
+}
+
 static void
 print_man_node(DECL_ARGS)
 {
@@ -1069,6 +1105,7 @@ print_man_foot(struct termp *p, const void *arg)
        /* Bottom left corner: manual source. */
 
        p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
+       p->trailspace = 1;
        p->offset = 0;
        p->rmargin = (p->maxrmargin - datelen + term_len(p, 1)) / 2;
 
@@ -1091,6 +1128,7 @@ print_man_foot(struct termp *p, const void *arg)
 
        p->flags &= ~TERMP_NOBREAK;
        p->flags |= TERMP_NOSPACE;
+       p->trailspace = 0;
        p->offset = p->rmargin;
        p->rmargin = p->maxrmargin;
 
@@ -1122,6 +1160,7 @@ print_man_head(struct termp *p, const void *arg)
        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 - 
@@ -1144,6 +1183,7 @@ print_man_head(struct termp *p, const void *arg)
        /* Top right corner: title and section, again. */
 
        p->flags &= ~TERMP_NOBREAK;
+       p->trailspace = 0;
        if (p->rmargin + titlen <= p->maxrmargin) {
                p->flags |= TERMP_NOSPACE;
                p->offset = p->rmargin;
index 7a9deed..da2e557 100644 (file)
@@ -1,7 +1,7 @@
-/*     $Id: man_validate.c,v 1.85 2012/11/17 00:26:33 schwarze Exp $ */
+/*     $Id: man_validate.c,v 1.86 2013/10/17 20:54:58 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012, 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
@@ -49,6 +49,7 @@ 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);
@@ -80,6 +81,7 @@ 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] = {
@@ -119,6 +121,8 @@ static      const struct man_valid man_valids[MAN_MAX] = {
        { NULL, posts_eq2 }, /* OP */
        { NULL, posts_nf }, /* EX */
        { NULL, posts_fi }, /* EE */
+       { NULL, posts_ur }, /* UR */
+       { NULL, NULL }, /* UE */
 };
 
 
@@ -246,6 +250,17 @@ INEQ_DEFINE(2, >=, ge2)
 INEQ_DEFINE(5, <=, le5)
 
 static int
+check_head1(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);
+}
+
+static int
 post_ft(CHKARGS)
 {
        char    *cp;
index bc6aa90..fe6503d 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $Id: mandoc.3,v 1.20 2013/09/16 22:54:38 schwarze Exp $
+.\"    $Id: mandoc.3,v 1.22 2013/10/06 17:01:52 schwarze Exp $
 .\"
 .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
 .\" Copyright (c) 2010 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,7 +15,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: September 16 2013 $
+.Dd $Mdocdate: October 6 2013 $
 .Dt MANDOC 3
 .Os
 .Sh NAME
 .Nm mparse_strlevel
 .Nd mandoc macro compiler library
 .Sh LIBRARY
-.Lb mandoc
+.Lb libmandoc
 .Sh SYNOPSIS
 .In man.h
 .In mdoc.h
 .In mandoc.h
 .Ft "enum mandoc_esc"
 .Fo mandoc_escape
-.Fa "const char **end"
-.Fa "const char **start"
+.Fa "const char const **end"
+.Fa "const char const **start"
 .Fa "int *sz"
 .Fc
 .Ft "const struct man_meta *"
index df51022..da738f2 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: mandoc.c,v 1.68 2013/08/08 20:07:47 schwarze Exp $ */
+/*     $Id: mandoc.c,v 1.74 2013/12/30 18:30:32 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
@@ -93,12 +93,23 @@ mandoc_escape(const char **end, const char **start, int *sz)
        case ('C'):
                if ('\'' != **start)
                        return(ESCAPE_ERROR);
-               gly = ESCAPE_SPECIAL;
                *start = ++*end;
+               if ('u' == (*start)[0] && '\'' != (*start)[1])
+                       gly = ESCAPE_UNICODE;
+               else
+                       gly = ESCAPE_SPECIAL;
                term = '\'';
                break;
 
        /*
+        * Escapes taking no arguments at all.
+        */
+       case ('d'):
+               /* FALLTHROUGH */
+       case ('u'):
+               return(ESCAPE_IGNORE);
+
+       /*
         * The \z escape is supposed to output the following
         * character without advancing the cursor position.  
         * Since we are mostly dealing with terminal mode,
@@ -154,12 +165,16 @@ mandoc_escape(const char **end, const char **start, int *sz)
                /* FALLTHROUGH */
        case ('b'):
                /* FALLTHROUGH */
+       case ('B'):
+               /* FALLTHROUGH */
        case ('D'):
                /* FALLTHROUGH */
        case ('o'):
                /* FALLTHROUGH */
        case ('R'):
                /* FALLTHROUGH */
+       case ('w'):
+               /* FALLTHROUGH */
        case ('X'):
                /* FALLTHROUGH */
        case ('Z'):
@@ -174,8 +189,6 @@ mandoc_escape(const char **end, const char **start, int *sz)
         * These escapes are of the form \X'N', where 'X' is the trigger
         * and 'N' resolves to a numerical expression.
         */
-       case ('B'):
-               /* FALLTHROUGH */
        case ('h'):
                /* FALLTHROUGH */
        case ('H'):
@@ -183,19 +196,15 @@ mandoc_escape(const char **end, const char **start, int *sz)
        case ('L'):
                /* FALLTHROUGH */
        case ('l'):
-               gly = ESCAPE_NUMBERED;
                /* FALLTHROUGH */
        case ('S'):
                /* FALLTHROUGH */
        case ('v'):
                /* FALLTHROUGH */
-       case ('w'):
-               /* FALLTHROUGH */
        case ('x'):
                if ('\'' != **start)
                        return(ESCAPE_ERROR);
-               if (ESCAPE_ERROR == gly)
-                       gly = ESCAPE_IGNORE;
+               gly = ESCAPE_IGNORE;
                *start = ++*end;
                term = '\'';
                break;
@@ -416,10 +425,10 @@ mandoc_strdup(const char *ptr)
  * Parse a quoted or unquoted roff-style request or macro argument.
  * Return a pointer to the parsed argument, which is either the original
  * pointer or advanced by one byte in case the argument is quoted.
- * Null-terminate the argument in place.
+ * NUL-terminate the argument in place.
  * Collapse pairs of quotes inside quoted arguments.
  * Advance the argument pointer to the next argument,
- * or to the null byte terminating the argument line.
+ * or to the NUL byte terminating the argument line.
  */
 char *
 mandoc_getarg(struct mparse *parse, char **cpp, int ln, int *pos)
@@ -490,7 +499,7 @@ mandoc_getarg(struct mparse *parse, char **cpp, int ln, int *pos)
        if (1 == quoted)
                mandoc_msg(MANDOCERR_BADQUOTE, parse, ln, *pos, NULL);
 
-       /* Null-terminate this argument and move to the next one. */
+       /* NUL-terminate this argument and move to the next one. */
        if (pairs)
                cp[-pairs] = '\0';
        if ('\0' != *cp) {
index c2406e9..4c6a32f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: mandoc.h,v 1.110 2013/09/16 00:25:07 schwarze Exp $ */
+/*     $Id: mandoc.h,v 1.112 2013/12/30 18:30:32 schwarze Exp $ */
 /*
  * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
index 23ccc0a..8d83566 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $Id: mandoc_char.7,v 1.53 2013/07/13 19:41:16 schwarze Exp $
+.\"    $Id: mandoc_char.7,v 1.56 2013/12/26 17:23:42 schwarze Exp $
 .\"
 .\" Copyright (c) 2003 Jason McIntyre <jmc@openbsd.org>
 .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -16,7 +16,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: July 13 2013 $
+.Dd $Mdocdate: December 26 2013 $
 .Dt MANDOC_CHAR 7
 .Os
 .Sh NAME
@@ -98,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\e1
 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 roff 7 .
+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&
@@ -194,14 +195,13 @@ manual.
 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:
@@ -655,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
@@ -730,9 +735,9 @@ The
 manual page was written by
 .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 7 ;
index 028377c..a7491ca 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: mandocdb.c,v 1.49.2.7 2013/10/02 21:03:26 schwarze Exp $ */
+/*     $Id: mandocdb.c,v 1.49.2.10 2013/11/21 01:53:48 schwarze Exp $ */
 /*
  * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2011, 2012 Ingo Schwarze <schwarze@openbsd.org>
 #include <string.h>
 #include <unistd.h>
 
-#if defined(__linux__) || defined(__sun)
-# include <endian.h>
-# include <db_185.h>
-#elif defined(__APPLE__)
+#if defined(__APPLE__)
 # include <libkern/OSByteOrder.h>
-# include <db.h>
+#elif defined(__linux__)
+# include <endian.h>
+#elif defined(__sun)
+# include <sys/byteorder.h>
+# include <sys/stat.h>
 #else
 # include <sys/endian.h>
-# include <db.h>
 #endif
 
-#if defined(__sun)
-#include <sys/stat.h>
+#if defined(__linux__) || defined(__sun)
+# include <db_185.h>
+#else
+# include <db.h>
 #endif
 
 #include "man.h"
@@ -620,6 +622,8 @@ index_merge(const struct of *of, struct mparse *mp,
        uint64_t         vbuf[2];
        char             type;
 
+       static char      emptystring[] = "";
+
        if (warnings) {
                files = NULL;
                hash_reset(&files);
@@ -732,13 +736,13 @@ index_merge(const struct of *of, struct mparse *mp,
                        }
                        buf_appendb(buf, ")", 2);
                        for (p = buf->cp; '\0' != *p; p++)
-                               *p = tolower(*p);
+                               *p = tolower((unsigned char)*p);
                        key.data = buf->cp;
                        key.size = buf->len;
                        val.data = NULL;
                        val.size = 0;
                        if (0 == skip)
-                               val.data = "";
+                               val.data = emptystring;
                        else {
                                ch = (*files->get)(files, &key, &val, 0);
                                if (ch < 0) {
index 9008932..c33e0ec 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: manpath.c,v 1.11 2013/06/05 02:00:26 schwarze Exp $ */
+/*     $Id: manpath.c,v 1.12 2013/11/21 01:49:18 schwarze Exp $ */
 /*
  * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -209,7 +209,7 @@ manpath_manconf(struct manpaths *dirs, const char *file)
                if (strncmp(MAN_CONF_KEY, p, keysz))
                        continue;
                p += keysz;
-               while (isspace(*p))
+               while (isspace((unsigned char)*p))
                        p++;
                if ('\0' == *p)
                        continue;
index 00e1a1a..165c76b 100644 (file)
@@ -1,7 +1,7 @@
-.\"    $Id: mdoc.7,v 1.220 2013/08/14 15:08:31 schwarze Exp $
+.\"    $Id: mdoc.7,v 1.223 2013/12/25 14:09:32 schwarze Exp $
 .\"
 .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
+.\" 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
@@ -15,7 +15,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: August 14 2013 $
+.Dd $Mdocdate: December 25 2013 $
 .Dt MDOC 7
 .Os
 .Sh NAME
@@ -477,6 +477,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:
@@ -1407,9 +1408,12 @@ 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
 .Dx
@@ -1570,15 +1574,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.
@@ -1859,7 +1880,7 @@ section as described in
 .Pp
 Examples:
 .Dl \&.Lb libz
-.Dl \&.Lb mdoc
+.Dl \&.Lb libmandoc
 .Ss \&Li
 Denotes text that should be in a
 .Li literal
@@ -2422,6 +2443,8 @@ The following standards are recognised:
 .St -xbd5
 .It \-xcu5
 .St -xcu5
+.It \-xsh4.2
+.St -xsh4.2
 .It \-xsh5
 .St -xsh5
 .It \-xns5
index df68229..87b3587 100644 (file)
@@ -1,7 +1,7 @@
-/*     $Id: mdoc.c,v 1.203 2012/11/17 00:26:33 schwarze Exp $ */
+/*     $Id: mdoc.c,v 1.206 2013/12/24 19:11:46 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012, 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
@@ -295,12 +295,10 @@ mdoc_parseln(struct mdoc *mdoc, int ln, char *buf, int offs)
         * whether this mode is on or off.
         * Note that this mode is also switched by the Sh macro.
         */
-       if (roff_regisset(mdoc->roff, REG_nS)) {
-               if (roff_regget(mdoc->roff, REG_nS))
-                       mdoc->flags |= MDOC_SYNOPSIS;
-               else
-                       mdoc->flags &= ~MDOC_SYNOPSIS;
-       }
+       if (roff_getreg(mdoc->roff, "nS"))
+               mdoc->flags |= MDOC_SYNOPSIS;
+       else
+               mdoc->flags &= ~MDOC_SYNOPSIS;
 
        return(roff_getcontrol(mdoc->roff, buf, &offs) ?
                        mdoc_pmacro(mdoc, ln, buf, offs) :
@@ -436,6 +434,7 @@ 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;
 
@@ -584,6 +583,23 @@ mdoc_word_alloc(struct mdoc *mdoc, int line, int pos, const char *p)
        return(1);
 }
 
+void
+mdoc_word_append(struct mdoc *mdoc, const char *p)
+{
+       struct mdoc_node        *n;
+       char                    *addstr, *newstr;
+
+       n = mdoc->last;
+       addstr = roff_strdup(mdoc->roff, p);
+       if (-1 == asprintf(&newstr, "%s %s", n->string, addstr)) {
+               perror(NULL);
+               exit((int)MANDOCLEVEL_SYSERR);
+       }
+       free(addstr);
+       free(n->string);
+       n->string = newstr;
+       mdoc->next = MDOC_NEXT_SIBLING;
+}
 
 static void
 mdoc_node_free(struct mdoc_node *p)
index cc807d7..d0153b4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: mdoc.h,v 1.124 2012/11/16 17:16:55 schwarze Exp $ */
+/*     $Id: mdoc.h,v 1.125 2013/12/24 19:11:45 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -351,6 +351,7 @@ 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 */
index 220260a..bb9bc6c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: mdoc_argv.c,v 1.86 2012/11/18 00:05:35 schwarze Exp $ */
+/*     $Id: mdoc_argv.c,v 1.89 2013/12/25 00:50:05 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2012 Ingo Schwarze <schwarze@openbsd.org>
@@ -260,7 +260,7 @@ static      const struct mdocarg mdocargs[MDOC_MAX] = {
        { ARGSFL_NONE, NULL }, /* %C */
        { ARGSFL_NONE, NULL }, /* Es */
        { ARGSFL_NONE, NULL }, /* En */
-       { ARGSFL_NONE, NULL }, /* Dx */
+       { ARGSFL_DELIM, NULL }, /* Dx */
        { ARGSFL_NONE, NULL }, /* %Q */
        { ARGSFL_NONE, NULL }, /* br */
        { ARGSFL_NONE, NULL }, /* sp */
@@ -447,6 +447,7 @@ args(struct mdoc *mdoc, int line, int *pos,
                char *buf, enum argsflag fl, char **v)
 {
        char            *p, *pp;
+       int              pairs;
        enum margserr    rc;
 
        if ('\0' == buf[*pos]) {
@@ -535,11 +536,13 @@ args(struct mdoc *mdoc, int line, int *pos,
                        /* Skip ahead. */ ;
 
                return(rc);
-       } 
+       }
 
-       /* 
+       /*
         * Process a quoted literal.  A quote begins with a double-quote
         * and ends with a double-quote NOT preceded by a double-quote.
+        * NUL-terminate the literal in place.
+        * Collapse pairs of quotes inside quoted literals.
         * Whitespace is NOT involved in literal termination.
         */
 
@@ -550,13 +553,22 @@ args(struct mdoc *mdoc, int line, int *pos,
                if (MDOC_PPHRASE & mdoc->flags)
                        mdoc->flags |= MDOC_PHRASELIT;
 
+               pairs = 0;
                for ( ; buf[*pos]; (*pos)++) {
+                       /* Move following text left after quoted quotes. */
+                       if (pairs)
+                               buf[*pos - pairs] = buf[*pos];
                        if ('\"' != buf[*pos])
                                continue;
+                       /* Unquoted quotes end quoted args. */
                        if ('\"' != buf[*pos + 1])
                                break;
+                       /* Quoted quotes collapse. */
+                       pairs++;
                        (*pos)++;
                }
+               if (pairs)
+                       buf[*pos - pairs] = '\0';
 
                if ('\0' == buf[*pos]) {
                        if (MDOC_PPHRASE & mdoc->flags)
index ba93749..a7aa722 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: mdoc_html.c,v 1.184 2012/11/17 00:26:33 schwarze Exp $ */
+/*     $Id: mdoc_html.c,v 1.186 2013/12/24 20:45:27 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -460,14 +460,10 @@ print_mdoc_node(MDOC_ARGS)
        }
 
        if (HTML_KEEP & h->flags) {
-               if (n->prev && n->prev->line != n->line) {
+               if (n->prev ? (n->prev->lastline != n->line) :
+                   (n->parent && n->parent->line != n->line)) {
                        h->flags &= ~HTML_KEEP;
                        h->flags |= HTML_PREKEEP;
-               } else if (NULL == n->prev) {
-                       if (n->parent && n->parent->line != n->line) {
-                               h->flags &= ~HTML_KEEP;
-                               h->flags |= HTML_PREKEEP;
-                       }
                }
        }
 
index 0a50486..2a63ca9 100644 (file)
@@ -1,7 +1,7 @@
-/*     $Id: mdoc_macro.c,v 1.122 2013/09/15 18:26:46 schwarze Exp $ */
+/*     $Id: mdoc_macro.c,v 1.125 2013/12/24 20:45:27 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012, 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
@@ -51,8 +51,8 @@ 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 *, enum mdelim);
+static int             dword(struct mdoc *, int, int, const char *,
+                                enum mdelim, int);
 static int             append_delims(struct mdoc *, 
                                int, int *, char *);
 static enum mdoct      lookup(enum mdoct, const char *);
@@ -70,128 +70,147 @@ static    int             rew_sub(enum mdoc_type, struct mdoc *,
                                enum mdoct, int, int);
 
 const  struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
-       { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ap */
+       { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ap */
        { in_line_eoln, MDOC_PROLOGUE }, /* Dd */
        { in_line_eoln, MDOC_PROLOGUE }, /* Dt */
        { in_line_eoln, MDOC_PROLOGUE }, /* Os */
-       { blk_full, MDOC_PARSED }, /* Sh */
-       { blk_full, MDOC_PARSED }, /* Ss */ 
-       { in_line_eoln, 0 }, /* Pp */ 
-       { blk_part_imp, MDOC_PARSED }, /* D1 */
-       { blk_part_imp, MDOC_PARSED }, /* Dl */
+       { blk_full, MDOC_PARSED | MDOC_JOIN }, /* Sh */
+       { blk_full, MDOC_PARSED | MDOC_JOIN }, /* Ss */
+       { in_line_eoln, 0 }, /* Pp */
+       { blk_part_imp, MDOC_PARSED | MDOC_JOIN }, /* D1 */
+       { blk_part_imp, MDOC_PARSED | MDOC_JOIN }, /* Dl */
        { blk_full, MDOC_EXPLICIT }, /* Bd */
-       { blk_exp_close, MDOC_EXPLICIT }, /* Ed */
+       { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ed */
        { blk_full, MDOC_EXPLICIT }, /* Bl */
-       { blk_exp_close, MDOC_EXPLICIT }, /* El */
-       { blk_full, MDOC_PARSED }, /* It */
-       { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */ 
-       { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* An */
+       { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* El */
+       { blk_full, MDOC_PARSED | MDOC_JOIN }, /* It */
+       { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */
+       { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* An */
        { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */
        { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cd */
        { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */
-       { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */ 
-       { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Er */ 
-       { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ev */ 
+       { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */
+       { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Er */
+       { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ev */
        { in_line_eoln, 0 }, /* Ex */
-       { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fa */ 
-       { in_line_eoln, 0 }, /* Fd */ 
+       { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Fa */
+       { in_line_eoln, 0 }, /* Fd */
        { 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 }, /* Fn */
+       { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ft */
+       { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ic */
        { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* In */
-       { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Li */
-       { blk_full, 0 }, /* Nd */ 
-       { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */ 
+       { 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 }, /* Pa */
        { in_line_eoln, 0 }, /* Rv */
-       { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* St */ 
+       { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* St */
        { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Va */
-       { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */ 
+       { ctx_synopsis, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */
        { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Xr */
-       { in_line_eoln, 0 }, /* %A */
-       { in_line_eoln, 0 }, /* %B */
-       { in_line_eoln, 0 }, /* %D */
-       { in_line_eoln, 0 }, /* %I */
-       { in_line_eoln, 0 }, /* %J */
+       { in_line_eoln, MDOC_JOIN }, /* %A */
+       { in_line_eoln, MDOC_JOIN }, /* %B */
+       { in_line_eoln, MDOC_JOIN }, /* %D */
+       { in_line_eoln, MDOC_JOIN }, /* %I */
+       { in_line_eoln, MDOC_JOIN }, /* %J */
        { in_line_eoln, 0 }, /* %N */
-       { in_line_eoln, 0 }, /* %O */
+       { in_line_eoln, MDOC_JOIN }, /* %O */
        { in_line_eoln, 0 }, /* %P */
-       { in_line_eoln, 0 }, /* %R */
-       { in_line_eoln, 0 }, /* %T */
+       { in_line_eoln, MDOC_JOIN }, /* %R */
+       { in_line_eoln, MDOC_JOIN }, /* %T */
        { in_line_eoln, 0 }, /* %V */
-       { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ac */
-       { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ao */
-       { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Aq */
+       { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
+                        MDOC_EXPLICIT | MDOC_JOIN }, /* Ac */
+       { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
+                       MDOC_EXPLICIT | MDOC_JOIN }, /* Ao */
+       { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Aq */
        { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* At */
-       { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Bc */
-       { blk_full, MDOC_EXPLICIT }, /* Bf */ 
-       { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bo */
-       { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Bq */
+       { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
+                        MDOC_EXPLICIT | MDOC_JOIN }, /* Bc */
+       { blk_full, MDOC_EXPLICIT }, /* Bf */
+       { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
+                       MDOC_EXPLICIT | MDOC_JOIN }, /* Bo */
+       { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Bq */
        { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bsx */
        { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Bx */
        { in_line_eoln, 0 }, /* Db */
-       { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Dc */
-       { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Do */
-       { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Dq */
-       { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ec */
-       { blk_exp_close, MDOC_EXPLICIT }, /* Ef */
-       { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Em */ 
+       { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
+                        MDOC_EXPLICIT | MDOC_JOIN }, /* Dc */
+       { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
+                       MDOC_EXPLICIT | MDOC_JOIN }, /* Do */
+       { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Dq */
+       { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ec */
+       { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ef */
+       { in_line, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Em */
        { 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 }, /* No */
-       { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* Ns */
+       { in_line_argn, MDOC_CALLABLE | MDOC_PARSED |
+                       MDOC_IGNDELIM | MDOC_JOIN }, /* No */
+       { in_line_argn, MDOC_CALLABLE | MDOC_PARSED |
+                       MDOC_IGNDELIM | MDOC_JOIN }, /* Ns */
        { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Nx */
        { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ox */
-       { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Pc */
+       { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
+                        MDOC_EXPLICIT | MDOC_JOIN }, /* Pc */
        { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_IGNDELIM }, /* Pf */
-       { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Po */
-       { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Pq */
-       { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Qc */
-       { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Ql */
-       { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Qo */
-       { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Qq */
-       { blk_exp_close, MDOC_EXPLICIT }, /* Re */
+       { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
+                       MDOC_EXPLICIT | MDOC_JOIN }, /* Po */
+       { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Pq */
+       { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
+                        MDOC_EXPLICIT | MDOC_JOIN }, /* Qc */
+       { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ql */
+       { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
+                       MDOC_EXPLICIT | MDOC_JOIN }, /* Qo */
+       { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Qq */
+       { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Re */
        { blk_full, MDOC_EXPLICIT }, /* Rs */
-       { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Sc */
-       { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* So */
-       { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Sq */
+       { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
+                        MDOC_EXPLICIT | MDOC_JOIN }, /* Sc */
+       { 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, MDOC_CALLABLE | MDOC_PARSED }, /* Sx */
-       { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sy */
+       { 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 */
-       { in_line_argn, MDOC_CALLABLE | MDOC_PARSED }, /* Ux */
+       { in_line_argn, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ux */
        { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Xc */
        { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Xo */
-       { blk_full, MDOC_EXPLICIT | MDOC_CALLABLE }, /* Fo */ 
-       { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Fc */ 
-       { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Oo */
-       { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Oc */
+       { blk_full, MDOC_EXPLICIT | MDOC_CALLABLE }, /* Fo */
+       { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
+                        MDOC_EXPLICIT | MDOC_JOIN }, /* Fc */
+       { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
+                       MDOC_EXPLICIT | MDOC_JOIN }, /* Oo */
+       { blk_exp_close, MDOC_CALLABLE | MDOC_PARSED |
+                        MDOC_EXPLICIT | MDOC_JOIN }, /* Oc */
        { blk_full, MDOC_EXPLICIT }, /* Bk */
-       { blk_exp_close, MDOC_EXPLICIT }, /* Ek */
+       { blk_exp_close, MDOC_EXPLICIT | MDOC_JOIN }, /* Ek */
        { in_line_eoln, 0 }, /* Bt */
        { in_line_eoln, 0 }, /* Hf */
        { obsolete, 0 }, /* Fr */
        { in_line_eoln, 0 }, /* Ud */
        { in_line, 0 }, /* Lb */
-       { in_line_eoln, 0 }, /* Lp */ 
-       { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Lk */ 
-       { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Mt */ 
-       { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED }, /* Brq */
-       { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bro */
-       { blk_exp_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Brc */
-       { in_line_eoln, 0 }, /* %C */
+       { in_line_eoln, 0 }, /* Lp */
+       { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Lk */
+       { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Mt */
+       { blk_part_imp, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Brq */
+       { blk_part_exp, MDOC_CALLABLE | MDOC_PARSED |
+                       MDOC_EXPLICIT | MDOC_JOIN }, /* Bro */
+       { 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 }, /* Dx */
-       { in_line_eoln, 0 }, /* %Q */
+       { 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 }, /* Ta */
+       { phrase_ta, MDOC_CALLABLE | MDOC_PARSED | MDOC_JOIN }, /* Ta */
 };
 
 const  struct mdoc_macro * const mdoc_macros = __mdoc_macros;
@@ -542,6 +561,9 @@ rew_sub(enum mdoc_type t, struct mdoc *mdoc,
                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, 
@@ -550,6 +572,8 @@ rew_sub(enum mdoc_type t, struct mdoc *mdoc,
                                        mdoc_macronames[n->tok]);
                        /* FALLTHROUGH */
                case (REWIND_MORE):
+                       n->lastline = line -
+                           (MDOC_NEWLINE & mdoc->flags ? 1 : 0);
                        n = n->parent;
                        continue;
                case (REWIND_LATER):
@@ -588,13 +612,21 @@ rew_sub(enum mdoc_type t, struct mdoc *mdoc,
  * Punctuation consists of those tokens found in mdoc_isdelim().
  */
 static int
-dword(struct mdoc *mdoc, int line, 
-               int col, const char *p, enum mdelim d)
+dword(struct mdoc *mdoc, int line, int col, const char *p,
+               enum mdelim d, int may_append)
 {
        
        if (DELIM_MAX == d)
                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_word_append(mdoc, p);
+               return(1);
+       }
+
        if ( ! mdoc_word_alloc(mdoc, line, col, p))
                return(0);
 
@@ -638,7 +670,7 @@ append_delims(struct mdoc *mdoc, int line, int *pos, char *buf)
                else if (ARGS_EOLN == ac)
                        break;
 
-               dword(mdoc, line, la, p, DELIM_MAX);
+               dword(mdoc, line, la, p, DELIM_MAX, 1);
 
                /*
                 * If we encounter end-of-sentence symbols, then trigger
@@ -680,6 +712,8 @@ blk_exp_close(MACRO_PROT_ARGS)
        case (MDOC_Ec):
                maxargs = 1;
                break;
+       case (MDOC_Ek):
+               mdoc->flags &= ~MDOC_KEEP;
        default:
                maxargs = 0;
                break;
@@ -782,7 +816,8 @@ blk_exp_close(MACRO_PROT_ARGS)
                ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
 
                if (MDOC_MAX == ntok) {
-                       if ( ! dword(mdoc, line, lastarg, p, DELIM_MAX))
+                       if ( ! dword(mdoc, line, lastarg, p, DELIM_MAX,
+                           MDOC_JOIN & mdoc_macros[tok].flags))
                                return(0);
                        continue;
                }
@@ -948,7 +983,8 @@ in_line(MACRO_PROT_ARGS)
                if (DELIM_NONE == d)
                        cnt++;
 
-               if ( ! dword(mdoc, line, la, p, d))
+               if ( ! dword(mdoc, line, la, p, d,
+                   MDOC_JOIN & mdoc_macros[tok].flags))
                        return(0);
 
                /*
@@ -1067,7 +1103,10 @@ blk_full(MACRO_PROT_ARGS)
                if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
                        return(0);
                body = mdoc->last;
-       } 
+       }
+
+       if (MDOC_Bk == tok)
+               mdoc->flags |= MDOC_KEEP;
 
        ac = ARGS_ERROR;
 
@@ -1112,7 +1151,7 @@ blk_full(MACRO_PROT_ARGS)
                                ARGS_PPHRASE != ac &&
                                ARGS_QWORD != ac &&
                                DELIM_OPEN == mdoc_isdelim(p)) {
-                       if ( ! dword(mdoc, line, la, p, DELIM_OPEN))
+                       if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0))
                                return(0);
                        continue;
                }
@@ -1165,7 +1204,8 @@ blk_full(MACRO_PROT_ARGS)
                        MDOC_MAX : lookup(tok, p);
 
                if (MDOC_MAX == ntok) {
-                       if ( ! dword(mdoc, line, la, p, DELIM_MAX))
+                       if ( ! dword(mdoc, line, la, p, DELIM_MAX,
+                           MDOC_JOIN & mdoc_macros[tok].flags))
                                return(0);
                        continue;
                }
@@ -1276,10 +1316,10 @@ blk_part_imp(MACRO_PROT_ARGS)
 
                if (NULL == body && ARGS_QWORD != ac &&
                                DELIM_OPEN == mdoc_isdelim(p)) {
-                       if ( ! dword(mdoc, line, la, p, DELIM_OPEN))
+                       if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0))
                                return(0);
                        continue;
-               } 
+               }
 
                if (NULL == body) {
                       if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
@@ -1290,7 +1330,8 @@ blk_part_imp(MACRO_PROT_ARGS)
                ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
 
                if (MDOC_MAX == ntok) {
-                       if ( ! dword(mdoc, line, la, p, DELIM_MAX))
+                       if ( ! dword(mdoc, line, la, p, DELIM_MAX,
+                           MDOC_JOIN & mdoc_macros[tok].flags))
                                return(0);
                        continue;
                }
@@ -1416,10 +1457,10 @@ blk_part_exp(MACRO_PROT_ARGS)
                if (NULL == head && ARGS_QWORD != ac &&
                                DELIM_OPEN == mdoc_isdelim(p)) {
                        assert(NULL == body);
-                       if ( ! dword(mdoc, line, la, p, DELIM_OPEN))
+                       if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0))
                                return(0);
                        continue;
-               } 
+               }
 
                if (NULL == head) {
                        assert(NULL == body);
@@ -1437,7 +1478,7 @@ blk_part_exp(MACRO_PROT_ARGS)
                        assert(head);
                        /* No check whether it's a macro! */
                        if (MDOC_Eo == tok)
-                               if ( ! dword(mdoc, line, la, p, DELIM_MAX))
+                               if ( ! dword(mdoc, line, la, p, DELIM_MAX, 0))
                                        return(0);
 
                        if ( ! rew_sub(MDOC_HEAD, mdoc, tok, line, ppos))
@@ -1455,7 +1496,8 @@ blk_part_exp(MACRO_PROT_ARGS)
                ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
 
                if (MDOC_MAX == ntok) {
-                       if ( ! dword(mdoc, line, la, p, DELIM_MAX))
+                       if ( ! dword(mdoc, line, la, p, DELIM_MAX,
+                           MDOC_JOIN & mdoc_macros[tok].flags))
                                return(0);
                        continue;
                }
@@ -1559,7 +1601,7 @@ in_line_argn(MACRO_PROT_ARGS)
                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))
+                       if ( ! dword(mdoc, line, la, p, DELIM_OPEN, 0))
                                return(0);
                        continue;
                } else if (0 == j)
@@ -1593,7 +1635,8 @@ in_line_argn(MACRO_PROT_ARGS)
                        flushed = 1;
                }
 
-               if ( ! dword(mdoc, line, la, p, DELIM_MAX))
+               if ( ! dword(mdoc, line, la, p, DELIM_MAX,
+                   MDOC_JOIN & mdoc_macros[tok].flags))
                        return(0);
                j++;
        }
@@ -1664,7 +1707,8 @@ in_line_eoln(MACRO_PROT_ARGS)
                ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup(tok, p);
 
                if (MDOC_MAX == ntok) {
-                       if ( ! dword(mdoc, line, la, p, DELIM_MAX))
+                       if ( ! dword(mdoc, line, la, p, DELIM_MAX,
+                           MDOC_JOIN & mdoc_macros[tok].flags))
                                return(0);
                        continue;
                }
@@ -1744,7 +1788,7 @@ phrase(struct mdoc *mdoc, int line, int ppos, char *buf)
                ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p);
 
                if (MDOC_MAX == ntok) {
-                       if ( ! dword(mdoc, line, la, p, DELIM_MAX))
+                       if ( ! dword(mdoc, line, la, p, DELIM_MAX, 1))
                                return(0);
                        continue;
                }
@@ -1795,7 +1839,8 @@ phrase_ta(MACRO_PROT_ARGS)
                ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p);
 
                if (MDOC_MAX == ntok) {
-                       if ( ! dword(mdoc, line, la, p, DELIM_MAX))
+                       if ( ! dword(mdoc, line, la, p, DELIM_MAX,
+                           MDOC_JOIN & mdoc_macros[tok].flags))
                                return(0);
                        continue;
                }
index 336791d..6ee8b3a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: mdoc_man.c,v 1.52 2013/09/15 18:48:31 schwarze Exp $ */
+/*     $Id: mdoc_man.c,v 1.57 2013/12/25 22:00:45 schwarze Exp $ */
 /*
  * Copyright (c) 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
  *
@@ -256,6 +256,7 @@ static      int             outflags;
 #define        MMAN_An_split   (1 << 9)  /* author mode is "split" */
 #define        MMAN_An_nosplit (1 << 10) /* author mode is "nosplit" */
 #define        MMAN_PD         (1 << 11) /* inter-paragraph spacing disabled */
+#define        MMAN_nbrword    (1 << 12) /* do not break the next word */
 
 #define        BL_STACK_MAX    32
 
@@ -364,6 +365,12 @@ print_word(const char *s)
                case (ASCII_HYPH):
                        putchar('-');
                        break;
+               case (' '):
+                       if (MMAN_nbrword & outflags) {
+                               printf("\\ ");
+                               break;
+                       }
+                       /* FALLTHROUGH */
                default:
                        putchar((unsigned char)*s);
                        break;
@@ -371,6 +378,7 @@ print_word(const char *s)
                if (TPremain)
                        TPremain--;
        }
+       outflags &= ~MMAN_nbrword;
 }
 
 static void
@@ -442,7 +450,7 @@ print_offs(const char *v)
        if (Bl_stack_len)
                sz += Bl_stack[Bl_stack_len - 1];
 
-       snprintf(buf, sizeof(buf), "%ldn", sz);
+       snprintf(buf, sizeof(buf), "%zun", sz);
        print_word(buf);
        outflags |= MMAN_nl;
 }
@@ -495,7 +503,7 @@ print_width(const char *v, const struct mdoc_node *child, size_t defsz)
                remain = sz + 2;
        }
        if (numeric) {
-               snprintf(buf, sizeof(buf), "%ldn", sz + 2);
+               snprintf(buf, sizeof(buf), "%zun", sz + 2);
                print_word(buf);
        } else
                print_word(v);
@@ -705,24 +713,12 @@ static int
 pre_sect(DECL_ARGS)
 {
 
-       switch (n->type) {
-       case (MDOC_HEAD):
+       if (MDOC_HEAD == n->type) {
                outflags |= MMAN_sp;
                print_block(manacts[n->tok].prefix, 0);
                print_word("");
                putchar('\"');
                outflags &= ~MMAN_spc;
-               break;
-       case (MDOC_BODY):
-               if (MDOC_Sh == n->tok) {
-                       if (MDOC_SYNPRETTY & n->flags)
-                               outflags |= MMAN_Bk;
-                       else
-                               outflags &= ~MMAN_Bk;
-               }
-               break;
-       default:
-               break;
        }
        return(1);
 }
@@ -900,7 +896,7 @@ static void
 post_bk(DECL_ARGS)
 {
 
-       if (MDOC_BODY == n->type && ! (MDOC_SYNPRETTY & n->flags))
+       if (MDOC_BODY == n->type)
                outflags &= ~MMAN_Bk;
 }
 
@@ -1034,12 +1030,17 @@ post_eo(DECL_ARGS)
 static int
 pre_fa(DECL_ARGS)
 {
+       int      am_Fa;
 
-       if (MDOC_Fa == n->tok)
+       am_Fa = MDOC_Fa == n->tok;
+
+       if (am_Fa)
                n = n->child;
 
        while (NULL != n) {
                font_push('I');
+               if (am_Fa || MDOC_SYNPRETTY & n->flags)
+                       outflags |= MMAN_nbrword;
                print_node(meta, n);
                font_pop();
                if (NULL != (n = n->next))
@@ -1103,6 +1104,9 @@ pre_fn(DECL_ARGS)
        if (NULL == n)
                return(0);
 
+       if (MDOC_SYNPRETTY & n->flags)
+               print_block(".HP 4n", MMAN_nl);
+
        font_push('B');
        print_node(meta, n);
        font_pop();
@@ -1123,7 +1127,7 @@ post_fn(DECL_ARGS)
        print_word(")");
        if (MDOC_SYNPRETTY & n->flags) {
                print_word(";");
-               outflags |= MMAN_br;
+               outflags |= MMAN_PP;
        }
 }
 
@@ -1136,6 +1140,8 @@ pre_fo(DECL_ARGS)
                pre_syn(n);
                break;
        case (MDOC_HEAD):
+               if (MDOC_SYNPRETTY & n->flags)
+                       print_block(".HP 4n", MMAN_nl);
                font_push('B');
                break;
        case (MDOC_BODY):
@@ -1148,7 +1154,7 @@ pre_fo(DECL_ARGS)
        }
        return(1);
 }
-               
+
 static void
 post_fo(DECL_ARGS)
 {
@@ -1294,7 +1300,7 @@ mid_it(void)
 
        /* Restore the indentation of the enclosing list. */
        print_line(".RS", MMAN_Bk_susp);
-       snprintf(buf, sizeof(buf), "%ldn", Bl_stack[Bl_stack_len - 1]);
+       snprintf(buf, sizeof(buf), "%zun", Bl_stack[Bl_stack_len - 1]);
        print_word(buf);
 
        /* Remeber to close out this .RS block later. */
@@ -1408,8 +1414,10 @@ pre_nm(DECL_ARGS)
 {
        char    *name;
 
-       if (MDOC_BLOCK == n->type)
+       if (MDOC_BLOCK == n->type) {
+               outflags |= MMAN_Bk;
                pre_syn(n);
+       }
        if (MDOC_ELEM != n->type && MDOC_HEAD != n->type)
                return(1);
        name = n->child ? n->child->string : meta->name;
@@ -1419,7 +1427,7 @@ pre_nm(DECL_ARGS)
                if (NULL == n->parent->prev)
                        outflags |= MMAN_sp;
                print_block(".HP", 0);
-               printf(" %ldn", strlen(name) + 1);
+               printf(" %zun", strlen(name) + 1);
                outflags |= MMAN_nl;
        }
        font_push('B');
@@ -1432,9 +1440,18 @@ static void
 post_nm(DECL_ARGS)
 {
 
-       if (MDOC_ELEM != n->type && MDOC_HEAD != n->type)
-               return;
-       font_pop();
+       switch (n->type) {
+       case (MDOC_BLOCK):
+               outflags &= ~MMAN_Bk;
+               break;
+       case (MDOC_HEAD):
+               /* FALLTHROUGH */
+       case (MDOC_ELEM):
+               font_pop();
+               break;
+       default:
+               break;
+       }
 }
 
 static int
index 99c5953..268fcae 100644 (file)
@@ -1,7 +1,8 @@
-/*     $Id: mdoc_term.c,v 1.249 2013/06/02 18:16:57 schwarze Exp $ */
+/*     $Id: mdoc_term.c,v 1.258 2013/12/25 21:24:12 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2013 Franco Fichtner <franco@lastsummer.de>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -100,7 +101,6 @@ static      int       termp_fl_pre(DECL_ARGS);
 static int       termp_fn_pre(DECL_ARGS);
 static int       termp_fo_pre(DECL_ARGS);
 static int       termp_ft_pre(DECL_ARGS);
-static int       termp_igndelim_pre(DECL_ARGS);
 static int       termp_in_pre(DECL_ARGS);
 static int       termp_it_pre(DECL_ARGS);
 static int       termp_li_pre(DECL_ARGS);
@@ -194,12 +194,12 @@ static    const struct termact termacts[MDOC_MAX] = {
        { termp_quote_pre, termp_quote_post }, /* Eo */
        { termp_xx_pre, NULL }, /* Fx */
        { termp_bold_pre, NULL }, /* Ms */
-       { termp_igndelim_pre, NULL }, /* No */
+       { NULL, NULL }, /* No */
        { termp_ns_pre, NULL }, /* Ns */
        { termp_xx_pre, NULL }, /* Nx */
        { termp_xx_pre, NULL }, /* Ox */
        { NULL, NULL }, /* Pc */
-       { termp_igndelim_pre, termp_pf_post }, /* Pf */
+       { NULL, termp_pf_post }, /* Pf */
        { termp_quote_pre, termp_quote_post }, /* Po */
        { termp_quote_pre, termp_quote_post }, /* Pq */
        { NULL, NULL }, /* Qc */
@@ -307,13 +307,10 @@ print_mdoc_node(DECL_ARGS)
        /*
         * Keeps only work until the end of a line.  If a keep was
         * invoked in a prior line, revert it to PREKEEP.
-        *
-        * Also let SYNPRETTY sections behave as if they were wrapped
-        * in a `Bk' block.
         */
 
-       if (TERMP_KEEP & p->flags || MDOC_SYNPRETTY & n->flags) {
-               if (n->prev ? (n->prev->line != n->line) :
+       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;
@@ -321,16 +318,6 @@ print_mdoc_node(DECL_ARGS)
        }
 
        /*
-        * Since SYNPRETTY sections aren't "turned off" with `Ek',
-        * we have to intuit whether we should disable formatting.
-        */
-
-       if ( ! (MDOC_SYNPRETTY & n->flags) &&
-           ((n->prev   && MDOC_SYNPRETTY & n->prev->flags) ||
-            (n->parent && MDOC_SYNPRETTY & n->parent->flags)))
-               p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
-
-       /*
         * After the keep flags have been set up, we may now
         * produce output.  Note that some pre-handlers do so.
         */
@@ -424,6 +411,7 @@ print_mdoc_foot(struct termp *p, const void *arg)
        p->offset = 0;
        p->rmargin = (p->maxrmargin - 
                        term_strlen(p, meta->date) + term_len(p, 1)) / 2;
+       p->trailspace = 1;
        p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
 
        term_word(p, meta->os);
@@ -438,6 +426,7 @@ print_mdoc_foot(struct termp *p, const void *arg)
 
        p->offset = p->rmargin;
        p->rmargin = p->maxrmargin;
+       p->trailspace = 0;
        p->flags &= ~TERMP_NOBREAK;
        p->flags |= TERMP_NOSPACE;
 
@@ -489,6 +478,7 @@ print_mdoc_head(struct termp *p, const void *arg)
        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 -
@@ -507,6 +497,7 @@ print_mdoc_head(struct termp *p, const void *arg)
        term_flushln(p);
 
        p->flags &= ~TERMP_NOBREAK;
+       p->trailspace = 0;
        if (p->rmargin + titlen <= p->maxrmargin) {
                p->flags |= TERMP_NOSPACE;
                p->offset = p->rmargin;
@@ -794,13 +785,13 @@ termp_it_pre(DECL_ARGS)
        case (LIST_dash):
                /* FALLTHROUGH */
        case (LIST_hyphen):
-               if (MDOC_HEAD == n->type)
-                       p->flags |= TERMP_NOBREAK;
+               if (MDOC_HEAD != n->type)
+                       break;
+               p->flags |= TERMP_NOBREAK;
+               p->trailspace = 1;
                break;
        case (LIST_hang):
-               if (MDOC_HEAD == n->type)
-                       p->flags |= TERMP_NOBREAK;
-               else
+               if (MDOC_HEAD != n->type)
                        break;
 
                /*
@@ -812,16 +803,18 @@ termp_it_pre(DECL_ARGS)
                if (n->next->child && 
                                (MDOC_Bl == n->next->child->tok ||
                                 MDOC_Bd == n->next->child->tok))
-                       p->flags &= ~TERMP_NOBREAK;
-               else
-                       p->flags |= TERMP_HANG;
+                       break;
+
+               p->flags |= TERMP_NOBREAK | TERMP_HANG;
+               p->trailspace = 1;
                break;
        case (LIST_tag):
-               if (MDOC_HEAD == n->type)
-                       p->flags |= TERMP_NOBREAK | TERMP_TWOSPACE;
-
                if (MDOC_HEAD != n->type)
                        break;
+
+               p->flags |= TERMP_NOBREAK;
+               p->trailspace = 2;
+
                if (NULL == n->next || NULL == n->next->child)
                        p->flags |= TERMP_DANGLE;
                break;
@@ -829,15 +822,20 @@ termp_it_pre(DECL_ARGS)
                if (MDOC_HEAD == n->type)
                        break;
 
-               if (NULL == n->next)
+               if (NULL == n->next) {
                        p->flags &= ~TERMP_NOBREAK;
-               else
+                       p->trailspace = 0;
+               } else {
                        p->flags |= TERMP_NOBREAK;
+                       p->trailspace = 1;
+               }
 
                break;
        case (LIST_diag):
-               if (MDOC_HEAD == n->type)
-                       p->flags |= TERMP_NOBREAK;
+               if (MDOC_HEAD != n->type)
+                       break;
+               p->flags |= TERMP_NOBREAK;
+               p->trailspace = 1;
                break;
        default:
                break;
@@ -989,8 +987,8 @@ termp_it_post(DECL_ARGS)
 
        p->flags &= ~TERMP_DANGLE;
        p->flags &= ~TERMP_NOBREAK;
-       p->flags &= ~TERMP_TWOSPACE;
        p->flags &= ~TERMP_HANG;
+       p->trailspace = 0;
 }
 
 
@@ -999,8 +997,10 @@ static int
 termp_nm_pre(DECL_ARGS)
 {
 
-       if (MDOC_BLOCK == n->type)
+       if (MDOC_BLOCK == n->type) {
+               p->flags |= TERMP_PREKEEP;
                return(1);
+       }
 
        if (MDOC_BODY == n->type) {
                if (NULL == n->child)
@@ -1023,6 +1023,7 @@ termp_nm_pre(DECL_ARGS)
 
        if (MDOC_HEAD == n->type && n->next->child) {
                p->flags |= TERMP_NOSPACE | TERMP_NOBREAK;
+               p->trailspace = 1;
                p->rmargin = p->offset + term_len(p, 1);
                if (NULL == n->child) {
                        p->rmargin += term_strlen(p, meta->name);
@@ -1048,9 +1049,12 @@ static void
 termp_nm_post(DECL_ARGS)
 {
 
-       if (MDOC_HEAD == n->type && n->next->child) {
+       if (MDOC_BLOCK == n->type) {
+               p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
+       } else if (MDOC_HEAD == n->type && n->next->child) {
                term_flushln(p);
                p->flags &= ~(TERMP_NOBREAK | TERMP_HANG);
+               p->trailspace = 0;
        } else if (MDOC_BODY == n->type && n->child)
                term_flushln(p);
 }
@@ -1525,6 +1529,7 @@ termp_ft_pre(DECL_ARGS)
 static int
 termp_fn_pre(DECL_ARGS)
 {
+       size_t           rmargin = 0;
        int              pretty;
 
        pretty = MDOC_SYNPRETTY & n->flags;
@@ -1534,11 +1539,24 @@ termp_fn_pre(DECL_ARGS)
        if (NULL == (n = n->child))
                return(0);
 
+       if (pretty) {
+               rmargin = p->rmargin;
+               p->rmargin = p->offset + term_len(p, 4);
+               p->flags |= TERMP_NOBREAK | TERMP_HANG;
+       }
+
        assert(MDOC_TEXT == n->type);
        term_fontpush(p, TERMFONT_BOLD);
        term_word(p, n->string);
        term_fontpop(p);
 
+       if (pretty) {
+               term_flushln(p);
+               p->flags &= ~(TERMP_NOBREAK | TERMP_HANG);
+               p->offset = p->rmargin;
+               p->rmargin = rmargin;
+       }
+
        p->flags |= TERMP_NOSPACE;
        term_word(p, "(");
        p->flags |= TERMP_NOSPACE;
@@ -1546,6 +1564,8 @@ termp_fn_pre(DECL_ARGS)
        for (n = n->next; n; n = n->next) {
                assert(MDOC_TEXT == n->type);
                term_fontpush(p, TERMFONT_UNDER);
+               if (pretty)
+                       p->flags |= TERMP_NBRWORD;
                term_word(p, n->string);
                term_fontpop(p);
 
@@ -1561,6 +1581,7 @@ termp_fn_pre(DECL_ARGS)
        if (pretty) {
                p->flags |= TERMP_NOSPACE;
                term_word(p, ";");
+               term_flushln(p);
        }
 
        return(0);
@@ -1580,20 +1601,16 @@ termp_fa_pre(DECL_ARGS)
 
        for (nn = n->child; nn; nn = nn->next) {
                term_fontpush(p, TERMFONT_UNDER);
+               p->flags |= TERMP_NBRWORD;
                term_word(p, nn->string);
                term_fontpop(p);
 
-               if (nn->next) {
+               if (nn->next || (n->next && n->next->tok == MDOC_Fa)) {
                        p->flags |= TERMP_NOSPACE;
                        term_word(p, ",");
                }
        }
 
-       if (n->child && n->next && n->next->tok == MDOC_Fa) {
-               p->flags |= TERMP_NOSPACE;
-               term_word(p, ",");
-       }
-
        return(0);
 }
 
@@ -1768,16 +1785,6 @@ termp_xx_pre(DECL_ARGS)
 
 
 /* ARGSUSED */
-static int
-termp_igndelim_pre(DECL_ARGS)
-{
-
-       p->flags |= TERMP_IGNDELIM;
-       return(1);
-}
-
-
-/* ARGSUSED */
 static void
 termp_pf_post(DECL_ARGS)
 {
@@ -2025,16 +2032,31 @@ termp_quote_post(DECL_ARGS)
 static int
 termp_fo_pre(DECL_ARGS)
 {
+       size_t           rmargin = 0;
+       int              pretty;
+
+       pretty = MDOC_SYNPRETTY & n->flags;
 
        if (MDOC_BLOCK == n->type) {
                synopsis_pre(p, n);
                return(1);
        } else if (MDOC_BODY == n->type) {
+               if (pretty) {
+                       rmargin = p->rmargin;
+                       p->rmargin = p->offset + term_len(p, 4);
+                       p->flags |= TERMP_NOBREAK | 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->offset = p->rmargin;
+                       p->rmargin = rmargin;
+               }
                return(1);
-       } 
+       }
 
        if (NULL == n->child)
                return(0);
@@ -2062,6 +2084,7 @@ termp_fo_post(DECL_ARGS)
        if (MDOC_SYNPRETTY & n->flags) {
                p->flags |= TERMP_NOSPACE;
                term_word(p, ";");
+               term_flushln(p);
        }
 }
 
@@ -2211,7 +2234,7 @@ static void
 termp_bk_post(DECL_ARGS)
 {
 
-       if (MDOC_BODY == n->type && ! (MDOC_SYNPRETTY & n->flags))
+       if (MDOC_BODY == n->type)
                p->flags &= ~(TERMP_KEEP | TERMP_PREKEEP);
 }
 
index 8ffc393..4cfd620 100644 (file)
@@ -1,7 +1,7 @@
-/*     $Id: mdoc_validate.c,v 1.193 2013/09/16 00:25:07 schwarze Exp $ */
+/*     $Id: mdoc_validate.c,v 1.198 2013/12/15 21:23:52 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2011, 2012 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010, 2011, 2012, 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
@@ -19,7 +19,7 @@
 #include "config.h"
 #endif
 
-#ifndef        OSNAME
+#ifndef OSNAME
 #include <sys/utsname.h>
 #endif
 
@@ -97,18 +97,19 @@ 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_defaults(POST_ARGS);
-static int      post_literal(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_ignpar(POST_ARGS);
 static int      post_prol(POST_ARGS);
 static int      post_root(POST_ARGS);
 static int      post_rs(POST_ARGS);
@@ -142,28 +143,30 @@ 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, 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, 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, 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_post   posts_wline[] = { bwarn_ge1, 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 };
@@ -171,8 +174,6 @@ 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_er[] = { NULL, NULL };
-static v_pre    pres_fd[] = { NULL, 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 };
@@ -188,7 +189,7 @@ static      const struct valids mdoc_valids[MDOC_MAX] = {
        { pres_sh, posts_sh },                  /* Sh */ 
        { pres_ss, posts_ss },                  /* Ss */ 
        { pres_pp, posts_pp },                  /* Pp */ 
-       { pres_d1, posts_wline },               /* D1 */
+       { pres_d1, posts_d1 },                  /* D1 */
        { pres_dl, posts_dl },                  /* Dl */
        { pres_bd, posts_bd },                  /* Bd */
        { NULL, NULL },                         /* Ed */
@@ -201,11 +202,11 @@ static    const struct valids mdoc_valids[MDOC_MAX] = {
        { NULL, NULL },                         /* Cd */ 
        { NULL, NULL },                         /* Cm */
        { NULL, NULL },                         /* Dv */ 
-       { pres_er, NULL },                      /* Er */ 
+       { NULL, NULL },                         /* Er */ 
        { NULL, NULL },                         /* Ev */ 
        { pres_std, posts_std },                /* Ex */ 
        { NULL, NULL },                         /* Fa */ 
-       { pres_fd, posts_text },                /* Fd */
+       { NULL, posts_text },                   /* Fd */
        { NULL, NULL },                         /* Fl */
        { NULL, NULL },                         /* Fn */ 
        { NULL, NULL },                         /* Ft */ 
@@ -223,15 +224,15 @@ static    const struct valids mdoc_valids[MDOC_MAX] = {
        { NULL, posts_vt },                     /* Vt */ 
        { NULL, posts_text },                   /* Xr */ 
        { NULL, posts_text },                   /* %A */
-       { NULL, posts_text },                   /* %B */ /* FIXME: can be used outside Rs/Re. */
+       { 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_text },                   /* %N */
-       { NULL, posts_text },                   /* %O */
+       { NULL, posts_hyphtext },               /* %N */
+       { NULL, posts_hyphtext },               /* %O */
        { NULL, posts_text },                   /* %P */
-       { NULL, posts_text },                   /* %R */
-       { NULL, posts_text },                   /* %T */ /* FIXME: can be used outside Rs/Re. */
+       { NULL, posts_hyphtext },               /* %R */
+       { NULL, posts_hyphtext },               /* %T */ /* FIXME: can be used outside Rs/Re. */
        { NULL, posts_text },                   /* %V */
        { NULL, NULL },                         /* Ac */
        { NULL, NULL },                         /* Ao */
@@ -271,7 +272,7 @@ static      const struct valids mdoc_valids[MDOC_MAX] = {
        { NULL, NULL },                         /* So */
        { NULL, NULL },                         /* Sq */
        { NULL, posts_bool },                   /* Sm */ 
-       { NULL, NULL },                         /* Sx */
+       { NULL, posts_hyph },                   /* Sx */
        { NULL, NULL },                         /* Sy */
        { NULL, NULL },                         /* Tn */
        { NULL, NULL },                         /* Ux */
@@ -888,8 +889,6 @@ pre_sh(PRE_ARGS)
 
        if (MDOC_BLOCK != n->type)
                return(1);
-
-       roff_regunset(mdoc->roff, REG_nS);
        return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT));
 }
 
@@ -1592,32 +1591,71 @@ post_bl_head(POST_ARGS)
 static int
 post_bl(POST_ARGS)
 {
-       struct mdoc_node        *n;
+       struct mdoc_node        *nparent, *nprev; /* of the Bl block */
+       struct mdoc_node        *nblock, *nbody;  /* of the Bl */
+       struct mdoc_node        *nchild, *nnext;  /* of the Bl body */
 
-       if (MDOC_HEAD == mdoc->last->type) 
-               return(post_bl_head(mdoc));
-       if (MDOC_BLOCK == mdoc->last->type)
+       nbody = mdoc->last;
+       switch (nbody->type) {
+       case (MDOC_BLOCK):
                return(post_bl_block(mdoc));
-       if (MDOC_BODY != mdoc->last->type)
+       case (MDOC_HEAD):
+               return(post_bl_head(mdoc));
+       case (MDOC_BODY):
+               break;
+       default:
                return(1);
+       }
 
-       for (n = mdoc->last->child; n; n = n->next) {
-               switch (n->tok) {
-               case (MDOC_Lp):
-                       /* FALLTHROUGH */
-               case (MDOC_Pp):
-                       mdoc_nmsg(mdoc, n, MANDOCERR_CHILD);
-                       /* FALLTHROUGH */
-               case (MDOC_It):
-                       /* FALLTHROUGH */
-               case (MDOC_Sm):
+       nchild = nbody->child;
+       while (NULL != nchild) {
+               if (MDOC_It == nchild->tok || MDOC_Sm == nchild->tok) {
+                       nchild = nchild->next;
                        continue;
-               default:
-                       break;
                }
 
-               mdoc_nmsg(mdoc, n, MANDOCERR_SYNTCHILD);
-               return(0);
+               mdoc_nmsg(mdoc, nchild, MANDOCERR_CHILD);
+
+               /*
+                * Move the node out of the Bl block.
+                * First, collect all required node pointers.
+                */
+
+               nblock  = nbody->parent;
+               nprev   = nblock->prev;
+               nparent = nblock->parent;
+               nnext   = nchild->next;
+
+               /*
+                * Unlink this child.
+                */
+
+               assert(NULL == nchild->prev);
+               if (0 == --nbody->nchild) {
+                       nbody->child = NULL;
+                       nbody->last  = NULL;
+                       assert(NULL == nnext);
+               } else {
+                       nbody->child = nnext;
+                       nnext->prev = NULL;
+               }
+
+               /*
+                * Relink this child.
+                */
+
+               nchild->parent = nparent;
+               nchild->prev   = nprev;
+               nchild->next   = nblock;
+
+               nblock->prev = nchild;
+               nparent->nchild++;
+               if (NULL == nprev)
+                       nparent->child = nchild;
+               else
+                       nprev->next = nchild;
+
+               nchild = nnext;
        }
 
        return(1);
@@ -1636,10 +1674,16 @@ ebool(struct mdoc *mdoc)
 
        assert(MDOC_TEXT == mdoc->last->child->type);
 
-       if (0 == strcmp(mdoc->last->child->string, "on"))
+       if (0 == strcmp(mdoc->last->child->string, "on")) {
+               if (MDOC_Sm == mdoc->last->tok)
+                       mdoc->flags &= ~MDOC_SMOFF;
                return(1);
-       if (0 == strcmp(mdoc->last->child->string, "off"))
+       }
+       if (0 == strcmp(mdoc->last->child->string, "off")) {
+               if (MDOC_Sm == mdoc->last->tok)
+                       mdoc->flags |= MDOC_SMOFF;
                return(1);
+       }
 
        mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL);
        return(1);
@@ -1819,6 +1863,47 @@ post_rs(POST_ARGS)
        return(1);
 }
 
+/*
+ * For some arguments of some macros,
+ * convert all breakable hyphens into ASCII_HYPH.
+ */
+static int
+post_hyph(POST_ARGS)
+{
+       struct mdoc_node        *n, *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)
+                       continue;
+               cp = nch->string;
+               if (3 > strnlen(cp, 3))
+                       continue;
+               while ('\0' != *(++cp))
+                       if ('-' == *cp &&
+                           isalpha((unsigned char)cp[-1]) &&
+                           isalpha((unsigned char)cp[1]))
+                               *cp = ASCII_HYPH;
+       }
+       return(1);
+}
+
 static int
 post_ns(POST_ARGS)
 {
@@ -1905,10 +1990,13 @@ post_sh_head(POST_ARGS)
 
        /* The SYNOPSIS gets special attention in other areas. */
 
-       if (SEC_SYNOPSIS == sec)
+       if (SEC_SYNOPSIS == sec) {
+               roff_setreg(mdoc->roff, "nS", 1, '=');
                mdoc->flags |= MDOC_SYNOPSIS;
-       else
+       } else {
+               roff_setreg(mdoc->roff, "nS", 0, '=');
                mdoc->flags &= ~MDOC_SYNOPSIS;
+       }
 
        /* Mark our last section. */
 
index 1d8c8ab..c931664 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: out.c,v 1.45 2013/05/31 21:37:17 schwarze Exp $ */
+/*     $Id: out.c,v 1.46 2013/10/05 20:30:05 schwarze Exp $ */
 /*
  * Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
@@ -142,7 +142,6 @@ void
 tblcalc(struct rofftbl *tbl, const struct tbl_span *sp)
 {
        const struct tbl_dat    *dp;
-       const struct tbl_head   *hp;
        struct roffcol          *col;
        int                      spans;
 
@@ -156,8 +155,6 @@ tblcalc(struct rofftbl *tbl, const struct tbl_span *sp)
        tbl->cols = mandoc_calloc
                ((size_t)sp->opts->cols, sizeof(struct roffcol));
 
-       hp = sp->head;
-
        for ( ; sp; sp = sp->next) {
                if (TBL_SPAN_DATA != sp->pos)
                        continue;
index 7c26086..48e16dd 100644 (file)
@@ -1,7 +1,7 @@
-.\"    $Id: roff.7,v 1.42 2013/08/08 20:07:47 schwarze Exp $
+.\"    $Id: roff.7,v 1.46 2013/12/26 02:43:18 schwarze Exp $
 .\"
-.\" Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
-.\" Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
+.\" Copyright (c) 2010, 2011, 2012 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
@@ -15,7 +15,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: August 8 2013 $
+.Dd $Mdocdate: December 26 2013 $
 .Dt ROFF 7
 .Os
 .Sh NAME
@@ -32,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 7
 or
 .Xr man 7
@@ -41,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
@@ -85,7 +85,7 @@ documents may contain only graphable 7-bit ASCII characters, the space
 character, and, in certain circumstances, the tab 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 ,
@@ -93,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 ,
@@ -638,6 +641,15 @@ Begin an equation block.
 See
 .Xr eqn 7
 for a description of the equation language.
+.Ss \&fam
+Change the font family.
+This line-scoped request is intended to have one argument specifying
+the font family to be selected.
+It is a groff extension, and currently, it is ignored including its
+arguments, and the number of arguments is not checked.
+.Ss \&hw
+Specify hyphenation points in words.
+This line-scoped request is currently ignored.
 .Ss \&hy
 Set automatic hyphenation mode.
 This line-scoped request is currently ignored.
@@ -805,19 +817,22 @@ 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.
 .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 value
 .Pp
 The
 .Ar value
 may, at the moment, only be an integer.
-So far, only the following register
+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
@@ -914,6 +929,249 @@ Begin a table, which formats input in aligned rows and columns.
 See
 .Xr tbl 7
 for a description of the tbl language.
+.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 7
+and
+.Xr man 7
+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 7 .
+.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 7 .
+.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
+Test whether
+.Ar string
+is a numerical expession; ignored by
+.Xr mandoc 1 .
+.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
+Interrupt text processing to insert requests or macros; ignored by
+.Xr mandoc 1 .
+.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
+.Ar string ;
+ignored by
+.Xr mandoc 1 .
+.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 ;
+ignored by
+.Xr mandoc 1 .
+.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
 .Nm
index 3ee8adf..42240d2 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: roff.c,v 1.178 2013/07/13 12:52:07 schwarze Exp $ */
+/*     $Id: roff.c,v 1.189 2013/12/30 18:44:06 schwarze Exp $ */
 /*
  * Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
@@ -46,6 +46,8 @@ enum  rofft {
        ROFF_de1,
        ROFF_ds,
        ROFF_el,
+       ROFF_fam,
+       ROFF_hw,
        ROFF_hy,
        ROFF_ie,
        ROFF_if,
@@ -74,18 +76,8 @@ enum rofft {
 };
 
 enum   roffrule {
-       ROFFRULE_ALLOW,
-       ROFFRULE_DENY
-};
-
-/*
- * A single register entity.  If "set" is zero, the value of the
- * register should be the default one, which is per-register.
- * Registers are assumed to be unsigned ints for now.
- */
-struct reg {
-       int              set; /* whether set or not */
-       unsigned int     u; /* unsigned integer */
+       ROFFRULE_DENY,
+       ROFFRULE_ALLOW
 };
 
 /*
@@ -105,6 +97,15 @@ struct      roffkv {
        struct roffkv   *next; /* next in list */
 };
 
+/*
+ * A single number register as part of a singly-linked list.
+ */
+struct roffreg {
+       struct roffstr   key;
+       int              val;
+       struct roffreg  *next;
+};
+
 struct roff {
        enum mparset     parsetype; /* requested parse type */
        struct mparse   *parse; /* parse point */
@@ -112,7 +113,7 @@ struct      roff {
        enum roffrule    rstack[RSTACK_MAX]; /* stack of !`ie' rules */
        char             control; /* control character */
        int              rstackpos; /* position in rstack */
-       struct reg       regs[REG__MAX];
+       struct roffreg  *regtab; /* number registers */
        struct roffkv   *strtab; /* user-defined strings & macros */
        struct roffkv   *xmbtab; /* multi-byte trans table (`tr') */
        struct roffstr  *xtab; /* single-byte trans table (`tr') */
@@ -183,8 +184,13 @@ static     enum rofferr     roff_cond_sub(ROFF_ARGS);
 static enum rofferr     roff_ds(ROFF_ARGS);
 static enum roffrule    roff_evalcond(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 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 *, 
                                const char *, size_t);
 static enum rofferr     roff_it(ROFF_ARGS);
@@ -231,6 +237,8 @@ static      struct roffmac   roffs[ROFF_MAX] = {
        { "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
        { "ds", roff_ds, NULL, NULL, 0, NULL },
        { "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
+       { "fam", roff_line_ignore, NULL, NULL, 0, NULL },
+       { "hw", roff_line_ignore, NULL, NULL, 0, NULL },
        { "hy", 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 },
@@ -424,6 +432,10 @@ roff_free1(struct roff *r)
 
        r->strtab = r->xmbtab = NULL;
 
+       roff_freereg(r->regtab);
+
+       r->regtab = NULL;
+
        if (r->xtab)
                for (i = 0; i < 128; i++)
                        free(r->xtab[i].p);
@@ -440,7 +452,6 @@ roff_reset(struct roff *r)
        roff_free1(r);
 
        r->control = 0;
-       memset(&r->regs, 0, sizeof(struct reg) * REG__MAX);
 
        for (i = 0; i < PREDEFS_MAX; i++) 
                roff_setstr(r, predefs[i].name, predefs[i].str, 0);
@@ -476,22 +487,23 @@ roff_alloc(enum mparset type, struct mparse *parse)
 }
 
 /*
- * Pre-filter each and every line for reserved words (one beginning with
- * `\*', e.g., `\*(ab').  These must be handled before the actual line
- * is processed. 
- * This also checks the syntax of regular escapes.
+ * In the current line, expand user-defined strings ("\*")
+ * and references to number registers ("\n").
+ * Also check the syntax of other escape sequences.
  */
 static enum rofferr
 roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
 {
-       enum mandoc_esc  esc;
+       char             ubuf[12]; /* buffer to print the number */
        const 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 */
-       int              i, maxl, expand_count;
-       size_t           nsz;
-       char            *n;
+       char            *nbuf;  /* new buffer to copy bufp to */
+       size_t           nsz;   /* size of the new buffer */
+       size_t           maxl;  /* expected length of the escape name */
+       size_t           naml;  /* actual length of the escape name */
+       int              expand_count;  /* to avoid infinite loops */
 
        expand_count = 0;
 
@@ -501,7 +513,7 @@ again:
                stesc = cp++;
 
                /*
-                * The second character must be an asterisk.
+                * 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.
                 */
@@ -509,12 +521,16 @@ again:
                if ('\0' == *cp)
                        return(ROFF_CONT);
 
-               if ('*' != *cp) {
-                       res = cp;
-                       esc = mandoc_escape(&cp, NULL, NULL);
-                       if (ESCAPE_ERROR != esc)
+               switch (*cp) {
+               case ('*'):
+                       res = NULL;
+                       break;
+               case ('n'):
+                       res = ubuf;
+                       break;
+               default:
+                       if (ESCAPE_ERROR != mandoc_escape(&cp, NULL, NULL))
                                continue;
-                       cp = res;
                        mandoc_msg
                                (MANDOCERR_BADESCAPE, r->parse, 
                                 ln, (int)(stesc - *bufp), NULL);
@@ -525,7 +541,7 @@ again:
 
                /*
                 * The third character decides the length
-                * of the name of the string.
+                * of the name of the string or register.
                 * Save a pointer to the name.
                 */
 
@@ -548,7 +564,7 @@ again:
 
                /* Advance to the end of the name. */
 
-               for (i = 0; 0 == maxl || i < maxl; i++, cp++) {
+               for (naml = 0; 0 == maxl || naml < maxl; naml++, cp++) {
                        if ('\0' == *cp) {
                                mandoc_msg
                                        (MANDOCERR_BADESCAPE, 
@@ -565,7 +581,11 @@ again:
                 * undefined, resume searching for escapes.
                 */
 
-               res = roff_getstrn(r, stnam, (size_t)i);
+               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
@@ -579,15 +599,15 @@ again:
                pos = stesc - *bufp;
 
                nsz = *szp + strlen(res) + 1;
-               n = mandoc_malloc(nsz);
+               nbuf = mandoc_malloc(nsz);
 
-               strlcpy(n, *bufp, (size_t)(stesc - *bufp + 1));
-               strlcat(n, res, nsz);
-               strlcat(n, cp + (maxl ? 0 : 1), nsz);
+               strlcpy(nbuf, *bufp, (size_t)(stesc - *bufp + 1));
+               strlcat(nbuf, res, nsz);
+               strlcat(nbuf, cp + (maxl ? 0 : 1), nsz);
 
                free(*bufp);
 
-               *bufp = n;
+               *bufp = nbuf;
                *szp = nsz;
 
                if (EXPAND_LIMIT >= ++expand_count)
@@ -626,8 +646,7 @@ roff_parsetext(char **bufp, size_t *szp, int pos, int *offs)
                if ('\\' == *p) {
                        /* Skip over escapes. */
                        p++;
-                       esc = mandoc_escape
-                               ((const char **)&p, NULL, NULL);
+                       esc = mandoc_escape((const char **)&p, NULL, NULL);
                        if (ESCAPE_ERROR == esc)
                                break;
                        continue;
@@ -698,19 +717,14 @@ roff_parseln(struct roff *r, int ln, char **bufp,
                assert(ROFF_IGN == e || ROFF_CONT == e);
                if (ROFF_CONT != e)
                        return(e);
-               if (r->eqn)
-                       return(eqn_read(&r->eqn, ln, *bufp, pos, offs));
-               if (r->tbl)
-                       return(tbl_read(r->tbl, ln, *bufp, pos));
-               return(roff_parsetext(bufp, szp, pos, offs));
-       } else if ( ! ctl) {
-               if (r->eqn)
-                       return(eqn_read(&r->eqn, ln, *bufp, pos, offs));
+       }
+       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));
-       } else if (r->eqn)
-               return(eqn_read(&r->eqn, ln, *bufp, ppos, offs));
+       }
 
        /*
         * If a scope is open, go to the child handler for that macro,
@@ -1116,9 +1130,61 @@ roff_cond_text(ROFF_ARGS)
        return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
 }
 
+static int
+roff_getnum(const char *v, int *pos, int *res)
+{
+       int p, n;
+
+       p = *pos;
+       n = v[p] == '-';
+       if (n)
+               p++;
+
+       for (*res = 0; isdigit((unsigned char)v[p]); p++)
+               *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] == '=';
+
+       switch (*res) {
+       case '=':
+               break;
+       case '>':
+               if (e)
+                       *res = 'g';
+               break;
+       case '<':
+               if (e)
+                       *res = 'l';
+               break;
+       default:
+               return(0);
+       }
+
+       *pos += 1 + e;
+
+       return(*res);
+}
+
 static enum roffrule
 roff_evalcond(const char *v, int *pos)
 {
+       int      not, lh, rh;
+       char     op;
 
        switch (v[*pos]) {
        case ('n'):
@@ -1131,13 +1197,47 @@ roff_evalcond(const char *v, int *pos)
        case ('t'):
                (*pos)++;
                return(ROFFRULE_DENY);
+       case ('!'):
+               (*pos)++;
+               not = 1;
+               break;
        default:
+               not = 0;
                break;
        }
 
-       while (v[*pos] && ' ' != v[*pos])
-               (*pos)++;
-       return(ROFFRULE_DENY);
+       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;
 }
 
 /* ARGSUSED */
@@ -1258,25 +1358,71 @@ roff_ds(ROFF_ARGS)
        return(ROFF_IGN);
 }
 
+void
+roff_setreg(struct roff *r, const char *name, int val, char sign)
+{
+       struct roffreg  *reg;
+
+       /* Search for an existing register with the same name. */
+       reg = r->regtab;
+
+       while (reg && strcmp(name, reg->key.p))
+               reg = reg->next;
+
+       if (NULL == reg) {
+               /* Create a new register. */
+               reg = mandoc_malloc(sizeof(struct roffreg));
+               reg->key.p = mandoc_strdup(name);
+               reg->key.sz = strlen(name);
+               reg->val = 0;
+               reg->next = r->regtab;
+               r->regtab = reg;
+       }
+
+       if ('+' == sign)
+               reg->val += val;
+       else if ('-' == sign)
+               reg->val -= val;
+       else
+               reg->val = val;
+}
+
 int
-roff_regisset(const struct roff *r, enum regs reg)
+roff_getreg(const struct roff *r, const char *name)
 {
+       struct roffreg  *reg;
 
-       return(r->regs[(int)reg].set);
+       for (reg = r->regtab; reg; reg = reg->next)
+               if (0 == strcmp(name, reg->key.p))
+                       return(reg->val);
+
+       return(0);
 }
 
-unsigned int
-roff_regget(const struct roff *r, enum regs reg)
+static int
+roff_getregn(const struct roff *r, const char *name, size_t len)
 {
+       struct roffreg  *reg;
 
-       return(r->regs[(int)reg].u);
+       for (reg = r->regtab; reg; reg = reg->next)
+               if (len == reg->key.sz &&
+                   0 == strncmp(name, reg->key.p, len))
+                       return(reg->val);
+
+       return(0);
 }
 
-void
-roff_regunset(struct roff *r, enum regs reg)
+static void
+roff_freereg(struct roffreg *reg)
 {
+       struct roffreg  *old_reg;
 
-       r->regs[(int)reg].set = 0;
+       while (NULL != reg) {
+               free(reg->key.p);
+               old_reg = reg;
+               reg = reg->next;
+               free(old_reg);
+       }
 }
 
 /* ARGSUSED */
@@ -1285,18 +1431,21 @@ roff_nr(ROFF_ARGS)
 {
        const char      *key;
        char            *val;
+       size_t           sz;
        int              iv;
+       char             sign;
 
        val = *bufp + pos;
        key = roff_getname(r, &val, ln, pos);
 
-       if (0 == strcmp(key, "nS")) {
-               r->regs[(int)REG_nS].set = 1;
-               if ((iv = mandoc_strntoi(val, strlen(val), 10)) >= 0)
-                       r->regs[(int)REG_nS].u = (unsigned)iv;
-               else
-                       r->regs[(int)REG_nS].u = 0u;
-       }
+       sign = *val;
+       if ('+' == sign || '-' == sign)
+               val++;
+
+       sz = strspn(val, "0123456789");
+       iv = sz ? mandoc_strntoi(val, sz, 10) : 0;
+
+       roff_setreg(r, key, iv, sign);
 
        return(ROFF_IGN);
 }
@@ -1583,7 +1732,7 @@ roff_userdef(ROFF_ARGS)
 
        /*
         * Collect pointers to macro argument strings
-        * and null-terminate them.
+        * and NUL-terminate them.
         */
        cp = *bufp + pos;
        for (i = 0; i < 9; i++)
index bedc6a6..c52ddab 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: st.in,v 1.20 2013/06/19 21:20:27 schwarze Exp $ */
+/*     $Id: st.in,v 1.22 2013/12/25 14:09:32 schwarze Exp $ */
 /*
  * Copyright (c) 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -71,11 +71,12 @@ LINE("-xpg4.2",             "X/Open Portability Guide Issue\\~4, Version\\~2 (\\(lqXPG4.2\\
 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")
-LINE("-susv3",         "Version\\~3 of the Single UNIX Specification")
+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)")
index 16def78..e7b9557 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: term.c,v 1.210 2013/08/21 21:20:40 schwarze Exp $ */
+/*     $Id: term.c,v 1.214 2013/12/25 00:39:31 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
@@ -83,9 +83,8 @@ term_end(struct termp *p)
  *  - 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.
- *
- *  - TERMP_TWOSPACE: make sure there is room for at least two space
- *    characters of padding.  Otherwise, rather break the line.
+ *    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.
@@ -121,7 +120,12 @@ term_flushln(struct termp *p)
         * First, establish the maximum columns of "visible" content.
         * This is usually the difference between the right-margin and
         * an indentation, but can be, for tagged lists or columns, a
-        * small set of values. 
+        * small set of values.
+        *
+        * The following unsigned-signed subtractions look strange,
+        * but they are actually correct.  If the int p->overstep
+        * is negative, it gets sign extended.  Subtracting that
+        * very large size_t effectively adds a small number to dv.
         */
        assert  (p->rmargin >= p->offset);
        dv     = p->rmargin - p->offset;
@@ -200,7 +204,11 @@ term_flushln(struct termp *p)
                        if (0 < ntab)
                                vbl += ntab * p->tabwidth;
 
-                       /* Remove the p->overstep width. */
+                       /*
+                        * Remove the p->overstep width.
+                        * Again, if p->overstep is negative,
+                        * sign extension does the right thing.
+                        */
 
                        bp += (size_t)p->overstep;
                        p->overstep = 0;
@@ -269,15 +277,17 @@ term_flushln(struct termp *p)
        }
 
        if (TERMP_HANG & p->flags) {
-               /* We need one blank after the tag. */
-               p->overstep = (int)(vis - maxvis + (*p->width)(p, ' '));
+               p->overstep = (int)(vis - maxvis +
+                               p->trailspace * (*p->width)(p, ' '));
 
                /*
                 * If we have overstepped the margin, temporarily move
                 * it to the right and flag the rest of the line to be
                 * shorter.
+                * If there is a request to keep the columns together,
+                * allow negative overstep when the column is not full.
                 */
-               if (p->overstep < 0)
+               if (p->trailspace && p->overstep < 0)
                        p->overstep = 0;
                return;
 
@@ -285,8 +295,7 @@ term_flushln(struct termp *p)
                return;
 
        /* If the column was overrun, break the line. */
-       if (maxvis <= vis +
-           ((TERMP_TWOSPACE & p->flags) ? (*p->width)(p, ' ') : 0)) {
+       if (maxvis < vis + p->trailspace * (*p->width)(p, ' ')) {
                (*p->endline)(p);
                p->viscol = 0;
        }
@@ -398,6 +407,7 @@ term_fontpop(struct termp *p)
 void
 term_word(struct termp *p, const char *word)
 {
+       const char       nbrsp[2] = { ASCII_NBRSP, 0 };
        const char      *seq, *cp;
        char             c;
        int              sz, uc;
@@ -420,7 +430,7 @@ term_word(struct termp *p, const char *word)
        else
                p->flags |= TERMP_NOSPACE;
 
-       p->flags &= ~(TERMP_SENTENCE | TERMP_IGNDELIM);
+       p->flags &= ~TERMP_SENTENCE;
 
        while ('\0' != *word) {
                if ('\\' != *word) {
@@ -429,7 +439,15 @@ term_word(struct termp *p, const char *word)
                                word++;
                                continue;
                        }
-                       ssz = strcspn(word, "\\");
+                       if (TERMP_NBRWORD & p->flags) {
+                               if (' ' == *word) {
+                                       encode(p, nbrsp, 1);
+                                       word++;
+                                       continue;
+                               }
+                               ssz = strcspn(word, "\\ ");
+                       } else
+                               ssz = strcspn(word, "\\");
                        encode(p, word, ssz);
                        word += (int)ssz;
                        continue;
@@ -504,6 +522,7 @@ term_word(struct termp *p, const char *word)
                        break;
                }
        }
+       p->flags &= ~TERMP_NBRWORD;
 }
 
 static void
index 6aa9934..8cad4be 100644 (file)
@@ -1,6 +1,7 @@
-/*     $Id: term.h,v 1.94 2013/08/21 21:20:40 schwarze Exp $ */
+/*     $Id: term.h,v 1.97 2013/12/25 00:39:31 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2011, 2012, 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
@@ -63,23 +64,23 @@ struct      termp {
        size_t            tabwidth;     /* Distance of tab positions. */
        size_t            col;          /* Bytes in buf. */
        size_t            viscol;       /* Chars on current line. */
+       size_t            trailspace;   /* See termp_flushln(). */
        int               overstep;     /* See termp_flushln(). */
        int               skipvsp;      /* Vertical space to skip. */
        int               flags;
 #define        TERMP_SENTENCE   (1 << 1)       /* Space before a sentence. */
 #define        TERMP_NOSPACE    (1 << 2)       /* No space before words. */
-#define        TERMP_NOBREAK    (1 << 4)       /* See term_flushln(). */
-#define        TERMP_IGNDELIM   (1 << 6)       /* Delims like regulars. */
-#define        TERMP_NONOSPACE  (1 << 7)       /* No space (no autounset). */
-#define        TERMP_DANGLE     (1 << 8)       /* See term_flushln(). */
-#define        TERMP_HANG       (1 << 9)       /* See term_flushln(). */
-#define        TERMP_TWOSPACE   (1 << 10)      /* See term_flushln(). */
+#define        TERMP_NONOSPACE  (1 << 3)       /* No space (no autounset). */
+#define        TERMP_NBRWORD    (1 << 4)       /* Make next word nonbreaking. */
+#define        TERMP_KEEP       (1 << 5)       /* Keep words together. */
+#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_KEEP       (1 << 14)      /* Keep words together. */
-#define        TERMP_PREKEEP    (1 << 15)      /* ...starting with the next one. */
-#define        TERMP_SKIPCHAR   (1 << 16)      /* Skip the next character. */
        int              *buf;          /* Output buffer. */
        enum termenc      enc;          /* Type of encoding. */
        struct mchars    *symtab;       /* Encoded-symbol table. */
index 08a76b8..fdb70e1 100644 (file)
@@ -1,6 +1,7 @@
-/*     $Id: tree.c,v 1.49 2013/09/15 17:33:57 schwarze Exp $ */
+/*     $Id: tree.c,v 1.50 2013/12/24 19:11:46 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2013 Ingo Schwarze <schwarze@openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -163,7 +164,10 @@ print_mdoc(const struct mdoc_node *n, int indent)
                putchar(' ');
                if (MDOC_LINE & n->flags)
                        putchar('*');
-               printf("%d:%d\n", n->line, n->pos);
+               printf("%d:%d", n->line, n->pos);
+               if (n->lastline != n->line)
+                       printf("-%d", n->lastline);
+               putchar('\n');
        }
 
        if (n->child)