]>
git.cameronkatri.com Git - mandoc.git/blob - action.c
1 /* $Id: action.c,v 1.42 2009/03/16 22:19:19 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_std(struct mdoc
*);
63 static int post_prologue(struct mdoc
*);
65 #define merr(m, t) nerr((m), (m)->last, (t))
66 #define mwarn(m, t) nwarn((m), (m)->last, (t))
68 const struct actions mdoc_actions
[MDOC_MAX
] = {
91 { post_std
}, /* Ex */
101 { post_nm
}, /* Nm */
105 { post_std
}, /* Rv */
190 nerr(struct mdoc
*m
, const struct mdoc_node
*n
, enum merr type
)
198 p
= "missing width argument";
203 return(mdoc_nerr(m
, n
, p
));
208 nwarn(struct mdoc
*m
, const struct mdoc_node
*n
, enum mwarn type
)
218 p
= "inappropriate document section in manual section";
222 p
= "cannot determine default width";
225 p
= "malformed date syntax";
230 return(mdoc_nwarn(m
, n
, c
, p
));
235 post_std(struct mdoc
*mdoc
)
239 * If '-std' is invoked without an argument, fill it in with our
240 * name (if it's been set).
243 if (NULL
== mdoc
->last
->args
)
245 if (mdoc
->last
->args
->argv
[0].sz
)
248 assert(mdoc
->meta
.name
);
250 mdoc_msg(mdoc
, "writing %s argument: %s",
251 mdoc_argnames
[MDOC_Std
],
254 mdoc
->last
->args
->argv
[0].value
= xcalloc(1, sizeof(char *));
255 mdoc
->last
->args
->argv
[0].sz
= 1;
256 mdoc
->last
->args
->argv
[0].value
[0] = xstrdup(mdoc
->meta
.name
);
262 post_nm(struct mdoc
*mdoc
)
269 (void)xstrlcpys(buf
, mdoc
->last
->child
, sizeof(buf
));
270 mdoc
->meta
.name
= xstrdup(buf
);
271 mdoc_msg(mdoc
, "name: %s", mdoc
->meta
.name
);
278 post_sh(struct mdoc
*mdoc
)
284 * We keep track of the current section /and/ the "named"
285 * section, which is one of the conventional ones, in order to
289 if (MDOC_HEAD
!= mdoc
->last
->type
)
292 (void)xstrlcpys(buf
, mdoc
->last
->child
, sizeof(buf
));
293 if (SEC_CUSTOM
!= (sec
= mdoc_atosec(buf
)))
294 mdoc
->lastnamed
= sec
;
298 switch (mdoc
->lastsec
) {
299 case (SEC_RETURN_VALUES
):
302 switch (mdoc
->meta
.msec
) {
310 return(mwarn(mdoc
, WBADSEC
));
321 post_dt(struct mdoc
*mdoc
)
328 if (mdoc
->meta
.title
)
329 free(mdoc
->meta
.title
);
331 free(mdoc
->meta
.vol
);
333 free(mdoc
->meta
.arch
);
335 mdoc
->meta
.title
= mdoc
->meta
.vol
= mdoc
->meta
.arch
= NULL
;
339 * --> title = unknown, volume = local, msec = 0, arch = NULL
342 if (NULL
== (n
= mdoc
->last
->child
)) {
343 mdoc
->meta
.title
= xstrdup("unknown");
344 mdoc
->meta
.vol
= xstrdup("local");
345 mdoc_msg(mdoc
, "title: %s", mdoc
->meta
.title
);
346 mdoc_msg(mdoc
, "volume: %s", mdoc
->meta
.vol
);
347 mdoc_msg(mdoc
, "arch: <unset>");
348 mdoc_msg(mdoc
, "msec: <unset>");
349 return(post_prologue(mdoc
));
352 /* Handles: `.Dt TITLE'
353 * --> title = TITLE, volume = local, msec = 0, arch = NULL
356 mdoc
->meta
.title
= xstrdup(n
->string
);
357 mdoc_msg(mdoc
, "title: %s", mdoc
->meta
.title
);
359 if (NULL
== (n
= n
->next
)) {
360 mdoc
->meta
.vol
= xstrdup("local");
361 mdoc_msg(mdoc
, "volume: %s", mdoc
->meta
.vol
);
362 mdoc_msg(mdoc
, "arch: <unset>");
363 mdoc_msg(mdoc
, "msec: %d", mdoc
->meta
.msec
);
364 return(post_prologue(mdoc
));
367 /* Handles: `.Dt TITLE SEC'
368 * --> title = TITLE, volume = SEC is msec ?
369 * format(msec) : SEC,
370 * msec = SEC is msec ? atoi(msec) : 0,
374 if ((cp
= mdoc_a2msec(n
->string
))) {
375 mdoc
->meta
.vol
= xstrdup(cp
);
377 lval
= strtol(n
->string
, &ep
, 10);
378 if (n
->string
[0] != '\0' && *ep
== '\0')
379 mdoc
->meta
.msec
= (int)lval
;
381 mdoc
->meta
.vol
= xstrdup(n
->string
);
383 if (NULL
== (n
= n
->next
)) {
384 mdoc_msg(mdoc
, "volume: %s", mdoc
->meta
.vol
);
385 mdoc_msg(mdoc
, "arch: <unset>");
386 mdoc_msg(mdoc
, "msec: %d", mdoc
->meta
.msec
);
387 return(post_prologue(mdoc
));
390 /* Handles: `.Dt TITLE SEC VOL'
391 * --> title = TITLE, volume = VOL is vol ?
393 * VOL is arch ? format(arch) :
397 if ((cp
= mdoc_a2vol(n
->string
))) {
398 free(mdoc
->meta
.vol
);
399 mdoc
->meta
.vol
= xstrdup(cp
);
402 cp
= mdoc_a2arch(n
->string
);
404 free(mdoc
->meta
.vol
);
405 mdoc
->meta
.vol
= xstrdup(n
->string
);
407 mdoc
->meta
.arch
= xstrdup(cp
);
410 mdoc_msg(mdoc
, "volume: %s", mdoc
->meta
.vol
);
411 mdoc_msg(mdoc
, "arch: %s", mdoc
->meta
.arch
?
412 mdoc
->meta
.arch
: "<unset>");
413 mdoc_msg(mdoc
, "msec: %d", mdoc
->meta
.msec
);
415 /* Ignore any subsequent parameters... */
417 return(post_prologue(mdoc
));
422 post_os(struct mdoc
*mdoc
)
425 struct utsname utsname
;
430 (void)xstrlcpys(buf
, mdoc
->last
->child
, sizeof(buf
));
433 if (-1 == uname(&utsname
))
434 return(mdoc_err(mdoc
, "utsname"));
435 (void)xstrlcpy(buf
, utsname
.sysname
, sizeof(buf
));
436 (void)xstrlcat(buf
, " ", sizeof(buf
));
437 (void)xstrlcat(buf
, utsname
.release
, sizeof(buf
));
440 mdoc
->meta
.os
= xstrdup(buf
);
441 mdoc_msg(mdoc
, "system: %s", mdoc
->meta
.os
);
443 mdoc
->lastnamed
= mdoc
->lastsec
= SEC_BODY
;
445 return(post_prologue(mdoc
));
450 post_bl_tagwidth(struct mdoc
*mdoc
)
457 * If -tag has been specified and -width has not been, then try
458 * to intuit our width from the first body element.
461 if (NULL
== (n
= mdoc
->last
->body
->child
))
465 * Use the text width, if a text node, or the default macro
469 if ((n
= n
->head
->child
)) {
470 if (MDOC_TEXT
!= n
->type
) {
471 if (0 == (sz
= (int)mdoc_macro2len(n
->tok
)))
474 sz
= (int)strlen(n
->string
) + 1;
479 if ( ! mwarn(mdoc
, WNOWIDTH
))
484 (void)snprintf(buf
, sizeof(buf
), "%dn", sz
);
487 * We have to dynamically add this to the macro's argument list.
488 * We're guaranteed that a MDOC_Width doesn't already exist.
491 if (NULL
== mdoc
->last
->args
) {
492 mdoc
->last
->args
= xcalloc
493 (1, sizeof(struct mdoc_arg
));
494 mdoc
->last
->args
->refcnt
= 1;
498 sz
= (int)n
->args
->argc
;
502 n
->args
->argv
= xrealloc(n
->args
->argv
,
503 n
->args
->argc
* sizeof(struct mdoc_arg
));
505 n
->args
->argv
[sz
- 1].arg
= MDOC_Width
;
506 n
->args
->argv
[sz
- 1].line
= mdoc
->last
->line
;
507 n
->args
->argv
[sz
- 1].pos
= mdoc
->last
->pos
;
508 n
->args
->argv
[sz
- 1].sz
= 1;
509 n
->args
->argv
[sz
- 1].value
= xcalloc(1, sizeof(char *));
510 n
->args
->argv
[sz
- 1].value
[0] = xstrdup(buf
);
512 mdoc_msg(mdoc
, "adding %s argument: %s",
513 mdoc_argnames
[MDOC_Width
], buf
);
520 post_bl_width(struct mdoc
*m
)
527 if (NULL
== m
->last
->args
)
528 return(merr(m
, ENOWIDTH
));
530 for (i
= 0; i
< (int)m
->last
->args
->argc
; i
++)
531 if (MDOC_Width
== m
->last
->args
->argv
[i
].arg
)
534 if (i
== (int)m
->last
->args
->argc
)
535 return(merr(m
, ENOWIDTH
));
537 p
= m
->last
->args
->argv
[i
].value
[0];
540 * If the value to -width is a macro, then we re-write it to be
541 * the macro's width as set in share/tmac/mdoc/doc-common.
544 if (xstrcmp(p
, "Ds"))
546 else if (MDOC_MAX
== (tok
= mdoc_tokhash_find(m
->htab
, p
)))
548 else if (0 == (width
= mdoc_macro2len(tok
)))
549 return(mwarn(m
, WNOWIDTH
));
551 mdoc_msg(m
, "re-writing %s argument: %s -> %zun",
552 mdoc_argnames
[MDOC_Width
], p
, width
);
554 /* The value already exists: free and reallocate it. */
556 (void)snprintf(buf
, sizeof(buf
), "%zun", width
);
558 free(m
->last
->args
->argv
[i
].value
[0]);
559 m
->last
->args
->argv
[i
].value
[0] = xstrdup(buf
);
566 post_bl(struct mdoc
*mdoc
)
570 if (MDOC_BLOCK
!= mdoc
->last
->type
)
574 * These are fairly complicated, so we've broken them into two
575 * functions. post_bl_tagwidth() is called when a -tag is
576 * specified, but no -width (it must be guessed). The second
577 * when a -width is specified (macro indicators must be
578 * rewritten into real lengths).
581 len
= (int)(mdoc
->last
->args
? mdoc
->last
->args
->argc
: 0);
583 for (r
= i
= 0; i
< len
; i
++) {
584 if (MDOC_Tag
== mdoc
->last
->args
->argv
[i
].arg
)
586 if (MDOC_Width
== mdoc
->last
->args
->argv
[i
].arg
)
590 if (r
& (1 << 0) && ! (r
& (1 << 1))) {
591 if ( ! post_bl_tagwidth(mdoc
))
593 } else if (r
& (1 << 1))
594 if ( ! post_bl_width(mdoc
))
602 post_ar(struct mdoc
*mdoc
)
606 if (mdoc
->last
->child
)
611 mdoc
->next
= MDOC_NEXT_CHILD
;
612 if ( ! mdoc_word_alloc(mdoc
, mdoc
->last
->line
,
613 mdoc
->last
->pos
, "file"))
615 mdoc
->next
= MDOC_NEXT_SIBLING
;
616 if ( ! mdoc_word_alloc(mdoc
, mdoc
->last
->line
,
617 mdoc
->last
->pos
, "..."))
621 mdoc
->next
= MDOC_NEXT_SIBLING
;
627 post_dd(struct mdoc
*mdoc
)
631 (void)xstrlcpys(buf
, mdoc
->last
->child
, sizeof(buf
));
633 if (0 == (mdoc
->meta
.date
= mdoc_atotime(buf
))) {
634 if ( ! mwarn(mdoc
, WBADDATE
))
636 mdoc
->meta
.date
= time(NULL
);
639 mdoc_msg(mdoc
, "date: %u", mdoc
->meta
.date
);
640 return(post_prologue(mdoc
));
645 post_prologue(struct mdoc
*mdoc
)
650 * The end document shouldn't have the prologue macros as part
651 * of the syntax tree (they encompass only meta-data).
654 if (mdoc
->last
->parent
->child
== mdoc
->last
)
655 mdoc
->last
->parent
->child
= mdoc
->last
->prev
;
656 if (mdoc
->last
->prev
)
657 mdoc
->last
->prev
->next
= NULL
;
660 assert(NULL
== mdoc
->last
->next
);
662 if (mdoc
->last
->prev
) {
663 mdoc
->last
= mdoc
->last
->prev
;
664 mdoc
->next
= MDOC_NEXT_SIBLING
;
666 mdoc
->last
= mdoc
->last
->parent
;
667 mdoc
->next
= MDOC_NEXT_CHILD
;
670 mdoc_node_freelist(n
);
676 mdoc_action_post(struct mdoc
*mdoc
)
679 if (MDOC_ACTED
& mdoc
->last
->flags
)
681 mdoc
->last
->flags
|= MDOC_ACTED
;
683 if (MDOC_TEXT
== mdoc
->last
->type
)
685 if (MDOC_ROOT
== mdoc
->last
->type
)
687 if (NULL
== mdoc_actions
[mdoc
->last
->tok
].post
)
689 return((*mdoc_actions
[mdoc
->last
->tok
].post
)(mdoc
));