Implement the roff(7) .rn (rename macro or string) request.
authorschwarze <schwarze@openbsd.org>
Wed, 7 Jun 2017 00:50:30 +0000 (00:50 +0000)
committerschwarze <schwarze@openbsd.org>
Wed, 7 Jun 2017 00:50:30 +0000 (00:50 +0000)
Renaming a user-defined macro is very simple: just copy
the definition to the new name and delete the old name.
Renaming high-level macros is a bit tricky: use a dedicated
key-value-table, with non-standard names as keys and standard
names as values.  When a macro is found that is not user-defined,
look it up in the "renamed" table and translate it back to the
standard name before passing it on to the high-level parsers.

share/man/man7/roff.7
usr.bin/mandoc/roff.c
usr.bin/mandoc/roff.h

index c0c3037..b3fe9f5 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: roff.7,v 1.65 2017/06/06 15:00:56 schwarze Exp $
+.\"    $OpenBSD: roff.7,v 1.66 2017/06/07 00:50:30 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 6 2017 $
+.Dd $Mdocdate: June 7 2017 $
 .Dt ROFF 7
 .Os
 .Sh NAME
@@ -528,7 +528,7 @@ input lines without filling.
 .Ar N
 defaults to 1.
 An argument of 0 or less ends centering.
-Currently, high level macros abort certering.
+Currently, high level macros abort centering.
 .It Ic \&cf Ar filename
 Output the contents of a file.
 Ignored because insecure.
@@ -1480,7 +1480,16 @@ Currently ignored.
 Remove a request, macro or string.
 .It Ic \&rn Ar oldname newname
 Rename a request, macro, diversion, or string.
-Currently unsupported.
+In
+.Xr mandoc 1 ,
+user-defined macros,
+.Xr mdoc 7
+and
+.Xr man 7
+macros, and user-defined strings can be renamed, but renaming of
+predefined strings and of
+.Nm
+requests is not supported, and diversions are not implemented at all.
 .It Ic \&rnn Ar oldname newname
 Rename a number register.
 Currently unsupported.
index 2535863..d1b83cb 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: roff.c,v 1.177 2017/06/06 15:00:56 schwarze Exp $ */
+/*     $OpenBSD: roff.c,v 1.178 2017/06/07 00:50:30 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -81,6 +81,7 @@ struct        roff {
        struct ohash    *reqtab; /* request lookup table */
        struct roffreg  *regtab; /* number registers */
        struct roffkv   *strtab; /* user-defined strings & macros */
+       struct roffkv   *rentab; /* renamed strings & macros */
        struct roffkv   *xmbtab; /* multi-byte trans table (`tr') */
        struct roffstr  *xtab; /* single-byte trans table (`tr') */
        const char      *current_string; /* value of last called user macro */
@@ -173,6 +174,8 @@ static      int              roff_getregn(const struct roff *,
                                const char *, size_t);
 static int              roff_getregro(const struct roff *,
                                const char *name);
