]> git.cameronkatri.com Git - mandoc.git/blobdiff - roff.c
Note that archives are being hosted at gmane.
[mandoc.git] / roff.c
diff --git a/roff.c b/roff.c
index 0c3deefe7b33ab3c22fe92818f1aa21994ed6632..b479cc298cff9ebcdc1d53227ddf7a199fd385a3 100644 (file)
--- a/roff.c
+++ b/roff.c
@@ -1,4 +1,4 @@
-/*     $Id: roff.c,v 1.168 2011/08/16 12:30:12 kristaps Exp $ */
+/*     $Id: roff.c,v 1.172 2011/10/24 21:41:45 schwarze Exp $ */
 /*
  * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
@@ -31,6 +31,9 @@
 /* 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
+
 enum   rofft {
        ROFF_ad,
        ROFF_am,
@@ -179,11 +182,11 @@ static    const char      *roff_getstrn(const struct roff *,
                                const char *, size_t);
 static enum rofferr     roff_line_ignore(ROFF_ARGS);
 static enum rofferr     roff_nr(ROFF_ARGS);
-static void             roff_openeqn(struct roff *, const char *, 
+static void             roff_openeqn(struct roff *, const char *,
                                int, int, const char *);
 static enum rofft       roff_parse(struct roff *, const char *, int *);
 static enum rofferr     roff_parsetext(char *);
-static void             roff_res(struct roff *, 
+static enum rofferr     roff_res(struct roff *, 
                                char **, size_t *, int, int);
 static enum rofferr     roff_rm(ROFF_ARGS);
 static void             roff_setstr(struct roff *,
@@ -429,7 +432,7 @@ roff_alloc(struct mparse *parse)
  * is processed. 
  * This also checks the syntax of regular escapes.
  */
-static void
+static enum rofferr
 roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
 {
        enum mandoc_esc  esc;
@@ -437,10 +440,12 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
        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 */
-       int              i, maxl;
+       int              i, maxl, expand_count;
        size_t           nsz;
        char            *n;
 
+       expand_count = 0;
+
 again:
        cp = *bufp + pos;
        while (NULL != (cp = strchr(cp, '\\'))) {
@@ -453,7 +458,7 @@ again:
                 */
 
                if ('\0' == *cp)
-                       return;
+                       return(ROFF_CONT);
 
                if ('*' != *cp) {
                        res = cp;
@@ -464,7 +469,7 @@ again:
                        mandoc_msg
                                (MANDOCERR_BADESCAPE, r->parse, 
                                 ln, (int)(stesc - *bufp), NULL);
-                       return;
+                       return(ROFF_CONT);
                }
 
                cp++;
@@ -477,7 +482,7 @@ again:
 
                switch (*cp) {
                case ('\0'):
-                       return;
+                       return(ROFF_CONT);
                case ('('):
                        cp++;
                        maxl = 2;
@@ -500,7 +505,7 @@ again:
                                        (MANDOCERR_BADESCAPE, 
                                         r->parse, ln, 
                                         (int)(stesc - *bufp), NULL);
-                               return;
+                               return(ROFF_CONT);
                        }
                        if (0 == maxl && ']' == *cp)
                                break;
@@ -535,8 +540,15 @@ again:
 
                *bufp = n;
                *szp = nsz;
-               goto again;
+
+               if (EXPAND_LIMIT >= ++expand_count)
+                       goto again;
+
+               /* Just leave the string unexpanded. */
+               mandoc_msg(MANDOCERR_ROFFLOOP, r->parse, ln, pos, NULL);
+               return(ROFF_IGN);
        }
+       return(ROFF_CONT);
 }
 
 /*
@@ -545,7 +557,6 @@ again:
 static enum rofferr
 roff_parsetext(char *p)
 {
-       char             l, r;
        size_t           sz;
        const char      *start;
        enum mandoc_esc  esc;
@@ -572,14 +583,8 @@ roff_parsetext(char *p)
                        continue;
                }
 
-               l = *(p - 1);
-               r = *(p + 1);
-               if ('\\' != l &&
-                               '\t' != r && '\t' != l &&
-                               ' ' != r && ' ' != l &&
-                               '-' != r && '-' != l &&
-                               ! isdigit((unsigned char)l) &&
-                               ! isdigit((unsigned char)r))
+               if (isalpha((unsigned char)p[-1]) &&
+                   isalpha((unsigned char)p[1]))
                        *p = ASCII_HYPH;
                p++;
        }
@@ -600,7 +605,10 @@ roff_parseln(struct roff *r, int ln, char **bufp,
         * words to fill in.
         */
 
-       roff_res(r, bufp, szp, ln, pos);
+       e = roff_res(r, bufp, szp, ln, pos);
+       if (ROFF_IGN == e)
+               return(e);
+       assert(ROFF_CONT == e);
 
        ppos = pos;
        ctl = mandoc_getcontrol(*bufp, &pos);