]> git.cameronkatri.com Git - mandoc.git/blobdiff - eqn.c
Modernize an example showing antiquated syntax,
[mandoc.git] / eqn.c
diff --git a/eqn.c b/eqn.c
index 0274e5f68aa049dff90587eb2a14fc2c18df40e9..8d99f3fb1517ea0be45e2c10a9e28e7ebdfa1c9c 100644 (file)
--- a/eqn.c
+++ b/eqn.c
@@ -1,6 +1,7 @@
-/*     $Id: eqn.c,v 1.52 2014/10/12 19:31:41 schwarze Exp $ */
+/*     $Id: eqn.c,v 1.62 2017/03/11 15:43:04 schwarze Exp $ */
 /*
  * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2014, 2015 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
 #include "libmandoc.h"
 #include "libroff.h"
 
-#define        EQN_MSG(t, x) \
-       mandoc_msg((t), (x)->parse, (x)->eqn.ln, (x)->eqn.pos, NULL)
 #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,
@@ -197,6 +194,7 @@ enum        eqn_symt {
        EQNSYM_equiv,
        EQNSYM_lessequal,
        EQNSYM_moreequal,
+       EQNSYM_minus,
        EQNSYM__MAX
 };
 
@@ -252,7 +250,7 @@ static      const struct eqnsym eqnsyms[EQNSYM__MAX] = {
        { "cdot", "pc" }, /* EQNSYM_cdot */
        { "nothing", "&" }, /* EQNSYM_nothing */
        { "approx", "~~" }, /* EQNSYM_approx */
-       { "prime", "aq" }, /* EQNSYM_prime */
+       { "prime", "fm" }, /* EQNSYM_prime */
        { "half", "12" }, /* EQNSYM_half */
        { "partial", "pd" }, /* EQNSYM_partial */
        { "inf", "if" }, /* EQNSYM_inf */
@@ -265,8 +263,24 @@ static     const struct eqnsym eqnsyms[EQNSYM__MAX] = {
        { "==", "==" }, /* EQNSYM_equiv */
        { "<=", "<=" }, /* EQNSYM_lessequal */
        { ">=", ">=" }, /* EQNSYM_moreequal */
+       { "-", "mi" }, /* EQNSYM_minus */
 };
 
+static struct eqn_box  *eqn_box_alloc(struct eqn_node *, struct eqn_box *);
+static void             eqn_box_free(struct eqn_box *);
+static struct eqn_box  *eqn_box_makebinary(struct eqn_node *,
+                               enum eqn_post, struct eqn_box *);
+static void             eqn_def(struct eqn_node *);
+static struct eqn_def  *eqn_def_find(struct eqn_node *, const char *, size_t);
+static void             eqn_delim(struct eqn_node *);
+static const char      *eqn_next(struct eqn_node *, char, size_t *, int);
+static const char      *eqn_nextrawtok(struct eqn_node *, size_t *);
+static const char      *eqn_nexttok(struct eqn_node *, size_t *);
+static enum rofferr     eqn_parse(struct eqn_node *, struct eqn_box *);
+static enum eqn_tok     eqn_tok_parse(struct eqn_node *, char **);
+static void             eqn_undef(struct eqn_node *);
+
+
 enum rofferr
 eqn_read(struct eqn_node **epp, int ln,
                const char *p, int pos, int *offs)
@@ -288,10 +302,10 @@ eqn_read(struct eqn_node **epp, int ln,
                while (' ' == *p || '\t' == *p)
                        p++;
                if ('\0' == *p)
-                       return(er);
+                       return er;
                mandoc_vmsg(MANDOCERR_ARG_SKIP, ep->parse,
                    ln, pos, "EN %s", p);
-               return(er);
+               return er;
        }
 
        /*
@@ -310,34 +324,22 @@ eqn_read(struct eqn_node **epp, int ln,
        ep->sz += sz;
        strlcat(ep->data, p + pos, ep->sz + 1);
        strlcat(ep->data, " ", ep->sz + 1);
-       return(ROFF_IGN);
+       return ROFF_IGN;
 }
 
 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;
        p->gsize = EQN_DEFSIZE;
 
-       return(p);
+       return p;
 }
 
 /*
@@ -351,9 +353,9 @@ eqn_def_find(struct eqn_node *ep, const char *key, size_t sz)
        for (i = 0; i < (int)ep->defsz; i++)
                if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key,
                    ep->defs[i].keysz, key, sz))
-                       return(&ep->defs[i]);
+                       return &ep->defs[i];
 
-       return(NULL);
+       return NULL;
 }
 
 /*
@@ -364,22 +366,27 @@ eqn_def_find(struct eqn_node *ep, const char *key, size_t sz)
 static const char *
 eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
 {
+       static size_t    last_len;
+       static int       lim;
+
        char            *start, *next;
-       int              q, diff, lim;
+       int              q, diff;
        size_t           ssz, dummy;
        struct eqn_def  *def;
 
        if (NULL == sz)
                sz = &dummy;
 
-       lim = 0;
+       if (ep->cur >= last_len)
+               lim = 0;
        ep->rew = ep->cur;
 again:
        /* Prevent self-definitions. */
 
        if (lim >= EQN_NEST_MAX) {
-               EQN_MSG(MANDOCERR_ROFFLOOP, ep);
-               return(NULL);
+               mandoc_msg(MANDOCERR_ROFFLOOP, ep->parse,
+                   ep->eqn.ln, ep->eqn.pos, NULL);
+               return NULL;
        }
 
        ep->cur = ep->rew;
