1 /* $Id: mdoc_validate.c,v 1.318 2017/02/06 03:44:58 schwarze Exp $ */
3 * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2010-2017 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 int build_list(struct roff_man
*, int);
55 static void check_text(struct roff_man
*, int, int, char *);
56 static void check_argv(struct roff_man
*,
57 struct roff_node
*, struct mdoc_argv
*);
58 static void check_args(struct roff_man
*, struct roff_node
*);
59 static int child_an(const struct roff_node
*);
60 static size_t macro2len(int);
61 static void rewrite_macro2len(char **);
63 static void post_an(POST_ARGS
);
64 static void post_an_norm(POST_ARGS
);
65 static void post_at(POST_ARGS
);
66 static void post_bd(POST_ARGS
);
67 static void post_bf(POST_ARGS
);
68 static void post_bk(POST_ARGS
);
69 static void post_bl(POST_ARGS
);
70 static void post_bl_block(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_rv(POST_ARGS
);
100 static void post_sh(POST_ARGS
);
101 static void post_sh_head(POST_ARGS
);
102 static void post_sh_name(POST_ARGS
);
103 static void post_sh_see_also(POST_ARGS
);
104 static void post_sh_authors(POST_ARGS
);
105 static void post_sm(POST_ARGS
);
106 static void post_st(POST_ARGS
);
107 static void post_std(POST_ARGS
);
108 static void post_xr(POST_ARGS
);
109 static void post_xx(POST_ARGS
);
111 static v_post mdoc_valids
[MDOC_MAX
] = {
117 post_ignpar
, /* Ss */
119 post_display
, /* D1 */
120 post_display
, /* Dl */
121 post_display
, /* Bd */
128 post_defaults
, /* Ar */
142 post_defaults
, /* Li */
146 post_obsolete
, /* Ot */
147 post_defaults
, /* Pa */
154 post_hyph
, /* %B */ /* FIXME: can be used outside Rs/Re. */
162 post_hyph
, /* %T */ /* FIXME: can be used outside Rs/Re. */
174 post_obsolete
, /* Db */
216 post_obsolete
, /* Fr */
221 post_defaults
, /* Mt */
237 #define RSORD_MAX 14 /* Number of `Rs' blocks. */
239 static const int rsord
[RSORD_MAX
] = {
256 static const char * const secnames
[SEC__MAX
] = {
263 "IMPLEMENTATION NOTES",
278 "SECURITY CONSIDERATIONS",
284 mdoc_node_validate(struct roff_man
*mdoc
)
290 mdoc
->last
= mdoc
->last
->child
;
291 while (mdoc
->last
!= NULL
) {
292 mdoc_node_validate(mdoc
);
294 mdoc
->last
= mdoc
->last
->child
;
296 mdoc
->last
= mdoc
->last
->next
;
300 mdoc
->next
= ROFF_NEXT_SIBLING
;
303 if (n
->sec
!= SEC_SYNOPSIS
||
304 (n
->parent
->tok
!= MDOC_Cd
&& n
->parent
->tok
!= MDOC_Fd
))
305 check_text(mdoc
, n
->line
, n
->pos
, n
->string
);
314 check_args(mdoc
, mdoc
->last
);
317 * Closing delimiters are not special at the
318 * beginning of a block, opening delimiters
319 * are not special at the end.
322 if (n
->child
!= NULL
)
323 n
->child
->flags
&= ~NODE_DELIMC
;
325 n
->last
->flags
&= ~NODE_DELIMO
;
327 /* Call the macro's postprocessor. */
329 p
= mdoc_valids
+ n
->tok
;
339 check_args(struct roff_man
*mdoc
, struct roff_node
*n
)
346 assert(n
->args
->argc
);
347 for (i
= 0; i
< (int)n
->args
->argc
; i
++)
348 check_argv(mdoc
, n
, &n
->args
->argv
[i
]);
352 check_argv(struct roff_man
*mdoc
, struct roff_node
*n
, struct mdoc_argv
*v
)
356 for (i
= 0; i
< (int)v
->sz
; i
++)
357 check_text(mdoc
, v
->line
, v
->pos
, v
->value
[i
]);
361 check_text(struct roff_man
*mdoc
, int ln
, int pos
, char *p
)
365 if (MDOC_LITERAL
& mdoc
->flags
)
368 for (cp
= p
; NULL
!= (p
= strchr(p
, '\t')); p
++)
369 mandoc_msg(MANDOCERR_FI_TAB
, mdoc
->parse
,
370 ln
, pos
+ (int)(p
- cp
), NULL
);
374 post_bl_norm(POST_ARGS
)
377 struct mdoc_argv
*argv
, *wa
;
379 enum mdocargt mdoclt
;
382 n
= mdoc
->last
->parent
;
383 n
->norm
->Bl
.type
= LIST__NONE
;
386 * First figure out which kind of list to use: bind ourselves to
387 * the first mentioned list type and warn about any remaining
388 * ones. If we find no list type, we default to LIST_item.
391 wa
= (n
->args
== NULL
) ? NULL
: n
->args
->argv
;
392 mdoclt
= MDOC_ARG_MAX
;
393 for (i
= 0; n
->args
&& i
< (int)n
->args
->argc
; i
++) {
394 argv
= n
->args
->argv
+ i
;
397 /* Set list types. */
431 /* Set list arguments. */
433 if (n
->norm
->Bl
.comp
)
434 mandoc_msg(MANDOCERR_ARG_REP
,
435 mdoc
->parse
, argv
->line
,
436 argv
->pos
, "Bl -compact");
437 n
->norm
->Bl
.comp
= 1;
442 mandoc_msg(MANDOCERR_ARG_EMPTY
,
443 mdoc
->parse
, argv
->line
,
444 argv
->pos
, "Bl -width");
445 n
->norm
->Bl
.width
= "0n";
448 if (NULL
!= n
->norm
->Bl
.width
)
449 mandoc_vmsg(MANDOCERR_ARG_REP
,
450 mdoc
->parse
, argv
->line
,
451 argv
->pos
, "Bl -width %s",
453 rewrite_macro2len(argv
->value
);
454 n
->norm
->Bl
.width
= argv
->value
[0];
458 mandoc_msg(MANDOCERR_ARG_EMPTY
,
459 mdoc
->parse
, argv
->line
,
460 argv
->pos
, "Bl -offset");
463 if (NULL
!= n
->norm
->Bl
.offs
)
464 mandoc_vmsg(MANDOCERR_ARG_REP
,
465 mdoc
->parse
, argv
->line
,
466 argv
->pos
, "Bl -offset %s",
468 rewrite_macro2len(argv
->value
);
469 n
->norm
->Bl
.offs
= argv
->value
[0];
474 if (LIST__NONE
== lt
)
478 /* Check: multiple list types. */
480 if (LIST__NONE
!= n
->norm
->Bl
.type
) {
481 mandoc_vmsg(MANDOCERR_BL_REP
,
482 mdoc
->parse
, n
->line
, n
->pos
,
483 "Bl -%s", mdoc_argnames
[argv
->arg
]);
487 /* The list type should come first. */
489 if (n
->norm
->Bl
.width
||
492 mandoc_vmsg(MANDOCERR_BL_LATETYPE
,
493 mdoc
->parse
, n
->line
, n
->pos
, "Bl -%s",
494 mdoc_argnames
[n
->args
->argv
[0].arg
]);
496 n
->norm
->Bl
.type
= lt
;
497 if (LIST_column
== lt
) {
498 n
->norm
->Bl
.ncols
= argv
->sz
;
499 n
->norm
->Bl
.cols
= (void *)argv
->value
;
503 /* Allow lists to default to LIST_item. */
505 if (LIST__NONE
== n
->norm
->Bl
.type
) {
506 mandoc_msg(MANDOCERR_BL_NOTYPE
, mdoc
->parse
,
507 n
->line
, n
->pos
, "Bl");
508 n
->norm
->Bl
.type
= LIST_item
;
513 * Validate the width field. Some list types don't need width
514 * types and should be warned about them. Others should have it
515 * and must also be warned. Yet others have a default and need
519 switch (n
->norm
->Bl
.type
) {
521 if (NULL
== n
->norm
->Bl
.width
)
522 mandoc_msg(MANDOCERR_BL_NOWIDTH
, mdoc
->parse
,
523 n
->line
, n
->pos
, "Bl -tag");
530 if (n
->norm
->Bl
.width
)
531 mandoc_vmsg(MANDOCERR_BL_SKIPW
, mdoc
->parse
,
532 wa
->line
, wa
->pos
, "Bl -%s",
533 mdoc_argnames
[mdoclt
]);
538 if (NULL
== n
->norm
->Bl
.width
)
539 n
->norm
->Bl
.width
= "2n";
542 if (NULL
== n
->norm
->Bl
.width
)
543 n
->norm
->Bl
.width
= "3n";
554 struct mdoc_argv
*argv
;
559 for (i
= 0; n
->args
&& i
< (int)n
->args
->argc
; i
++) {
560 argv
= n
->args
->argv
+ i
;
580 mandoc_msg(MANDOCERR_BD_FILE
, mdoc
->parse
,
581 n
->line
, n
->pos
, NULL
);
585 mandoc_msg(MANDOCERR_ARG_EMPTY
,
586 mdoc
->parse
, argv
->line
,
587 argv
->pos
, "Bd -offset");
590 if (NULL
!= n
->norm
->Bd
.offs
)
591 mandoc_vmsg(MANDOCERR_ARG_REP
,
592 mdoc
->parse
, argv
->line
,
593 argv
->pos
, "Bd -offset %s",
595 rewrite_macro2len(argv
->value
);
596 n
->norm
->Bd
.offs
= argv
->value
[0];
599 if (n
->norm
->Bd
.comp
)
600 mandoc_msg(MANDOCERR_ARG_REP
,
601 mdoc
->parse
, argv
->line
,
602 argv
->pos
, "Bd -compact");
603 n
->norm
->Bd
.comp
= 1;
608 if (DISP__NONE
== dt
)
611 if (DISP__NONE
== n
->norm
->Bd
.type
)
612 n
->norm
->Bd
.type
= dt
;
614 mandoc_vmsg(MANDOCERR_BD_REP
,
615 mdoc
->parse
, n
->line
, n
->pos
,
616 "Bd -%s", mdoc_argnames
[argv
->arg
]);
619 if (DISP__NONE
== n
->norm
->Bd
.type
) {
620 mandoc_msg(MANDOCERR_BD_NOTYPE
, mdoc
->parse
,
621 n
->line
, n
->pos
, "Bd");
622 n
->norm
->Bd
.type
= DISP_ragged
;
627 * Stand-alone line macros.
631 post_an_norm(POST_ARGS
)
634 struct mdoc_argv
*argv
;
641 for (i
= 1; i
< n
->args
->argc
; i
++) {
642 argv
= n
->args
->argv
+ i
;
643 mandoc_vmsg(MANDOCERR_AN_REP
,
644 mdoc
->parse
, argv
->line
, argv
->pos
,
645 "An -%s", mdoc_argnames
[argv
->arg
]);
648 argv
= n
->args
->argv
;
649 if (argv
->arg
== MDOC_Split
)
650 n
->norm
->An
.auth
= AUTH_split
;
651 else if (argv
->arg
== MDOC_Nosplit
)
652 n
->norm
->An
.auth
= AUTH_nosplit
;
663 if (n
->child
!= NULL
)
664 mandoc_vmsg(MANDOCERR_ARG_SKIP
, mdoc
->parse
,
665 n
->line
, n
->pos
, "%s %s",
666 mdoc_macronames
[n
->tok
], n
->child
->string
);
668 while (n
->child
!= NULL
)
669 roff_node_delete(mdoc
, n
->child
);
671 roff_word_alloc(mdoc
, n
->line
, n
->pos
, n
->tok
== MDOC_Bt
?
672 "is currently in beta test." : "currently under development.");
673 mdoc
->last
->flags
|= NODE_EOS
| NODE_NOSRC
;
678 build_list(struct roff_man
*mdoc
, int tok
)
683 n
= mdoc
->last
->next
;
684 for (ic
= 1;; ic
++) {
685 roff_elem_alloc(mdoc
, n
->line
, n
->pos
, tok
);
686 mdoc
->last
->flags
|= NODE_NOSRC
;
687 mdoc_node_relink(mdoc
, n
);
688 n
= mdoc
->last
= mdoc
->last
->parent
;
689 mdoc
->next
= ROFF_NEXT_SIBLING
;
692 if (ic
> 1 || n
->next
->next
!= NULL
) {
693 roff_word_alloc(mdoc
, n
->line
, n
->pos
, ",");
694 mdoc
->last
->flags
|= NODE_DELIMC
| NODE_NOSRC
;
696 n
= mdoc
->last
->next
;
697 if (n
->next
== NULL
) {
698 roff_word_alloc(mdoc
, n
->line
, n
->pos
, "and");
699 mdoc
->last
->flags
|= NODE_NOSRC
;
713 mdoc
->next
= ROFF_NEXT_CHILD
;
714 roff_word_alloc(mdoc
, n
->line
, n
->pos
, "The");
715 mdoc
->last
->flags
|= NODE_NOSRC
;
717 if (mdoc
->last
->next
!= NULL
)
718 ic
= build_list(mdoc
, MDOC_Nm
);
719 else if (mdoc
->meta
.name
!= NULL
) {
720 roff_elem_alloc(mdoc
, n
->line
, n
->pos
, MDOC_Nm
);
721 mdoc
->last
->flags
|= NODE_NOSRC
;
722 roff_word_alloc(mdoc
, n
->line
, n
->pos
, mdoc
->meta
.name
);
723 mdoc
->last
->flags
|= NODE_NOSRC
;
724 mdoc
->last
= mdoc
->last
->parent
;
725 mdoc
->next
= ROFF_NEXT_SIBLING
;
728 mandoc_msg(MANDOCERR_EX_NONAME
, mdoc
->parse
,
729 n
->line
, n
->pos
, "Ex");
733 roff_word_alloc(mdoc
, n
->line
, n
->pos
,
734 ic
> 1 ? "utilities exit\\~0" : "utility exits\\~0");
735 mdoc
->last
->flags
|= NODE_NOSRC
;
736 roff_word_alloc(mdoc
, n
->line
, n
->pos
,
737 "on success, and\\~>0 if an error occurs.");
738 mdoc
->last
->flags
|= NODE_EOS
| NODE_NOSRC
;
749 assert(n
->child
->type
== ROFFT_TEXT
);
750 mdoc
->next
= ROFF_NEXT_CHILD
;
752 if ((p
= mdoc_a2lib(n
->child
->string
)) != NULL
) {
753 n
->child
->flags
|= NODE_NOPRT
;
754 roff_word_alloc(mdoc
, n
->line
, n
->pos
, p
);
755 mdoc
->last
->flags
= NODE_NOSRC
;
760 roff_word_alloc(mdoc
, n
->line
, n
->pos
, "library");
761 mdoc
->last
->flags
= NODE_NOSRC
;
762 roff_word_alloc(mdoc
, n
->line
, n
->pos
, "\\(Lq");
763 mdoc
->last
->flags
= NODE_DELIMO
| NODE_NOSRC
;
764 mdoc
->last
= mdoc
->last
->next
;
765 roff_word_alloc(mdoc
, n
->line
, n
->pos
, "\\(Rq");
766 mdoc
->last
->flags
= NODE_DELIMC
| NODE_NOSRC
;
779 mdoc
->next
= ROFF_NEXT_CHILD
;
780 if (n
->child
!= NULL
) {
781 roff_word_alloc(mdoc
, n
->line
, n
->pos
, "The");
782 mdoc
->last
->flags
|= NODE_NOSRC
;
783 ic
= build_list(mdoc
, MDOC_Fn
);
784 roff_word_alloc(mdoc
, n
->line
, n
->pos
,
785 ic
> 1 ? "functions return" : "function returns");
786 mdoc
->last
->flags
|= NODE_NOSRC
;
787 roff_word_alloc(mdoc
, n
->line
, n
->pos
,
788 "the value\\~0 if successful;");
790 roff_word_alloc(mdoc
, n
->line
, n
->pos
, "Upon successful "
791 "completion, the value\\~0 is returned;");
792 mdoc
->last
->flags
|= NODE_NOSRC
;
794 roff_word_alloc(mdoc
, n
->line
, n
->pos
, "otherwise "
795 "the value\\~\\-1 is returned and the global variable");
796 mdoc
->last
->flags
|= NODE_NOSRC
;
797 roff_elem_alloc(mdoc
, n
->line
, n
->pos
, MDOC_Va
);
798 mdoc
->last
->flags
|= NODE_NOSRC
;
799 roff_word_alloc(mdoc
, n
->line
, n
->pos
, "errno");
800 mdoc
->last
->flags
|= NODE_NOSRC
;
801 mdoc
->last
= mdoc
->last
->parent
;
802 mdoc
->next
= ROFF_NEXT_SIBLING
;
803 roff_word_alloc(mdoc
, n
->line
, n
->pos
,
804 "is set to indicate the error.");
805 mdoc
->last
->flags
|= NODE_EOS
| NODE_NOSRC
;
815 if (n
->args
&& n
->args
->argc
== 1)
816 if (n
->args
->argv
[0].arg
== MDOC_Std
)
819 mandoc_msg(MANDOCERR_ARG_STD
, mdoc
->parse
,
820 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
826 struct roff_node
*n
, *nch
;
831 assert(nch
->type
== ROFFT_TEXT
);
833 if ((p
= mdoc_a2st(nch
->string
)) == NULL
) {
834 mandoc_vmsg(MANDOCERR_ST_BAD
, mdoc
->parse
,
835 nch
->line
, nch
->pos
, "St %s", nch
->string
);
836 roff_node_delete(mdoc
, n
);
840 nch
->flags
|= NODE_NOPRT
;
841 mdoc
->next
= ROFF_NEXT_CHILD
;
842 roff_word_alloc(mdoc
, nch
->line
, nch
->pos
, p
);
843 mdoc
->last
->flags
|= NODE_NOSRC
;
848 post_obsolete(POST_ARGS
)
853 if (n
->type
== ROFFT_ELEM
|| n
->type
== ROFFT_BLOCK
)
854 mandoc_msg(MANDOCERR_MACRO_OBS
, mdoc
->parse
,
855 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
865 struct roff_node
*np
, *nch
;
868 * Unlike other data pointers, these are "housed" by the HEAD
869 * element, which contains the goods.
873 if (np
->type
!= ROFFT_HEAD
)
876 assert(np
->parent
->type
== ROFFT_BLOCK
);
877 assert(np
->parent
->tok
== MDOC_Bf
);
879 /* Check the number of arguments. */
882 if (np
->parent
->args
== NULL
) {
884 mandoc_msg(MANDOCERR_BF_NOFONT
, mdoc
->parse
,
885 np
->line
, np
->pos
, "Bf");
891 mandoc_vmsg(MANDOCERR_ARG_EXCESS
, mdoc
->parse
,
892 nch
->line
, nch
->pos
, "Bf ... %s", nch
->string
);
894 /* Extract argument into data. */
896 if (np
->parent
->args
!= NULL
) {
897 switch (np
->parent
->args
->argv
[0].arg
) {
899 np
->norm
->Bf
.font
= FONT_Em
;
902 np
->norm
->Bf
.font
= FONT_Li
;
905 np
->norm
->Bf
.font
= FONT_Sy
;
913 /* Extract parameter into data. */
915 if ( ! strcmp(np
->child
->string
, "Em"))
916 np
->norm
->Bf
.font
= FONT_Em
;
917 else if ( ! strcmp(np
->child
->string
, "Li"))
918 np
->norm
->Bf
.font
= FONT_Li
;
919 else if ( ! strcmp(np
->child
->string
, "Sy"))
920 np
->norm
->Bf
.font
= FONT_Sy
;
922 mandoc_vmsg(MANDOCERR_BF_BADFONT
, mdoc
->parse
,
923 np
->child
->line
, np
->child
->pos
,
924 "Bf %s", np
->child
->string
);
928 post_fname(POST_ARGS
)
930 const struct roff_node
*n
;
934 n
= mdoc
->last
->child
;
935 pos
= strcspn(n
->string
, "()");
936 cp
= n
->string
+ pos
;
937 if ( ! (cp
[0] == '\0' || (cp
[0] == '(' && cp
[1] == '*')))
938 mandoc_msg(MANDOCERR_FN_PAREN
, mdoc
->parse
,
939 n
->line
, n
->pos
+ pos
, n
->string
);
953 const struct roff_node
*n
;
957 if (n
->type
!= ROFFT_HEAD
)
960 if (n
->child
== NULL
) {
961 mandoc_msg(MANDOCERR_FO_NOHEAD
, mdoc
->parse
,
962 n
->line
, n
->pos
, "Fo");
965 if (n
->child
!= n
->last
) {
966 mandoc_vmsg(MANDOCERR_ARG_EXCESS
, mdoc
->parse
,
967 n
->child
->next
->line
, n
->child
->next
->pos
,
968 "Fo ... %s", n
->child
->next
->string
);
969 while (n
->child
!= n
->last
)
970 roff_node_delete(mdoc
, n
->last
);
979 const struct roff_node
*n
;
982 for (n
= mdoc
->last
->child
; n
!= NULL
; n
= n
->next
) {
983 for (cp
= n
->string
; *cp
!= '\0'; cp
++) {
984 /* Ignore callbacks and alterations. */
985 if (*cp
== '(' || *cp
== '{')
989 mandoc_msg(MANDOCERR_FA_COMMA
, mdoc
->parse
,
990 n
->line
, n
->pos
+ (cp
- n
->string
),
1000 struct roff_node
*n
;
1004 if (n
->last
!= NULL
&&
1005 (n
->last
->tok
== MDOC_Pp
||
1006 n
->last
->tok
== MDOC_Lp
))
1007 mdoc_node_relink(mdoc
, n
->last
);
1009 if (mdoc
->meta
.name
== NULL
)
1010 deroff(&mdoc
->meta
.name
, n
);
1012 if (mdoc
->meta
.name
== NULL
||
1013 (mdoc
->lastsec
== SEC_NAME
&& n
->child
== NULL
))
1014 mandoc_msg(MANDOCERR_NM_NONAME
, mdoc
->parse
,
1015 n
->line
, n
->pos
, "Nm");
1017 if ((n
->type
!= ROFFT_ELEM
&& n
->type
!= ROFFT_HEAD
) ||
1018 (n
->child
!= NULL
&& n
->child
->type
== ROFFT_TEXT
) ||
1019 mdoc
->meta
.name
== NULL
)
1022 mdoc
->next
= ROFF_NEXT_CHILD
;
1023 roff_word_alloc(mdoc
, n
->line
, n
->pos
, mdoc
->meta
.name
);
1024 mdoc
->last
->flags
|= NODE_NOSRC
;
1031 struct roff_node
*n
;
1035 if (n
->type
!= ROFFT_BODY
)
1038 if (n
->child
== NULL
)
1039 mandoc_msg(MANDOCERR_ND_EMPTY
, mdoc
->parse
,
1040 n
->line
, n
->pos
, "Nd");
1046 post_display(POST_ARGS
)
1048 struct roff_node
*n
, *np
;
1053 if (n
->end
!= ENDBODY_NOT
) {
1054 if (n
->tok
== MDOC_Bd
&&
1055 n
->body
->parent
->args
== NULL
)
1056 roff_node_delete(mdoc
, n
);
1057 } else if (n
->child
== NULL
)
1058 mandoc_msg(MANDOCERR_BLK_EMPTY
, mdoc
->parse
,
1059 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
1060 else if (n
->tok
== MDOC_D1
)
1064 if (n
->tok
== MDOC_Bd
) {
1065 if (n
->args
== NULL
) {
1066 mandoc_msg(MANDOCERR_BD_NOARG
,
1067 mdoc
->parse
, n
->line
, n
->pos
, "Bd");
1068 mdoc
->next
= ROFF_NEXT_SIBLING
;
1069 while (n
->body
->child
!= NULL
)
1070 mdoc_node_relink(mdoc
,
1072 roff_node_delete(mdoc
, n
);
1078 for (np
= n
->parent
; np
!= NULL
; np
= np
->parent
) {
1079 if (np
->type
== ROFFT_BLOCK
&& np
->tok
== MDOC_Bd
) {
1080 mandoc_vmsg(MANDOCERR_BD_NEST
,
1081 mdoc
->parse
, n
->line
, n
->pos
,
1082 "%s in Bd", mdoc_macronames
[n
->tok
]);
1093 post_defaults(POST_ARGS
)
1095 struct roff_node
*nn
;
1098 * The `Ar' defaults to "file ..." if no value is provided as an
1099 * argument; the `Mt' and `Pa' macros use "~"; the `Li' just
1100 * gets an empty string.
1103 if (mdoc
->last
->child
!= NULL
)
1110 mdoc
->next
= ROFF_NEXT_CHILD
;
1111 roff_word_alloc(mdoc
, nn
->line
, nn
->pos
, "file");
1112 mdoc
->last
->flags
|= NODE_NOSRC
;
1113 roff_word_alloc(mdoc
, nn
->line
, nn
->pos
, "...");
1114 mdoc
->last
->flags
|= NODE_NOSRC
;
1118 mdoc
->next
= ROFF_NEXT_CHILD
;
1119 roff_word_alloc(mdoc
, nn
->line
, nn
->pos
, "~");
1120 mdoc
->last
->flags
|= NODE_NOSRC
;
1131 struct roff_node
*n
, *nch
;
1138 * If we have a child, look it up in the standard keys. If a
1139 * key exist, use that instead of the child; if it doesn't,
1140 * prefix "AT&T UNIX " to the existing data.
1144 if (nch
!= NULL
&& ((att
= mdoc_a2att(nch
->string
)) == NULL
))
1145 mandoc_vmsg(MANDOCERR_AT_BAD
, mdoc
->parse
,
1146 nch
->line
, nch
->pos
, "At %s", nch
->string
);
1148 mdoc
->next
= ROFF_NEXT_CHILD
;
1150 roff_word_alloc(mdoc
, nch
->line
, nch
->pos
, att
);
1151 nch
->flags
|= NODE_NOPRT
;
1153 roff_word_alloc(mdoc
, n
->line
, n
->pos
, "AT&T UNIX");
1154 mdoc
->last
->flags
|= NODE_NOSRC
;
1161 struct roff_node
*np
, *nch
;
1167 if (np
->norm
->An
.auth
== AUTH__NONE
) {
1169 mandoc_msg(MANDOCERR_MACRO_EMPTY
, mdoc
->parse
,
1170 np
->line
, np
->pos
, "An");
1171 } else if (nch
!= NULL
)
1172 mandoc_vmsg(MANDOCERR_ARG_EXCESS
, mdoc
->parse
,
1173 nch
->line
, nch
->pos
, "An ... %s", nch
->string
);
1180 post_obsolete(mdoc
);
1181 if (mdoc
->last
->type
== ROFFT_BLOCK
)
1182 mdoc
->last
->norm
->Es
= mdoc
->last_es
;
1189 post_obsolete(mdoc
);
1190 mdoc
->last_es
= mdoc
->last
;
1196 struct roff_node
*n
;
1222 mdoc
->next
= ROFF_NEXT_CHILD
;
1223 roff_word_alloc(mdoc
, n
->line
, n
->pos
, os
);
1224 mdoc
->last
->flags
|= NODE_NOSRC
;
1231 struct roff_node
*nbl
, *nit
, *nch
;
1238 if (nit
->type
!= ROFFT_BLOCK
)
1241 nbl
= nit
->parent
->parent
;
1242 lt
= nbl
->norm
->Bl
.type
;
1250 if (nit
->head
->child
== NULL
)
1251 mandoc_vmsg(MANDOCERR_IT_NOHEAD
,
1252 mdoc
->parse
, nit
->line
, nit
->pos
,
1254 mdoc_argnames
[nbl
->args
->argv
[0].arg
]);
1260 if (nit
->body
== NULL
|| nit
->body
->child
== NULL
)
1261 mandoc_vmsg(MANDOCERR_IT_NOBODY
,
1262 mdoc
->parse
, nit
->line
, nit
->pos
,
1264 mdoc_argnames
[nbl
->args
->argv
[0].arg
]);
1267 if ((nch
= nit
->head
->child
) != NULL
)
1268 mandoc_vmsg(MANDOCERR_ARG_SKIP
,
1269 mdoc
->parse
, nit
->line
, nit
->pos
,
1270 "It %s", nch
->string
== NULL
?
1271 mdoc_macronames
[nch
->tok
] : nch
->string
);
1274 cols
= (int)nbl
->norm
->Bl
.ncols
;
1276 assert(nit
->head
->child
== NULL
);
1279 for (nch
= nit
->child
; nch
!= NULL
; nch
= nch
->next
)
1280 if (nch
->type
== ROFFT_BODY
)
1283 if (i
< cols
|| i
> cols
+ 1)
1284 mandoc_vmsg(MANDOCERR_BL_COL
,
1285 mdoc
->parse
, nit
->line
, nit
->pos
,
1286 "%d columns, %d cells", cols
, i
);
1294 post_bl_block(POST_ARGS
)
1296 struct roff_node
*n
, *ni
, *nc
;
1301 for (ni
= n
->body
->child
; ni
!= NULL
; ni
= ni
->next
) {
1302 if (ni
->body
== NULL
)
1304 nc
= ni
->body
->last
;
1305 while (nc
!= NULL
) {
1315 if (ni
->next
== NULL
) {
1316 mandoc_msg(MANDOCERR_PAR_MOVE
,
1317 mdoc
->parse
, nc
->line
, nc
->pos
,
1318 mdoc_macronames
[nc
->tok
]);
1319 mdoc_node_relink(mdoc
, nc
);
1320 } else if (n
->norm
->Bl
.comp
== 0 &&
1321 n
->norm
->Bl
.type
!= LIST_column
) {
1322 mandoc_vmsg(MANDOCERR_PAR_SKIP
,
1323 mdoc
->parse
, nc
->line
, nc
->pos
,
1325 mdoc_macronames
[nc
->tok
]);
1326 roff_node_delete(mdoc
, nc
);
1329 nc
= ni
->body
->last
;
1335 * If the argument of -offset or -width is a macro,
1336 * replace it with the associated default width.
1339 rewrite_macro2len(char **arg
)
1346 else if ( ! strcmp(*arg
, "Ds"))
1348 else if ((tok
= mdoc_hash_find(*arg
)) == TOKEN_NONE
)
1351 width
= macro2len(tok
);
1354 mandoc_asprintf(arg
, "%zun", width
);
1358 post_bl_head(POST_ARGS
)
1360 struct roff_node
*nbl
, *nh
, *nch
, *nnext
;
1361 struct mdoc_argv
*argv
;
1367 if (nh
->norm
->Bl
.type
!= LIST_column
) {
1368 if ((nch
= nh
->child
) == NULL
)
1370 mandoc_vmsg(MANDOCERR_ARG_EXCESS
, mdoc
->parse
,
1371 nch
->line
, nch
->pos
, "Bl ... %s", nch
->string
);
1372 while (nch
!= NULL
) {
1373 roff_node_delete(mdoc
, nch
);
1380 * Append old-style lists, where the column width specifiers
1381 * trail as macro parameters, to the new-style ("normal-form")
1382 * lists where they're argument values following -column.
1385 if (nh
->child
== NULL
)
1389 for (j
= 0; j
< (int)nbl
->args
->argc
; j
++)
1390 if (nbl
->args
->argv
[j
].arg
== MDOC_Column
)
1393 assert(j
< (int)nbl
->args
->argc
);
1396 * Accommodate for new-style groff column syntax. Shuffle the
1397 * child nodes, all of which must be TEXT, as arguments for the
1398 * column field. Then, delete the head children.
1401 argv
= nbl
->args
->argv
+ j
;
1403 for (nch
= nh
->child
; nch
!= NULL
; nch
= nch
->next
)
1405 argv
->value
= mandoc_reallocarray(argv
->value
,
1406 argv
->sz
, sizeof(char *));
1408 nh
->norm
->Bl
.ncols
= argv
->sz
;
1409 nh
->norm
->Bl
.cols
= (void *)argv
->value
;
1411 for (nch
= nh
->child
; nch
!= NULL
; nch
= nnext
) {
1412 argv
->value
[i
++] = nch
->string
;
1415 roff_node_delete(NULL
, nch
);
1423 struct roff_node
*nparent
, *nprev
; /* of the Bl block */
1424 struct roff_node
*nblock
, *nbody
; /* of the Bl */
1425 struct roff_node
*nchild
, *nnext
; /* of the Bl body */
1428 switch (nbody
->type
) {
1430 post_bl_block(mdoc
);
1440 if (nbody
->end
!= ENDBODY_NOT
)
1443 nchild
= nbody
->child
;
1444 if (nchild
== NULL
) {
1445 mandoc_msg(MANDOCERR_BLK_EMPTY
, mdoc
->parse
,
1446 nbody
->line
, nbody
->pos
, "Bl");
1449 while (nchild
!= NULL
) {
1450 nnext
= nchild
->next
;
1451 if (nchild
->tok
== MDOC_It
||
1452 (nchild
->tok
== MDOC_Sm
&&
1453 nnext
!= NULL
&& nnext
->tok
== MDOC_It
)) {
1459 * In .Bl -column, the first rows may be implicit,
1460 * that is, they may not start with .It macros.
1461 * Such rows may be followed by nodes generated on the
1462 * roff level, for example .TS, which cannot be moved
1463 * out of the list. In that case, wrap such roff nodes
1464 * into an implicit row.
1467 if (nchild
->prev
!= NULL
) {
1468 mdoc
->last
= nchild
;
1469 mdoc
->next
= ROFF_NEXT_SIBLING
;
1470 roff_block_alloc(mdoc
, nchild
->line
,
1471 nchild
->pos
, MDOC_It
);
1472 roff_head_alloc(mdoc
, nchild
->line
,
1473 nchild
->pos
, MDOC_It
);
1474 mdoc
->next
= ROFF_NEXT_SIBLING
;
1475 roff_body_alloc(mdoc
, nchild
->line
,
1476 nchild
->pos
, MDOC_It
);
1477 while (nchild
->tok
!= MDOC_It
) {
1478 mdoc_node_relink(mdoc
, nchild
);
1479 if ((nchild
= nnext
) == NULL
)
1481 nnext
= nchild
->next
;
1482 mdoc
->next
= ROFF_NEXT_SIBLING
;
1488 mandoc_msg(MANDOCERR_BL_MOVE
, mdoc
->parse
,
1489 nchild
->line
, nchild
->pos
,
1490 mdoc_macronames
[nchild
->tok
]);
1493 * Move the node out of the Bl block.
1494 * First, collect all required node pointers.
1497 nblock
= nbody
->parent
;
1498 nprev
= nblock
->prev
;
1499 nparent
= nblock
->parent
;
1502 * Unlink this child.
1505 nbody
->child
= nnext
;
1512 * Relink this child.
1515 nchild
->parent
= nparent
;
1516 nchild
->prev
= nprev
;
1517 nchild
->next
= nblock
;
1519 nblock
->prev
= nchild
;
1521 nparent
->child
= nchild
;
1523 nprev
->next
= nchild
;
1532 struct roff_node
*n
;
1536 if (n
->type
== ROFFT_BLOCK
&& n
->body
->child
== NULL
) {
1537 mandoc_msg(MANDOCERR_BLK_EMPTY
,
1538 mdoc
->parse
, n
->line
, n
->pos
, "Bk");
1539 roff_node_delete(mdoc
, n
);
1546 struct roff_node
*nch
;
1548 nch
= mdoc
->last
->child
;
1551 mdoc
->flags
^= MDOC_SMOFF
;
1555 assert(nch
->type
== ROFFT_TEXT
);
1557 if ( ! strcmp(nch
->string
, "on")) {
1558 mdoc
->flags
&= ~MDOC_SMOFF
;
1561 if ( ! strcmp(nch
->string
, "off")) {
1562 mdoc
->flags
|= MDOC_SMOFF
;
1566 mandoc_vmsg(MANDOCERR_SM_BAD
,
1567 mdoc
->parse
, nch
->line
, nch
->pos
,
1568 "%s %s", mdoc_macronames
[mdoc
->last
->tok
], nch
->string
);
1569 mdoc_node_relink(mdoc
, nch
);
1574 post_root(POST_ARGS
)
1576 struct roff_node
*n
;
1578 /* Add missing prologue data. */
1580 if (mdoc
->meta
.date
== NULL
)
1581 mdoc
->meta
.date
= mdoc
->quick
?
1583 mandoc_normdate(mdoc
->parse
, NULL
, 0, 0);
1585 if (mdoc
->meta
.title
== NULL
) {
1586 mandoc_msg(MANDOCERR_DT_NOTITLE
,
1587 mdoc
->parse
, 0, 0, "EOF");
1588 mdoc
->meta
.title
= mandoc_strdup("UNTITLED");
1591 if (mdoc
->meta
.vol
== NULL
)
1592 mdoc
->meta
.vol
= mandoc_strdup("LOCAL");
1594 if (mdoc
->meta
.os
== NULL
) {
1595 mandoc_msg(MANDOCERR_OS_MISSING
,
1596 mdoc
->parse
, 0, 0, NULL
);
1597 mdoc
->meta
.os
= mandoc_strdup("");
1600 /* Check that we begin with a proper `Sh'. */
1602 n
= mdoc
->first
->child
;
1603 while (n
!= NULL
&& n
->tok
!= TOKEN_NONE
&&
1604 mdoc_macros
[n
->tok
].flags
& MDOC_PROLOGUE
)
1608 mandoc_msg(MANDOCERR_DOC_EMPTY
, mdoc
->parse
, 0, 0, NULL
);
1609 else if (n
->tok
!= MDOC_Sh
)
1610 mandoc_msg(MANDOCERR_SEC_BEFORE
, mdoc
->parse
,
1611 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
1617 struct roff_node
*np
, *nch
, *next
, *prev
;
1622 if (np
->type
!= ROFFT_BODY
)
1625 if (np
->child
== NULL
) {
1626 mandoc_msg(MANDOCERR_RS_EMPTY
, mdoc
->parse
,
1627 np
->line
, np
->pos
, "Rs");
1632 * The full `Rs' block needs special handling to order the
1633 * sub-elements according to `rsord'. Pick through each element
1634 * and correctly order it. This is an insertion sort.
1638 for (nch
= np
->child
->next
; nch
!= NULL
; nch
= next
) {
1639 /* Determine order number of this child. */
1640 for (i
= 0; i
< RSORD_MAX
; i
++)
1641 if (rsord
[i
] == nch
->tok
)
1644 if (i
== RSORD_MAX
) {
1645 mandoc_msg(MANDOCERR_RS_BAD
,
1646 mdoc
->parse
, nch
->line
, nch
->pos
,
1647 mdoc_macronames
[nch
->tok
]);
1649 } else if (nch
->tok
== MDOC__J
|| nch
->tok
== MDOC__B
)
1650 np
->norm
->Rs
.quote_T
++;
1653 * Remove this child from the chain. This somewhat
1654 * repeats roff_node_unlink(), but since we're
1655 * just re-ordering, there's no need for the
1656 * full unlink process.
1659 if ((next
= nch
->next
) != NULL
)
1660 next
->prev
= nch
->prev
;
1662 if ((prev
= nch
->prev
) != NULL
)
1663 prev
->next
= nch
->next
;
1665 nch
->prev
= nch
->next
= NULL
;
1668 * Scan back until we reach a node that's
1669 * to be ordered before this child.
1672 for ( ; prev
; prev
= prev
->prev
) {
1673 /* Determine order of `prev'. */
1674 for (j
= 0; j
< RSORD_MAX
; j
++)
1675 if (rsord
[j
] == prev
->tok
)
1685 * Set this child back into its correct place
1686 * in front of the `prev' node.
1692 np
->child
->prev
= nch
;
1693 nch
->next
= np
->child
;
1697 prev
->next
->prev
= nch
;
1698 nch
->next
= prev
->next
;
1705 * For some arguments of some macros,
1706 * convert all breakable hyphens into ASCII_HYPH.
1709 post_hyph(POST_ARGS
)
1711 struct roff_node
*nch
;
1714 for (nch
= mdoc
->last
->child
; nch
!= NULL
; nch
= nch
->next
) {
1715 if (nch
->type
!= ROFFT_TEXT
)
1720 while (*(++cp
) != '\0')
1722 isalpha((unsigned char)cp
[-1]) &&
1723 isalpha((unsigned char)cp
[1]))
1732 if (mdoc
->last
->flags
& NODE_LINE
)
1733 mandoc_msg(MANDOCERR_NS_SKIP
, mdoc
->parse
,
1734 mdoc
->last
->line
, mdoc
->last
->pos
, NULL
);
1743 switch (mdoc
->last
->type
) {
1748 switch (mdoc
->lastsec
) {
1753 post_sh_see_also(mdoc
);
1756 post_sh_authors(mdoc
);
1768 post_sh_name(POST_ARGS
)
1770 struct roff_node
*n
;
1775 for (n
= mdoc
->last
->child
; n
!= NULL
; n
= n
->next
) {
1778 if (hasnm
&& n
->child
!= NULL
)
1779 mandoc_vmsg(MANDOCERR_NAMESEC_PUNCT
,
1780 mdoc
->parse
, n
->line
, n
->pos
,
1781 "Nm %s", n
->child
->string
);
1786 if (n
->next
!= NULL
)
1787 mandoc_msg(MANDOCERR_NAMESEC_ND
,
1788 mdoc
->parse
, n
->line
, n
->pos
, NULL
);
1791 if (n
->type
== ROFFT_TEXT
&&
1792 n
->string
[0] == ',' && n
->string
[1] == '\0' &&
1793 n
->next
!= NULL
&& n
->next
->tok
== MDOC_Nm
) {
1799 mandoc_msg(MANDOCERR_NAMESEC_BAD
, mdoc
->parse
,
1800 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
1807 mandoc_msg(MANDOCERR_NAMESEC_NONM
, mdoc
->parse
,
1808 mdoc
->last
->line
, mdoc
->last
->pos
, NULL
);
1810 mandoc_msg(MANDOCERR_NAMESEC_NOND
, mdoc
->parse
,
1811 mdoc
->last
->line
, mdoc
->last
->pos
, NULL
);
1815 post_sh_see_also(POST_ARGS
)
1817 const struct roff_node
*n
;
1818 const char *name
, *sec
;
1819 const char *lastname
, *lastsec
, *lastpunct
;
1822 n
= mdoc
->last
->child
;
1823 lastname
= lastsec
= lastpunct
= NULL
;
1825 if (n
->tok
!= MDOC_Xr
||
1827 n
->child
->next
== NULL
)
1830 /* Process one .Xr node. */
1832 name
= n
->child
->string
;
1833 sec
= n
->child
->next
->string
;
1834 if (lastsec
!= NULL
) {
1835 if (lastpunct
[0] != ',' || lastpunct
[1] != '\0')
1836 mandoc_vmsg(MANDOCERR_XR_PUNCT
,
1837 mdoc
->parse
, n
->line
, n
->pos
,
1838 "%s before %s(%s)", lastpunct
,
1840 cmp
= strcmp(lastsec
, sec
);
1842 mandoc_vmsg(MANDOCERR_XR_ORDER
,
1843 mdoc
->parse
, n
->line
, n
->pos
,
1844 "%s(%s) after %s(%s)", name
,
1845 sec
, lastname
, lastsec
);
1846 else if (cmp
== 0 &&
1847 strcasecmp(lastname
, name
) > 0)
1848 mandoc_vmsg(MANDOCERR_XR_ORDER
,
1849 mdoc
->parse
, n
->line
, n
->pos
,
1850 "%s after %s", name
, lastname
);
1855 /* Process the following node. */
1860 if (n
->tok
== MDOC_Xr
) {
1864 if (n
->type
!= ROFFT_TEXT
)
1866 for (name
= n
->string
; *name
!= '\0'; name
++)
1867 if (isalpha((const unsigned char)*name
))
1869 lastpunct
= n
->string
;
1870 if (n
->next
== NULL
)
1871 mandoc_vmsg(MANDOCERR_XR_PUNCT
, mdoc
->parse
,
1872 n
->line
, n
->pos
, "%s after %s(%s)",
1873 lastpunct
, lastname
, lastsec
);
1879 child_an(const struct roff_node
*n
)
1882 for (n
= n
->child
; n
!= NULL
; n
= n
->next
)
1883 if ((n
->tok
== MDOC_An
&& n
->child
!= NULL
) || child_an(n
))
1889 post_sh_authors(POST_ARGS
)
1892 if ( ! child_an(mdoc
->last
))
1893 mandoc_msg(MANDOCERR_AN_MISSING
, mdoc
->parse
,
1894 mdoc
->last
->line
, mdoc
->last
->pos
, NULL
);
1898 post_sh_head(POST_ARGS
)
1900 struct roff_node
*nch
;
1901 const char *goodsec
;
1905 * Process a new section. Sections are either "named" or
1906 * "custom". Custom sections are user-defined, while named ones
1907 * follow a conventional order and may only appear in certain
1911 sec
= mdoc
->last
->sec
;
1913 /* The NAME should be first. */
1915 if (sec
!= SEC_NAME
&& mdoc
->lastnamed
== SEC_NONE
)
1916 mandoc_vmsg(MANDOCERR_NAMESEC_FIRST
, mdoc
->parse
,
1917 mdoc
->last
->line
, mdoc
->last
->pos
, "Sh %s",
1918 sec
!= SEC_CUSTOM
? secnames
[sec
] :
1919 (nch
= mdoc
->last
->child
) == NULL
? "" :
1920 nch
->type
== ROFFT_TEXT
? nch
->string
:
1921 mdoc_macronames
[nch
->tok
]);
1923 /* The SYNOPSIS gets special attention in other areas. */
1925 if (sec
== SEC_SYNOPSIS
) {
1926 roff_setreg(mdoc
->roff
, "nS", 1, '=');
1927 mdoc
->flags
|= MDOC_SYNOPSIS
;
1929 roff_setreg(mdoc
->roff
, "nS", 0, '=');
1930 mdoc
->flags
&= ~MDOC_SYNOPSIS
;
1933 /* Mark our last section. */
1935 mdoc
->lastsec
= sec
;
1937 /* We don't care about custom sections after this. */
1939 if (sec
== SEC_CUSTOM
)
1943 * Check whether our non-custom section is being repeated or is
1947 if (sec
== mdoc
->lastnamed
)
1948 mandoc_vmsg(MANDOCERR_SEC_REP
, mdoc
->parse
,
1949 mdoc
->last
->line
, mdoc
->last
->pos
,
1950 "Sh %s", secnames
[sec
]);
1952 if (sec
< mdoc
->lastnamed
)
1953 mandoc_vmsg(MANDOCERR_SEC_ORDER
, mdoc
->parse
,
1954 mdoc
->last
->line
, mdoc
->last
->pos
,
1955 "Sh %s", secnames
[sec
]);
1957 /* Mark the last named section. */
1959 mdoc
->lastnamed
= sec
;
1961 /* Check particular section/manual conventions. */
1963 if (mdoc
->meta
.msec
== NULL
)
1969 if (*mdoc
->meta
.msec
== '4')
1971 goodsec
= "2, 3, 4, 9";
1973 case SEC_RETURN_VALUES
:
1975 if (*mdoc
->meta
.msec
== '2')
1977 if (*mdoc
->meta
.msec
== '3')
1979 if (NULL
== goodsec
)
1980 goodsec
= "2, 3, 9";
1983 if (*mdoc
->meta
.msec
== '9')
1985 if (NULL
== goodsec
)
1987 mandoc_vmsg(MANDOCERR_SEC_MSEC
, mdoc
->parse
,
1988 mdoc
->last
->line
, mdoc
->last
->pos
,
1989 "Sh %s for %s only", secnames
[sec
], goodsec
);
1999 struct roff_node
*n
, *nch
;
2003 if (nch
->next
== NULL
) {
2004 mandoc_vmsg(MANDOCERR_XR_NOSEC
, mdoc
->parse
,
2005 n
->line
, n
->pos
, "Xr %s", nch
->string
);
2008 assert(nch
->next
== n
->last
);
2012 post_ignpar(POST_ARGS
)
2014 struct roff_node
*np
;
2016 switch (mdoc
->last
->type
) {
2026 if ((np
= mdoc
->last
->child
) != NULL
)
2027 if (np
->tok
== MDOC_Pp
|| np
->tok
== MDOC_Lp
) {
2028 mandoc_vmsg(MANDOCERR_PAR_SKIP
,
2029 mdoc
->parse
, np
->line
, np
->pos
,
2030 "%s after %s", mdoc_macronames
[np
->tok
],
2031 mdoc_macronames
[mdoc
->last
->tok
]);
2032 roff_node_delete(mdoc
, np
);
2035 if ((np
= mdoc
->last
->last
) != NULL
)
2036 if (np
->tok
== MDOC_Pp
|| np
->tok
== MDOC_Lp
) {
2037 mandoc_vmsg(MANDOCERR_PAR_SKIP
, mdoc
->parse
,
2038 np
->line
, np
->pos
, "%s at the end of %s",
2039 mdoc_macronames
[np
->tok
],
2040 mdoc_macronames
[mdoc
->last
->tok
]);
2041 roff_node_delete(mdoc
, np
);
2046 post_prevpar(POST_ARGS
)
2048 struct roff_node
*n
;
2051 if (NULL
== n
->prev
)
2053 if (n
->type
!= ROFFT_ELEM
&& n
->type
!= ROFFT_BLOCK
)
2057 * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
2058 * block: `Lp', `Pp', or non-compact `Bd' or `Bl'.
2061 if (n
->prev
->tok
!= MDOC_Pp
&&
2062 n
->prev
->tok
!= MDOC_Lp
&&
2063 n
->prev
->tok
!= MDOC_br
)
2065 if (n
->tok
== MDOC_Bl
&& n
->norm
->Bl
.comp
)
2067 if (n
->tok
== MDOC_Bd
&& n
->norm
->Bd
.comp
)
2069 if (n
->tok
== MDOC_It
&& n
->parent
->norm
->Bl
.comp
)
2072 mandoc_vmsg(MANDOCERR_PAR_SKIP
, mdoc
->parse
,
2073 n
->prev
->line
, n
->prev
->pos
,
2074 "%s before %s", mdoc_macronames
[n
->prev
->tok
],
2075 mdoc_macronames
[n
->tok
]);
2076 roff_node_delete(mdoc
, n
->prev
);
2082 struct roff_node
*np
;
2085 if (np
->tok
!= MDOC_br
&& np
->tok
!= MDOC_sp
)
2088 if (np
->tok
== MDOC_sp
) {
2089 if (np
->child
!= NULL
&& np
->child
->next
!= NULL
)
2090 mandoc_vmsg(MANDOCERR_ARG_EXCESS
, mdoc
->parse
,
2091 np
->child
->next
->line
, np
->child
->next
->pos
,
2092 "sp ... %s", np
->child
->next
->string
);
2093 } else if (np
->child
!= NULL
)
2094 mandoc_vmsg(MANDOCERR_ARG_SKIP
,
2095 mdoc
->parse
, np
->line
, np
->pos
, "%s %s",
2096 mdoc_macronames
[np
->tok
], np
->child
->string
);
2098 if ((np
= mdoc
->last
->prev
) == NULL
) {
2099 np
= mdoc
->last
->parent
;
2100 if (np
->tok
!= MDOC_Sh
&& np
->tok
!= MDOC_Ss
)
2102 } else if (np
->tok
!= MDOC_Pp
&& np
->tok
!= MDOC_Lp
&&
2103 (mdoc
->last
->tok
!= MDOC_br
||
2104 (np
->tok
!= MDOC_sp
&& np
->tok
!= MDOC_br
)))
2107 mandoc_vmsg(MANDOCERR_PAR_SKIP
, mdoc
->parse
,
2108 mdoc
->last
->line
, mdoc
->last
->pos
,
2109 "%s after %s", mdoc_macronames
[mdoc
->last
->tok
],
2110 mdoc_macronames
[np
->tok
]);
2111 roff_node_delete(mdoc
, mdoc
->last
);
2117 struct roff_node
*n
;
2121 n
->flags
|= NODE_NOPRT
;
2123 if (mdoc
->meta
.date
!= NULL
) {
2124 mandoc_msg(MANDOCERR_PROLOG_REP
, mdoc
->parse
,
2125 n
->line
, n
->pos
, "Dd");
2126 free(mdoc
->meta
.date
);
2127 } else if (mdoc
->flags
& MDOC_PBODY
)
2128 mandoc_msg(MANDOCERR_PROLOG_LATE
, mdoc
->parse
,
2129 n
->line
, n
->pos
, "Dd");
2130 else if (mdoc
->meta
.title
!= NULL
)
2131 mandoc_msg(MANDOCERR_PROLOG_ORDER
, mdoc
->parse
,
2132 n
->line
, n
->pos
, "Dd after Dt");
2133 else if (mdoc
->meta
.os
!= NULL
)
2134 mandoc_msg(MANDOCERR_PROLOG_ORDER
, mdoc
->parse
,
2135 n
->line
, n
->pos
, "Dd after Os");
2137 if (n
->child
== NULL
|| n
->child
->string
[0] == '\0') {
2138 mdoc
->meta
.date
= mdoc
->quick
? mandoc_strdup("") :
2139 mandoc_normdate(mdoc
->parse
, NULL
, n
->line
, n
->pos
);
2144 deroff(&datestr
, n
);
2146 mdoc
->meta
.date
= datestr
;
2148 mdoc
->meta
.date
= mandoc_normdate(mdoc
->parse
,
2149 datestr
, n
->line
, n
->pos
);
2157 struct roff_node
*nn
, *n
;
2162 n
->flags
|= NODE_NOPRT
;
2164 if (mdoc
->flags
& MDOC_PBODY
) {
2165 mandoc_msg(MANDOCERR_DT_LATE
, mdoc
->parse
,
2166 n
->line
, n
->pos
, "Dt");
2170 if (mdoc
->meta
.title
!= NULL
)
2171 mandoc_msg(MANDOCERR_PROLOG_REP
, mdoc
->parse
,
2172 n
->line
, n
->pos
, "Dt");
2173 else if (mdoc
->meta
.os
!= NULL
)
2174 mandoc_msg(MANDOCERR_PROLOG_ORDER
, mdoc
->parse
,
2175 n
->line
, n
->pos
, "Dt after Os");
2177 free(mdoc
->meta
.title
);
2178 free(mdoc
->meta
.msec
);
2179 free(mdoc
->meta
.vol
);
2180 free(mdoc
->meta
.arch
);
2182 mdoc
->meta
.title
= NULL
;
2183 mdoc
->meta
.msec
= NULL
;
2184 mdoc
->meta
.vol
= NULL
;
2185 mdoc
->meta
.arch
= NULL
;
2187 /* Mandatory first argument: title. */
2190 if (nn
== NULL
|| *nn
->string
== '\0') {
2191 mandoc_msg(MANDOCERR_DT_NOTITLE
,
2192 mdoc
->parse
, n
->line
, n
->pos
, "Dt");
2193 mdoc
->meta
.title
= mandoc_strdup("UNTITLED");
2195 mdoc
->meta
.title
= mandoc_strdup(nn
->string
);
2197 /* Check that all characters are uppercase. */
2199 for (p
= nn
->string
; *p
!= '\0'; p
++)
2200 if (islower((unsigned char)*p
)) {
2201 mandoc_vmsg(MANDOCERR_TITLE_CASE
,
2202 mdoc
->parse
, nn
->line
,
2203 nn
->pos
+ (p
- nn
->string
),
2204 "Dt %s", nn
->string
);
2209 /* Mandatory second argument: section. */
2215 mandoc_vmsg(MANDOCERR_MSEC_MISSING
,
2216 mdoc
->parse
, n
->line
, n
->pos
,
2217 "Dt %s", mdoc
->meta
.title
);
2218 mdoc
->meta
.vol
= mandoc_strdup("LOCAL");
2219 return; /* msec and arch remain NULL. */
2222 mdoc
->meta
.msec
= mandoc_strdup(nn
->string
);
2224 /* Infer volume title from section number. */
2226 cp
= mandoc_a2msec(nn
->string
);
2228 mandoc_vmsg(MANDOCERR_MSEC_BAD
, mdoc
->parse
,
2229 nn
->line
, nn
->pos
, "Dt ... %s", nn
->string
);
2230 mdoc
->meta
.vol
= mandoc_strdup(nn
->string
);
2232 mdoc
->meta
.vol
= mandoc_strdup(cp
);
2234 /* Optional third argument: architecture. */
2236 if ((nn
= nn
->next
) == NULL
)
2239 for (p
= nn
->string
; *p
!= '\0'; p
++)
2240 *p
= tolower((unsigned char)*p
);
2241 mdoc
->meta
.arch
= mandoc_strdup(nn
->string
);
2243 /* Ignore fourth and later arguments. */
2245 if ((nn
= nn
->next
) != NULL
)
2246 mandoc_vmsg(MANDOCERR_ARG_EXCESS
, mdoc
->parse
,
2247 nn
->line
, nn
->pos
, "Dt ... %s", nn
->string
);
2253 struct roff_node
*n
, *nch
;
2261 mdoc
->next
= ROFF_NEXT_SIBLING
;
2262 roff_elem_alloc(mdoc
, n
->line
, n
->pos
, MDOC_Ns
);
2263 mdoc
->last
->flags
|= NODE_NOSRC
;
2264 mdoc
->next
= ROFF_NEXT_SIBLING
;
2266 mdoc
->next
= ROFF_NEXT_CHILD
;
2267 roff_word_alloc(mdoc
, n
->line
, n
->pos
, "BSD");
2268 mdoc
->last
->flags
|= NODE_NOSRC
;
2275 roff_elem_alloc(mdoc
, n
->line
, n
->pos
, MDOC_Ns
);
2276 mdoc
->last
->flags
|= NODE_NOSRC
;
2277 mdoc
->next
= ROFF_NEXT_SIBLING
;
2278 roff_word_alloc(mdoc
, n
->line
, n
->pos
, "-");
2279 mdoc
->last
->flags
|= NODE_NOSRC
;
2280 roff_elem_alloc(mdoc
, n
->line
, n
->pos
, MDOC_Ns
);
2281 mdoc
->last
->flags
|= NODE_NOSRC
;
2285 * Make `Bx's second argument always start with an uppercase
2286 * letter. Groff checks if it's an "accepted" term, but we just
2287 * uppercase blindly.
2290 *nch
->string
= (char)toupper((unsigned char)*nch
->string
);
2297 struct utsname utsname
;
2298 static char *defbuf
;
2300 struct roff_node
*n
;
2303 n
->flags
|= NODE_NOPRT
;
2305 if (mdoc
->meta
.os
!= NULL
)
2306 mandoc_msg(MANDOCERR_PROLOG_REP
, mdoc
->parse
,
2307 n
->line
, n
->pos
, "Os");
2308 else if (mdoc
->flags
& MDOC_PBODY
)
2309 mandoc_msg(MANDOCERR_PROLOG_LATE
, mdoc
->parse
,
2310 n
->line
, n
->pos
, "Os");
2313 * Set the operating system by way of the `Os' macro.
2314 * The order of precedence is:
2315 * 1. the argument of the `Os' macro, unless empty
2316 * 2. the -Ios=foo command line argument, if provided
2317 * 3. -DOSNAME="\"foo\"", if provided during compilation
2318 * 4. "sysname release" from uname(3)
2321 free(mdoc
->meta
.os
);
2322 mdoc
->meta
.os
= NULL
;
2323 deroff(&mdoc
->meta
.os
, n
);
2328 mdoc
->meta
.os
= mandoc_strdup(mdoc
->defos
);
2333 mdoc
->meta
.os
= mandoc_strdup(OSNAME
);
2335 if (defbuf
== NULL
) {
2336 if (uname(&utsname
) == -1) {
2337 mandoc_msg(MANDOCERR_OS_UNAME
, mdoc
->parse
,
2338 n
->line
, n
->pos
, "Os");
2339 defbuf
= mandoc_strdup("UNKNOWN");
2341 mandoc_asprintf(&defbuf
, "%s %s",
2342 utsname
.sysname
, utsname
.release
);
2344 mdoc
->meta
.os
= mandoc_strdup(defbuf
);
2349 mdoc_a2sec(const char *p
)
2353 for (i
= 0; i
< (int)SEC__MAX
; i
++)
2354 if (secnames
[i
] && 0 == strcmp(p
, secnames
[i
]))
2355 return (enum roff_sec
)i
;
2361 macro2len(int macro
)