]> git.cameronkatri.com Git - mandoc.git/blob - action.c
Made `Ds' emit a warning.
[mandoc.git] / action.c
1 /* $Id: action.c,v 1.25 2009/02/28 14:43: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 <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, "invalid parameter syntax"));
263 case (2):
264 mdoc->meta.vol = mdoc_atovol(p);
265 if (VOL_DEFAULT != mdoc->meta.vol)
266 break;
267 mdoc->meta.arch = mdoc_atoarch(p);
268 if (ARCH_DEFAULT != mdoc->meta.arch)
269 break;
270 return(mdoc_nerr(mdoc, n, "invalid parameter syntax"));
271 default:
272 return(mdoc_nerr(mdoc, n, "too many parameters"));
273 }
274 }
275
276 if (NULL == mdoc->meta.title)
277 mdoc->meta.title = xstrdup("UNTITLED");
278
279 mdoc_msg(mdoc, "title: %s", mdoc->meta.title);
280
281 return(post_prologue(mdoc));
282 }
283
284
285 static int
286 post_os(struct mdoc *mdoc)
287 {
288 char buf[64];
289
290 /*
291 * Prologue operating system must be parsed into document
292 * meta-data.
293 */
294
295 assert(MDOC_ELEM == mdoc->last->type);
296 assert(MDOC_Os == mdoc->last->tok);
297 assert(NULL == mdoc->meta.os);
298
299 if ( ! xstrlcats(buf, mdoc->last->child, 64))
300 return(mdoc_err(mdoc, "macro parameters too long"));
301
302 mdoc->meta.os = xstrdup(buf[0] ? buf : "LOCAL");
303 mdoc->lastnamed = SEC_BODY;
304
305 return(post_prologue(mdoc));
306 }
307
308
309 static int
310 post_bl_tagwidth(struct mdoc *mdoc)
311 {
312 struct mdoc_node *n;
313 struct mdoc_block *b;
314 int sz;
315 char buf[32];
316
317 /*
318 * If -tag has been specified and -width has not been, then try
319 * to intuit our width from the first body element.
320 */
321
322 b = &mdoc->last->data.block;
323
324 if (NULL == (n = b->body->child))
325 return(1);
326 assert(MDOC_It == n->tok);
327
328 /*
329 * Use the text width, if a text node, or the default macro
330 * width if a macro.
331 */
332
333 if ((n = n->data.block.head->child)) {
334 if (MDOC_TEXT != n->type) {
335 if (0 == (sz = mdoc_macro2len(n->tok)))
336 sz = -1;
337 } else
338 sz = (int)strlen(n->data.text.string) + 1;
339 } else
340 sz = -1;
341
342 if (-1 == sz) {
343 if ( ! mdoc_warn(mdoc, WARN_SYNTAX,
344 "cannot determine default %s",
345 mdoc_argnames[MDOC_Width]))
346 return(0);
347 sz = 10;
348 }
349
350 (void)snprintf(buf, sizeof(buf), "%dn", sz);
351
352 /*
353 * We have to dynamically add this to the macro's argument list.
354 * We're guaranteed that a MDOC_Width doesn't already exist.
355 */
356
357 (b->argc)++;
358 b->argv = xrealloc(b->argv, b->argc * sizeof(struct mdoc_arg));
359
360 b->argv[b->argc - 1].arg = MDOC_Width;
361 b->argv[b->argc - 1].line = mdoc->last->line;
362 b->argv[b->argc - 1].pos = mdoc->last->pos;
363 b->argv[b->argc - 1].sz = 1;
364 b->argv[b->argc - 1].value = xcalloc(1, sizeof(char *));
365 b->argv[b->argc - 1].value[0] = xstrdup(buf);
366
367 mdoc_msg(mdoc, "adding %s argument: %dn",
368 mdoc_argnames[MDOC_Width], sz);
369
370 return(1);
371 }
372
373
374 static int
375 post_bl_width(struct mdoc *mdoc)
376 {
377 size_t width;
378 int i, tok;
379 char buf[32];
380 char **p;
381
382 for (i = 0; i < (int)mdoc->last->data.block.argc; i++)
383 if (MDOC_Width == mdoc->last->data.block.argv[i].arg)
384 break;
385
386 assert(i < (int)mdoc->last->data.block.argc);
387 assert(1 == mdoc->last->data.block.argv[i].sz);
388 p = &mdoc->last->data.block.argv[i].value[0];
389
390 /*
391 * If the value to -width is a macro, then we re-write it to be
392 * the macro's width as set in share/tmac/mdoc/doc-common.
393 */
394
395 if (xstrcmp(*p, "Ds")) {
396 if ( ! mdoc_warn(mdoc, WARN_COMPAT,
397 "%s argument deprecated",
398 mdoc_argnames[MDOC_Width]))
399 return(0);
400 width = 6;
401 } else if (MDOC_MAX == (tok = mdoc_find(mdoc, *p)))
402 return(1);
403 else if (0 == (width = mdoc_macro2len(tok)))
404 return(mdoc_warn(mdoc, WARN_SYNTAX,
405 "%s macro has no length",
406 mdoc_argnames[MDOC_Width]));
407
408 mdoc_msg(mdoc, "re-writing %s argument: %s -> %zun",
409 mdoc_argnames[MDOC_Width], *p, width);
410
411 /* The value already exists: free and reallocate it. */
412
413 (void)snprintf(buf, sizeof(buf), "%zun", width);
414
415 free(*p);
416 *p = strdup(buf);
417
418 return(1);
419 }
420
421
422 static int
423 post_bl(struct mdoc *mdoc)
424 {
425 int i, r;
426
427 if (MDOC_BLOCK != mdoc->last->type)
428 return(1);
429
430 /*
431 * These are fairly complicated, so we've broken them into two
432 * functions. post_bl_tagwidth() is called when a -tag is
433 * specified, but no -width (it must be guessed). The second
434 * when a -width is specified (macro indicators must be
435 * rewritten into real lengths).
436 */
437
438 for (r = i = 0; i < (int)mdoc->last->data.block.argc; i++) {
439 if (MDOC_Tag == mdoc->last->data.block.argv[i].arg)
440 r |= 1 << 0;
441 if (MDOC_Width == mdoc->last->data.block.argv[i].arg)
442 r |= 1 << 1;
443 }
444
445 if (r & (1 << 0) && ! (r & (1 << 1))) {
446 if ( ! post_bl_tagwidth(mdoc))
447 return(0);
448 } else if (r & (1 << 1))
449 if ( ! post_bl_width(mdoc))
450 return(0);
451
452 return(1);
453 }
454
455
456 static int
457 post_dd(struct mdoc *mdoc)
458 {
459 char buf[64];
460
461 /*
462 * Prologue date must be parsed into document meta-data. We
463 * accept multiple kinds of dates, described mostly in
464 * mdoc_atotime().
465 */
466
467 assert(MDOC_ELEM == mdoc->last->type);
468 assert(MDOC_Dd == mdoc->last->tok);
469
470 assert(0 == mdoc->meta.date);
471
472 if ( ! xstrlcats(buf, mdoc->last->child, 64))
473 return(mdoc_err(mdoc, "macro parameters too long"));
474 if (0 == (mdoc->meta.date = mdoc_atotime(buf)))
475 return(mdoc_err(mdoc, "invalid parameter syntax"));
476
477 mdoc_msg(mdoc, "date: %u", mdoc->meta.date);
478
479 return(post_prologue(mdoc));
480 }
481
482
483 static int
484 post_prologue(struct mdoc *mdoc)
485 {
486 struct mdoc_node *n;
487
488 /*
489 * The end document shouldn't have the prologue macros as part
490 * of the syntax tree (they encompass only meta-data).
491 */
492
493 if (mdoc->last->parent->child == mdoc->last)
494 mdoc->last->parent->child = mdoc->last->prev;
495 if (mdoc->last->prev)
496 mdoc->last->prev->next = NULL;
497
498 n = mdoc->last;
499 assert(NULL == mdoc->last->next);
500
501 if (mdoc->last->prev) {
502 mdoc->last = mdoc->last->prev;
503 mdoc->next = MDOC_NEXT_SIBLING;
504 } else {
505 mdoc->last = mdoc->last->parent;
506 mdoc->next = MDOC_NEXT_CHILD;
507 }
508
509 mdoc_node_freelist(n);
510 return(1);
511 }
512
513
514 int
515 mdoc_action_post(struct mdoc *mdoc)
516 {
517
518 if (MDOC_ACTED & mdoc->last->flags)
519 return(1);
520 mdoc->last->flags |= MDOC_ACTED;
521
522 if (MDOC_TEXT == mdoc->last->type)
523 return(1);
524 if (MDOC_ROOT == mdoc->last->type)
525 return(1);
526 if (NULL == mdoc_actions[mdoc->last->tok].post)
527 return(1);
528 return((*mdoc_actions[mdoc->last->tok].post)(mdoc));
529 }