]> git.cameronkatri.com Git - mandoc.git/blobdiff - eqn.c
Grrr, patch(1) merged the new function to the wrong place in this file.
[mandoc.git] / eqn.c
diff --git a/eqn.c b/eqn.c
index c2e7aed2fb7990a8a35ccd42d993f729ee17f13c..a64031b29b9c8e158eee91e685b711053cd2e170 100644 (file)
--- a/eqn.c
+++ b/eqn.c
@@ -1,6 +1,7 @@
-/*     $Id: eqn.c,v 1.48 2014/10/10 08:44:24 kristaps Exp $ */
+/*     $Id: eqn.c,v 1.56 2014/10/25 15:06:30 schwarze Exp $ */
 /*
- * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014 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
@@ -35,8 +36,6 @@
 #define        EQN_NEST_MAX     128 /* maximum nesting of defines */
 #define        STRNEQ(p1, sz1, p2, sz2) \
        ((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1)))
-#define        EQNSTREQ(x, p, sz) \
-       STRNEQ((x)->name, (x)->sz, (p), (sz))
 
 enum   eqn_tok {
        EQN_TOK_DYAD = 0,
@@ -314,24 +313,12 @@ eqn_read(struct eqn_node **epp, int ln,
 }
 
 struct eqn_node *
-eqn_alloc(const char *name, int pos, int line, struct mparse *parse)
+eqn_alloc(int pos, int line, struct mparse *parse)
 {
        struct eqn_node *p;
-       size_t           sz;
-       const char      *end;
 
        p = mandoc_calloc(1, sizeof(struct eqn_node));
 
-       if (name && '\0' != *name) {
-               sz = strlen(name);
-               assert(sz);
-               do {
-                       sz--;
-                       end = name + (int)sz;
-               } while (' ' == *end || '\t' == *end);
-               p->eqn.name = mandoc_strndup(name, sz + 1);
-       }
-
        p->parse = parse;
        p->eqn.ln = line;
        p->eqn.pos = pos;
@@ -486,13 +473,22 @@ eqn_tok_parse(struct eqn_node *ep, char **p)
 {
        const char      *start;
        size_t           i, sz;
+       int              quoted;
 
        if (NULL != p)
                *p = NULL;
 
+       quoted = ep->data[ep->cur] == '"';
+
        if (NULL == (start = eqn_nexttok(ep, &sz)))
                return(EQN_TOK_EOF);
 
+       if (quoted) {
+               if (p != NULL)
+                       *p = mandoc_strndup(start, sz);
+               return(EQN_TOK__MAX);
+       }
+
        for (i = 0; i < EQN_TOK__MAX; i++) {
                if (NULL == eqn_toks[i])
                        continue;
@@ -537,10 +533,7 @@ eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent)
        bp->expectargs = UINT_MAX;
        bp->size = ep->gsize;
 
-       assert(NULL != parent);
-
        if (NULL != parent->first) {
-               assert(NULL != parent->last);
                parent->last->next = bp;
                bp->prev = parent->last;
        } else
@@ -557,7 +550,7 @@ eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent)
  * The new EQN_SUBEXPR will have a two-child limit.
  */
 static struct eqn_box *
-eqn_box_makebinary(struct eqn_node *ep, 
+eqn_box_makebinary(struct eqn_node *ep,
        enum eqn_post pos, struct eqn_box *parent)
 {
        struct eqn_box  *b, *newb;
@@ -580,6 +573,30 @@ eqn_box_makebinary(struct eqn_node *ep,
        return(newb);
 }
 
+/*
+ * Parse the "delim" control statement.
+ */
+static void
+eqn_delim(struct eqn_node *ep)
+{
+       const char      *start;
+       size_t           sz;
+
+       if ((start = eqn_nextrawtok(ep, &sz)) == NULL)
+               mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+                   ep->eqn.ln, ep->eqn.pos, "delim");
+       else if (strncmp(start, "off", 3) == 0)
+               ep->delim = 0;
+       else if (strncmp(start, "on", 2) == 0) {
+               if (ep->odelim && ep->cdelim)
+                       ep->delim = 1;
+       } else if (start[1] != '\0') {
+               ep->odelim = start[0];
+               ep->cdelim = start[1];
+               ep->delim = 1;
+       }
+}
+
 /*
  * Undefine a previously-defined string.
  */
@@ -659,7 +676,7 @@ static int
 eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
 {
        char            *p;
-       enum eqn_tok     tok;
+       enum eqn_tok     tok, subtok;
        enum eqn_post    pos;
        struct eqn_box  *cur;
        int              rc, size;
@@ -667,10 +684,15 @@ eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
        char             sym[64];
        const char      *start;
 
-       assert(NULL != parent);
-again:
-       
-       switch ((tok = eqn_tok_parse(ep, &p))) {
+       assert(parent != NULL);
+       if (ep->data == NULL)
+               return(-1);
+
+next_tok:
+       tok = eqn_tok_parse(ep, &p);
+
+this_tok:
+       switch (tok) {
        case (EQN_TOK_UNDEF):
                if ((rc = eqn_undef(ep)) <= 0)
                        return(rc);
@@ -683,15 +705,17 @@ again:
        case (EQN_TOK_TDEFINE):
                if (NULL == eqn_nextrawtok(ep, NULL))
                        EQN_MSG(MANDOCERR_EQNEOF, ep);
-               else if (NULL == eqn_next(ep, 
+               else if (NULL == eqn_next(ep,
                                ep->data[(int)ep->cur], NULL, 0))
                        EQN_MSG(MANDOCERR_EQNEOF, ep);
                break;
+       case (EQN_TOK_DELIM):
+               eqn_delim(ep);
+               break;
        case (EQN_TOK_GFONT):
-               if (NULL == eqn_nextrawtok(ep, NULL)) {
-                       EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                       return(-1);
-               }
+               if (eqn_nextrawtok(ep, NULL) == NULL)
+                       mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+                           ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
                break;
        case (EQN_TOK_MARK):
        case (EQN_TOK_LINEUP):
@@ -705,12 +729,14 @@ again:
        case (EQN_TOK_HAT):
        case (EQN_TOK_DOT):
        case (EQN_TOK_DOTDOT):
-               if (NULL == parent->last) {
-                       EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                       return(-1);
+               if (parent->last == NULL) {
+                       mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
+                           ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+                       cur = eqn_box_alloc(ep, parent);
+                       cur->type = EQN_TEXT;
+                       cur->text = mandoc_strdup("");
                }
-               parent = eqn_box_makebinary
-                       (ep, EQNPOS_NONE, parent);
+               parent = eqn_box_makebinary(ep, EQNPOS_NONE, parent);
                parent->type = EQN_LISTONE;
                parent->expectargs = 1;
                switch (tok) {
@@ -764,10 +790,12 @@ again:
        case (EQN_TOK_BACK):
        case (EQN_TOK_DOWN):
        case (EQN_TOK_UP):
-               tok = eqn_tok_parse(ep, NULL); 
-               if (EQN_TOK__MAX != tok) {
-                       EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                       return(-1);
+               subtok = eqn_tok_parse(ep, NULL);
+               if (subtok != EQN_TOK__MAX) {
+                       mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+                           ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+                       tok = subtok;
+                       goto this_tok;
                }
                break;
        case (EQN_TOK_FAT):
@@ -775,10 +803,7 @@ again:
        case (EQN_TOK_ITALIC):
        case (EQN_TOK_BOLD):
                while (parent->args == parent->expectargs)
-                       if (NULL == (parent = parent->parent)) {
-                               EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                               return(-1);
-                       }
+                       parent = parent->parent;
                /*
                 * These values apply to the next word or sequence of
                 * words; thus, we mark that we'll have a child with
@@ -808,13 +833,15 @@ again:
        case (EQN_TOK_GSIZE):
                /* Accept two values: integral size and a single. */
                if (NULL == (start = eqn_nexttok(ep, &sz))) {
-                       EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                       return(-1);
+                       mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+                           ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+                       break;
                }
                size = mandoc_strntoi(start, sz, 10);
                if (-1 == size) {
-                       EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                       return(-1);
+                       mandoc_msg(MANDOCERR_IT_NONUM, ep->parse,
+                           ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+                       break;
                }
                if (EQN_TOK_GSIZE == tok) {
                        ep->gsize = size;
@@ -834,9 +861,12 @@ again:
                 * Repivot under a positional node, open a child scope
                 * and keep on reading.
                 */
-               if (NULL == parent->last) {
-                       EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                       return(-1);
+               if (parent->last == NULL) {
+                       mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
+                           ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+                       cur = eqn_box_alloc(ep, parent);
+                       cur->type = EQN_TEXT;
+                       cur->text = mandoc_strdup("");
                }
                /* Handle the "subsup" and "fromto" positions. */
                if (EQN_TOK_SUP == tok && parent->pos == EQNPOS_SUB) {
@@ -869,11 +899,8 @@ again:
                break;
        case (EQN_TOK_SQRT):
                while (parent->args == parent->expectargs)
-                       if (NULL == (parent = parent->parent)) {
-                               EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                               return(-1);
-                       }
-               /* 
+                       parent = parent->parent;
+               /*
                 * Accept a left-right-associative set of arguments just
                 * like sub and sup and friends but without rebalancing
                 * under a pivot.
@@ -889,15 +916,15 @@ again:
                 * Close out anything that's currently open, then
                 * rebalance and continue reading.
                 */
-               if (NULL == parent->last) {
-                       EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                       return(-1);
+               if (parent->last == NULL) {
+                       mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse,
+                           ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+                       cur = eqn_box_alloc(ep, parent);
+                       cur->type = EQN_TEXT;
+                       cur->text = mandoc_strdup("");
                }
                while (EQN_SUBEXPR == parent->type)
-                       if (NULL == (parent = parent->parent)) {
-                               EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                               return(-1);
-                       }
+                       parent = parent->parent;
                parent = eqn_box_makebinary(ep, EQNPOS_OVER, parent);
                break;
        case (EQN_TOK_RIGHT):
@@ -907,19 +934,23 @@ again:
                 * FIXME: this is a shitty sentinel: we should really
                 * have a native EQN_BRACE type or whatnot.
                 */
-               while (parent->type != EQN_LIST) 
-                       if (NULL == (parent = parent->parent)) {
-                               EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                               return(-1);
-                       }
+               for (cur = parent; cur != NULL; cur = cur->parent)
+                       if (cur->type == EQN_LIST &&
+                           (tok == EQN_TOK_BRACE_CLOSE ||
+                            cur->left != NULL))
+                               break;
+               if (cur == NULL) {
+                       mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->parse,
+                           ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+                       break;
+               }
+               parent = cur;
                if (EQN_TOK_RIGHT == tok) {
-                       if (NULL == parent->left) {
-                               EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                               return(-1);
-                       }
                        if (NULL == (start = eqn_nexttok(ep, &sz))) {
-                               EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                               return(-1);
+                               mandoc_msg(MANDOCERR_REQ_EMPTY,
+                                   ep->parse, ep->eqn.ln,
+                                   ep->eqn.pos, eqn_toks[tok]);
+                               break;
                        }
                        /* Handling depends on right/left. */
                        if (STRNEQ(start, sz, "ceiling", 7)) {
@@ -928,24 +959,18 @@ again:
                        } else if (STRNEQ(start, sz, "floor", 5)) {
                                strlcpy(sym, "\\[rf]", sizeof(sym));
                                parent->right = mandoc_strdup(sym);
-                       } else 
+                       } else
                                parent->right = mandoc_strndup(start, sz);
                }
-               if (NULL == (parent = parent->parent)) {
-                       EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                       return(-1);
-               }
-               if (EQN_TOK_BRACE_CLOSE == tok && parent && 
-                       (parent->type == EQN_PILE ||
-                        parent->type == EQN_MATRIX))
+               parent = parent->parent;
+               if (EQN_TOK_BRACE_CLOSE == tok && parent &&
+                   (parent->type == EQN_PILE ||
+                    parent->type == EQN_MATRIX))
                        parent = parent->parent;
                /* Close out any "singleton" lists. */
-               while (parent->type == EQN_LISTONE && 
-                       parent->args == parent->expectargs)
-                       if (NULL == (parent = parent->parent)) {
-                               EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                               return(-1);
-                       }
+               while (parent->type == EQN_LISTONE &&
+                   parent->args == parent->expectargs)
+                       parent = parent->parent;
                break;
        case (EQN_TOK_BRACE_OPEN):
        case (EQN_TOK_LEFT):
@@ -955,25 +980,23 @@ again:
                 * (just like with the text node).
                 */
                while (parent->args == parent->expectargs)
-                       if (NULL == (parent = parent->parent)) {
-                               EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                               return(-1);
-                       }
+                       parent = parent->parent;
+               if (EQN_TOK_LEFT == tok &&
+                   (start = eqn_nexttok(ep, &sz)) == NULL) {
+                       mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+                           ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+                       break;
+               }
                parent = eqn_box_alloc(ep, parent);
                parent->type = EQN_LIST;
                if (EQN_TOK_LEFT == tok) {
-                       if (NULL == (start = eqn_nexttok(ep, &sz))) {
-                               EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                               return(-1);
-                       }
-                       /* Handling depends on right/left. */
                        if (STRNEQ(start, sz, "ceiling", 7)) {
                                strlcpy(sym, "\\[lc]", sizeof(sym));
                                parent->left = mandoc_strdup(sym);
                        } else if (STRNEQ(start, sz, "floor", 5)) {
                                strlcpy(sym, "\\[lf]", sizeof(sym));
                                parent->left = mandoc_strdup(sym);
-                       } else 
+                       } else
                                parent->left = mandoc_strndup(start, sz);
                }
                break;
@@ -985,46 +1008,33 @@ again:
        case (EQN_TOK_LCOL):
        case (EQN_TOK_RCOL):
                while (parent->args == parent->expectargs)
-                       if (NULL == (parent = parent->parent)) {
-                               EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                               return(-1);
-                       }
-               if (EQN_TOK_BRACE_OPEN != eqn_tok_parse(ep, NULL)) {
-                       EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                       return(-1);
-               }
+                       parent = parent->parent;
                parent = eqn_box_alloc(ep, parent);
                parent->type = EQN_PILE;
-               parent = eqn_box_alloc(ep, parent);
-               parent->type = EQN_LIST;
+               parent->expectargs = 1;
                break;
        case (EQN_TOK_ABOVE):
-               while (parent->type != EQN_PILE) 
-                       if (NULL == (parent = parent->parent)) {
-                               EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                               return(-1);
-                       }
-               parent = eqn_box_alloc(ep, parent);
+               for (cur = parent; cur != NULL; cur = cur->parent)
+                       if (cur->type == EQN_PILE)
+                               break;
+               if (cur == NULL) {
+                       mandoc_msg(MANDOCERR_IT_STRAY, ep->parse,
+                           ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]);
+                       break;
+               }
+               parent = eqn_box_alloc(ep, cur);
                parent->type = EQN_LIST;
                break;
        case (EQN_TOK_MATRIX):
                while (parent->args == parent->expectargs)
-                       if (NULL == (parent = parent->parent)) {
-                               EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                               return(-1);
-                       }
-               if (EQN_TOK_BRACE_OPEN != eqn_tok_parse(ep, NULL)) {
-                       EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                       return(-1);
-               }
+                       parent = parent->parent;
                parent = eqn_box_alloc(ep, parent);
                parent->type = EQN_MATRIX;
-               parent = eqn_box_alloc(ep, parent);
-               parent->type = EQN_LIST;
+               parent->expectargs = 1;
                break;
        case (EQN_TOK_EOF):
                /*
-                * End of file! 
+                * End of file!
                 * TODO: make sure we're not in an open subexpression.
                 */
                return(0);
@@ -1036,16 +1046,12 @@ again:
                 * in an expression, then rewind til we're not any more.
                 */
                while (parent->args == parent->expectargs)
-                       if (NULL == (parent = parent->parent)) {
-                               EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                               free(p);
-                               return(-1);
-                       }
+                       parent = parent->parent;
                cur = eqn_box_alloc(ep, parent);
                cur->type = EQN_TEXT;
                for (i = 0; i < EQNSYM__MAX; i++)
                        if (0 == strcmp(eqnsyms[i].str, p)) {
-                               (void)snprintf(sym, sizeof(sym), 
+                               (void)snprintf(sym, sizeof(sym),
                                        "\\[%s]", eqnsyms[i].sym);
                                cur->text = mandoc_strdup(sym);
                                free(p);
@@ -1057,19 +1063,16 @@ again:
                /*
                 * Post-process list status.
                 */
-               while (parent->type == EQN_LISTONE && 
-                       parent->args == parent->expectargs)
-                       if (NULL == (parent = parent->parent)) {
-                               EQN_MSG(MANDOCERR_EQNSYNT, ep);
-                               return(-1);
-                       }
+               while (parent->type == EQN_LISTONE &&
+                   parent->args == parent->expectargs)
+                       parent = parent->parent;
                break;
        }
-       goto again;
+       goto next_tok;
 }
 
 enum rofferr
-eqn_end(struct eqn_node **epp) 
+eqn_end(struct eqn_node **epp)
 {
        struct eqn_node *ep;
 
@@ -1093,7 +1096,6 @@ eqn_free(struct eqn_node *p)
                free(p->defs[i].val);
        }
 
-       free(p->eqn.name);
        free(p->data);
        free(p->defs);
        free(p);