]> git.cameronkatri.com Git - mandoc.git/blob - action.c
Lint fixes.
[mandoc.git] / action.c
1 /* $Id: action.c,v 1.48 2009/03/21 09:48:29 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@openbsd.org>
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 <sys/utsname.h>
20
21 #include <assert.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "private.h"
28
29 /*
30 * Actions are executed on macros after they've been post-validated: in
31 * other words, a macro will not be "acted upon" until all of its
32 * children have been filled in (post-fix order).
33 */
34
35 enum merr {
36 ENOWIDTH
37 };
38
39 enum mwarn {
40 WBADSEC,
41 WNOWIDTH,
42 WBADDATE
43 };
44
45 #define PRE_ARGS struct mdoc *m, const struct mdoc_node *n
46 #define POST_ARGS struct mdoc *m
47
48 struct actions {
49 int (*pre)(PRE_ARGS);
50 int (*post)(POST_ARGS);
51 };
52
53 static int pwarn(struct mdoc *, int, int, enum mwarn);
54 static int perr(struct mdoc *, int, int, enum merr);
55
56 static int post_ar(POST_ARGS);
57 static int post_bl(POST_ARGS);
58 static int post_bl_width(POST_ARGS);
59 static int post_bl_tagwidth(POST_ARGS);
60 static int post_dd(POST_ARGS);
61 static int post_display(POST_ARGS);
62 static int post_dt(POST_ARGS);
63 static int post_nm(POST_ARGS);
64 static int post_os(POST_ARGS);
65 static int post_prol(POST_ARGS);
66 static int post_sh(POST_ARGS);
67 static int post_std(POST_ARGS);
68
69 static int pre_bd(PRE_ARGS);
70 static int pre_dl(PRE_ARGS);
71
72 #define merr(m, t) perr((m), (m)->last->line, (m)->last->pos, (t))
73 #define mwarn(m, t) pwarn((m), (m)->last->line, (m)->last->pos, (t))
74
75 const struct actions mdoc_actions[MDOC_MAX] = {
76 { NULL, NULL }, /* \" */
77 { NULL, post_dd }, /* Dd */
78 { NULL, post_dt }, /* Dt */
79 { NULL, post_os }, /* Os */
80 { NULL, post_sh }, /* Sh */
81 { NULL, NULL }, /* Ss */
82 { NULL, NULL }, /* Pp */
83 { NULL, NULL }, /* D1 */
84 { pre_dl, post_display }, /* Dl */
85 { pre_bd, post_display }, /* Bd */
86 { NULL, NULL }, /* Ed */
87 { NULL, post_bl }, /* Bl */
88 { NULL, NULL }, /* El */
89 { NULL, NULL }, /* It */
90 { NULL, NULL }, /* Ad */
91 { NULL, NULL }, /* An */
92 { NULL, post_ar }, /* Ar */
93 { NULL, NULL }, /* Cd */
94 { NULL, NULL }, /* Cm */
95 { NULL, NULL }, /* Dv */
96 { NULL, NULL }, /* Er */
97 { NULL, NULL }, /* Ev */
98 { NULL, post_std }, /* Ex */
99 { NULL, NULL }, /* Fa */
100 { NULL, NULL }, /* Fd */
101 { NULL, NULL }, /* Fl */
102 { NULL, NULL }, /* Fn */
103 { NULL, NULL }, /* Ft */
104 { NULL, NULL }, /* Ic */
105 { NULL, NULL }, /* In */
106 { NULL, NULL }, /* Li */
107 { NULL, NULL }, /* Nd */
108 { NULL, post_nm }, /* Nm */
109 { NULL, NULL }, /* Op */
110 { NULL, NULL }, /* Ot */
111 { NULL, NULL }, /* Pa */
112 { NULL, post_std }, /* Rv */
113 { NULL, NULL }, /* St */
114 { NULL, NULL }, /* Va */
115 { NULL, NULL }, /* Vt */
116 { NULL, NULL }, /* Xr */
117 { NULL, NULL }, /* %A */
118 { NULL, NULL }, /* %B */
119 { NULL, NULL }, /* %D */
120 { NULL, NULL }, /* %I */
121 { NULL, NULL }, /* %J */
122 { NULL, NULL }, /* %N */
123 { NULL, NULL }, /* %O */
124 { NULL, NULL }, /* %P */
125 { NULL, NULL }, /* %R */
126 { NULL, NULL }, /* %T */
127 { NULL, NULL }, /* %V */
128 { NULL, NULL }, /* Ac */
129 { NULL, NULL }, /* Ao */
130 { NULL, NULL }, /* Aq */
131 { NULL, NULL }, /* At */
132 { NULL, NULL }, /* Bc */
133 { NULL, NULL }, /* Bf */
134 { NULL, NULL }, /* Bo */
135 { NULL, NULL }, /* Bq */
136 { NULL, NULL }, /* Bsx */
137 { NULL, NULL }, /* Bx */
138 { NULL, NULL }, /* Db */
139 { NULL, NULL }, /* Dc */
140 { NULL, NULL }, /* Do */
141 { NULL, NULL }, /* Dq */
142 { NULL, NULL }, /* Ec */
143 { NULL, NULL }, /* Ef */
144 { NULL, NULL }, /* Em */
145 { NULL, NULL }, /* Eo */
146 { NULL, NULL }, /* Fx */
147 { NULL, NULL }, /* Ms */
148 { NULL, NULL }, /* No */
149 { NULL, NULL }, /* Ns */
150 { NULL, NULL }, /* Nx */
151 { NULL, NULL }, /* Ox */
152 { NULL, NULL }, /* Pc */
153 { NULL, NULL }, /* Pf */
154 { NULL, NULL }, /* Po */
155 { NULL, NULL }, /* Pq */
156 { NULL, NULL }, /* Qc */
157 { NULL, NULL }, /* Ql */
158 { NULL, NULL }, /* Qo */
159 { NULL, NULL }, /* Qq */
160 { NULL, NULL }, /* Re */
161 { NULL, NULL }, /* Rs */
162 { NULL, NULL }, /* Sc */
163 { NULL, NULL }, /* So */
164 { NULL, NULL }, /* Sq */
165 { NULL, NULL }, /* Sm */
166 { NULL, NULL }, /* Sx */
167 { NULL, NULL }, /* Sy */
168 { NULL, NULL }, /* Tn */
169 { NULL, NULL }, /* Ux */
170 { NULL, NULL }, /* Xc */
171 { NULL, NULL }, /* Xo */
172 { NULL, NULL }, /* Fo */
173 { NULL, NULL }, /* Fc */
174 { NULL, NULL }, /* Oo */
175 { NULL, NULL }, /* Oc */
176 { NULL, NULL }, /* Bk */
177 { NULL, NULL }, /* Ek */
178 { NULL, NULL }, /* Bt */
179 { NULL, NULL }, /* Hf */
180 { NULL, NULL }, /* Fr */
181 { NULL, NULL }, /* Ud */
182 { NULL, NULL }, /* Lb */
183 { NULL, NULL }, /* Ap */
184 { NULL, NULL }, /* Lp */
185 { NULL, NULL }, /* Lk */
186 { NULL, NULL }, /* Mt */
187 { NULL, NULL }, /* Brq */
188 { NULL, NULL }, /* Bro */
189 { NULL, NULL }, /* Brc */
190 { NULL, NULL }, /* %C */
191 { NULL, NULL }, /* Es */
192 { NULL, NULL }, /* En */
193 { NULL, NULL }, /* Dx */
194 { NULL, NULL }, /* %Q */
195 };
196
197
198 int
199 mdoc_action_pre(struct mdoc *m, const struct mdoc_node *n)
200 {
201
202 switch (n->type) {
203 case (MDOC_ROOT):
204 break;
205 case (MDOC_TEXT):
206 break;
207 default:
208 if (NULL == mdoc_actions[m->last->tok].pre)
209 break;
210 return((*mdoc_actions[m->last->tok].pre)(m, n));
211 }
212 return(1);
213 }
214
215
216 int
217 mdoc_action_post(struct mdoc *m)
218 {
219
220 if (MDOC_ACTED & m->last->flags)
221 return(1);
222 m->last->flags |= MDOC_ACTED;
223
224 switch (m->last->type) {
225 case (MDOC_TEXT):
226 break;
227 case (MDOC_ROOT):
228 break;
229 default:
230 if (NULL == mdoc_actions[m->last->tok].post)
231 break;
232 return((*mdoc_actions[m->last->tok].post)(m));
233 }
234 return(1);
235 }
236
237
238 static int
239 perr(struct mdoc *m, int line, int pos, enum merr type)
240 {
241 char *p;
242
243 p = NULL;
244
245 switch (type) {
246 case (ENOWIDTH):
247 p = "missing width argument";
248 break;
249 }
250
251 assert(p);
252 return(mdoc_perr(m, line, pos, p));
253 }
254
255
256 static int
257 pwarn(struct mdoc *m, int line, int pos, enum mwarn type)
258 {
259 char *p;
260 int c;
261
262 p = NULL;
263 c = WARN_SYNTAX;
264
265 switch (type) {
266 case (WBADSEC):
267 p = "inappropriate document section in manual section";
268 c = WARN_COMPAT;
269 break;
270 case (WNOWIDTH):
271 p = "cannot determine default width";
272 break;
273 case (WBADDATE):
274 p = "malformed date syntax";
275 break;
276 }
277
278 assert(p);
279 return(mdoc_pwarn(m, line, pos, c, p));
280 }
281
282
283 static int
284 post_std(POST_ARGS)
285 {
286
287 /*
288 * If '-std' is invoked without an argument, fill it in with our
289 * name (if it's been set).
290 */
291
292 if (NULL == m->last->args)
293 return(1);
294 if (m->last->args->argv[0].sz)
295 return(1);
296
297 assert(m->meta.name);
298
299 m->last->args->argv[0].value = xcalloc(1, sizeof(char *));
300 m->last->args->argv[0].sz = 1;
301 m->last->args->argv[0].value[0] = xstrdup(m->meta.name);
302 return(1);
303 }
304
305
306 static int
307 post_nm(POST_ARGS)
308 {
309 char buf[64];
310
311 if (m->meta.name)
312 return(1);
313
314 (void)xstrlcpys(buf, m->last->child, sizeof(buf));
315 m->meta.name = xstrdup(buf);
316
317 return(1);
318 }
319
320
321 static int
322 post_sh(POST_ARGS)
323 {
324 enum mdoc_sec sec;
325 char buf[64];
326
327 /*
328 * We keep track of the current section /and/ the "named"
329 * section, which is one of the conventional ones, in order to
330 * check ordering.
331 */
332
333 if (MDOC_HEAD != m->last->type)
334 return(1);
335
336 (void)xstrlcpys(buf, m->last->child, sizeof(buf));
337 if (SEC_CUSTOM != (sec = mdoc_atosec(buf)))
338 m->lastnamed = sec;
339
340 switch ((m->lastsec = sec)) {
341 case (SEC_RETURN_VALUES):
342 /* FALLTHROUGH */
343 case (SEC_ERRORS):
344 switch (m->meta.msec) {
345 case (2):
346 /* FALLTHROUGH */
347 case (3):
348 /* FALLTHROUGH */
349 case (9):
350 break;
351 default:
352 return(mwarn(m, WBADSEC));
353 }
354 break;
355 default:
356 break;
357 }
358 return(1);
359 }
360
361
362 static int
363 post_dt(POST_ARGS)
364 {
365 struct mdoc_node *n;
366 const char *cp;
367 char *ep;
368 long lval;
369
370 if (m->meta.title)
371 free(m->meta.title);
372 if (m->meta.vol)
373 free(m->meta.vol);
374 if (m->meta.arch)
375 free(m->meta.arch);
376
377 m->meta.title = m->meta.vol = m->meta.arch = NULL;
378 m->meta.msec = 0;
379
380 /* Handles: `.Dt'
381 * --> title = unknown, volume = local, msec = 0, arch = NULL
382 */
383
384 if (NULL == (n = m->last->child)) {
385 m->meta.title = xstrdup("unknown");
386 m->meta.vol = xstrdup("local");
387 return(post_prol(m));
388 }
389
390 /* Handles: `.Dt TITLE'
391 * --> title = TITLE, volume = local, msec = 0, arch = NULL
392 */
393
394 m->meta.title = xstrdup(n->string);
395
396 if (NULL == (n = n->next)) {
397 m->meta.vol = xstrdup("local");
398 return(post_prol(m));
399 }
400
401 /* Handles: `.Dt TITLE SEC'
402 * --> title = TITLE, volume = SEC is msec ?
403 * format(msec) : SEC,
404 * msec = SEC is msec ? atoi(msec) : 0,
405 * arch = NULL
406 */
407
408 cp = mdoc_a2msec(n->string);
409 if (cp) {
410 m->meta.vol = xstrdup(cp);
411 errno = 0;
412 lval = strtol(n->string, &ep, 10);
413 if (n->string[0] != '\0' && *ep == '\0')
414 m->meta.msec = (int)lval;
415 } else
416 m->meta.vol = xstrdup(n->string);
417
418 if (NULL == (n = n->next))
419 return(post_prol(m));
420
421 /* Handles: `.Dt TITLE SEC VOL'
422 * --> title = TITLE, volume = VOL is vol ?
423 * format(VOL) :
424 * VOL is arch ? format(arch) :
425 * VOL
426 */
427
428 cp = mdoc_a2vol(n->string);
429 if (cp) {
430 free(m->meta.vol);
431 m->meta.vol = xstrdup(cp);
432 n = n->next;
433 } else {
434 cp = mdoc_a2arch(n->string);
435 if (NULL == cp) {
436 free(m->meta.vol);
437 m->meta.vol = xstrdup(n->string);
438 } else
439 m->meta.arch = xstrdup(cp);
440 }
441
442 /* Ignore any subsequent parameters... */
443
444 return(post_prol(m));
445 }
446
447
448 static int
449 post_os(POST_ARGS)
450 {
451 char buf[64];
452 struct utsname utsname;
453
454 if (m->meta.os)
455 free(m->meta.os);
456
457 (void)xstrlcpys(buf, m->last->child, sizeof(buf));
458
459 if (0 == buf[0]) {
460 if (-1 == uname(&utsname))
461 return(mdoc_err(m, "utsname"));
462 (void)xstrlcpy(buf, utsname.sysname, sizeof(buf));
463 (void)xstrlcat(buf, " ", sizeof(buf));
464 (void)xstrlcat(buf, utsname.release, sizeof(buf));
465 }
466
467 m->meta.os = xstrdup(buf);
468 m->lastnamed = m->lastsec = SEC_BODY;
469
470 return(post_prol(m));
471 }
472
473
474 static int
475 post_bl_tagwidth(struct mdoc *m)
476 {
477 struct mdoc_node *n;
478 int sz;
479 char buf[32];
480
481 /*
482 * If -tag has been specified and -width has not been, then try
483 * to intuit our width from the first body element.
484 */
485
486 if (NULL == (n = m->last->body->child))
487 return(1);
488
489 /*
490 * Use the text width, if a text node, or the default macro
491 * width if a macro.
492 */
493
494 n = n->head->child;
495 if (n) {
496 if (MDOC_TEXT != n->type) {
497 if (0 == (sz = (int)mdoc_macro2len(n->tok)))
498 sz = -1;
499 } else
500 sz = (int)strlen(n->string) + 1;
501 } else
502 sz = -1;
503
504 if (-1 == sz) {
505 if ( ! mwarn(m, WNOWIDTH))
506 return(0);
507 sz = 10;
508 }
509
510 (void)snprintf(buf, sizeof(buf), "%dn", sz);
511
512 /*
513 * We have to dynamically add this to the macro's argument list.
514 * We're guaranteed that a MDOC_Width doesn't already exist.
515 */
516
517 if (NULL == m->last->args) {
518 m->last->args = xcalloc
519 (1, sizeof(struct mdoc_arg));
520 m->last->args->refcnt = 1;
521 }
522
523 n = m->last;
524 sz = (int)n->args->argc;
525
526 (n->args->argc)++;
527
528 n->args->argv = xrealloc(n->args->argv,
529 n->args->argc * sizeof(struct mdoc_arg));
530
531 n->args->argv[sz - 1].arg = MDOC_Width;
532 n->args->argv[sz - 1].line = m->last->line;
533 n->args->argv[sz - 1].pos = m->last->pos;
534 n->args->argv[sz - 1].sz = 1;
535 n->args->argv[sz - 1].value = xcalloc(1, sizeof(char *));
536 n->args->argv[sz - 1].value[0] = xstrdup(buf);
537
538 return(1);
539 }
540
541
542 static int
543 post_bl_width(struct mdoc *m)
544 {
545 size_t width;
546 int i, tok;
547 char buf[32];
548 char *p;
549
550 if (NULL == m->last->args)
551 return(merr(m, ENOWIDTH));
552
553 for (i = 0; i < (int)m->last->args->argc; i++)
554 if (MDOC_Width == m->last->args->argv[i].arg)
555 break;
556
557 if (i == (int)m->last->args->argc)
558 return(merr(m, ENOWIDTH));
559
560 p = m->last->args->argv[i].value[0];
561
562 /*
563 * If the value to -width is a macro, then we re-write it to be
564 * the macro's width as set in share/tmac/mdoc/doc-common.
565 */
566
567 if (xstrcmp(p, "Ds"))
568 width = 8;
569 else if (MDOC_MAX == (tok = mdoc_tokhash_find(m->htab, p)))
570 return(1);
571 else if (0 == (width = mdoc_macro2len(tok)))
572 return(mwarn(m, WNOWIDTH));
573
574 /* The value already exists: free and reallocate it. */
575
576 (void)snprintf(buf, sizeof(buf), "%zun", width);
577
578 free(m->last->args->argv[i].value[0]);
579 m->last->args->argv[i].value[0] = xstrdup(buf);
580
581 return(1);
582 }
583
584
585 static int
586 post_bl(POST_ARGS)
587 {
588 int i, r, len;
589
590 if (MDOC_BLOCK != m->last->type)
591 return(1);
592
593 /*
594 * These are fairly complicated, so we've broken them into two
595 * functions. post_bl_tagwidth() is called when a -tag is
596 * specified, but no -width (it must be guessed). The second
597 * when a -width is specified (macro indicators must be
598 * rewritten into real lengths).
599 */
600
601 len = (int)(m->last->args ? m->last->args->argc : 0);
602
603 for (r = i = 0; i < len; i++) {
604 if (MDOC_Tag == m->last->args->argv[i].arg)
605 r |= 1 << 0;
606 if (MDOC_Width == m->last->args->argv[i].arg)
607 r |= 1 << 1;
608 }
609
610 if (r & (1 << 0) && ! (r & (1 << 1))) {
611 if ( ! post_bl_tagwidth(m))
612 return(0);
613 } else if (r & (1 << 1))
614 if ( ! post_bl_width(m))
615 return(0);
616
617 return(1);
618 }
619
620
621 static int
622 post_ar(POST_ARGS)
623 {
624 struct mdoc_node *n;
625
626 if (m->last->child)
627 return(1);
628
629 n = m->last;
630 m->next = MDOC_NEXT_CHILD;
631 if ( ! mdoc_word_alloc(m, m->last->line,
632 m->last->pos, "file"))
633 return(0);
634 m->next = MDOC_NEXT_SIBLING;
635 if ( ! mdoc_word_alloc(m, m->last->line,
636 m->last->pos, "..."))
637 return(0);
638
639 m->last = n;
640 m->next = MDOC_NEXT_SIBLING;
641 return(1);
642 }
643
644
645 static int
646 post_dd(POST_ARGS)
647 {
648 char buf[64];
649
650 (void)xstrlcpys(buf, m->last->child, sizeof(buf));
651
652 if (0 == (m->meta.date = mdoc_atotime(buf))) {
653 if ( ! mwarn(m, WBADDATE))
654 return(0);
655 m->meta.date = time(NULL);
656 }
657
658 return(post_prol(m));
659 }
660
661
662 static int
663 post_prol(POST_ARGS)
664 {
665 struct mdoc_node *n;
666
667 /*
668 * The end document shouldn't have the prologue macros as part
669 * of the syntax tree (they encompass only meta-data).
670 */
671
672 if (m->last->parent->child == m->last)
673 m->last->parent->child = m->last->prev;
674 if (m->last->prev)
675 m->last->prev->next = NULL;
676
677 n = m->last;
678 assert(NULL == m->last->next);
679
680 if (m->last->prev) {
681 m->last = m->last->prev;
682 m->next = MDOC_NEXT_SIBLING;
683 } else {
684 m->last = m->last->parent;
685 m->next = MDOC_NEXT_CHILD;
686 }
687
688 mdoc_node_freelist(n);
689 return(1);
690 }
691
692
693 static int
694 pre_dl(PRE_ARGS)
695 {
696
697 if (MDOC_BODY != n->type)
698 return(1);
699 m->flags |= MDOC_LITERAL;
700 return(1);
701 }
702
703
704 static int
705 pre_bd(PRE_ARGS)
706 {
707 int i;
708
709 if (MDOC_BODY != n->type)
710 return(1);
711
712 /*
713 * We ONLY enter a literal context if `Bd -literal' or `Bd
714 * -unfilled'.
715 */
716
717 n = n->parent;
718
719 for (i = 0; i < (int)n->args->argc; i++)
720 if (MDOC_Literal == n->args->argv[i].arg)
721 break;
722 else if (MDOC_Unfilled == n->args->argv[i].arg)
723 break;
724
725 if (i < (int)n->args->argc)
726 m->flags |= MDOC_LITERAL;
727
728 return(1);
729 }
730
731
732 static int
733 post_display(POST_ARGS)
734 {
735
736 if (MDOC_BODY == m->last->type)
737 m->flags &= ~MDOC_LITERAL;
738 return(1);
739 }
740
741