]> git.cameronkatri.com Git - mandoc.git/blobdiff - roff.c
In URIs in apropos(1) result tables,
[mandoc.git] / roff.c
diff --git a/roff.c b/roff.c
index 0f8a194cdcbd0cc7c8a8a7bd39b6bef6d27eba60..268d6470ade19460f23314ccd25ff6a3156c0cbb 100644 (file)
--- a/roff.c
+++ b/roff.c
@@ -1,7 +1,7 @@
-/*     $Id: roff.c,v 1.278 2015/10/12 00:08:16 schwarze Exp $ */
+/*     $Id: roff.c,v 1.293 2017/03/09 15:29:35 schwarze Exp $ */
 /*
  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
 /*
  * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2010-2015, 2017 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
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -33,9 +33,6 @@
 #include "roff_int.h"
 #include "libroff.h"
 
 #include "roff_int.h"
 #include "libroff.h"
 
-/* Maximum number of nested if-else conditionals. */
-#define        RSTACK_MAX      128
-
 /* Maximum number of string expansions per line, to break infinite loops. */
 #define        EXPAND_LIMIT    1000
 
 /* Maximum number of string expansions per line, to break infinite loops. */
 #define        EXPAND_LIMIT    1000
 
@@ -316,7 +313,6 @@ struct      roffreg {
 
 struct roff {
        struct mparse   *parse; /* parse point */
 
 struct roff {
        struct mparse   *parse; /* parse point */
-       const struct mchars *mchars; /* character table */
        struct roffnode *last; /* leaf of stack */
        int             *rstack; /* stack of inverted `ie' values */
        struct roffreg  *regtab; /* number registers */
        struct roffnode *last; /* leaf of stack */
        int             *rstack; /* stack of inverted `ie' values */
        struct roffreg  *regtab; /* number registers */
@@ -901,13 +897,12 @@ roff_free(struct roff *r)
 }
 
 struct roff *
 }
 
 struct roff *
-roff_alloc(struct mparse *parse, const struct mchars *mchars, int options)
+roff_alloc(struct mparse *parse, int options)
 {
        struct roff     *r;
 
        r = mandoc_calloc(1, sizeof(struct roff));
        r->parse = parse;
 {
        struct roff     *r;
 
        r = mandoc_calloc(1, sizeof(struct roff));
        r->parse = parse;
-       r->mchars = mchars;
        r->options = options;
        r->format = options & (MPARSE_MDOC | MPARSE_MAN);
        r->rstackpos = -1;
        r->options = options;
        r->format = options & (MPARSE_MDOC | MPARSE_MAN);
        r->rstackpos = -1;
@@ -996,11 +991,11 @@ roff_node_alloc(struct roff_man *man, int line, int pos,
        n->sec = man->lastsec;
 
        if (man->flags & MDOC_SYNOPSIS)
        n->sec = man->lastsec;
 
        if (man->flags & MDOC_SYNOPSIS)
-               n->flags |= MDOC_SYNPRETTY;
+               n->flags |= NODE_SYNPRETTY;
        else
        else
-               n->flags &= ~MDOC_SYNPRETTY;
+               n->flags &= ~NODE_SYNPRETTY;
        if (man->flags & MDOC_NEWLINE)
        if (man->flags & MDOC_NEWLINE)
-               n->flags |= MDOC_LINE;
+               n->flags |= NODE_LINE;
        man->flags &= ~MDOC_NEWLINE;
 
        return n;
        man->flags &= ~MDOC_NEWLINE;
 
        return n;
@@ -1012,60 +1007,52 @@ roff_node_append(struct roff_man *man, struct roff_node *n)
 
        switch (man->next) {
        case ROFF_NEXT_SIBLING:
 
        switch (man->next) {
        case ROFF_NEXT_SIBLING:
+               if (man->last->next != NULL) {
+                       n->next = man->last->next;
+                       man->last->next->prev = n;
+               } else
+                       man->last->parent->last = n;
                man->last->next = n;
                n->prev = man->last;
                n->parent = man->last->parent;
                break;
        case ROFF_NEXT_CHILD:
                man->last->next = n;
                n->prev = man->last;
                n->parent = man->last->parent;
                break;
        case ROFF_NEXT_CHILD:
+               if (man->last->child != NULL) {
+                       n->next = man->last->child;
+                       man->last->child->prev = n;
+               } else
+                       man->last->last = n;
                man->last->child = n;
                n->parent = man->last;
                break;
        default:
                abort();
        }
                man->last->child = n;
                n->parent = man->last;
                break;
        default:
                abort();
        }
-       n->parent->nchild++;
-       n->parent->last = n;
-
-       /*
-        * Copy over the normalised-data pointer of our parent.  Not
-        * everybody has one, but copying a null pointer is fine.
-        */
-
-       switch (n->type) {
-       case ROFFT_BODY:
-               if (n->end != ENDBODY_NOT)
-                       break;
-               /* FALLTHROUGH */
-       case ROFFT_TAIL:
-       case ROFFT_HEAD:
-               n->norm = n->parent->norm;
-               break;
-       default:
-               break;
-       }
-
-       if (man->macroset == MACROSET_MDOC)
-               mdoc_valid_pre(man, n);
+       man->last = n;
 
        switch (n->type) {
        case ROFFT_HEAD:
 
        switch (n->type) {
        case ROFFT_HEAD:
-               assert(n->parent->type == ROFFT_BLOCK);
                n->parent->head = n;
                break;
        case ROFFT_BODY:
                n->parent->head = n;
                break;
        case ROFFT_BODY:
-               if (n->end)
-                       break;
-               assert(n->parent->type == ROFFT_BLOCK);
+               if (n->end != ENDBODY_NOT)
+                       return;
                n->parent->body = n;
                break;
        case ROFFT_TAIL:
                n->parent->body = n;
                break;
        case ROFFT_TAIL:
-               assert(n->parent->type == ROFFT_BLOCK);
                n->parent->tail = n;
                break;
        default:
                n->parent->tail = n;
                break;
        default:
-               break;
+               return;
        }
        }
-       man->last = n;
+
+       /*
+        * Copy over the normalised-data pointer of our parent.  Not
+        * everybody has one, but copying a null pointer is fine.
+        */
+
+       n->norm = n->parent->norm;
+       assert(n->parent->type == ROFFT_BLOCK);
 }
 
 void
 }
 
 void
@@ -1076,10 +1063,7 @@ roff_word_alloc(struct roff_man *man, int line, int pos, const char *word)
        n = roff_node_alloc(man, line, pos, ROFFT_TEXT, TOKEN_NONE);
        n->string = roff_strdup(man->roff, word);
        roff_node_append(man, n);
        n = roff_node_alloc(man, line, pos, ROFFT_TEXT, TOKEN_NONE);
        n->string = roff_strdup(man->roff, word);
        roff_node_append(man, n);
-       if (man->macroset == MACROSET_MDOC)
-               mdoc_valid_post(man);
-       else
-               man_valid_post(man);
+       n->flags |= NODE_VALID | NODE_ENDED;
        man->next = ROFF_NEXT_SIBLING;
 }
 
        man->next = ROFF_NEXT_SIBLING;
 }
 
