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