Annotation of mandoc/argv.c, Revision 1.3
1.3 ! kristaps 1: /* $Id: argv.c,v 1.2 2008/12/28 00:34:20 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.2 kristaps 29: static int lookup(int, const char *);
30: static int parse(struct mdoc *, int,
31: struct mdoc_arg *, int *, char *);
32: static int postparse(struct mdoc *, int,
33: const struct mdoc_arg *, int);
1.1 kristaps 34:
35:
1.2 kristaps 36: int
37: mdoc_args(struct mdoc *mdoc, int tok, int *pos, char *buf, int fl, char **v)
1.1 kristaps 38: {
1.2 kristaps 39: int i;
1.1 kristaps 40:
41: if (0 == buf[*pos])
1.2 kristaps 42: return(ARGS_EOLN);
43:
44: if ('\"' == buf[*pos] && ! (fl & ARGS_QUOTED))
45: if ( ! mdoc_warn(mdoc, tok, *pos, WARN_SYNTAX_QUOTED))
46: return(ARGS_ERROR);
47:
48: if ('-' == buf[*pos])
49: if ( ! mdoc_warn(mdoc, tok, *pos, WARN_SYNTAX_ARGLIKE))
50: return(ARGS_ERROR);
51:
52: if ((fl & ARGS_DELIM) && mdoc_iscdelim(buf[*pos])) {
53: for (i = *pos; buf[i]; ) {
54: if ( ! mdoc_iscdelim(buf[i]))
55: break;
56: i++;
57: if (0 == buf[i] || ! isspace(buf[i]))
58: break;
59: i++;
60: while (buf[i] && isspace(buf[i]))
61: i++;
62: }
63: if (0 == buf[i]) {
64: *v = &buf[*pos];
65: return(ARGS_PUNCT);
66: }
67: }
68:
69: /*
70: * Parse routine for non-quoted string.
71: */
1.1 kristaps 72:
73: if ('\"' != buf[*pos]) {
74: *v = &buf[*pos];
75:
76: while (buf[*pos] && ! isspace(buf[*pos]))
77: (*pos)++;
78:
79: if (0 == buf[*pos])
1.2 kristaps 80: return(ARGS_WORD);
1.1 kristaps 81:
82: buf[(*pos)++] = 0;
83: if (0 == buf[*pos])
1.2 kristaps 84: return(ARGS_WORD);
1.1 kristaps 85:
86: while (buf[*pos] && isspace(buf[*pos]))
87: (*pos)++;
88:
89: if (buf[*pos])
1.2 kristaps 90: return(ARGS_WORD);
1.1 kristaps 91:
92: if ( ! mdoc_warn(mdoc, tok, *pos, WARN_SYNTAX_WS_EOLN))
1.2 kristaps 93: return(ARGS_ERROR);
1.1 kristaps 94:
1.2 kristaps 95: return(ARGS_WORD);
96: }
97:
98: /*
99: * If we're a quoted string (and quoted strings are allowed),
100: * then parse ahead to the next quote. If none's found, it's an
101: * error. After, parse to the next word. We're not allowed to
102: * also be DELIM requests (for now).
103: */
104: assert( ! (fl & ARGS_DELIM));
1.1 kristaps 105:
106: *v = &buf[++(*pos)];
107:
108: while (buf[*pos] && '\"' != buf[*pos])
109: (*pos)++;
110:
111: if (0 == buf[*pos]) {
112: (void)mdoc_err(mdoc, tok, *pos, ERR_SYNTAX_UNQUOTE);
1.2 kristaps 113: return(ARGS_ERROR);
1.1 kristaps 114: }
115:
116: buf[(*pos)++] = 0;
117: if (0 == buf[*pos])
1.2 kristaps 118: return(ARGS_WORD);
1.1 kristaps 119:
120: while (buf[*pos] && isspace(buf[*pos]))
121: (*pos)++;
122:
123: if (buf[*pos])
1.2 kristaps 124: return(ARGS_WORD);
1.1 kristaps 125:
126: if ( ! mdoc_warn(mdoc, tok, *pos, WARN_SYNTAX_WS_EOLN))
1.2 kristaps 127: return(ARGS_ERROR);
128:
129: return(ARGS_WORD);
1.1 kristaps 130: }
131:
132:
1.2 kristaps 133: static int
134: lookup(int tok, const char *argv)
1.1 kristaps 135: {
136:
137: switch (tok) {
1.2 kristaps 138: case (MDOC_Bd):
1.1 kristaps 139: if (xstrcmp(argv, "ragged"))
140: return(MDOC_Ragged);
141: else if (xstrcmp(argv, "unfilled"))
142: return(MDOC_Unfilled);
143: else if (xstrcmp(argv, "literal"))
144: return(MDOC_Literal);
145: else if (xstrcmp(argv, "file"))
146: return(MDOC_File);
147: else if (xstrcmp(argv, "offset"))
148: return(MDOC_Offset);
1.2 kristaps 149: break;
150:
151: case (MDOC_Bl):
152: if (xstrcmp(argv, "bullet"))
1.1 kristaps 153: return(MDOC_Bullet);
154: else if (xstrcmp(argv, "dash"))
155: return(MDOC_Dash);
156: else if (xstrcmp(argv, "hyphen"))
157: return(MDOC_Hyphen);
158: else if (xstrcmp(argv, "item"))
159: return(MDOC_Item);
160: else if (xstrcmp(argv, "enum"))
161: return(MDOC_Enum);
162: else if (xstrcmp(argv, "tag"))
163: return(MDOC_Tag);
164: else if (xstrcmp(argv, "diag"))
165: return(MDOC_Diag);
166: else if (xstrcmp(argv, "hang"))
167: return(MDOC_Hang);
168: else if (xstrcmp(argv, "ohang"))
169: return(MDOC_Ohang);
170: else if (xstrcmp(argv, "inset"))
171: return(MDOC_Inset);
172: else if (xstrcmp(argv, "column"))
173: return(MDOC_Column);
174: else if (xstrcmp(argv, "width"))
175: return(MDOC_Width);
1.2 kristaps 176: else if (xstrcmp(argv, "offset"))
177: return(MDOC_Offset);
1.1 kristaps 178: else if (xstrcmp(argv, "compact"))
179: return(MDOC_Compact);
1.2 kristaps 180: break;
1.3 ! kristaps 181:
! 182: case (MDOC_Rv):
! 183: /* FALLTHROUGH */
! 184: case (MDOC_Ex):
! 185: if (xstrcmp(argv, "std"))
! 186: return(MDOC_Std);
! 187: break;
1.1 kristaps 188:
189: default:
190: abort();
191: /* NOTREACHED */
192: }
193:
194: return(MDOC_ARG_MAX);
195: }
196:
197:
1.2 kristaps 198: static int
199: postparse(struct mdoc *mdoc, int tok, const struct mdoc_arg *v, int pos)
200: {
201:
202: switch (v->arg) {
203: case (MDOC_Offset):
204: assert(v->value);
205: assert(v->value[0]);
206: if (xstrcmp(v->value[0], "left"))
207: break;
208: if (xstrcmp(v->value[0], "right"))
209: break;
210: if (xstrcmp(v->value[0], "center"))
211: break;
212: if (xstrcmp(v->value[0], "indent"))
213: break;
214: if (xstrcmp(v->value[0], "indent-two"))
215: break;
216: return(mdoc_err(mdoc, tok, pos, ERR_SYNTAX_ARGBAD));
217: default:
218: break;
219: }
220:
221: return(1);
222: }
223:
224:
225: static int
226: parse(struct mdoc *mdoc, int tok,
1.1 kristaps 227: struct mdoc_arg *v, int *pos, char *buf)
228: {
229: char *p;
230: int c, ppos, i;
231:
232: ppos = *pos;
233:
1.2 kristaps 234: switch (v->arg) {
1.1 kristaps 235: case(MDOC_Compact):
236: /* FALLTHROUGH */
237: case(MDOC_Ragged):
238: /* FALLTHROUGH */
239: case(MDOC_Unfilled):
240: /* FALLTHROUGH */
241: case(MDOC_Literal):
242: /* FALLTHROUGH */
243: case(MDOC_File):
244: /* FALLTHROUGH */
245: case(MDOC_Bullet):
246: /* FALLTHROUGH */
247: case(MDOC_Dash):
248: /* FALLTHROUGH */
249: case(MDOC_Hyphen):
250: /* FALLTHROUGH */
251: case(MDOC_Item):
252: /* FALLTHROUGH */
253: case(MDOC_Enum):
254: /* FALLTHROUGH */
255: case(MDOC_Tag):
256: /* FALLTHROUGH */
257: case(MDOC_Diag):
258: /* FALLTHROUGH */
259: case(MDOC_Hang):
260: /* FALLTHROUGH */
261: case(MDOC_Ohang):
262: /* FALLTHROUGH */
263: case(MDOC_Inset):
264: v->sz = 0;
265: v->value = NULL;
266: break;
267:
1.3 ! kristaps 268: case(MDOC_Std):
! 269: /* FALLTHROUGH */
1.1 kristaps 270: case(MDOC_Width):
271: /* FALLTHROUGH */
272: case(MDOC_Offset):
273: /*
274: * This has a single value for an argument.
275: */
1.2 kristaps 276: c = mdoc_args(mdoc, tok, pos, buf, ARGS_QUOTED, &p);
277: if (ARGS_ERROR == c)
1.1 kristaps 278: return(0);
1.2 kristaps 279: else if (ARGS_EOLN == c)
1.1 kristaps 280: return(mdoc_err(mdoc, tok, ppos, ERR_SYNTAX_ARGVAL));
281:
282: v->sz = 1;
283: v->value = xcalloc(1, sizeof(char *));
284: v->value[0] = p;
285: break;
286:
287: case(MDOC_Column):
288: /*
289: * This has several value for a single argument. We
290: * pre-allocate a pointer array and don't let it exceed
291: * this size.
292: */
293: v->sz = 0;
294: v->value = xcalloc(MDOC_LINEARG_MAX, sizeof(char *));
295: for (i = 0; i < MDOC_LINEARG_MAX; i++) {
1.2 kristaps 296: c = mdoc_args(mdoc, tok, pos, buf, ARGS_QUOTED, &p);
297: if (ARGS_ERROR == c) {
1.1 kristaps 298: free(v->value);
299: return(0);
1.2 kristaps 300: } else if (ARGS_EOLN == c)
1.1 kristaps 301: break;
302: v->value[i] = p;
303: }
304: if (0 == i) {
305: free(v->value);
306: return(mdoc_err(mdoc, tok, ppos, ERR_SYNTAX_ARGVAL));
307: } else if (MDOC_LINEARG_MAX == i)
308: return(mdoc_err(mdoc, tok, ppos, ERR_SYNTAX_ARGMANY));
309:
310: v->sz = i;
311: break;
312: default:
313: abort();
314: /* NOTREACHED */
315: }
316:
317: return(1);
318: }
319:
320:
1.2 kristaps 321: int
322: mdoc_argv(struct mdoc *mdoc, int tok,
323: struct mdoc_arg *v, int *pos, char *buf)
324: {
325: int i, ppos;
326: char *argv;
327:
328: (void)memset(v, 0, sizeof(struct mdoc_arg));
329:
330: if (0 == buf[*pos])
331: return(0);
332:
333: assert( ! isspace(buf[*pos]));
334:
335: if ('-' != buf[*pos]) {
336: (void)mdoc_err(mdoc, tok, *pos, ERR_SYNTAX_ARGFORM);
337: return(-1);
338: }
339:
340: i = *pos;
341: argv = &buf[++(*pos)];
342:
343: while (buf[*pos] && ! isspace(buf[*pos]))
344: (*pos)++;
345:
346: if (buf[*pos])
347: buf[(*pos)++] = 0;
348:
349: if (MDOC_ARG_MAX == (v->arg = lookup(tok, argv))) {
350: (void)mdoc_err(mdoc, tok, i, ERR_SYNTAX_ARG);
351: return(-1);
352: }
353:
354: while (buf[*pos] && isspace(buf[*pos]))
355: (*pos)++;
356:
357: /* FIXME: whitespace if no value. */
358:
359: ppos = *pos;
360: if ( ! parse(mdoc, tok, v, pos, buf))
361: return(-1);
362: if ( ! postparse(mdoc, tok, v, ppos))
363: return(-1);
364:
365: return(1);
366: }
367:
368:
1.1 kristaps 369: void
370: mdoc_argv_free(int sz, struct mdoc_arg *arg)
371: {
372: int i;
373:
374: for (i = 0; i < sz; i++) {
375: if (0 == arg[i].sz) {
376: assert(NULL == arg[i].value);
377: continue;
378: }
379: assert(arg[i].value);
380: free(arg[i].value);
381: }
382: }
1.2 kristaps 383:
CVSweb