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