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