+/*
+ * 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.
+ */
+int
+mdoc_argv(struct mdoc *mdoc, int line, int tok,
+ struct mdoc_arg **v, int *pos, char *buf)
+{
+ int i;
+ char *p;
+ struct mdoc_argv tmp;
+ struct mdoc_arg *arg;
+
+ if (0 == buf[*pos])
+ return(ARGV_EOLN);
+
+ assert( ! isspace((u_char)buf[*pos]));
+
+ if ('-' != buf[*pos])
+ return(ARGV_WORD);
+
+ i = *pos;
+ p = &buf[++(*pos)];
+
+ assert(*pos > 0);
+
+ /* LINTED */
+ while (buf[*pos]) {
+ if (isspace((u_char)buf[*pos]))
+ if ('\\' != buf[*pos - 1])
+ break;
+ (*pos)++;
+ }
+
+ if (buf[*pos])
+ buf[(*pos)++] = 0;
+
+ (void)memset(&tmp, 0, sizeof(struct mdoc_argv));
+ tmp.line = line;
+ tmp.pos = *pos;
+
+ /*
+ * We now parse out the per-macro arguments. XXX - this can be
+ * made much cleaner using per-argument tables. See argv_a2arg
+ * for details.
+ */
+
+ if (MDOC_ARG_MAX == (tmp.arg = argv_a2arg(tok, p))) {
+ if ( ! pwarn(mdoc, line, i, WARGVPARM))
+ return(ARGV_ERROR);
+ return(ARGV_WORD);
+ }
+
+ while (buf[*pos] && isspace((u_char)buf[*pos]))
+ (*pos)++;
+
+ /* FIXME: whitespace if no value. */
+
+ if ( ! argv(mdoc, tok, line, &tmp, pos, buf))
+ return(ARGV_ERROR);
+
+ if (NULL == (arg = *v)) {
+ v = xcalloc(1, sizeof(struct mdoc_arg));
+ arg = *v;
+ }
+
+ arg->argc++;
+ arg->argv = xrealloc(arg->argv, arg->argc *
+ sizeof(struct mdoc_arg));
+
+ (void)memcpy(&arg->argv[(int)arg->argc - 1],
+ &tmp, sizeof(struct mdoc_argv));
+
+ return(ARGV_ARG);
+}
+
+
+void
+mdoc_argv_free(struct mdoc_arg *p)
+{
+ int i, j;
+
+ if (p->refcnt && --(p->refcnt) > 0)
+ return;
+
+ /* LINTED */
+ for (i = 0; i < (int)p->argc; i++) {
+ if (0 == p->argv[i].sz)
+ continue;
+ /* LINTED */
+ for (j = 0; j < (int)p->argv[i].sz; j++)
+ free(p->argv[i].value[j]);
+ free(p->argv[i].value);
+ }
+
+ if (p->argc)
+ free(p->argv);
+ free(p);
+}
+
+
+