]> git.cameronkatri.com Git - mandoc.git/blobdiff - roff.c
The `am', `ami', `de', and holy `dei' are all being properly ignored.
[mandoc.git] / roff.c
diff --git a/roff.c b/roff.c
index 5a78640e54480362a68dee63af391b1ea318853e..89c3fdd406805c8b6a20fb200a052e0b1199e8c3 100644 (file)
--- a/roff.c
+++ b/roff.c
@@ -1,4 +1,4 @@
-/*     $Id: roff.c,v 1.68 2010/05/15 18:43:59 kristaps Exp $ */
+/*     $Id: roff.c,v 1.72 2010/05/15 22:22:51 kristaps Exp $ */
 /*
  * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -44,11 +44,13 @@ struct      roff {
 struct roffnode {
        enum rofft       tok; /* type of node */
        struct roffnode *parent; /* up one in stack */
+       char            *end; /* custom end-token */
        int              line; /* parse line */
        int              col; /* parse col */
 };
 
 #define        ROFF_ARGS        struct roff *r, /* parse ctx */ \
+                        enum rofft tok, /* tok of macro */ \
                         char **bufp, /* input buffer */ \
                         size_t *szp, /* size of input buffer */ \
                         int ln, /* parse line */ \
@@ -62,21 +64,19 @@ struct      roffmac {
        roffproc         new; /* root of stack (type = ROFF_MAX) */
 };
 
-static enum rofferr     roff_ignore(ROFF_ARGS);
 static enum rofferr     roff_new_close(ROFF_ARGS);
 static enum rofferr     roff_new_ig(ROFF_ARGS);
 static enum rofferr     roff_sub_ig(ROFF_ARGS);
 
 const  struct roffmac   roffs[ROFF_MAX] = {
-       { "de", NULL, roff_ignore },
-       { "dei", NULL, roff_ignore },
-       { "am", NULL, roff_ignore },
-       { "ami", NULL, roff_ignore },
+       { "de", roff_sub_ig, roff_new_ig },
+       { "dei", roff_sub_ig, roff_new_ig },
+       { "am", roff_sub_ig, roff_new_ig },
+       { "ami", roff_sub_ig, roff_new_ig },
        { "ig", roff_sub_ig, roff_new_ig },
        { ".", NULL, roff_new_close },
 };
 
-static void             roff_alloc1(struct roff *);
 static void             roff_free1(struct roff *);
 static enum rofft       roff_hash_find(const char *);
 static int              roffnode_push(struct roff *, 
@@ -153,20 +153,11 @@ roff_free1(struct roff *r)
 }
 
 
-static void
-roff_alloc1(struct roff *r)
-{
-
-       /* Do nothing for now. */
-}
-
-
 void
 roff_reset(struct roff *r)
 {
 
        roff_free1(r);
-       roff_alloc1(r);
 }
 
 
@@ -208,7 +199,7 @@ roff_parseln(struct roff *r, int ln, char **bufp, size_t *szp)
                 */
                t = r->last->tok;
                assert(roffs[t].sub);
-               return((*roffs[t].sub)(r, bufp, szp, ln, 0));
+               return((*roffs[t].sub)(r, t, bufp, szp, ln, 0));
        } else if ('.' != (*bufp)[0] && NULL == r->last)
                /* Return when in free text without a context. */
                return(ROFF_CONT);
@@ -219,7 +210,7 @@ roff_parseln(struct roff *r, int ln, char **bufp, size_t *szp)
                return(ROFF_CONT);
 
        assert(roffs[t].new);
-       return((*roffs[t].new)(r, bufp, szp, ln, ppos));
+       return((*roffs[t].new)(r, t, bufp, szp, ln, ppos));
 }
 
 
@@ -264,34 +255,45 @@ roff_parse(const char *buf, int *pos)
 }
 
 
-/* ARGSUSED */
-static enum rofferr
-roff_ignore(ROFF_ARGS)
-{
-
-       return(ROFF_IGN);
-}
-
-
 /* ARGSUSED */
 static enum rofferr
 roff_sub_ig(ROFF_ARGS)
 {
-       enum rofft       t;
-       int              pos;
+       int              i, j;
 
        /* Ignore free-text lines. */
 
        if ('.' != (*bufp)[ppos])
                return(ROFF_IGN);
 
-       /* Ignore macros unless it's a closing macro. */
+       if (r->last->end) {
+               i = ppos + 1;
+
+               while ((*bufp)[i] && ' ' == (*bufp)[i])
+                       i++;
 
-       t = roff_parse(*bufp, &pos);
-       if (ROFF_close != t)
+               for (j = 0; r->last->end[j]; i++, j++)
+                       if ((*bufp)[i] != r->last->end[j])
+                               return(ROFF_IGN);
+
+               if (r->last->end[j])
+                       return(ROFF_IGN);
+               if ((*bufp)[i] && ' ' != (*bufp)[i])
+                       return(ROFF_IGN);
+
+               while (' ' == (*bufp)[i])
+                       i++;
+
+       } else if (ROFF_close != roff_parse(*bufp, &i))
                return(ROFF_IGN);
 
        roffnode_pop(r);
+
+       if ('\0' == (*bufp)[i])
+               return(ROFF_IGN);
+       if ( ! (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, i, NULL))
+               return(ROFF_ERR);
+
        return(ROFF_IGN);
 }
 
@@ -301,11 +303,10 @@ static enum rofferr
 roff_new_close(ROFF_ARGS)
 {
 
-       /*
        if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL))
                return(ROFF_ERR);
-       */
-       return(ROFF_CONT);
+
+       return(ROFF_IGN);
 }
 
 
@@ -313,9 +314,51 @@ roff_new_close(ROFF_ARGS)
 static enum rofferr
 roff_new_ig(ROFF_ARGS)
 {
+       int              i;
+
+       if ( ! roffnode_push(r, tok, ln, ppos))
+               return(ROFF_ERR);
+
+       if (ROFF_ig != tok) {
+               while ((*bufp)[ppos] && ' ' != (*bufp)[ppos])
+                       ppos++;
+               while (' ' == (*bufp)[ppos])
+                       ppos++;
+       }
+
+       i = (int)ppos;
 
-       return(roffnode_push(r, ROFF_ig, ln, ppos) ? 
-                       ROFF_IGN : ROFF_ERR);
+       while ((*bufp)[i] && ' ' != (*bufp)[i])
+               i++;
+
+       if (i == (int)ppos)
+               return(ROFF_IGN);
+
+       if ((*bufp)[i])
+               if ( ! (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, i, NULL))
+                       return(ROFF_ERR);
+
+       /*
+        * If the macro has arguments, the first argument (up to the
+        * next whitespace) is interpreted as an argument marking the
+        * macro close.  Thus, `.ig foo' will close at `.foo'.
+        *
+        * NOTE: the closing macro `.foo' in the above case is not
+        * allowed to have leading spaces with old groff!  Thus `.foo'
+        * != `. foo'.  Oh yeah, everything after the `.foo' is lost.
+        * Merry fucking Christmas.
+        */
+
+       r->last->end = malloc((size_t)i - ppos + 1);
+       if (NULL == r->last->end) {
+               (*r->msg)(MANDOCERR_MEM, r->data, ln, ppos, NULL);
+               return(ROFF_ERR);
+       }
+
+       memcpy(r->last->end, &(*bufp)[ppos], (size_t)i - ppos);
+       r->last->end[(size_t)i - ppos] = '\0';
+
+       return(ROFF_IGN);
 }