+static const char      *roff_getrenn(const struct roff *,
+                               const char *, size_t);
 static const char      *roff_getstrn(const struct roff *,
                                const char *, size_t);
 static int              roff_hasregn(const struct roff *,
@@ -189,8 +192,10 @@ static     enum roff_tok    roff_parse(struct roff *, char *, int *,
                                int, int);
 static enum rofferr     roff_parsetext(struct roff *, struct buf *,
                                int, int *);
+static enum rofferr     roff_renamed(ROFF_ARGS);
 static enum rofferr     roff_res(struct roff *, struct buf *, int, int);
 static enum rofferr     roff_rm(ROFF_ARGS);
+static enum rofferr     roff_rn(ROFF_ARGS);
 static enum rofferr     roff_rr(ROFF_ARGS);
 static void             roff_setstr(struct roff *,
                                const char *, const char *, int);
@@ -276,7 +281,7 @@ const char *__roff_name[MAN_MAX + 1] = {
        "warnscale",    "watch",        "watchlength",  "watchn",
        "wh",           "while",        "write",        "writec",
        "writem",       "xflag",        ".",            NULL,
-       "text",
+       NULL,           "text",
        "Dd",           "Dt",           "Os",           "Sh",
        "Ss",           "Pp",           "D1",           "Dl",
        "Bd",           "Ed",           "Bl",           "El",
@@ -506,7 +511,7 @@ static      struct roffmac   roffs[TOKEN_NONE] = {
        { roff_line_ignore, NULL, NULL, 0 },  /* rhang */
        { roff_line_ignore, NULL, NULL, 0 },  /* rj */
        { roff_rm, NULL, NULL, 0 },  /* rm */
-       { roff_unsupp, NULL, NULL, 0 },  /* rn */
+       { roff_rn, NULL, NULL, 0 },  /* rn */
        { roff_unsupp, NULL, NULL, 0 },  /* rnn */
        { roff_rr, NULL, NULL, 0 },  /* rr */
        { roff_line_ignore, NULL, NULL, 0 },  /* rs */
@@ -562,6 +567,7 @@ static      struct roffmac   roffs[TOKEN_NONE] = {
        { roff_insec, NULL, NULL, 0 },  /* writem */
        { roff_line_ignore, NULL, NULL, 0 },  /* xflag */
        { roff_cblock, NULL, NULL, 0 },  /* . */
+       { roff_renamed, NULL, NULL, 0 },
        { roff_userdef, NULL, NULL, 0 }
 };
 
@@ -741,8 +747,9 @@ roff_free1(struct roff *r)
        r->regtab = NULL;
 
        roff_freestr(r->strtab);
+       roff_freestr(r->rentab);
        roff_freestr(r->xmbtab);
-       r->strtab = r->xmbtab = NULL;
+       r->strtab = r->rentab = r->xmbtab = NULL;
 
        if (r->xtab)
                for (i = 0; i < 128; i++)
@@ -1612,8 +1619,10 @@ roff_parse(struct roff *r, char *buf, int *pos, int ln, int ppos)
        mac = cp;
        maclen = roff_getname(r, &cp, ln, ppos);
 
-       t = (r->current_string = roff_getstrn(r, mac, maclen))
-           ? ROFF_USERDEF : roffhash_find(r->reqtab, mac, maclen);
+       t = (r->current_string = roff_getstrn(r, mac, maclen)) ?
+           ROFF_USERDEF :
+           (r->current_string = roff_getrenn(r, mac, maclen)) ?
+           ROFF_RENAMED : roffhash_find(r->reqtab, mac, maclen);
 
        if (t != TOKEN_NONE)
                *pos = cp - buf;
@@ -3055,6 +3064,56 @@ roff_tr(ROFF_ARGS)
        return ROFF_IGN;
 }
 
+static enum rofferr
+roff_rn(ROFF_ARGS)
+{
+       const char      *value;
+       char            *oldn, *newn, *end;
+       size_t           oldsz, newsz;
+
+       oldn = newn = buf->buf + pos;
+       if (*oldn == '\0')
+               return ROFF_IGN;
+
+       oldsz = roff_getname(r, &newn, ln, pos);
+       if (oldn[oldsz] == '\\' || *newn == '\0')
+               return ROFF_IGN;
+
+       end = newn;
+       newsz = roff_getname(r, &end, ln, newn - buf->buf);
+       if (newsz == 0)
+               return ROFF_IGN;
+
+       /*
+        * Rename a user-defined macro bearing the old name,
+        * overriding an existing renamed high-level macro
+        * bearing the new name, if that exists.
+        */
+
+       if ((value = roff_getstrn(r, oldn, oldsz)) != NULL) {
+               roff_setstrn(&r->strtab, newn, newsz, value, strlen(value), 0);
+               roff_setstrn(&r->strtab, oldn, oldsz, NULL, 0, 0);
+               roff_setstrn(&r->rentab, newn, newsz, NULL, 0, 0);
+               return ROFF_IGN;
+       }
+
+       /*
+        * Rename a high-level macro bearing the old name,
+        * either renaming it a second time if it was already
+        * renamed before, or renaming it for the first time.
+        * In both cases, override an existing user-defined
+        * macro bearing the new name, if that exists.
+        */
+
+       if ((value = roff_getrenn(r, oldn, oldsz)) != NULL) {
+               roff_setstrn(&r->rentab, newn, newsz, value, strlen(value), 0);
+               roff_setstrn(&r->rentab, oldn, oldsz, NULL, 0, 0);
+       } else
+               roff_setstrn(&r->rentab, newn, newsz, oldn, oldsz, 0);
+       roff_setstrn(&r->strtab, newn, newsz, NULL, 0, 0);
+       return ROFF_IGN;
+}
+
 static enum rofferr
 roff_so(ROFF_ARGS)
 {
@@ -3229,6 +3288,22 @@ roff_userdef(ROFF_ARGS)
           ROFF_REPARSE : ROFF_APPEND;
 }
 
+/*
+ * Calling a high-level macro that was renamed with .rn.
+ * r->current_string has already been set up by roff_parse().
+ */
+static enum rofferr
+roff_renamed(ROFF_ARGS)
+{
+       char    *nbuf;
+
+       buf->sz = mandoc_asprintf(&nbuf, ".%s %s", r->current_string,
+           buf->buf + pos) + 1;
+       free(buf->buf);
+       buf->buf = nbuf;
+       return ROFF_CONT;
+}
+
 static size_t
 roff_getname(struct roff *r, char **cpp, int ln, int pos)
 {
@@ -3374,6 +3449,23 @@ roff_getstrn(const struct roff *r, const char *name, size_t len)
        return NULL;
 }
 
+/*
+ * Check whether *name is the renamed name of a high-level macro.
+ * Return the standard name, or NULL if it is not.
+ */
+static const char *
+roff_getrenn(const struct roff *r, const char *name, size_t len)
+{
+       const struct roffkv *n;
+
+       for (n = r->rentab; n; n = n->next)
+               if (0 == strncmp(name, n->key.p, len) &&
+                   '\0' == n->key.p[(int)len])
+                       return n->val.p;
+
+       return NULL;
+}
+
 static void
 roff_freestr(struct roffkv *r)
 {
index 24816e5..c1ce3b2 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: roff.h,v 1.32 2017/06/06 15:00:56 schwarze Exp $      */
+/*     $OpenBSD: roff.h,v 1.33 2017/06/07 00:50:30 schwarze Exp $      */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -309,6 +309,7 @@ enum        roff_tok {
        ROFF_writem,
        ROFF_xflag,
        ROFF_cblock,
+       ROFF_RENAMED,
        ROFF_USERDEF,
        TOKEN_NONE,
        MDOC_Dd,