]>
git.cameronkatri.com Git - mandoc.git/blob - action.c
b776d9e17ac6bb0632faaf4cbd2a7fb3a0ab96e3
1 /* $Id: action.c,v 1.39 2009/03/09 14:19:59 kristaps Exp $ */
3 * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
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
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.
19 #include <sys/utsname.h>
30 * Actions are executed on macros after they've been post-validated: in
31 * other words, a macro will not be "acted upon" until all of its
32 * children have been filled in (post-fix order).
46 int (*post
)(struct mdoc
*);
49 static int nwarn(struct mdoc
*,
50 const struct mdoc_node
*, enum mwarn
);
51 static int nerr(struct mdoc
*,
52 const struct mdoc_node
*, enum merr
);
53 static int post_ar(struct mdoc
*);
54 static int post_bl(struct mdoc
*);
55 static int post_bl_width(struct mdoc
*);
56 static int post_bl_tagwidth(struct mdoc
*);
57 static int post_dd(struct mdoc
*);
58 static int post_dt(struct mdoc
*);
59 static int post_nm(struct mdoc
*);
60 static int post_os(struct mdoc
*);
61 static int post_sh(struct mdoc
*);
62 static int post_ex(struct mdoc
*);
63 static int post_prologue(struct mdoc
*);
65 const struct actions mdoc_actions
[MDOC_MAX
] = {
180 #define merr(m, t) nerr((m), (m)->last, (t))
182 nerr(struct mdoc
*m
, const struct mdoc_node
*n
, enum merr type
)
190 p
= "missing width argument";
195 return(mdoc_nerr(m
, n
, p
));
199 #define mwarn(m, t) nwarn((m), (m)->last, (t))
201 nwarn(struct mdoc
*m
, const struct mdoc_node
*n
, enum mwarn type
)
211 p
= "inappropriate document section in manual section";
215 p
= "cannot determine default width";
218 p
= "malformed date syntax";
223 return(mdoc_nwarn(m
, n
, c
, p
));
228 post_ex(struct mdoc
*mdoc
)
232 * If `.Ex -std' is invoked without an argument, fill it in with
233 * our name (if it's been set).
236 if (NULL
== mdoc
->last
->args
)
238 if (mdoc
->last
->args
->argv
[0].sz
)
241 assert(mdoc
->meta
.name
);
243 mdoc_msg(mdoc
, "writing %s argument: %s",
244 mdoc_argnames
[MDOC_Std
],
247 mdoc
->last
->args
->argv
[0].value
= xcalloc(1, sizeof(char *));
248 mdoc
->last
->args
->argv
[0].sz
= 1;
249 mdoc
->last
->args
->argv
[0].value
[0] = xstrdup(mdoc
->meta
.name
);
255 post_nm(struct mdoc
*mdoc
)
262 (void)xstrlcpys(buf
, mdoc
->last
->child
, sizeof(buf
));
263 mdoc
->meta
.name
= xstrdup(buf
);
264 mdoc_msg(mdoc
, "name: %s", mdoc
->meta
.name
);
271 post_sh(struct mdoc
*mdoc
)
277 * We keep track of the current section /and/ the "named"
278 * section, which is one of the conventional ones, in order to
282 if (MDOC_HEAD
!= mdoc
->last
->type
)
285 (void)xstrlcpys(buf
, mdoc
->last
->child
, sizeof(buf
));
286 if (SEC_CUSTOM
!= (sec
= mdoc_atosec(buf
)))
287 mdoc
->lastnamed
= sec
;
291 switch (mdoc
->lastsec
) {
292 case (SEC_RETURN_VALUES
):
295 switch (mdoc
->meta
.msec
) {
303 return(mwarn(mdoc
, WBADSEC
));
314 post_dt(struct mdoc
*mdoc
)
321 if (mdoc
->meta
.title
)
322 free(mdoc
->meta
.title
);
324 free(mdoc
->meta
.vol
);
326 free(mdoc
->meta
.arch
);
328 mdoc
->meta
.title
= mdoc
->meta
.vol
= mdoc
->meta
.arch
= NULL
;
332 * --> title = unknown, volume = local, msec = 0, arch = NULL
335 if (NULL
== (n
= mdoc
->last
->child
)) {
336 mdoc
->meta
.title
= xstrdup("unknown");
337 mdoc
->meta
.vol
= xstrdup("local");
338 mdoc_msg(mdoc
, "title: %s", mdoc
->meta
.title
);
339 mdoc_msg(mdoc
, "volume: %s", mdoc
->meta
.vol
);
340 mdoc_msg(mdoc
, "arch: <unset>");
341 mdoc_msg(mdoc
, "msec: <unset>");
342 return(post_prologue(mdoc
));
345 /* Handles: `.Dt TITLE'
346 * --> title = TITLE, volume = local, msec = 0, arch = NULL
349 mdoc
->meta
.title
= xstrdup(n
->string
);
350 mdoc_msg(mdoc
, "title: %s", mdoc
->meta
.title
);
352 if (NULL
== (n
= n
->next
)) {
353 mdoc
->meta
.vol
= xstrdup("local");
354 mdoc_msg(mdoc
, "volume: %s", mdoc
->meta
.vol
);
355 mdoc_msg(mdoc
, "arch: <unset>");
356 mdoc_msg(mdoc
, "msec: %d", mdoc
->meta
.msec
);
357 return(post_prologue(mdoc
));
360 /* Handles: `.Dt TITLE SEC'
361 * --> title = TITLE, volume = SEC is msec ?
362 * format(msec) : SEC,
363 * msec = SEC is msec ? atoi(msec) : 0,
367 if ((cp
= mdoc_a2msec(n
->string
))) {
368 mdoc
->meta
.vol
= xstrdup(cp
);
370 lval
= strtol(n
->string
, &ep
, 10);
371 if (n
->string
[0] != '\0' && *ep
== '\0')
372 mdoc
->meta
.msec
= (int)lval
;
374 mdoc
->meta
.vol
= xstrdup(n
->string
);
376 if (NULL
== (n
= n
->next
)) {
377 mdoc_msg(mdoc
, "volume: %s", mdoc
->meta
.vol
);
378 mdoc_msg(mdoc
, "arch: <unset>");
379 mdoc_msg(mdoc
, "msec: %d", mdoc
->meta
.msec
);
380 return(post_prologue(mdoc
));
383 /* Handles: `.Dt TITLE SEC VOL'
384 * --> title = TITLE, volume = VOL is vol ?
386 * VOL is arch ? format(arch) :
390 if ((cp
= mdoc_a2vol(n
->string
))) {
391 free(mdoc
->meta
.vol
);
392 mdoc
->meta
.vol
= xstrdup(cp
);
395 cp
= mdoc_a2arch(n
->string
);
397 free(mdoc
->meta
.vol
);
398 mdoc
->meta
.vol
= xstrdup(n
->string
);
400 mdoc
->meta
.arch
= xstrdup(cp
);
403 mdoc_msg(mdoc
, "volume: %s", mdoc
->meta
.vol
);
404 mdoc_msg(mdoc
, "arch: %s", mdoc
->meta
.arch
?
405 mdoc
->meta
.arch
: "<unset>");
406 mdoc_msg(mdoc
, "msec: %d", mdoc
->meta
.msec
);
408 /* Ignore any subsequent parameters... */
410 return(post_prologue(mdoc
));
415 post_os(struct mdoc
*mdoc
)
418 struct utsname utsname
;
423 (void)xstrlcpys(buf
, mdoc
->last
->child
, sizeof(buf
));
426 if (-1 == uname(&utsname
))
427 return(mdoc_err(mdoc
, "utsname"));
428 (void)xstrlcpy(buf
, utsname
.sysname
, sizeof(buf
));
429 (void)xstrlcat(buf
, " ", sizeof(buf
));
430 (void)xstrlcat(buf
, utsname
.release
, sizeof(buf
));
433 mdoc
->meta
.os
= xstrdup(buf
);
434 mdoc_msg(mdoc
, "system: %s", mdoc
->meta
.os
);
436 mdoc
->lastnamed
= mdoc
->lastsec
= SEC_BODY
;
438 return(post_prologue(mdoc
));
443 post_bl_tagwidth(struct mdoc
*mdoc
)
450 * If -tag has been specified and -width has not been, then try
451 * to intuit our width from the first body element.
454 if (NULL
== (n
= mdoc
->last
->body
->child
))
458 * Use the text width, if a text node, or the default macro
462 if ((n
= n
->head
->child
)) {
463 if (MDOC_TEXT
!= n
->type
) {
464 if (0 == (sz
= (int)mdoc_macro2len(n
->tok
)))
467 sz
= (int)strlen(n
->string
) + 1;
472 if ( ! mwarn(mdoc
, WNOWIDTH
))
477 (void)snprintf(buf
, sizeof(buf
), "%dn", sz
);
480 * We have to dynamically add this to the macro's argument list.
481 * We're guaranteed that a MDOC_Width doesn't already exist.
484 if (NULL
== mdoc
->last
->args
) {
485 mdoc
->last
->args
= xcalloc
486 (1, sizeof(struct mdoc_arg
));
487 mdoc
->last
->args
->refcnt
= 1;
491 sz
= (int)n
->args
->argc
;
495 n
->args
->argv
= xrealloc(n
->args
->argv
,
496 n
->args
->argc
* sizeof(struct mdoc_arg
));
498 n
->args
->argv
[sz
- 1].arg
= MDOC_Width
;
499 n
->args
->argv
[sz
- 1].line
= mdoc
->last
->line
;
500 n
->args
->argv
[sz
- 1].pos
= mdoc
->last
->pos
;
501 n
->args
->argv
[sz
- 1].sz
= 1;
502 n
->args
->argv
[sz
- 1].value
= xcalloc(1, sizeof(char *));
503 n
->args
->argv
[sz
- 1].value
[0] = xstrdup(buf
);
505 mdoc_msg(mdoc
, "adding %s argument: %s",
506 mdoc_argnames
[MDOC_Width
], buf
);
513 post_bl_width(struct mdoc
*m
)
520 if (NULL
== m
->last
->args
)
521 return(merr(m
, ENOWIDTH
));
523 for (i
= 0; i
< (int)m
->last
->args
->argc
; i
++)
524 if (MDOC_Width
== m
->last
->args
->argv
[i
].arg
)
527 if (i
== (int)m
->last
->args
->argc
)
528 return(merr(m
, ENOWIDTH
));
530 p
= m
->last
->args
->argv
[i
].value
[0];
533 * If the value to -width is a macro, then we re-write it to be
534 * the macro's width as set in share/tmac/mdoc/doc-common.
537 if (xstrcmp(p
, "Ds"))
539 else if (MDOC_MAX
== (tok
= mdoc_tokhash_find(m
->htab
, p
)))
541 else if (0 == (width
= mdoc_macro2len(tok
)))
542 return(mwarn(m
, WNOWIDTH
));
544 mdoc_msg(m
, "re-writing %s argument: %s -> %zun",
545 mdoc_argnames
[MDOC_Width
], p
, width
);
547 /* The value already exists: free and reallocate it. */
549 (void)snprintf(buf
, sizeof(buf
), "%zun", width
);
551 free(m
->last
->args
->argv
[i
].value
[0]);
552 m
->last
->args
->argv
[i
].value
[0] = xstrdup(buf
);
559 post_bl(struct mdoc
*mdoc
)
563 if (MDOC_BLOCK
!= mdoc
->last
->type
)
567 * These are fairly complicated, so we've broken them into two
568 * functions. post_bl_tagwidth() is called when a -tag is
569 * specified, but no -width (it must be guessed). The second
570 * when a -width is specified (macro indicators must be
571 * rewritten into real lengths).
574 len
= (int)(mdoc
->last
->args
? mdoc
->last
->args
->argc
: 0);
576 for (r
= i
= 0; i
< len
; i
++) {
577 if (MDOC_Tag
== mdoc
->last
->args
->argv
[i
].arg
)
579 if (MDOC_Width
== mdoc
->last
->args
->argv
[i
].arg
)
583 if (r
& (1 << 0) && ! (r
& (1 << 1))) {
584 if ( ! post_bl_tagwidth(mdoc
))
586 } else if (r
& (1 << 1))
587 if ( ! post_bl_width(mdoc
))
595 post_ar(struct mdoc
*mdoc
)
599 if (mdoc
->last
->child
)
604 mdoc
->next
= MDOC_NEXT_CHILD
;
605 if ( ! mdoc_word_alloc(mdoc
, mdoc
->last
->line
,
606 mdoc
->last
->pos
, "file"))
608 mdoc
->next
= MDOC_NEXT_SIBLING
;
609 if ( ! mdoc_word_alloc(mdoc
, mdoc
->last
->line
,
610 mdoc
->last
->pos
, "..."))
614 mdoc
->next
= MDOC_NEXT_SIBLING
;
620 post_dd(struct mdoc
*mdoc
)
624 (void)xstrlcpys(buf
, mdoc
->last
->child
, sizeof(buf
));
626 if (0 == (mdoc
->meta
.date
= mdoc_atotime(buf
))) {
627 if ( ! mwarn(mdoc
, WBADDATE
))
629 mdoc
->meta
.date
= time(NULL
);
632 mdoc_msg(mdoc
, "date: %u", mdoc
->meta
.date
);
633 return(post_prologue(mdoc
));
638 post_prologue(struct mdoc
*mdoc
)
643 * The end document shouldn't have the prologue macros as part
644 * of the syntax tree (they encompass only meta-data).
647 if (mdoc
->last
->parent
->child
== mdoc
->last
)
648 mdoc
->last
->parent
->child
= mdoc
->last
->prev
;
649 if (mdoc
->last
->prev
)
650 mdoc
->last
->prev
->next
= NULL
;
653 assert(NULL
== mdoc
->last
->next
);
655 if (mdoc
->last
->prev
) {
656 mdoc
->last
= mdoc
->last
->prev
;
657 mdoc
->next
= MDOC_NEXT_SIBLING
;
659 mdoc
->last
= mdoc
->last
->parent
;
660 mdoc
->next
= MDOC_NEXT_CHILD
;
663 mdoc_node_freelist(n
);
669 mdoc_action_post(struct mdoc
*mdoc
)
672 if (MDOC_ACTED
& mdoc
->last
->flags
)
674 mdoc
->last
->flags
|= MDOC_ACTED
;
676 if (MDOC_TEXT
== mdoc
->last
->type
)
678 if (MDOC_ROOT
== mdoc
->last
->type
)
680 if (NULL
== mdoc_actions
[mdoc
->last
->tok
].post
)
682 return((*mdoc_actions
[mdoc
->last
->tok
].post
)(mdoc
));