]>
git.cameronkatri.com Git - mandoc.git/blob - action.c
1 /* $Id: action.c,v 1.41 2009/03/12 16:30:50 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 const struct actions mdoc_actions
[MDOC_MAX
] = {
88 { post_std
}, /* Ex */
102 { post_std
}, /* Rv */
184 #define merr(m, t) nerr((m), (m)->last, (t))
186 nerr(struct mdoc
*m
, const struct mdoc_node
*n
, enum merr type
)
194 p
= "missing width argument";
199 return(mdoc_nerr(m
, n
, p
));
203 #define mwarn(m, t) nwarn((m), (m)->last, (t))
205 nwarn(struct mdoc
*m
, const struct mdoc_node
*n
, enum mwarn type
)
215 p
= "inappropriate document section in manual section";
219 p
= "cannot determine default width";
222 p
= "malformed date syntax";
227 return(mdoc_nwarn(m
, n
, c
, p
));
232 post_std(struct mdoc
*mdoc
)
236 * If '-std' is invoked without an argument, fill it in with our
237 * name (if it's been set).
240 if (NULL
== mdoc
->last
->args
)
242 if (mdoc
->last
->args
->argv
[0].sz
)
245 assert(mdoc
->meta
.name
);
247 mdoc_msg(mdoc
, "writing %s argument: %s",
248 mdoc_argnames
[MDOC_Std
],
251 mdoc
->last
->args
->argv
[0].value
= xcalloc(1, sizeof(char *));
252 mdoc
->last
->args
->argv
[0].sz
= 1;
253 mdoc
->last
->args
->argv
[0].value
[0] = xstrdup(mdoc
->meta
.name
);
259 post_nm(struct mdoc
*mdoc
)
266 (void)xstrlcpys(buf
, mdoc
->last
->child
, sizeof(buf
));
267 mdoc
->meta
.name
= xstrdup(buf
);
268 mdoc_msg(mdoc
, "name: %s", mdoc
->meta
.name
);
275 post_sh(struct mdoc
*mdoc
)
281 * We keep track of the current section /and/ the "named"
282 * section, which is one of the conventional ones, in order to
286 if (MDOC_HEAD
!= mdoc
->last
->type
)
289 (void)xstrlcpys(buf
, mdoc
->last
->child
, sizeof(buf
));
290 if (SEC_CUSTOM
!= (sec
= mdoc_atosec(buf
)))
291 mdoc
->lastnamed
= sec
;
295 switch (mdoc
->lastsec
) {
296 case (SEC_RETURN_VALUES
):
299 switch (mdoc
->meta
.msec
) {
307 return(mwarn(mdoc
, WBADSEC
));
318 post_dt(struct mdoc
*mdoc
)
325 if (mdoc
->meta
.title
)
326 free(mdoc
->meta
.title
);
328 free(mdoc
->meta
.vol
);
330 free(mdoc
->meta
.arch
);
332 mdoc
->meta
.title
= mdoc
->meta
.vol
= mdoc
->meta
.arch
= NULL
;
336 * --> title = unknown, volume = local, msec = 0, arch = NULL
339 if (NULL
== (n
= mdoc
->last
->child
)) {
340 mdoc
->meta
.title
= xstrdup("unknown");
341 mdoc
->meta
.vol
= xstrdup("local");
342 mdoc_msg(mdoc
, "title: %s", mdoc
->meta
.title
);
343 mdoc_msg(mdoc
, "volume: %s", mdoc
->meta
.vol
);
344 mdoc_msg(mdoc
, "arch: <unset>");
345 mdoc_msg(mdoc
, "msec: <unset>");
346 return(post_prologue(mdoc
));
349 /* Handles: `.Dt TITLE'
350 * --> title = TITLE, volume = local, msec = 0, arch = NULL
353 mdoc
->meta
.title
= xstrdup(n
->string
);
354 mdoc_msg(mdoc
, "title: %s", mdoc
->meta
.title
);
356 if (NULL
== (n
= n
->next
)) {
357 mdoc
->meta
.vol
= xstrdup("local");
358 mdoc_msg(mdoc
, "volume: %s", mdoc
->meta
.vol
);
359 mdoc_msg(mdoc
, "arch: <unset>");
360 mdoc_msg(mdoc
, "msec: %d", mdoc
->meta
.msec
);
361 return(post_prologue(mdoc
));
364 /* Handles: `.Dt TITLE SEC'
365 * --> title = TITLE, volume = SEC is msec ?
366 * format(msec) : SEC,
367 * msec = SEC is msec ? atoi(msec) : 0,
371 if ((cp
= mdoc_a2msec(n
->string
))) {
372 mdoc
->meta
.vol
= xstrdup(cp
);
374 lval
= strtol(n
->string
, &ep
, 10);
375 if (n
->string
[0] != '\0' && *ep
== '\0')
376 mdoc
->meta
.msec
= (int)lval
;
378 mdoc
->meta
.vol
= xstrdup(n
->string
);
380 if (NULL
== (n
= n
->next
)) {
381 mdoc_msg(mdoc
, "volume: %s", mdoc
->meta
.vol
);
382 mdoc_msg(mdoc
, "arch: <unset>");
383 mdoc_msg(mdoc
, "msec: %d", mdoc
->meta
.msec
);
384 return(post_prologue(mdoc
));
387 /* Handles: `.Dt TITLE SEC VOL'
388 * --> title = TITLE, volume = VOL is vol ?
390 * VOL is arch ? format(arch) :
394 if ((cp
= mdoc_a2vol(n
->string
))) {
395 free(mdoc
->meta
.vol
);
396 mdoc
->meta
.vol
= xstrdup(cp
);
399 cp
= mdoc_a2arch(n
->string
);
401 free(mdoc
->meta
.vol
);
402 mdoc
->meta
.vol
= xstrdup(n
->string
);
404 mdoc
->meta
.arch
= xstrdup(cp
);
407 mdoc_msg(mdoc
, "volume: %s", mdoc
->meta
.vol
);
408 mdoc_msg(mdoc
, "arch: %s", mdoc
->meta
.arch
?
409 mdoc
->meta
.arch
: "<unset>");
410 mdoc_msg(mdoc
, "msec: %d", mdoc
->meta
.msec
);
412 /* Ignore any subsequent parameters... */
414 return(post_prologue(mdoc
));
419 post_os(struct mdoc
*mdoc
)
422 struct utsname utsname
;
427 (void)xstrlcpys(buf
, mdoc
->last
->child
, sizeof(buf
));
430 if (-1 == uname(&utsname
))
431 return(mdoc_err(mdoc
, "utsname"));
432 (void)xstrlcpy(buf
, utsname
.sysname
, sizeof(buf
));
433 (void)xstrlcat(buf
, " ", sizeof(buf
));
434 (void)xstrlcat(buf
, utsname
.release
, sizeof(buf
));
437 mdoc
->meta
.os
= xstrdup(buf
);
438 mdoc_msg(mdoc
, "system: %s", mdoc
->meta
.os
);
440 mdoc
->lastnamed
= mdoc
->lastsec
= SEC_BODY
;
442 return(post_prologue(mdoc
));
447 post_bl_tagwidth(struct mdoc
*mdoc
)
454 * If -tag has been specified and -width has not been, then try
455 * to intuit our width from the first body element.
458 if (NULL
== (n
= mdoc
->last
->body
->child
))
462 * Use the text width, if a text node, or the default macro
466 if ((n
= n
->head
->child
)) {
467 if (MDOC_TEXT
!= n
->type
) {
468 if (0 == (sz
= (int)mdoc_macro2len(n
->tok
)))
471 sz
= (int)strlen(n
->string
) + 1;
476 if ( ! mwarn(mdoc
, WNOWIDTH
))
481 (void)snprintf(buf
, sizeof(buf
), "%dn", sz
);
484 * We have to dynamically add this to the macro's argument list.
485 * We're guaranteed that a MDOC_Width doesn't already exist.
488 if (NULL
== mdoc
->last
->args
) {
489 mdoc
->last
->args
= xcalloc
490 (1, sizeof(struct mdoc_arg
));
491 mdoc
->last
->args
->refcnt
= 1;
495 sz
= (int)n
->args
->argc
;
499 n
->args
->argv
= xrealloc(n
->args
->argv
,
500 n
->args
->argc
* sizeof(struct mdoc_arg
));
502 n
->args
->argv
[sz
- 1].arg
= MDOC_Width
;
503 n
->args
->argv
[sz
- 1].line
= mdoc
->last
->line
;
504 n
->args
->argv
[sz
- 1].pos
= mdoc
->last
->pos
;
505 n
->args
->argv
[sz
- 1].sz
= 1;
506 n
->args
->argv
[sz
- 1].value
= xcalloc(1, sizeof(char *));
507 n
->args
->argv
[sz
- 1].value
[0] = xstrdup(buf
);
509 mdoc_msg(mdoc
, "adding %s argument: %s",
510 mdoc_argnames
[MDOC_Width
], buf
);
517 post_bl_width(struct mdoc
*m
)
524 if (NULL
== m
->last
->args
)
525 return(merr(m
, ENOWIDTH
));
527 for (i
= 0; i
< (int)m
->last
->args
->argc
; i
++)
528 if (MDOC_Width
== m
->last
->args
->argv
[i
].arg
)
531 if (i
== (int)m
->last
->args
->argc
)
532 return(merr(m
, ENOWIDTH
));
534 p
= m
->last
->args
->argv
[i
].value
[0];
537 * If the value to -width is a macro, then we re-write it to be
538 * the macro's width as set in share/tmac/mdoc/doc-common.
541 if (xstrcmp(p
, "Ds"))
543 else if (MDOC_MAX
== (tok
= mdoc_tokhash_find(m
->htab
, p
)))
545 else if (0 == (width
= mdoc_macro2len(tok
)))
546 return(mwarn(m
, WNOWIDTH
));
548 mdoc_msg(m
, "re-writing %s argument: %s -> %zun",
549 mdoc_argnames
[MDOC_Width
], p
, width
);
551 /* The value already exists: free and reallocate it. */
553 (void)snprintf(buf
, sizeof(buf
), "%zun", width
);
555 free(m
->last
->args
->argv
[i
].value
[0]);
556 m
->last
->args
->argv
[i
].value
[0] = xstrdup(buf
);
563 post_bl(struct mdoc
*mdoc
)
567 if (MDOC_BLOCK
!= mdoc
->last
->type
)
571 * These are fairly complicated, so we've broken them into two
572 * functions. post_bl_tagwidth() is called when a -tag is
573 * specified, but no -width (it must be guessed). The second
574 * when a -width is specified (macro indicators must be
575 * rewritten into real lengths).
578 len
= (int)(mdoc
->last
->args
? mdoc
->last
->args
->argc
: 0);
580 for (r
= i
= 0; i
< len
; i
++) {
581 if (MDOC_Tag
== mdoc
->last
->args
->argv
[i
].arg
)
583 if (MDOC_Width
== mdoc
->last
->args
->argv
[i
].arg
)
587 if (r
& (1 << 0) && ! (r
& (1 << 1))) {
588 if ( ! post_bl_tagwidth(mdoc
))
590 } else if (r
& (1 << 1))
591 if ( ! post_bl_width(mdoc
))
599 post_ar(struct mdoc
*mdoc
)
603 if (mdoc
->last
->child
)
608 mdoc
->next
= MDOC_NEXT_CHILD
;
609 if ( ! mdoc_word_alloc(mdoc
, mdoc
->last
->line
,
610 mdoc
->last
->pos
, "file"))
612 mdoc
->next
= MDOC_NEXT_SIBLING
;
613 if ( ! mdoc_word_alloc(mdoc
, mdoc
->last
->line
,
614 mdoc
->last
->pos
, "..."))
618 mdoc
->next
= MDOC_NEXT_SIBLING
;
624 post_dd(struct mdoc
*mdoc
)
628 (void)xstrlcpys(buf
, mdoc
->last
->child
, sizeof(buf
));
630 if (0 == (mdoc
->meta
.date
= mdoc_atotime(buf
))) {
631 if ( ! mwarn(mdoc
, WBADDATE
))
633 mdoc
->meta
.date
= time(NULL
);
636 mdoc_msg(mdoc
, "date: %u", mdoc
->meta
.date
);
637 return(post_prologue(mdoc
));
642 post_prologue(struct mdoc
*mdoc
)
647 * The end document shouldn't have the prologue macros as part
648 * of the syntax tree (they encompass only meta-data).
651 if (mdoc
->last
->parent
->child
== mdoc
->last
)
652 mdoc
->last
->parent
->child
= mdoc
->last
->prev
;
653 if (mdoc
->last
->prev
)
654 mdoc
->last
->prev
->next
= NULL
;
657 assert(NULL
== mdoc
->last
->next
);
659 if (mdoc
->last
->prev
) {
660 mdoc
->last
= mdoc
->last
->prev
;
661 mdoc
->next
= MDOC_NEXT_SIBLING
;
663 mdoc
->last
= mdoc
->last
->parent
;
664 mdoc
->next
= MDOC_NEXT_CHILD
;
667 mdoc_node_freelist(n
);
673 mdoc_action_post(struct mdoc
*mdoc
)
676 if (MDOC_ACTED
& mdoc
->last
->flags
)
678 mdoc
->last
->flags
|= MDOC_ACTED
;
680 if (MDOC_TEXT
== mdoc
->last
->type
)
682 if (MDOC_ROOT
== mdoc
->last
->type
)
684 if (NULL
== mdoc_actions
[mdoc
->last
->tok
].post
)
686 return((*mdoc_actions
[mdoc
->last
->tok
].post
)(mdoc
));