]> git.cameronkatri.com Git - mandoc.git/blob - action.c
Added argv regression tests.
[mandoc.git] / action.c
1 /* $Id: action.c,v 1.29 2009/03/05 12:08:53 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 <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <time.h>
24
25 #include "private.h"
26
27 /*
28 * Actions are executed on macros after they've been post-validated: in
29 * other words, a macro will not be "acted upon" until all of its
30 * children have been filled in (post-fix order).
31 */
32
33 struct actions {
34 int (*post)(struct mdoc *);
35 };
36
37 /* Per-macro action routines. */
38
39 static int post_bl(struct mdoc *);
40 static int post_bl_width(struct mdoc *);
41 static int post_bl_tagwidth(struct mdoc *);
42 static int post_dd(struct mdoc *);
43 static int post_dt(struct mdoc *);
44 static int post_ex(struct mdoc *);
45 static int post_nm(struct mdoc *);
46 static int post_os(struct mdoc *);
47 static int post_sh(struct mdoc *);
48
49 static int post_prologue(struct mdoc *);
50
51 /* Array of macro action routines. */
52
53 const struct actions mdoc_actions[MDOC_MAX] = {
54 { NULL }, /* \" */
55 { post_dd }, /* Dd */
56 { post_dt }, /* Dt */
57 { post_os }, /* Os */
58 { post_sh }, /* Sh */
59 { NULL }, /* Ss */
60 { NULL }, /* Pp */
61 { NULL }, /* D1 */
62 { NULL }, /* Dl */
63 { NULL }, /* Bd */
64 { NULL }, /* Ed */
65 { post_bl }, /* Bl */
66 { NULL }, /* El */
67 { NULL }, /* It */
68 { NULL }, /* Ad */
69 { NULL }, /* An */
70 { NULL }, /* Ar */
71 { NULL }, /* Cd */
72 { NULL }, /* Cm */
73 { NULL }, /* Dv */
74 { NULL }, /* Er */
75 { NULL }, /* Ev */
76 { post_ex }, /* Ex */
77 { NULL }, /* Fa */
78 { NULL }, /* Fd */
79 { NULL }, /* Fl */
80 { NULL }, /* Fn */
81 { NULL }, /* Ft */
82 { NULL }, /* Ic */
83 { NULL }, /* In */
84 { NULL }, /* Li */
85 { NULL }, /* Nd */
86 { post_nm }, /* Nm */
87 { NULL }, /* Op */
88 { NULL }, /* Ot */
89 { NULL }, /* Pa */
90 { NULL }, /* Rv */
91 { NULL }, /* St */
92 { NULL }, /* Va */
93 { NULL }, /* Vt */
94 { NULL }, /* Xr */
95 { NULL }, /* %A */
96 { NULL }, /* %B */
97 { NULL }, /* %D */
98 { NULL }, /* %I */
99 { NULL }, /* %J */
100 { NULL }, /* %N */
101 { NULL }, /* %O */
102 { NULL }, /* %P */
103 { NULL }, /* %R */
104 { NULL }, /* %T */
105 { NULL }, /* %V */
106 { NULL }, /* Ac */
107 { NULL }, /* Ao */
108 { NULL }, /* Aq */
109 { NULL }, /* At */
110 { NULL }, /* Bc */
111 { NULL }, /* Bf */
112 { NULL }, /* Bo */
113 { NULL }, /* Bq */
114 { NULL }, /* Bsx */
115 { NULL }, /* Bx */
116 { NULL }, /* Db */
117 { NULL }, /* Dc */
118 { NULL }, /* Do */
119 { NULL }, /* Dq */
120 { NULL }, /* Ec */
121 { NULL }, /* Ef */
122 { NULL }, /* Em */
123 { NULL }, /* Eo */
124 { NULL }, /* Fx */
125 { NULL }, /* Ms */
126 { NULL }, /* No */
127 { NULL }, /* Ns */
128 { NULL }, /* Nx */
129 { NULL }, /* Ox */
130 { NULL }, /* Pc */
131 { NULL }, /* Pf */
132 { NULL }, /* Po */
133 { NULL }, /* Pq */
134 { NULL }, /* Qc */
135 { NULL }, /* Ql */
136 { NULL }, /* Qo */
137 { NULL }, /* Qq */
138 { NULL }, /* Re */
139 { NULL }, /* Rs */
140 { NULL }, /* Sc */
141 { NULL }, /* So */
142 { NULL }, /* Sq */
143 { NULL }, /* Sm */
144 { NULL }, /* Sx */
145 { NULL }, /* Sy */
146 { NULL }, /* Tn */
147 { NULL }, /* Ux */
148 { NULL }, /* Xc */
149 { NULL }, /* Xo */
150 { NULL }, /* Fo */
151 { NULL }, /* Fc */
152 { NULL }, /* Oo */
153 { NULL }, /* Oc */
154 { NULL }, /* Bk */
155 { NULL }, /* Ek */
156 { NULL }, /* Bt */
157 { NULL }, /* Hf */
158 { NULL }, /* Fr */
159 { NULL }, /* Ud */
160 };
161
162
163 static int
164 post_ex(struct mdoc *mdoc)
165 {
166
167 /*
168 * If `.Ex -std' is invoked without an argument, fill it in with
169 * our name (if it's been set).
170 */
171
172 if (0 == mdoc->last->data.elem.argc)
173 return(1);
174
175 assert(1 == mdoc->last->data.elem.argc);
176 if (1 == mdoc->last->data.elem.argv[0].sz)
177 return(1);
178 assert(0 == mdoc->last->data.elem.argv[0].sz);
179
180 if (NULL == mdoc->meta.name)
181 return(mdoc_err(mdoc, "default name not yet set"));
182
183 mdoc_msg(mdoc, "writing %s argument: %s",
184 mdoc_argnames[MDOC_Std], mdoc->meta.name);
185
186 mdoc->last->data.elem.argv[0].sz = 1;
187 mdoc->last->data.elem.argv[0].value = xcalloc(1, sizeof(char *));
188 mdoc->last->data.elem.argv[0].value[0] = xstrdup(mdoc->meta.name);
189 return(1);
190 }
191
192
193 static int
194 post_nm(struct mdoc *mdoc)
195 {
196 char buf[64];
197
198 assert(MDOC_ELEM == mdoc->last->type);
199 assert(MDOC_Nm == mdoc->last->tok);
200
201 /*
202 * The `Nm' macro sets the document's name when used the first
203 * time with an argument. Subsequent calls without a value will
204 * result in the name value being used.
205 */
206
207 if (mdoc->meta.name)
208 return(1);
209
210 if (xstrlcats(buf, mdoc->last->child, 64)) {
211 mdoc->meta.name = xstrdup(buf);
212 return(1);
213 }
214
215 return(mdoc_err(mdoc, "macro parameters too long"));
216 }
217
218
219 static int
220 post_sh(struct mdoc *mdoc)
221 {
222 enum mdoc_sec sec;
223 char buf[64];
224
225 /*
226 * We keep track of the current section /and/ the "named"
227 * section, which is one of the conventional ones, in order to
228 * check ordering.
229 */
230
231 if (MDOC_HEAD != mdoc->last->type)
232 return(1);
233 if (xstrlcats(buf, mdoc->last->child, 64)) {
234 if (SEC_CUSTOM != (sec = mdoc_atosec(buf)))
235 mdoc->lastnamed = sec;
236 mdoc->lastsec = sec;
237 } else
238 return(mdoc_err(mdoc, "parameters too long"));
239
240 switch (mdoc->lastsec) {
241 case (SEC_RETURN_VALUES):
242 /* FALLTHROUGH */
243 case (SEC_ERRORS):
244 switch (mdoc->meta.msec) {
245 case (MSEC_2):
246 /* FALLTHROUGH */
247 case (MSEC_3):
248 /* FALLTHROUGH */
249 case (MSEC_9):
250 break;
251 default:
252 return(mdoc_warn(mdoc, WARN_COMPAT,
253 "inappropriate section for "
254 "manual section"));
255 }
256 break;
257 default:
258 break;
259 }
260 return(1);
261 }
262
263
264 static int
265 post_dt(struct mdoc *mdoc)
266 {
267 int i;
268 char *p;
269 struct mdoc_node *n;
270
271 /*
272 * Prologue title must be parsed into document meta-data.
273 */
274
275 assert(MDOC_ELEM == mdoc->last->type);
276 assert(MDOC_Dt == mdoc->last->tok);
277
278 assert(NULL == mdoc->meta.title);
279
280 /* LINTED */
281 for (i = 0, n = mdoc->last->child; n; n = n->next, i++) {
282 assert(MDOC_TEXT == n->type);
283 p = n->data.text.string;
284
285 switch (i) {
286 case (0):
287 mdoc->meta.title = xstrdup(p);
288 break;
289 case (1):
290 mdoc->meta.msec = mdoc_atomsec(p);
291 if (MSEC_DEFAULT != mdoc->meta.msec)
292 break;
293 return(mdoc_nerr(mdoc, n,
294 "invalid parameter syntax"));
295 case (2):
296 mdoc->meta.vol = mdoc_atovol(p);
297 if (VOL_DEFAULT != mdoc->meta.vol)
298 break;
299 mdoc->meta.arch = mdoc_atoarch(p);
300 if (ARCH_DEFAULT != mdoc->meta.arch)
301 break;
302 return(mdoc_nerr(mdoc, n,
303 "invalid parameter syntax"));
304 default:
305 return(mdoc_nerr(mdoc, n,
306 "too many parameters"));
307 }
308 }
309
310 if (NULL == mdoc->meta.title)
311 mdoc->meta.title = xstrdup("UNTITLED");
312
313 mdoc_msg(mdoc, "title: %s", mdoc->meta.title);
314
315 return(post_prologue(mdoc));
316 }
317
318
319 static int
320 post_os(struct mdoc *mdoc)
321 {
322 char buf[64];
323
324 /*
325 * Prologue operating system must be parsed into document
326 * meta-data.
327 */
328
329 assert(MDOC_ELEM == mdoc->last->type);
330 assert(MDOC_Os == mdoc->last->tok);
331 assert(NULL == mdoc->meta.os);
332
333 if ( ! xstrlcats(buf, mdoc->last->child, 64))
334 return(mdoc_err(mdoc, "macro parameters too long"));
335
336 mdoc->meta.os = xstrdup(buf[0] ? buf : "LOCAL");
337 mdoc->lastnamed = SEC_BODY;
338
339 return(post_prologue(mdoc));
340 }
341
342
343 static int
344 post_bl_tagwidth(struct mdoc *mdoc)
345 {
346 struct mdoc_node *n;
347 struct mdoc_block *b;
348 int sz;
349 char buf[32];
350
351 /*
352 * If -tag has been specified and -width has not been, then try
353 * to intuit our width from the first body element.
354 */
355
356 b = &mdoc->last->data.block;
357
358 if (NULL == (n = b->body->child))
359 return(1);
360 assert(MDOC_It == n->tok);
361
362 /*
363 * Use the text width, if a text node, or the default macro
364 * width if a macro.
365 */
366
367 if ((n = n->data.block.head->child)) {
368 if (MDOC_TEXT != n->type) {
369 if (0 == (sz = mdoc_macro2len(n->tok)))
370 sz = -1;
371 } else
372 sz = (int)strlen(n->data.text.string) + 1;
373 } else
374 sz = -1;
375
376 if (-1 == sz) {
377 if ( ! mdoc_warn(mdoc, WARN_SYNTAX,
378 "cannot determine default %s",
379 mdoc_argnames[MDOC_Width]))
380 return(0);
381 sz = 10;
382 }
383
384 (void)snprintf(buf, sizeof(buf), "%dn", sz);
385
386 /*
387 * We have to dynamically add this to the macro's argument list.
388 * We're guaranteed that a MDOC_Width doesn't already exist.
389 */
390
391 (b->argc)++;
392 b->argv = xrealloc(b->argv, b->argc * sizeof(struct mdoc_arg));
393
394 b->argv[b->argc - 1].arg = MDOC_Width;
395 b->argv[b->argc - 1].line = mdoc->last->line;
396 b->argv[b->argc - 1].pos = mdoc->last->pos;
397 b->argv[b->argc - 1].sz = 1;
398 b->argv[b->argc - 1].value = xcalloc(1, sizeof(char *));
399 b->argv[b->argc - 1].value[0] = xstrdup(buf);
400
401 mdoc_msg(mdoc, "adding %s argument: %dn",
402 mdoc_argnames[MDOC_Width], sz);
403
404 return(1);
405 }
406
407
408 static int
409 post_bl_width(struct mdoc *mdoc)
410 {
411 size_t width;
412 int i, tok;
413 char buf[32];
414 char **p;
415
416 for (i = 0; i < (int)mdoc->last->data.block.argc; i++)
417 if (MDOC_Width == mdoc->last->data.block.argv[i].arg)
418 break;
419
420 assert(i < (int)mdoc->last->data.block.argc);
421 assert(1 == mdoc->last->data.block.argv[i].sz);
422 p = &mdoc->last->data.block.argv[i].value[0];
423
424 /*
425 * If the value to -width is a macro, then we re-write it to be
426 * the macro's width as set in share/tmac/mdoc/doc-common.
427 */
428
429 if (xstrcmp(*p, "Ds"))
430 width = 8;
431 else if (MDOC_MAX == (tok = mdoc_find(mdoc, *p)))
432 return(1);
433 else if (0 == (width = mdoc_macro2len(tok)))
434 return(mdoc_warn(mdoc, WARN_SYNTAX,
435 "%s macro has no length",
436 mdoc_argnames[MDOC_Width]));
437
438 mdoc_msg(mdoc, "re-writing %s argument: %s -> %zun",
439 mdoc_argnames[MDOC_Width], *p, width);
440
441 /* The value already exists: free and reallocate it. */
442
443 (void)snprintf(buf, sizeof(buf), "%zun", width);
444
445 free(*p);
446 *p = strdup(buf);
447
448 return(1);
449 }
450
451
452 static int
453 post_bl(struct mdoc *mdoc)
454 {
455 int i, r;
456
457 if (MDOC_BLOCK != mdoc->last->type)
458 return(1);
459
460 /*
461 * These are fairly complicated, so we've broken them into two
462 * functions. post_bl_tagwidth() is called when a -tag is
463 * specified, but no -width (it must be guessed). The second
464 * when a -width is specified (macro indicators must be
465 * rewritten into real lengths).
466 */
467
468 for (r = i = 0; i < (int)mdoc->last->data.block.argc; i++) {
469 if (MDOC_Tag == mdoc->last->data.block.argv[i].arg)
470 r |= 1 << 0;
471 if (MDOC_Width == mdoc->last->data.block.argv[i].arg)
472 r |= 1 << 1;
473 }
474
475 if (r & (1 << 0) && ! (r & (1 << 1))) {
476 if ( ! post_bl_tagwidth(mdoc))
477 return(0);
478 } else if (r & (1 << 1))
479 if ( ! post_bl_width(mdoc))
480 return(0);
481
482 return(1);
483 }
484
485
486 static int
487 post_dd(struct mdoc *mdoc)
488 {
489 char buf[64];
490
491 /*
492 * Prologue date must be parsed into document meta-data. We
493 * accept multiple kinds of dates, described mostly in
494 * mdoc_atotime().
495 */
496
497 assert(MDOC_ELEM == mdoc->last->type);
498 assert(MDOC_Dd == mdoc->last->tok);
499
500 assert(0 == mdoc->meta.date);
501
502 if ( ! xstrlcats(buf, mdoc->last->child, 64))
503 return(mdoc_err(mdoc, "macro parameters too long"));
504 if (0 == (mdoc->meta.date = mdoc_atotime(buf)))
505 return(mdoc_err(mdoc, "invalid parameter syntax"));
506
507 mdoc_msg(mdoc, "date: %u", mdoc->meta.date);
508
509 return(post_prologue(mdoc));
510 }
511
512
513 static int
514 post_prologue(struct mdoc *mdoc)
515 {
516 struct mdoc_node *n;
517
518 /*
519 * The end document shouldn't have the prologue macros as part
520 * of the syntax tree (they encompass only meta-data).
521 */
522
523 if (mdoc->last->parent->child == mdoc->last)
524 mdoc->last->parent->child = mdoc->last->prev;
525 if (mdoc->last->prev)
526 mdoc->last->prev->next = NULL;
527
528 n = mdoc->last;
529 assert(NULL == mdoc->last->next);
530
531 if (mdoc->last->prev) {
532 mdoc->last = mdoc->last->prev;
533 mdoc->next = MDOC_NEXT_SIBLING;
534 } else {
535 mdoc->last = mdoc->last->parent;
536 mdoc->next = MDOC_NEXT_CHILD;
537 }
538
539 mdoc_node_freelist(n);
540 return(1);
541 }
542
543
544 int
545 mdoc_action_post(struct mdoc *mdoc)
546 {
547
548 if (MDOC_ACTED & mdoc->last->flags)
549 return(1);
550 mdoc->last->flags |= MDOC_ACTED;
551
552 if (MDOC_TEXT == mdoc->last->type)
553 return(1);
554 if (MDOC_ROOT == mdoc->last->type)
555 return(1);
556 if (NULL == mdoc_actions[mdoc->last->tok].post)
557 return(1);
558 return((*mdoc_actions[mdoc->last->tok].post)(mdoc));
559 }