]> git.cameronkatri.com Git - mandoc.git/blob - argv.c
Removed unnecessary test cases (most were for visual).
[mandoc.git] / argv.c
1 /* $Id: argv.c,v 1.17 2009/01/19 17:02:58 kristaps Exp $ */
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
29 /* FIXME: .It called with -column and quoted arguments. */
30
31 static int lookup(int, const char *);
32 static int parse(struct mdoc *, int,
33 struct mdoc_arg *, int *, char *);
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 *);
38 static int postparse(struct mdoc *, int,
39 const struct mdoc_arg *, int);
40
41
42 int
43 mdoc_args(struct mdoc *mdoc, int line, int *pos, char *buf, int fl, char **v)
44 {
45 int i;
46
47 if (0 == buf[*pos])
48 return(ARGS_EOLN);
49
50 if ('\"' == buf[*pos] && ! (fl & ARGS_QUOTED))
51 if ( ! mdoc_pwarn(mdoc, line, *pos, WARN_SYNTAX, "unexpected quoted parameter"))
52 return(ARGS_ERROR);
53
54 if ('-' == buf[*pos])
55 if ( ! mdoc_pwarn(mdoc, line, *pos, WARN_SYNTAX, "argument-like parameter"))
56 return(ARGS_ERROR);
57
58 if ((fl & ARGS_DELIM) && mdoc_iscdelim(buf[*pos])) {
59 /*
60 * If ARGS_DELIM, return ARGS_PUNCT if only space-separated
61 * punctuation remains.
62 */
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
79 /* Parse routine for non-quoted string. */
80
81 assert(*pos > 0);
82 if ('\"' != buf[*pos] || ! (ARGS_QUOTED & fl)) {
83 *v = &buf[*pos];
84
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 }
102 else {
103 while (buf[*pos]) {
104 if (isspace(buf[*pos]))
105 if ('\\' != buf[*pos - 1])
106 break;
107 (*pos)++;
108 }
109 }
110
111 if (0 == buf[*pos])
112 return(ARGS_WORD);
113
114 buf[(*pos)++] = 0;
115
116 if (0 == buf[*pos])
117 return(ARGS_WORD);
118
119 if ( ! (ARGS_TABSEP & fl))
120 while (buf[*pos] && isspace(buf[*pos]))
121 (*pos)++;
122
123 if (buf[*pos])
124 return(ARGS_WORD);
125
126 if ( ! mdoc_pwarn(mdoc, line, *pos, WARN_COMPAT, "whitespace at end-of-line"))
127 return(ARGS_ERROR);
128
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
135 * error. After, parse to the next word.
136 */
137
138 *v = &buf[++(*pos)];
139
140 while (buf[*pos] && '\"' != buf[*pos])
141 (*pos)++;
142
143 if (0 == buf[*pos]) {
144 (void)mdoc_perr(mdoc, line, *pos, "unterminated quoted parameter");
145 return(ARGS_ERROR);
146 }
147
148 buf[(*pos)++] = 0;
149 if (0 == buf[*pos])
150 return(ARGS_WORD);
151
152 while (buf[*pos] && isspace(buf[*pos]))
153 (*pos)++;
154
155 if (buf[*pos])
156 return(ARGS_WORD);
157
158 if ( ! mdoc_pwarn(mdoc, line, *pos, WARN_COMPAT, "whitespace at end-of-line"))
159 return(ARGS_ERROR);
160
161 return(ARGS_WORD);
162 }
163
164
165 static int
166 lookup(int tok, const char *argv)
167 {
168
169 switch (tok) {
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
177 case (MDOC_Bd):
178 if (xstrcmp(argv, "ragged"))
179 return(MDOC_Ragged);
180 else if (xstrcmp(argv, "unfilled"))
181 return(MDOC_Unfilled);
182 else if (xstrcmp(argv, "filled"))
183 return(MDOC_Filled);
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);
190 break;
191
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
201 case (MDOC_Bk):
202 if (xstrcmp(argv, "words"))
203 return(MDOC_Words);
204 break;
205
206 case (MDOC_Bl):
207 if (xstrcmp(argv, "bullet"))
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);
231 else if (xstrcmp(argv, "offset"))
232 return(MDOC_Offset);
233 else if (xstrcmp(argv, "compact"))
234 return(MDOC_Compact);
235 break;
236
237 case (MDOC_Rv):
238 /* FALLTHROUGH */
239 case (MDOC_Ex):
240 if (xstrcmp(argv, "std"))
241 return(MDOC_Std);
242 break;
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;
320
321 default:
322 break;
323 }
324
325 return(MDOC_ARG_MAX);
326 }
327
328
329 static int
330 postparse(struct mdoc *mdoc, int line, const struct mdoc_arg *v, int pos)
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;
347 return(mdoc_perr(mdoc, line, pos, "invalid offset value"));
348 default:
349 break;
350 }
351
352 return(1);
353 }
354
355
356 static int
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);
384 return(mdoc_perr(mdoc, line, ppos, 0 == v->sz ?
385 "argument requires a value" :
386 "too many values to argument"));
387 }
388
389
390 static int
391 parse_single(struct mdoc *mdoc, int line,
392 struct mdoc_arg *v, int *pos, char *buf)
393 {
394 int c, ppos;
395 char *p;
396
397 ppos = *pos;
398
399 c = mdoc_args(mdoc, line, pos, buf, ARGS_QUOTED, &p);
400 if (ARGS_ERROR == c)
401 return(0);
402 if (ARGS_EOLN == c)
403 return(mdoc_perr(mdoc, line, ppos, "argument requires a value"));
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
413 parse(struct mdoc *mdoc, int line,
414 struct mdoc_arg *v, int *pos, char *buf)
415 {
416
417 v->sz = 0;
418 v->value = NULL;
419
420 switch (v->arg) {
421 case(MDOC_Std):
422 /* FALLTHROUGH */
423 case(MDOC_Width):
424 /* FALLTHROUGH */
425 case(MDOC_Offset):
426 return(parse_single(mdoc, line, v, pos, buf));
427 case(MDOC_Column):
428 return(parse_multi(mdoc, line, v, pos, buf));
429 default:
430 break;
431 }
432
433 return(1);
434 }
435
436
437 int
438 mdoc_argv(struct mdoc *mdoc, int line, int tok,
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])
447 return(ARGV_EOLN);
448
449 assert( ! isspace(buf[*pos]));
450
451 if ('-' != buf[*pos])
452 return(ARGV_WORD);
453
454 i = *pos;
455 argv = &buf[++(*pos)];
456
457 v->line = line;
458 v->pos = *pos;
459
460 assert(*pos > 0);
461 while (buf[*pos]) {
462 if (isspace(buf[*pos]))
463 if ('\\' != buf[*pos - 1])
464 break;
465 (*pos)++;
466 }
467
468 if (buf[*pos])
469 buf[(*pos)++] = 0;
470
471 if (MDOC_ARG_MAX == (v->arg = lookup(tok, argv))) {
472 if ( ! mdoc_pwarn(mdoc, line, i, WARN_SYNTAX, "argument-like parameter"))
473 return(ARGV_ERROR);
474 return(ARGV_WORD);
475 }
476
477 while (buf[*pos] && isspace(buf[*pos]))
478 (*pos)++;
479
480 /* FIXME: whitespace if no value. */
481
482 ppos = *pos;
483 if ( ! parse(mdoc, line, v, pos, buf))
484 return(ARGV_ERROR);
485 if ( ! postparse(mdoc, line, v, ppos))
486 return(ARGV_ERROR);
487
488 return(ARGV_ARG);
489 }
490
491
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 }
506