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