Minimal implementation of the roff(7) .ce request (center a number
authorschwarze <schwarze@openbsd.org>
Tue, 6 Jun 2017 15:00:56 +0000 (15:00 +0000)
committerschwarze <schwarze@openbsd.org>
Tue, 6 Jun 2017 15:00:56 +0000 (15:00 +0000)
of input lines without filling).
Contrary to groff, high-level macros abort .ce mode for now.

share/man/man7/roff.7
usr.bin/mandoc/mandoc.1
usr.bin/mandoc/mandoc.h
usr.bin/mandoc/mdoc_man.c
usr.bin/mandoc/read.c
usr.bin/mandoc/roff.c
usr.bin/mandoc/roff.h
usr.bin/mandoc/roff_html.c
usr.bin/mandoc/roff_term.c
usr.bin/mandoc/roff_validate.c

index 3ad9ee4..c0c3037 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: roff.7,v 1.64 2017/06/04 22:43:50 schwarze Exp $
+.\"    $OpenBSD: roff.7,v 1.65 2017/06/06 15:00:56 schwarze Exp $
 .\"
 .\" Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
 .\" Copyright (c) 2010,2011,2013-2015,2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,7 +15,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: June 4 2017 $
+.Dd $Mdocdate: June 6 2017 $
 .Dt ROFF 7
 .Os
 .Sh NAME
@@ -525,7 +525,10 @@ Trailing characters are ignored.
 Center the next
 .Ar N
 input lines without filling.
-Currently ignored.
+.Ar N
+defaults to 1.
+An argument of 0 or less ends centering.
+Currently, high level macros abort certering.
 .It Ic \&cf Ar filename
 Output the contents of a file.
 Ignored because insecure.
index 2597104..2354ec2 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: mandoc.1,v 1.117 2017/06/03 12:16:19 schwarze Exp $
+.\"    $OpenBSD: mandoc.1,v 1.118 2017/06/06 15:00:56 schwarze Exp $
 .\"
 .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
 .\" Copyright (c) 2012, 2014-2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -15,7 +15,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: June 3 2017 $
+.Dd $Mdocdate: June 6 2017 $
 .Dt MANDOC 1
 .Os
 .Sh NAME
@@ -1716,6 +1716,11 @@ whatever mode was active before the block.
 A
 .Ic \&Bl
 macro fails to specify the list type.
+.It Sy "argument is not numeric, using 1"
+.Pq roff
+The argument of a
+.Ic \&ce
+request is not a number.
 .It Sy "missing manual name, using \(dq\(dq"
 .Pq mdoc
 The first call to
index f6e49fd..a0ddd42 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mandoc.h,v 1.164 2017/06/03 15:54:09 schwarze Exp $ */
+/*     $OpenBSD: mandoc.h,v 1.165 2017/06/06 15:00:56 schwarze Exp $ */
 /*
  * Copyright (c) 2010, 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -185,6 +185,7 @@ enum        mandocerr {
        MANDOCERR_BD_FILE, /* NOT IMPLEMENTED: Bd -file */
        MANDOCERR_BD_NOARG, /* skipping display without arguments: Bd */
        MANDOCERR_BL_NOTYPE, /* missing list type, using -item: Bl */
+       MANDOCERR_CE_NONUM, /* argument is not numeric, using 1: ce ... */
        MANDOCERR_NM_NONAME, /* missing manual name, using "": Nm */
        MANDOCERR_OS_UNAME, /* uname(3) system call failed, using UNKNOWN */
        MANDOCERR_ST_BAD, /* unknown standard specifier: St standard */
