Annotation of mandoc/argv.c, Revision 1.19
1.19 ! kristaps 1: /* $Id: argv.c,v 1.18 2009/01/20 12:51:28 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.15 kristaps 28: /* FIXME: .It called with -column and quoted arguments. */
1.18 kristaps 29: /* FIXME: if arguments are quoted, they should not be later parsed for
30: * macros. */
1.15 kristaps 31:
1.2 kristaps 32: static int lookup(int, const char *);
1.16 kristaps 33: static int parse(struct mdoc *, int,
1.2 kristaps 34: struct mdoc_arg *, int *, char *);
1.12 kristaps 35: static int parse_single(struct mdoc *, int,
36: struct mdoc_arg *, int *, char *);
37: static int parse_multi(struct mdoc *, int,
38: struct mdoc_arg *, int *, char *);
1.2 kristaps 39: static int postparse(struct mdoc *, int,
40: const struct mdoc_arg *, int);
1.1 kristaps 41:
42:
1.2 kristaps 43: int
1.9 kristaps 44: mdoc_args(struct mdoc *mdoc, int line, int *pos, char *buf, int fl, char **v)
1.1 kristaps 45: {
1.2 kristaps 46: int i;
1.1 kristaps 47:
48: if (0 == buf[*pos])
1.2 kristaps 49: return(ARGS_EOLN);
50:
51: if ('\"' == buf[*pos] && ! (fl & ARGS_QUOTED))
1.14 kristaps 52: if ( ! mdoc_pwarn(mdoc, line, *pos, WARN_SYNTAX, "unexpected quoted parameter"))
1.2 kristaps 53: return(ARGS_ERROR);
54:
55: if ('-' == buf[*pos])
1.14 kristaps 56: if ( ! mdoc_pwarn(mdoc, line, *pos, WARN_SYNTAX, "argument-like parameter"))
1.2 kristaps 57: return(ARGS_ERROR);
58:
59: if ((fl & ARGS_DELIM) && mdoc_iscdelim(buf[*pos])) {
1.12 kristaps 60: /*
61: * If ARGS_DELIM, return ARGS_PUNCT if only space-separated
62: * punctuation remains.
63: */
1.2 kristaps 64: for (i = *pos; buf[i]; ) {
65: if ( ! mdoc_iscdelim(buf[i]))
66: break;
67: i++;
68: if (0 == buf[i] || ! isspace(buf[i]))
69: break;
70: i++;
71: while (buf[i] && isspace(buf[i]))
72: i++;
73: }
74: if (0 == buf[i]) {
75: *v = &buf[*pos];
76: return(ARGS_PUNCT);
77: }
78: }
79:
1.12 kristaps 80: /* Parse routine for non-quoted string. */
1.1 kristaps 81:
1.17 kristaps 82: assert(*pos > 0);
83: if ('\"' != buf[*pos] || ! (ARGS_QUOTED & fl)) {
1.1 kristaps 84: *v = &buf[*pos];
85:
1.12 kristaps 86: /* FIXME: UGLY tab-sep processing. */
87:
88: if (ARGS_TABSEP & fl)
89: while (buf[*pos]) {
90: if ('\t' == buf[*pos])
91: break;
92: if ('T' == buf[*pos]) {
93: (*pos)++;
94: if (0 == buf[*pos])
95: break;
96: if ('a' == buf[*pos]) {
97: buf[*pos - 1] = 0;
98: break;
99: }
100: }
101: (*pos)++;
102: }
1.17 kristaps 103: else {
104: while (buf[*pos]) {
105: if (isspace(buf[*pos]))
106: if ('\\' != buf[*pos - 1])
107: break;
1.12 kristaps 108: (*pos)++;
1.17 kristaps 109: }
110: }
1.1 kristaps 111:
112: if (0 == buf[*pos])
1.2 kristaps 113: return(ARGS_WORD);
1.1 kristaps 114:
115: buf[(*pos)++] = 0;
1.12 kristaps 116:
1.1 kristaps 117: if (0 == buf[*pos])
1.2 kristaps 118: return(ARGS_WORD);
1.1 kristaps 119:
1.12 kristaps 120: if ( ! (ARGS_TABSEP & fl))
121: while (buf[*pos] && isspace(buf[*pos]))
122: (*pos)++;
1.1 kristaps 123:
124: if (buf[*pos])
1.2 kristaps 125: return(ARGS_WORD);
1.1 kristaps 126:
1.14 kristaps 127: if ( ! mdoc_pwarn(mdoc, line, *pos, WARN_COMPAT, "whitespace at end-of-line"))
1.2 kristaps 128: return(ARGS_ERROR);
1.1 kristaps 129:
1.2 kristaps 130: return(ARGS_WORD);
131: }
132:
133: /*
134: * If we're a quoted string (and quoted strings are allowed),
135: * then parse ahead to the next quote. If none's found, it's an
1.4 kristaps 136: * error. After, parse to the next word.
1.2 kristaps 137: */
1.1 kristaps 138:
139: *v = &buf[++(*pos)];
140:
141: while (buf[*pos] && '\"' != buf[*pos])
142: (*pos)++;
143:
144: if (0 == buf[*pos]) {
1.14 kristaps 145: (void)mdoc_perr(mdoc, line, *pos, "unterminated quoted parameter");
1.2 kristaps 146: return(ARGS_ERROR);
1.1 kristaps 147: }
148:
149: buf[(*pos)++] = 0;
150: if (0 == buf[*pos])
1.19 ! kristaps 151: return(ARGS_QWORD);
1.1 kristaps 152:
153: while (buf[*pos] && isspace(buf[*pos]))
154: (*pos)++;
155:
156: if (buf[*pos])
1.19 ! kristaps 157: return(ARGS_QWORD);
1.1 kristaps 158:
1.14 kristaps 159: if ( ! mdoc_pwarn(mdoc, line, *pos, WARN_COMPAT, "whitespace at end-of-line"))
1.2 kristaps 160: return(ARGS_ERROR);
161:
1.19 ! kristaps 162: return(ARGS_QWORD);
1.1 kristaps 163: }
164:
165:
1.2 kristaps 166: static int
167: lookup(int tok, const char *argv)
1.1 kristaps 168: {
169:
170: switch (tok) {
1.6 kristaps 171: case (MDOC_An):
172: if (xstrcmp(argv, "split"))
173: return(MDOC_Split);
174: else if (xstrcmp(argv, "nosplit"))
175: return(MDOC_Nosplit);
176: break;
177:
1.2 kristaps 178: case (MDOC_Bd):
1.1 kristaps 179: if (xstrcmp(argv, "ragged"))
180: return(MDOC_Ragged);
181: else if (xstrcmp(argv, "unfilled"))
182: return(MDOC_Unfilled);
1.13 kristaps 183: else if (xstrcmp(argv, "filled"))
184: return(MDOC_Filled);
1.1 kristaps 185: else if (xstrcmp(argv, "literal"))
186: return(MDOC_Literal);
187: else if (xstrcmp(argv, "file"))
188: return(MDOC_File);
189: else if (xstrcmp(argv, "offset"))
190: return(MDOC_Offset);
1.2 kristaps 191: break;
192:
1.8 kristaps 193: case (MDOC_Bf):
194: if (xstrcmp(argv, "emphasis"))
195: return(MDOC_Emphasis);
196: else if (xstrcmp(argv, "literal"))
197: return(MDOC_Literal);
198: else if (xstrcmp(argv, "symbolic"))
199: return(MDOC_Symbolic);
200: break;
201:
1.7 kristaps 202: case (MDOC_Bk):
203: if (xstrcmp(argv, "words"))
204: return(MDOC_Words);
205: break;
206:
1.2 kristaps 207: case (MDOC_Bl):
208: if (xstrcmp(argv, "bullet"))
1.1 kristaps 209: return(MDOC_Bullet);
210: else if (xstrcmp(argv, "dash"))
211: return(MDOC_Dash);
212: else if (xstrcmp(argv, "hyphen"))
213: return(MDOC_Hyphen);
214: else if (xstrcmp(argv, "item"))
215: return(MDOC_Item);
216: else if (xstrcmp(argv, "enum"))
217: return(MDOC_Enum);
218: else if (xstrcmp(argv, "tag"))
219: return(MDOC_Tag);
220: else if (xstrcmp(argv, "diag"))
221: return(MDOC_Diag);
222: else if (xstrcmp(argv, "hang"))
223: return(MDOC_Hang);
224: else if (xstrcmp(argv, "ohang"))
225: return(MDOC_Ohang);
226: else if (xstrcmp(argv, "inset"))
227: return(MDOC_Inset);
228: else if (xstrcmp(argv, "column"))
229: return(MDOC_Column);
230: else if (xstrcmp(argv, "width"))
231: return(MDOC_Width);
1.2 kristaps 232: else if (xstrcmp(argv, "offset"))
233: return(MDOC_Offset);
1.1 kristaps 234: else if (xstrcmp(argv, "compact"))
235: return(MDOC_Compact);
1.2 kristaps 236: break;
1.3 kristaps 237:
238: case (MDOC_Rv):
239: /* FALLTHROUGH */
240: case (MDOC_Ex):
241: if (xstrcmp(argv, "std"))
242: return(MDOC_Std);
243: break;
1.5 kristaps 244:
245: case (MDOC_St):
246: if (xstrcmp(argv, "p1003.1-88"))
247: return(MDOC_p1003_1_88);
248: else if (xstrcmp(argv, "p1003.1-90"))
249: return(MDOC_p1003_1_90);
250: else if (xstrcmp(argv, "p1003.1-96"))
251: return(MDOC_p1003_1_96);
252: else if (xstrcmp(argv, "p1003.1-2001"))
253: return(MDOC_p1003_1_2001);
254: else if (xstrcmp(argv, "p1003.1-2004"))
255: return(MDOC_p1003_1_2004);
256: else if (xstrcmp(argv, "p1003.1"))
257: return(MDOC_p1003_1);
258: else if (xstrcmp(argv, "p1003.1b"))
259: return(MDOC_p1003_1b);
260: else if (xstrcmp(argv, "p1003.1b-93"))
261: return(MDOC_p1003_1b_93);
262: else if (xstrcmp(argv, "p1003.1c-95"))
263: return(MDOC_p1003_1c_95);
264: else if (xstrcmp(argv, "p1003.1g-2000"))
265: return(MDOC_p1003_1g_2000);
266: else if (xstrcmp(argv, "p1003.2-92"))
267: return(MDOC_p1003_2_92);
268: else if (xstrcmp(argv, "p1003.2-95"))
269: return(MDOC_p1387_2_95);
270: else if (xstrcmp(argv, "p1003.2"))
271: return(MDOC_p1003_2);
272: else if (xstrcmp(argv, "p1387.2-95"))
273: return(MDOC_p1387_2);
274: else if (xstrcmp(argv, "isoC-90"))
275: return(MDOC_isoC_90);
276: else if (xstrcmp(argv, "isoC-amd1"))
277: return(MDOC_isoC_amd1);
278: else if (xstrcmp(argv, "isoC-tcor1"))
279: return(MDOC_isoC_tcor1);
280: else if (xstrcmp(argv, "isoC-tcor2"))
281: return(MDOC_isoC_tcor2);
282: else if (xstrcmp(argv, "isoC-99"))
283: return(MDOC_isoC_99);
284: else if (xstrcmp(argv, "ansiC"))
285: return(MDOC_ansiC);
286: else if (xstrcmp(argv, "ansiC-89"))
287: return(MDOC_ansiC_89);
288: else if (xstrcmp(argv, "ansiC-99"))
289: return(MDOC_ansiC_99);
290: else if (xstrcmp(argv, "ieee754"))
291: return(MDOC_ieee754);
292: else if (xstrcmp(argv, "iso8802-3"))
293: return(MDOC_iso8802_3);
294: else if (xstrcmp(argv, "xpg3"))
295: return(MDOC_xpg3);
296: else if (xstrcmp(argv, "xpg4"))
297: return(MDOC_xpg4);
298: else if (xstrcmp(argv, "xpg4.2"))
299: return(MDOC_xpg4_2);
300: else if (xstrcmp(argv, "xpg4.3"))
301: return(MDOC_xpg4_3);
302: else if (xstrcmp(argv, "xbd5"))
303: return(MDOC_xbd5);
304: else if (xstrcmp(argv, "xcu5"))
305: return(MDOC_xcu5);
306: else if (xstrcmp(argv, "xsh5"))
307: return(MDOC_xsh5);
308: else if (xstrcmp(argv, "xns5"))
309: return(MDOC_xns5);
310: else if (xstrcmp(argv, "xns5.2d2.0"))
311: return(MDOC_xns5_2d2_0);
312: else if (xstrcmp(argv, "xcurses4.2"))
313: return(MDOC_xcurses4_2);
314: else if (xstrcmp(argv, "susv2"))
315: return(MDOC_susv2);
316: else if (xstrcmp(argv, "susv3"))
317: return(MDOC_susv3);
318: else if (xstrcmp(argv, "svid4"))
319: return(MDOC_svid4);
320: break;
1.1 kristaps 321:
322: default:
1.8 kristaps 323: break;
1.1 kristaps 324: }
325:
326: return(MDOC_ARG_MAX);
327: }
328:
329:
1.2 kristaps 330: static int
1.9 kristaps 331: postparse(struct mdoc *mdoc, int line, const struct mdoc_arg *v, int pos)
1.2 kristaps 332: {
333:
334: switch (v->arg) {
335: case (MDOC_Offset):
336: assert(v->value);
337: assert(v->value[0]);
338: if (xstrcmp(v->value[0], "left"))
339: break;
340: if (xstrcmp(v->value[0], "right"))
341: break;
342: if (xstrcmp(v->value[0], "center"))
343: break;
344: if (xstrcmp(v->value[0], "indent"))
345: break;
346: if (xstrcmp(v->value[0], "indent-two"))
347: break;
1.14 kristaps 348: return(mdoc_perr(mdoc, line, pos, "invalid offset value"));
1.2 kristaps 349: default:
350: break;
351: }
352:
353: return(1);
354: }
355:
356:
357: static int
1.12 kristaps 358: parse_multi(struct mdoc *mdoc, int line,
359: struct mdoc_arg *v, int *pos, char *buf)
360: {
361: int c, ppos;
362: char *p;
363:
364: v->sz = 0;
365: v->value = xcalloc(MDOC_LINEARG_MAX, sizeof(char *));
366:
367: ppos = *pos;
368:
369: for (v->sz = 0; v->sz < MDOC_LINEARG_MAX; v->sz++) {
370: if ('-' == buf[*pos])
371: break;
372: c = mdoc_args(mdoc, line, pos, buf, ARGS_QUOTED, &p);
373: if (ARGS_ERROR == c) {
374: free(v->value);
375: return(0);
376: } else if (ARGS_EOLN == c)
377: break;
378: v->value[v->sz] = p;
379: }
380:
381: if (0 < v->sz && v->sz < MDOC_LINEARG_MAX)
382: return(1);
383:
384: free(v->value);
1.14 kristaps 385: return(mdoc_perr(mdoc, line, ppos, 0 == v->sz ?
386: "argument requires a value" :
387: "too many values to argument"));
1.12 kristaps 388: }
389:
390:
391: static int
392: parse_single(struct mdoc *mdoc, int line,
1.1 kristaps 393: struct mdoc_arg *v, int *pos, char *buf)
394: {
1.12 kristaps 395: int c, ppos;
1.1 kristaps 396: char *p;
397:
398: ppos = *pos;
399:
1.12 kristaps 400: c = mdoc_args(mdoc, line, pos, buf, ARGS_QUOTED, &p);
401: if (ARGS_ERROR == c)
402: return(0);
403: if (ARGS_EOLN == c)
1.14 kristaps 404: return(mdoc_perr(mdoc, line, ppos, "argument requires a value"));
1.12 kristaps 405:
406: v->sz = 1;
407: v->value = xcalloc(1, sizeof(char *));
408: v->value[0] = p;
409: return(1);
410: }
411:
412:
413: static int
1.16 kristaps 414: parse(struct mdoc *mdoc, int line,
1.12 kristaps 415: struct mdoc_arg *v, int *pos, char *buf)
416: {
417:
418: v->sz = 0;
419: v->value = NULL;
420:
1.2 kristaps 421: switch (v->arg) {
1.3 kristaps 422: case(MDOC_Std):
423: /* FALLTHROUGH */
1.1 kristaps 424: case(MDOC_Width):
425: /* FALLTHROUGH */
426: case(MDOC_Offset):
1.12 kristaps 427: return(parse_single(mdoc, line, v, pos, buf));
1.1 kristaps 428: case(MDOC_Column):
1.12 kristaps 429: return(parse_multi(mdoc, line, v, pos, buf));
1.1 kristaps 430: default:
1.6 kristaps 431: break;
1.1 kristaps 432: }
433:
434: return(1);
435: }
436:
437:
1.2 kristaps 438: int
1.9 kristaps 439: mdoc_argv(struct mdoc *mdoc, int line, int tok,
1.2 kristaps 440: struct mdoc_arg *v, int *pos, char *buf)
441: {
442: int i, ppos;
443: char *argv;
444:
445: (void)memset(v, 0, sizeof(struct mdoc_arg));
446:
447: if (0 == buf[*pos])
1.5 kristaps 448: return(ARGV_EOLN);
1.2 kristaps 449:
450: assert( ! isspace(buf[*pos]));
451:
1.5 kristaps 452: if ('-' != buf[*pos])
453: return(ARGV_WORD);
1.2 kristaps 454:
455: i = *pos;
456: argv = &buf[++(*pos)];
457:
1.11 kristaps 458: v->line = line;
459: v->pos = *pos;
460:
1.17 kristaps 461: assert(*pos > 0);
462: while (buf[*pos]) {
463: if (isspace(buf[*pos]))
464: if ('\\' != buf[*pos - 1])
465: break;
1.2 kristaps 466: (*pos)++;
1.17 kristaps 467: }
1.2 kristaps 468:
469: if (buf[*pos])
470: buf[(*pos)++] = 0;
471:
472: if (MDOC_ARG_MAX == (v->arg = lookup(tok, argv))) {
1.14 kristaps 473: if ( ! mdoc_pwarn(mdoc, line, i, WARN_SYNTAX, "argument-like parameter"))
474: return(ARGV_ERROR);
1.10 kristaps 475: return(ARGV_WORD);
1.2 kristaps 476: }
477:
478: while (buf[*pos] && isspace(buf[*pos]))
479: (*pos)++;
480:
481: /* FIXME: whitespace if no value. */
482:
483: ppos = *pos;
1.16 kristaps 484: if ( ! parse(mdoc, line, v, pos, buf))
1.5 kristaps 485: return(ARGV_ERROR);
1.9 kristaps 486: if ( ! postparse(mdoc, line, v, ppos))
1.5 kristaps 487: return(ARGV_ERROR);
1.2 kristaps 488:
1.5 kristaps 489: return(ARGV_ARG);
1.2 kristaps 490: }
491:
492:
1.1 kristaps 493: void
494: mdoc_argv_free(int sz, struct mdoc_arg *arg)
495: {
496: int i;
497:
498: for (i = 0; i < sz; i++) {
499: if (0 == arg[i].sz) {
500: assert(NULL == arg[i].value);
501: continue;
502: }
503: assert(arg[i].value);
504: free(arg[i].value);
505: }
506: }
1.2 kristaps 507:
CVSweb