]> git.cameronkatri.com Git - mandoc.git/blobdiff - roff.c
Small fix to preserve trailing semicolons in examples.
[mandoc.git] / roff.c
diff --git a/roff.c b/roff.c
index 7c8512d9111a7ffde3a31c1bc23ef5b9d6b16337..24aa46e6e9a649fd3ba97d0e8edd9b74ce498f44 100644 (file)
--- a/roff.c
+++ b/roff.c
@@ -1,4 +1,4 @@
-/*     $Id: roff.c,v 1.82 2010/05/17 02:01:05 kristaps Exp $ */
+/*     $Id: roff.c,v 1.86 2010/06/01 11:47:28 kristaps Exp $ */
 /*
  * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -19,6 +19,7 @@
 #endif
 
 #include <assert.h>
+#include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
@@ -38,10 +39,13 @@ enum        rofft {
        ROFF_de,
        ROFF_dei,
        ROFF_de1,
+       ROFF_ds,
        ROFF_el,
        ROFF_ie,
        ROFF_if,
        ROFF_ig,
+       ROFF_rm,
+       ROFF_tr,
        ROFF_cblock,
        ROFF_ccond,
        ROFF_MAX
@@ -88,6 +92,7 @@ struct        roffmac {
        roffproc         sub; /* process as child of macro */
        int              flags;
 #define        ROFFMAC_STRUCT  (1 << 0) /* always interpret */
+       struct roffmac  *next;
 };
 
 static enum rofferr     roff_block(ROFF_ARGS);
@@ -98,30 +103,67 @@ static     enum rofferr     roff_ccond(ROFF_ARGS);
 static enum rofferr     roff_cond(ROFF_ARGS);
 static enum rofferr     roff_cond_text(ROFF_ARGS);
 static enum rofferr     roff_cond_sub(ROFF_ARGS);
