]> git.cameronkatri.com Git - mandoc.git/blobdiff - roff.c
Eliminate the class=It-* attributes.
[mandoc.git] / roff.c
diff --git a/roff.c b/roff.c
index 2411477eb2bf81baf3cbfa85464df02b5e4869c9..c0ccca87211b4f0f4302ed7de709364d4b871fb8 100644 (file)
--- a/roff.c
+++ b/roff.c
@@ -1,7 +1,7 @@
-/*     $Id: roff.c,v 1.323 2017/07/14 16:49:39 schwarze Exp $ */
+/*     $Id: roff.c,v 1.328 2018/04/11 17:11:13 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2015, 2017, 2018 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
@@ -46,6 +46,7 @@
 #define        ROFFDEF_STD     (1 << 4)  /* mdoc(7) or man(7) macro. */
 #define        ROFFDEF_ANY     (ROFFDEF_USER | ROFFDEF_PRE | \
                         ROFFDEF_REN | ROFFDEF_STD)
+#define        ROFFDEF_UNDEF   (1 << 5)  /* Completely undefined. */
 
 /* --- data types --------------------------------------------------------- */
 
@@ -72,6 +73,7 @@ struct        roffkv {
 struct roffreg {
        struct roffstr   key;
        int              val;
+       int              step;
        struct roffreg  *next;
 };
 
@@ -181,11 +183,11 @@ static    void             roff_freestr(struct roffkv *);
 static size_t           roff_getname(struct roff *, char **, int, int);
 static int              roff_getnum(const char *, int *, int *, int);
 static int              roff_getop(const char *, int *, char *);
-static int              roff_getregn(const struct roff *,
-                               const char *, size_t);
+static int              roff_getregn(struct roff *,
+                               const char *, size_t, char);
 static int              roff_getregro(const struct roff *,
                                const char *name);
-static const char      *roff_getstrn(const struct roff *,
+static const char      *roff_getstrn(struct roff *,
                                const char *, size_t, int *);
 static int              roff_hasregn(const struct roff *,
                                const char *, size_t);
@@ -206,6 +208,8 @@ 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_setregn(struct roff *, const char *,
+                               size_t, int, char, int);
 static void             roff_setstr(struct roff *,
                                const char *, const char *, int);
 static void             roff_setstrn(struct roffkv **, const char *,
@@ -758,7 +762,7 @@ roff_alloc(struct mparse *parse, int options)
 
        r = mandoc_calloc(1, sizeof(struct roff));
        r->parse = parse;
-       r->reqtab = roffhash_alloc(0, ROFF_USERDEF);
+       r->reqtab = roffhash_alloc(0, ROFF_RENAMED);
        r->options = options;
        r->format = options & (MPARSE_MDOC | MPARSE_MAN);
        r->rstackpos = -1;
@@ -1118,8 +1122,10 @@ static enum rofferr
 roff_res(struct roff *r, struct buf *buf, int ln, int pos)
 {
        char             ubuf[24]; /* buffer to print the number */
+       struct roff_node *n;    /* used for header comments */
        const char      *start; /* start of the string to process */
        char            *stesc; /* start of an escape sequence ('\\') */
+       char            *ep;    /* end of comment string */
        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 */
@@ -1134,6 +1140,7 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
        int              done;  /* no more input available */
        int              deftype; /* type of definition to paste */
        int              rcsid; /* kind of RCS id seen */
+       char             sign;  /* increment number register */
        char             term;  /* character terminating the escape */
 
        /* Search forward for comments. */
@@ -1168,14 +1175,35 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
 
                /* Handle trailing whitespace. */
 
-               cp = strchr(stesc--, '\0') - 1;
-               if (*cp == '\n') {
+               ep = strchr(stesc--, '\0') - 1;
+               if (*ep == '\n') {
                        done = 1;
-                       cp--;
+                       ep--;
                }
-               if (*cp == ' ' || *cp == '\t')
+               if (*ep == ' ' || *ep == '\t')
                        mandoc_msg(MANDOCERR_SPACE_EOL, r->parse,
-                           ln, cp - buf->buf, NULL);
+                           ln, ep - buf->buf, NULL);
+
+               /*
+                * Save comments preceding the title macro
+                * in the syntax tree.
+                */
+
+               if (r->format == 0) {
+                       while (*ep == ' ' || *ep == '\t')
+                               ep--;
+                       ep[1] = '\0';
+                       n = roff_node_alloc(r->man,
+                           ln, stesc + 1 - buf->buf,
+                           ROFFT_COMMENT, TOKEN_NONE);
+                       n->string = mandoc_strdup(stesc + 2);
+                       roff_node_append(r->man, n);
+                       n->flags |= NODE_VALID | NODE_ENDED;
+                       r->man->next = ROFF_NEXT_SIBLING;
+               }
+
+               /* Discard comments. */
+
                while (stesc > start && stesc[-1] == ' ')
                        stesc--;
                *stesc = '\0';
@@ -1244,6 +1272,9 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
                        term = cp[1];
                        /* FALLTHROUGH */
                case 'n':
+                       sign = cp[1];
+                       if (sign == '+' || sign == '-')
+                               cp++;
                        res = ubuf;
                        break;
                default:
@@ -1348,7 +1379,7 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
                case 'n':
                        if (arg_complete)
                                (void)snprintf(ubuf, sizeof(ubuf), "%d",
-                                   roff_getregn(r, stnam, naml));
+                                   roff_getregn(r, stnam, naml, sign));
                        else
                                ubuf[0] = '\0';
                        break;
@@ -1559,7 +1590,8 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
        /* For now, let high level macros abort .ce mode. */
 
        if (ctl && roffce_node != NULL &&
-           (t == TOKEN_NONE || t == ROFF_EQ || t == ROFF_TS)) {
+           (t == TOKEN_NONE || t == ROFF_Dd || t == ROFF_EQ ||
+            t == ROFF_TH || t == ROFF_TS)) {
                r->man->last = roffce_node;
                r->man->next = ROFF_NEXT_SIBLING;
                roffce_lines = 0;
@@ -1638,6 +1670,11 @@ roff_parse(struct roff *r, char *buf, int *pos, int ln, int ppos)
        }
        if (t != TOKEN_NONE)
                *pos = cp - buf;
+       else if (deftype == ROFFDEF_UNDEF) {
+               /* Using an undefined macro defines it to be empty. */
+               roff_setstrn(&r->strtab, mac, maclen, "", 0, 0);
+               roff_setstrn(&r->rentab, mac, maclen, NULL, 0, 0);
+       }
        return t;
 }
 
@@ -2513,21 +2550,30 @@ roff_evalnum(struct roff *r, int ln, const char *v,
 
 void
 roff_setreg(struct roff *r, const char *name, int val, char sign)
+{
+       roff_setregn(r, name, strlen(name), val, sign, INT_MIN);
+}
+
+static void
+roff_setregn(struct roff *r, const char *name, size_t len,
+    int val, char sign, int step)
 {
        struct roffreg  *reg;
 
        /* Search for an existing register with the same name. */
        reg = r->regtab;
 
-       while (reg && strcmp(name, reg->key.p))
+       while (reg != NULL && (reg->key.sz != len ||
+           strncmp(reg->key.p, name, len) != 0))
                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->key.p = mandoc_strndup(name, len);
+               reg->key.sz = len;
                reg->val = 0;
+               reg->step = 0;
                reg->next = r->regtab;
                r->regtab = reg;
        }
@@ -2538,6 +2584,8 @@ roff_setreg(struct roff *r, const char *name, int val, char sign)
                reg->val -= val;
        else
                reg->val = val;
+       if (step != INT_MIN)
+               reg->step = step;
 }
 
 /*
@@ -2571,26 +2619,13 @@ roff_getregro(const struct roff *r, const char *name)
 }
 
 int
-roff_getreg(const struct roff *r, const char *name)
+roff_getreg(struct roff *r, const char *name)
 {
-       struct roffreg  *reg;
-       int              val;
-
-       if ('.' == name[0] && '\0' != name[1] && '\0' == name[2]) {
-               val = roff_getregro(r, name + 1);
-               if (-1 != val)
-                       return val;
-       }
-
-       for (reg = r->regtab; reg; reg = reg->next)
-               if (0 == strcmp(name, reg->key.p))
-                       return reg->val;
-
-       return 0;
+       return roff_getregn(r, name, strlen(name), '\0');
 }
 
 static int
-roff_getregn(const struct roff *r, const char *name, size_t len)
+roff_getregn(struct roff *r, const char *name, size_t len, char sign)
 {
        struct roffreg  *reg;
        int              val;
@@ -2601,11 +2636,24 @@ roff_getregn(const struct roff *r, const char *name, size_t len)
                        return val;
        }
 
-       for (reg = r->regtab; reg; reg = reg->next)
+       for (reg = r->regtab; reg; reg = reg->next) {
                if (len == reg->key.sz &&
-                   0 == strncmp(name, reg->key.p, len))
+                   0 == strncmp(name, reg->key.p, len)) {
+                       switch (sign) {
+                       case '+':
+                               reg->val += reg->step;
+                               break;
+                       case '-':
+                               reg->val -= reg->step;
+                               break;
+                       default:
+                               break;
+                       }
                        return reg->val;
+               }
+       }
 
+       roff_setregn(r, name, len, 0, '\0', INT_MIN);
        return 0;
 }
 
@@ -2645,9 +2693,9 @@ roff_freereg(struct roffreg *reg)
 static enum rofferr
 roff_nr(ROFF_ARGS)
 {
-       char            *key, *val;
+       char            *key, *val, *step;
        size_t           keysz;
-       int              iv;
+       int              iv, is, len;
        char             sign;
 
        key = val = buf->buf + pos;
@@ -2657,15 +2705,22 @@ roff_nr(ROFF_ARGS)
        keysz = roff_getname(r, &val, ln, pos);
        if (key[keysz] == '\\')
                return ROFF_IGN;
-       key[keysz] = '\0';
 
        sign = *val;
        if (sign == '+' || sign == '-')
                val++;
 
-       if (roff_evalnum(r, ln, val, NULL, &iv, ROFFNUM_SCALE))
-               roff_setreg(r, key, iv, sign);
+       len = 0;
+       if (roff_evalnum(r, ln, val, &len, &iv, ROFFNUM_SCALE) == 0)
+               return ROFF_IGN;
+
+       step = val + len;
+       while (isspace((unsigned char)*step))
+               step++;
+       if (roff_evalnum(r, ln, step, NULL, &is, 0) == 0)
+               is = INT_MIN;
 
+       roff_setregn(r, key, keysz, iv, sign, is);
        return ROFF_IGN;
 }
 
@@ -3536,62 +3591,95 @@ roff_setstrn(struct roffkv **r, const char *name, size_t namesz,
 }
 
 static const char *
-roff_getstrn(const struct roff *r, const char *name, size_t len,
+roff_getstrn(struct roff *r, const char *name, size_t len,
     int *deftype)
 {
        const struct roffkv     *n;
-       int                      i;
+       int                      found, i;
        enum roff_tok            tok;
 
-       if (*deftype & ROFFDEF_USER) {
-               for (n = r->strtab; n != NULL; n = n->next) {
-                       if (strncmp(name, n->key.p, len) == 0 &&
-                           n->key.p[len] == '\0' &&
-                           n->val.p != NULL) {
-                               *deftype = ROFFDEF_USER;
-                               return n->val.p;
-                       }
+       found = 0;
+       for (n = r->strtab; n != NULL; n = n->next) {
+               if (strncmp(name, n->key.p, len) != 0 ||
+                   n->key.p[len] != '\0' || n->val.p == NULL)
+                       continue;
+               if (*deftype & ROFFDEF_USER) {
+                       *deftype = ROFFDEF_USER;
+                       return n->val.p;
+               } else {
+                       found = 1;
+                       break;
                }
        }
-       if (*deftype & ROFFDEF_PRE) {
-               for (i = 0; i < PREDEFS_MAX; i++) {
-                       if (strncmp(name, predefs[i].name, len) == 0 &&
-                           predefs[i].name[len] == '\0') {
-                               *deftype = ROFFDEF_PRE;
-                               return predefs[i].str;
-                       }
+       for (n = r->rentab; n != NULL; n = n->next) {
+               if (strncmp(name, n->key.p, len) != 0 ||
+                   n->key.p[len] != '\0' || n->val.p == NULL)
+                       continue;
+               if (*deftype & ROFFDEF_REN) {
+                       *deftype = ROFFDEF_REN;
+                       return n->val.p;
+               } else {
+                       found = 1;
+                       break;
                }
        }
-       if (*deftype & ROFFDEF_REN) {
-               for (n = r->rentab; n != NULL; n = n->next) {
-                       if (strncmp(name, n->key.p, len) == 0 &&
-                           n->key.p[len] == '\0' &&
-                           n->val.p != NULL) {
-                               *deftype = ROFFDEF_REN;
-                               return n->val.p;
-                       }
+       for (i = 0; i < PREDEFS_MAX; i++) {
+               if (strncmp(name, predefs[i].name, len) != 0 ||
+                   predefs[i].name[len] != '\0')
+                       continue;
+               if (*deftype & ROFFDEF_PRE) {
+                       *deftype = ROFFDEF_PRE;
+                       return predefs[i].str;
+               } else {
+                       found = 1;
+                       break;
                }
        }
-       if (*deftype & ROFFDEF_STD) {
-               if (r->man->macroset != MACROSET_MAN) {
-                       for (tok = MDOC_Dd; tok < MDOC_MAX; tok++) {
-                               if (strncmp(name, roff_name[tok], len) == 0 &&
-                                   roff_name[tok][len] == '\0') {
-                                       *deftype = ROFFDEF_STD;
-                                       return NULL;
-                               }
+       if (r->man->macroset != MACROSET_MAN) {
+               for (tok = MDOC_Dd; tok < MDOC_MAX; tok++) {
+                       if (strncmp(name, roff_name[tok], len) != 0 ||
+                           roff_name[tok][len] != '\0')
+                               continue;
+                       if (*deftype & ROFFDEF_STD) {
+                               *deftype = ROFFDEF_STD;
+                               return NULL;
+                       } else {
+                               found = 1;
+                               break;
                        }
                }
-               if (r->man->macroset != MACROSET_MDOC) {
-                       for (tok = MAN_TH; tok < MAN_MAX; tok++) {
-                               if (strncmp(name, roff_name[tok], len) == 0 &&
-                                   roff_name[tok][len] == '\0') {
-                                       *deftype = ROFFDEF_STD;
-                                       return NULL;
-                               }
+       }
+       if (r->man->macroset != MACROSET_MDOC) {
+               for (tok = MAN_TH; tok < MAN_MAX; tok++) {
+                       if (strncmp(name, roff_name[tok], len) != 0 ||
+                           roff_name[tok][len] != '\0')
+                               continue;
+                       if (*deftype & ROFFDEF_STD) {
+                               *deftype = ROFFDEF_STD;
+                               return NULL;
+                       } else {
+                               found = 1;
+                               break;
                        }
                }
        }
+
+       if (found == 0 && *deftype != ROFFDEF_ANY) {
+               if (*deftype & ROFFDEF_REN) {
+                       /*
+                        * This might still be a request,
+                        * so do not treat it as undefined yet.
+                        */
+                       *deftype = ROFFDEF_UNDEF;
+                       return NULL;
+               }
+
+               /* Using an undefined string defines it to be empty. */
+
+               roff_setstrn(&r->strtab, name, len, "", 0, 0);
+               roff_setstrn(&r->rentab, name, len, NULL, 0, 0);
+       }
+
        *deftype = 0;
        return NULL;
 }