]> git.cameronkatri.com Git - mandoc.git/blob - action.c
Noted lacking areas in mdocterm.1.
[mandoc.git] / action.c
1 /* $Id: action.c,v 1.28 2009/03/01 23:14:15 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 <assert.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <time.h>
24
25 #include "private.h"
26
27 /*
28 * Actions are executed on macros after they've been post-validated: in
29 * other words, a macro will not be "acted upon" until all of its
30 * children have been filled in (post-fix order).
31 */
32
33 struct actions {
34 int (*post)(struct mdoc *);
35 };
36
37 /* Per-macro action routines. */
38
39 static int post_bl(struct mdoc *);
40 static int post_bl_width(struct mdoc *);
41 static int post_bl_tagwidth(struct mdoc *);
42 static int post_sh(struct mdoc *);
43 static int post_os(struct mdoc *);
44 static int post_dt(struct mdoc *);
45 static int post_dd(struct mdoc *);
46 static int post_nm(struct mdoc *);
47
48 static int post_prologue(struct mdoc *);
49
50 /* Array of macro action routines. */
51
52 const struct actions mdoc_actions[MDOC_MAX] = {
53 { NULL }, /* \" */
54 { post_dd }, /* Dd */
55 { post_dt }, /* Dt */
56 { post_os }, /* Os */
57 { post_sh }, /* Sh */
58 { NULL }, /* Ss */
59 { NULL }, /* Pp */
60 { NULL }, /* D1 */
61 { NULL }, /* Dl */
62 { NULL }, /* Bd */
63 { NULL }, /* Ed */
64 { post_bl }, /* Bl */
65 { NULL }, /* El */
66 { NULL }, /* It */
67 { NULL }, /* Ad */
68 { NULL }, /* An */
69 { NULL }, /* Ar */
70 { NULL }, /* Cd */
71 { NULL }, /* Cm */
72 { NULL }, /* Dv */
73 { NULL }, /* Er */
74 { NULL }, /* Ev */
75 { NULL }, /* Ex */
76 { NULL }, /* Fa */
77 { NULL }, /* Fd */
78 { NULL }, /* Fl */
79 { NULL }, /* Fn */
80 { NULL }, /* Ft */
81 { NULL }, /* Ic */
82 { NULL }, /* In */
83 { NULL }, /* Li */
84 { NULL }, /* Nd */
85 { post_nm }, /* Nm */
86 { NULL }, /* Op */
87 { NULL }, /* Ot */
88 { NULL }, /* Pa */
89 { NULL }, /* Rv */
90 { NULL }, /* St */
91 { NULL }, /* Va */
92 { NULL }, /* Vt */
93 { NULL }, /* Xr */
94 { NULL }, /* %A */
95 { NULL }, /* %B */
96 { NULL }, /* %D */
97 { NULL }, /* %I */
98 { NULL }, /* %J */
99 { NULL }, /* %N */
100 { NULL }, /* %O */
101 { NULL }, /* %P */
102 { NULL }, /* %R */
103 { NULL }, /* %T */
104 { NULL }, /* %V */
105 { NULL }, /* Ac */
106 { NULL }, /* Ao */
107 { NULL }, /* Aq */
108 { NULL }, /* At */
109 { NULL }, /* Bc */
110 { NULL }, /* Bf */
111 { NULL }, /* Bo */
112 { NULL }, /* Bq */
113 { NULL }, /* Bsx */
114 { NULL }, /* Bx */
115 { NULL }, /* Db */
116 { NULL }, /* Dc */
117 { NULL }, /* Do */
118 { NULL }, /* Dq */
119 { NULL }, /* Ec */
120 { NULL }, /* Ef */
121 { NULL }, /* Em */
122 { NULL }, /* Eo */
123 { NULL }, /* Fx */
124 { NULL }, /* Ms */
125 { NULL }, /* No */
126 { NULL }, /* Ns */
127 { NULL }, /* Nx */
128 { NULL }, /* Ox */
129 { NULL }, /* Pc */
130 { NULL }, /* Pf */
131 { NULL }, /* Po */
132 { NULL }, /* Pq */
133 { NULL }, /* Qc */
134 { NULL }, /* Ql */
135 { NULL }, /* Qo */
136 { NULL }, /* Qq */
137 { NULL }, /* Re */
138 { NULL }, /* Rs */
139 { NULL }, /* Sc */
140 { NULL }, /* So */
141 { NULL }, /* Sq */
142 { NULL }, /* Sm */
143 { NULL }, /* Sx */
144 { NULL }, /* Sy */
145 { NULL }, /* Tn */
146 { NULL }, /* Ux */
147 { NULL }, /* Xc */
148 { NULL }, /* Xo */
149 { NULL }, /* Fo */
150 { NULL }, /* Fc */
151 { NULL }, /* Oo */
152 { NULL }, /* Oc */
153 { NULL }, /* Bk */
154 { NULL }, /* Ek */
155 { NULL }, /* Bt */
156 { NULL }, /* Hf */
157 { NULL }, /* Fr */
158 { NULL }, /* Ud */
159 };
160
161
162 static int
163 post_nm(struct mdoc *mdoc)
164 {
165 char buf[64];
166
167 assert(MDOC_ELEM == mdoc->last->type);
168 assert(MDOC_Nm == mdoc->last->tok);
169
170 /*
171 * The `Nm' macro sets the document's name when used the first
172 * time with an argument. Subsequent calls without a value will
173 * result in the name value being used.
174 */
175
176 if (mdoc->meta.name)
177 return(1);
178
179 if (xstrlcats(buf, mdoc->last->child, 64)) {
180 mdoc->meta.name = xstrdup(buf);
181 return(1);
182 }
183
184 return(mdoc_err(mdoc, "macro parameters too long"));
185 }
186
187
188 static int
189 post_sh(struct mdoc *mdoc)
190 {
191 enum mdoc_sec sec;
192 char buf[64];
193
194 /*
195 * We keep track of the current section /and/ the "named"
196 * section, which is one of the conventional ones, in order to
197 * check ordering.
198 */
199
200 if (MDOC_HEAD != mdoc->last->type)
201 return(1);
202 if (xstrlcats(buf, mdoc->last->child, 64)) {
203 if (SEC_CUSTOM != (sec = mdoc_atosec(buf)))
204 mdoc->lastnamed = sec;
205 mdoc->lastsec = sec;
206 } else
207 return(mdoc_err(mdoc, "parameters too long"));
208
209 switch (mdoc->lastsec) {
210 case (SEC_RETURN_VALUES):
211 /* FALLTHROUGH */
212 case (SEC_ERRORS):
213 switch (mdoc->meta.msec) {
214 case (MSEC_2):
215 /* FALLTHROUGH */
216 case (MSEC_3):
217 /* FALLTHROUGH */
218 case (MSEC_9):
219 break;
220 default:
221 return(mdoc_warn(mdoc, WARN_COMPAT,
222 "inappropriate section for "
223 "manual section"));
224 }
225 break;
226 default:
227 break;
228 }
229 return(1);
230 }
231
232
233 static int
234 post_dt(struct mdoc *mdoc)
235 {
236 int i;
237 char *p;
238 struct mdoc_node *n;
239
240 /*
241 * Prologue title must be parsed into document meta-data.
242 */
243
244 assert(MDOC_ELEM == mdoc->last->type);
245 assert(MDOC_Dt == mdoc->last->tok);
246
247 assert(NULL == mdoc->meta.title);
248
249 /* LINTED */
250 for (i = 0, n = mdoc->last->child; n; n = n->next, i++) {
251 assert(MDOC_TEXT == n->type);
252 p = n->data.text.string;
253
254 switch (i) {
255 case (0):
256 mdoc->meta.title = xstrdup(p);
257 break;
258 case (1):
259 mdoc->meta.msec = mdoc_atomsec(p);
260 if (MSEC_DEFAULT != mdoc->meta.msec)
261 break;
262 return(mdoc_nerr(mdoc, n,
263 "invalid parameter syntax"));
264 case (2):
265 mdoc->meta.vol = mdoc_atovol(p);
266 if (VOL_DEFAULT != mdoc->meta.vol)
267 break;
268 mdoc->meta.arch = mdoc_atoarch(p);
269 if (ARCH_DEFAULT != mdoc->meta.arch)
270 break;
271 return(mdoc_nerr(mdoc, n,
272 "invalid parameter syntax"));
273 default:
274 return(mdoc_nerr(mdoc, n,
275 "too many parameters"));
276 }
277 }
278
279 if (NULL == mdoc->meta.title)
280 mdoc->meta.title = xstrdup("UNTITLED");
281
282 mdoc_msg(mdoc, "title: %s", mdoc->meta.title);
283
284 return(post_prologue(mdoc));
285 }
286
287
288 static int
289 post_os(struct mdoc *mdoc)
290 {
291 char buf[64];
292
293 /*
294 * Prologue operating system must be parsed into document
295 * meta-data.
296 */
297
298 assert(MDOC_ELEM == mdoc->last->type);
299 assert(MDOC_Os == mdoc->last->tok);
300 assert(NULL == mdoc->meta.os);
301
302 if ( ! xstrlcats(buf, mdoc->last->child, 64))
303 return(mdoc_err(mdoc, "macro parameters too long"));
304
305 mdoc->meta.os = xstrdup(buf[0] ? buf : "LOCAL");
306 mdoc->lastnamed = SEC_BODY;
307
308 return(post_prologue(mdoc));
309 }
310
311
312 static int
313 post_bl_tagwidth(struct mdoc *mdoc)
314 {
315 struct mdoc_node *n;
316 struct mdoc_block *b;
317 int sz;
318 char buf[32];
319
320 /*
321 * If -tag has been specified and -width has not been, then try
322 * to intuit our width from the first body element.
323 */
324
325 b = &mdoc->last->data.block;
326
327 if (NULL == (n = b->body->child))
328 return(1);
329 assert(MDOC_It == n->tok);
330
331 /*
332 * Use the text width, if a text node, or the default macro
333 * width if a macro.
334 */
335
336 if ((n = n->data.block.head->child)) {
337 if (MDOC_TEXT != n->type) {
338 if (0 == (sz = mdoc_macro2len(n->tok)))
339 sz = -1;
340 } else
341 sz = (int)strlen(n->data.text.string) + 1;
342 } else
343 sz = -1;
344
345 if (-1 == sz) {
346 if ( ! mdoc_warn(mdoc, WARN_SYNTAX,
347 "cannot determine default %s",
348 mdoc_argnames[MDOC_Width]))
349 return(0);
350 sz = 10;
351 }
352
353 (void)snprintf(buf, sizeof(buf), "%dn", sz);
354
355 /*
356 * We have to dynamically add this to the macro's argument list.
357 * We're guaranteed that a MDOC_Width doesn't already exist.
358 */
359
360 (b->argc)++;
361 b->argv = xrealloc(b->argv, b->argc * sizeof(struct mdoc_arg));
362
363 b->argv[b->argc - 1].arg = MDOC_Width;
364 b->argv[b->argc - 1].line = mdoc->last->line;
365 b->argv[b->argc - 1].pos = mdoc->last->pos;
366 b->argv[b->argc - 1].sz = 1;
367 b->argv[b->argc - 1].value = xcalloc(1, sizeof(char *));
368 b->argv[b->argc - 1].value[0] = xstrdup(buf);
369
370 mdoc_msg(mdoc, "adding %s argument: %dn",
371 mdoc_argnames[MDOC_Width], sz);
372
373 return(1);
374 }
375
376
377 static int
378 post_bl_width(struct mdoc *mdoc)
379 {
380 size_t width;
381 int i, tok;
382 char buf[32];
383 char **p;
384
385 for (i = 0; i < (int)mdoc->last->data.block.argc; i++)
386 if (MDOC_Width == mdoc->last->data.block.argv[i].arg)
387 break;
388
389 assert(i < (int)mdoc->last->data.block.argc);
390 assert(1 == mdoc->last->data.block.argv[i].sz);
391 p = &mdoc->last->data.block.argv[i].value[0];
392
393 /*
394 * If the value to -width is a macro, then we re-write it to be
395 * the macro's width as set in share/tmac/mdoc/doc-common.
396 */
397
398 if (xstrcmp(*p, "Ds"))
399 width = 8;
400 else if (MDOC_MAX == (tok = mdoc_find(mdoc, *p)))
401 return(1);
402 else if (0 == (width = mdoc_macro2len(tok)))
403 return(mdoc_warn(mdoc, WARN_SYNTAX,
404 "%s macro has no length",
405 mdoc_argnames[MDOC_Width]));
406
407 mdoc_msg(mdoc, "re-writing %s argument: %s -> %zun",
408 mdoc_argnames[MDOC_Width], *p, width);
409
410 /* The value already exists: free and reallocate it. */
411
412 (void)snprintf(buf, sizeof(buf), "%zun", width);
413
414 free(*p);
415 *p = strdup(buf);
416
417 return(1);
418 }
419
420
421 static int
422 post_bl(struct mdoc *mdoc)
423 {
424 int i, r;
425
426 if (MDOC_BLOCK != mdoc->last->type)
427 return(1);
428
429 /*
430 * These are fairly complicated, so we've broken them into two
431 * functions. post_bl_tagwidth() is called when a -tag is
432 * specified, but no -width (it must be guessed). The second
433 * when a -width is specified (macro indicators must be
434 * rewritten into real lengths).
435 */
436
437 for (r = i = 0; i < (int)mdoc->last->data.block.argc; i++) {
438 if (MDOC_Tag == mdoc->last->data.block.argv[i].arg)
439 r |= 1 << 0;
440 if (MDOC_Width == mdoc->last->data.block.argv[i].arg)
441 r |= 1 << 1;
442 }
443
444 if (r & (1 << 0) && ! (r & (1 << 1))) {
445 if ( ! post_bl_tagwidth(mdoc))
446 return(0);
447 } else if (r & (1 << 1))
448 if ( ! post_bl_width(mdoc))
449 return(0);
450
451 return(1);
452 }
453
454
455 static int
456 post_dd(struct mdoc *mdoc)
457 {
458 char buf[64];
459
460 /*
461 * Prologue date must be parsed into document meta-data. We
462 * accept multiple kinds of dates, described mostly in
463 * mdoc_atotime().
464 */
465
466 assert(MDOC_ELEM == mdoc->last->type);
467 assert(MDOC_Dd == mdoc->last->tok);
468
469 assert(0 == mdoc->meta.date);
470
471 if ( ! xstrlcats(buf, mdoc->last->child, 64))
472 return(mdoc_err(mdoc, "macro parameters too long"));
473 if (0 == (mdoc->meta.date = mdoc_atotime(buf)))
474 return(mdoc_err(mdoc, "invalid parameter syntax"));
475
476 mdoc_msg(mdoc, "date: %u", mdoc->meta.date);
477
478 return(post_prologue(mdoc));
479 }
480
481
482 static int
483 post_prologue(struct mdoc *mdoc)
484 {
485 struct mdoc_node *n;
486
487 /*
488 * The end document shouldn't have the prologue macros as part
489 * of the syntax tree (they encompass only meta-data).
490 */
491
492 if (mdoc->last->parent->child == mdoc->last)
493 mdoc->last->parent->child = mdoc->last->prev;
494 if (mdoc->last->prev)
495 mdoc->last->prev->next = NULL;
496
497 n = mdoc->last;
498 assert(NULL == mdoc->last->next);
499
500 if (mdoc->last->prev) {
501 mdoc->last = mdoc->last->prev;
502 mdoc->next = MDOC_NEXT_SIBLING;
503 } else {
504 mdoc->last = mdoc->last->parent;
505 mdoc->next = MDOC_NEXT_CHILD;
506 }
507
508 mdoc_node_freelist(n);
509 return(1);
510 }
511
512
513 int
514 mdoc_action_post(struct mdoc *mdoc)
515 {
516
517 if (MDOC_ACTED & mdoc->last->flags)
518 return(1);
519 mdoc->last->flags |= MDOC_ACTED;
520
521 if (MDOC_TEXT == mdoc->last->type)
522 return(1);
523 if (MDOC_ROOT == mdoc->last->type)
524 return(1);
525 if (NULL == mdoc_actions[mdoc->last->tok].post)
526 return(1);
527 return((*mdoc_actions[mdoc->last->tok].post)(mdoc));
528 }