]>
git.cameronkatri.com Git - mandoc.git/blob - mdoc_validate.c
1 /* $Id: mdoc_validate.c,v 1.299 2015/10/21 23:51:11 schwarze Exp $ */
3 * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2010-2015 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
) {
901 for (np
= n
->parent
; np
!= NULL
; np
= np
->parent
) {
902 if (np
->type
== ROFFT_BLOCK
&& np
->tok
== MDOC_Bd
) {
903 mandoc_vmsg(MANDOCERR_BD_NEST
,
904 mdoc
->parse
, n
->line
, n
->pos
,
905 "%s in Bd", mdoc_macronames
[n
->tok
]);
916 post_defaults(POST_ARGS
)
918 struct roff_node
*nn
;
921 * The `Ar' defaults to "file ..." if no value is provided as an
922 * argument; the `Mt' and `Pa' macros use "~"; the `Li' just
923 * gets an empty string.
926 if (mdoc
->last
->child
!= NULL
)
933 mdoc
->next
= ROFF_NEXT_CHILD
;
934 roff_word_alloc(mdoc
, nn
->line
, nn
->pos
, "file");
935 roff_word_alloc(mdoc
, nn
->line
, nn
->pos
, "...");
939 mdoc
->next
= ROFF_NEXT_CHILD
;
940 roff_word_alloc(mdoc
, nn
->line
, nn
->pos
, "~");
956 if (n
->child
== NULL
) {
957 mdoc
->next
= ROFF_NEXT_CHILD
;
958 roff_word_alloc(mdoc
, n
->line
, n
->pos
, "AT&T UNIX");
964 * If we have a child, look it up in the standard keys. If a
965 * key exist, use that instead of the child; if it doesn't,
966 * prefix "AT&T UNIX " to the existing data.
970 assert(n
->type
== ROFFT_TEXT
);
971 if ((std_att
= mdoc_a2att(n
->string
)) == NULL
) {
972 mandoc_vmsg(MANDOCERR_AT_BAD
, mdoc
->parse
,
973 n
->line
, n
->pos
, "At %s", n
->string
);
974 mandoc_asprintf(&att
, "AT&T UNIX %s", n
->string
);
976 att
= mandoc_strdup(std_att
);
985 struct roff_node
*np
, *nch
;
991 if (np
->norm
->An
.auth
== AUTH__NONE
) {
993 mandoc_msg(MANDOCERR_MACRO_EMPTY
, mdoc
->parse
,
994 np
->line
, np
->pos
, "An");
995 } else if (nch
!= NULL
)
996 mandoc_vmsg(MANDOCERR_ARG_EXCESS
, mdoc
->parse
,
997 nch
->line
, nch
->pos
, "An ... %s", nch
->string
);
1004 post_obsolete(mdoc
);
1005 if (mdoc
->last
->type
== ROFFT_BLOCK
)
1006 mdoc
->last
->norm
->Es
= mdoc
->last_es
;
1013 post_obsolete(mdoc
);
1014 mdoc
->last_es
= mdoc
->last
;
1020 struct roff_node
*nbl
, *nit
, *nch
;
1027 if (nit
->type
!= ROFFT_BLOCK
)
1030 nbl
= nit
->parent
->parent
;
1031 lt
= nbl
->norm
->Bl
.type
;
1039 if (nit
->head
->child
== NULL
)
1040 mandoc_vmsg(MANDOCERR_IT_NOHEAD
,
1041 mdoc
->parse
, nit
->line
, nit
->pos
,
1043 mdoc_argnames
[nbl
->args
->argv
[0].arg
]);
1049 if (nit
->body
== NULL
|| nit
->body
->child
== NULL
)
1050 mandoc_vmsg(MANDOCERR_IT_NOBODY
,
1051 mdoc
->parse
, nit
->line
, nit
->pos
,
1053 mdoc_argnames
[nbl
->args
->argv
[0].arg
]);
1056 if (nit
->head
->child
!= NULL
)
1057 mandoc_vmsg(MANDOCERR_ARG_SKIP
,
1058 mdoc
->parse
, nit
->line
, nit
->pos
,
1059 "It %s", nit
->head
->child
->string
);
1062 cols
= (int)nbl
->norm
->Bl
.ncols
;
1064 assert(nit
->head
->child
== NULL
);
1067 for (nch
= nit
->child
; nch
!= NULL
; nch
= nch
->next
)
1068 if (nch
->type
== ROFFT_BODY
)
1071 if (i
< cols
|| i
> cols
+ 1)
1072 mandoc_vmsg(MANDOCERR_BL_COL
,
1073 mdoc
->parse
, nit
->line
, nit
->pos
,
1074 "%d columns, %d cells", cols
, i
);
1082 post_bl_block(POST_ARGS
)
1084 struct roff_node
*n
, *ni
, *nc
;
1089 * These are fairly complicated, so we've broken them into two
1090 * functions. post_bl_block_tag() is called when a -tag is
1091 * specified, but no -width (it must be guessed). The second
1092 * when a -width is specified (macro indicators must be
1093 * rewritten into real lengths).
1098 if (n
->norm
->Bl
.type
== LIST_tag
&&
1099 n
->norm
->Bl
.width
== NULL
) {
1100 post_bl_block_tag(mdoc
);
1101 assert(n
->norm
->Bl
.width
!= NULL
);
1104 for (ni
= n
->body
->child
; ni
!= NULL
; ni
= ni
->next
) {
1105 if (ni
->body
== NULL
)
1107 nc
= ni
->body
->last
;
1108 while (nc
!= NULL
) {
1118 if (ni
->next
== NULL
) {
1119 mandoc_msg(MANDOCERR_PAR_MOVE
,
1120 mdoc
->parse
, nc
->line
, nc
->pos
,
1121 mdoc_macronames
[nc
->tok
]);
1122 mdoc_node_relink(mdoc
, nc
);
1123 } else if (n
->norm
->Bl
.comp
== 0 &&
1124 n
->norm
->Bl
.type
!= LIST_column
) {
1125 mandoc_vmsg(MANDOCERR_PAR_SKIP
,
1126 mdoc
->parse
, nc
->line
, nc
->pos
,
1128 mdoc_macronames
[nc
->tok
]);
1129 roff_node_delete(mdoc
, nc
);
1132 nc
= ni
->body
->last
;
1138 * If the argument of -offset or -width is a macro,
1139 * replace it with the associated default width.
1142 rewrite_macro2len(char **arg
)
1149 else if ( ! strcmp(*arg
, "Ds"))
1151 else if ((tok
= mdoc_hash_find(*arg
)) == TOKEN_NONE
)
1154 width
= macro2len(tok
);
1157 mandoc_asprintf(arg
, "%zun", width
);
1161 post_bl_block_tag(POST_ARGS
)
1163 struct roff_node
*n
, *nn
;
1169 * Calculate the -width for a `Bl -tag' list if it hasn't been
1170 * provided. Uses the first head macro. NOTE AGAIN: this is
1171 * ONLY if the -width argument has NOT been provided. See
1172 * rewrite_macro2len() for converting the -width string.
1178 for (nn
= n
->body
->child
; nn
!= NULL
; nn
= nn
->next
) {
1179 if (nn
->tok
!= MDOC_It
)
1182 assert(nn
->type
== ROFFT_BLOCK
);
1183 nn
= nn
->head
->child
;
1188 if (nn
->type
== ROFFT_TEXT
) {
1189 sz
= strlen(nn
->string
) + 1;
1193 if (0 != (ssz
= macro2len(nn
->tok
)))
1199 /* Defaults to ten ens. */
1201 (void)snprintf(buf
, sizeof(buf
), "%un", (unsigned int)sz
);
1204 * We have to dynamically add this to the macro's argument list.
1205 * We're guaranteed that a MDOC_Width doesn't already exist.
1208 assert(n
->args
!= NULL
);
1209 i
= (int)(n
->args
->argc
)++;
1211 n
->args
->argv
= mandoc_reallocarray(n
->args
->argv
,
1212 n
->args
->argc
, sizeof(struct mdoc_argv
));
1214 n
->args
->argv
[i
].arg
= MDOC_Width
;
1215 n
->args
->argv
[i
].line
= n
->line
;
1216 n
->args
->argv
[i
].pos
= n
->pos
;
1217 n
->args
->argv
[i
].sz
= 1;
1218 n
->args
->argv
[i
].value
= mandoc_malloc(sizeof(char *));
1219 n
->args
->argv
[i
].value
[0] = mandoc_strdup(buf
);
1221 /* Set our width! */
1222 n
->norm
->Bl
.width
= n
->args
->argv
[i
].value
[0];
1226 post_bl_head(POST_ARGS
)
1228 struct roff_node
*nbl
, *nh
, *nch
, *nnext
;
1229 struct mdoc_argv
*argv
;
1235 if (nh
->norm
->Bl
.type
!= LIST_column
) {
1236 if ((nch
= nh
->child
) == NULL
)
1238 mandoc_vmsg(MANDOCERR_ARG_EXCESS
, mdoc
->parse
,
1239 nch
->line
, nch
->pos
, "Bl ... %s", nch
->string
);
1240 while (nch
!= NULL
) {
1241 roff_node_delete(mdoc
, nch
);
1248 * Append old-style lists, where the column width specifiers
1249 * trail as macro parameters, to the new-style ("normal-form")
1250 * lists where they're argument values following -column.
1253 if (nh
->child
== NULL
)
1257 for (j
= 0; j
< (int)nbl
->args
->argc
; j
++)
1258 if (nbl
->args
->argv
[j
].arg
== MDOC_Column
)
1261 assert(j
< (int)nbl
->args
->argc
);
1264 * Accommodate for new-style groff column syntax. Shuffle the
1265 * child nodes, all of which must be TEXT, as arguments for the
1266 * column field. Then, delete the head children.
1269 argv
= nbl
->args
->argv
+ j
;
1271 argv
->sz
+= nh
->nchild
;
1272 argv
->value
= mandoc_reallocarray(argv
->value
,
1273 argv
->sz
, sizeof(char *));
1275 nh
->norm
->Bl
.ncols
= argv
->sz
;
1276 nh
->norm
->Bl
.cols
= (void *)argv
->value
;
1278 for (nch
= nh
->child
; nch
!= NULL
; nch
= nnext
) {
1279 argv
->value
[i
++] = nch
->string
;
1282 roff_node_delete(NULL
, nch
);
1291 struct roff_node
*nparent
, *nprev
; /* of the Bl block */
1292 struct roff_node
*nblock
, *nbody
; /* of the Bl */
1293 struct roff_node
*nchild
, *nnext
; /* of the Bl body */
1296 switch (nbody
->type
) {
1298 post_bl_block(mdoc
);
1308 if (nbody
->end
!= ENDBODY_NOT
)
1311 nchild
= nbody
->child
;
1312 if (nchild
== NULL
) {
1313 mandoc_msg(MANDOCERR_BLK_EMPTY
, mdoc
->parse
,
1314 nbody
->line
, nbody
->pos
, "Bl");
1317 while (nchild
!= NULL
) {
1318 if (nchild
->tok
== MDOC_It
||
1319 (nchild
->tok
== MDOC_Sm
&&
1320 nchild
->next
!= NULL
&&
1321 nchild
->next
->tok
== MDOC_It
)) {
1322 nchild
= nchild
->next
;
1326 mandoc_msg(MANDOCERR_BL_MOVE
, mdoc
->parse
,
1327 nchild
->line
, nchild
->pos
,
1328 mdoc_macronames
[nchild
->tok
]);
1331 * Move the node out of the Bl block.
1332 * First, collect all required node pointers.
1335 nblock
= nbody
->parent
;
1336 nprev
= nblock
->prev
;
1337 nparent
= nblock
->parent
;
1338 nnext
= nchild
->next
;
1341 * Unlink this child.
1344 assert(nchild
->prev
== NULL
);
1345 if (--nbody
->nchild
== 0) {
1346 nbody
->child
= NULL
;
1348 assert(nnext
== NULL
);
1350 nbody
->child
= nnext
;
1355 * Relink this child.
1358 nchild
->parent
= nparent
;
1359 nchild
->prev
= nprev
;
1360 nchild
->next
= nblock
;
1362 nblock
->prev
= nchild
;
1365 nparent
->child
= nchild
;
1367 nprev
->next
= nchild
;
1376 struct roff_node
*n
;
1380 if (n
->type
== ROFFT_BLOCK
&& n
->body
->child
== NULL
) {
1381 mandoc_msg(MANDOCERR_BLK_EMPTY
,
1382 mdoc
->parse
, n
->line
, n
->pos
, "Bk");
1383 roff_node_delete(mdoc
, n
);
1390 struct roff_node
*nch
;
1392 nch
= mdoc
->last
->child
;
1395 mdoc
->flags
^= MDOC_SMOFF
;
1399 assert(nch
->type
== ROFFT_TEXT
);
1401 if ( ! strcmp(nch
->string
, "on")) {
1402 mdoc
->flags
&= ~MDOC_SMOFF
;
1405 if ( ! strcmp(nch
->string
, "off")) {
1406 mdoc
->flags
|= MDOC_SMOFF
;
1410 mandoc_vmsg(MANDOCERR_SM_BAD
,
1411 mdoc
->parse
, nch
->line
, nch
->pos
,
1412 "%s %s", mdoc_macronames
[mdoc
->last
->tok
], nch
->string
);
1413 mdoc_node_relink(mdoc
, nch
);
1418 post_root(POST_ARGS
)
1420 struct roff_node
*n
;
1422 /* Add missing prologue data. */
1424 if (mdoc
->meta
.date
== NULL
)
1425 mdoc
->meta
.date
= mdoc
->quick
?
1427 mandoc_normdate(mdoc
->parse
, NULL
, 0, 0);
1429 if (mdoc
->meta
.title
== NULL
) {
1430 mandoc_msg(MANDOCERR_DT_NOTITLE
,
1431 mdoc
->parse
, 0, 0, "EOF");
1432 mdoc
->meta
.title
= mandoc_strdup("UNTITLED");
1435 if (mdoc
->meta
.vol
== NULL
)
1436 mdoc
->meta
.vol
= mandoc_strdup("LOCAL");
1438 if (mdoc
->meta
.os
== NULL
) {
1439 mandoc_msg(MANDOCERR_OS_MISSING
,
1440 mdoc
->parse
, 0, 0, NULL
);
1441 mdoc
->meta
.os
= mandoc_strdup("");
1444 /* Check that we begin with a proper `Sh'. */
1446 n
= mdoc
->first
->child
;
1447 while (n
!= NULL
&& n
->tok
!= TOKEN_NONE
&&
1448 mdoc_macros
[n
->tok
].flags
& MDOC_PROLOGUE
)
1452 mandoc_msg(MANDOCERR_DOC_EMPTY
, mdoc
->parse
, 0, 0, NULL
);
1453 else if (n
->tok
!= MDOC_Sh
)
1454 mandoc_msg(MANDOCERR_SEC_BEFORE
, mdoc
->parse
,
1455 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
1461 struct roff_node
*n
, *nch
;
1467 assert(nch
->type
== ROFFT_TEXT
);
1469 if ((p
= mdoc_a2st(nch
->string
)) == NULL
) {
1470 mandoc_vmsg(MANDOCERR_ST_BAD
, mdoc
->parse
,
1471 nch
->line
, nch
->pos
, "St %s", nch
->string
);
1472 roff_node_delete(mdoc
, n
);
1475 nch
->string
= mandoc_strdup(p
);
1482 struct roff_node
*np
, *nch
, *next
, *prev
;
1487 if (np
->type
!= ROFFT_BODY
)
1490 if (np
->child
== NULL
) {
1491 mandoc_msg(MANDOCERR_RS_EMPTY
, mdoc
->parse
,
1492 np
->line
, np
->pos
, "Rs");
1497 * The full `Rs' block needs special handling to order the
1498 * sub-elements according to `rsord'. Pick through each element
1499 * and correctly order it. This is an insertion sort.
1503 for (nch
= np
->child
->next
; nch
!= NULL
; nch
= next
) {
1504 /* Determine order number of this child. */
1505 for (i
= 0; i
< RSORD_MAX
; i
++)
1506 if (rsord
[i
] == nch
->tok
)
1509 if (i
== RSORD_MAX
) {
1510 mandoc_msg(MANDOCERR_RS_BAD
,
1511 mdoc
->parse
, nch
->line
, nch
->pos
,
1512 mdoc_macronames
[nch
->tok
]);
1514 } else if (nch
->tok
== MDOC__J
|| nch
->tok
== MDOC__B
)
1515 np
->norm
->Rs
.quote_T
++;
1518 * Remove this child from the chain. This somewhat
1519 * repeats roff_node_unlink(), but since we're
1520 * just re-ordering, there's no need for the
1521 * full unlink process.
1524 if ((next
= nch
->next
) != NULL
)
1525 next
->prev
= nch
->prev
;
1527 if ((prev
= nch
->prev
) != NULL
)
1528 prev
->next
= nch
->next
;
1530 nch
->prev
= nch
->next
= NULL
;
1533 * Scan back until we reach a node that's
1534 * to be ordered before this child.
1537 for ( ; prev
; prev
= prev
->prev
) {
1538 /* Determine order of `prev'. */
1539 for (j
= 0; j
< RSORD_MAX
; j
++)
1540 if (rsord
[j
] == prev
->tok
)
1550 * Set this child back into its correct place
1551 * in front of the `prev' node.
1557 np
->child
->prev
= nch
;
1558 nch
->next
= np
->child
;
1562 prev
->next
->prev
= nch
;
1563 nch
->next
= prev
->next
;
1570 * For some arguments of some macros,
1571 * convert all breakable hyphens into ASCII_HYPH.
1574 post_hyph(POST_ARGS
)
1576 struct roff_node
*nch
;
1579 for (nch
= mdoc
->last
->child
; nch
!= NULL
; nch
= nch
->next
) {
1580 if (nch
->type
!= ROFFT_TEXT
)
1585 while (*(++cp
) != '\0')
1587 isalpha((unsigned char)cp
[-1]) &&
1588 isalpha((unsigned char)cp
[1]))
1597 if (mdoc
->last
->flags
& MDOC_LINE
)
1598 mandoc_msg(MANDOCERR_NS_SKIP
, mdoc
->parse
,
1599 mdoc
->last
->line
, mdoc
->last
->pos
, NULL
);
1608 switch (mdoc
->last
->type
) {
1613 switch (mdoc
->lastsec
) {
1618 post_sh_see_also(mdoc
);
1621 post_sh_authors(mdoc
);
1633 post_sh_name(POST_ARGS
)
1635 struct roff_node
*n
;
1640 for (n
= mdoc
->last
->child
; n
!= NULL
; n
= n
->next
) {
1647 if (n
->next
!= NULL
)
1648 mandoc_msg(MANDOCERR_NAMESEC_ND
,
1649 mdoc
->parse
, n
->line
, n
->pos
, NULL
);
1656 mandoc_msg(MANDOCERR_NAMESEC_BAD
, mdoc
->parse
,
1657 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
1663 mandoc_msg(MANDOCERR_NAMESEC_NONM
, mdoc
->parse
,
1664 mdoc
->last
->line
, mdoc
->last
->pos
, NULL
);
1666 mandoc_msg(MANDOCERR_NAMESEC_NOND
, mdoc
->parse
,
1667 mdoc
->last
->line
, mdoc
->last
->pos
, NULL
);
1671 post_sh_see_also(POST_ARGS
)
1673 const struct roff_node
*n
;
1674 const char *name
, *sec
;
1675 const char *lastname
, *lastsec
, *lastpunct
;
1678 n
= mdoc
->last
->child
;
1679 lastname
= lastsec
= lastpunct
= NULL
;
1681 if (n
->tok
!= MDOC_Xr
|| n
->nchild
< 2)
1684 /* Process one .Xr node. */
1686 name
= n
->child
->string
;
1687 sec
= n
->child
->next
->string
;
1688 if (lastsec
!= NULL
) {
1689 if (lastpunct
[0] != ',' || lastpunct
[1] != '\0')
1690 mandoc_vmsg(MANDOCERR_XR_PUNCT
,
1691 mdoc
->parse
, n
->line
, n
->pos
,
1692 "%s before %s(%s)", lastpunct
,
1694 cmp
= strcmp(lastsec
, sec
);
1696 mandoc_vmsg(MANDOCERR_XR_ORDER
,
1697 mdoc
->parse
, n
->line
, n
->pos
,
1698 "%s(%s) after %s(%s)", name
,
1699 sec
, lastname
, lastsec
);
1700 else if (cmp
== 0 &&
1701 strcasecmp(lastname
, name
) > 0)
1702 mandoc_vmsg(MANDOCERR_XR_ORDER
,
1703 mdoc
->parse
, n
->line
, n
->pos
,
1704 "%s after %s", name
, lastname
);
1709 /* Process the following node. */
1714 if (n
->tok
== MDOC_Xr
) {
1718 if (n
->type
!= ROFFT_TEXT
)
1720 for (name
= n
->string
; *name
!= '\0'; name
++)
1721 if (isalpha((const unsigned char)*name
))
1723 lastpunct
= n
->string
;
1724 if (n
->next
== NULL
)
1725 mandoc_vmsg(MANDOCERR_XR_PUNCT
, mdoc
->parse
,
1726 n
->line
, n
->pos
, "%s after %s(%s)",
1727 lastpunct
, lastname
, lastsec
);
1733 child_an(const struct roff_node
*n
)
1736 for (n
= n
->child
; n
!= NULL
; n
= n
->next
)
1737 if ((n
->tok
== MDOC_An
&& n
->nchild
) || child_an(n
))
1743 post_sh_authors(POST_ARGS
)
1746 if ( ! child_an(mdoc
->last
))
1747 mandoc_msg(MANDOCERR_AN_MISSING
, mdoc
->parse
,
1748 mdoc
->last
->line
, mdoc
->last
->pos
, NULL
);
1752 post_sh_head(POST_ARGS
)
1754 const char *goodsec
;
1758 * Process a new section. Sections are either "named" or
1759 * "custom". Custom sections are user-defined, while named ones
1760 * follow a conventional order and may only appear in certain
1764 sec
= mdoc
->last
->sec
;
1766 /* The NAME should be first. */
1768 if (SEC_NAME
!= sec
&& SEC_NONE
== mdoc
->lastnamed
)
1769 mandoc_vmsg(MANDOCERR_NAMESEC_FIRST
, mdoc
->parse
,
1770 mdoc
->last
->line
, mdoc
->last
->pos
,
1771 "Sh %s", secnames
[sec
]);
1773 /* The SYNOPSIS gets special attention in other areas. */
1775 if (sec
== SEC_SYNOPSIS
) {
1776 roff_setreg(mdoc
->roff
, "nS", 1, '=');
1777 mdoc
->flags
|= MDOC_SYNOPSIS
;
1779 roff_setreg(mdoc
->roff
, "nS", 0, '=');
1780 mdoc
->flags
&= ~MDOC_SYNOPSIS
;
1783 /* Mark our last section. */
1785 mdoc
->lastsec
= sec
;
1787 /* We don't care about custom sections after this. */
1789 if (sec
== SEC_CUSTOM
)
1793 * Check whether our non-custom section is being repeated or is
1797 if (sec
== mdoc
->lastnamed
)
1798 mandoc_vmsg(MANDOCERR_SEC_REP
, mdoc
->parse
,
1799 mdoc
->last
->line
, mdoc
->last
->pos
,
1800 "Sh %s", secnames
[sec
]);
1802 if (sec
< mdoc
->lastnamed
)
1803 mandoc_vmsg(MANDOCERR_SEC_ORDER
, mdoc
->parse
,
1804 mdoc
->last
->line
, mdoc
->last
->pos
,
1805 "Sh %s", secnames
[sec
]);
1807 /* Mark the last named section. */
1809 mdoc
->lastnamed
= sec
;
1811 /* Check particular section/manual conventions. */
1813 if (mdoc
->meta
.msec
== NULL
)
1819 if (*mdoc
->meta
.msec
== '4')
1821 goodsec
= "2, 3, 4, 9";
1823 case SEC_RETURN_VALUES
:
1825 if (*mdoc
->meta
.msec
== '2')
1827 if (*mdoc
->meta
.msec
== '3')
1829 if (NULL
== goodsec
)
1830 goodsec
= "2, 3, 9";
1833 if (*mdoc
->meta
.msec
== '9')
1835 if (NULL
== goodsec
)
1837 mandoc_vmsg(MANDOCERR_SEC_MSEC
, mdoc
->parse
,
1838 mdoc
->last
->line
, mdoc
->last
->pos
,
1839 "Sh %s for %s only", secnames
[sec
], goodsec
);
1847 post_ignpar(POST_ARGS
)
1849 struct roff_node
*np
;
1851 switch (mdoc
->last
->type
) {
1861 if ((np
= mdoc
->last
->child
) != NULL
)
1862 if (np
->tok
== MDOC_Pp
|| np
->tok
== MDOC_Lp
) {
1863 mandoc_vmsg(MANDOCERR_PAR_SKIP
,
1864 mdoc
->parse
, np
->line
, np
->pos
,
1865 "%s after %s", mdoc_macronames
[np
->tok
],
1866 mdoc_macronames
[mdoc
->last
->tok
]);
1867 roff_node_delete(mdoc
, np
);
1870 if ((np
= mdoc
->last
->last
) != NULL
)
1871 if (np
->tok
== MDOC_Pp
|| np
->tok
== MDOC_Lp
) {
1872 mandoc_vmsg(MANDOCERR_PAR_SKIP
, mdoc
->parse
,
1873 np
->line
, np
->pos
, "%s at the end of %s",
1874 mdoc_macronames
[np
->tok
],
1875 mdoc_macronames
[mdoc
->last
->tok
]);
1876 roff_node_delete(mdoc
, np
);
1881 post_prevpar(POST_ARGS
)
1883 struct roff_node
*n
;
1886 if (NULL
== n
->prev
)
1888 if (n
->type
!= ROFFT_ELEM
&& n
->type
!= ROFFT_BLOCK
)
1892 * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
1893 * block: `Lp', `Pp', or non-compact `Bd' or `Bl'.
1896 if (n
->prev
->tok
!= MDOC_Pp
&&
1897 n
->prev
->tok
!= MDOC_Lp
&&
1898 n
->prev
->tok
!= MDOC_br
)
1900 if (n
->tok
== MDOC_Bl
&& n
->norm
->Bl
.comp
)
1902 if (n
->tok
== MDOC_Bd
&& n
->norm
->Bd
.comp
)
1904 if (n
->tok
== MDOC_It
&& n
->parent
->norm
->Bl
.comp
)
1907 mandoc_vmsg(MANDOCERR_PAR_SKIP
, mdoc
->parse
,
1908 n
->prev
->line
, n
->prev
->pos
,
1909 "%s before %s", mdoc_macronames
[n
->prev
->tok
],
1910 mdoc_macronames
[n
->tok
]);
1911 roff_node_delete(mdoc
, n
->prev
);
1917 struct roff_node
*np
;
1920 if (np
->tok
!= MDOC_br
&& np
->tok
!= MDOC_sp
)
1923 if (np
->tok
== MDOC_sp
) {
1925 mandoc_vmsg(MANDOCERR_ARG_EXCESS
, mdoc
->parse
,
1926 np
->child
->next
->line
, np
->child
->next
->pos
,
1927 "sp ... %s", np
->child
->next
->string
);
1928 } else if (np
->child
!= NULL
)
1929 mandoc_vmsg(MANDOCERR_ARG_SKIP
,
1930 mdoc
->parse
, np
->line
, np
->pos
, "%s %s",
1931 mdoc_macronames
[np
->tok
], np
->child
->string
);
1933 if ((np
= mdoc
->last
->prev
) == NULL
) {
1934 np
= mdoc
->last
->parent
;
1935 if (np
->tok
!= MDOC_Sh
&& np
->tok
!= MDOC_Ss
)
1937 } else if (np
->tok
!= MDOC_Pp
&& np
->tok
!= MDOC_Lp
&&
1938 (mdoc
->last
->tok
!= MDOC_br
||
1939 (np
->tok
!= MDOC_sp
&& np
->tok
!= MDOC_br
)))
1942 mandoc_vmsg(MANDOCERR_PAR_SKIP
, mdoc
->parse
,
1943 mdoc
->last
->line
, mdoc
->last
->pos
,
1944 "%s after %s", mdoc_macronames
[mdoc
->last
->tok
],
1945 mdoc_macronames
[np
->tok
]);
1946 roff_node_delete(mdoc
, mdoc
->last
);
1952 struct roff_node
*n
;
1956 if (mdoc
->meta
.date
!= NULL
) {
1957 mandoc_msg(MANDOCERR_PROLOG_REP
, mdoc
->parse
,
1958 n
->line
, n
->pos
, "Dd");
1959 free(mdoc
->meta
.date
);
1960 } else if (mdoc
->flags
& MDOC_PBODY
)
1961 mandoc_msg(MANDOCERR_PROLOG_LATE
, mdoc
->parse
,
1962 n
->line
, n
->pos
, "Dd");
1963 else if (mdoc
->meta
.title
!= NULL
)
1964 mandoc_msg(MANDOCERR_PROLOG_ORDER
, mdoc
->parse
,
1965 n
->line
, n
->pos
, "Dd after Dt");
1966 else if (mdoc
->meta
.os
!= NULL
)
1967 mandoc_msg(MANDOCERR_PROLOG_ORDER
, mdoc
->parse
,
1968 n
->line
, n
->pos
, "Dd after Os");
1970 if (n
->child
== NULL
|| n
->child
->string
[0] == '\0') {
1971 mdoc
->meta
.date
= mdoc
->quick
? mandoc_strdup("") :
1972 mandoc_normdate(mdoc
->parse
, NULL
, n
->line
, n
->pos
);
1977 deroff(&datestr
, n
);
1979 mdoc
->meta
.date
= datestr
;
1981 mdoc
->meta
.date
= mandoc_normdate(mdoc
->parse
,
1982 datestr
, n
->line
, n
->pos
);
1986 roff_node_delete(mdoc
, n
);
1992 struct roff_node
*nn
, *n
;
1997 if (mdoc
->flags
& MDOC_PBODY
) {
1998 mandoc_msg(MANDOCERR_DT_LATE
, mdoc
->parse
,
1999 n
->line
, n
->pos
, "Dt");
2003 if (mdoc
->meta
.title
!= NULL
)
2004 mandoc_msg(MANDOCERR_PROLOG_REP
, mdoc
->parse
,
2005 n
->line
, n
->pos
, "Dt");
2006 else if (mdoc
->meta
.os
!= NULL
)
2007 mandoc_msg(MANDOCERR_PROLOG_ORDER
, mdoc
->parse
,
2008 n
->line
, n
->pos
, "Dt after Os");
2010 free(mdoc
->meta
.title
);
2011 free(mdoc
->meta
.msec
);
2012 free(mdoc
->meta
.vol
);
2013 free(mdoc
->meta
.arch
);
2015 mdoc
->meta
.title
= NULL
;
2016 mdoc
->meta
.msec
= NULL
;
2017 mdoc
->meta
.vol
= NULL
;
2018 mdoc
->meta
.arch
= NULL
;
2020 /* Mandatory first argument: title. */
2023 if (nn
== NULL
|| *nn
->string
== '\0') {
2024 mandoc_msg(MANDOCERR_DT_NOTITLE
,
2025 mdoc
->parse
, n
->line
, n
->pos
, "Dt");
2026 mdoc
->meta
.title
= mandoc_strdup("UNTITLED");
2028 mdoc
->meta
.title
= mandoc_strdup(nn
->string
);
2030 /* Check that all characters are uppercase. */
2032 for (p
= nn
->string
; *p
!= '\0'; p
++)
2033 if (islower((unsigned char)*p
)) {
2034 mandoc_vmsg(MANDOCERR_TITLE_CASE
,
2035 mdoc
->parse
, nn
->line
,
2036 nn
->pos
+ (p
- nn
->string
),
2037 "Dt %s", nn
->string
);
2042 /* Mandatory second argument: section. */
2048 mandoc_vmsg(MANDOCERR_MSEC_MISSING
,
2049 mdoc
->parse
, n
->line
, n
->pos
,
2050 "Dt %s", mdoc
->meta
.title
);
2051 mdoc
->meta
.vol
= mandoc_strdup("LOCAL");
2052 goto out
; /* msec and arch remain NULL. */
2055 mdoc
->meta
.msec
= mandoc_strdup(nn
->string
);
2057 /* Infer volume title from section number. */
2059 cp
= mandoc_a2msec(nn
->string
);
2061 mandoc_vmsg(MANDOCERR_MSEC_BAD
, mdoc
->parse
,
2062 nn
->line
, nn
->pos
, "Dt ... %s", nn
->string
);
2063 mdoc
->meta
.vol
= mandoc_strdup(nn
->string
);
2065 mdoc
->meta
.vol
= mandoc_strdup(cp
);
2067 /* Optional third argument: architecture. */
2069 if ((nn
= nn
->next
) == NULL
)
2072 for (p
= nn
->string
; *p
!= '\0'; p
++)
2073 *p
= tolower((unsigned char)*p
);
2074 mdoc
->meta
.arch
= mandoc_strdup(nn
->string
);
2076 /* Ignore fourth and later arguments. */
2078 if ((nn
= nn
->next
) != NULL
)
2079 mandoc_vmsg(MANDOCERR_ARG_EXCESS
, mdoc
->parse
,
2080 nn
->line
, nn
->pos
, "Dt ... %s", nn
->string
);
2083 roff_node_delete(mdoc
, n
);
2089 struct roff_node
*n
;
2092 * Make `Bx's second argument always start with an uppercase
2093 * letter. Groff checks if it's an "accepted" term, but we just
2094 * uppercase blindly.
2097 if ((n
= mdoc
->last
->child
) != NULL
&& (n
= n
->next
) != NULL
)
2098 *n
->string
= (char)toupper((unsigned char)*n
->string
);
2105 struct utsname utsname
;
2106 static char *defbuf
;
2108 struct roff_node
*n
;
2111 if (mdoc
->meta
.os
!= NULL
)
2112 mandoc_msg(MANDOCERR_PROLOG_REP
, mdoc
->parse
,
2113 n
->line
, n
->pos
, "Os");
2114 else if (mdoc
->flags
& MDOC_PBODY
)
2115 mandoc_msg(MANDOCERR_PROLOG_LATE
, mdoc
->parse
,
2116 n
->line
, n
->pos
, "Os");
2119 * Set the operating system by way of the `Os' macro.
2120 * The order of precedence is:
2121 * 1. the argument of the `Os' macro, unless empty
2122 * 2. the -Ios=foo command line argument, if provided
2123 * 3. -DOSNAME="\"foo\"", if provided during compilation
2124 * 4. "sysname release" from uname(3)
2127 free(mdoc
->meta
.os
);
2128 mdoc
->meta
.os
= NULL
;
2129 deroff(&mdoc
->meta
.os
, n
);
2134 mdoc
->meta
.os
= mandoc_strdup(mdoc
->defos
);
2139 mdoc
->meta
.os
= mandoc_strdup(OSNAME
);
2141 if (defbuf
== NULL
) {
2142 if (uname(&utsname
) == -1) {
2143 mandoc_msg(MANDOCERR_OS_UNAME
, mdoc
->parse
,
2144 n
->line
, n
->pos
, "Os");
2145 defbuf
= mandoc_strdup("UNKNOWN");
2147 mandoc_asprintf(&defbuf
, "%s %s",
2148 utsname
.sysname
, utsname
.release
);
2150 mdoc
->meta
.os
= mandoc_strdup(defbuf
);
2154 roff_node_delete(mdoc
, n
);
2158 * If no argument is provided,
2159 * fill in the name of the current manual page.
2164 struct roff_node
*n
;
2169 if (n
->child
!= NULL
)
2172 if (mdoc
->meta
.name
== NULL
) {
2173 mandoc_msg(MANDOCERR_EX_NONAME
, mdoc
->parse
,
2174 n
->line
, n
->pos
, "Ex");
2178 mdoc
->next
= ROFF_NEXT_CHILD
;
2179 roff_word_alloc(mdoc
, n
->line
, n
->pos
, mdoc
->meta
.name
);
2184 mdoc_a2sec(const char *p
)
2188 for (i
= 0; i
< (int)SEC__MAX
; i
++)
2189 if (secnames
[i
] && 0 == strcmp(p
, secnames
[i
]))
2190 return (enum roff_sec
)i
;
2196 macro2len(int macro
)