]> git.cameronkatri.com Git - mandoc.git/blob - argv.c
*** empty log message ***
[mandoc.git] / argv.c
1 /* $Id: argv.c,v 1.2 2008/12/28 00:34:20 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 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);
34
35
36 int
37 mdoc_args(struct mdoc *mdoc, int tok, int *pos, char *buf, int fl, char **v)
38 {
39 int i;
40
41 if (0 == buf[*pos])
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 */
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])
80 return(ARGS_WORD);
81
82 buf[(*pos)++] = 0;
83 if (0 == buf[*pos])
84 return(ARGS_WORD);
85
86 while (buf[*pos] && isspace(buf[*pos]))
87 (*pos)++;
88
89 if (buf[*pos])
90 return(ARGS_WORD);
91
92 if ( ! mdoc_warn(mdoc, tok, *pos, WARN_SYNTAX_WS_EOLN))
93 return(ARGS_ERROR);
94
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));
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);
113 return(ARGS_ERROR);
114 }
115
116 buf[(*pos)++] = 0;
117 if (0 == buf[*pos])
118 return(ARGS_WORD);
119
120 while (buf[*pos] && isspace(buf[*pos]))
121 (*pos)++;
122
123 if (buf[*pos])
124 return(ARGS_WORD);
125
126 if ( ! mdoc_warn(mdoc, tok, *pos, WARN_SYNTAX_WS_EOLN))
127 return(ARGS_ERROR);
128
129 return(ARGS_WORD);
130 }
131
132
133 static int
134 lookup(int tok, const char *argv)
135 {
136
137 switch (tok) {
138 case (MDOC_Bd):
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);
149 break;
150
151 case (MDOC_Bl):
152 if (xstrcmp(argv, "bullet"))
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);
176 else if (xstrcmp(argv, "offset"))
177 return(MDOC_Offset);
178 else if (xstrcmp(argv, "compact"))
179 return(MDOC_Compact);
180 break;
181
182 default:
183 abort();
184 /* NOTREACHED */
185 }
186
187 return(MDOC_ARG_MAX);
188 }
189
190
191 static int
192 postparse(struct mdoc *mdoc, int tok, const struct mdoc_arg *v, int pos)
193 {
194
195 switch (v->arg) {
196 case (MDOC_Offset):
197 assert(v->value);
198 assert(v->value[0]);
199 if (xstrcmp(v->value[0], "left"))
200 break;
201 if (xstrcmp(v->value[0], "right"))
202 break;
203 if (xstrcmp(v->value[0], "center"))
204 break;
205 if (xstrcmp(v->value[0], "indent"))
206 break;
207 if (xstrcmp(v->value[0], "indent-two"))
208 break;
209 return(mdoc_err(mdoc, tok, pos, ERR_SYNTAX_ARGBAD));
210 default:
211 break;
212 }
213
214 return(1);
215 }
216
217
218 static int
219 parse(struct mdoc *mdoc, int tok,
220 struct mdoc_arg *v, int *pos, char *buf)
221 {
222 char *p;
223 int c, ppos, i;
224
225 ppos = *pos;
226
227 switch (v->arg) {
228 case(MDOC_Compact):
229 /* FALLTHROUGH */
230 case(MDOC_Ragged):
231 /* FALLTHROUGH */
232 case(MDOC_Unfilled):
233 /* FALLTHROUGH */
234 case(MDOC_Literal):
235 /* FALLTHROUGH */
236 case(MDOC_File):
237 /* FALLTHROUGH */
238 case(MDOC_Bullet):
239 /* FALLTHROUGH */
240 case(MDOC_Dash):
241 /* FALLTHROUGH */
242 case(MDOC_Hyphen):
243 /* FALLTHROUGH */
244 case(MDOC_Item):
245 /* FALLTHROUGH */
246 case(MDOC_Enum):
247 /* FALLTHROUGH */
248 case(MDOC_Tag):
249 /* FALLTHROUGH */
250 case(MDOC_Diag):
251 /* FALLTHROUGH */
252 case(MDOC_Hang):
253 /* FALLTHROUGH */
254 case(MDOC_Ohang):
255 /* FALLTHROUGH */
256 case(MDOC_Inset):
257 v->sz = 0;
258 v->value = NULL;
259 break;
260
261 case(MDOC_Width):
262 /* FALLTHROUGH */
263 case(MDOC_Offset):
264 /*
265 * This has a single value for an argument.
266 */
267 c = mdoc_args(mdoc, tok, pos, buf, ARGS_QUOTED, &p);
268 if (ARGS_ERROR == c)
269 return(0);
270 else if (ARGS_EOLN == c)
271 return(mdoc_err(mdoc, tok, ppos, ERR_SYNTAX_ARGVAL));
272
273 v->sz = 1;
274 v->value = xcalloc(1, sizeof(char *));
275 v->value[0] = p;
276 break;
277
278 case(MDOC_Column):
279 /*
280 * This has several value for a single argument. We
281 * pre-allocate a pointer array and don't let it exceed
282 * this size.
283 */
284 v->sz = 0;
285 v->value = xcalloc(MDOC_LINEARG_MAX, sizeof(char *));
286 for (i = 0; i < MDOC_LINEARG_MAX; i++) {
287 c = mdoc_args(mdoc, tok, pos, buf, ARGS_QUOTED, &p);
288 if (ARGS_ERROR == c) {
289 free(v->value);
290 return(0);
291 } else if (ARGS_EOLN == c)
292 break;
293 v->value[i] = p;
294 }
295 if (0 == i) {
296 free(v->value);
297 return(mdoc_err(mdoc, tok, ppos, ERR_SYNTAX_ARGVAL));
298 } else if (MDOC_LINEARG_MAX == i)
299 return(mdoc_err(mdoc, tok, ppos, ERR_SYNTAX_ARGMANY));
300
301 v->sz = i;
302 break;
303 default:
304 abort();
305 /* NOTREACHED */
306 }
307
308 return(1);
309 }
310
311
312 int
313 mdoc_argv(struct mdoc *mdoc, int tok,
314 struct mdoc_arg *v, int *pos, char *buf)
315 {
316 int i, ppos;
317 char *argv;
318
319 (void)memset(v, 0, sizeof(struct mdoc_arg));
320
321 if (0 == buf[*pos])
322 return(0);
323
324 assert( ! isspace(buf[*pos]));
325
326 if ('-' != buf[*pos]) {
327 (void)mdoc_err(mdoc, tok, *pos, ERR_SYNTAX_ARGFORM);
328 return(-1);
329 }
330
331 i = *pos;
332 argv = &buf[++(*pos)];
333
334 while (buf[*pos] && ! isspace(buf[*pos]))
335 (*pos)++;
336
337 if (buf[*pos])
338 buf[(*pos)++] = 0;
339
340 if (MDOC_ARG_MAX == (v->arg = lookup(tok, argv))) {
341 (void)mdoc_err(mdoc, tok, i, ERR_SYNTAX_ARG);
342 return(-1);
343 }
344
345 while (buf[*pos] && isspace(buf[*pos]))
346 (*pos)++;
347
348 /* FIXME: whitespace if no value. */
349
350 ppos = *pos;
351 if ( ! parse(mdoc, tok, v, pos, buf))
352 return(-1);
353 if ( ! postparse(mdoc, tok, v, ppos))
354 return(-1);
355
356 return(1);
357 }
358
359
360 void
361 mdoc_argv_free(int sz, struct mdoc_arg *arg)
362 {
363 int i;
364
365 for (i = 0; i < sz; i++) {
366 if (0 == arg[i].sz) {
367 assert(NULL == arg[i].value);
368 continue;
369 }
370 assert(arg[i].value);
371 free(arg[i].value);
372 }
373 }
374