]>
git.cameronkatri.com Git - mandoc.git/blob - action.c
1 /* $Id: action.c,v 1.35 2009/03/08 13:01:35 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>
31 * Actions are executed on macros after they've been post-validated: in
32 * other words, a macro will not be "acted upon" until all of its
33 * children have been filled in (post-fix order).
47 int (*post
)(struct mdoc
*);
50 static int nwarn(struct mdoc
*,
51 const struct mdoc_node
*, enum mwarn
);
52 static int nerr(struct mdoc
*,
53 const struct mdoc_node
*, enum merr
);
54 static int post_ar(struct mdoc
*);
55 static int post_bl(struct mdoc
*);
56 static int post_bl_width(struct mdoc
*);
57 static int post_bl_tagwidth(struct mdoc
*);
58 static int post_dd(struct mdoc
*);
59 static int post_dt(struct mdoc
*);
60 static int post_nm(struct mdoc
*);
61 static int post_os(struct mdoc
*);
62 static int post_sh(struct mdoc
*);
63 static int post_ex(struct mdoc
*);
64 static int post_prologue(struct mdoc
*);
66 const struct actions mdoc_actions
[MDOC_MAX
] = {
177 #define merr(m, t) nerr((m), (m)->last, (t))
179 nerr(struct mdoc
*m
, const struct mdoc_node
*n
, enum merr type
)
187 p
= "missing width argument";
192 return(mdoc_nerr(m
, n
, p
));
196 #define mwarn(m, t) nwarn((m), (m)->last, (t))
198 nwarn(struct mdoc
*m
, const struct mdoc_node
*n
, enum mwarn type
)
208 p
= "inappropriate document section in manual section";
212 p
= "cannot determine default width";
215 p
= "malformed date syntax";
220 return(mdoc_nwarn(m
, n
, c
, p
));
225 post_ex(struct mdoc
*mdoc
)
229 * If `.Ex -std' is invoked without an argument, fill it in with
230 * our name (if it's been set).
233 if (NULL
== mdoc
->last
->args
)
235 if (mdoc
->last
->args
->argv
[0].sz
)
238 assert(mdoc
->meta
.name
);
240 mdoc_msg(mdoc
, "writing %s argument: %s",
241 mdoc_argnames
[MDOC_Std
],
244 mdoc
->last
->args
->argv
[0].value
= xcalloc(1, sizeof(char *));
245 mdoc
->last
->args
->argv
[0].sz
= 1;
246 mdoc
->last
->args
->argv
[0].value
[0] = xstrdup(mdoc
->meta
.name
);
252 post_nm(struct mdoc
*mdoc
)
259 (void)xstrlcpys(buf
, mdoc
->last
->child
, sizeof(buf
));
260 mdoc
->meta
.name
= xstrdup(buf
);
261 mdoc_msg(mdoc
, "name: %s", mdoc
->meta
.name
);
268 post_sh(struct mdoc
*mdoc
)
274 * We keep track of the current section /and/ the "named"
275 * section, which is one of the conventional ones, in order to
279 if (MDOC_HEAD
!= mdoc
->last
->type
)
282 (void)xstrlcpys(buf
, mdoc
->last
->child
, sizeof(buf
));
283 if (SEC_CUSTOM
!= (sec
= mdoc_atosec(buf
)))
284 mdoc
->lastnamed
= sec
;
288 switch (mdoc
->lastsec
) {
289 case (SEC_RETURN_VALUES
):
292 switch (mdoc
->meta
.msec
) {
300 return(mwarn(mdoc
, WBADSEC
));
311 post_dt(struct mdoc
*mdoc
)
318 if (mdoc
->meta
.title
)
319 free(mdoc
->meta
.title
);
321 free(mdoc
->meta
.vol
);
323 free(mdoc
->meta
.arch
);
325 mdoc
->meta
.title
= mdoc
->meta
.vol
= mdoc
->meta
.arch
= NULL
;
329 * --> title = unknown, volume = local, msec = 0, arch = NULL
332 if (NULL
== (n
= mdoc
->last
->child
)) {
333 mdoc
->meta
.title
= xstrdup("unknown");
334 mdoc
->meta
.vol
= xstrdup("local");
335 mdoc_msg(mdoc
, "title: %s", mdoc
->meta
.title
);
336 mdoc_msg(mdoc
, "volume: %s", mdoc
->meta
.vol
);
337 mdoc_msg(mdoc
, "arch: <unset>");
338 mdoc_msg(mdoc
, "msec: <unset>");
339 return(post_prologue(mdoc
));
342 /* Handles: `.Dt TITLE'
343 * --> title = TITLE, volume = local, msec = 0, arch = NULL
346 mdoc
->meta
.title
= xstrdup(n
->string
);
347 mdoc_msg(mdoc
, "title: %s", mdoc
->meta
.title
);
349 if (NULL
== (n
= n
->next
)) {
350 mdoc
->meta
.vol
= xstrdup("local");
351 mdoc_msg(mdoc
, "volume: %s", mdoc
->meta
.vol
);
352 mdoc_msg(mdoc
, "arch: <unset>");
353 mdoc_msg(mdoc
, "msec: %d", mdoc
->meta
.msec
);
354 return(post_prologue(mdoc
));
357 /* Handles: `.Dt TITLE SEC'
358 * --> title = TITLE, volume = SEC is msec ?
359 * format(msec) : SEC,
360 * msec = SEC is msec ? atoi(msec) : 0,
364 if ((cp
= mdoc_a2msec(n
->string
))) {
365 mdoc
->meta
.vol
= xstrdup(cp
);
367 lval
= strtol(n
->string
, &ep
, 10);
368 if (n
->string
[0] != '\0' && *ep
== '\0')
369 mdoc
->meta
.msec
= (int)lval
;
371 mdoc
->meta
.vol
= xstrdup(n
->string
);
373 if (NULL
== (n
= n
->next
)) {
374 mdoc_msg(mdoc
, "volume: %s", mdoc
->meta
.vol
);
375 mdoc_msg(mdoc
, "arch: <unset>");
376 mdoc_msg(mdoc
, "msec: %d", mdoc
->meta
.msec
);
377 return(post_prologue(mdoc
));
380 /* Handles: `.Dt TITLE SEC VOL'
381 * --> title = TITLE, volume = VOL is vol ?
383 * VOL is arch ? format(arch) :
387 if ((cp
= mdoc_a2vol(n
->string
))) {
388 free(mdoc
->meta
.vol
);
389 mdoc
->meta
.vol
= xstrdup(cp
);
392 cp
= mdoc_a2arch(n
->string
);
394 free(mdoc
->meta
.vol
);
395 mdoc
->meta
.vol
= xstrdup(n
->string
);
397 mdoc
->meta
.arch
= xstrdup(cp
);
400 mdoc_msg(mdoc
, "volume: %s", mdoc
->meta
.vol
);
401 mdoc_msg(mdoc
, "arch: %s", mdoc
->meta
.arch
?
402 mdoc
->meta
.arch
: "<unset>");
403 mdoc_msg(mdoc
, "msec: %d", mdoc
->meta
.msec
);
405 /* Ignore any subsequent parameters... */
407 return(post_prologue(mdoc
));
412 post_os(struct mdoc
*mdoc
)
415 struct utsname utsname
;
420 (void)xstrlcpys(buf
, mdoc
->last
->child
, sizeof(buf
));
423 if (-1 == uname(&utsname
))
424 return(mdoc_err(mdoc
, "utsname"));
425 (void)xstrlcpy(buf
, utsname
.sysname
, sizeof(buf
));
426 (void)xstrlcat(buf
, " ", sizeof(buf
));
427 (void)xstrlcat(buf
, utsname
.release
, sizeof(buf
));
430 mdoc
->meta
.os
= xstrdup(buf
);
431 mdoc_msg(mdoc
, "system: %s", mdoc
->meta
.os
);
433 mdoc
->lastnamed
= mdoc
->lastsec
= SEC_BODY
;
435 return(post_prologue(mdoc
));
440 post_bl_tagwidth(struct mdoc
*mdoc
)
447 * If -tag has been specified and -width has not been, then try
448 * to intuit our width from the first body element.
451 if (NULL
== (n
= mdoc
->last
->body
->child
))
455 * Use the text width, if a text node, or the default macro
459 if ((n
= n
->head
->child
)) {
460 if (MDOC_TEXT
!= n
->type
) {
461 if (0 == (sz
= (int)mdoc_macro2len(n
->tok
)))
464 sz
= (int)strlen(n
->string
) + 1;
469 if ( ! mwarn(mdoc
, WNOWIDTH
))
474 (void)snprintf(buf
, sizeof(buf
), "%dn", sz
);
477 * We have to dynamically add this to the macro's argument list.
478 * We're guaranteed that a MDOC_Width doesn't already exist.
481 if (NULL
== mdoc
->last
->args
) {
482 mdoc
->last
->args
= xcalloc
483 (1, sizeof(struct mdoc_arg
));
484 mdoc
->last
->args
->refcnt
= 1;
488 sz
= (int)n
->args
->argc
;
492 n
->args
->argv
= xrealloc(n
->args
->argv
,
493 n
->args
->argc
* sizeof(struct mdoc_arg
));
495 n
->args
->argv
[sz
- 1].arg
= MDOC_Width
;
496 n
->args
->argv
[sz
- 1].line
= mdoc
->last
->line
;
497 n
->args
->argv
[sz
- 1].pos
= mdoc
->last
->pos
;
498 n
->args
->argv
[sz
- 1].sz
= 1;
499 n
->args
->argv
[sz
- 1].value
= xcalloc(1, sizeof(char *));
500 n
->args
->argv
[sz
- 1].value
[0] = xstrdup(buf
);
502 mdoc_msg(mdoc
, "adding %s argument: %s",
503 mdoc_argnames
[MDOC_Width
], buf
);
510 post_bl_width(struct mdoc
*m
)
517 if (NULL
== m
->last
->args
)
518 return(merr(m
, ENOWIDTH
));
520 for (i
= 0; i
< (int)m
->last
->args
->argc
; i
++)
521 if (MDOC_Width
== m
->last
->args
->argv
[i
].arg
)
524 if (i
== (int)m
->last
->args
->argc
)
525 return(merr(m
, ENOWIDTH
));
527 p
= m
->last
->args
->argv
[i
].value
[0];
530 * If the value to -width is a macro, then we re-write it to be
531 * the macro's width as set in share/tmac/mdoc/doc-common.
534 if (xstrcmp(p
, "Ds"))
536 else if (MDOC_MAX
== (tok
= mdoc_tokhash_find(m
->htab
, p
)))
538 else if (0 == (width
= mdoc_macro2len(tok
)))
539 return(mwarn(m
, WNOWIDTH
));
541 mdoc_msg(m
, "re-writing %s argument: %s -> %zun",
542 mdoc_argnames
[MDOC_Width
], p
, width
);
544 /* The value already exists: free and reallocate it. */
546 (void)snprintf(buf
, sizeof(buf
), "%zun", width
);
548 free(m
->last
->args
->argv
[i
].value
[0]);
549 m
->last
->args
->argv
[i
].value
[0] = xstrdup(buf
);
556 post_bl(struct mdoc
*mdoc
)
560 if (MDOC_BLOCK
!= mdoc
->last
->type
)
564 * These are fairly complicated, so we've broken them into two
565 * functions. post_bl_tagwidth() is called when a -tag is
566 * specified, but no -width (it must be guessed). The second
567 * when a -width is specified (macro indicators must be
568 * rewritten into real lengths).
571 len
= (int)(mdoc
->last
->args
? mdoc
->last
->args
->argc
: 0);
573 for (r
= i
= 0; i
< len
; i
++) {
574 if (MDOC_Tag
== mdoc
->last
->args
->argv
[i
].arg
)
576 if (MDOC_Width
== mdoc
->last
->args
->argv
[i
].arg
)
580 if (r
& (1 << 0) && ! (r
& (1 << 1))) {
581 if ( ! post_bl_tagwidth(mdoc
))
583 } else if (r
& (1 << 1))
584 if ( ! post_bl_width(mdoc
))
592 post_ar(struct mdoc
*mdoc
)
596 if (mdoc
->last
->child
)
601 mdoc
->next
= MDOC_NEXT_CHILD
;
602 if ( ! mdoc_word_alloc(mdoc
, mdoc
->last
->line
,
603 mdoc
->last
->pos
, "file"))
605 mdoc
->next
= MDOC_NEXT_SIBLING
;
606 if ( ! mdoc_word_alloc(mdoc
, mdoc
->last
->line
,
607 mdoc
->last
->pos
, "..."))
611 mdoc
->next
= MDOC_NEXT_SIBLING
;
617 post_dd(struct mdoc
*mdoc
)
621 (void)xstrlcpys(buf
, mdoc
->last
->child
, sizeof(buf
));
623 if (0 == (mdoc
->meta
.date
= mdoc_atotime(buf
))) {
624 if ( ! mwarn(mdoc
, WBADDATE
))
626 mdoc
->meta
.date
= time(NULL
);
629 mdoc_msg(mdoc
, "date: %u", mdoc
->meta
.date
);
630 return(post_prologue(mdoc
));
635 post_prologue(struct mdoc
*mdoc
)
640 * The end document shouldn't have the prologue macros as part
641 * of the syntax tree (they encompass only meta-data).
644 if (mdoc
->last
->parent
->child
== mdoc
->last
)
645 mdoc
->last
->parent
->child
= mdoc
->last
->prev
;
646 if (mdoc
->last
->prev
)
647 mdoc
->last
->prev
->next
= NULL
;
650 assert(NULL
== mdoc
->last
->next
);
652 if (mdoc
->last
->prev
) {
653 mdoc
->last
= mdoc
->last
->prev
;
654 mdoc
->next
= MDOC_NEXT_SIBLING
;
656 mdoc
->last
= mdoc
->last
->parent
;
657 mdoc
->next
= MDOC_NEXT_CHILD
;
660 mdoc_node_freelist(n
);
666 mdoc_action_post(struct mdoc
*mdoc
)
669 if (MDOC_ACTED
& mdoc
->last
->flags
)
671 mdoc
->last
->flags
|= MDOC_ACTED
;
673 if (MDOC_TEXT
== mdoc
->last
->type
)
675 if (MDOC_ROOT
== mdoc
->last
->type
)
677 if (NULL
== mdoc_actions
[mdoc
->last
->tok
].post
)
679 return((*mdoc_actions
[mdoc
->last
->tok
].post
)(mdoc
));