@@ -1149,7 +1133,7 @@ roff_addeqn(struct roff_man *man, const struct eqn *eqn)
        n = roff_node_alloc(man, eqn->ln, eqn->pos, ROFFT_EQN, TOKEN_NONE);
        n->eqn = eqn;
        if (eqn->ln > man->last->line)
        n = roff_node_alloc(man, eqn->ln, eqn->pos, ROFFT_EQN, TOKEN_NONE);
        n->eqn = eqn;
        if (eqn->ln > man->last->line)
-               n->flags |= MDOC_LINE;
+               n->flags |= NODE_LINE;
        roff_node_append(man, n);
        man->next = ROFF_NEXT_SIBLING;
 }
        roff_node_append(man, n);
        man->next = ROFF_NEXT_SIBLING;
 }
@@ -1164,10 +1148,7 @@ roff_addtbl(struct roff_man *man, const struct tbl_span *tbl)
        n = roff_node_alloc(man, tbl->line, 0, ROFFT_TBL, TOKEN_NONE);
        n->span = tbl;
        roff_node_append(man, n);
        n = roff_node_alloc(man, tbl->line, 0, ROFFT_TBL, TOKEN_NONE);
        n->span = tbl;
        roff_node_append(man, n);
-       if (man->macroset == MACROSET_MDOC)
-               mdoc_valid_post(man);
-       else
-               man_valid_post(man);
+       n->flags |= NODE_VALID | NODE_ENDED;
        man->next = ROFF_NEXT_SIBLING;
 }
 
        man->next = ROFF_NEXT_SIBLING;
 }
 
