]> git.cameronkatri.com Git - mandoc.git/blob - action.c
Memory-corruption fix.
[mandoc.git] / action.c
1 /* $Id: action.c,v 1.35 2009/03/08 13:01:35 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 mdoc->last->args->argv[0].value = xcalloc(1, sizeof(char *));
245 mdoc->last->args->argv[0].sz = 1;
246 mdoc->last->args->argv[0].value[0] = xstrdup(mdoc->meta.name);
247 return(1);
248 }
249
250
251 static int
252 post_nm(struct mdoc *mdoc)
253 {
254 char buf[64];
255
256 if (mdoc->meta.name)
257 return(1);
258
259 (void)xstrlcpys(buf, mdoc->last->child, sizeof(buf));
260 mdoc->meta.name = xstrdup(buf);
261 mdoc_msg(mdoc, "name: %s", mdoc->meta.name);
262
263 return(1);
264 }
265
266
267 static int
268 post_sh(struct mdoc *mdoc)
269 {
270 enum mdoc_sec sec;
271 char buf[64];
272
273 /*
274 * We keep track of the current section /and/ the "named"
275 * section, which is one of the conventional ones, in order to
276 * check ordering.
277 */
278
279 if (MDOC_HEAD != mdoc->last->type)
280 return(1);
281
282 (void)xstrlcpys(buf, mdoc->last->child, sizeof(buf));
283 if (SEC_CUSTOM != (sec = mdoc_atosec(buf)))
284 mdoc->lastnamed = sec;
285
286 mdoc->lastsec = sec;
287
288 switch (mdoc->lastsec) {
289 case (SEC_RETURN_VALUES):
290 /* FALLTHROUGH */
291 case (SEC_ERRORS):
292 switch (mdoc->meta.msec) {
293 case (2):
294 /* FALLTHROUGH */
295 case (3):
296 /* FALLTHROUGH */
297 case (9):
298 break;
299 default:
300 return(mwarn(mdoc, WBADSEC));
301 }
302 break;
303 default:
304 break;
305 }
306 return(1);
307 }
308
309
310 static int
311 post_dt(struct mdoc *mdoc)
312 {
313 struct mdoc_node *n;
314 const char *cp;
315 char *ep;
316 long lval;
317
318 if (mdoc->meta.title)
319 free(mdoc->meta.title);
320 if (mdoc->meta.vol)
321 free(mdoc->meta.vol);
322 if (mdoc->meta.arch)
323 free(mdoc->meta.arch);
324
325 mdoc->meta.title = mdoc->meta.vol = mdoc->meta.arch = NULL;
326 mdoc->meta.msec = 0;
327
328 /* Handles: `.Dt'
329 * --> title = unknown, volume = local, msec = 0, arch = NULL
330 */
331
332 if (NULL == (n = mdoc->last->child)) {
333 mdoc->meta.title = xstrdup("unknown");
334 mdoc->meta.vol = xstrdup("local");
335 mdoc_msg(mdoc, "title: %s", mdoc->meta.title);
336 mdoc_msg(mdoc, "volume: %s", mdoc->meta.vol);
337 mdoc_msg(mdoc, "arch: <unset>");
338 mdoc_msg(mdoc, "msec: <unset>");
339 return(post_prologue(mdoc));
340 }
341
342 /* Handles: `.Dt TITLE'
343 * --> title = TITLE, volume = local, msec = 0, arch = NULL
344 */
345
346 mdoc->meta.title = xstrdup(n->string);
347 mdoc_msg(mdoc, "title: %s", mdoc->meta.title);
348
349 if (NULL == (n = n->next)) {
350 mdoc->meta.vol = xstrdup("local");
351 mdoc_msg(mdoc, "volume: %s", mdoc->meta.vol);
352 mdoc_msg(mdoc, "arch: <unset>");
353 mdoc_msg(mdoc, "msec: %d", mdoc->meta.msec);
354 return(post_prologue(mdoc));
355 }
356
357 /* Handles: `.Dt TITLE SEC'
358 * --> title = TITLE, volume = SEC is msec ?
359 * format(msec) : SEC,
360 * msec = SEC is msec ? atoi(msec) : 0,
361 * arch = NULL
362 */
363
364 if ((cp = mdoc_a2msec(n->string))) {
365 mdoc->meta.vol = xstrdup(cp);
366 errno = 0;
367 lval = strtol(n->string, &ep, 10);
368 if (n->string[0] != '\0' && *ep == '\0')
369 mdoc->meta.msec = (int)lval;
370 } else
371 mdoc->meta.vol = xstrdup(n->string);
372
373 if (NULL == (n = n->next)) {
374 mdoc_msg(mdoc, "volume: %s", mdoc->meta.vol);
375 mdoc_msg(mdoc, "arch: <unset>");
376 mdoc_msg(mdoc, "msec: %d", mdoc->meta.msec);
377 return(post_prologue(mdoc));
378 }
379
380 /* Handles: `.Dt TITLE SEC VOL'
381 * --> title = TITLE, volume = VOL is vol ?
382 * format(VOL) :
383 * VOL is arch ? format(arch) :
384 * VOL
385 */
386
387 if ((cp = mdoc_a2vol(n->string))) {
388 free(mdoc->meta.vol);
389 mdoc->meta.vol = xstrdup(cp);
390 n = n->next;
391 } else {
392 cp = mdoc_a2arch(n->string);
393 if (NULL == cp) {
394 free(mdoc->meta.vol);
395 mdoc->meta.vol = xstrdup(n->string);
396 } else
397 mdoc->meta.arch = xstrdup(cp);
398 }
399
400 mdoc_msg(mdoc, "volume: %s", mdoc->meta.vol);
401 mdoc_msg(mdoc, "arch: %s", mdoc->meta.arch ?
402 mdoc->meta.arch : "<unset>");
403 mdoc_msg(mdoc, "msec: %d", mdoc->meta.msec);
404
405 /* Ignore any subsequent parameters... */
406
407 return(post_prologue(mdoc));
408 }
409
410
411 static int
412 post_os(struct mdoc *mdoc)
413 {
414 char buf[64];
415 struct utsname utsname;
416
417 if (mdoc->meta.os)
418 free(mdoc->meta.os);
419
420 (void)xstrlcpys(buf, mdoc->last->child, sizeof(buf));
421
422 if (0 == buf[0]) {
423 if (-1 == uname(&utsname))
424 return(mdoc_err(mdoc, "utsname"));
425 (void)xstrlcpy(buf, utsname.sysname, sizeof(buf));
426 (void)xstrlcat(buf, " ", sizeof(buf));
427 (void)xstrlcat(buf, utsname.release, sizeof(buf));
428 }
429
430 mdoc->meta.os = xstrdup(buf);
431 mdoc_msg(mdoc, "system: %s", mdoc->meta.os);
432
433 mdoc->lastnamed = mdoc->lastsec = SEC_BODY;
434
435 return(post_prologue(mdoc));
436 }
437
438
439 static int
440 post_bl_tagwidth(struct mdoc *mdoc)
441 {
442 struct mdoc_node *n;
443 int sz;
444 char buf[32];
445
446 /*
447 * If -tag has been specified and -width has not been, then try
448 * to intuit our width from the first body element.
449 */
450
451 if (NULL == (n = mdoc->last->body->child))
452 return(1);
453
454 /*
455 * Use the text width, if a text node, or the default macro
456 * width if a macro.
457 */
458
459 if ((n = n->head->child)) {
460 if (MDOC_TEXT != n->type) {
461 if (0 == (sz = (int)mdoc_macro2len(n->tok)))
462 sz = -1;
463 } else
464 sz = (int)strlen(n->string) + 1;
465 } else
466 sz = -1;
467
468 if (-1 == sz) {
469 if ( ! mwarn(mdoc, WNOWIDTH))
470 return(0);
471 sz = 10;
472 }
473
474 (void)snprintf(buf, sizeof(buf), "%dn", sz);
475
476 /*
477 * We have to dynamically add this to the macro's argument list.
478 * We're guaranteed that a MDOC_Width doesn't already exist.
479 */
480
481 if (NULL == mdoc->last->args) {
482 mdoc->last->args = xcalloc
483 (1, sizeof(struct mdoc_arg));
484 mdoc->last->args->refcnt = 1;
485 }
486
487 n = mdoc->last;
488 sz = (int)n->args->argc;
489
490 (n->args->argc)++;
491
492 n->args->argv = xrealloc(n->args->argv,
493 n->args->argc * sizeof(struct mdoc_arg));
494
495 n->args->argv[sz - 1].arg = MDOC_Width;
496 n->args->argv[sz - 1].line = mdoc->last->line;
497 n->args->argv[sz - 1].pos = mdoc->last->pos;
498 n->args->argv[sz - 1].sz = 1;
499 n->args->argv[sz - 1].value = xcalloc(1, sizeof(char *));
500 n->args->argv[sz - 1].value[0] = xstrdup(buf);
501
502 mdoc_msg(mdoc, "adding %s argument: %s",
503 mdoc_argnames[MDOC_Width], buf);
504
505 return(1);
506 }
507
508
509 static int
510 post_bl_width(struct mdoc *m)
511 {
512 size_t width;
513 int i, tok;
514 char buf[32];
515 char *p;
516
517 if (NULL == m->last->args)
518 return(merr(m, ENOWIDTH));
519
520 for (i = 0; i < (int)m->last->args->argc; i++)
521 if (MDOC_Width == m->last->args->argv[i].arg)
522 break;
523
524 if (i == (int)m->last->args->argc)
525 return(merr(m, ENOWIDTH));
526
527 p = m->last->args->argv[i].value[0];
528
529 /*
530 * If the value to -width is a macro, then we re-write it to be
531 * the macro's width as set in share/tmac/mdoc/doc-common.
532 */
533
534 if (xstrcmp(p, "Ds"))
535 width = 8;
536 else if (MDOC_MAX == (tok = mdoc_tokhash_find(m->htab, p)))
537 return(1);
538 else if (0 == (width = mdoc_macro2len(tok)))
539 return(mwarn(m, WNOWIDTH));
540
541 mdoc_msg(m, "re-writing %s argument: %s -> %zun",
542 mdoc_argnames[MDOC_Width], p, width);
543
544 /* The value already exists: free and reallocate it. */
545
546 (void)snprintf(buf, sizeof(buf), "%zun", width);
547
548 free(m->last->args->argv[i].value[0]);
549 m->last->args->argv[i].value[0] = xstrdup(buf);
550
551 return(1);
552 }
553
554
555 static int
556 post_bl(struct mdoc *mdoc)
557 {
558 int i, r, len;
559
560 if (MDOC_BLOCK != mdoc->last->type)
561 return(1);
562
563 /*
564 * These are fairly complicated, so we've broken them into two
565 * functions. post_bl_tagwidth() is called when a -tag is
566 * specified, but no -width (it must be guessed). The second
567 * when a -width is specified (macro indicators must be
568 * rewritten into real lengths).
569 */
570
571 len = (int)(mdoc->last->args ? mdoc->last->args->argc : 0);
572
573 for (r = i = 0; i < len; i++) {
574 if (MDOC_Tag == mdoc->last->args->argv[i].arg)
575 r |= 1 << 0;
576 if (MDOC_Width == mdoc->last->args->argv[i].arg)
577 r |= 1 << 1;
578 }
579
580 if (r & (1 << 0) && ! (r & (1 << 1))) {
581 if ( ! post_bl_tagwidth(mdoc))
582 return(0);
583 } else if (r & (1 << 1))
584 if ( ! post_bl_width(mdoc))
585 return(0);
586
587 return(1);
588 }
589
590
591 static int
592 post_ar(struct mdoc *mdoc)
593 {
594 struct mdoc_node *n;
595
596 if (mdoc->last->child)
597 return(1);
598
599 n = mdoc->last;
600
601 mdoc->next = MDOC_NEXT_CHILD;
602 if ( ! mdoc_word_alloc(mdoc, mdoc->last->line,
603 mdoc->last->pos, "file"))
604 return(0);
605 mdoc->next = MDOC_NEXT_SIBLING;
606 if ( ! mdoc_word_alloc(mdoc, mdoc->last->line,
607 mdoc->last->pos, "..."))
608 return(0);
609
610 mdoc->last = n;
611 mdoc->next = MDOC_NEXT_SIBLING;
612 return(1);
613 }
614
615
616 static int
617 post_dd(struct mdoc *mdoc)
618 {
619 char buf[64];
620
621 (void)xstrlcpys(buf, mdoc->last->child, sizeof(buf));
622
623 if (0 == (mdoc->meta.date = mdoc_atotime(buf))) {
624 if ( ! mwarn(mdoc, WBADDATE))
625 return(0);
626 mdoc->meta.date = time(NULL);
627 }
628
629 mdoc_msg(mdoc, "date: %u", mdoc->meta.date);
630 return(post_prologue(mdoc));
631 }
632
633
634 static int
635 post_prologue(struct mdoc *mdoc)
636 {
637 struct mdoc_node *n;
638
639 /*
640 * The end document shouldn't have the prologue macros as part
641 * of the syntax tree (they encompass only meta-data).
642 */
643
644 if (mdoc->last->parent->child == mdoc->last)
645 mdoc->last->parent->child = mdoc->last->prev;
646 if (mdoc->last->prev)
647 mdoc->last->prev->next = NULL;
648
649 n = mdoc->last;
650 assert(NULL == mdoc->last->next);
651
652 if (mdoc->last->prev) {
653 mdoc->last = mdoc->last->prev;
654 mdoc->next = MDOC_NEXT_SIBLING;
655 } else {
656 mdoc->last = mdoc->last->parent;
657 mdoc->next = MDOC_NEXT_CHILD;
658 }
659
660 mdoc_node_freelist(n);
661 return(1);
662 }
663
664
665 int
666 mdoc_action_post(struct mdoc *mdoc)
667 {
668
669 if (MDOC_ACTED & mdoc->last->flags)
670 return(1);
671 mdoc->last->flags |= MDOC_ACTED;
672
673 if (MDOC_TEXT == mdoc->last->type)
674 return(1);
675 if (MDOC_ROOT == mdoc->last->type)
676 return(1);
677 if (NULL == mdoc_actions[mdoc->last->tok].post)
678 return(1);
679 return((*mdoc_actions[mdoc->last->tok].post)(mdoc));
680 }