@@ -387,7 +394,7 @@ again:
        q = 0;
 
        if ('\0' == *start)
-               return(NULL);
+               return NULL;
 
        if (quote == *start) {
                ep->cur++;
@@ -419,7 +426,8 @@ again:
                        ep->cur++;
        } else {
                if (q)
-                       EQN_MSG(MANDOCERR_ARG_QUOTE, ep);
+                       mandoc_msg(MANDOCERR_ARG_QUOTE, ep->parse,
+                           ep->eqn.ln, ep->eqn.pos, NULL);
                next = strchr(start, '\0');
                *sz = (size_t)(next - start);
                ep->cur += *sz;
@@ -428,7 +436,7 @@ again:
        /* Quotes aren't expanded for values. */
 
        if (q || ! repl)
-               return(start);
+               return start;
 
        if (NULL != (def = eqn_def_find(ep, start, *sz))) {
                diff = def->valsz - *sz;
@@ -444,10 +452,12 @@ again:
                memmove(start + *sz + diff, start + *sz,
                    (strlen(start) - *sz) + 1);
                memcpy(start, def->val, def->valsz);
+               last_len = start - ep->data + def->valsz;
+               lim++;
                goto again;
        }
 
-       return(start);
+       return start;
 }
 
 /*
@@ -458,7 +468,7 @@ static const char *
 eqn_nexttok(struct eqn_node *ep, size_t *sz)
 {
 
-       return(eqn_next(ep, '"', sz, 1));
+       return eqn_next(ep, '"', sz, 1);
 }
 
 /*
@@ -468,7 +478,7 @@ static const char *
 eqn_nextrawtok(struct eqn_node *ep, size_t *sz)
 {
 
-       return(eqn_next(ep, '"', sz, 0));
+       return eqn_next(ep, '"', sz, 0);
 }
 
 /*
@@ -486,12 +496,21 @@ 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);
+               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])
@@ -503,7 +522,7 @@ eqn_tok_parse(struct eqn_node *ep, char **p)
        if (i == EQN_TOK__MAX && NULL != p)
                *p = mandoc_strndup(start, sz);
 
-       return(i);
+       return i;
 }
 
 static void
@@ -544,7 +563,7 @@ eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent)
                parent->first = bp;
 
        parent->last = bp;
-       return(bp);
+       return bp;
 }
 
 /*
@@ -574,29 +593,57 @@ eqn_box_makebinary(struct eqn_node *ep,
        newb->first = newb->last = b;
        newb->first->next = NULL;
        b->parent = newb;
-       return(newb);
+       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.
  */
-static int
+static void
 eqn_undef(struct eqn_node *ep)
 {
        const char      *start;
        struct eqn_def  *def;
        size_t           sz;
 
-       if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
-               EQN_MSG(MANDOCERR_EQNEOF, ep);
-               return(0);
-       } else if (NULL != (def = eqn_def_find(ep, start, sz)))
-               def->keysz = 0;
-
-       return(1);
+       if ((start = eqn_nextrawtok(ep, &sz)) == NULL) {
+               mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+                   ep->eqn.ln, ep->eqn.pos, "undef");
+               return;
+       }
+       if ((def = eqn_def_find(ep, start, sz)) == NULL)
+               return;
+       free(def->key);
+       free(def->val);
+       def->key = def->val = NULL;
+       def->keysz = def->valsz = 0;
 }
 