index 5c4a41a..8e14c4c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: mdoc_man.c,v 1.115 2017/06/04 22:43:50 schwarze Exp $ */
+/*     $OpenBSD: mdoc_man.c,v 1.116 2017/06/06 15:00:56 schwarze Exp $ */
 /*
  * Copyright (c) 2011-2017 Ingo Schwarze <schwarze@openbsd.org>
  *
@@ -124,6 +124,7 @@ static      void      print_node(DECL_ARGS);
 
 static const void_fp roff_manacts[ROFF_MAX] = {
        pre_br,
+       pre_onearg,
        pre_ft,
        pre_onearg,
        pre_onearg,
@@ -1580,6 +1581,9 @@ pre_onearg(DECL_ARGS)
        if (n->child != NULL)
                print_word(n->child->string);
        outflags |= MMAN_nl;
+       if (n->tok == ROFF_ce)
+               for (n = n->child->next; n != NULL; n = n->next)
+                       print_node(meta, n);
 }
 
 static int
index 21538c2..7c6ccae 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: read.c,v 1.142 2017/06/04 00:08:56 schwarze Exp $ */
+/*     $OpenBSD: read.c,v 1.143 2017/06/06 15:00:56 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -223,6 +223,7 @@ static      const char * const      mandocerrs[MANDOCERR_MAX] = {
        "NOT IMPLEMENTED: Bd -file",
        "skipping display without arguments",
        "missing list type, using -item",
+       "argument is not numeric, using 1",
        "missing manual name, using \"\"",
        "uname(3) system call failed, using UNKNOWN",
        "unknown standard specifier",
index a6c19dd..2535863 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: roff.c,v 1.176 2017/06/04 22:43:50 schwarze Exp $ */
+/*     $OpenBSD: roff.c,v 1.177 2017/06/06 15:00:56 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -187,7 +187,8 @@ static      enum rofferr     roff_nr(ROFF_ARGS);
 static enum rofferr     roff_onearg(ROFF_ARGS);
 static enum roff_tok    roff_parse(struct roff *, char *, int *,
                                int, int);
-static enum rofferr     roff_parsetext(struct buf *, int, int *);
+static enum rofferr     roff_parsetext(struct roff *, struct buf *,
+                               int, int *);
 static enum rofferr     roff_res(struct roff *, struct buf *, int, int);
 static enum rofferr     roff_rm(ROFF_ARGS);
 static enum rofferr     roff_rr(ROFF_ARGS);
@@ -213,15 +214,16 @@ static    enum rofferr     roff_userdef(ROFF_ARGS);
 #define        ROFFNUM_WHITE   (1 << 1)  /* Skip whitespace in roff_evalnum(). */
 
 const char *__roff_name[MAN_MAX + 1] = {
-       "br",           "ft",           "ll",           "mc",
-       "sp",           "ta",           "ti",           NULL,
+       "br",           "ce",           "ft",           "ll",
+       "mc",           "sp",           "ta",           "ti",
+       NULL,
        "ab",           "ad",           "af",           "aln",
        "als",          "am",           "am1",          "ami",
        "ami1",         "as",           "as1",          "asciify",
        "backtrace",    "bd",           "bleedat",      "blm",
         "box",         "boxa",         "bp",           "BP",
        "break",        "breakchar",    "brnl",         "brp",
-       "brpnl",        "c2",           "cc",           "ce",
+       "brpnl",        "c2",           "cc",
        "cf",           "cflags",       "ch",           "char",
        "chop",         "class",        "close",        "CL",
        "color",        "composite",    "continue",     "cp",
@@ -321,6 +323,7 @@ const       char *const *roff_name = __roff_name;
 
 static struct roffmac   roffs[TOKEN_NONE] = {
        { roff_br, NULL, NULL, 0 },  /* br */
+       { roff_onearg, NULL, NULL, 0 },  /* ce */
        { roff_onearg, NULL, NULL, 0 },  /* ft */
        { roff_onearg, NULL, NULL, 0 },  /* ll */
        { roff_onearg, NULL, NULL, 0 },  /* mc */
@@ -355,7 +358,6 @@ static      struct roffmac   roffs[TOKEN_NONE] = {
        { roff_line_ignore, NULL, NULL, 0 },  /* brpnl */
        { roff_unsupp, NULL, NULL, 0 },  /* c2 */
        { roff_cc, NULL, NULL, 0 },  /* cc */
-       { roff_line_ignore, NULL, NULL, 0 },  /* ce */
        { roff_insec, NULL, NULL, 0 },  /* cf */
        { roff_line_ignore, NULL, NULL, 0 },  /* cflags */
        { roff_line_ignore, NULL, NULL, 0 },  /* ch */
@@ -602,6 +604,8 @@ static      const struct predef predefs[PREDEFS_MAX] = {
 #include "predefs.in"
 };
 
+static int      roffce_lines;  /* number of input lines to center */
+static struct roff_node *roffce_node;  /* active request */
 static int      roffit_lines;  /* number of lines to delay */
 static char    *roffit_macro;  /* nil-terminated macro line */
 
@@ -1385,7 +1389,7 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
  * Process text streams.
  */
 static enum rofferr
-roff_parsetext(struct buf *buf, int pos, int *offs)
+roff_parsetext(struct roff *r, struct buf *buf, int pos, int *offs)
 {
        size_t           sz;
        const char      *start;
@@ -1407,6 +1411,16 @@ roff_parsetext(struct buf *buf, int pos, int *offs)
        } else if (roffit_lines > 1)
                --roffit_lines;
 
+       if (roffce_node != NULL && buf->buf[pos] != '\0') {
+               if (roffce_lines < 1) {
+                       r->man->last = roffce_node;
+                       r->man->next = ROFF_NEXT_SIBLING;
+                       roffce_lines = 0;
+                       roffce_node = NULL;
+               } else
+                       roffce_lines--;
+       }
+
        /* Convert all breakable hyphens into ASCII_HYPH. */
 
        start = p = buf->buf + pos;
@@ -1492,7 +1506,7 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
        if (r->tbl != NULL && ( ! ctl || buf->buf[pos] == '\0'))
                return tbl_read(r->tbl, ln, buf->buf, ppos);
        if ( ! ctl)
-               return roff_parsetext(buf, pos, offs);
+               return roff_parsetext(r, buf, pos, offs);
 
        /* Skip empty request lines. */
 
@@ -1533,6 +1547,16 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
                return tbl_read(r->tbl, ln, buf->buf, pos);
        }
 
+       /* For now, let high level macros abort .ce mode. */
+
+       if (ctl && roffce_node != NULL &&
+           (t == TOKEN_NONE || t == ROFF_EQ || t == ROFF_TS)) {
+               r->man->last = roffce_node;
+               r->man->next = ROFF_NEXT_SIBLING;
+               roffce_lines = 0;
+               roffce_node = NULL;
+       }
+
        /*
         * This is neither a roff request nor a user-defined macro.
         * Let the standard macro set parsers handle it.
@@ -2834,11 +2858,17 @@ roff_onearg(ROFF_ARGS)
 {
        struct roff_node        *n;
        char                    *cp;
+       int                      npos;
 
        if (r->man->flags & (MAN_BLINE | MAN_ELINE) &&
            (tok == ROFF_sp || tok == ROFF_ti))
                man_breakscope(r->man, tok);
 
+       if (tok == ROFF_ce && roffce_node != NULL) {
+               r->man->last = roffce_node;
+               r->man->next = ROFF_NEXT_SIBLING;
+       }
+
        roff_elem_alloc(r->man, ln, ppos, tok);
        n = r->man->last;
 
@@ -2855,8 +2885,29 @@ roff_onearg(ROFF_ARGS)
                roff_word_alloc(r->man, ln, pos, buf->buf + pos);
        }
 
-       n->flags |= NODE_LINE | NODE_VALID | NODE_ENDED;
-       r->man->last = n;
+       if (tok == ROFF_ce) {
+               if (r->man->last->tok == ROFF_ce) {
+                       roff_word_alloc(r->man, ln, pos, "1");
+                       r->man->last->flags |= NODE_NOSRC;
+               }
+               npos = 0;
+               if (roff_evalnum(r, ln, r->man->last->string, &npos,
+                   &roffce_lines, 0) == 0) {
+                       mandoc_vmsg(MANDOCERR_CE_NONUM,
+                           r->parse, ln, pos, "ce %s", buf->buf + pos);
+                       roffce_lines = 1;
+               }
+               if (roffce_lines < 1) {
+                       r->man->last = r->man->last->parent;
+                       roffce_node = NULL;
+                       roffce_lines = 0;
+               } else
+                       roffce_node = r->man->last->parent;
+       } else {
+               n->flags |= NODE_VALID | NODE_ENDED;
+               r->man->last = n;
+       }
+       n->flags |= NODE_LINE;
        r->man->next = ROFF_NEXT_SIBLING;
        return ROFF_IGN;
 }
index 0f4c3e3..24816e5 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: roff.h,v 1.31 2017/06/04 22:43:50 schwarze Exp $      */
+/*     $OpenBSD: roff.h,v 1.32 2017/06/06 15:00:56 schwarze Exp $      */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -67,6 +67,7 @@ enum  roff_type {
 
 enum   roff_tok {
        ROFF_br = 0,
+       ROFF_ce,
        ROFF_ft,
        ROFF_ll,
        ROFF_mc,
@@ -101,7 +102,6 @@ enum        roff_tok {
        ROFF_brpnl,
        ROFF_c2,
        ROFF_cc,
-       ROFF_ce,
        ROFF_cf,
        ROFF_cflags,
        ROFF_ch,
index 4974557..641ade8 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: roff_html.c,v 1.6 2017/06/04 22:43:50 schwarze Exp $ */
+/*     $OpenBSD: roff_html.c,v 1.7 2017/06/06 15:00:56 schwarze Exp $ */
 /*
  * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2014, 2017 Ingo Schwarze <schwarze@openbsd.org>
 typedef        void    (*roff_html_pre_fp)(ROFF_HTML_ARGS);
 
 static void      roff_html_pre_br(ROFF_HTML_ARGS);
+static void      roff_html_pre_ce(ROFF_HTML_ARGS);
 static void      roff_html_pre_sp(ROFF_HTML_ARGS);
 
 static const roff_html_pre_fp roff_html_pre_acts[ROFF_MAX] = {
        roff_html_pre_br,  /* br */
+       roff_html_pre_ce,  /* ce */
        NULL,  /* ft */
        NULL,  /* ll */
        NULL,  /* mc */
@@ -53,8 +55,25 @@ roff_html_pre(struct html *h, const struct roff_node *n)
 static void
 roff_html_pre_br(ROFF_HTML_ARGS)
 {
-       print_otag(h, TAG_DIV, "");
+       struct tag      *t;
+
+       t = print_otag(h, TAG_DIV, "");
        print_text(h, "\\~");  /* So the div isn't empty. */
+       print_tagq(h, t);
+}
+
+static void
+roff_html_pre_ce(ROFF_HTML_ARGS)
+{
+       for (n = n->child->next; n != NULL; n = n->next) {
+               if (n->type == ROFFT_TEXT) {
+                       if (n->flags & NODE_LINE)
+                               roff_html_pre_br(h, n);
+                       print_text(h, n->string);
+               } else
+                       roff_html_pre(h, n);
+       }
+       roff_html_pre_br(h, n);
 }
 
 static void
index 7f15f3c..dc4c740 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: roff_term.c,v 1.7 2017/06/04 22:43:50 schwarze Exp $ */
+/*     $OpenBSD: roff_term.c,v 1.8 2017/06/06 15:00:56 schwarze Exp $ */
 /*
  * Copyright (c) 2010, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
  *
@@ -28,6 +28,7 @@
 typedef        void    (*roff_term_pre_fp)(ROFF_TERM_ARGS);
 
 static void      roff_term_pre_br(ROFF_TERM_ARGS);
+static void      roff_term_pre_ce(ROFF_TERM_ARGS);
 static void      roff_term_pre_ft(ROFF_TERM_ARGS);
 static void      roff_term_pre_ll(ROFF_TERM_ARGS);
 static void      roff_term_pre_mc(ROFF_TERM_ARGS);
@@ -37,6 +38,7 @@ static        void      roff_term_pre_ti(ROFF_TERM_ARGS);
 
 static const roff_term_pre_fp roff_term_pre_acts[ROFF_MAX] = {
        roff_term_pre_br,  /* br */
+       roff_term_pre_ce,  /* ce */
        roff_term_pre_ft,  /* ft */
        roff_term_pre_ll,  /* ll */
        roff_term_pre_mc,  /* mc */
@@ -64,6 +66,43 @@ roff_term_pre_br(ROFF_TERM_ARGS)
        }
 }
 
+static void
+roff_term_pre_ce(ROFF_TERM_ARGS)
+{
+       const struct roff_node  *nch;
+       size_t                   len, lm;
+
+       roff_term_pre_br(p, n);
+       lm = p->offset;
+       n = n->child->next;
+       while (n != NULL) {
+               nch = n;
+               len = 0;
+               do {
+                       if (n->type == ROFFT_TEXT) {
+                               if (len)
+                                       len++;
+                               len += term_strlen(p, nch->string);
+                       }
+                       nch = nch->next;
+               } while (nch != NULL && (n->type != ROFFT_TEXT ||
+                   (n->flags & NODE_LINE) == 0));
+               p->offset = len >= p->rmargin ? 0 :
+                   lm + len >= p->rmargin ? p->rmargin - len :
+                   (lm + p->rmargin - len) / 2;
+               while (n != nch) {
+                       if (n->type == ROFFT_TEXT)
+                               term_word(p, n->string);
+                       else
+                               roff_term_pre(p, n);
+                       n = n->next;
+               }
+               p->flags |= TERMP_NOSPACE;
+               term_flushln(p);
+       }
+       p->offset = lm;
+}
+
 static void
 roff_term_pre_ft(ROFF_TERM_ARGS)
 {
index c1974d2..68fcf5f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: roff_validate.c,v 1.6 2017/06/04 22:43:50 schwarze Exp $ */
+/*     $OpenBSD: roff_validate.c,v 1.7 2017/06/06 15:00:56 schwarze Exp $ */
 /*
  * Copyright (c) 2010, 2017 Ingo Schwarze <schwarze@openbsd.org>
  *
@@ -32,6 +32,7 @@ static        void      roff_valid_ft(ROFF_VALID_ARGS);
 
 static const roff_valid_fp roff_valids[ROFF_MAX] = {
        NULL,  /* br */
+       NULL,  /* ce */
        roff_valid_ft,  /* ft */
        NULL,  /* ll */
        NULL,  /* mc */