]> git.cameronkatri.com Git - mandoc.git/blobdiff - mdoc_macro.c
Missing prototype for getsubopt() on NetBSD fixed.
[mandoc.git] / mdoc_macro.c
index 6754c9a08ec4b6039e0f2e9008b6a01202f2e13d..d4c8dd140bf0fa3b1a0294a96bc6effe188b58cc 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: mdoc_macro.c,v 1.68 2010/05/17 22:11:42 kristaps Exp $ */
+/*     $Id: mdoc_macro.c,v 1.79 2010/05/31 23:49:16 kristaps Exp $ */
 /*
  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
  *
@@ -44,13 +44,13 @@ static      int             in_line_eoln(MACRO_PROT_ARGS);
 static int             in_line_argn(MACRO_PROT_ARGS);
 static int             in_line(MACRO_PROT_ARGS);
 static int             obsolete(MACRO_PROT_ARGS);
+static int             phrase_ta(MACRO_PROT_ARGS);
 
 static int             append_delims(struct mdoc *, 
                                int, int *, char *);
 static enum mdoct      lookup(enum mdoct, const char *);
 static enum mdoct      lookup_raw(const char *);
-static int             phrase(struct mdoc *, int, int, 
-                               char *, enum margserr);
+static int             phrase(struct mdoc *, int, int, char *);
 static enum mdoct      rew_alt(enum mdoct);
 static int             rew_dobreak(enum mdoct, 
                                const struct mdoc_node *);
@@ -171,7 +171,7 @@ const       struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
        { in_line_eoln, 0 }, /* Hf */
        { obsolete, 0 }, /* Fr */
        { in_line_eoln, 0 }, /* Ud */
-       { in_line_eoln, 0 }, /* Lb */
+       { in_line, 0 }, /* Lb */
        { in_line_eoln, 0 }, /* Lp */ 
        { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Lk */ 
        { in_line, MDOC_CALLABLE | MDOC_PARSED }, /* Mt */ 
@@ -186,6 +186,7 @@ const       struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
        { in_line_eoln, 0 }, /* br */
        { in_line_eoln, 0 }, /* sp */
        { in_line_eoln, 0 }, /* %U */
+       { phrase_ta, MDOC_CALLABLE | MDOC_PARSED }, /* Ta */
 };
 
 const  struct mdoc_macro * const mdoc_macros = __mdoc_macros;
@@ -196,7 +197,7 @@ swarn(struct mdoc *mdoc, enum mdoc_type type,
                int line, int pos, const struct mdoc_node *p)
 {
        const char      *n, *t, *tt;
-       int              rc;
+       enum mandocerr   ec;
 
        n = t = "<root>";
        tt = "block";
@@ -229,11 +230,12 @@ swarn(struct mdoc *mdoc, enum mdoc_type type,
                break;
        }
 
-       rc = mdoc_vmsg(mdoc, MANDOCERR_SCOPE, line, pos,
-                       "%s scope breaks %s of %s", tt, t, n);
+       ec = (MDOC_IGN_SCOPE & mdoc->pflags) ?
+               MANDOCERR_SCOPE : MANDOCERR_SYNTSCOPE;
 
-       /* FIXME: logic should be in driver. */
-       return(MDOC_IGN_SCOPE & mdoc->pflags ? rc : 0);
+       return(mdoc_vmsg(mdoc, ec, line, pos, 
+                               "%s scope breaks %s of %s", 
+                               tt, t, n));
 }
 
 
@@ -754,7 +756,7 @@ blk_exp_close(MACRO_PROT_ARGS)
 static int
 in_line(MACRO_PROT_ARGS)
 {
-       int              la, lastpunct, cnt, nc, nl;
+       int              la, scope, cnt, nc, nl;
        enum margverr    av;
        enum mdoct       ntok;
        enum margserr    ac;
@@ -805,7 +807,7 @@ in_line(MACRO_PROT_ARGS)
                return(0);
        }
 