@@ -1185,7 +1166,6 @@ roff_node_unlink(struct roff_man *man, struct roff_node *n)
        /* Adjust parent. */
 
        if (n->parent != NULL) {
        /* Adjust parent. */
 
        if (n->parent != NULL) {
-               n->parent->nchild--;
                if (n->parent->child == n)
                        n->parent->child = n->next;
                if (n->parent->last == n)
                if (n->parent->child == n)
                        n->parent->child = n->next;
                if (n->parent->last == n)
@@ -1227,7 +1207,6 @@ roff_node_delete(struct roff_man *man, struct roff_node *n)
 
        while (n->child != NULL)
                roff_node_delete(man, n->child);
 
        while (n->child != NULL)
                roff_node_delete(man, n->child);
-       assert(n->nchild == 0);
        roff_node_unlink(man, n);
        roff_node_free(n);
 }
        roff_node_unlink(man, n);
        roff_node_free(n);
 }
@@ -1244,22 +1223,25 @@ deroff(char **dest, const struct roff_node *n)
                return;
        }
 
                return;
        }
 
-       /* Skip leading whitespace and escape sequences. */
+       /* Skip leading whitespace. */
 
 
-       cp = n->string;
-       while (*cp != '\0') {
-               if ('\\' == *cp) {
-                       cp++;
-                       mandoc_escape((const char **)&cp, NULL, NULL);
-               } else if (isspace((unsigned char)*cp))
+       for (cp = n->string; *cp != '\0'; cp++) {
+               if (cp[0] == '\\' && cp[1] != '\0' &&
+                   strchr(" %&0^|~", cp[1]) != NULL)
                        cp++;
                        cp++;
-               else
+               else if ( ! isspace((unsigned char)*cp))
                        break;
        }
 
                        break;
        }
 
+       /* Skip trailing backslash. */
+
+       sz = strlen(cp);
+       if (sz > 0 && cp[sz - 1] == '\\')
+               sz--;
+
        /* Skip trailing whitespace. */
 
        /* Skip trailing whitespace. */
 
-       for (sz = strlen(cp); sz; sz--)
+       for (; sz; sz--)
                if ( ! isspace((unsigned char)cp[sz-1]))
                        break;
 
                if ( ! isspace((unsigned char)cp[sz-1]))
                        break;
 
@@ -1344,7 +1326,7 @@ roff_res(struct roff *r, struct buf *buf, int ln, int pos)
                        esc = mandoc_escape(&cp, &stnam, &inaml);
                        if (esc == ESCAPE_ERROR ||
                            (esc == ESCAPE_SPECIAL &&
                        esc = mandoc_escape(&cp, &stnam, &inaml);
                        if (esc == ESCAPE_ERROR ||
                            (esc == ESCAPE_SPECIAL &&
-                            mchars_spec2cp(r->mchars, stnam, inaml) < 0))
+                            mchars_spec2cp(stnam, inaml) < 0))
                                mandoc_vmsg(MANDOCERR_ESC_BAD,
                                    r->parse, ln, (int)(stesc - buf->buf),
                                    "%.*s", (int)(cp - stesc), stesc);
                                mandoc_vmsg(MANDOCERR_ESC_BAD,
                                    r->parse, ln, (int)(stesc - buf->buf),
                                    "%.*s", (int)(cp - stesc), stesc);