-
-const  struct roffmac   roffs[ROFF_MAX] = {
-       { "am", roff_block, roff_block_text, roff_block_sub, 0 },
-       { "ami", roff_block, roff_block_text, roff_block_sub, 0 },
-       { "am1", roff_block, roff_block_text, roff_block_sub, 0 },
-       { "de", roff_block, roff_block_text, roff_block_sub, 0 },
-       { "dei", roff_block, roff_block_text, roff_block_sub, 0 },
-       { "de1", roff_block, roff_block_text, roff_block_sub, 0 },
-       { "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT },
-       { "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT },
-       { "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT },
-       { "ig", roff_block, roff_block_text, roff_block_sub, 0 },
-       { ".", roff_cblock, NULL, NULL, 0 },
-       { "\\}", roff_ccond, NULL, NULL, 0 },
+static enum rofferr     roff_line(ROFF_ARGS);
+
+/* See roff_hash_find() */
+
+#define        ASCII_HI         126
+#define        ASCII_LO         33
+#define        HASHWIDTH       (ASCII_HI - ASCII_LO + 1)
+
+static struct roffmac  *hash[HASHWIDTH];
+
+static struct roffmac   roffs[ROFF_MAX] = {
+       { "am", roff_block, roff_block_text, roff_block_sub, 0, NULL },
+       { "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },
+       { "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
+       { "de", roff_block, roff_block_text, roff_block_sub, 0, NULL },
+       { "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },
+       { "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
+       { "ds", roff_line, NULL, NULL, 0, NULL },
+       { "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
+       { "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
+       { "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
+       { "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL },
+       { "rm", roff_line, NULL, NULL, 0, NULL },
+       { "tr", roff_line, NULL, NULL, 0, NULL },
+       { ".", roff_cblock, NULL, NULL, 0, NULL },
+       { "\\}", roff_ccond, NULL, NULL, 0, NULL },
 };
 
 static void             roff_free1(struct roff *);
 static enum rofft       roff_hash_find(const char *);
+static void             roff_hash_init(void);
 static void             roffnode_cleanscope(struct roff *);
 static int              roffnode_push(struct roff *, 
                                enum rofft, int, int);
 static void             roffnode_pop(struct roff *);
 static enum rofft       roff_parse(const char *, int *);
 
+/* See roff_hash_find() */
+#define        ROFF_HASH(p)    (p[0] - ASCII_LO)
+
+static void
+roff_hash_init(void)
+{
+       struct roffmac   *n;
+       int               buc, i;
+
+       for (i = 0; i < (int)ROFF_MAX; i++) {
+               assert(roffs[i].name[0] >= ASCII_LO);
+               assert(roffs[i].name[0] <= ASCII_HI);
+
+               buc = ROFF_HASH(roffs[i].name);
+
+               if (NULL != (n = hash[buc])) {
+                       for ( ; n->next; n = n->next)
+                               /* Do nothing. */ ;
+                       n->next = &roffs[i];
+               } else
+                       hash[buc] = &roffs[i];
+       }
+}
+
 
 /*
  * Look up a roff token by its name.  Returns ROFF_MAX if no macro by
@@ -130,13 +172,26 @@ static    enum rofft       roff_parse(const char *, int *);
 static enum rofft
 roff_hash_find(const char *p)
 {
-       int              i;
+       int              buc;
+       struct roffmac  *n;
 
-       /* FIXME: make this be fast and efficient. */
+       /*
+        * libroff has an extremely simple hashtable, for the time
+        * being, which simply keys on the first character, which must
+        * be printable, then walks a chain.  It works well enough until
+        * optimised.
+        */
+
+       if (p[0] < ASCII_LO || p[0] > ASCII_HI)
+               return(ROFF_MAX);
 
-       for (i = 0; i < (int)ROFF_MAX; i++)
-               if (0 == strcmp(roffs[i].name, p))
-                       return((enum rofft)i);
+       buc = ROFF_HASH(p);
+
+       if (NULL == (n = hash[buc]))
+               return(ROFF_MAX);
+       for ( ; n; n = n->next)
+               if (0 == strcmp(n->name, p))
+                       return((enum rofft)(n - roffs));
 
        return(ROFF_MAX);
 }
@@ -229,6 +284,8 @@ roff_alloc(const mandocmsg msg, void *data)
        r->msg = msg;
        r->data = data;
        r->rstackpos = -1;
+       
+       roff_hash_init();
        return(r);
 }
 
@@ -568,7 +625,7 @@ roff_cond_sub(ROFF_ARGS)
        ppos = pos;
        rr = r->last->rule;
 
-       roffnode_cleanscope(r);
+       roff_cond_text(r, tok, bufp, szp, ln, ppos, pos, offs);
 
        if (ROFF_MAX == (t = roff_parse(*bufp, &pos)))
                return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
@@ -609,7 +666,7 @@ roff_cond_text(ROFF_ARGS)
                return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
        }
 
-       if (ep > st && '\\' != *(ep - 1))
+       if (ep == st || (ep > st && '\\' != *(ep - 1)))
                roffnode_pop(r);
 
        roffnode_cleanscope(r);
@@ -621,6 +678,7 @@ roff_cond_text(ROFF_ARGS)
 static enum rofferr
 roff_cond(ROFF_ARGS)
 {
+       int              cpos;  /* position of the condition */
        int              sv;
 
        /* Stack overflow! */
@@ -630,6 +688,8 @@ roff_cond(ROFF_ARGS)
                return(ROFF_ERR);
        }
 
+       cpos = pos;
+
        if (ROFF_if == tok || ROFF_ie == tok) {
                /*
                 * Read ahead past the conditional.  FIXME: this does
@@ -660,9 +720,12 @@ roff_cond(ROFF_ARGS)
        if ( ! roffnode_push(r, tok, ln, ppos))
                return(ROFF_ERR);
 
-       /* TODO: here we would evaluate the conditional. */
+       /* XXX: Implement more conditionals. */
 
-       if (ROFF_el == tok) {
+       if (ROFF_if == tok || ROFF_ie == tok)
+               r->last->rule = 'n' == (*bufp)[cpos] ?
+                   ROFFRULE_ALLOW : ROFFRULE_DENY;
+       else if (ROFF_el == tok) {
                /* 
                 * An `.el' will get the value of the current rstack
                 * entry set in prior `ie' calls or defaults to DENY.
@@ -671,7 +734,8 @@ roff_cond(ROFF_ARGS)
                        r->last->rule = ROFFRULE_DENY;
                else
                        r->last->rule = r->rstack[r->rstackpos];
-       } else if (ROFF_ie == tok) {
+       }
+       if (ROFF_ie == tok) {
                /*
                 * An if-else will put the NEGATION of the current
                 * evaluated conditional into the stack.
@@ -682,6 +746,8 @@ roff_cond(ROFF_ARGS)
                else
                        r->rstack[r->rstackpos] = ROFFRULE_DENY;
        }
+       if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule)
+               r->last->rule = ROFFRULE_DENY;
 
        r->last->endspan = 1;
 
@@ -703,3 +769,12 @@ roff_cond(ROFF_ARGS)
        *offs = pos;
        return(ROFF_RERUN);
 }
+
+
+/* ARGSUSED */
+static enum rofferr
+roff_line(ROFF_ARGS)
+{
+
+       return(ROFF_IGN);
+}