Print this page
Update to 1.12.3.

@@ -1,8 +1,9 @@
-/*      $Id: mdoc_argv.c,v 1.82 2012/03/23 05:50:24 kristaps Exp $ */
+/*      $Id: mdoc_argv.c,v 1.89 2013/12/25 00:50:05 schwarze Exp $ */
 /*
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2012 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
  * copyright notice and this permission notice appear in all copies.
  *

@@ -40,12 +41,11 @@
 };
 
 enum    argvflag {
         ARGV_NONE, /* no args to flag (e.g., -split) */
         ARGV_SINGLE, /* one arg to flag (e.g., -file xxx)  */
-        ARGV_MULTI, /* multiple args (e.g., -column xxx yyy) */
-        ARGV_OPT_SINGLE /* optional arg (e.g., -offset [xxx]) */
+        ARGV_MULTI /* multiple args (e.g., -column xxx yyy) */
 };
 
 struct  mdocarg {
         enum argsflag    flags;
         const enum mdocargt *argvs;

@@ -55,12 +55,10 @@
 static  enum margserr    args(struct mdoc *, int, int *, 
                                 char *, enum argsflag, char **);
 static  int              args_checkpunct(const char *, int);
 static  int              argv_multi(struct mdoc *, int, 
                                 struct mdoc_argv *, int *, char *);
-static  int              argv_opt_single(struct mdoc *, int, 
-                                struct mdoc_argv *, int *, char *);
 static  int              argv_single(struct mdoc *, int, 
                                 struct mdoc_argv *, int *, char *);
 
 static  const enum argvflag argvflags[MDOC_ARG_MAX] = {
         ARGV_NONE,      /* MDOC_Split */

@@ -67,11 +65,11 @@
         ARGV_NONE,      /* MDOC_Nosplit */
         ARGV_NONE,      /* MDOC_Ragged */
         ARGV_NONE,      /* MDOC_Unfilled */
         ARGV_NONE,      /* MDOC_Literal */
         ARGV_SINGLE,    /* MDOC_File */
-        ARGV_OPT_SINGLE, /* MDOC_Offset */
+        ARGV_SINGLE,    /* MDOC_Offset */
         ARGV_NONE,      /* MDOC_Bullet */
         ARGV_NONE,      /* MDOC_Dash */
         ARGV_NONE,      /* MDOC_Hyphen */
         ARGV_NONE,      /* MDOC_Item */
         ARGV_NONE,      /* MDOC_Enum */

@@ -79,11 +77,11 @@
         ARGV_NONE,      /* MDOC_Diag */
         ARGV_NONE,      /* MDOC_Hang */
         ARGV_NONE,      /* MDOC_Ohang */
         ARGV_NONE,      /* MDOC_Inset */
         ARGV_MULTI,     /* MDOC_Column */
-        ARGV_OPT_SINGLE, /* MDOC_Width */
+        ARGV_SINGLE,    /* MDOC_Width */
         ARGV_NONE,      /* MDOC_Compact */
         ARGV_NONE,      /* MDOC_Std */
         ARGV_NONE,      /* MDOC_Filled */
         ARGV_NONE,      /* MDOC_Words */
         ARGV_NONE,      /* MDOC_Emphasis */

@@ -144,11 +142,11 @@
         MDOC_Nested,
         MDOC_ARG_MAX
 };
 
 static  const struct mdocarg mdocargs[MDOC_MAX] = {
-        { ARGSFL_NONE, NULL }, /* Ap */
+        { ARGSFL_DELIM, NULL }, /* Ap */
         { ARGSFL_NONE, NULL }, /* Dd */
         { ARGSFL_NONE, NULL }, /* Dt */
         { ARGSFL_NONE, NULL }, /* Os */
         { ARGSFL_NONE, NULL }, /* Sh */
         { ARGSFL_NONE, NULL }, /* Ss */ 

@@ -161,11 +159,11 @@
         { ARGSFL_NONE, NULL }, /* El */
         { ARGSFL_NONE, NULL }, /* It */
         { ARGSFL_DELIM, NULL }, /* Ad */ 
         { ARGSFL_DELIM, args_An }, /* An */
         { ARGSFL_DELIM, NULL }, /* Ar */
-        { ARGSFL_NONE, NULL }, /* Cd */
+        { ARGSFL_DELIM, NULL }, /* Cd */
         { ARGSFL_DELIM, NULL }, /* Cm */
         { ARGSFL_DELIM, NULL }, /* Dv */ 
         { ARGSFL_DELIM, NULL }, /* Er */ 
         { ARGSFL_DELIM, NULL }, /* Ev */ 
         { ARGSFL_NONE, args_Ex }, /* Ex */

@@ -173,11 +171,11 @@
         { ARGSFL_NONE, NULL }, /* Fd */ 
         { ARGSFL_DELIM, NULL }, /* Fl */
         { ARGSFL_DELIM, NULL }, /* Fn */ 
         { ARGSFL_DELIM, NULL }, /* Ft */ 
         { ARGSFL_DELIM, NULL }, /* Ic */ 
-        { ARGSFL_NONE, NULL }, /* In */ 
+        { ARGSFL_DELIM, NULL }, /* In */ 
         { ARGSFL_DELIM, NULL }, /* Li */
         { ARGSFL_NONE, NULL }, /* Nd */ 
         { ARGSFL_DELIM, NULL }, /* Nm */ 
         { ARGSFL_DELIM, NULL }, /* Op */
         { ARGSFL_NONE, NULL }, /* Ot */

@@ -241,30 +239,30 @@
         { ARGSFL_DELIM, NULL }, /* Tn */
         { ARGSFL_DELIM, NULL }, /* Ux */
         { ARGSFL_DELIM, NULL }, /* Xc */
         { ARGSFL_NONE, NULL }, /* Xo */
         { ARGSFL_NONE, NULL }, /* Fo */ 
-        { ARGSFL_NONE, NULL }, /* Fc */ 
+        { ARGSFL_DELIM, NULL }, /* Fc */ 
         { ARGSFL_NONE, NULL }, /* Oo */
         { ARGSFL_DELIM, NULL }, /* Oc */
         { ARGSFL_NONE, args_Bk }, /* Bk */
         { ARGSFL_NONE, NULL }, /* Ek */
         { ARGSFL_NONE, NULL }, /* Bt */
         { ARGSFL_NONE, NULL }, /* Hf */
         { ARGSFL_NONE, NULL }, /* Fr */
         { ARGSFL_NONE, NULL }, /* Ud */
-        { ARGSFL_NONE, NULL }, /* Lb */
+        { ARGSFL_DELIM, NULL }, /* Lb */
         { ARGSFL_NONE, NULL }, /* Lp */
         { ARGSFL_DELIM, NULL }, /* Lk */
         { ARGSFL_DELIM, NULL }, /* Mt */
         { ARGSFL_DELIM, NULL }, /* Brq */
         { ARGSFL_NONE, NULL }, /* Bro */
         { ARGSFL_DELIM, NULL }, /* Brc */
         { ARGSFL_NONE, NULL }, /* %C */
         { ARGSFL_NONE, NULL }, /* Es */
         { ARGSFL_NONE, NULL }, /* En */
-        { ARGSFL_NONE, NULL }, /* Dx */
+        { ARGSFL_DELIM, NULL }, /* Dx */
         { ARGSFL_NONE, NULL }, /* %Q */
         { ARGSFL_NONE, NULL }, /* br */
         { ARGSFL_NONE, NULL }, /* sp */
         { ARGSFL_NONE, NULL }, /* %U */
         { ARGSFL_NONE, NULL }, /* Ta */

@@ -275,11 +273,11 @@
  * Parse an argument from line text.  This comes in the form of -key
  * [value0...], which may either have a single mandatory value, at least
  * one mandatory value, an optional single value, or no value.
  */
 enum margverr
-mdoc_argv(struct mdoc *m, int line, enum mdoct tok,
+mdoc_argv(struct mdoc *mdoc, int line, enum mdoct tok,
                 struct mdoc_arg **v, int *pos, char *buf)
 {
         char             *p, sv;
         struct mdoc_argv tmp;
         struct mdoc_arg  *arg;

@@ -342,21 +340,17 @@
         while (buf[*pos] && ' ' == buf[*pos])
                 (*pos)++;
 
         switch (argvflags[tmp.arg]) {
         case (ARGV_SINGLE):
-                if ( ! argv_single(m, line, &tmp, pos, buf))
+                if ( ! argv_single(mdoc, line, &tmp, pos, buf))
                         return(ARGV_ERROR);
                 break;
         case (ARGV_MULTI):
-                if ( ! argv_multi(m, line, &tmp, pos, buf))
+                if ( ! argv_multi(mdoc, line, &tmp, pos, buf))
                         return(ARGV_ERROR);
                 break;
-        case (ARGV_OPT_SINGLE):
-                if ( ! argv_opt_single(m, line, &tmp, pos, buf))
-                        return(ARGV_ERROR);
-                break;
         case (ARGV_NONE):
                 break;
         }
 
         if (NULL == (arg = *v))

@@ -411,64 +405,65 @@
         for (--p->argc; iarg < (int)p->argc; iarg++)
                 p->argv[iarg] = p->argv[iarg+1];
 }
 
 enum margserr
-mdoc_zargs(struct mdoc *m, int line, int *pos, char *buf, char **v)
+mdoc_zargs(struct mdoc *mdoc, int line, int *pos, char *buf, char **v)
 {
 
-        return(args(m, line, pos, buf, ARGSFL_NONE, v));
+        return(args(mdoc, line, pos, buf, ARGSFL_NONE, v));
 }
 
 enum margserr
-mdoc_args(struct mdoc *m, int line, int *pos, 
+mdoc_args(struct mdoc *mdoc, int line, int *pos, 
                 char *buf, enum mdoct tok, char **v)
 {
         enum argsflag     fl;
         struct mdoc_node *n;
 
         fl = mdocargs[tok].flags;
 
         if (MDOC_It != tok)
-                return(args(m, line, pos, buf, fl, v));
+                return(args(mdoc, line, pos, buf, fl, v));
 
         /*
          * We know that we're in an `It', so it's reasonable to expect
          * us to be sitting in a `Bl'.  Someday this may not be the case
          * (if we allow random `It's sitting out there), so provide a
          * safe fall-back into the default behaviour.
          */
 
-        for (n = m->last; n; n = n->parent)
+        for (n = mdoc->last; n; n = n->parent)
                 if (MDOC_Bl == n->tok)
                         if (LIST_column == n->norm->Bl.type) {
                                 fl = ARGSFL_TABSEP;
                                 break;
                         }
 
-        return(args(m, line, pos, buf, fl, v));
+        return(args(mdoc, line, pos, buf, fl, v));
 }
 
 static enum margserr
-args(struct mdoc *m, int line, int *pos, 
+args(struct mdoc *mdoc, int line, int *pos, 
                 char *buf, enum argsflag fl, char **v)
 {
         char            *p, *pp;
+        int              pairs;
         enum margserr    rc;
 
         if ('\0' == buf[*pos]) {
-                if (MDOC_PPHRASE & m->flags)
+                if (MDOC_PPHRASE & mdoc->flags)
                         return(ARGS_EOLN);
                 /*
                  * If we're not in a partial phrase and the flag for
                  * being a phrase literal is still set, the punctuation
                  * is unterminated.
                  */
-                if (MDOC_PHRASELIT & m->flags)
-                        mdoc_pmsg(m, line, *pos, MANDOCERR_BADQUOTE);
+                if (MDOC_PHRASELIT & mdoc->flags)
+                        mdoc_pmsg(mdoc, line, *pos, MANDOCERR_BADQUOTE);
 
-                m->flags &= ~MDOC_PHRASELIT;
+                mdoc->flags &= ~MDOC_PHRASELIT;
                 return(ARGS_EOLN);
         }
 
         *v = &buf[*pos];
 

@@ -487,11 +482,11 @@
                 /* Scan ahead to tab (can't be escaped). */
                 p = strchr(*v, '\t');
                 pp = NULL;
 
                 /* Scan ahead to unescaped `Ta'. */
-                if ( ! (MDOC_PHRASELIT & m->flags)) 
+                if ( ! (MDOC_PHRASELIT & mdoc->flags)) 
                         for (pp = *v; ; pp++) {
                                 if (NULL == (pp = strstr(pp, "Ta")))
                                         break;
                                 if (pp > *v && ' ' != *(pp - 1))
                                         continue;

@@ -521,11 +516,11 @@
                         p = strchr(*v, 0);
                 }
 
                 /* Whitespace check for eoln case... */
                 if ('\0' == *p && ' ' == *(p - 1))
-                        mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE);
+                        mdoc_pmsg(mdoc, line, *pos, MANDOCERR_EOLNSPACE);
 
                 *pos += (int)(p - *v);
 
                 /* Strip delimiter's preceding whitespace. */
                 pp = p - 1;

@@ -544,52 +539,63 @@
         } 
 
         /* 
          * Process a quoted literal.  A quote begins with a double-quote
          * and ends with a double-quote NOT preceded by a double-quote.
+         * NUL-terminate the literal in place.
+         * Collapse pairs of quotes inside quoted literals.
          * Whitespace is NOT involved in literal termination.
          */
 
-        if (MDOC_PHRASELIT & m->flags || '\"' == buf[*pos]) {
-                if ( ! (MDOC_PHRASELIT & m->flags))
+        if (MDOC_PHRASELIT & mdoc->flags || '\"' == buf[*pos]) {
+                if ( ! (MDOC_PHRASELIT & mdoc->flags))
                         *v = &buf[++(*pos)];
 
-                if (MDOC_PPHRASE & m->flags)
-                        m->flags |= MDOC_PHRASELIT;
+                if (MDOC_PPHRASE & mdoc->flags)
+                        mdoc->flags |= MDOC_PHRASELIT;
 
+                pairs = 0;
                 for ( ; buf[*pos]; (*pos)++) {
+                        /* Move following text left after quoted quotes. */
+                        if (pairs)
+                                buf[*pos - pairs] = buf[*pos];
                         if ('\"' != buf[*pos])
                                 continue;
+                        /* Unquoted quotes end quoted args. */
                         if ('\"' != buf[*pos + 1])
                                 break;
+                        /* Quoted quotes collapse. */
+                        pairs++;
                         (*pos)++;
                 }
+                if (pairs)
+                        buf[*pos - pairs] = '\0';
 
                 if ('\0' == buf[*pos]) {
-                        if (MDOC_PPHRASE & m->flags)
+                        if (MDOC_PPHRASE & mdoc->flags)
                                 return(ARGS_QWORD);
-                        mdoc_pmsg(m, line, *pos, MANDOCERR_BADQUOTE);
+                        mdoc_pmsg(mdoc, line, *pos, MANDOCERR_BADQUOTE);
                         return(ARGS_QWORD);
                 }
 
-                m->flags &= ~MDOC_PHRASELIT;
+                mdoc->flags &= ~MDOC_PHRASELIT;
                 buf[(*pos)++] = '\0';
 
                 if ('\0' == buf[*pos])
                         return(ARGS_QWORD);
 
                 while (' ' == buf[*pos])
                         (*pos)++;
 
                 if ('\0' == buf[*pos])
-                        mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE);
+                        mdoc_pmsg(mdoc, line, *pos, MANDOCERR_EOLNSPACE);
 
                 return(ARGS_QWORD);
         }
 
         p = &buf[*pos];
-        *v = mandoc_getarg(m->parse, &p, line, pos);
+        *v = mandoc_getarg(mdoc->parse, &p, line, pos);
 
         return(ARGS_WORD);
 }
 
 /* 

@@ -641,20 +647,20 @@
 
         return('\0' == buf[i]);
 }
 
 static int
-argv_multi(struct mdoc *m, int line, 
+argv_multi(struct mdoc *mdoc, int line, 
                 struct mdoc_argv *v, int *pos, char *buf)
 {
         enum margserr    ac;
         char            *p;
 
         for (v->sz = 0; ; v->sz++) {
                 if ('-' == buf[*pos])
                         break;
-                ac = args(m, line, pos, buf, ARGSFL_NONE, &p);
+                ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p);
                 if (ARGS_ERROR == ac)
                         return(0);
                 else if (ARGS_EOLN == ac)
                         break;
 

@@ -667,50 +673,23 @@
 
         return(1);
 }
 
 static int
-argv_opt_single(struct mdoc *m, int line, 
+argv_single(struct mdoc *mdoc, int line, 
                 struct mdoc_argv *v, int *pos, char *buf)
 {
         enum margserr    ac;
         char            *p;
 
-        if ('-' == buf[*pos])
-                return(1);
-
-        ac = args(m, line, pos, buf, ARGSFL_NONE, &p);
+        ac = args(mdoc, line, pos, buf, ARGSFL_NONE, &p);
         if (ARGS_ERROR == ac)
                 return(0);
         if (ARGS_EOLN == ac)
                 return(1);
 
         v->sz = 1;
-        v->value = mandoc_malloc(sizeof(char *));
-        v->value[0] = mandoc_strdup(p);
-
-        return(1);
-}
-
-static int
-argv_single(struct mdoc *m, int line, 
-                struct mdoc_argv *v, int *pos, char *buf)
-{
-        int              ppos;
-        enum margserr    ac;
-        char            *p;
-
-        ppos = *pos;
-
-        ac = args(m, line, pos, buf, ARGSFL_NONE, &p);
-        if (ARGS_EOLN == ac) {
-                mdoc_pmsg(m, line, ppos, MANDOCERR_SYNTARGVCOUNT);
-                return(0);
-        } else if (ARGS_ERROR == ac)
-                return(0);
-
-        v->sz = 1;
         v->value = mandoc_malloc(sizeof(char *));
         v->value[0] = mandoc_strdup(p);
 
         return(1);
 }