From e13b41953a89d6f9c45672a4e590dd7b96ec8c86 Mon Sep 17 00:00:00 2001 From: schwarze Date: Tue, 6 Jun 2017 15:00:56 +0000 Subject: [PATCH] Minimal implementation of the roff(7) .ce request (center a number of input lines without filling). Contrary to groff, high-level macros abort .ce mode for now. --- share/man/man7/roff.7 | 9 +++-- usr.bin/mandoc/mandoc.1 | 9 ++++- usr.bin/mandoc/mandoc.h | 3 +- usr.bin/mandoc/mdoc_man.c | 6 ++- usr.bin/mandoc/read.c | 3 +- usr.bin/mandoc/roff.c | 71 +++++++++++++++++++++++++++++----- usr.bin/mandoc/roff.h | 4 +- usr.bin/mandoc/roff_html.c | 23 ++++++++++- usr.bin/mandoc/roff_term.c | 41 +++++++++++++++++++- usr.bin/mandoc/roff_validate.c | 3 +- 10 files changed, 148 insertions(+), 24 deletions(-) diff --git a/share/man/man7/roff.7 b/share/man/man7/roff.7 index 3ad9ee4f96a..c0c30372de7 100644 --- a/share/man/man7/roff.7 +++ b/share/man/man7/roff.7 @@ -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 .\" Copyright (c) 2010,2011,2013-2015,2017 Ingo Schwarze @@ -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. diff --git a/usr.bin/mandoc/mandoc.1 b/usr.bin/mandoc/mandoc.1 index 25971045f6a..2354ec21155 100644 --- a/usr.bin/mandoc/mandoc.1 +++ b/usr.bin/mandoc/mandoc.1 @@ -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 .\" Copyright (c) 2012, 2014-2017 Ingo Schwarze @@ -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 diff --git a/usr.bin/mandoc/mandoc.h b/usr.bin/mandoc/mandoc.h index f6e49fdb70b..a0ddd429047 100644 --- a/usr.bin/mandoc/mandoc.h +++ b/usr.bin/mandoc/mandoc.h @@ -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 * Copyright (c) 2010-2017 Ingo Schwarze @@ -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 */ diff --git a/usr.bin/mandoc/mdoc_man.c b/usr.bin/mandoc/mdoc_man.c index 5c4a41a47ce..8e14c4c8607 100644 --- a/usr.bin/mandoc/mdoc_man.c +++ b/usr.bin/mandoc/mdoc_man.c @@ -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 * @@ -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 diff --git a/usr.bin/mandoc/read.c b/usr.bin/mandoc/read.c index 21538c2050f..7c6ccaed233 100644 --- a/usr.bin/mandoc/read.c +++ b/usr.bin/mandoc/read.c @@ -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 * Copyright (c) 2010-2017 Ingo Schwarze @@ -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", diff --git a/usr.bin/mandoc/roff.c b/usr.bin/mandoc/roff.c index a6c19dd3a23..253586382f3 100644 --- a/usr.bin/mandoc/roff.c +++ b/usr.bin/mandoc/roff.c @@ -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 * Copyright (c) 2010-2015, 2017 Ingo Schwarze @@ -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; } diff --git a/usr.bin/mandoc/roff.h b/usr.bin/mandoc/roff.h index 0f4c3e3eba8..24816e5e4a2 100644 --- a/usr.bin/mandoc/roff.h +++ b/usr.bin/mandoc/roff.h @@ -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 * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze @@ -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, diff --git a/usr.bin/mandoc/roff_html.c b/usr.bin/mandoc/roff_html.c index 49745576933..641ade8355c 100644 --- a/usr.bin/mandoc/roff_html.c +++ b/usr.bin/mandoc/roff_html.c @@ -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 * Copyright (c) 2014, 2017 Ingo Schwarze @@ -29,10 +29,12 @@ 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 diff --git a/usr.bin/mandoc/roff_term.c b/usr.bin/mandoc/roff_term.c index 7f15f3cfa80..dc4c7400a45 100644 --- a/usr.bin/mandoc/roff_term.c +++ b/usr.bin/mandoc/roff_term.c @@ -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 * @@ -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) { diff --git a/usr.bin/mandoc/roff_validate.c b/usr.bin/mandoc/roff_validate.c index c1974d2fc6b..68fcf5f67a1 100644 --- a/usr.bin/mandoc/roff_validate.c +++ b/usr.bin/mandoc/roff_validate.c @@ -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 * @@ -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 */ -- 2.20.1