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