]> git.cameronkatri.com Git - mandoc.git/blobdiff - roff.c
Update mandoc_hyph() to the extent that numbers on either side of the
[mandoc.git] / roff.c
diff --git a/roff.c b/roff.c
index 8f74edf0139db7821c666eede32181f4de7ffe0e..498e85be2ca37ff86fab7caab9e86b4462817f4c 100644 (file)
--- a/roff.c
+++ b/roff.c
@@ -1,4 +1,4 @@
-/*     $Id: roff.c,v 1.143 2011/06/30 08:05:13 kristaps Exp $ */
+/*     $Id: roff.c,v 1.153 2011/07/26 14:24:06 kristaps Exp $ */
 /*
  * Copyright (c) 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
@@ -71,6 +71,16 @@ enum roffrule {
        ROFFRULE_DENY
 };
 
+/*
+ * A single register entity.  If "set" is zero, the value of the
+ * register should be the default one, which is per-register.
+ * Registers are assumed to be unsigned ints for now.
+ */
+struct reg {
+       int               set; /* whether set or not */
+       unsigned int      u; /* unsigned integer */
+};
+
 struct roffstr {
        char            *name; /* key of symbol */
        char            *string; /* current value */
@@ -82,7 +92,7 @@ struct        roff {
        struct roffnode *last; /* leaf of stack */
        enum roffrule    rstack[RSTACK_MAX]; /* stack of !`ie' rules */
        int              rstackpos; /* position in rstack */
-       struct regset   *regs; /* read/writable registers */
+       struct reg       regs[REG__MAX];
        struct roffstr  *first_string; /* user-defined strings & macros */
        const char      *current_string; /* value of last called user macro */
        struct tbl_node *first_tbl; /* first table parsed */
@@ -351,6 +361,8 @@ roff_reset(struct roff *r)
 
        roff_free1(r);
 
+       memset(&r->regs, 0, sizeof(struct reg) * REG__MAX);
+
        for (i = 0; i < PREDEFS_MAX; i++) 
                roff_setstr(r, predefs[i].name, predefs[i].str, 0);
 }
@@ -366,13 +378,12 @@ roff_free(struct roff *r)
 
 
 struct roff *
-roff_alloc(struct regset *regs, struct mparse *parse)
+roff_alloc(struct mparse *parse)
 {
        struct roff     *r;
        int              i;
 
        r = mandoc_calloc(1, sizeof(struct roff));
-       r->regs = regs;
        r->parse = parse;
        r->rstackpos = -1;
        
@@ -384,15 +395,16 @@ roff_alloc(struct regset *regs, struct mparse *parse)
        return(r);
 }
 
-
 /*
  * Pre-filter each and every line for reserved words (one beginning with
  * `\*', e.g., `\*(ab').  These must be handled before the actual line
  * is processed. 
- */
+ * This also checks the syntax of regular escapes.
+*/
 static int
 roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
 {
+       enum mandoc_esc  esc;
        const char      *stesc; /* start of an escape sequence ('\\') */
        const char      *stnam; /* start of the name, after "[(*" */
        const char      *cp;    /* end of the name, e.g. before ']' */
@@ -415,8 +427,20 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
 
                if ('\0' == *cp)
                        return(1);
-               if ('*' != *cp++)
+
+               if ('*' != *cp) {
+                       res = cp;
+                       esc = mandoc_escape(&cp, NULL, NULL);
+                       if (ESCAPE_ERROR != esc)
+                               continue;
+                       cp = res;
+                       mandoc_msg
+                               (MANDOCERR_BADESCAPE, r->parse, 
+                                ln, (int)(stesc - *bufp), NULL);
                        continue;
+               }
+
+               cp++;
 
                /*
                 * The third character decides the length
@@ -444,8 +468,13 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
                /* Advance to the end of the name. */
 
                for (i = 0; 0 == maxl || i < maxl; i++, cp++) {
-                       if ('\0' == *cp)
-                               return(1); /* Error. */
+                       if ('\0' == *cp) {
+                               mandoc_msg
+                                       (MANDOCERR_BADESCAPE, 
+                                        r->parse, ln, 
+                                        (int)(stesc - *bufp), NULL);
+                               return(1); 
+                       }
                        if (0 == maxl && ']' == *cp)
                                break;
                }
@@ -458,8 +487,9 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
                res = roff_getstrn(r, stnam, (size_t)i);
 
                if (NULL == res) {
-                       /* TODO: keep track of the correct position. */
-                       mandoc_msg(MANDOCERR_BADESCAPE, r->parse, ln, pos, NULL);
+                       mandoc_msg
+                               (MANDOCERR_BADESCAPE, r->parse, 
+                                ln, (int)(stesc - *bufp), NULL);
                        res = "";
                }
 
@@ -482,7 +512,6 @@ roff_res(struct roff *r, char **bufp, size_t *szp, int ln, int pos)
        return(1);
 }
 
-
 enum rofferr
 roff_parseln(struct roff *r, int ln, char **bufp, 
                size_t *szp, int pos, int *offs)
@@ -496,7 +525,7 @@ roff_parseln(struct roff *r, int ln, char **bufp,
         * words to fill in.
         */
 
-       if (r->first_string && ! roff_res(r, bufp, szp, ln, pos))
+       if ( ! roff_res(r, bufp, szp, ln, pos))
                return(ROFF_REPARSE);
 
        ppos = pos;
@@ -519,18 +548,18 @@ roff_parseln(struct roff *r, int ln, char **bufp,
                if (ROFF_CONT != e)
                        return(e);
                if (r->eqn)
-                       return(eqn_read(&r->eqn, ln, *bufp, pos));
+                       return(eqn_read(&r->eqn, ln, *bufp, pos, offs));
                if (r->tbl)
                        return(tbl_read(r->tbl, ln, *bufp, pos));
                return(ROFF_CONT);
        } else if ( ! ctl) {
                if (r->eqn)
-                       return(eqn_read(&r->eqn, ln, *bufp, pos));
+                       return(eqn_read(&r->eqn, ln, *bufp, pos, offs));
                if (r->tbl)
                        return(tbl_read(r->tbl, ln, *bufp, pos));
                return(ROFF_CONT);
        } else if (r->eqn)
-               return(eqn_read(&r->eqn, ln, *bufp, ppos));
+               return(eqn_read(&r->eqn, ln, *bufp, ppos, offs));
 
        /*
         * If a scope is open, go to the child handler for that macro,
@@ -572,16 +601,14 @@ roff_endparse(struct roff *r)
 
        if (r->eqn) {
                mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse, 
-                               r->eqn->eqn.line, r->eqn->eqn.pos, NULL);
-               eqn_end(r->eqn);
-               r->eqn = NULL;
+                               r->eqn->eqn.ln, r->eqn->eqn.pos, NULL);
+               eqn_end(&r->eqn);
        }
 
        if (r->tbl) {
                mandoc_msg(MANDOCERR_SCOPEEXIT, r->parse, 
                                r->tbl->line, r->tbl->pos, NULL);
-               tbl_end(r->tbl);
-               r->tbl = NULL;
+               tbl_end(&r->tbl);
        }
 }
 
@@ -596,11 +623,18 @@ roff_parse(struct roff *r, const char *buf, int *pos)
        size_t           maclen;
        enum rofft       t;
 
-       if ('\0' == buf[*pos] || '"' == buf[*pos])
+       if ('\0' == buf[*pos] || '"' == buf[*pos] || 
+                       '\t' == buf[*pos] || ' ' == buf[*pos])
                return(ROFF_MAX);
 
+       /*
+        * We stop the macro parse at an escape, tab, space, or nil.
+        * However, `\}' is also a valid macro, so make sure we don't
+        * clobber it by seeing the `\' as the end of token.
+        */
+
        mac = buf + *pos;
-       maclen = strcspn(mac, " \\\t\0");
+       maclen = strcspn(mac + 1, " \\\t\0") + 1;
 
        t = (r->current_string = roff_getstrn(r, mac, maclen))
            ? ROFF_USERDEF : roff_hash_find(mac, maclen);
@@ -882,7 +916,22 @@ roff_cond_sub(ROFF_ARGS)
                        ep++;
                        if ('}' != *ep)
                                continue;
-                       *ep = '&';
+
+                       /*
+                        * Make the \} go away.
+                        * This is a little haphazard, as it's not quite
+                        * clear how nroff does this.
+                        * If we're at the end of line, then just chop
+                        * off the \} and resize the buffer.
+                        * If we aren't, then conver it to spaces.
+                        */
+
+                       if ('\0' == *(ep + 1)) {
+                               *--ep = '\0';
+                               *szp -= 2;
+                       } else
+                               *(ep - 1) = *ep = ' ';
+
                        roff_ccond(r, ROFF_ccond, bufp, szp, 
                                        ln, pos, pos + 2, offs);
                        break;
@@ -1082,6 +1131,26 @@ roff_ds(ROFF_ARGS)
        return(ROFF_IGN);
 }
 
+int
+roff_regisset(const struct roff *r, enum regs reg)
+{
+
+       return(r->regs[(int)reg].set);
+}
+
+unsigned int
+roff_regget(const struct roff *r, enum regs reg)
+{
+
+       return(r->regs[(int)reg].u);
+}
+
+void
+roff_regunset(struct roff *r, enum regs reg)
+{
+
+       r->regs[(int)reg].set = 0;
+}
 
 /* ARGSUSED */
 static enum rofferr
@@ -1090,18 +1159,16 @@ roff_nr(ROFF_ARGS)
        const char      *key;
        char            *val;
        int              iv;
-       struct reg      *rg;
 
        val = *bufp + pos;
        key = roff_getname(r, &val, ln, pos);
-       rg = r->regs->regs;
 
        if (0 == strcmp(key, "nS")) {
-               rg[(int)REG_nS].set = 1;
-               if ((iv = mandoc_strntou(val, strlen(val), 10)) >= 0)
-                       rg[REG_nS].v.u = (unsigned)iv;
+               r->regs[(int)REG_nS].set = 1;
+               if ((iv = mandoc_strntoi(val, strlen(val), 10)) >= 0)
+                       r->regs[(int)REG_nS].u = (unsigned)iv;
                else
-                       rg[(int)REG_nS].v.u = 0u;
+                       r->regs[(int)REG_nS].u = 0u;
        }
 
        return(ROFF_IGN);
@@ -1131,9 +1198,8 @@ roff_TE(ROFF_ARGS)
        if (NULL == r->tbl)
                mandoc_msg(MANDOCERR_NOSCOPE, r->parse, ln, ppos, NULL);
        else
-               tbl_end(r->tbl);
+               tbl_end(&r->tbl);
 
-       r->tbl = NULL;
        return(ROFF_IGN);
 }
 
