Annotation of mandoc/mdoc_argv.c, Revision 1.15
1.15 ! kristaps 1: /* $Id: mdoc_argv.c,v 1.14 2009/07/17 10:56:57 kristaps Exp $ */
1.1 kristaps 2: /*
1.4 kristaps 3: * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
1.1 kristaps 4: *
5: * Permission to use, copy, modify, and distribute this software for any
1.3 kristaps 6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 8: *
1.3 kristaps 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 kristaps 16: */
17: #include <sys/types.h>
18:
19: #include <assert.h>
20: #include <ctype.h>
21: #include <stdlib.h>
22: #include <stdio.h>
23: #include <string.h>
24:
25: #include "libmdoc.h"
26:
27: /*
28: * Routines to parse arguments of macros. Arguments follow the syntax
29: * of `-arg [val [valN...]]'. Arguments come in all types: quoted
30: * arguments, multiple arguments per value, no-value arguments, etc.
31: *
32: * There's no limit to the number or arguments that may be allocated.
33: */
34:
1.6 kristaps 35: /* FIXME .Bf Li raises "macro-like parameter". */
36:
1.1 kristaps 37: #define ARGS_QUOTED (1 << 0)
38: #define ARGS_DELIM (1 << 1)
39: #define ARGS_TABSEP (1 << 2)
40:
41: #define ARGV_NONE (1 << 0)
42: #define ARGV_SINGLE (1 << 1)
43: #define ARGV_MULTI (1 << 2)
44: #define ARGV_OPT_SINGLE (1 << 3)
45:
46: #define MULTI_STEP 5
47:
48: static int argv_a2arg(int, const char *);
49: static int args(struct mdoc *, int, int *,
50: char *, int, char **);
51: static int argv(struct mdoc *, int,
52: struct mdoc_argv *, int *, char *);
53: static int argv_single(struct mdoc *, int,
54: struct mdoc_argv *, int *, char *);
55: static int argv_opt_single(struct mdoc *, int,
56: struct mdoc_argv *, int *, char *);
57: static int argv_multi(struct mdoc *, int,
58: struct mdoc_argv *, int *, char *);
1.2 kristaps 59:
1.1 kristaps 60: /* Per-argument flags. */
61:
62: static int mdoc_argvflags[MDOC_ARG_MAX] = {
63: ARGV_NONE, /* MDOC_Split */
64: ARGV_NONE, /* MDOC_Nosplit */
65: ARGV_NONE, /* MDOC_Ragged */
66: ARGV_NONE, /* MDOC_Unfilled */
67: ARGV_NONE, /* MDOC_Literal */
68: ARGV_NONE, /* MDOC_File */
69: ARGV_SINGLE, /* MDOC_Offset */
70: ARGV_NONE, /* MDOC_Bullet */
71: ARGV_NONE, /* MDOC_Dash */
72: ARGV_NONE, /* MDOC_Hyphen */
73: ARGV_NONE, /* MDOC_Item */
74: ARGV_NONE, /* MDOC_Enum */
75: ARGV_NONE, /* MDOC_Tag */
76: ARGV_NONE, /* MDOC_Diag */
77: ARGV_NONE, /* MDOC_Hang */
78: ARGV_NONE, /* MDOC_Ohang */
79: ARGV_NONE, /* MDOC_Inset */
80: ARGV_MULTI, /* MDOC_Column */
81: ARGV_SINGLE, /* MDOC_Width */
82: ARGV_NONE, /* MDOC_Compact */
83: ARGV_OPT_SINGLE, /* MDOC_Std */
84: ARGV_NONE, /* MDOC_Filled */
85: ARGV_NONE, /* MDOC_Words */
86: ARGV_NONE, /* MDOC_Emphasis */
87: ARGV_NONE, /* MDOC_Symbolic */
88: ARGV_NONE /* MDOC_Symbolic */
89: };
90:
91: static int mdoc_argflags[MDOC_MAX] = {
1.5 kristaps 92: 0, /* Ap */
1.1 kristaps 93: 0, /* Dd */
94: 0, /* Dt */
95: 0, /* Os */
96: ARGS_QUOTED, /* Sh */
97: ARGS_QUOTED, /* Ss */
98: ARGS_DELIM, /* Pp */
99: ARGS_DELIM, /* D1 */
100: ARGS_DELIM | ARGS_QUOTED, /* Dl */
101: 0, /* Bd */
102: 0, /* Ed */
1.7 kristaps 103: ARGS_QUOTED, /* Bl */
1.1 kristaps 104: 0, /* El */
105: 0, /* It */
106: ARGS_DELIM, /* Ad */
107: ARGS_DELIM, /* An */
108: ARGS_DELIM | ARGS_QUOTED, /* Ar */
109: ARGS_QUOTED, /* Cd */
110: ARGS_DELIM, /* Cm */
111: ARGS_DELIM, /* Dv */
112: ARGS_DELIM, /* Er */
113: ARGS_DELIM, /* Ev */
114: 0, /* Ex */
115: ARGS_DELIM | ARGS_QUOTED, /* Fa */
116: 0, /* Fd */
117: ARGS_DELIM, /* Fl */
118: ARGS_DELIM | ARGS_QUOTED, /* Fn */
119: ARGS_DELIM | ARGS_QUOTED, /* Ft */
120: ARGS_DELIM, /* Ic */
121: 0, /* In */
122: ARGS_DELIM | ARGS_QUOTED, /* Li */
123: ARGS_QUOTED, /* Nd */
124: ARGS_DELIM, /* Nm */
125: ARGS_DELIM, /* Op */
126: 0, /* Ot */
127: ARGS_DELIM, /* Pa */
128: 0, /* Rv */
1.15 ! kristaps 129: ARGS_DELIM, /* St */
1.1 kristaps 130: ARGS_DELIM, /* Va */
131: ARGS_DELIM, /* Vt */
132: ARGS_DELIM, /* Xr */
133: ARGS_QUOTED, /* %A */
134: ARGS_QUOTED, /* %B */
135: ARGS_QUOTED, /* %D */
136: ARGS_QUOTED, /* %I */
137: ARGS_QUOTED, /* %J */
138: ARGS_QUOTED, /* %N */
139: ARGS_QUOTED, /* %O */
140: ARGS_QUOTED, /* %P */
141: ARGS_QUOTED, /* %R */
142: ARGS_QUOTED, /* %T */
143: ARGS_QUOTED, /* %V */
144: ARGS_DELIM, /* Ac */
145: 0, /* Ao */
146: ARGS_DELIM, /* Aq */
147: ARGS_DELIM, /* At */
148: ARGS_DELIM, /* Bc */
149: 0, /* Bf */
150: 0, /* Bo */
151: ARGS_DELIM, /* Bq */
152: ARGS_DELIM, /* Bsx */
153: ARGS_DELIM, /* Bx */
154: 0, /* Db */
155: ARGS_DELIM, /* Dc */
156: 0, /* Do */
157: ARGS_DELIM, /* Dq */
158: ARGS_DELIM, /* Ec */
159: 0, /* Ef */
160: ARGS_DELIM, /* Em */
161: 0, /* Eo */
162: ARGS_DELIM, /* Fx */
163: ARGS_DELIM, /* Ms */
164: ARGS_DELIM, /* No */
165: ARGS_DELIM, /* Ns */
166: ARGS_DELIM, /* Nx */
167: ARGS_DELIM, /* Ox */
168: ARGS_DELIM, /* Pc */
169: ARGS_DELIM, /* Pf */
170: 0, /* Po */
171: ARGS_DELIM, /* Pq */
172: ARGS_DELIM, /* Qc */
173: ARGS_DELIM, /* Ql */
174: 0, /* Qo */
175: ARGS_DELIM, /* Qq */
176: 0, /* Re */
177: 0, /* Rs */
178: ARGS_DELIM, /* Sc */
179: 0, /* So */
180: ARGS_DELIM, /* Sq */
181: 0, /* Sm */
182: ARGS_DELIM, /* Sx */
183: ARGS_DELIM | ARGS_QUOTED, /* Sy */
184: ARGS_DELIM, /* Tn */
185: ARGS_DELIM, /* Ux */
186: ARGS_DELIM, /* Xc */
187: 0, /* Xo */
188: ARGS_QUOTED, /* Fo */
189: 0, /* Fc */
190: 0, /* Oo */
191: ARGS_DELIM, /* Oc */
192: 0, /* Bk */
193: 0, /* Ek */
194: 0, /* Bt */
195: 0, /* Hf */
196: 0, /* Fr */
197: 0, /* Ud */
198: 0, /* Lb */
199: ARGS_DELIM, /* Lp */
200: ARGS_DELIM | ARGS_QUOTED, /* Lk */
201: ARGS_DELIM | ARGS_QUOTED, /* Mt */
202: ARGS_DELIM, /* Brq */
203: 0, /* Bro */
204: ARGS_DELIM, /* Brc */
205: ARGS_QUOTED, /* %C */
206: 0, /* Es */
207: 0, /* En */
208: 0, /* Dx */
209: ARGS_QUOTED, /* %Q */
1.14 kristaps 210: 0, /* br */
211: 0, /* sp */
1.1 kristaps 212: };
213:
214:
215: /*
216: * Parse an argument from line text. This comes in the form of -key
217: * [value0...], which may either have a single mandatory value, at least
218: * one mandatory value, an optional single value, or no value.
219: */
220: int
1.11 kristaps 221: mdoc_argv(struct mdoc *m, int line, int tok,
1.1 kristaps 222: struct mdoc_arg **v, int *pos, char *buf)
223: {
224: int i;
225: char *p, sv;
226: struct mdoc_argv tmp;
227: struct mdoc_arg *arg;
228:
229: if (0 == buf[*pos])
230: return(ARGV_EOLN);
231:
232: assert(' ' != buf[*pos]);
233:
234: /* Parse through to the first unescaped space. */
235:
236: i = *pos;
237: p = &buf[++(*pos)];
238:
239: assert(*pos > 0);
240:
241: /* LINTED */
242: while (buf[*pos]) {
243: if (' ' == buf[*pos])
244: if ('\\' != buf[*pos - 1])
245: break;
246: (*pos)++;
247: }
248:
249: /* XXX - save zeroed byte, if not an argument. */
250:
251: sv = 0;
252: if (buf[*pos]) {
253: sv = buf[*pos];
254: buf[(*pos)++] = 0;
255: }
256:
257: (void)memset(&tmp, 0, sizeof(struct mdoc_argv));
258: tmp.line = line;
259: tmp.pos = *pos;
260:
261: /* See if our token accepts the argument. */
262:
263: if (MDOC_ARG_MAX == (tmp.arg = argv_a2arg(tok, p))) {
264: /* XXX - restore saved zeroed byte. */
265: if (sv)
266: buf[*pos - 1] = sv;
267: return(ARGV_WORD);
268: }
269:
270: while (buf[*pos] && ' ' == buf[*pos])
271: (*pos)++;
272:
1.11 kristaps 273: if ( ! argv(m, line, &tmp, pos, buf))
1.1 kristaps 274: return(ARGV_ERROR);
275:
276: if (NULL == (arg = *v)) {
1.2 kristaps 277: *v = calloc(1, sizeof(struct mdoc_arg));
278: if (NULL == *v) {
1.11 kristaps 279: (void)mdoc_nerr(m, m->last, EMALLOC);
1.2 kristaps 280: return(ARGV_ERROR);
281: }
1.1 kristaps 282: arg = *v;
283: }
284:
285: arg->argc++;
1.2 kristaps 286: arg->argv = realloc(arg->argv, arg->argc *
1.1 kristaps 287: sizeof(struct mdoc_argv));
288:
1.2 kristaps 289: if (NULL == arg->argv) {
1.11 kristaps 290: (void)mdoc_nerr(m, m->last, EMALLOC);
1.2 kristaps 291: return(ARGV_ERROR);
292: }
293:
1.1 kristaps 294: (void)memcpy(&arg->argv[(int)arg->argc - 1],
295: &tmp, sizeof(struct mdoc_argv));
296:
297: return(ARGV_ARG);
298: }
299:
300:
301: void
302: mdoc_argv_free(struct mdoc_arg *p)
303: {
304: int i, j;
305:
306: if (NULL == p)
307: return;
308:
309: if (p->refcnt) {
310: --(p->refcnt);
311: if (p->refcnt)
312: return;
313: }
314: assert(p->argc);
315:
316: /* LINTED */
317: for (i = 0; i < (int)p->argc; i++) {
318: if (0 == p->argv[i].sz)
319: continue;
320: /* LINTED */
321: for (j = 0; j < (int)p->argv[i].sz; j++)
322: free(p->argv[i].value[j]);
323:
324: free(p->argv[i].value);
325: }
326:
327: free(p->argv);
328: free(p);
329: }
330:
331:
332: int
1.11 kristaps 333: mdoc_args(struct mdoc *m, int line,
1.1 kristaps 334: int *pos, char *buf, int tok, char **v)
335: {
336: int fl, c, i;
337: struct mdoc_node *n;
338:
339: fl = (0 == tok) ? 0 : mdoc_argflags[tok];
340:
341: /*
342: * Override per-macro argument flags with context-specific ones.
343: * As of now, this is only valid for `It' depending on its list
344: * context.
345: */
346:
347: switch (tok) {
348: case (MDOC_It):
1.11 kristaps 349: for (n = m->last; n; n = n->parent)
1.1 kristaps 350: if (MDOC_BLOCK == n->type && MDOC_Bl == n->tok)
351: break;
352:
353: assert(n);
354: c = (int)(n->args ? n->args->argc : 0);
355: assert(c > 0);
356:
357: /*
358: * Using `Bl -column' adds ARGS_TABSEP to the arguments
359: * and invalidates ARGS_DELIM. Using `Bl -diag' allows
360: * for quoted arguments.
361: */
362:
363: /* LINTED */
364: for (i = 0; i < c; i++) {
365: switch (n->args->argv[i].arg) {
366: case (MDOC_Column):
367: fl |= ARGS_TABSEP;
368: fl &= ~ARGS_DELIM;
369: i = c;
370: break;
371: case (MDOC_Diag):
372: fl |= ARGS_QUOTED;
373: i = c;
374: break;
375: default:
376: break;
377: }
378: }
379: break;
380: default:
381: break;
382: }
383:
1.11 kristaps 384: return(args(m, line, pos, buf, fl, v));
1.1 kristaps 385: }
386:
387:
388: static int
1.13 kristaps 389: args(struct mdoc *m, int line, int *pos,
390: char *buf, int fl, char **v)
1.1 kristaps 391: {
392: int i;
393: char *p, *pp;
394:
395: assert(*pos > 0);
396:
397: if (0 == buf[*pos])
398: return(ARGS_EOLN);
399:
400: if ('\"' == buf[*pos] && ! (fl & ARGS_QUOTED))
1.11 kristaps 401: if ( ! mdoc_pwarn(m, line, *pos, EQUOTPARM))
1.1 kristaps 402: return(ARGS_ERROR);
403:
404: /*
405: * If the first character is a delimiter and we're to look for
406: * delimited strings, then pass down the buffer seeing if it
407: * follows the pattern of [[::delim::][ ]+]+.
408: */
409:
410: if ((fl & ARGS_DELIM) && mdoc_iscdelim(buf[*pos])) {
411: for (i = *pos; buf[i]; ) {
412: if ( ! mdoc_iscdelim(buf[i]))
413: break;
414: i++;
415: /* There must be at least one space... */
416: if (0 == buf[i] || ' ' != buf[i])
417: break;
418: i++;
419: while (buf[i] && ' ' == buf[i])
420: i++;
421: }
422: if (0 == buf[i]) {
423: *v = &buf[*pos];
424: return(ARGS_PUNCT);
425: }
426: }
427:
428: /* First parse non-quoted strings. */
429:
430: if ('\"' != buf[*pos] || ! (ARGS_QUOTED & fl)) {
431: *v = &buf[*pos];
432:
433: /*
434: * Thar be dragons here! If we're tab-separated, search
435: * ahead for either a tab or the `Ta' macro.
436: * If a `Ta' is detected, it must be space-buffered before and
437: * after. If either of these hold true, then prune out the
438: * extra spaces and call it an argument.
439: */
440:
441: if (ARGS_TABSEP & fl) {
442: /* Scan ahead to unescaped tab. */
443:
444: p = strchr(*v, '\t');
445:
446: /* Scan ahead to unescaped `Ta'. */
447:
448: for (pp = *v; ; pp++) {
449: if (NULL == (pp = strstr(pp, "Ta")))
450: break;
451: if (pp > *v && ' ' != *(pp - 1))
452: continue;
453: if (' ' == *(pp + 2) || 0 == *(pp + 2))
454: break;
455: }
456:
457: /* Choose delimiter tab/Ta. */
458:
459: if (p && pp)
460: p = (p < pp ? p : pp);
461: else if ( ! p && pp)
462: p = pp;
463:
464: /* Strip delimiter's preceding whitespace. */
465:
466: if (p && p > *v) {
467: pp = p - 1;
468: while (pp > *v && ' ' == *pp)
469: pp--;
470: if (pp == *v && ' ' == *pp)
471: *pp = 0;
472: else if (' ' == *pp)
473: *(pp + 1) = 0;
474: }
475:
476: /* ...in- and proceding whitespace. */
477:
478: if (p && ('\t' != *p)) {
479: *p++ = 0;
480: *p++ = 0;
481: } else if (p)
482: *p++ = 0;
483:
484: if (p) {
485: while (' ' == *p)
486: p++;
487: if (0 != *p)
488: *(p - 1) = 0;
489: *pos += (int)(p - *v);
490: }
491:
492: if (p && 0 == *p)
1.11 kristaps 493: if ( ! mdoc_pwarn(m, line, *pos, ECOLEMPTY))
1.13 kristaps 494: return(ARGS_ERROR);
1.1 kristaps 495: if (p && 0 == *p && p > *v && ' ' == *(p - 1))
1.11 kristaps 496: if ( ! mdoc_pwarn(m, line, *pos, ETAILWS))
1.13 kristaps 497: return(ARGS_ERROR);
1.1 kristaps 498:
499: if (p)
500: return(ARGS_PHRASE);
501:
502: /* Configure the eoln case, too. */
503:
504: p = strchr(*v, 0);
505: assert(p);
506:
507: if (p > *v && ' ' == *(p - 1))
1.11 kristaps 508: if ( ! mdoc_pwarn(m, line, *pos, ETAILWS))
1.13 kristaps 509: return(ARGS_ERROR);
1.1 kristaps 510: *pos += (int)(p - *v);
511:
512: return(ARGS_PHRASE);
513: }
514:
515: /* Do non-tabsep look-ahead here. */
516:
517: if ( ! (ARGS_TABSEP & fl))
518: while (buf[*pos]) {
519: if (' ' == buf[*pos])
520: if ('\\' != buf[*pos - 1])
521: break;
522: (*pos)++;
523: }
524:
525: if (0 == buf[*pos])
526: return(ARGS_WORD);
527:
528: buf[(*pos)++] = 0;
529:
530: if (0 == buf[*pos])
531: return(ARGS_WORD);
532:
533: if ( ! (ARGS_TABSEP & fl))
534: while (buf[*pos] && ' ' == buf[*pos])
535: (*pos)++;
536:
537: if (buf[*pos])
538: return(ARGS_WORD);
539:
1.11 kristaps 540: if ( ! mdoc_pwarn(m, line, *pos, ETAILWS))
1.1 kristaps 541: return(ARGS_ERROR);
542:
543: return(ARGS_WORD);
544: }
545:
546: /*
547: * If we're a quoted string (and quoted strings are allowed),
548: * then parse ahead to the next quote. If none's found, it's an
549: * error. After, parse to the next word.
550: */
551:
552: *v = &buf[++(*pos)];
553:
554: while (buf[*pos] && '\"' != buf[*pos])
555: (*pos)++;
556:
557: if (0 == buf[*pos]) {
1.11 kristaps 558: (void)mdoc_perr(m, line, *pos, EQUOTTERM);
1.1 kristaps 559: return(ARGS_ERROR);
560: }
561:
562: buf[(*pos)++] = 0;
563: if (0 == buf[*pos])
564: return(ARGS_QWORD);
565:
566: while (buf[*pos] && ' ' == buf[*pos])
567: (*pos)++;
568:
569: if (buf[*pos])
570: return(ARGS_QWORD);
571:
1.11 kristaps 572: if ( ! mdoc_pwarn(m, line, *pos, ETAILWS))
1.1 kristaps 573: return(ARGS_ERROR);
574:
575: return(ARGS_QWORD);
576: }
577:
578:
579: static int
580: argv_a2arg(int tok, const char *argv)
581: {
582:
583: /*
584: * Parse an argument identifier from its text. XXX - this
585: * should really be table-driven to clarify the code.
586: *
587: * If you add an argument to the list, make sure that you
588: * register it here with its one or more macros!
589: */
590:
591: switch (tok) {
592: case (MDOC_An):
1.2 kristaps 593: if (0 == strcmp(argv, "split"))
1.1 kristaps 594: return(MDOC_Split);
1.2 kristaps 595: else if (0 == strcmp(argv, "nosplit"))
1.1 kristaps 596: return(MDOC_Nosplit);
597: break;
598:
599: case (MDOC_Bd):
1.2 kristaps 600: if (0 == strcmp(argv, "ragged"))
1.1 kristaps 601: return(MDOC_Ragged);
1.2 kristaps 602: else if (0 == strcmp(argv, "unfilled"))
1.1 kristaps 603: return(MDOC_Unfilled);
1.2 kristaps 604: else if (0 == strcmp(argv, "filled"))
1.1 kristaps 605: return(MDOC_Filled);
1.2 kristaps 606: else if (0 == strcmp(argv, "literal"))
1.1 kristaps 607: return(MDOC_Literal);
1.2 kristaps 608: else if (0 == strcmp(argv, "file"))
1.1 kristaps 609: return(MDOC_File);
1.2 kristaps 610: else if (0 == strcmp(argv, "offset"))
1.1 kristaps 611: return(MDOC_Offset);
1.2 kristaps 612: else if (0 == strcmp(argv, "compact"))
1.1 kristaps 613: return(MDOC_Compact);
614: break;
615:
616: case (MDOC_Bf):
1.2 kristaps 617: if (0 == strcmp(argv, "emphasis"))
1.1 kristaps 618: return(MDOC_Emphasis);
1.2 kristaps 619: else if (0 == strcmp(argv, "literal"))
1.1 kristaps 620: return(MDOC_Literal);
1.2 kristaps 621: else if (0 == strcmp(argv, "symbolic"))
1.1 kristaps 622: return(MDOC_Symbolic);
623: break;
624:
625: case (MDOC_Bk):
1.2 kristaps 626: if (0 == strcmp(argv, "words"))
1.1 kristaps 627: return(MDOC_Words);
628: break;
629:
630: case (MDOC_Bl):
1.2 kristaps 631: if (0 == strcmp(argv, "bullet"))
1.1 kristaps 632: return(MDOC_Bullet);
1.2 kristaps 633: else if (0 == strcmp(argv, "dash"))
1.1 kristaps 634: return(MDOC_Dash);
1.2 kristaps 635: else if (0 == strcmp(argv, "hyphen"))
1.1 kristaps 636: return(MDOC_Hyphen);
1.2 kristaps 637: else if (0 == strcmp(argv, "item"))
1.1 kristaps 638: return(MDOC_Item);
1.2 kristaps 639: else if (0 == strcmp(argv, "enum"))
1.1 kristaps 640: return(MDOC_Enum);
1.2 kristaps 641: else if (0 == strcmp(argv, "tag"))
1.1 kristaps 642: return(MDOC_Tag);
1.2 kristaps 643: else if (0 == strcmp(argv, "diag"))
1.1 kristaps 644: return(MDOC_Diag);
1.2 kristaps 645: else if (0 == strcmp(argv, "hang"))
1.1 kristaps 646: return(MDOC_Hang);
1.2 kristaps 647: else if (0 == strcmp(argv, "ohang"))
1.1 kristaps 648: return(MDOC_Ohang);
1.2 kristaps 649: else if (0 == strcmp(argv, "inset"))
1.1 kristaps 650: return(MDOC_Inset);
1.2 kristaps 651: else if (0 == strcmp(argv, "column"))
1.1 kristaps 652: return(MDOC_Column);
1.2 kristaps 653: else if (0 == strcmp(argv, "width"))
1.1 kristaps 654: return(MDOC_Width);
1.2 kristaps 655: else if (0 == strcmp(argv, "offset"))
1.1 kristaps 656: return(MDOC_Offset);
1.2 kristaps 657: else if (0 == strcmp(argv, "compact"))
1.1 kristaps 658: return(MDOC_Compact);
1.2 kristaps 659: else if (0 == strcmp(argv, "nested"))
1.1 kristaps 660: return(MDOC_Nested);
661: break;
662:
663: case (MDOC_Rv):
664: /* FALLTHROUGH */
665: case (MDOC_Ex):
1.2 kristaps 666: if (0 == strcmp(argv, "std"))
1.1 kristaps 667: return(MDOC_Std);
668: break;
669: default:
670: break;
671: }
672:
673: return(MDOC_ARG_MAX);
674: }
675:
676:
677: static int
1.11 kristaps 678: argv_multi(struct mdoc *m, int line,
1.1 kristaps 679: struct mdoc_argv *v, int *pos, char *buf)
680: {
1.8 kristaps 681: int c;
1.1 kristaps 682: char *p;
683:
684: for (v->sz = 0; ; v->sz++) {
685: if ('-' == buf[*pos])
686: break;
1.11 kristaps 687: c = args(m, line, pos, buf, ARGS_QUOTED, &p);
1.1 kristaps 688: if (ARGS_ERROR == c)
689: return(0);
690: else if (ARGS_EOLN == c)
691: break;
692:
1.2 kristaps 693: if (0 == v->sz % MULTI_STEP) {
694: v->value = realloc(v->value,
1.1 kristaps 695: (v->sz + MULTI_STEP) * sizeof(char *));
1.2 kristaps 696: if (NULL == v->value) {
1.11 kristaps 697: (void)mdoc_nerr(m, m->last, EMALLOC);
1.2 kristaps 698: return(ARGV_ERROR);
699: }
700: }
1.1 kristaps 701: if (NULL == (v->value[(int)v->sz] = strdup(p)))
1.11 kristaps 702: return(mdoc_nerr(m, m->last, EMALLOC));
1.1 kristaps 703: }
704:
1.7 kristaps 705: return(1);
1.1 kristaps 706: }
707:
708:
709: static int
1.11 kristaps 710: argv_opt_single(struct mdoc *m, int line,
1.1 kristaps 711: struct mdoc_argv *v, int *pos, char *buf)
712: {
713: int c;
714: char *p;
715:
716: if ('-' == buf[*pos])
717: return(1);
718:
1.11 kristaps 719: c = args(m, line, pos, buf, ARGS_QUOTED, &p);
1.1 kristaps 720: if (ARGS_ERROR == c)
721: return(0);
722: if (ARGS_EOLN == c)
723: return(1);
724:
725: v->sz = 1;
726: if (NULL == (v->value = calloc(1, sizeof(char *))))
1.11 kristaps 727: return(mdoc_nerr(m, m->last, EMALLOC));
1.1 kristaps 728: if (NULL == (v->value[0] = strdup(p)))
1.11 kristaps 729: return(mdoc_nerr(m, m->last, EMALLOC));
1.2 kristaps 730:
1.1 kristaps 731: return(1);
732: }
733:
734:
735: /*
736: * Parse a single, mandatory value from the stream.
737: */
738: static int
1.11 kristaps 739: argv_single(struct mdoc *m, int line,
1.1 kristaps 740: struct mdoc_argv *v, int *pos, char *buf)
741: {
742: int c, ppos;
743: char *p;
744:
745: ppos = *pos;
746:
1.11 kristaps 747: c = args(m, line, pos, buf, ARGS_QUOTED, &p);
1.1 kristaps 748: if (ARGS_ERROR == c)
749: return(0);
750: if (ARGS_EOLN == c)
1.11 kristaps 751: return(mdoc_perr(m, line, ppos, EARGVAL));
1.1 kristaps 752:
753: v->sz = 1;
754: if (NULL == (v->value = calloc(1, sizeof(char *))))
1.11 kristaps 755: return(mdoc_nerr(m, m->last, EMALLOC));
1.1 kristaps 756: if (NULL == (v->value[0] = strdup(p)))
1.11 kristaps 757: return(mdoc_nerr(m, m->last, EMALLOC));
1.2 kristaps 758:
1.1 kristaps 759: return(1);
760: }
761:
762:
763: /*
764: * Determine rules for parsing arguments. Arguments can either accept
765: * no parameters, an optional single parameter, one parameter, or
766: * multiple parameters.
767: */
768: static int
769: argv(struct mdoc *mdoc, int line,
770: struct mdoc_argv *v, int *pos, char *buf)
771: {
772:
773: v->sz = 0;
774: v->value = NULL;
775:
776: switch (mdoc_argvflags[v->arg]) {
777: case (ARGV_SINGLE):
778: return(argv_single(mdoc, line, v, pos, buf));
779: case (ARGV_MULTI):
780: return(argv_multi(mdoc, line, v, pos, buf));
781: case (ARGV_OPT_SINGLE):
782: return(argv_opt_single(mdoc, line, v, pos, buf));
783: default:
784: /* ARGV_NONE */
785: break;
786: }
787:
788: return(1);
789: }
CVSweb