-       for (cnt = 0, lastpunct = 1;; ) {
+       for (cnt = scope = 0;; ) {
                la = *pos;
                ac = mdoc_args(m, line, pos, buf, tok, &p);
 
@@ -826,7 +828,7 @@ in_line(MACRO_PROT_ARGS)
                 */
 
                if (MDOC_MAX != ntok) {
-                       if (0 == lastpunct && ! rew_elem(m, tok))
+                       if (scope && ! rew_elem(m, tok))
                                return(0);
                        if (nc && 0 == cnt) {
                                if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
@@ -853,14 +855,35 @@ in_line(MACRO_PROT_ARGS)
 
                d = ARGS_QWORD == ac ? DELIM_NONE : mdoc_isdelim(p);
 
-               if (ARGS_QWORD != ac && DELIM_NONE != d) {
-                       if (0 == lastpunct && ! rew_elem(m, tok))
+               if (DELIM_NONE != d) {
+                       /*
+                        * If we encounter closing punctuation, no word
+                        * has been omitted, no scope is open, and we're
+                        * allowed to have an empty element, then start
+                        * a new scope.  `Ar', `Fl', and `Li', only do
+                        * this once per invocation.  There may be more
+                        * of these (all of them?).
+                        */
+                       if (0 == cnt && (nc || MDOC_Li == tok) && 
+                                       DELIM_CLOSE == d && ! scope) {
+                               if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
+                                       return(0);
+                               if (MDOC_Ar == tok || MDOC_Li == tok || 
+                                               MDOC_Fl == tok)
+                                       cnt++;
+                               scope = 1;
+                       }
+                       /*
+                        * Close out our scope, if one is open, before
+                        * any punctuation.
+                        */
+                       if (scope && ! rew_elem(m, tok))
                                return(0);
-                       lastpunct = 1;
-               } else if (lastpunct) {
+                       scope = 0;
+               } else if ( ! scope) {
                        if ( ! mdoc_elem_alloc(m, line, ppos, tok, arg))
                                return(0);
-                       lastpunct = 0;
+                       scope = 1;
                }
 
                if (DELIM_NONE == d)
@@ -873,14 +896,14 @@ in_line(MACRO_PROT_ARGS)
                 * word so that the `-' can be added to each one without
                 * having to parse out spaces.
                 */
-               if (0 == lastpunct && MDOC_Fl == tok) {
+               if (scope && MDOC_Fl == tok) {
                        if ( ! rew_elem(m, tok))
                                return(0);
-                       lastpunct = 1;
+                       scope = 0;
                }
        }
 
-       if (0 == lastpunct && ! rew_elem(m, tok))
+       if (scope && ! rew_elem(m, tok))
                return(0);
 
        /*
@@ -916,6 +939,7 @@ blk_full(MACRO_PROT_ARGS)
 #ifdef UGLY
        struct mdoc_node *n;
 #endif
+       enum mdoc_type    mtt;
        enum mdoct        ntok;
        enum margserr     ac, lac;
        enum margverr     av;
@@ -984,24 +1008,38 @@ blk_full(MACRO_PROT_ARGS)
 
        for ( ; ; ) {
                la = *pos;
-               lac = ac;
+               /* Initialise last-phrase-type with ARGS_PEND. */
+               lac = ARGS_ERROR == ac ? ARGS_PEND : ac;
                ac = mdoc_args(m, line, pos, buf, tok, &p);
 
                if (ARGS_ERROR == ac)
                        return(0);
-               if (ARGS_EOLN == ac)
-                       break;
 
-               if (ARGS_PEND == ac) {
-                       if (ARGS_PPHRASE == lac)
-                               ac = ARGS_PPHRASE;
-                       else
-                               ac = ARGS_PHRASE;
+               if (ARGS_EOLN == ac) {
+                       if (ARGS_PPHRASE != lac && ARGS_PHRASE != lac)
+                               break;
+                       /*
+                        * This is necessary: if the last token on a
+                        * line is a `Ta' or tab, then we'll get
+                        * ARGS_EOLN, so we must be smart enough to
+                        * reopen our scope if the last parse was a
+                        * phrase or partial phrase.
+                        */
+                       if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
+                               return(0);
+                       if ( ! mdoc_body_alloc(m, line, ppos, tok))
+                               return(0);
+                       body = m->last;
+                       break;
                }
 
-               /* Don't emit leading punct. for phrases. */
+               /* 
+                * Emit leading punctuation (i.e., punctuation before
+                * the MDOC_HEAD) for non-phrase types.
+                */
 
                if (NULL == head && 
+                               ARGS_PEND != ac &&
                                ARGS_PHRASE != ac &&
                                ARGS_PPHRASE != ac &&
                                ARGS_QWORD != ac &&
@@ -1011,24 +1049,47 @@ blk_full(MACRO_PROT_ARGS)
                        continue;
                }
 
-               /* Always re-open head for phrases. */
+               /* Open a head if one hasn't been opened. */
 
-               if (NULL == head || 
-                               ARGS_PHRASE == ac || 
-                               ARGS_PPHRASE == ac) {
+               if (NULL == head) {
                        if ( ! mdoc_head_alloc(m, line, ppos, tok))
                                return(0);
                        head = m->last;
                }
 
-               if (ARGS_PHRASE == ac || ARGS_PPHRASE == ac) {
+               if (ARGS_PHRASE == ac || 
+                               ARGS_PEND == ac ||
+                               ARGS_PPHRASE == ac) {
+                       /*
+                        * If we haven't opened a body yet, rewind the
+                        * head; if we have, rewind that instead.
+                        */
+
+                       mtt = body ? MDOC_BODY : MDOC_HEAD;
+                       if ( ! rew_sub(mtt, m, tok, line, ppos))
+                               return(0);
+                       
+                       /* Then allocate our body context. */
+
+                       if ( ! mdoc_body_alloc(m, line, ppos, tok))
+                               return(0);
+                       body = m->last;
+
+                       /*
+                        * Process phrases: set whether we're in a
+                        * partial-phrase (this effects line handling)
+                        * then call down into the phrase parser.
+                        */
+
                        if (ARGS_PPHRASE == ac)
                                m->flags |= MDOC_PPHRASE;
-                       if ( ! phrase(m, line, la, buf, ac))
+                       if (ARGS_PEND == ac && ARGS_PPHRASE == lac)
+                               m->flags |= MDOC_PPHRASE;
+
+                       if ( ! phrase(m, line, la, buf))
                                return(0);
+
                        m->flags &= ~MDOC_PPHRASE;
-                       if ( ! rew_sub(MDOC_HEAD, m, tok, line, ppos))
-                               return(0);
                        continue;
                }
 
@@ -1057,7 +1118,7 @@ blk_full(MACRO_PROT_ARGS)
        /* If we've already opened our body, exit now. */
 
        if (NULL != body)
-               return(1);
+               goto out;
 
 #ifdef UGLY
        /*
@@ -1084,6 +1145,16 @@ blk_full(MACRO_PROT_ARGS)
        if ( ! mdoc_body_alloc(m, line, ppos, tok))
                return(0);
 
+out:
+       if ( ! (MDOC_FREECOL & m->flags))
+               return(1);
+
+       if ( ! rew_sub(MDOC_BODY, m, tok, line, ppos))
+               return(0);
+       if ( ! rew_sub(MDOC_BLOCK, m, tok, line, ppos))
+               return(0);
+
+       m->flags &= ~MDOC_FREECOL;
        return(1);
 }
 
@@ -1578,26 +1649,24 @@ obsolete(MACRO_PROT_ARGS)
  * macro is encountered.
  */
 static int
-phrase(struct mdoc *m, int line, int ppos, char *buf, enum margserr ac)
+phrase(struct mdoc *m, int line, int ppos, char *buf)
 {
        int              la, pos;
-       enum margserr    aac;
+       enum margserr    ac;
        enum mdoct       ntok;
        char            *p;
 
-       assert(ARGS_PHRASE == ac || ARGS_PPHRASE == ac);
-
        for (pos = ppos; ; ) {
                la = pos;
 
-               aac = mdoc_zargs(m, line, &pos, buf, 0, &p);
+               ac = mdoc_zargs(m, line, &pos, buf, 0, &p);
 
-               if (ARGS_ERROR == aac)
+               if (ARGS_ERROR == ac)
                        return(0);
-               if (ARGS_EOLN == aac)
+               if (ARGS_EOLN == ac)
                        break;
 
-               ntok = ARGS_QWORD == aac ? MDOC_MAX : lookup_raw(p);
+               ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p);
 
                if (MDOC_MAX == ntok) {
                        if ( ! mdoc_word_alloc(m, line, la, p))
@@ -1614,3 +1683,46 @@ phrase(struct mdoc *m, int line, int ppos, char *buf, enum margserr ac)
 }
 
 
+/* ARGSUSED */
+static int
+phrase_ta(MACRO_PROT_ARGS)
+{
+       int               la;
+       enum mdoct        ntok;
+       enum margserr     ac;
+       char             *p;
+
+       /*
+        * FIXME: this is overly restrictive: if the `Ta' is unexpected,
+        * it should simply error out with ARGSLOST.
+        */
+
+       if ( ! rew_sub(MDOC_BODY, m, MDOC_It, line, ppos))
+               return(0);
+       if ( ! mdoc_body_alloc(m, line, ppos, MDOC_It))
+               return(0);
+
+       for (;;) {
+               la = *pos;
+               ac = mdoc_zargs(m, line, pos, buf, 0, &p);
+
+               if (ARGS_ERROR == ac)
+                       return(0);
+               if (ARGS_EOLN == ac)
+                       break;
+
+               ntok = ARGS_QWORD == ac ? MDOC_MAX : lookup_raw(p);
+
+               if (MDOC_MAX == ntok) {
+                       if ( ! mdoc_word_alloc(m, line, la, p))
+                               return(0);
+                       continue;
+               }
+
+               if ( ! mdoc_macro(m, ntok, line, la, pos, buf))
+                       return(0);
+               return(append_delims(m, line, pos, buf));
+       }
+
+       return(1);
+}