]>
git.cameronkatri.com Git - mandoc.git/blob - action.c
1 /* $Id: action.c,v 1.31 2009/03/06 14:13:47 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).
37 int (*post
)(struct mdoc
*);
40 /* Per-macro action routines. */
42 static int post_ar(struct mdoc
*);
43 static int post_bl(struct mdoc
*);
44 static int post_bl_width(struct mdoc
*);
45 static int post_bl_tagwidth(struct mdoc
*);
46 static int post_dd(struct mdoc
*);
47 static int post_dt(struct mdoc
*);
48 static int post_nm(struct mdoc
*);
49 static int post_os(struct mdoc
*);
50 static int post_sh(struct mdoc
*);
51 static int post_ex(struct mdoc
*);
53 static int post_prologue(struct mdoc
*);
55 /* Array of macro action routines. */
57 const struct actions mdoc_actions
[MDOC_MAX
] = {
169 post_ex(struct mdoc
*mdoc
)
173 * If `.Ex -std' is invoked without an argument, fill it in with
174 * our name (if it's been set).
177 if (0 == mdoc
->last
->data
.elem
.argc
)
179 if (mdoc
->last
->data
.elem
.argv
[0].sz
)
182 assert(mdoc
->meta
.name
);
184 mdoc_msg(mdoc
, "writing %s argument: %s",
185 mdoc_argnames
[MDOC_Std
], mdoc
->meta
.name
);
187 mdoc
->last
->data
.elem
.argv
[0].sz
= 1;
188 mdoc
->last
->data
.elem
.argv
[0].value
= xcalloc(1, sizeof(char *));
189 mdoc
->last
->data
.elem
.argv
[0].value
[0] = xstrdup(mdoc
->meta
.name
);
195 post_nm(struct mdoc
*mdoc
)
202 (void)xstrlcpys(buf
, mdoc
->last
->child
, sizeof(buf
));
203 mdoc
->meta
.name
= xstrdup(buf
);
204 mdoc_msg(mdoc
, "name: %s", mdoc
->meta
.name
);
211 post_sh(struct mdoc
*mdoc
)
217 * We keep track of the current section /and/ the "named"
218 * section, which is one of the conventional ones, in order to
222 if (MDOC_HEAD
!= mdoc
->last
->type
)
225 (void)xstrlcpys(buf
, mdoc
->last
->child
, sizeof(buf
));
226 if (SEC_CUSTOM
!= (sec
= mdoc_atosec(buf
)))
227 mdoc
->lastnamed
= sec
;
231 switch (mdoc
->lastsec
) {
232 case (SEC_RETURN_VALUES
):
235 switch (mdoc
->meta
.msec
) {
243 return(mdoc_warn(mdoc
, WARN_COMPAT
,
244 "inappropriate section for "
256 post_dt(struct mdoc
*mdoc
)
263 if (mdoc
->meta
.title
)
264 free(mdoc
->meta
.title
);
266 free(mdoc
->meta
.vol
);
268 free(mdoc
->meta
.arch
);
270 mdoc
->meta
.title
= mdoc
->meta
.vol
= mdoc
->meta
.arch
= NULL
;
274 * --> title = unknown, volume = local, msec = 0, arch = NULL
277 if (NULL
== (n
= mdoc
->last
->child
)) {
278 mdoc
->meta
.title
= xstrdup("unknown");
279 mdoc
->meta
.vol
= xstrdup("local");
280 mdoc_msg(mdoc
, "title: %s", mdoc
->meta
.title
);
281 mdoc_msg(mdoc
, "volume: %s", mdoc
->meta
.vol
);
282 mdoc_msg(mdoc
, "arch: <unset>");
283 mdoc_msg(mdoc
, "msec: <unset>");
284 return(post_prologue(mdoc
));
287 /* Handles: `.Dt TITLE'
288 * --> title = TITLE, volume = local, msec = 0, arch = NULL
291 mdoc
->meta
.title
= xstrdup(n
->data
.text
.string
);
292 mdoc_msg(mdoc
, "title: %s", mdoc
->meta
.title
);
294 if (NULL
== (n
= n
->next
)) {
295 mdoc
->meta
.vol
= xstrdup("local");
296 mdoc_msg(mdoc
, "volume: %s", mdoc
->meta
.vol
);
297 mdoc_msg(mdoc
, "arch: <unset>");
298 mdoc_msg(mdoc
, "msec: %d", mdoc
->meta
.msec
);
299 return(post_prologue(mdoc
));
302 /* Handles: `.Dt TITLE SEC'
303 * --> title = TITLE, volume = SEC is msec ?
304 * format(msec) : SEC,
305 * msec = SEC is msec ? atoi(msec) : 0,
309 if ((cp
= mdoc_a2msec(n
->data
.text
.string
))) {
310 mdoc
->meta
.vol
= xstrdup(cp
);
312 lval
= strtol(n
->data
.text
.string
, &ep
, 10);
313 if (n
->data
.text
.string
[0] != '\0' && *ep
== '\0')
314 mdoc
->meta
.msec
= (int)lval
;
316 mdoc
->meta
.vol
= xstrdup(n
->data
.text
.string
);
318 if (NULL
== (n
= n
->next
)) {
319 mdoc_msg(mdoc
, "volume: %s", mdoc
->meta
.vol
);
320 mdoc_msg(mdoc
, "arch: <unset>");
321 mdoc_msg(mdoc
, "msec: %d", mdoc
->meta
.msec
);
322 return(post_prologue(mdoc
));
325 /* Handles: `.Dt TITLE SEC VOL'
326 * --> title = TITLE, volume = VOL is vol ?
328 * VOL is arch ? format(arch) :
332 if ((cp
= mdoc_a2vol(n
->data
.text
.string
))) {
333 free(mdoc
->meta
.vol
);
334 mdoc
->meta
.vol
= xstrdup(cp
);
337 cp
= mdoc_a2arch(n
->data
.text
.string
);
339 free(mdoc
->meta
.vol
);
340 mdoc
->meta
.vol
= xstrdup(n
->data
.text
.string
);
342 mdoc
->meta
.arch
= xstrdup(cp
);
345 mdoc_msg(mdoc
, "volume: %s", mdoc
->meta
.vol
);
346 mdoc_msg(mdoc
, "arch: %s", mdoc
->meta
.arch
?
347 mdoc
->meta
.arch
: "<unset>");
348 mdoc_msg(mdoc
, "msec: %d", mdoc
->meta
.msec
);
350 /* Ignore any subsequent parameters... */
352 return(post_prologue(mdoc
));
357 post_os(struct mdoc
*mdoc
)
360 struct utsname utsname
;
365 (void)xstrlcpys(buf
, mdoc
->last
->child
, sizeof(buf
));
368 if (-1 == uname(&utsname
))
369 return(mdoc_err(mdoc
, "utsname"));
370 (void)xstrlcpy(buf
, utsname
.sysname
, sizeof(buf
));
371 (void)xstrlcat(buf
, " ", sizeof(buf
));
372 (void)xstrlcat(buf
, utsname
.release
, sizeof(buf
));
375 mdoc
->meta
.os
= xstrdup(buf
);
376 mdoc_msg(mdoc
, "system: %s", mdoc
->meta
.os
);
378 mdoc
->lastnamed
= mdoc
->lastsec
= SEC_BODY
;
380 return(post_prologue(mdoc
));
385 post_bl_tagwidth(struct mdoc
*mdoc
)
388 struct mdoc_block
*b
;
393 * If -tag has been specified and -width has not been, then try
394 * to intuit our width from the first body element.
397 b
= &mdoc
->last
->data
.block
;
399 if (NULL
== (n
= b
->body
->child
))
401 assert(MDOC_It
== n
->tok
);
404 * Use the text width, if a text node, or the default macro
408 if ((n
= n
->data
.block
.head
->child
)) {
409 if (MDOC_TEXT
!= n
->type
) {
410 if (0 == (sz
= mdoc_macro2len(n
->tok
)))
413 sz
= (int)strlen(n
->data
.text
.string
) + 1;
418 if ( ! mdoc_warn(mdoc
, WARN_SYNTAX
,
419 "cannot determine default %s",
420 mdoc_argnames
[MDOC_Width
]))
425 (void)snprintf(buf
, sizeof(buf
), "%dn", sz
);
428 * We have to dynamically add this to the macro's argument list.
429 * We're guaranteed that a MDOC_Width doesn't already exist.
433 b
->argv
= xrealloc(b
->argv
, b
->argc
* sizeof(struct mdoc_arg
));
435 b
->argv
[b
->argc
- 1].arg
= MDOC_Width
;
436 b
->argv
[b
->argc
- 1].line
= mdoc
->last
->line
;
437 b
->argv
[b
->argc
- 1].pos
= mdoc
->last
->pos
;
438 b
->argv
[b
->argc
- 1].sz
= 1;
439 b
->argv
[b
->argc
- 1].value
= xcalloc(1, sizeof(char *));
440 b
->argv
[b
->argc
- 1].value
[0] = xstrdup(buf
);
442 mdoc_msg(mdoc
, "adding %s argument: %dn",
443 mdoc_argnames
[MDOC_Width
], sz
);
450 post_bl_width(struct mdoc
*mdoc
)
457 for (i
= 0; i
< (int)mdoc
->last
->data
.block
.argc
; i
++)
458 if (MDOC_Width
== mdoc
->last
->data
.block
.argv
[i
].arg
)
461 assert(i
< (int)mdoc
->last
->data
.block
.argc
);
462 assert(1 == mdoc
->last
->data
.block
.argv
[i
].sz
);
463 p
= &mdoc
->last
->data
.block
.argv
[i
].value
[0];
466 * If the value to -width is a macro, then we re-write it to be
467 * the macro's width as set in share/tmac/mdoc/doc-common.
470 if (xstrcmp(*p
, "Ds"))
472 else if (MDOC_MAX
== (tok
= mdoc_find(mdoc
, *p
)))
474 else if (0 == (width
= mdoc_macro2len(tok
)))
475 return(mdoc_warn(mdoc
, WARN_SYNTAX
,
476 "%s macro has no length",
477 mdoc_argnames
[MDOC_Width
]));
479 mdoc_msg(mdoc
, "re-writing %s argument: %s -> %zun",
480 mdoc_argnames
[MDOC_Width
], *p
, width
);
482 /* The value already exists: free and reallocate it. */
484 (void)snprintf(buf
, sizeof(buf
), "%zun", width
);
494 post_bl(struct mdoc
*mdoc
)
498 if (MDOC_BLOCK
!= mdoc
->last
->type
)
502 * These are fairly complicated, so we've broken them into two
503 * functions. post_bl_tagwidth() is called when a -tag is
504 * specified, but no -width (it must be guessed). The second
505 * when a -width is specified (macro indicators must be
506 * rewritten into real lengths).
509 for (r
= i
= 0; i
< (int)mdoc
->last
->data
.block
.argc
; i
++) {
510 if (MDOC_Tag
== mdoc
->last
->data
.block
.argv
[i
].arg
)
512 if (MDOC_Width
== mdoc
->last
->data
.block
.argv
[i
].arg
)
516 if (r
& (1 << 0) && ! (r
& (1 << 1))) {
517 if ( ! post_bl_tagwidth(mdoc
))
519 } else if (r
& (1 << 1))
520 if ( ! post_bl_width(mdoc
))
528 post_ar(struct mdoc
*mdoc
)
532 if (mdoc
->last
->child
)
537 mdoc
->next
= MDOC_NEXT_CHILD
;
538 mdoc_word_alloc(mdoc
, mdoc
->last
->line
,
539 mdoc
->last
->pos
, "file");
540 mdoc
->next
= MDOC_NEXT_SIBLING
;
541 mdoc_word_alloc(mdoc
, mdoc
->last
->line
,
542 mdoc
->last
->pos
, "...");
545 mdoc
->next
= MDOC_NEXT_SIBLING
;
551 post_dd(struct mdoc
*mdoc
)
555 (void)xstrlcpys(buf
, mdoc
->last
->child
, sizeof(buf
));
557 if (0 == (mdoc
->meta
.date
= mdoc_atotime(buf
)))
558 return(mdoc_err(mdoc
, "invalid date syntax"));
560 mdoc_msg(mdoc
, "date: %u", mdoc
->meta
.date
);
561 return(post_prologue(mdoc
));
566 post_prologue(struct mdoc
*mdoc
)
571 * The end document shouldn't have the prologue macros as part
572 * of the syntax tree (they encompass only meta-data).
575 if (mdoc
->last
->parent
->child
== mdoc
->last
)
576 mdoc
->last
->parent
->child
= mdoc
->last
->prev
;
577 if (mdoc
->last
->prev
)
578 mdoc
->last
->prev
->next
= NULL
;
581 assert(NULL
== mdoc
->last
->next
);
583 if (mdoc
->last
->prev
) {
584 mdoc
->last
= mdoc
->last
->prev
;
585 mdoc
->next
= MDOC_NEXT_SIBLING
;
587 mdoc
->last
= mdoc
->last
->parent
;
588 mdoc
->next
= MDOC_NEXT_CHILD
;
591 mdoc_node_freelist(n
);
597 mdoc_action_post(struct mdoc
*mdoc
)
600 if (MDOC_ACTED
& mdoc
->last
->flags
)
602 mdoc
->last
->flags
|= MDOC_ACTED
;
604 if (MDOC_TEXT
== mdoc
->last
->type
)
606 if (MDOC_ROOT
== mdoc
->last
->type
)
608 if (NULL
== mdoc_actions
[mdoc
->last
->tok
].post
)
610 return((*mdoc_actions
[mdoc
->last
->tok
].post
)(mdoc
));