1 /* $Id: mdoc_validate.c,v 1.301 2016/01/08 17:48:09 schwarze Exp $ */
3 * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2010-2016 Ingo Schwarze <schwarze@openbsd.org>
5 * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 #include <sys/types.h>
23 #include <sys/utsname.h>
34 #include "mandoc_aux.h"
38 #include "libmandoc.h"
42 /* FIXME: .Bl -diag can't have non-text children in HEAD. */
44 #define POST_ARGS struct roff_man *mdoc
52 typedef void (*v_post
)(POST_ARGS
);
54 static void check_text(struct roff_man
*, int, int, char *);
55 static void check_argv(struct roff_man
*,
56 struct roff_node
*, struct mdoc_argv
*);
57 static void check_args(struct roff_man
*, struct roff_node
*);
58 static int child_an(const struct roff_node
*);
59 static size_t macro2len(int);
60 static void rewrite_macro2len(char **);
62 static void post_an(POST_ARGS
);
63 static void post_an_norm(POST_ARGS
);
64 static void post_at(POST_ARGS
);
65 static void post_bd(POST_ARGS
);
66 static void post_bf(POST_ARGS
);
67 static void post_bk(POST_ARGS
);
68 static void post_bl(POST_ARGS
);
69 static void post_bl_block(POST_ARGS
);
70 static void post_bl_block_tag(POST_ARGS
);
71 static void post_bl_head(POST_ARGS
);
72 static void post_bl_norm(POST_ARGS
);
73 static void post_bx(POST_ARGS
);
74 static void post_defaults(POST_ARGS
);
75 static void post_display(POST_ARGS
);
76 static void post_dd(POST_ARGS
);
77 static void post_dt(POST_ARGS
);
78 static void post_en(POST_ARGS
);
79 static void post_es(POST_ARGS
);
80 static void post_eoln(POST_ARGS
);
81 static void post_ex(POST_ARGS
);
82 static void post_fa(POST_ARGS
);
83 static void post_fn(POST_ARGS
);
84 static void post_fname(POST_ARGS
);
85 static void post_fo(POST_ARGS
);
86 static void post_hyph(POST_ARGS
);
87 static void post_ignpar(POST_ARGS
);
88 static void post_it(POST_ARGS
);
89 static void post_lb(POST_ARGS
);
90 static void post_nd(POST_ARGS
);
91 static void post_nm(POST_ARGS
);
92 static void post_ns(POST_ARGS
);
93 static void post_obsolete(POST_ARGS
);
94 static void post_os(POST_ARGS
);
95 static void post_par(POST_ARGS
);
96 static void post_prevpar(POST_ARGS
);
97 static void post_root(POST_ARGS
);
98 static void post_rs(POST_ARGS
);
99 static void post_sh(POST_ARGS
);
100 static void post_sh_head(POST_ARGS
);
101 static void post_sh_name(POST_ARGS
);
102 static void post_sh_see_also(POST_ARGS
);
103 static void post_sh_authors(POST_ARGS
);
104 static void post_sm(POST_ARGS
);
105 static void post_st(POST_ARGS
);
106 static void post_std(POST_ARGS
);
108 static v_post mdoc_valids
[MDOC_MAX
] = {
114 post_ignpar
, /* Ss */
116 post_display
, /* D1 */
117 post_display
, /* Dl */
118 post_display
, /* Bd */
125 post_defaults
, /* Ar */
139 post_defaults
, /* Li */
143 post_obsolete
, /* Ot */
144 post_defaults
, /* Pa */
151 post_hyph
, /* %B */ /* FIXME: can be used outside Rs/Re. */
159 post_hyph
, /* %T */ /* FIXME: can be used outside Rs/Re. */
171 post_obsolete
, /* Db */
213 post_obsolete
, /* Fr */
218 post_defaults
, /* Mt */
234 #define RSORD_MAX 14 /* Number of `Rs' blocks. */
236 static const int rsord
[RSORD_MAX
] = {
253 static const char * const secnames
[SEC__MAX
] = {
260 "IMPLEMENTATION NOTES",
275 "SECURITY CONSIDERATIONS",
281 mdoc_node_validate(struct roff_man
*mdoc
)
287 mdoc
->last
= mdoc
->last
->child
;
288 while (mdoc
->last
!= NULL
) {
289 mdoc_node_validate(mdoc
);
291 mdoc
->last
= mdoc
->last
->child
;
293 mdoc
->last
= mdoc
->last
->next
;
297 mdoc
->next
= ROFF_NEXT_SIBLING
;
300 if (n
->sec
!= SEC_SYNOPSIS
|| n
->parent
->tok
!= MDOC_Fd
)
301 check_text(mdoc
, n
->line
, n
->pos
, n
->string
);
310 check_args(mdoc
, mdoc
->last
);
313 * Closing delimiters are not special at the
314 * beginning of a block, opening delimiters
315 * are not special at the end.
318 if (n
->child
!= NULL
)
319 n
->child
->flags
&= ~MDOC_DELIMC
;
321 n
->last
->flags
&= ~MDOC_DELIMO
;
323 /* Call the macro's postprocessor. */
325 p
= mdoc_valids
+ n
->tok
;
335 check_args(struct roff_man
*mdoc
, struct roff_node
*n
)
342 assert(n
->args
->argc
);
343 for (i
= 0; i
< (int)n
->args
->argc
; i
++)
344 check_argv(mdoc
, n
, &n
->args
->argv
[i
]);
348 check_argv(struct roff_man
*mdoc
, struct roff_node
*n
, struct mdoc_argv
*v
)
352 for (i
= 0; i
< (int)v
->sz
; i
++)
353 check_text(mdoc
, v
->line
, v
->pos
, v
->value
[i
]);
357 check_text(struct roff_man
*mdoc
, int ln
, int pos
, char *p
)
361 if (MDOC_LITERAL
& mdoc
->flags
)
364 for (cp
= p
; NULL
!= (p
= strchr(p
, '\t')); p
++)
365 mandoc_msg(MANDOCERR_FI_TAB
, mdoc
->parse
,
366 ln
, pos
+ (int)(p
- cp
), NULL
);
370 post_bl_norm(POST_ARGS
)
373 struct mdoc_argv
*argv
, *wa
;
375 enum mdocargt mdoclt
;
378 n
= mdoc
->last
->parent
;
379 n
->norm
->Bl
.type
= LIST__NONE
;
382 * First figure out which kind of list to use: bind ourselves to
383 * the first mentioned list type and warn about any remaining
384 * ones. If we find no list type, we default to LIST_item.
387 wa
= (n
->args
== NULL
) ? NULL
: n
->args
->argv
;
388 mdoclt
= MDOC_ARG_MAX
;
389 for (i
= 0; n
->args
&& i
< (int)n
->args
->argc
; i
++) {
390 argv
= n
->args
->argv
+ i
;
393 /* Set list types. */
427 /* Set list arguments. */
429 if (n
->norm
->Bl
.comp
)
430 mandoc_msg(MANDOCERR_ARG_REP
,
431 mdoc
->parse
, argv
->line
,
432 argv
->pos
, "Bl -compact");
433 n
->norm
->Bl
.comp
= 1;
438 mandoc_msg(MANDOCERR_ARG_EMPTY
,
439 mdoc
->parse
, argv
->line
,
440 argv
->pos
, "Bl -width");
441 n
->norm
->Bl
.width
= "0n";
444 if (NULL
!= n
->norm
->Bl
.width
)
445 mandoc_vmsg(MANDOCERR_ARG_REP
,
446 mdoc
->parse
, argv
->line
,
447 argv
->pos
, "Bl -width %s",
449 rewrite_macro2len(argv
->value
);
450 n
->norm
->Bl
.width
= argv
->value
[0];
454 mandoc_msg(MANDOCERR_ARG_EMPTY
,
455 mdoc
->parse
, argv
->line
,
456 argv
->pos
, "Bl -offset");
459 if (NULL
!= n
->norm
->Bl
.offs
)
460 mandoc_vmsg(MANDOCERR_ARG_REP
,
461 mdoc
->parse
, argv
->line
,
462 argv
->pos
, "Bl -offset %s",
464 rewrite_macro2len(argv
->value
);
465 n
->norm
->Bl
.offs
= argv
->value
[0];
470 if (LIST__NONE
== lt
)
474 /* Check: multiple list types. */
476 if (LIST__NONE
!= n
->norm
->Bl
.type
) {
477 mandoc_vmsg(MANDOCERR_BL_REP
,
478 mdoc
->parse
, n
->line
, n
->pos
,
479 "Bl -%s", mdoc_argnames
[argv
->arg
]);
483 /* The list type should come first. */
485 if (n
->norm
->Bl
.width
||
488 mandoc_vmsg(MANDOCERR_BL_LATETYPE
,
489 mdoc
->parse
, n
->line
, n
->pos
, "Bl -%s",
490 mdoc_argnames
[n
->args
->argv
[0].arg
]);
492 n
->norm
->Bl
.type
= lt
;
493 if (LIST_column
== lt
) {
494 n
->norm
->Bl
.ncols
= argv
->sz
;
495 n
->norm
->Bl
.cols
= (void *)argv
->value
;
499 /* Allow lists to default to LIST_item. */
501 if (LIST__NONE
== n
->norm
->Bl
.type
) {
502 mandoc_msg(MANDOCERR_BL_NOTYPE
, mdoc
->parse
,
503 n
->line
, n
->pos
, "Bl");
504 n
->norm
->Bl
.type
= LIST_item
;
508 * Validate the width field. Some list types don't need width
509 * types and should be warned about them. Others should have it
510 * and must also be warned. Yet others have a default and need
514 switch (n
->norm
->Bl
.type
) {
516 if (NULL
== n
->norm
->Bl
.width
)
517 mandoc_msg(MANDOCERR_BL_NOWIDTH
, mdoc
->parse
,
518 n
->line
, n
->pos
, "Bl -tag");
525 if (n
->norm
->Bl
.width
)
526 mandoc_vmsg(MANDOCERR_BL_SKIPW
, mdoc
->parse
,
527 wa
->line
, wa
->pos
, "Bl -%s",
528 mdoc_argnames
[mdoclt
]);
533 if (NULL
== n
->norm
->Bl
.width
)
534 n
->norm
->Bl
.width
= "2n";
537 if (NULL
== n
->norm
->Bl
.width
)
538 n
->norm
->Bl
.width
= "3n";
549 struct mdoc_argv
*argv
;
554 for (i
= 0; n
->args
&& i
< (int)n
->args
->argc
; i
++) {
555 argv
= n
->args
->argv
+ i
;
575 mandoc_msg(MANDOCERR_BD_FILE
, mdoc
->parse
,
576 n
->line
, n
->pos
, NULL
);
580 mandoc_msg(MANDOCERR_ARG_EMPTY
,
581 mdoc
->parse
, argv
->line
,
582 argv
->pos
, "Bd -offset");
585 if (NULL
!= n
->norm
->Bd
.offs
)
586 mandoc_vmsg(MANDOCERR_ARG_REP
,
587 mdoc
->parse
, argv
->line
,
588 argv
->pos
, "Bd -offset %s",
590 rewrite_macro2len(argv
->value
);
591 n
->norm
->Bd
.offs
= argv
->value
[0];
594 if (n
->norm
->Bd
.comp
)
595 mandoc_msg(MANDOCERR_ARG_REP
,
596 mdoc
->parse
, argv
->line
,
597 argv
->pos
, "Bd -compact");
598 n
->norm
->Bd
.comp
= 1;
603 if (DISP__NONE
== dt
)
606 if (DISP__NONE
== n
->norm
->Bd
.type
)
607 n
->norm
->Bd
.type
= dt
;
609 mandoc_vmsg(MANDOCERR_BD_REP
,
610 mdoc
->parse
, n
->line
, n
->pos
,
611 "Bd -%s", mdoc_argnames
[argv
->arg
]);
614 if (DISP__NONE
== n
->norm
->Bd
.type
) {
615 mandoc_msg(MANDOCERR_BD_NOTYPE
, mdoc
->parse
,
616 n
->line
, n
->pos
, "Bd");
617 n
->norm
->Bd
.type
= DISP_ragged
;
622 post_an_norm(POST_ARGS
)
625 struct mdoc_argv
*argv
;
632 for (i
= 1; i
< n
->args
->argc
; i
++) {
633 argv
= n
->args
->argv
+ i
;
634 mandoc_vmsg(MANDOCERR_AN_REP
,
635 mdoc
->parse
, argv
->line
, argv
->pos
,
636 "An -%s", mdoc_argnames
[argv
->arg
]);
639 argv
= n
->args
->argv
;
640 if (argv
->arg
== MDOC_Split
)
641 n
->norm
->An
.auth
= AUTH_split
;
642 else if (argv
->arg
== MDOC_Nosplit
)
643 n
->norm
->An
.auth
= AUTH_nosplit
;
654 if (n
->args
&& n
->args
->argc
== 1)
655 if (n
->args
->argv
[0].arg
== MDOC_Std
)
658 mandoc_msg(MANDOCERR_ARG_STD
, mdoc
->parse
,
659 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
663 post_obsolete(POST_ARGS
)
668 if (n
->type
== ROFFT_ELEM
|| n
->type
== ROFFT_BLOCK
)
669 mandoc_msg(MANDOCERR_MACRO_OBS
, mdoc
->parse
,
670 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
676 struct roff_node
*np
, *nch
;
679 * Unlike other data pointers, these are "housed" by the HEAD
680 * element, which contains the goods.
684 if (np
->type
!= ROFFT_HEAD
)
687 assert(np
->parent
->type
== ROFFT_BLOCK
);
688 assert(np
->parent
->tok
== MDOC_Bf
);
690 /* Check the number of arguments. */
693 if (np
->parent
->args
== NULL
) {
695 mandoc_msg(MANDOCERR_BF_NOFONT
, mdoc
->parse
,
696 np
->line
, np
->pos
, "Bf");
702 mandoc_vmsg(MANDOCERR_ARG_EXCESS
, mdoc
->parse
,
703 nch
->line
, nch
->pos
, "Bf ... %s", nch
->string
);
705 /* Extract argument into data. */
707 if (np
->parent
->args
!= NULL
) {
708 switch (np
->parent
->args
->argv
[0].arg
) {
710 np
->norm
->Bf
.font
= FONT_Em
;
713 np
->norm
->Bf
.font
= FONT_Li
;
716 np
->norm
->Bf
.font
= FONT_Sy
;
724 /* Extract parameter into data. */
726 if ( ! strcmp(np
->child
->string
, "Em"))
727 np
->norm
->Bf
.font
= FONT_Em
;
728 else if ( ! strcmp(np
->child
->string
, "Li"))
729 np
->norm
->Bf
.font
= FONT_Li
;
730 else if ( ! strcmp(np
->child
->string
, "Sy"))
731 np
->norm
->Bf
.font
= FONT_Sy
;
733 mandoc_vmsg(MANDOCERR_BF_BADFONT
, mdoc
->parse
,
734 np
->child
->line
, np
->child
->pos
,
735 "Bf %s", np
->child
->string
);
742 const char *stdlibname
;
745 n
= mdoc
->last
->child
;
746 assert(n
->type
== ROFFT_TEXT
);
748 if (NULL
== (stdlibname
= mdoc_a2lib(n
->string
)))
749 mandoc_asprintf(&libname
,
750 "library \\(Lq%s\\(Rq", n
->string
);
752 libname
= mandoc_strdup(stdlibname
);
761 const struct roff_node
*n
;
764 if (n
->child
!= NULL
)
765 mandoc_vmsg(MANDOCERR_ARG_SKIP
,
766 mdoc
->parse
, n
->line
, n
->pos
,
767 "%s %s", mdoc_macronames
[n
->tok
],
772 post_fname(POST_ARGS
)
774 const struct roff_node
*n
;
778 n
= mdoc
->last
->child
;
779 pos
= strcspn(n
->string
, "()");
780 cp
= n
->string
+ pos
;
781 if ( ! (cp
[0] == '\0' || (cp
[0] == '(' && cp
[1] == '*')))
782 mandoc_msg(MANDOCERR_FN_PAREN
, mdoc
->parse
,
783 n
->line
, n
->pos
+ pos
, n
->string
);
797 const struct roff_node
*n
;
801 if (n
->type
!= ROFFT_HEAD
)
804 if (n
->child
== NULL
) {
805 mandoc_msg(MANDOCERR_FO_NOHEAD
, mdoc
->parse
,
806 n
->line
, n
->pos
, "Fo");
809 if (n
->child
!= n
->last
) {
810 mandoc_vmsg(MANDOCERR_ARG_EXCESS
, mdoc
->parse
,
811 n
->child
->next
->line
, n
->child
->next
->pos
,
812 "Fo ... %s", n
->child
->next
->string
);
813 while (n
->child
!= n
->last
)
814 roff_node_delete(mdoc
, n
->last
);
823 const struct roff_node
*n
;
826 for (n
= mdoc
->last
->child
; n
!= NULL
; n
= n
->next
) {
827 for (cp
= n
->string
; *cp
!= '\0'; cp
++) {
828 /* Ignore callbacks and alterations. */
829 if (*cp
== '(' || *cp
== '{')
833 mandoc_msg(MANDOCERR_FA_COMMA
, mdoc
->parse
,
834 n
->line
, n
->pos
+ (cp
- n
->string
),
848 if (n
->last
!= NULL
&&
849 (n
->last
->tok
== MDOC_Pp
||
850 n
->last
->tok
== MDOC_Lp
))
851 mdoc_node_relink(mdoc
, n
->last
);
853 if (mdoc
->meta
.name
!= NULL
)
856 deroff(&mdoc
->meta
.name
, n
);
858 if (mdoc
->meta
.name
== NULL
)
859 mandoc_msg(MANDOCERR_NM_NONAME
, mdoc
->parse
,
860 n
->line
, n
->pos
, "Nm");
870 if (n
->type
!= ROFFT_BODY
)
873 if (n
->child
== NULL
)
874 mandoc_msg(MANDOCERR_ND_EMPTY
, mdoc
->parse
,
875 n
->line
, n
->pos
, "Nd");
881 post_display(POST_ARGS
)
883 struct roff_node
*n
, *np
;
888 if (n
->end
!= ENDBODY_NOT
)
890 if (n
->child
== NULL
)
891 mandoc_msg(MANDOCERR_BLK_EMPTY
, mdoc
->parse
,
892 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
893 else if (n
->tok
== MDOC_D1
)
897 if (n
->tok
== MDOC_Bd
) {
898 if (n
->args
== NULL
) {
899 mandoc_msg(MANDOCERR_BD_NOARG
,
900 mdoc
->parse
, n
->line
, n
->pos
, "Bd");
901 mdoc
->next
= ROFF_NEXT_SIBLING
;
902 while (n
->body
->child
!= NULL
)
903 mdoc_node_relink(mdoc
,
905 roff_node_delete(mdoc
, n
);
911 for (np
= n
->parent
; np
!= NULL
; np
= np
->parent
) {
912 if (np
->type
== ROFFT_BLOCK
&& np
->tok
== MDOC_Bd
) {
913 mandoc_vmsg(MANDOCERR_BD_NEST
,
914 mdoc
->parse
, n
->line
, n
->pos
,
915 "%s in Bd", mdoc_macronames
[n
->tok
]);
926 post_defaults(POST_ARGS
)
928 struct roff_node
*nn
;
931 * The `Ar' defaults to "file ..." if no value is provided as an
932 * argument; the `Mt' and `Pa' macros use "~"; the `Li' just
933 * gets an empty string.
936 if (mdoc
->last
->child
!= NULL
)
943 mdoc
->next
= ROFF_NEXT_CHILD
;
944 roff_word_alloc(mdoc
, nn
->line
, nn
->pos
, "file");
945 roff_word_alloc(mdoc
, nn
->line
, nn
->pos
, "...");
949 mdoc
->next
= ROFF_NEXT_CHILD
;
950 roff_word_alloc(mdoc
, nn
->line
, nn
->pos
, "~");
966 if (n
->child
== NULL
) {
967 mdoc
->next
= ROFF_NEXT_CHILD
;
968 roff_word_alloc(mdoc
, n
->line
, n
->pos
, "AT&T UNIX");
974 * If we have a child, look it up in the standard keys. If a
975 * key exist, use that instead of the child; if it doesn't,
976 * prefix "AT&T UNIX " to the existing data.
980 assert(n
->type
== ROFFT_TEXT
);
981 if ((std_att
= mdoc_a2att(n
->string
)) == NULL
) {
982 mandoc_vmsg(MANDOCERR_AT_BAD
, mdoc
->parse
,
983 n
->line
, n
->pos
, "At %s", n
->string
);
984 mandoc_asprintf(&att
, "AT&T UNIX %s", n
->string
);
986 att
= mandoc_strdup(std_att
);
995 struct roff_node
*np
, *nch
;
1001 if (np
->norm
->An
.auth
== AUTH__NONE
) {
1003 mandoc_msg(MANDOCERR_MACRO_EMPTY
, mdoc
->parse
,
1004 np
->line
, np
->pos
, "An");
1005 } else if (nch
!= NULL
)
1006 mandoc_vmsg(MANDOCERR_ARG_EXCESS
, mdoc
->parse
,
1007 nch
->line
, nch
->pos
, "An ... %s", nch
->string
);
1014 post_obsolete(mdoc
);
1015 if (mdoc
->last
->type
== ROFFT_BLOCK
)
1016 mdoc
->last
->norm
->Es
= mdoc
->last_es
;
1023 post_obsolete(mdoc
);
1024 mdoc
->last_es
= mdoc
->last
;
1030 struct roff_node
*nbl
, *nit
, *nch
;
1037 if (nit
->type
!= ROFFT_BLOCK
)
1040 nbl
= nit
->parent
->parent
;
1041 lt
= nbl
->norm
->Bl
.type
;
1049 if (nit
->head
->child
== NULL
)
1050 mandoc_vmsg(MANDOCERR_IT_NOHEAD
,
1051 mdoc
->parse
, nit
->line
, nit
->pos
,
1053 mdoc_argnames
[nbl
->args
->argv
[0].arg
]);
1059 if (nit
->body
== NULL
|| nit
->body
->child
== NULL
)
1060 mandoc_vmsg(MANDOCERR_IT_NOBODY
,
1061 mdoc
->parse
, nit
->line
, nit
->pos
,
1063 mdoc_argnames
[nbl
->args
->argv
[0].arg
]);
1066 if (nit
->head
->child
!= NULL
)
1067 mandoc_vmsg(MANDOCERR_ARG_SKIP
,
1068 mdoc
->parse
, nit
->line
, nit
->pos
,
1069 "It %s", nit
->head
->child
->string
);
1072 cols
= (int)nbl
->norm
->Bl
.ncols
;
1074 assert(nit
->head
->child
== NULL
);
1077 for (nch
= nit
->child
; nch
!= NULL
; nch
= nch
->next
)
1078 if (nch
->type
== ROFFT_BODY
)
1081 if (i
< cols
|| i
> cols
+ 1)
1082 mandoc_vmsg(MANDOCERR_BL_COL
,
1083 mdoc
->parse
, nit
->line
, nit
->pos
,
1084 "%d columns, %d cells", cols
, i
);
1092 post_bl_block(POST_ARGS
)
1094 struct roff_node
*n
, *ni
, *nc
;
1099 * These are fairly complicated, so we've broken them into two
1100 * functions. post_bl_block_tag() is called when a -tag is
1101 * specified, but no -width (it must be guessed). The second
1102 * when a -width is specified (macro indicators must be
1103 * rewritten into real lengths).
1108 if (n
->norm
->Bl
.type
== LIST_tag
&&
1109 n
->norm
->Bl
.width
== NULL
) {
1110 post_bl_block_tag(mdoc
);
1111 assert(n
->norm
->Bl
.width
!= NULL
);
1114 for (ni
= n
->body
->child
; ni
!= NULL
; ni
= ni
->next
) {
1115 if (ni
->body
== NULL
)
1117 nc
= ni
->body
->last
;
1118 while (nc
!= NULL
) {
1128 if (ni
->next
== NULL
) {
1129 mandoc_msg(MANDOCERR_PAR_MOVE
,
1130 mdoc
->parse
, nc
->line
, nc
->pos
,
1131 mdoc_macronames
[nc
->tok
]);
1132 mdoc_node_relink(mdoc
, nc
);
1133 } else if (n
->norm
->Bl
.comp
== 0 &&
1134 n
->norm
->Bl
.type
!= LIST_column
) {
1135 mandoc_vmsg(MANDOCERR_PAR_SKIP
,
1136 mdoc
->parse
, nc
->line
, nc
->pos
,
1138 mdoc_macronames
[nc
->tok
]);
1139 roff_node_delete(mdoc
, nc
);
1142 nc
= ni
->body
->last
;
1148 * If the argument of -offset or -width is a macro,
1149 * replace it with the associated default width.
1152 rewrite_macro2len(char **arg
)
1159 else if ( ! strcmp(*arg
, "Ds"))
1161 else if ((tok
= mdoc_hash_find(*arg
)) == TOKEN_NONE
)
1164 width
= macro2len(tok
);
1167 mandoc_asprintf(arg
, "%zun", width
);
1171 post_bl_block_tag(POST_ARGS
)
1173 struct roff_node
*n
, *nn
;
1179 * Calculate the -width for a `Bl -tag' list if it hasn't been
1180 * provided. Uses the first head macro. NOTE AGAIN: this is
1181 * ONLY if the -width argument has NOT been provided. See
1182 * rewrite_macro2len() for converting the -width string.
1188 for (nn
= n
->body
->child
; nn
!= NULL
; nn
= nn
->next
) {
1189 if (nn
->tok
!= MDOC_It
)
1192 assert(nn
->type
== ROFFT_BLOCK
);
1193 nn
= nn
->head
->child
;
1198 if (nn
->type
== ROFFT_TEXT
) {
1199 sz
= strlen(nn
->string
) + 1;
1203 if (0 != (ssz
= macro2len(nn
->tok
)))
1209 /* Defaults to ten ens. */
1211 (void)snprintf(buf
, sizeof(buf
), "%un", (unsigned int)sz
);
1214 * We have to dynamically add this to the macro's argument list.
1215 * We're guaranteed that a MDOC_Width doesn't already exist.
1218 assert(n
->args
!= NULL
);
1219 i
= (int)(n
->args
->argc
)++;
1221 n
->args
->argv
= mandoc_reallocarray(n
->args
->argv
,
1222 n
->args
->argc
, sizeof(struct mdoc_argv
));
1224 n
->args
->argv
[i
].arg
= MDOC_Width
;
1225 n
->args
->argv
[i
].line
= n
->line
;
1226 n
->args
->argv
[i
].pos
= n
->pos
;
1227 n
->args
->argv
[i
].sz
= 1;
1228 n
->args
->argv
[i
].value
= mandoc_malloc(sizeof(char *));
1229 n
->args
->argv
[i
].value
[0] = mandoc_strdup(buf
);
1231 /* Set our width! */
1232 n
->norm
->Bl
.width
= n
->args
->argv
[i
].value
[0];
1236 post_bl_head(POST_ARGS
)
1238 struct roff_node
*nbl
, *nh
, *nch
, *nnext
;
1239 struct mdoc_argv
*argv
;
1245 if (nh
->norm
->Bl
.type
!= LIST_column
) {
1246 if ((nch
= nh
->child
) == NULL
)
1248 mandoc_vmsg(MANDOCERR_ARG_EXCESS
, mdoc
->parse
,
1249 nch
->line
, nch
->pos
, "Bl ... %s", nch
->string
);
1250 while (nch
!= NULL
) {
1251 roff_node_delete(mdoc
, nch
);
1258 * Append old-style lists, where the column width specifiers
1259 * trail as macro parameters, to the new-style ("normal-form")
1260 * lists where they're argument values following -column.
1263 if (nh
->child
== NULL
)
1267 for (j
= 0; j
< (int)nbl
->args
->argc
; j
++)
1268 if (nbl
->args
->argv
[j
].arg
== MDOC_Column
)
1271 assert(j
< (int)nbl
->args
->argc
);
1274 * Accommodate for new-style groff column syntax. Shuffle the
1275 * child nodes, all of which must be TEXT, as arguments for the
1276 * column field. Then, delete the head children.
1279 argv
= nbl
->args
->argv
+ j
;
1281 for (nch
= nh
->child
; nch
!= NULL
; nch
= nch
->next
)
1283 argv
->value
= mandoc_reallocarray(argv
->value
,
1284 argv
->sz
, sizeof(char *));
1286 nh
->norm
->Bl
.ncols
= argv
->sz
;
1287 nh
->norm
->Bl
.cols
= (void *)argv
->value
;
1289 for (nch
= nh
->child
; nch
!= NULL
; nch
= nnext
) {
1290 argv
->value
[i
++] = nch
->string
;
1293 roff_node_delete(NULL
, nch
);
1301 struct roff_node
*nparent
, *nprev
; /* of the Bl block */
1302 struct roff_node
*nblock
, *nbody
; /* of the Bl */
1303 struct roff_node
*nchild
, *nnext
; /* of the Bl body */
1306 switch (nbody
->type
) {
1308 post_bl_block(mdoc
);
1318 if (nbody
->end
!= ENDBODY_NOT
)
1321 nchild
= nbody
->child
;
1322 if (nchild
== NULL
) {
1323 mandoc_msg(MANDOCERR_BLK_EMPTY
, mdoc
->parse
,
1324 nbody
->line
, nbody
->pos
, "Bl");
1327 while (nchild
!= NULL
) {
1328 if (nchild
->tok
== MDOC_It
||
1329 (nchild
->tok
== MDOC_Sm
&&
1330 nchild
->next
!= NULL
&&
1331 nchild
->next
->tok
== MDOC_It
)) {
1332 nchild
= nchild
->next
;
1336 mandoc_msg(MANDOCERR_BL_MOVE
, mdoc
->parse
,
1337 nchild
->line
, nchild
->pos
,
1338 mdoc_macronames
[nchild
->tok
]);
1341 * Move the node out of the Bl block.
1342 * First, collect all required node pointers.
1345 nblock
= nbody
->parent
;
1346 nprev
= nblock
->prev
;
1347 nparent
= nblock
->parent
;
1348 nnext
= nchild
->next
;
1351 * Unlink this child.
1354 assert(nchild
->prev
== NULL
);
1355 nbody
->child
= nnext
;
1362 * Relink this child.
1365 nchild
->parent
= nparent
;
1366 nchild
->prev
= nprev
;
1367 nchild
->next
= nblock
;
1369 nblock
->prev
= nchild
;
1371 nparent
->child
= nchild
;
1373 nprev
->next
= nchild
;
1382 struct roff_node
*n
;
1386 if (n
->type
== ROFFT_BLOCK
&& n
->body
->child
== NULL
) {
1387 mandoc_msg(MANDOCERR_BLK_EMPTY
,
1388 mdoc
->parse
, n
->line
, n
->pos
, "Bk");
1389 roff_node_delete(mdoc
, n
);
1396 struct roff_node
*nch
;
1398 nch
= mdoc
->last
->child
;
1401 mdoc
->flags
^= MDOC_SMOFF
;
1405 assert(nch
->type
== ROFFT_TEXT
);
1407 if ( ! strcmp(nch
->string
, "on")) {
1408 mdoc
->flags
&= ~MDOC_SMOFF
;
1411 if ( ! strcmp(nch
->string
, "off")) {
1412 mdoc
->flags
|= MDOC_SMOFF
;
1416 mandoc_vmsg(MANDOCERR_SM_BAD
,
1417 mdoc
->parse
, nch
->line
, nch
->pos
,
1418 "%s %s", mdoc_macronames
[mdoc
->last
->tok
], nch
->string
);
1419 mdoc_node_relink(mdoc
, nch
);
1424 post_root(POST_ARGS
)
1426 struct roff_node
*n
;
1428 /* Add missing prologue data. */
1430 if (mdoc
->meta
.date
== NULL
)
1431 mdoc
->meta
.date
= mdoc
->quick
?
1433 mandoc_normdate(mdoc
->parse
, NULL
, 0, 0);
1435 if (mdoc
->meta
.title
== NULL
) {
1436 mandoc_msg(MANDOCERR_DT_NOTITLE
,
1437 mdoc
->parse
, 0, 0, "EOF");
1438 mdoc
->meta
.title
= mandoc_strdup("UNTITLED");
1441 if (mdoc
->meta
.vol
== NULL
)
1442 mdoc
->meta
.vol
= mandoc_strdup("LOCAL");
1444 if (mdoc
->meta
.os
== NULL
) {
1445 mandoc_msg(MANDOCERR_OS_MISSING
,
1446 mdoc
->parse
, 0, 0, NULL
);
1447 mdoc
->meta
.os
= mandoc_strdup("");
1450 /* Check that we begin with a proper `Sh'. */
1452 n
= mdoc
->first
->child
;
1453 while (n
!= NULL
&& n
->tok
!= TOKEN_NONE
&&
1454 mdoc_macros
[n
->tok
].flags
& MDOC_PROLOGUE
)
1458 mandoc_msg(MANDOCERR_DOC_EMPTY
, mdoc
->parse
, 0, 0, NULL
);
1459 else if (n
->tok
!= MDOC_Sh
)
1460 mandoc_msg(MANDOCERR_SEC_BEFORE
, mdoc
->parse
,
1461 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
1467 struct roff_node
*n
, *nch
;
1473 assert(nch
->type
== ROFFT_TEXT
);
1475 if ((p
= mdoc_a2st(nch
->string
)) == NULL
) {
1476 mandoc_vmsg(MANDOCERR_ST_BAD
, mdoc
->parse
,
1477 nch
->line
, nch
->pos
, "St %s", nch
->string
);
1478 roff_node_delete(mdoc
, n
);
1481 nch
->string
= mandoc_strdup(p
);
1488 struct roff_node
*np
, *nch
, *next
, *prev
;
1493 if (np
->type
!= ROFFT_BODY
)
1496 if (np
->child
== NULL
) {
1497 mandoc_msg(MANDOCERR_RS_EMPTY
, mdoc
->parse
,
1498 np
->line
, np
->pos
, "Rs");
1503 * The full `Rs' block needs special handling to order the
1504 * sub-elements according to `rsord'. Pick through each element
1505 * and correctly order it. This is an insertion sort.
1509 for (nch
= np
->child
->next
; nch
!= NULL
; nch
= next
) {
1510 /* Determine order number of this child. */
1511 for (i
= 0; i
< RSORD_MAX
; i
++)
1512 if (rsord
[i
] == nch
->tok
)
1515 if (i
== RSORD_MAX
) {
1516 mandoc_msg(MANDOCERR_RS_BAD
,
1517 mdoc
->parse
, nch
->line
, nch
->pos
,
1518 mdoc_macronames
[nch
->tok
]);
1520 } else if (nch
->tok
== MDOC__J
|| nch
->tok
== MDOC__B
)
1521 np
->norm
->Rs
.quote_T
++;
1524 * Remove this child from the chain. This somewhat
1525 * repeats roff_node_unlink(), but since we're
1526 * just re-ordering, there's no need for the
1527 * full unlink process.
1530 if ((next
= nch
->next
) != NULL
)
1531 next
->prev
= nch
->prev
;
1533 if ((prev
= nch
->prev
) != NULL
)
1534 prev
->next
= nch
->next
;
1536 nch
->prev
= nch
->next
= NULL
;
1539 * Scan back until we reach a node that's
1540 * to be ordered before this child.
1543 for ( ; prev
; prev
= prev
->prev
) {
1544 /* Determine order of `prev'. */
1545 for (j
= 0; j
< RSORD_MAX
; j
++)
1546 if (rsord
[j
] == prev
->tok
)
1556 * Set this child back into its correct place
1557 * in front of the `prev' node.
1563 np
->child
->prev
= nch
;
1564 nch
->next
= np
->child
;
1568 prev
->next
->prev
= nch
;
1569 nch
->next
= prev
->next
;
1576 * For some arguments of some macros,
1577 * convert all breakable hyphens into ASCII_HYPH.
1580 post_hyph(POST_ARGS
)
1582 struct roff_node
*nch
;
1585 for (nch
= mdoc
->last
->child
; nch
!= NULL
; nch
= nch
->next
) {
1586 if (nch
->type
!= ROFFT_TEXT
)
1591 while (*(++cp
) != '\0')
1593 isalpha((unsigned char)cp
[-1]) &&
1594 isalpha((unsigned char)cp
[1]))
1603 if (mdoc
->last
->flags
& MDOC_LINE
)
1604 mandoc_msg(MANDOCERR_NS_SKIP
, mdoc
->parse
,
1605 mdoc
->last
->line
, mdoc
->last
->pos
, NULL
);
1614 switch (mdoc
->last
->type
) {
1619 switch (mdoc
->lastsec
) {
1624 post_sh_see_also(mdoc
);
1627 post_sh_authors(mdoc
);
1639 post_sh_name(POST_ARGS
)
1641 struct roff_node
*n
;
1646 for (n
= mdoc
->last
->child
; n
!= NULL
; n
= n
->next
) {
1653 if (n
->next
!= NULL
)
1654 mandoc_msg(MANDOCERR_NAMESEC_ND
,
1655 mdoc
->parse
, n
->line
, n
->pos
, NULL
);
1662 mandoc_msg(MANDOCERR_NAMESEC_BAD
, mdoc
->parse
,
1663 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
1669 mandoc_msg(MANDOCERR_NAMESEC_NONM
, mdoc
->parse
,
1670 mdoc
->last
->line
, mdoc
->last
->pos
, NULL
);
1672 mandoc_msg(MANDOCERR_NAMESEC_NOND
, mdoc
->parse
,
1673 mdoc
->last
->line
, mdoc
->last
->pos
, NULL
);
1677 post_sh_see_also(POST_ARGS
)
1679 const struct roff_node
*n
;
1680 const char *name
, *sec
;
1681 const char *lastname
, *lastsec
, *lastpunct
;
1684 n
= mdoc
->last
->child
;
1685 lastname
= lastsec
= lastpunct
= NULL
;
1687 if (n
->tok
!= MDOC_Xr
||
1689 n
->child
->next
== NULL
)
1692 /* Process one .Xr node. */
1694 name
= n
->child
->string
;
1695 sec
= n
->child
->next
->string
;
1696 if (lastsec
!= NULL
) {
1697 if (lastpunct
[0] != ',' || lastpunct
[1] != '\0')
1698 mandoc_vmsg(MANDOCERR_XR_PUNCT
,
1699 mdoc
->parse
, n
->line
, n
->pos
,
1700 "%s before %s(%s)", lastpunct
,
1702 cmp
= strcmp(lastsec
, sec
);
1704 mandoc_vmsg(MANDOCERR_XR_ORDER
,
1705 mdoc
->parse
, n
->line
, n
->pos
,
1706 "%s(%s) after %s(%s)", name
,
1707 sec
, lastname
, lastsec
);
1708 else if (cmp
== 0 &&
1709 strcasecmp(lastname
, name
) > 0)
1710 mandoc_vmsg(MANDOCERR_XR_ORDER
,
1711 mdoc
->parse
, n
->line
, n
->pos
,
1712 "%s after %s", name
, lastname
);
1717 /* Process the following node. */
1722 if (n
->tok
== MDOC_Xr
) {
1726 if (n
->type
!= ROFFT_TEXT
)
1728 for (name
= n
->string
; *name
!= '\0'; name
++)
1729 if (isalpha((const unsigned char)*name
))
1731 lastpunct
= n
->string
;
1732 if (n
->next
== NULL
)
1733 mandoc_vmsg(MANDOCERR_XR_PUNCT
, mdoc
->parse
,
1734 n
->line
, n
->pos
, "%s after %s(%s)",
1735 lastpunct
, lastname
, lastsec
);
1741 child_an(const struct roff_node
*n
)
1744 for (n
= n
->child
; n
!= NULL
; n
= n
->next
)
1745 if ((n
->tok
== MDOC_An
&& n
->child
!= NULL
) || child_an(n
))
1751 post_sh_authors(POST_ARGS
)
1754 if ( ! child_an(mdoc
->last
))
1755 mandoc_msg(MANDOCERR_AN_MISSING
, mdoc
->parse
,
1756 mdoc
->last
->line
, mdoc
->last
->pos
, NULL
);
1760 post_sh_head(POST_ARGS
)
1762 const char *goodsec
;
1766 * Process a new section. Sections are either "named" or
1767 * "custom". Custom sections are user-defined, while named ones
1768 * follow a conventional order and may only appear in certain
1772 sec
= mdoc
->last
->sec
;
1774 /* The NAME should be first. */
1776 if (SEC_NAME
!= sec
&& SEC_NONE
== mdoc
->lastnamed
)
1777 mandoc_vmsg(MANDOCERR_NAMESEC_FIRST
, mdoc
->parse
,
1778 mdoc
->last
->line
, mdoc
->last
->pos
,
1779 "Sh %s", secnames
[sec
]);
1781 /* The SYNOPSIS gets special attention in other areas. */
1783 if (sec
== SEC_SYNOPSIS
) {
1784 roff_setreg(mdoc
->roff
, "nS", 1, '=');
1785 mdoc
->flags
|= MDOC_SYNOPSIS
;
1787 roff_setreg(mdoc
->roff
, "nS", 0, '=');
1788 mdoc
->flags
&= ~MDOC_SYNOPSIS
;
1791 /* Mark our last section. */
1793 mdoc
->lastsec
= sec
;
1795 /* We don't care about custom sections after this. */
1797 if (sec
== SEC_CUSTOM
)
1801 * Check whether our non-custom section is being repeated or is
1805 if (sec
== mdoc
->lastnamed
)
1806 mandoc_vmsg(MANDOCERR_SEC_REP
, mdoc
->parse
,
1807 mdoc
->last
->line
, mdoc
->last
->pos
,
1808 "Sh %s", secnames
[sec
]);
1810 if (sec
< mdoc
->lastnamed
)
1811 mandoc_vmsg(MANDOCERR_SEC_ORDER
, mdoc
->parse
,
1812 mdoc
->last
->line
, mdoc
->last
->pos
,
1813 "Sh %s", secnames
[sec
]);
1815 /* Mark the last named section. */
1817 mdoc
->lastnamed
= sec
;
1819 /* Check particular section/manual conventions. */
1821 if (mdoc
->meta
.msec
== NULL
)
1827 if (*mdoc
->meta
.msec
== '4')
1829 goodsec
= "2, 3, 4, 9";
1831 case SEC_RETURN_VALUES
:
1833 if (*mdoc
->meta
.msec
== '2')
1835 if (*mdoc
->meta
.msec
== '3')
1837 if (NULL
== goodsec
)
1838 goodsec
= "2, 3, 9";
1841 if (*mdoc
->meta
.msec
== '9')
1843 if (NULL
== goodsec
)
1845 mandoc_vmsg(MANDOCERR_SEC_MSEC
, mdoc
->parse
,
1846 mdoc
->last
->line
, mdoc
->last
->pos
,
1847 "Sh %s for %s only", secnames
[sec
], goodsec
);
1855 post_ignpar(POST_ARGS
)
1857 struct roff_node
*np
;
1859 switch (mdoc
->last
->type
) {
1869 if ((np
= mdoc
->last
->child
) != NULL
)
1870 if (np
->tok
== MDOC_Pp
|| np
->tok
== MDOC_Lp
) {
1871 mandoc_vmsg(MANDOCERR_PAR_SKIP
,
1872 mdoc
->parse
, np
->line
, np
->pos
,
1873 "%s after %s", mdoc_macronames
[np
->tok
],
1874 mdoc_macronames
[mdoc
->last
->tok
]);
1875 roff_node_delete(mdoc
, np
);
1878 if ((np
= mdoc
->last
->last
) != NULL
)
1879 if (np
->tok
== MDOC_Pp
|| np
->tok
== MDOC_Lp
) {
1880 mandoc_vmsg(MANDOCERR_PAR_SKIP
, mdoc
->parse
,
1881 np
->line
, np
->pos
, "%s at the end of %s",
1882 mdoc_macronames
[np
->tok
],
1883 mdoc_macronames
[mdoc
->last
->tok
]);
1884 roff_node_delete(mdoc
, np
);
1889 post_prevpar(POST_ARGS
)
1891 struct roff_node
*n
;
1894 if (NULL
== n
->prev
)
1896 if (n
->type
!= ROFFT_ELEM
&& n
->type
!= ROFFT_BLOCK
)
1900 * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
1901 * block: `Lp', `Pp', or non-compact `Bd' or `Bl'.
1904 if (n
->prev
->tok
!= MDOC_Pp
&&
1905 n
->prev
->tok
!= MDOC_Lp
&&
1906 n
->prev
->tok
!= MDOC_br
)
1908 if (n
->tok
== MDOC_Bl
&& n
->norm
->Bl
.comp
)
1910 if (n
->tok
== MDOC_Bd
&& n
->norm
->Bd
.comp
)
1912 if (n
->tok
== MDOC_It
&& n
->parent
->norm
->Bl
.comp
)
1915 mandoc_vmsg(MANDOCERR_PAR_SKIP
, mdoc
->parse
,
1916 n
->prev
->line
, n
->prev
->pos
,
1917 "%s before %s", mdoc_macronames
[n
->prev
->tok
],
1918 mdoc_macronames
[n
->tok
]);
1919 roff_node_delete(mdoc
, n
->prev
);
1925 struct roff_node
*np
;
1928 if (np
->tok
!= MDOC_br
&& np
->tok
!= MDOC_sp
)
1931 if (np
->tok
== MDOC_sp
) {
1932 if (np
->child
!= NULL
&& np
->child
->next
!= NULL
)
1933 mandoc_vmsg(MANDOCERR_ARG_EXCESS
, mdoc
->parse
,
1934 np
->child
->next
->line
, np
->child
->next
->pos
,
1935 "sp ... %s", np
->child
->next
->string
);
1936 } else if (np
->child
!= NULL
)
1937 mandoc_vmsg(MANDOCERR_ARG_SKIP
,
1938 mdoc
->parse
, np
->line
, np
->pos
, "%s %s",
1939 mdoc_macronames
[np
->tok
], np
->child
->string
);
1941 if ((np
= mdoc
->last
->prev
) == NULL
) {
1942 np
= mdoc
->last
->parent
;
1943 if (np
->tok
!= MDOC_Sh
&& np
->tok
!= MDOC_Ss
)
1945 } else if (np
->tok
!= MDOC_Pp
&& np
->tok
!= MDOC_Lp
&&
1946 (mdoc
->last
->tok
!= MDOC_br
||
1947 (np
->tok
!= MDOC_sp
&& np
->tok
!= MDOC_br
)))
1950 mandoc_vmsg(MANDOCERR_PAR_SKIP
, mdoc
->parse
,
1951 mdoc
->last
->line
, mdoc
->last
->pos
,
1952 "%s after %s", mdoc_macronames
[mdoc
->last
->tok
],
1953 mdoc_macronames
[np
->tok
]);
1954 roff_node_delete(mdoc
, mdoc
->last
);
1960 struct roff_node
*n
;
1964 if (mdoc
->meta
.date
!= NULL
) {
1965 mandoc_msg(MANDOCERR_PROLOG_REP
, mdoc
->parse
,
1966 n
->line
, n
->pos
, "Dd");
1967 free(mdoc
->meta
.date
);
1968 } else if (mdoc
->flags
& MDOC_PBODY
)
1969 mandoc_msg(MANDOCERR_PROLOG_LATE
, mdoc
->parse
,
1970 n
->line
, n
->pos
, "Dd");
1971 else if (mdoc
->meta
.title
!= NULL
)
1972 mandoc_msg(MANDOCERR_PROLOG_ORDER
, mdoc
->parse
,
1973 n
->line
, n
->pos
, "Dd after Dt");
1974 else if (mdoc
->meta
.os
!= NULL
)
1975 mandoc_msg(MANDOCERR_PROLOG_ORDER
, mdoc
->parse
,
1976 n
->line
, n
->pos
, "Dd after Os");
1978 if (n
->child
== NULL
|| n
->child
->string
[0] == '\0') {
1979 mdoc
->meta
.date
= mdoc
->quick
? mandoc_strdup("") :
1980 mandoc_normdate(mdoc
->parse
, NULL
, n
->line
, n
->pos
);
1985 deroff(&datestr
, n
);
1987 mdoc
->meta
.date
= datestr
;
1989 mdoc
->meta
.date
= mandoc_normdate(mdoc
->parse
,
1990 datestr
, n
->line
, n
->pos
);
1994 roff_node_delete(mdoc
, n
);
2000 struct roff_node
*nn
, *n
;
2005 if (mdoc
->flags
& MDOC_PBODY
) {
2006 mandoc_msg(MANDOCERR_DT_LATE
, mdoc
->parse
,
2007 n
->line
, n
->pos
, "Dt");
2011 if (mdoc
->meta
.title
!= NULL
)
2012 mandoc_msg(MANDOCERR_PROLOG_REP
, mdoc
->parse
,
2013 n
->line
, n
->pos
, "Dt");
2014 else if (mdoc
->meta
.os
!= NULL
)
2015 mandoc_msg(MANDOCERR_PROLOG_ORDER
, mdoc
->parse
,
2016 n
->line
, n
->pos
, "Dt after Os");
2018 free(mdoc
->meta
.title
);
2019 free(mdoc
->meta
.msec
);
2020 free(mdoc
->meta
.vol
);
2021 free(mdoc
->meta
.arch
);
2023 mdoc
->meta
.title
= NULL
;
2024 mdoc
->meta
.msec
= NULL
;
2025 mdoc
->meta
.vol
= NULL
;
2026 mdoc
->meta
.arch
= NULL
;
2028 /* Mandatory first argument: title. */
2031 if (nn
== NULL
|| *nn
->string
== '\0') {
2032 mandoc_msg(MANDOCERR_DT_NOTITLE
,
2033 mdoc
->parse
, n
->line
, n
->pos
, "Dt");
2034 mdoc
->meta
.title
= mandoc_strdup("UNTITLED");
2036 mdoc
->meta
.title
= mandoc_strdup(nn
->string
);
2038 /* Check that all characters are uppercase. */
2040 for (p
= nn
->string
; *p
!= '\0'; p
++)
2041 if (islower((unsigned char)*p
)) {
2042 mandoc_vmsg(MANDOCERR_TITLE_CASE
,
2043 mdoc
->parse
, nn
->line
,
2044 nn
->pos
+ (p
- nn
->string
),
2045 "Dt %s", nn
->string
);
2050 /* Mandatory second argument: section. */
2056 mandoc_vmsg(MANDOCERR_MSEC_MISSING
,
2057 mdoc
->parse
, n
->line
, n
->pos
,
2058 "Dt %s", mdoc
->meta
.title
);
2059 mdoc
->meta
.vol
= mandoc_strdup("LOCAL");
2060 goto out
; /* msec and arch remain NULL. */
2063 mdoc
->meta
.msec
= mandoc_strdup(nn
->string
);
2065 /* Infer volume title from section number. */
2067 cp
= mandoc_a2msec(nn
->string
);
2069 mandoc_vmsg(MANDOCERR_MSEC_BAD
, mdoc
->parse
,
2070 nn
->line
, nn
->pos
, "Dt ... %s", nn
->string
);
2071 mdoc
->meta
.vol
= mandoc_strdup(nn
->string
);
2073 mdoc
->meta
.vol
= mandoc_strdup(cp
);
2075 /* Optional third argument: architecture. */
2077 if ((nn
= nn
->next
) == NULL
)
2080 for (p
= nn
->string
; *p
!= '\0'; p
++)
2081 *p
= tolower((unsigned char)*p
);
2082 mdoc
->meta
.arch
= mandoc_strdup(nn
->string
);
2084 /* Ignore fourth and later arguments. */
2086 if ((nn
= nn
->next
) != NULL
)
2087 mandoc_vmsg(MANDOCERR_ARG_EXCESS
, mdoc
->parse
,
2088 nn
->line
, nn
->pos
, "Dt ... %s", nn
->string
);
2091 roff_node_delete(mdoc
, n
);
2097 struct roff_node
*n
;
2100 * Make `Bx's second argument always start with an uppercase
2101 * letter. Groff checks if it's an "accepted" term, but we just
2102 * uppercase blindly.
2105 if ((n
= mdoc
->last
->child
) != NULL
&& (n
= n
->next
) != NULL
)
2106 *n
->string
= (char)toupper((unsigned char)*n
->string
);
2113 struct utsname utsname
;
2114 static char *defbuf
;
2116 struct roff_node
*n
;
2119 if (mdoc
->meta
.os
!= NULL
)
2120 mandoc_msg(MANDOCERR_PROLOG_REP
, mdoc
->parse
,
2121 n
->line
, n
->pos
, "Os");
2122 else if (mdoc
->flags
& MDOC_PBODY
)
2123 mandoc_msg(MANDOCERR_PROLOG_LATE
, mdoc
->parse
,
2124 n
->line
, n
->pos
, "Os");
2127 * Set the operating system by way of the `Os' macro.
2128 * The order of precedence is:
2129 * 1. the argument of the `Os' macro, unless empty
2130 * 2. the -Ios=foo command line argument, if provided
2131 * 3. -DOSNAME="\"foo\"", if provided during compilation
2132 * 4. "sysname release" from uname(3)
2135 free(mdoc
->meta
.os
);
2136 mdoc
->meta
.os
= NULL
;
2137 deroff(&mdoc
->meta
.os
, n
);
2142 mdoc
->meta
.os
= mandoc_strdup(mdoc
->defos
);
2147 mdoc
->meta
.os
= mandoc_strdup(OSNAME
);
2149 if (defbuf
== NULL
) {
2150 if (uname(&utsname
) == -1) {
2151 mandoc_msg(MANDOCERR_OS_UNAME
, mdoc
->parse
,
2152 n
->line
, n
->pos
, "Os");
2153 defbuf
= mandoc_strdup("UNKNOWN");
2155 mandoc_asprintf(&defbuf
, "%s %s",
2156 utsname
.sysname
, utsname
.release
);
2158 mdoc
->meta
.os
= mandoc_strdup(defbuf
);
2162 roff_node_delete(mdoc
, n
);
2166 * If no argument is provided,
2167 * fill in the name of the current manual page.
2172 struct roff_node
*n
;
2177 if (n
->child
!= NULL
)
2180 if (mdoc
->meta
.name
== NULL
) {
2181 mandoc_msg(MANDOCERR_EX_NONAME
, mdoc
->parse
,
2182 n
->line
, n
->pos
, "Ex");
2186 mdoc
->next
= ROFF_NEXT_CHILD
;
2187 roff_word_alloc(mdoc
, n
->line
, n
->pos
, mdoc
->meta
.name
);
2192 mdoc_a2sec(const char *p
)
2196 for (i
= 0; i
< (int)SEC__MAX
; i
++)
2197 if (secnames
[i
] && 0 == strcmp(p
, secnames
[i
]))
2198 return (enum roff_sec
)i
;
2204 macro2len(int macro
)