-static int
+static void
 eqn_def(struct eqn_node *ep)
 {
        const char      *start;
@@ -604,9 +651,10 @@ eqn_def(struct eqn_node *ep)
        struct eqn_def  *def;
        int              i;
 
-       if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
-               EQN_MSG(MANDOCERR_EQNEOF, ep);
-               return(0);
+       if ((start = eqn_nextrawtok(ep, &sz)) == NULL) {
+               mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+                   ep->eqn.ln, ep->eqn.pos, "define");
+               return;
        }
 
        /*
@@ -626,45 +674,51 @@ eqn_def(struct eqn_node *ep)
                        ep->defs[i].key = ep->defs[i].val = NULL;
                }
 
-               ep->defs[i].keysz = sz;
-               ep->defs[i].key = mandoc_realloc(
-                   ep->defs[i].key, sz + 1);
-
-               memcpy(ep->defs[i].key, start, sz);
-               ep->defs[i].key[(int)sz] = '\0';
-               def = &ep->defs[i];
+               def = ep->defs + i;
+               free(def->key);
+               def->key = mandoc_strndup(start, sz);
+               def->keysz = sz;
        }
 
        start = eqn_next(ep, ep->data[(int)ep->cur], &sz, 0);
-
-       if (NULL == start) {
-               EQN_MSG(MANDOCERR_EQNEOF, ep);
-               return(-1);
+       if (start == NULL) {
+               mandoc_vmsg(MANDOCERR_REQ_EMPTY, ep->parse,
+                   ep->eqn.ln, ep->eqn.pos, "define %s", def->key);
+               free(def->key);
+               free(def->val);
+               def->key = def->val = NULL;
+               def->keysz = def->valsz = 0;
+               return;
        }
-
+       free(def->val);
+       def->val = mandoc_strndup(start, sz);
        def->valsz = sz;
-       def->val = mandoc_realloc(def->val, sz + 1);
-       memcpy(def->val, start, sz);
-       def->val[(int)sz] = '\0';
-       return(1);
 }
 
 /*
  * Recursively parse an eqn(7) expression.
  */
-static int
+static enum rofferr
 eqn_parse(struct eqn_node *ep, struct eqn_box *parent)
 {
+       char             sym[64];
+       struct eqn_box  *cur;
+       const char      *start;
        char            *p;
+       size_t           i, sz;
        enum eqn_tok     tok, subtok;
        enum eqn_post    pos;
-       struct eqn_box  *cur;
-       int              rc, size;
-       size_t           i, sz;
-       char             sym[64];
-       const char      *start;
+       int              size;
+
+       assert(parent != NULL);
 
-       assert(NULL != parent);
+       /*
+        * Empty equation.
+        * Do not add it to the high-level syntax tree.
+        */
+
+       if (ep->data == NULL)
+               return ROFF_IGN;
 
 next_tok:
        tok = eqn_tok_parse(ep, &p);
@@ -672,22 +726,21 @@ next_tok:
 this_tok:
        switch (tok) {
        case (EQN_TOK_UNDEF):
-               if ((rc = eqn_undef(ep)) <= 0)
-                       return(rc);
+               eqn_undef(ep);
                break;
        case (EQN_TOK_NDEFINE):
        case (EQN_TOK_DEFINE):
-               if ((rc = eqn_def(ep)) <= 0)
-                       return(rc);
+               eqn_def(ep);
                break;
        case (EQN_TOK_TDEFINE):
-               if (NULL == eqn_nextrawtok(ep, NULL))
-                       EQN_MSG(MANDOCERR_EQNEOF, ep);
-               else if (NULL == eqn_next(ep,
-                               ep->data[(int)ep->cur], NULL, 0))
-                       EQN_MSG(MANDOCERR_EQNEOF, ep);
+               if (eqn_nextrawtok(ep, NULL) == NULL ||
+                   eqn_next(ep, ep->data[(int)ep->cur], NULL, 0) == NULL)
+                       mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
+                           ep->eqn.ln, ep->eqn.pos, "tdefine");
                break;
        case (EQN_TOK_DELIM):
+               eqn_delim(ep);
+               break;
        case (EQN_TOK_GFONT):
                if (eqn_nextrawtok(ep, NULL) == NULL)
                        mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse,
@@ -939,7 +992,7 @@ this_tok:
                                parent->right = mandoc_strndup(start, sz);
                }
                parent = parent->parent;
-               if (EQN_TOK_BRACE_CLOSE == tok && parent &&
+               if (tok == EQN_TOK_BRACE_CLOSE &&
                    (parent->type == EQN_PILE ||
                     parent->type == EQN_MATRIX))
                        parent = parent->parent;
@@ -1013,7 +1066,7 @@ this_tok:
                 * End of file!
                 * TODO: make sure we're not in an open subexpression.
                 */
-               return(0);
+               return ROFF_EQN;
        default:
                assert(tok == EQN_TOK__MAX);
                assert(NULL != p);
@@ -1057,7 +1110,7 @@ eqn_end(struct eqn_node **epp)
 
        ep->eqn.root = mandoc_calloc(1, sizeof(struct eqn_box));
        ep->eqn.root->expectargs = UINT_MAX;
-       return(0 == eqn_parse(ep, ep->eqn.root) ? ROFF_EQN : ROFF_IGN);
+       return eqn_parse(ep, ep->eqn.root);
 }
 
 void
@@ -1072,7 +1125,6 @@ eqn_free(struct eqn_node *p)
                free(p->defs[i].val);
        }
 
-       free(p->eqn.name);
        free(p->data);
        free(p->defs);
        free(p);