]> git.cameronkatri.com Git - mandoc.git/blob - mdoc_action.c
Migrate `Nm' and `Pa' handling from mdoc_action.c into mdoc_validate.c.
[mandoc.git] / mdoc_action.c
1 /* $Id: mdoc_action.c,v 1.85 2010/11/29 16:06:46 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
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 above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #ifndef OSNAME
22 #include <sys/utsname.h>
23 #endif
24
25 #include <assert.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <time.h>
30
31 #include "mandoc.h"
32 #include "libmdoc.h"
33 #include "libmandoc.h"
34
35 /*
36 * FIXME: this file is deprecated. All future "actions" should be
37 * pushed into mdoc_validate.c.
38 */
39
40 #define POST_ARGS struct mdoc *m, struct mdoc_node *n
41 #define PRE_ARGS struct mdoc *m, struct mdoc_node *n
42
43 #define NUMSIZ 32
44 #define DATESIZ 32
45
46 struct actions {
47 int (*pre)(PRE_ARGS);
48 int (*post)(POST_ARGS);
49 };
50
51 static int concat(struct mdoc *, char *,
52 const struct mdoc_node *, size_t);
53
54 static int post_bl(POST_ARGS);
55 static int post_bl_head(POST_ARGS);
56 static int post_bl_tagwidth(POST_ARGS);
57 static int post_bl_width(POST_ARGS);
58 static int post_dd(POST_ARGS);
59 static int post_dt(POST_ARGS);
60 static int post_os(POST_ARGS);
61 static int post_prol(POST_ARGS);
62 static int post_std(POST_ARGS);
63
64 static const struct actions mdoc_actions[MDOC_MAX] = {
65 { NULL, NULL }, /* Ap */
66 { NULL, post_dd }, /* Dd */
67 { NULL, post_dt }, /* Dt */
68 { NULL, post_os }, /* Os */
69 { NULL, NULL }, /* Sh */
70 { NULL, NULL }, /* Ss */
71 { NULL, NULL }, /* Pp */
72 { NULL, NULL }, /* D1 */
73 { NULL, NULL }, /* Dl */
74 { NULL, NULL }, /* Bd */
75 { NULL, NULL }, /* Ed */
76 { NULL, post_bl }, /* Bl */
77 { NULL, NULL }, /* El */
78 { NULL, NULL }, /* It */
79 { NULL, NULL }, /* Ad */
80 { NULL, NULL }, /* An */
81 { NULL, NULL }, /* Ar */
82 { NULL, NULL }, /* Cd */
83 { NULL, NULL }, /* Cm */
84 { NULL, NULL }, /* Dv */
85 { NULL, NULL }, /* Er */
86 { NULL, NULL }, /* Ev */
87 { NULL, post_std }, /* Ex */
88 { NULL, NULL }, /* Fa */
89 { NULL, NULL }, /* Fd */
90 { NULL, NULL }, /* Fl */
91 { NULL, NULL }, /* Fn */
92 { NULL, NULL }, /* Ft */
93 { NULL, NULL }, /* Ic */
94 { NULL, NULL }, /* In */
95 { NULL, NULL }, /* Li */
96 { NULL, NULL }, /* Nd */
97 { NULL, NULL }, /* Nm */
98 { NULL, NULL }, /* Op */
99 { NULL, NULL }, /* Ot */
100 { NULL, NULL }, /* Pa */
101 { NULL, post_std }, /* Rv */
102 { NULL, NULL }, /* St */
103 { NULL, NULL }, /* Va */
104 { NULL, NULL }, /* Vt */
105 { NULL, NULL }, /* Xr */
106 { NULL, NULL }, /* %A */
107 { NULL, NULL }, /* %B */
108 { NULL, NULL }, /* %D */
109 { NULL, NULL }, /* %I */
110 { NULL, NULL }, /* %J */
111 { NULL, NULL }, /* %N */
112 { NULL, NULL }, /* %O */
113 { NULL, NULL }, /* %P */
114 { NULL, NULL }, /* %R */
115 { NULL, NULL }, /* %T */
116 { NULL, NULL }, /* %V */
117 { NULL, NULL }, /* Ac */
118 { NULL, NULL }, /* Ao */
119 { NULL, NULL }, /* Aq */
120 { NULL, NULL }, /* At */
121 { NULL, NULL }, /* Bc */
122 { NULL, NULL }, /* Bf */
123 { NULL, NULL }, /* Bo */
124 { NULL, NULL }, /* Bq */
125 { NULL, NULL }, /* Bsx */
126 { NULL, NULL }, /* Bx */
127 { NULL, NULL }, /* Db */
128 { NULL, NULL }, /* Dc */
129 { NULL, NULL }, /* Do */
130 { NULL, NULL }, /* Dq */
131 { NULL, NULL }, /* Ec */
132 { NULL, NULL }, /* Ef */
133 { NULL, NULL }, /* Em */
134 { NULL, NULL }, /* Eo */
135 { NULL, NULL }, /* Fx */
136 { NULL, NULL }, /* Ms */
137 { NULL, NULL }, /* No */
138 { NULL, NULL }, /* Ns */
139 { NULL, NULL }, /* Nx */
140 { NULL, NULL }, /* Ox */
141 { NULL, NULL }, /* Pc */
142 { NULL, NULL }, /* Pf */
143 { NULL, NULL }, /* Po */
144 { NULL, NULL }, /* Pq */
145 { NULL, NULL }, /* Qc */
146 { NULL, NULL }, /* Ql */
147 { NULL, NULL }, /* Qo */
148 { NULL, NULL }, /* Qq */
149 { NULL, NULL }, /* Re */
150 { NULL, NULL }, /* Rs */
151 { NULL, NULL }, /* Sc */
152 { NULL, NULL }, /* So */
153 { NULL, NULL }, /* Sq */
154 { NULL, NULL }, /* Sm */
155 { NULL, NULL }, /* Sx */
156 { NULL, NULL }, /* Sy */
157 { NULL, NULL }, /* Tn */
158 { NULL, NULL }, /* Ux */
159 { NULL, NULL }, /* Xc */
160 { NULL, NULL }, /* Xo */
161 { NULL, NULL }, /* Fo */
162 { NULL, NULL }, /* Fc */
163 { NULL, NULL }, /* Oo */
164 { NULL, NULL }, /* Oc */
165 { NULL, NULL }, /* Bk */
166 { NULL, NULL }, /* Ek */
167 { NULL, NULL }, /* Bt */
168 { NULL, NULL }, /* Hf */
169 { NULL, NULL }, /* Fr */
170 { NULL, NULL }, /* Ud */
171 { NULL, NULL }, /* Lb */
172 { NULL, NULL }, /* Lp */
173 { NULL, NULL }, /* Lk */
174 { NULL, NULL }, /* Mt */
175 { NULL, NULL }, /* Brq */
176 { NULL, NULL }, /* Bro */
177 { NULL, NULL }, /* Brc */
178 { NULL, NULL }, /* %C */
179 { NULL, NULL }, /* Es */
180 { NULL, NULL }, /* En */
181 { NULL, NULL }, /* Dx */
182 { NULL, NULL }, /* %Q */
183 { NULL, NULL }, /* br */
184 { NULL, NULL }, /* sp */
185 { NULL, NULL }, /* %U */
186 { NULL, NULL }, /* Ta */
187 };
188
189
190 int
191 mdoc_action_pre(struct mdoc *m, struct mdoc_node *n)
192 {
193
194 switch (n->type) {
195 case (MDOC_ROOT):
196 /* FALLTHROUGH */
197 case (MDOC_TEXT):
198 return(1);
199 default:
200 break;
201 }
202
203 if (NULL == mdoc_actions[n->tok].pre)
204 return(1);
205 return((*mdoc_actions[n->tok].pre)(m, n));
206 }
207
208
209 int
210 mdoc_action_post(struct mdoc *m)
211 {
212
213 if (MDOC_ACTED & m->last->flags)
214 return(1);
215 m->last->flags |= MDOC_ACTED;
216
217 switch (m->last->type) {
218 case (MDOC_TEXT):
219 /* FALLTHROUGH */
220 case (MDOC_ROOT):
221 return(1);
222 default:
223 break;
224 }
225
226 if (NULL == mdoc_actions[m->last->tok].post)
227 return(1);
228 return((*mdoc_actions[m->last->tok].post)(m, m->last));
229 }
230
231
232 /*
233 * Concatenate sibling nodes together. All siblings must be of type
234 * MDOC_TEXT or an assertion is raised. Concatenation is separated by a
235 * single whitespace.
236 */
237 static int
238 concat(struct mdoc *m, char *p, const struct mdoc_node *n, size_t sz)
239 {
240
241 assert(sz);
242 p[0] = '\0';
243 for ( ; n; n = n->next) {
244 assert(MDOC_TEXT == n->type);
245 /*
246 * XXX: yes, these can technically be resized, but it's
247 * highly unlikely that we're going to get here, so let
248 * it slip for now.
249 */
250 if (strlcat(p, n->string, sz) >= sz) {
251 mdoc_nmsg(m, n, MANDOCERR_MEM);
252 return(0);
253 }
254 if (NULL == n->next)
255 continue;
256 if (strlcat(p, " ", sz) >= sz) {
257 mdoc_nmsg(m, n, MANDOCERR_MEM);
258 return(0);
259 }
260 }
261
262 return(1);
263 }
264
265
266 /*
267 * Macros accepting `-std' as an argument have the name of the current
268 * document (`Nm') filled in as the argument if it's not provided.
269 */
270 static int
271 post_std(POST_ARGS)
272 {
273 struct mdoc_node *nn;
274
275 if (n->child)
276 return(1);
277 if (NULL == m->meta.name)
278 return(1);
279
280 nn = n;
281 m->next = MDOC_NEXT_CHILD;
282
283 if ( ! mdoc_word_alloc(m, n->line, n->pos, m->meta.name))
284 return(0);
285 m->last = nn;
286 return(1);
287 }
288
289 /*
290 * Parse out the contents of `Dt'. See in-line documentation for how we
291 * handle the various fields of this macro.
292 */
293 static int
294 post_dt(POST_ARGS)
295 {
296 struct mdoc_node *nn;
297 const char *cp;
298
299 if (m->meta.title)
300 free(m->meta.title);
301 if (m->meta.vol)
302 free(m->meta.vol);
303 if (m->meta.arch)
304 free(m->meta.arch);
305
306 m->meta.title = m->meta.vol = m->meta.arch = NULL;
307 /* Handles: `.Dt'
308 * --> title = unknown, volume = local, msec = 0, arch = NULL
309 */
310
311 if (NULL == (nn = n->child)) {
312 /* XXX: make these macro values. */
313 /* FIXME: warn about missing values. */
314 m->meta.title = mandoc_strdup("UNKNOWN");
315 m->meta.vol = mandoc_strdup("LOCAL");
316 m->meta.msec = mandoc_strdup("1");
317 return(post_prol(m, n));
318 }
319
320 /* Handles: `.Dt TITLE'
321 * --> title = TITLE, volume = local, msec = 0, arch = NULL
322 */
323
324 m->meta.title = mandoc_strdup
325 ('\0' == nn->string[0] ? "UNKNOWN" : nn->string);
326
327 if (NULL == (nn = nn->next)) {
328 /* FIXME: warn about missing msec. */
329 /* XXX: make this a macro value. */
330 m->meta.vol = mandoc_strdup("LOCAL");
331 m->meta.msec = mandoc_strdup("1");
332 return(post_prol(m, n));
333 }
334
335 /* Handles: `.Dt TITLE SEC'
336 * --> title = TITLE, volume = SEC is msec ?
337 * format(msec) : SEC,
338 * msec = SEC is msec ? atoi(msec) : 0,
339 * arch = NULL
340 */
341
342 cp = mdoc_a2msec(nn->string);
343 if (cp) {
344 m->meta.vol = mandoc_strdup(cp);
345 m->meta.msec = mandoc_strdup(nn->string);
346 } else if (mdoc_nmsg(m, n, MANDOCERR_BADMSEC)) {
347 m->meta.vol = mandoc_strdup(nn->string);
348 m->meta.msec = mandoc_strdup(nn->string);
349 } else
350 return(0);
351
352 if (NULL == (nn = nn->next))
353 return(post_prol(m, n));
354
355 /* Handles: `.Dt TITLE SEC VOL'
356 * --> title = TITLE, volume = VOL is vol ?
357 * format(VOL) :
358 * VOL is arch ? format(arch) :
359 * VOL
360 */
361
362 cp = mdoc_a2vol(nn->string);
363 if (cp) {
364 free(m->meta.vol);
365 m->meta.vol = mandoc_strdup(cp);
366 } else {
367 /* FIXME: warn about bad arch. */
368 cp = mdoc_a2arch(nn->string);
369 if (NULL == cp) {
370 free(m->meta.vol);
371 m->meta.vol = mandoc_strdup(nn->string);
372 } else
373 m->meta.arch = mandoc_strdup(cp);
374 }
375
376 /* Ignore any subsequent parameters... */
377 /* FIXME: warn about subsequent parameters. */
378
379 return(post_prol(m, n));
380 }
381
382
383 /*
384 * Set the operating system by way of the `Os' macro. Note that if an
385 * argument isn't provided and -DOSNAME="\"foo\"" is provided during
386 * compilation, this value will be used instead of filling in "sysname
387 * release" from uname().
388 */
389 static int
390 post_os(POST_ARGS)
391 {
392 char buf[BUFSIZ];
393 #ifndef OSNAME
394 struct utsname utsname;
395 #endif
396
397 if (m->meta.os)
398 free(m->meta.os);
399
400 if ( ! concat(m, buf, n->child, BUFSIZ))
401 return(0);
402
403 /* XXX: yes, these can all be dynamically-adjusted buffers, but
404 * it's really not worth the extra hackery.
405 */
406
407 if ('\0' == buf[0]) {
408 #ifdef OSNAME
409 if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) {
410 mdoc_nmsg(m, n, MANDOCERR_MEM);
411 return(0);
412 }
413 #else /*!OSNAME */
414 if (-1 == uname(&utsname))
415 return(mdoc_nmsg(m, n, MANDOCERR_UTSNAME));
416
417 if (strlcat(buf, utsname.sysname, BUFSIZ) >= BUFSIZ) {
418 mdoc_nmsg(m, n, MANDOCERR_MEM);
419 return(0);
420 }
421 if (strlcat(buf, " ", 64) >= BUFSIZ) {
422 mdoc_nmsg(m, n, MANDOCERR_MEM);
423 return(0);
424 }
425 if (strlcat(buf, utsname.release, BUFSIZ) >= BUFSIZ) {
426 mdoc_nmsg(m, n, MANDOCERR_MEM);
427 return(0);
428 }
429 #endif /*!OSNAME*/
430 }
431
432 m->meta.os = mandoc_strdup(buf);
433 return(post_prol(m, n));
434 }
435
436
437 /*
438 * Calculate the -width for a `Bl -tag' list if it hasn't been provided.
439 * Uses the first head macro. NOTE AGAIN: this is ONLY if the -width
440 * argument has NOT been provided. See post_bl_width() for converting
441 * the -width string.
442 */
443 static int
444 post_bl_tagwidth(POST_ARGS)
445 {
446 struct mdoc_node *nn;
447 size_t sz, ssz;
448 int i;
449 char buf[NUMSIZ];
450
451 sz = 10;
452
453 for (nn = n->body->child; nn; nn = nn->next) {
454 if (MDOC_It != nn->tok)
455 continue;
456
457 assert(MDOC_BLOCK == nn->type);
458 nn = nn->head->child;
459
460 if (nn == NULL) {
461 /* No -width for .Bl and first .It is emtpy */
462 if ( ! mdoc_nmsg(m, n, MANDOCERR_NOWIDTHARG))
463 return(0);
464 break;
465 }
466
467 if (MDOC_TEXT == nn->type) {
468 sz = strlen(nn->string) + 1;
469 break;
470 }
471
472 if (0 != (ssz = mdoc_macro2len(nn->tok)))
473 sz = ssz;
474 else if ( ! mdoc_nmsg(m, n, MANDOCERR_NOWIDTHARG))
475 return(0);
476
477 break;
478 }
479
480 /* Defaults to ten ens. */
481
482 snprintf(buf, NUMSIZ, "%zun", sz);
483
484 /*
485 * We have to dynamically add this to the macro's argument list.
486 * We're guaranteed that a MDOC_Width doesn't already exist.
487 */
488
489 assert(n->args);
490 i = (int)(n->args->argc)++;
491
492 n->args->argv = mandoc_realloc(n->args->argv,
493 n->args->argc * sizeof(struct mdoc_argv));
494
495 n->args->argv[i].arg = MDOC_Width;
496 n->args->argv[i].line = n->line;
497 n->args->argv[i].pos = n->pos;
498 n->args->argv[i].sz = 1;
499 n->args->argv[i].value = mandoc_malloc(sizeof(char *));
500 n->args->argv[i].value[0] = mandoc_strdup(buf);
501
502 /* Set our width! */
503 n->data.Bl->width = n->args->argv[i].value[0];
504 return(1);
505 }
506
507
508 /*
509 * Calculate the real width of a list from the -width string, which may
510 * contain a macro (with a known default width), a literal string, or a
511 * scaling width.
512 */
513 static int
514 post_bl_width(POST_ARGS)
515 {
516 size_t width;
517 int i;
518 enum mdoct tok;
519 char buf[NUMSIZ];
520
521 /*
522 * If the value to -width is a macro, then we re-write it to be
523 * the macro's width as set in share/tmac/mdoc/doc-common.
524 */
525
526 if (0 == strcmp(n->data.Bl->width, "Ds"))
527 width = 6;
528 else if (MDOC_MAX == (tok = mdoc_hash_find(n->data.Bl->width)))
529 return(1);
530 else if (0 == (width = mdoc_macro2len(tok)))
531 return(mdoc_nmsg(m, n, MANDOCERR_BADWIDTH));
532
533 /* The value already exists: free and reallocate it. */
534
535 assert(n->args);
536
537 for (i = 0; i < (int)n->args->argc; i++)
538 if (MDOC_Width == n->args->argv[i].arg)
539 break;
540
541 assert(i < (int)n->args->argc);
542
543 snprintf(buf, NUMSIZ, "%zun", width);
544 free(n->args->argv[i].value[0]);
545 n->args->argv[i].value[0] = mandoc_strdup(buf);
546
547 /* Set our width! */
548 n->data.Bl->width = n->args->argv[i].value[0];
549 return(1);
550 }
551
552
553 /*
554 * Do processing for -column lists, which can have two distinct styles
555 * of invocation. Merge this two styles into a consistent form.
556 */
557 /* ARGSUSED */
558 static int
559 post_bl_head(POST_ARGS)
560 {
561 int i, c;
562 struct mdoc_node *np, *nn, *nnp;
563
564 if (LIST_column != n->data.Bl->type)
565 return(1);
566 else if (NULL == n->child)
567 return(1);
568
569 np = n->parent;
570 assert(np->args);
571
572 for (c = 0; c < (int)np->args->argc; c++)
573 if (MDOC_Column == np->args->argv[c].arg)
574 break;
575
576 assert(c < (int)np->args->argc);
577 assert(0 == np->args->argv[c].sz);
578
579 /*
580 * Accomodate for new-style groff column syntax. Shuffle the
581 * child nodes, all of which must be TEXT, as arguments for the
582 * column field. Then, delete the head children.
583 */
584
585 np->args->argv[c].sz = (size_t)n->nchild;
586 np->args->argv[c].value = mandoc_malloc
587 ((size_t)n->nchild * sizeof(char *));
588
589 n->data.Bl->ncols = np->args->argv[c].sz;
590 n->data.Bl->cols = (const char **)np->args->argv[c].value;
591
592 for (i = 0, nn = n->child; nn; i++) {
593 np->args->argv[c].value[i] = nn->string;
594 nn->string = NULL;
595 nnp = nn;
596 nn = nn->next;
597 mdoc_node_delete(NULL, nnp);
598 }
599
600 n->nchild = 0;
601 n->child = NULL;
602 return(1);
603 }
604
605
606 static int
607 post_bl(POST_ARGS)
608 {
609
610 if (MDOC_HEAD == n->type)
611 return(post_bl_head(m, n));
612 if (MDOC_BLOCK != n->type)
613 return(1);
614
615 /*
616 * These are fairly complicated, so we've broken them into two
617 * functions. post_bl_tagwidth() is called when a -tag is
618 * specified, but no -width (it must be guessed). The second
619 * when a -width is specified (macro indicators must be
620 * rewritten into real lengths).
621 */
622
623 if (LIST_tag == n->data.Bl->type && NULL == n->data.Bl->width) {
624 if ( ! post_bl_tagwidth(m, n))
625 return(0);
626 } else if (NULL != n->data.Bl->width) {
627 if ( ! post_bl_width(m, n))
628 return(0);
629 } else
630 return(1);
631
632 assert(n->data.Bl->width);
633 return(1);
634 }
635
636 /*
637 * Parse the date field in `Dd'.
638 */
639 static int
640 post_dd(POST_ARGS)
641 {
642 char buf[DATESIZ];
643
644 if (NULL == n->child) {
645 m->meta.date = time(NULL);
646 return(post_prol(m, n));
647 }
648
649 if ( ! concat(m, buf, n->child, DATESIZ))
650 return(0);
651
652 m->meta.date = mandoc_a2time
653 (MTIME_MDOCDATE | MTIME_CANONICAL, buf);
654
655 if (0 == m->meta.date) {
656 if ( ! mdoc_nmsg(m, n, MANDOCERR_BADDATE))
657 return(0);
658 m->meta.date = time(NULL);
659 }
660
661 return(post_prol(m, n));
662 }
663
664
665 /*
666 * Remove prologue macros from the document after they're processed.
667 * The final document uses mdoc_meta for these values and discards the
668 * originals.
669 */
670 static int
671 post_prol(POST_ARGS)
672 {
673
674 mdoc_node_delete(m, n);
675 if (m->meta.title && m->meta.date && m->meta.os)
676 m->flags |= MDOC_PBODY;
677 return(1);
678 }