@@ -1626,7 +1608,7 @@ roff_parseln(struct roff *r, int ln, struct buf *buf, int *offs)
                        return ROFF_IGN;
                while (buf->buf[pos] != '\0' && buf->buf[pos] != ' ')
                        pos++;
                        return ROFF_IGN;
                while (buf->buf[pos] != '\0' && buf->buf[pos] != ' ')
                        pos++;
-               while (buf->buf[pos] != '\0' && buf->buf[pos] == ' ')
+               while (buf->buf[pos] == ' ')
                        pos++;
                return tbl_read(r->tbl, ln, buf->buf, pos);
        }
                        pos++;
                return tbl_read(r->tbl, ln, buf->buf, pos);
        }
@@ -3056,7 +3038,7 @@ roff_userdef(ROFF_ARGS)
 {
        const char       *arg[9], *ap;
        char             *cp, *n1, *n2;
 {
        const char       *arg[9], *ap;
        char             *cp, *n1, *n2;
-       int               i, ib, ie;
+       int               expand_count, i, ib, ie;
        size_t            asz, rsz;
 
        /*
        size_t            asz, rsz;
 
        /*
@@ -3080,8 +3062,9 @@ roff_userdef(ROFF_ARGS)
         */
 
        buf->sz = strlen(r->current_string) + 1;
         */
 
        buf->sz = strlen(r->current_string) + 1;
-       n1 = cp = mandoc_malloc(buf->sz);
+       n1 = n2 = cp = mandoc_malloc(buf->sz);
        memcpy(n1, r->current_string, buf->sz);
        memcpy(n1, r->current_string, buf->sz);
+       expand_count = 0;
        while (*cp != '\0') {
 
                /* Scan ahead for the next argument invocation. */
        while (*cp != '\0') {
 
                /* Scan ahead for the next argument invocation. */
@@ -3100,6 +3083,20 @@ roff_userdef(ROFF_ARGS)
                }
                cp -= 2;
 
                }
                cp -= 2;
 
+               /*
+                * Prevent infinite recursion.
+                */
+
+               if (cp >= n2)
+                       expand_count = 1;
+               else if (++expand_count > EXPAND_LIMIT) {
+                       mandoc_msg(MANDOCERR_ROFFLOOP, r->parse,
+                           ln, (int)(cp - n1), NULL);
+                       free(buf->buf);
+                       buf->buf = n1;
+                       return ROFF_IGN;
+               }
+
                /*
                 * Determine the size of the expanded argument,
                 * taking escaping of quotes into account.
                /*
                 * Determine the size of the expanded argument,
                 * taking escaping of quotes into account.
@@ -3383,7 +3380,8 @@ roff_strdup(const struct roff *r, const char *p)
        ssz = 0;
 
        while ('\0' != *p) {
        ssz = 0;
 
        while ('\0' != *p) {
-               if ('\\' != *p && r->xtab && r->xtab[(int)*p].p) {
+               assert((unsigned int)*p < 128);
+               if ('\\' != *p && r->xtab && r->xtab[(unsigned int)*p].p) {
                        sz = r->xtab[(int)*p].sz;
                        res = mandoc_realloc(res, ssz + sz + 1);
                        memcpy(res + ssz, r->xtab[(int)*p].p, sz);
                        sz = r->xtab[(int)*p].sz;
                        res = mandoc_realloc(res, ssz + sz + 1);
                        memcpy(res + ssz, r->xtab[(int)*p].p, sz);