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