@@ -1150,14 +1216,22 @@ roff_T_(ROFF_ARGS)
        return(ROFF_IGN);
 }
 
-/* ARGSUSED */
-static enum rofferr
-roff_EQ(ROFF_ARGS)
+int
+roff_closeeqn(struct roff *r)
 {
-       struct eqn_node *e;
+
+       return(r->eqn && ROFF_EQN == eqn_end(&r->eqn) ? 1 : 0);
+}
+
+void
+roff_openeqn(struct roff *r, const char *name, int line, 
+               int offs, const char *buf)
+{
+       struct eqn_node *e;
+       int              poff;
 
        assert(NULL == r->eqn);
-       e = eqn_alloc(ppos, ln);
+       e = eqn_alloc(name, offs, line, r->parse);
 
        if (r->last_eqn)
                r->last_eqn->next = e;
@@ -1165,6 +1239,19 @@ roff_EQ(ROFF_ARGS)
                r->first_eqn = r->last_eqn = e;
 
        r->eqn = r->last_eqn = e;
+
+       if (buf) {
+               poff = 0;
+               eqn_read(&r->eqn, line, buf, offs, &poff);
+       }
+}
+
+/* ARGSUSED */
+static enum rofferr
+roff_EQ(ROFF_ARGS)
+{
+
+       roff_openeqn(r, *bufp + pos, ln, ppos, NULL);
        return(ROFF_IGN);
 }
 
@@ -1185,7 +1272,7 @@ roff_TS(ROFF_ARGS)
 
        if (r->tbl) {
                mandoc_msg(MANDOCERR_SCOPEBROKEN, r->parse, ln, ppos, NULL);
-               tbl_end(r->tbl);
+               tbl_end(&r->tbl);
        }
 
        t = tbl_alloc(ppos, ln, r->parse);
@@ -1421,3 +1508,10 @@ roff_eqn(const struct roff *r)
        
        return(r->last_eqn ? &r->last_eqn->eqn : NULL);
 }
+
+char
+roff_eqndelim(const struct roff *r)
+{
+
+       return('\0');
+}