]>
git.cameronkatri.com Git - mandoc.git/blob - mdoc_validate.c
1 /* $Id: mdoc_validate.c,v 1.260 2014/11/28 17:24:41 schwarze Exp $ */
3 * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2010-2014 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 AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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>
36 #include "mandoc_aux.h"
38 #include "libmandoc.h"
40 /* FIXME: .Bl -diag can't have non-text children in HEAD. */
42 #define PRE_ARGS struct mdoc *mdoc, struct mdoc_node *n
43 #define POST_ARGS struct mdoc *mdoc
56 typedef void (*v_pre
)(PRE_ARGS
);
57 typedef void (*v_post
)(POST_ARGS
);
64 static void check_count(struct mdoc
*, enum mdoc_type
,
65 enum check_lvl
, enum check_ineq
, int);
66 static void check_text(struct mdoc
*, int, int, char *);
67 static void check_argv(struct mdoc
*,
68 struct mdoc_node
*, struct mdoc_argv
*);
69 static void check_args(struct mdoc
*, struct mdoc_node
*);
70 static int child_an(const struct mdoc_node
*);
71 static enum mdoc_sec
a2sec(const char *);
72 static size_t macro2len(enum mdoct
);
73 static void rewrite_macro2len(char **);
75 static void bwarn_ge1(POST_ARGS
);
76 static void ewarn_eq1(POST_ARGS
);
77 static void ewarn_ge1(POST_ARGS
);
78 static void hwarn_eq0(POST_ARGS
);
80 static void post_an(POST_ARGS
);
81 static void post_at(POST_ARGS
);
82 static void post_bf(POST_ARGS
);
83 static void post_bk(POST_ARGS
);
84 static void post_bl(POST_ARGS
);
85 static void post_bl_block(POST_ARGS
);
86 static void post_bl_block_tag(POST_ARGS
);
87 static void post_bl_head(POST_ARGS
);
88 static void post_bx(POST_ARGS
);
89 static void post_d1(POST_ARGS
);
90 static void post_defaults(POST_ARGS
);
91 static void post_dd(POST_ARGS
);
92 static void post_dt(POST_ARGS
);
93 static void post_en(POST_ARGS
);
94 static void post_es(POST_ARGS
);
95 static void post_eoln(POST_ARGS
);
96 static void post_ex(POST_ARGS
);
97 static void post_fa(POST_ARGS
);
98 static void post_fn(POST_ARGS
);
99 static void post_fname(POST_ARGS
);
100 static void post_fo(POST_ARGS
);
101 static void post_hyph(POST_ARGS
);
102 static void post_hyphtext(POST_ARGS
);
103 static void post_ignpar(POST_ARGS
);
104 static void post_it(POST_ARGS
);
105 static void post_lb(POST_ARGS
);
106 static void post_literal(POST_ARGS
);
107 static void post_nd(POST_ARGS
);
108 static void post_nm(POST_ARGS
);
109 static void post_ns(POST_ARGS
);
110 static void post_os(POST_ARGS
);
111 static void post_par(POST_ARGS
);
112 static void post_root(POST_ARGS
);
113 static void post_rs(POST_ARGS
);
114 static void post_sh(POST_ARGS
);
115 static void post_sh_head(POST_ARGS
);
116 static void post_sh_name(POST_ARGS
);
117 static void post_sh_see_also(POST_ARGS
);
118 static void post_sh_authors(POST_ARGS
);
119 static void post_sm(POST_ARGS
);
120 static void post_st(POST_ARGS
);
121 static void post_vt(POST_ARGS
);
123 static void pre_an(PRE_ARGS
);
124 static void pre_bd(PRE_ARGS
);
125 static void pre_bl(PRE_ARGS
);
126 static void pre_dd(PRE_ARGS
);
127 static void pre_display(PRE_ARGS
);
128 static void pre_dt(PRE_ARGS
);
129 static void pre_literal(PRE_ARGS
);
130 static void pre_obsolete(PRE_ARGS
);
131 static void pre_os(PRE_ARGS
);
132 static void pre_par(PRE_ARGS
);
133 static void pre_std(PRE_ARGS
);
135 static const struct valids mdoc_valids
[MDOC_MAX
] = {
136 { NULL
, NULL
}, /* Ap */
137 { pre_dd
, post_dd
}, /* Dd */
138 { pre_dt
, post_dt
}, /* Dt */
139 { pre_os
, post_os
}, /* Os */
140 { NULL
, post_sh
}, /* Sh */
141 { NULL
, post_ignpar
}, /* Ss */
142 { pre_par
, post_par
}, /* Pp */
143 { pre_display
, post_d1
}, /* D1 */
144 { pre_literal
, post_literal
}, /* Dl */
145 { pre_bd
, post_literal
}, /* Bd */
146 { NULL
, NULL
}, /* Ed */
147 { pre_bl
, post_bl
}, /* Bl */
148 { NULL
, NULL
}, /* El */
149 { pre_par
, post_it
}, /* It */
150 { NULL
, NULL
}, /* Ad */
151 { pre_an
, post_an
}, /* An */
152 { NULL
, post_defaults
}, /* Ar */
153 { NULL
, NULL
}, /* Cd */
154 { NULL
, NULL
}, /* Cm */
155 { NULL
, NULL
}, /* Dv */
156 { NULL
, NULL
}, /* Er */
157 { NULL
, NULL
}, /* Ev */
158 { pre_std
, post_ex
}, /* Ex */
159 { NULL
, post_fa
}, /* Fa */
160 { NULL
, ewarn_ge1
}, /* Fd */
161 { NULL
, NULL
}, /* Fl */
162 { NULL
, post_fn
}, /* Fn */
163 { NULL
, NULL
}, /* Ft */
164 { NULL
, NULL
}, /* Ic */
165 { NULL
, ewarn_eq1
}, /* In */
166 { NULL
, post_defaults
}, /* Li */
167 { NULL
, post_nd
}, /* Nd */
168 { NULL
, post_nm
}, /* Nm */
169 { NULL
, NULL
}, /* Op */
170 { pre_obsolete
, NULL
}, /* Ot */
171 { NULL
, post_defaults
}, /* Pa */
172 { pre_std
, NULL
}, /* Rv */
173 { NULL
, post_st
}, /* St */
174 { NULL
, NULL
}, /* Va */
175 { NULL
, post_vt
}, /* Vt */
176 { NULL
, ewarn_ge1
}, /* Xr */
177 { NULL
, ewarn_ge1
}, /* %A */
178 { NULL
, post_hyphtext
}, /* %B */ /* FIXME: can be used outside Rs/Re. */
179 { NULL
, ewarn_ge1
}, /* %D */
180 { NULL
, ewarn_ge1
}, /* %I */
181 { NULL
, ewarn_ge1
}, /* %J */
182 { NULL
, post_hyphtext
}, /* %N */
183 { NULL
, post_hyphtext
}, /* %O */
184 { NULL
, ewarn_ge1
}, /* %P */
185 { NULL
, post_hyphtext
}, /* %R */
186 { NULL
, post_hyphtext
}, /* %T */ /* FIXME: can be used outside Rs/Re. */
187 { NULL
, ewarn_ge1
}, /* %V */
188 { NULL
, NULL
}, /* Ac */
189 { NULL
, NULL
}, /* Ao */
190 { NULL
, NULL
}, /* Aq */
191 { NULL
, post_at
}, /* At */
192 { NULL
, NULL
}, /* Bc */
193 { NULL
, post_bf
}, /* Bf */
194 { NULL
, NULL
}, /* Bo */
195 { NULL
, NULL
}, /* Bq */
196 { NULL
, NULL
}, /* Bsx */
197 { NULL
, post_bx
}, /* Bx */
198 { pre_obsolete
, NULL
}, /* Db */
199 { NULL
, NULL
}, /* Dc */
200 { NULL
, NULL
}, /* Do */
201 { NULL
, NULL
}, /* Dq */
202 { NULL
, NULL
}, /* Ec */
203 { NULL
, NULL
}, /* Ef */
204 { NULL
, NULL
}, /* Em */
205 { NULL
, NULL
}, /* Eo */
206 { NULL
, NULL
}, /* Fx */
207 { NULL
, NULL
}, /* Ms */
208 { NULL
, NULL
}, /* No */
209 { NULL
, post_ns
}, /* Ns */
210 { NULL
, NULL
}, /* Nx */
211 { NULL
, NULL
}, /* Ox */
212 { NULL
, NULL
}, /* Pc */
213 { NULL
, ewarn_eq1
}, /* Pf */
214 { NULL
, NULL
}, /* Po */
215 { NULL
, NULL
}, /* Pq */
216 { NULL
, NULL
}, /* Qc */
217 { NULL
, NULL
}, /* Ql */
218 { NULL
, NULL
}, /* Qo */
219 { NULL
, NULL
}, /* Qq */
220 { NULL
, NULL
}, /* Re */
221 { NULL
, post_rs
}, /* Rs */
222 { NULL
, NULL
}, /* Sc */
223 { NULL
, NULL
}, /* So */
224 { NULL
, NULL
}, /* Sq */
225 { NULL
, post_sm
}, /* Sm */
226 { NULL
, post_hyph
}, /* Sx */
227 { NULL
, NULL
}, /* Sy */
228 { NULL
, NULL
}, /* Tn */
229 { NULL
, NULL
}, /* Ux */
230 { NULL
, NULL
}, /* Xc */
231 { NULL
, NULL
}, /* Xo */
232 { NULL
, post_fo
}, /* Fo */
233 { NULL
, NULL
}, /* Fc */
234 { NULL
, NULL
}, /* Oo */
235 { NULL
, NULL
}, /* Oc */
236 { NULL
, post_bk
}, /* Bk */
237 { NULL
, NULL
}, /* Ek */
238 { NULL
, post_eoln
}, /* Bt */
239 { NULL
, NULL
}, /* Hf */
240 { pre_obsolete
, NULL
}, /* Fr */
241 { NULL
, post_eoln
}, /* Ud */
242 { NULL
, post_lb
}, /* Lb */
243 { pre_par
, post_par
}, /* Lp */
244 { NULL
, NULL
}, /* Lk */
245 { NULL
, post_defaults
}, /* Mt */
246 { NULL
, NULL
}, /* Brq */
247 { NULL
, NULL
}, /* Bro */
248 { NULL
, NULL
}, /* Brc */
249 { NULL
, ewarn_ge1
}, /* %C */
250 { pre_obsolete
, post_es
}, /* Es */
251 { pre_obsolete
, post_en
}, /* En */
252 { NULL
, NULL
}, /* Dx */
253 { NULL
, ewarn_ge1
}, /* %Q */
254 { NULL
, post_par
}, /* br */
255 { NULL
, post_par
}, /* sp */
256 { NULL
, ewarn_eq1
}, /* %U */
257 { NULL
, NULL
}, /* Ta */
258 { NULL
, NULL
}, /* ll */
261 #define RSORD_MAX 14 /* Number of `Rs' blocks. */
263 static const enum mdoct rsord
[RSORD_MAX
] = {
280 static const char * const secnames
[SEC__MAX
] = {
287 "IMPLEMENTATION NOTES",
302 "SECURITY CONSIDERATIONS",
308 mdoc_valid_pre(struct mdoc
*mdoc
, struct mdoc_node
*n
)
314 check_text(mdoc
, n
->line
, n
->pos
, n
->string
);
327 p
= mdoc_valids
[n
->tok
].pre
;
333 mdoc_valid_post(struct mdoc
*mdoc
)
339 if (n
->flags
& MDOC_VALID
)
341 n
->flags
|= MDOC_VALID
;
356 * Closing delimiters are not special at the
357 * beginning of a block, opening delimiters
358 * are not special at the end.
361 if (n
->child
!= NULL
)
362 n
->child
->flags
&= ~MDOC_DELIMC
;
364 n
->last
->flags
&= ~MDOC_DELIMO
;
366 /* Call the macro's postprocessor. */
368 p
= mdoc_valids
[n
->tok
].post
;
376 check_count(struct mdoc
*mdoc
, enum mdoc_type type
,
377 enum check_lvl lvl
, enum check_ineq ineq
, int val
)
382 if (mdoc
->last
->type
!= type
)
388 if (mdoc
->last
->nchild
< val
)
393 if (mdoc
->last
->nchild
> val
)
398 if (val
== mdoc
->last
->nchild
)
406 t
= lvl
== CHECK_WARN
? MANDOCERR_ARGCWARN
: MANDOCERR_ARGCOUNT
;
407 mandoc_vmsg(t
, mdoc
->parse
, mdoc
->last
->line
,
408 mdoc
->last
->pos
, "want %s%d children (have %d)",
409 p
, val
, mdoc
->last
->nchild
);
415 check_count(mdoc
, MDOC_BODY
, CHECK_WARN
, CHECK_GT
, 0);
421 check_count(mdoc
, MDOC_ELEM
, CHECK_WARN
, CHECK_EQ
, 1);
427 check_count(mdoc
, MDOC_ELEM
, CHECK_WARN
, CHECK_GT
, 0);
433 check_count(mdoc
, MDOC_HEAD
, CHECK_WARN
, CHECK_EQ
, 0);
437 check_args(struct mdoc
*mdoc
, struct mdoc_node
*n
)
444 assert(n
->args
->argc
);
445 for (i
= 0; i
< (int)n
->args
->argc
; i
++)
446 check_argv(mdoc
, n
, &n
->args
->argv
[i
]);
450 check_argv(struct mdoc
*mdoc
, struct mdoc_node
*n
, struct mdoc_argv
*v
)
454 for (i
= 0; i
< (int)v
->sz
; i
++)
455 check_text(mdoc
, v
->line
, v
->pos
, v
->value
[i
]);
459 check_text(struct mdoc
*mdoc
, int ln
, int pos
, char *p
)
463 if (MDOC_LITERAL
& mdoc
->flags
)
466 for (cp
= p
; NULL
!= (p
= strchr(p
, '\t')); p
++)
467 mandoc_msg(MANDOCERR_FI_TAB
, mdoc
->parse
,
468 ln
, pos
+ (int)(p
- cp
), NULL
);
472 pre_display(PRE_ARGS
)
474 struct mdoc_node
*node
;
476 if (MDOC_BLOCK
!= n
->type
)
479 for (node
= mdoc
->last
->parent
; node
; node
= node
->parent
)
480 if (MDOC_BLOCK
== node
->type
)
481 if (MDOC_Bd
== node
->tok
)
485 mandoc_vmsg(MANDOCERR_BD_NEST
,
486 mdoc
->parse
, n
->line
, n
->pos
,
487 "%s in Bd", mdoc_macronames
[n
->tok
]);
493 struct mdoc_node
*np
;
494 struct mdoc_argv
*argv
, *wa
;
496 enum mdocargt mdoclt
;
499 if (MDOC_BLOCK
!= n
->type
) {
500 if (ENDBODY_NOT
!= n
->end
) {
502 np
= n
->pending
->parent
;
507 assert(MDOC_BLOCK
== np
->type
);
508 assert(MDOC_Bl
== np
->tok
);
513 * First figure out which kind of list to use: bind ourselves to
514 * the first mentioned list type and warn about any remaining
515 * ones. If we find no list type, we default to LIST_item.
518 wa
= (n
->args
== NULL
) ? NULL
: n
->args
->argv
;
519 mdoclt
= MDOC_ARG_MAX
;
520 for (i
= 0; n
->args
&& i
< (int)n
->args
->argc
; i
++) {
521 argv
= n
->args
->argv
+ i
;
524 /* Set list types. */
558 /* Set list arguments. */
560 if (n
->norm
->Bl
.comp
)
561 mandoc_msg(MANDOCERR_ARG_REP
,
562 mdoc
->parse
, argv
->line
,
563 argv
->pos
, "Bl -compact");
564 n
->norm
->Bl
.comp
= 1;
569 mandoc_msg(MANDOCERR_ARG_EMPTY
,
570 mdoc
->parse
, argv
->line
,
571 argv
->pos
, "Bl -width");
572 n
->norm
->Bl
.width
= "0n";
575 if (NULL
!= n
->norm
->Bl
.width
)
576 mandoc_vmsg(MANDOCERR_ARG_REP
,
577 mdoc
->parse
, argv
->line
,
578 argv
->pos
, "Bl -width %s",
580 rewrite_macro2len(argv
->value
);
581 n
->norm
->Bl
.width
= argv
->value
[0];
585 mandoc_msg(MANDOCERR_ARG_EMPTY
,
586 mdoc
->parse
, argv
->line
,
587 argv
->pos
, "Bl -offset");
590 if (NULL
!= n
->norm
->Bl
.offs
)
591 mandoc_vmsg(MANDOCERR_ARG_REP
,
592 mdoc
->parse
, argv
->line
,
593 argv
->pos
, "Bl -offset %s",
595 rewrite_macro2len(argv
->value
);
596 n
->norm
->Bl
.offs
= argv
->value
[0];
601 if (LIST__NONE
== lt
)
605 /* Check: multiple list types. */
607 if (LIST__NONE
!= n
->norm
->Bl
.type
) {
608 mandoc_vmsg(MANDOCERR_BL_REP
,
609 mdoc
->parse
, n
->line
, n
->pos
,
610 "Bl -%s", mdoc_argnames
[argv
->arg
]);
614 /* The list type should come first. */
616 if (n
->norm
->Bl
.width
||
619 mandoc_vmsg(MANDOCERR_BL_LATETYPE
,
620 mdoc
->parse
, n
->line
, n
->pos
, "Bl -%s",
621 mdoc_argnames
[n
->args
->argv
[0].arg
]);
623 n
->norm
->Bl
.type
= lt
;
624 if (LIST_column
== lt
) {
625 n
->norm
->Bl
.ncols
= argv
->sz
;
626 n
->norm
->Bl
.cols
= (void *)argv
->value
;
630 /* Allow lists to default to LIST_item. */
632 if (LIST__NONE
== n
->norm
->Bl
.type
) {
633 mandoc_msg(MANDOCERR_BL_NOTYPE
, mdoc
->parse
,
634 n
->line
, n
->pos
, "Bl");
635 n
->norm
->Bl
.type
= LIST_item
;
639 * Validate the width field. Some list types don't need width
640 * types and should be warned about them. Others should have it
641 * and must also be warned. Yet others have a default and need
645 switch (n
->norm
->Bl
.type
) {
647 if (NULL
== n
->norm
->Bl
.width
)
648 mandoc_msg(MANDOCERR_BL_NOWIDTH
, mdoc
->parse
,
649 n
->line
, n
->pos
, "Bl -tag");
660 if (n
->norm
->Bl
.width
)
661 mandoc_vmsg(MANDOCERR_BL_SKIPW
, mdoc
->parse
,
662 wa
->line
, wa
->pos
, "Bl -%s",
663 mdoc_argnames
[mdoclt
]);
670 if (NULL
== n
->norm
->Bl
.width
)
671 n
->norm
->Bl
.width
= "2n";
674 if (NULL
== n
->norm
->Bl
.width
)
675 n
->norm
->Bl
.width
= "3n";
686 struct mdoc_node
*np
;
687 struct mdoc_argv
*argv
;
691 pre_literal(mdoc
, n
);
693 if (MDOC_BLOCK
!= n
->type
) {
694 if (ENDBODY_NOT
!= n
->end
) {
696 np
= n
->pending
->parent
;
701 assert(MDOC_BLOCK
== np
->type
);
702 assert(MDOC_Bd
== np
->tok
);
706 for (i
= 0; n
->args
&& i
< (int)n
->args
->argc
; i
++) {
707 argv
= n
->args
->argv
+ i
;
727 mandoc_msg(MANDOCERR_BD_FILE
, mdoc
->parse
,
728 n
->line
, n
->pos
, NULL
);
732 mandoc_msg(MANDOCERR_ARG_EMPTY
,
733 mdoc
->parse
, argv
->line
,
734 argv
->pos
, "Bd -offset");
737 if (NULL
!= n
->norm
->Bd
.offs
)
738 mandoc_vmsg(MANDOCERR_ARG_REP
,
739 mdoc
->parse
, argv
->line
,
740 argv
->pos
, "Bd -offset %s",
742 rewrite_macro2len(argv
->value
);
743 n
->norm
->Bd
.offs
= argv
->value
[0];
746 if (n
->norm
->Bd
.comp
)
747 mandoc_msg(MANDOCERR_ARG_REP
,
748 mdoc
->parse
, argv
->line
,
749 argv
->pos
, "Bd -compact");
750 n
->norm
->Bd
.comp
= 1;
756 if (DISP__NONE
== dt
)
759 if (DISP__NONE
== n
->norm
->Bd
.type
)
760 n
->norm
->Bd
.type
= dt
;
762 mandoc_vmsg(MANDOCERR_BD_REP
,
763 mdoc
->parse
, n
->line
, n
->pos
,
764 "Bd -%s", mdoc_argnames
[argv
->arg
]);
767 if (DISP__NONE
== n
->norm
->Bd
.type
) {
768 mandoc_msg(MANDOCERR_BD_NOTYPE
, mdoc
->parse
,
769 n
->line
, n
->pos
, "Bd");
770 n
->norm
->Bd
.type
= DISP_ragged
;
778 struct mdoc_argv
*argv
;
784 for (i
= 1; i
< n
->args
->argc
; i
++) {
785 argv
= n
->args
->argv
+ i
;
786 mandoc_vmsg(MANDOCERR_AN_REP
,
787 mdoc
->parse
, argv
->line
, argv
->pos
,
788 "An -%s", mdoc_argnames
[argv
->arg
]);
791 argv
= n
->args
->argv
;
792 if (argv
->arg
== MDOC_Split
)
793 n
->norm
->An
.auth
= AUTH_split
;
794 else if (argv
->arg
== MDOC_Nosplit
)
795 n
->norm
->An
.auth
= AUTH_nosplit
;
804 if (n
->args
&& 1 == n
->args
->argc
)
805 if (MDOC_Std
== n
->args
->argv
[0].arg
)
808 mandoc_msg(MANDOCERR_ARG_STD
, mdoc
->parse
,
809 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
813 pre_obsolete(PRE_ARGS
)
816 if (MDOC_ELEM
== n
->type
|| MDOC_BLOCK
== n
->type
)
817 mandoc_msg(MANDOCERR_MACRO_OBS
, mdoc
->parse
,
818 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
825 if (mdoc
->meta
.title
!= NULL
)
826 mandoc_msg(MANDOCERR_PROLOG_REP
, mdoc
->parse
,
827 n
->line
, n
->pos
, "Dt");
828 else if (mdoc
->meta
.os
!= NULL
)
829 mandoc_msg(MANDOCERR_PROLOG_ORDER
, mdoc
->parse
,
830 n
->line
, n
->pos
, "Dt after Os");
837 if (mdoc
->meta
.os
!= NULL
)
838 mandoc_msg(MANDOCERR_PROLOG_REP
, mdoc
->parse
,
839 n
->line
, n
->pos
, "Os");
840 else if (mdoc
->flags
& MDOC_PBODY
)
841 mandoc_msg(MANDOCERR_PROLOG_LATE
, mdoc
->parse
,
842 n
->line
, n
->pos
, "Os");
849 if (mdoc
->meta
.date
!= NULL
)
850 mandoc_msg(MANDOCERR_PROLOG_REP
, mdoc
->parse
,
851 n
->line
, n
->pos
, "Dd");
852 else if (mdoc
->flags
& MDOC_PBODY
)
853 mandoc_msg(MANDOCERR_PROLOG_LATE
, mdoc
->parse
,
854 n
->line
, n
->pos
, "Dd");
855 else if (mdoc
->meta
.title
!= NULL
)
856 mandoc_msg(MANDOCERR_PROLOG_ORDER
, mdoc
->parse
,
857 n
->line
, n
->pos
, "Dd after Dt");
858 else if (mdoc
->meta
.os
!= NULL
)
859 mandoc_msg(MANDOCERR_PROLOG_ORDER
, mdoc
->parse
,
860 n
->line
, n
->pos
, "Dd after Os");
866 struct mdoc_node
*np
, *nch
;
870 * Unlike other data pointers, these are "housed" by the HEAD
871 * element, which contains the goods.
874 if (MDOC_HEAD
!= mdoc
->last
->type
) {
875 if (ENDBODY_NOT
!= mdoc
->last
->end
) {
876 assert(mdoc
->last
->pending
);
877 np
= mdoc
->last
->pending
->parent
->head
;
878 } else if (MDOC_BLOCK
!= mdoc
->last
->type
) {
879 np
= mdoc
->last
->parent
->head
;
881 np
= mdoc
->last
->head
;
884 assert(MDOC_HEAD
== np
->type
);
885 assert(MDOC_Bf
== np
->tok
);
890 assert(MDOC_BLOCK
== np
->parent
->type
);
891 assert(MDOC_Bf
== np
->parent
->tok
);
893 /* Check the number of arguments. */
896 if (NULL
== np
->parent
->args
) {
898 mandoc_msg(MANDOCERR_BF_NOFONT
, mdoc
->parse
,
899 np
->line
, np
->pos
, "Bf");
905 mandoc_vmsg(MANDOCERR_ARG_EXCESS
, mdoc
->parse
,
906 nch
->line
, nch
->pos
, "Bf ... %s", nch
->string
);
908 /* Extract argument into data. */
910 if (np
->parent
->args
) {
911 arg
= np
->parent
->args
->argv
[0].arg
;
912 if (MDOC_Emphasis
== arg
)
913 np
->norm
->Bf
.font
= FONT_Em
;
914 else if (MDOC_Literal
== arg
)
915 np
->norm
->Bf
.font
= FONT_Li
;
916 else if (MDOC_Symbolic
== arg
)
917 np
->norm
->Bf
.font
= FONT_Sy
;
923 /* Extract parameter into data. */
925 if (0 == strcmp(np
->child
->string
, "Em"))
926 np
->norm
->Bf
.font
= FONT_Em
;
927 else if (0 == strcmp(np
->child
->string
, "Li"))
928 np
->norm
->Bf
.font
= FONT_Li
;
929 else if (0 == strcmp(np
->child
->string
, "Sy"))
930 np
->norm
->Bf
.font
= FONT_Sy
;
932 mandoc_vmsg(MANDOCERR_BF_BADFONT
, mdoc
->parse
,
933 np
->child
->line
, np
->child
->pos
,
934 "Bf %s", np
->child
->string
);
941 const char *stdlibname
;
944 check_count(mdoc
, MDOC_ELEM
, CHECK_WARN
, CHECK_EQ
, 1);
945 n
= mdoc
->last
->child
;
946 assert(MDOC_TEXT
== n
->type
);
948 if (NULL
== (stdlibname
= mdoc_a2lib(n
->string
)))
949 mandoc_asprintf(&libname
,
950 "library \\(lq%s\\(rq", n
->string
);
952 libname
= mandoc_strdup(stdlibname
);
961 const struct mdoc_node
*n
;
965 mandoc_vmsg(MANDOCERR_ARG_SKIP
,
966 mdoc
->parse
, n
->line
, n
->pos
,
967 "%s %s", mdoc_macronames
[n
->tok
],
972 post_fname(POST_ARGS
)
974 const struct mdoc_node
*n
;
978 n
= mdoc
->last
->child
;
979 pos
= strcspn(n
->string
, "()");
980 cp
= n
->string
+ pos
;
981 if ( ! (cp
[0] == '\0' || (cp
[0] == '(' && cp
[1] == '*')))
982 mandoc_msg(MANDOCERR_FN_PAREN
, mdoc
->parse
,
983 n
->line
, n
->pos
+ pos
, n
->string
);
998 check_count(mdoc
, MDOC_HEAD
, CHECK_WARN
, CHECK_EQ
, 1);
1000 if (mdoc
->last
->type
== MDOC_HEAD
&& mdoc
->last
->nchild
)
1007 const struct mdoc_node
*n
;
1010 for (n
= mdoc
->last
->child
; n
!= NULL
; n
= n
->next
) {
1011 for (cp
= n
->string
; *cp
!= '\0'; cp
++) {
1012 /* Ignore callbacks and alterations. */
1013 if (*cp
== '(' || *cp
== '{')
1017 mandoc_msg(MANDOCERR_FA_COMMA
, mdoc
->parse
,
1018 n
->line
, n
->pos
+ (cp
- n
->string
),
1028 const struct mdoc_node
*n
;
1031 * The Vt macro comes in both ELEM and BLOCK form, both of which
1032 * have different syntaxes (yet more context-sensitive
1033 * behaviour). ELEM types must have a child, which is already
1034 * guaranteed by the in_line parsing routine; BLOCK types,
1035 * specifically the BODY, should only have TEXT children.
1038 if (MDOC_BODY
!= mdoc
->last
->type
)
1041 for (n
= mdoc
->last
->child
; n
; n
= n
->next
)
1042 if (MDOC_TEXT
!= n
->type
)
1043 mandoc_msg(MANDOCERR_VT_CHILD
, mdoc
->parse
,
1044 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
1051 if (NULL
!= mdoc
->meta
.name
)
1054 mdoc_deroff(&mdoc
->meta
.name
, mdoc
->last
);
1056 if (NULL
== mdoc
->meta
.name
)
1057 mandoc_msg(MANDOCERR_NM_NONAME
, mdoc
->parse
,
1058 mdoc
->last
->line
, mdoc
->last
->pos
, "Nm");
1065 check_count(mdoc
, MDOC_BODY
, CHECK_ERROR
, CHECK_GT
, 0);
1078 post_literal(POST_ARGS
)
1081 if (mdoc
->last
->tok
== MDOC_Bd
)
1086 * The `Dl' (note "el" not "one") and `Bd' macros unset the
1087 * MDOC_LITERAL flag as they leave. Note that `Bd' only sets
1088 * this in literal mode, but it doesn't hurt to just switch it
1089 * off in general since displays can't be nested.
1092 if (MDOC_BODY
== mdoc
->last
->type
)
1093 mdoc
->flags
&= ~MDOC_LITERAL
;
1097 post_defaults(POST_ARGS
)
1099 struct mdoc_node
*nn
;
1102 * The `Ar' defaults to "file ..." if no value is provided as an
1103 * argument; the `Mt' and `Pa' macros use "~"; the `Li' just
1104 * gets an empty string.
1107 if (mdoc
->last
->child
)
1111 mdoc
->next
= MDOC_NEXT_CHILD
;
1115 mdoc_word_alloc(mdoc
, nn
->line
, nn
->pos
, "file");
1116 mdoc_word_alloc(mdoc
, nn
->line
, nn
->pos
, "...");
1121 mdoc_word_alloc(mdoc
, nn
->line
, nn
->pos
, "~");
1133 struct mdoc_node
*n
;
1134 const char *std_att
;
1138 if (n
->child
== NULL
) {
1139 mdoc
->next
= MDOC_NEXT_CHILD
;
1140 mdoc_word_alloc(mdoc
, n
->line
, n
->pos
, "AT&T UNIX");
1146 * If we have a child, look it up in the standard keys. If a
1147 * key exist, use that instead of the child; if it doesn't,
1148 * prefix "AT&T UNIX " to the existing data.
1152 assert(MDOC_TEXT
== n
->type
);
1153 if (NULL
== (std_att
= mdoc_a2att(n
->string
))) {
1154 mandoc_vmsg(MANDOCERR_AT_BAD
, mdoc
->parse
,
1155 n
->line
, n
->pos
, "At %s", n
->string
);
1156 mandoc_asprintf(&att
, "AT&T UNIX %s", n
->string
);
1158 att
= mandoc_strdup(std_att
);
1167 struct mdoc_node
*np
;
1170 if (AUTH__NONE
== np
->norm
->An
.auth
) {
1172 check_count(mdoc
, MDOC_ELEM
, CHECK_WARN
, CHECK_GT
, 0);
1173 } else if (np
->child
)
1174 check_count(mdoc
, MDOC_ELEM
, CHECK_WARN
, CHECK_EQ
, 0);
1181 if (MDOC_BLOCK
== mdoc
->last
->type
)
1182 mdoc
->last
->norm
->Es
= mdoc
->last_es
;
1189 mdoc
->last_es
= mdoc
->last
;
1197 struct mdoc_node
*nbl
, *nit
, *nch
;
1200 if (MDOC_BLOCK
!= nit
->type
)
1203 nbl
= nit
->parent
->parent
;
1204 lt
= nbl
->norm
->Bl
.type
;
1216 if (NULL
== nit
->head
->child
)
1217 mandoc_vmsg(MANDOCERR_IT_NOHEAD
,
1218 mdoc
->parse
, nit
->line
, nit
->pos
,
1220 mdoc_argnames
[nbl
->args
->argv
[0].arg
]);
1229 if (NULL
== nit
->body
->child
)
1230 mandoc_vmsg(MANDOCERR_IT_NOBODY
,
1231 mdoc
->parse
, nit
->line
, nit
->pos
,
1233 mdoc_argnames
[nbl
->args
->argv
[0].arg
]);
1236 if (NULL
!= nit
->head
->child
)
1237 mandoc_vmsg(MANDOCERR_ARG_SKIP
,
1238 mdoc
->parse
, nit
->line
, nit
->pos
,
1239 "It %s", nit
->head
->child
->string
);
1242 cols
= (int)nbl
->norm
->Bl
.ncols
;
1244 assert(NULL
== nit
->head
->child
);
1246 for (i
= 0, nch
= nit
->child
; nch
; nch
= nch
->next
)
1247 if (MDOC_BODY
== nch
->type
)
1250 if (i
< cols
|| i
> cols
+ 1)
1251 mandoc_vmsg(MANDOCERR_ARGCOUNT
,
1252 mdoc
->parse
, nit
->line
, nit
->pos
,
1253 "columns == %d (have %d)", cols
, i
);
1261 post_bl_block(POST_ARGS
)
1263 struct mdoc_node
*n
, *ni
, *nc
;
1266 * These are fairly complicated, so we've broken them into two
1267 * functions. post_bl_block_tag() is called when a -tag is
1268 * specified, but no -width (it must be guessed). The second
1269 * when a -width is specified (macro indicators must be
1270 * rewritten into real lengths).
1275 if (LIST_tag
== n
->norm
->Bl
.type
&&
1276 NULL
== n
->norm
->Bl
.width
) {
1277 post_bl_block_tag(mdoc
);
1278 assert(n
->norm
->Bl
.width
);
1281 for (ni
= n
->body
->child
; ni
; ni
= ni
->next
) {
1282 if (NULL
== ni
->body
)
1284 nc
= ni
->body
->last
;
1285 while (NULL
!= nc
) {
1297 if (NULL
== ni
->next
) {
1298 mandoc_msg(MANDOCERR_PAR_MOVE
,
1299 mdoc
->parse
, nc
->line
, nc
->pos
,
1300 mdoc_macronames
[nc
->tok
]);
1301 mdoc_node_relink(mdoc
, nc
);
1302 } else if (0 == n
->norm
->Bl
.comp
&&
1303 LIST_column
!= n
->norm
->Bl
.type
) {
1304 mandoc_vmsg(MANDOCERR_PAR_SKIP
,
1305 mdoc
->parse
, nc
->line
, nc
->pos
,
1307 mdoc_macronames
[nc
->tok
]);
1308 mdoc_node_delete(mdoc
, nc
);
1311 nc
= ni
->body
->last
;
1317 * If the argument of -offset or -width is a macro,
1318 * replace it with the associated default width.
1321 rewrite_macro2len(char **arg
)
1328 else if ( ! strcmp(*arg
, "Ds"))
1330 else if ((tok
= mdoc_hash_find(*arg
)) == MDOC_MAX
)
1333 width
= macro2len(tok
);
1336 mandoc_asprintf(arg
, "%zun", width
);
1340 post_bl_block_tag(POST_ARGS
)
1342 struct mdoc_node
*n
, *nn
;
1348 * Calculate the -width for a `Bl -tag' list if it hasn't been
1349 * provided. Uses the first head macro. NOTE AGAIN: this is
1350 * ONLY if the -width argument has NOT been provided. See
1351 * rewrite_macro2len() for converting the -width string.
1357 for (nn
= n
->body
->child
; nn
; nn
= nn
->next
) {
1358 if (MDOC_It
!= nn
->tok
)
1361 assert(MDOC_BLOCK
== nn
->type
);
1362 nn
= nn
->head
->child
;
1367 if (MDOC_TEXT
== nn
->type
) {
1368 sz
= strlen(nn
->string
) + 1;
1372 if (0 != (ssz
= macro2len(nn
->tok
)))
1378 /* Defaults to ten ens. */
1380 (void)snprintf(buf
, sizeof(buf
), "%un", (unsigned int)sz
);
1383 * We have to dynamically add this to the macro's argument list.
1384 * We're guaranteed that a MDOC_Width doesn't already exist.
1388 i
= (int)(n
->args
->argc
)++;
1390 n
->args
->argv
= mandoc_reallocarray(n
->args
->argv
,
1391 n
->args
->argc
, sizeof(struct mdoc_argv
));
1393 n
->args
->argv
[i
].arg
= MDOC_Width
;
1394 n
->args
->argv
[i
].line
= n
->line
;
1395 n
->args
->argv
[i
].pos
= n
->pos
;
1396 n
->args
->argv
[i
].sz
= 1;
1397 n
->args
->argv
[i
].value
= mandoc_malloc(sizeof(char *));
1398 n
->args
->argv
[i
].value
[0] = mandoc_strdup(buf
);
1400 /* Set our width! */
1401 n
->norm
->Bl
.width
= n
->args
->argv
[i
].value
[0];
1405 post_bl_head(POST_ARGS
)
1407 struct mdoc_node
*np
, *nn
, *nnp
;
1408 struct mdoc_argv
*argv
;
1411 if (LIST_column
!= mdoc
->last
->norm
->Bl
.type
) {
1412 /* FIXME: this should be ERROR class... */
1418 * Append old-style lists, where the column width specifiers
1419 * trail as macro parameters, to the new-style ("normal-form")
1420 * lists where they're argument values following -column.
1423 if (mdoc
->last
->child
== NULL
)
1426 np
= mdoc
->last
->parent
;
1429 for (j
= 0; j
< (int)np
->args
->argc
; j
++)
1430 if (MDOC_Column
== np
->args
->argv
[j
].arg
)
1433 assert(j
< (int)np
->args
->argc
);
1436 * Accommodate for new-style groff column syntax. Shuffle the
1437 * child nodes, all of which must be TEXT, as arguments for the
1438 * column field. Then, delete the head children.
1441 argv
= np
->args
->argv
+ j
;
1443 argv
->sz
+= mdoc
->last
->nchild
;
1444 argv
->value
= mandoc_reallocarray(argv
->value
,
1445 argv
->sz
, sizeof(char *));
1447 mdoc
->last
->norm
->Bl
.ncols
= argv
->sz
;
1448 mdoc
->last
->norm
->Bl
.cols
= (void *)argv
->value
;
1450 for (nn
= mdoc
->last
->child
; nn
; i
++) {
1451 argv
->value
[i
] = nn
->string
;
1455 mdoc_node_delete(NULL
, nnp
);
1458 mdoc
->last
->nchild
= 0;
1459 mdoc
->last
->child
= NULL
;
1465 struct mdoc_node
*nparent
, *nprev
; /* of the Bl block */
1466 struct mdoc_node
*nblock
, *nbody
; /* of the Bl */
1467 struct mdoc_node
*nchild
, *nnext
; /* of the Bl body */
1470 switch (nbody
->type
) {
1472 post_bl_block(mdoc
);
1485 nchild
= nbody
->child
;
1486 while (NULL
!= nchild
) {
1487 if (MDOC_It
== nchild
->tok
|| MDOC_Sm
== nchild
->tok
) {
1488 nchild
= nchild
->next
;
1492 mandoc_msg(MANDOCERR_BL_MOVE
, mdoc
->parse
,
1493 nchild
->line
, nchild
->pos
,
1494 mdoc_macronames
[nchild
->tok
]);
1497 * Move the node out of the Bl block.
1498 * First, collect all required node pointers.
1501 nblock
= nbody
->parent
;
1502 nprev
= nblock
->prev
;
1503 nparent
= nblock
->parent
;
1504 nnext
= nchild
->next
;
1507 * Unlink this child.
1510 assert(NULL
== nchild
->prev
);
1511 if (0 == --nbody
->nchild
) {
1512 nbody
->child
= NULL
;
1514 assert(NULL
== nnext
);
1516 nbody
->child
= nnext
;
1521 * Relink this child.
1524 nchild
->parent
= nparent
;
1525 nchild
->prev
= nprev
;
1526 nchild
->next
= nblock
;
1528 nblock
->prev
= nchild
;
1531 nparent
->child
= nchild
;
1533 nprev
->next
= nchild
;
1548 post_sm(struct mdoc
*mdoc
)
1550 struct mdoc_node
*nch
;
1552 nch
= mdoc
->last
->child
;
1555 mdoc
->flags
^= MDOC_SMOFF
;
1559 assert(nch
->type
== MDOC_TEXT
);
1561 if ( ! strcmp(nch
->string
, "on")) {
1562 mdoc
->flags
&= ~MDOC_SMOFF
;
1565 if ( ! strcmp(nch
->string
, "off")) {
1566 mdoc
->flags
|= MDOC_SMOFF
;
1570 mandoc_vmsg(MANDOCERR_SM_BAD
,
1571 mdoc
->parse
, nch
->line
, nch
->pos
,
1572 "%s %s", mdoc_macronames
[mdoc
->last
->tok
], nch
->string
);
1573 mdoc_node_relink(mdoc
, nch
);
1578 post_root(POST_ARGS
)
1580 struct mdoc_node
*n
;
1582 /* Add missing prologue data. */
1584 if (mdoc
->meta
.date
== NULL
)
1585 mdoc
->meta
.date
= mdoc
->quick
?
1587 mandoc_normdate(mdoc
->parse
, NULL
, 0, 0);
1589 if (mdoc
->meta
.title
== NULL
) {
1590 mandoc_msg(MANDOCERR_DT_NOTITLE
,
1591 mdoc
->parse
, 0, 0, "EOF");
1592 mdoc
->meta
.title
= mandoc_strdup("UNTITLED");
1595 if (mdoc
->meta
.vol
== NULL
)
1596 mdoc
->meta
.vol
= mandoc_strdup("LOCAL");
1598 if (mdoc
->meta
.os
== NULL
) {
1599 mandoc_msg(MANDOCERR_OS_MISSING
,
1600 mdoc
->parse
, 0, 0, NULL
);
1601 mdoc
->meta
.os
= mandoc_strdup("");
1604 /* Check that we begin with a proper `Sh'. */
1606 n
= mdoc
->first
->child
;
1607 while (n
!= NULL
&& mdoc_macros
[n
->tok
].flags
& MDOC_PROLOGUE
)
1611 mandoc_msg(MANDOCERR_DOC_EMPTY
, mdoc
->parse
, 0, 0, NULL
);
1612 else if (n
->tok
!= MDOC_Sh
)
1613 mandoc_msg(MANDOCERR_SEC_BEFORE
, mdoc
->parse
,
1614 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
1620 struct mdoc_node
*n
, *nch
;
1627 mandoc_msg(MANDOCERR_MACRO_EMPTY
, mdoc
->parse
,
1628 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
1629 mdoc_node_delete(mdoc
, n
);
1633 assert(MDOC_TEXT
== nch
->type
);
1635 if (NULL
== (p
= mdoc_a2st(nch
->string
))) {
1636 mandoc_vmsg(MANDOCERR_ST_BAD
, mdoc
->parse
,
1637 nch
->line
, nch
->pos
, "St %s", nch
->string
);
1638 mdoc_node_delete(mdoc
, n
);
1641 nch
->string
= mandoc_strdup(p
);
1648 struct mdoc_node
*nn
, *next
, *prev
;
1651 switch (mdoc
->last
->type
) {
1653 check_count(mdoc
, MDOC_HEAD
, CHECK_WARN
, CHECK_EQ
, 0);
1656 if (mdoc
->last
->child
)
1658 check_count(mdoc
, MDOC_BODY
, CHECK_WARN
, CHECK_GT
, 0);
1665 * The full `Rs' block needs special handling to order the
1666 * sub-elements according to `rsord'. Pick through each element
1667 * and correctly order it. This is an insertion sort.
1671 for (nn
= mdoc
->last
->child
->next
; nn
; nn
= next
) {
1672 /* Determine order of `nn'. */
1673 for (i
= 0; i
< RSORD_MAX
; i
++)
1674 if (rsord
[i
] == nn
->tok
)
1677 if (i
== RSORD_MAX
) {
1678 mandoc_msg(MANDOCERR_RS_BAD
,
1679 mdoc
->parse
, nn
->line
, nn
->pos
,
1680 mdoc_macronames
[nn
->tok
]);
1682 } else if (MDOC__J
== nn
->tok
|| MDOC__B
== nn
->tok
)
1683 mdoc
->last
->norm
->Rs
.quote_T
++;
1686 * Remove `nn' from the chain. This somewhat
1687 * repeats mdoc_node_unlink(), but since we're
1688 * just re-ordering, there's no need for the
1689 * full unlink process.
1692 if (NULL
!= (next
= nn
->next
))
1693 next
->prev
= nn
->prev
;
1695 if (NULL
!= (prev
= nn
->prev
))
1696 prev
->next
= nn
->next
;
1698 nn
->prev
= nn
->next
= NULL
;
1701 * Scan back until we reach a node that's
1702 * ordered before `nn'.
1705 for ( ; prev
; prev
= prev
->prev
) {
1706 /* Determine order of `prev'. */
1707 for (j
= 0; j
< RSORD_MAX
; j
++)
1708 if (rsord
[j
] == prev
->tok
)
1718 * Set `nn' back into its correct place in front
1719 * of the `prev' node.
1726 prev
->next
->prev
= nn
;
1727 nn
->next
= prev
->next
;
1730 mdoc
->last
->child
->prev
= nn
;
1731 nn
->next
= mdoc
->last
->child
;
1732 mdoc
->last
->child
= nn
;
1738 * For some arguments of some macros,
1739 * convert all breakable hyphens into ASCII_HYPH.
1742 post_hyph(POST_ARGS
)
1744 struct mdoc_node
*n
, *nch
;
1750 if (MDOC_Sh
== n
->tok
|| MDOC_Ss
== n
->tok
)
1754 if (MDOC_D1
== n
->tok
|| MDOC_Nd
== n
->tok
)
1763 for (nch
= n
->child
; nch
; nch
= nch
->next
) {
1764 if (MDOC_TEXT
!= nch
->type
)
1769 while ('\0' != *(++cp
))
1771 isalpha((unsigned char)cp
[-1]) &&
1772 isalpha((unsigned char)cp
[1]))
1778 post_hyphtext(POST_ARGS
)
1789 if (MDOC_LINE
& mdoc
->last
->flags
)
1790 mandoc_msg(MANDOCERR_NS_SKIP
, mdoc
->parse
,
1791 mdoc
->last
->line
, mdoc
->last
->pos
, NULL
);
1800 switch (mdoc
->last
->type
) {
1805 switch (mdoc
->lastsec
) {
1810 post_sh_see_also(mdoc
);
1813 post_sh_authors(mdoc
);
1825 post_sh_name(POST_ARGS
)
1827 struct mdoc_node
*n
;
1830 * Warn if the NAME section doesn't contain the `Nm' and `Nd'
1831 * macros (can have multiple `Nm' and one `Nd'). Note that the
1832 * children of the BODY declaration can also be "text".
1835 if (NULL
== (n
= mdoc
->last
->child
)) {
1836 mandoc_msg(MANDOCERR_NAMESEC_BAD
, mdoc
->parse
,
1837 mdoc
->last
->line
, mdoc
->last
->pos
, "empty");
1841 for ( ; n
&& n
->next
; n
= n
->next
) {
1842 if (MDOC_ELEM
== n
->type
&& MDOC_Nm
== n
->tok
)
1844 if (MDOC_TEXT
== n
->type
)
1846 mandoc_msg(MANDOCERR_NAMESEC_BAD
, mdoc
->parse
,
1847 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
1851 if (MDOC_BLOCK
== n
->type
&& MDOC_Nd
== n
->tok
)
1854 mandoc_msg(MANDOCERR_NAMESEC_BAD
, mdoc
->parse
,
1855 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
1859 post_sh_see_also(POST_ARGS
)
1861 const struct mdoc_node
*n
;
1862 const char *name
, *sec
;
1863 const char *lastname
, *lastsec
, *lastpunct
;
1866 n
= mdoc
->last
->child
;
1867 lastname
= lastsec
= lastpunct
= NULL
;
1869 if (n
->tok
!= MDOC_Xr
|| n
->nchild
< 2)
1872 /* Process one .Xr node. */
1874 name
= n
->child
->string
;
1875 sec
= n
->child
->next
->string
;
1876 if (lastsec
!= NULL
) {
1877 if (lastpunct
[0] != ',' || lastpunct
[1] != '\0')
1878 mandoc_vmsg(MANDOCERR_XR_PUNCT
,
1879 mdoc
->parse
, n
->line
, n
->pos
,
1880 "%s before %s(%s)", lastpunct
,
1882 cmp
= strcmp(lastsec
, sec
);
1884 mandoc_vmsg(MANDOCERR_XR_ORDER
,
1885 mdoc
->parse
, n
->line
, n
->pos
,
1886 "%s(%s) after %s(%s)", name
,
1887 sec
, lastname
, lastsec
);
1888 else if (cmp
== 0 &&
1889 strcasecmp(lastname
, name
) > 0)
1890 mandoc_vmsg(MANDOCERR_XR_ORDER
,
1891 mdoc
->parse
, n
->line
, n
->pos
,
1892 "%s after %s", name
, lastname
);
1897 /* Process the following node. */
1902 if (n
->tok
== MDOC_Xr
) {
1906 if (n
->type
!= MDOC_TEXT
)
1908 for (name
= n
->string
; *name
!= '\0'; name
++)
1909 if (isalpha((const unsigned char)*name
))
1911 lastpunct
= n
->string
;
1912 if (n
->next
== NULL
)
1913 mandoc_vmsg(MANDOCERR_XR_PUNCT
, mdoc
->parse
,
1914 n
->line
, n
->pos
, "%s after %s(%s)",
1915 lastpunct
, lastname
, lastsec
);
1921 child_an(const struct mdoc_node
*n
)
1924 for (n
= n
->child
; n
!= NULL
; n
= n
->next
)
1925 if ((n
->tok
== MDOC_An
&& n
->nchild
) || child_an(n
))
1931 post_sh_authors(POST_ARGS
)
1934 if ( ! child_an(mdoc
->last
))
1935 mandoc_msg(MANDOCERR_AN_MISSING
, mdoc
->parse
,
1936 mdoc
->last
->line
, mdoc
->last
->pos
, NULL
);
1940 post_sh_head(POST_ARGS
)
1942 struct mdoc_node
*n
;
1943 const char *goodsec
;
1948 * Process a new section. Sections are either "named" or
1949 * "custom". Custom sections are user-defined, while named ones
1950 * follow a conventional order and may only appear in certain
1956 mdoc_deroff(&secname
, mdoc
->last
);
1957 sec
= NULL
== secname
? SEC_CUSTOM
: a2sec(secname
);
1959 /* The NAME should be first. */
1961 if (SEC_NAME
!= sec
&& SEC_NONE
== mdoc
->lastnamed
)
1962 mandoc_vmsg(MANDOCERR_NAMESEC_FIRST
, mdoc
->parse
,
1963 mdoc
->last
->line
, mdoc
->last
->pos
,
1966 /* The SYNOPSIS gets special attention in other areas. */
1968 if (SEC_SYNOPSIS
== sec
) {
1969 roff_setreg(mdoc
->roff
, "nS", 1, '=');
1970 mdoc
->flags
|= MDOC_SYNOPSIS
;
1972 roff_setreg(mdoc
->roff
, "nS", 0, '=');
1973 mdoc
->flags
&= ~MDOC_SYNOPSIS
;
1976 /* Mark our last section. */
1978 mdoc
->lastsec
= sec
;
1981 * Set the section attribute for the current HEAD, for its
1982 * parent BLOCK, and for the HEAD children; the latter can
1983 * only be TEXT nodes, so no recursion is needed.
1984 * For other blocks and elements, including .Sh BODY, this is
1985 * done when allocating the node data structures, but for .Sh
1986 * BLOCK and HEAD, the section is still unknown at that time.
1989 mdoc
->last
->parent
->sec
= sec
;
1990 mdoc
->last
->sec
= sec
;
1991 for (n
= mdoc
->last
->child
; n
; n
= n
->next
)
1994 /* We don't care about custom sections after this. */
1996 if (SEC_CUSTOM
== sec
) {
2002 * Check whether our non-custom section is being repeated or is
2006 if (sec
== mdoc
->lastnamed
)
2007 mandoc_vmsg(MANDOCERR_SEC_REP
, mdoc
->parse
,
2008 mdoc
->last
->line
, mdoc
->last
->pos
,
2011 if (sec
< mdoc
->lastnamed
)
2012 mandoc_vmsg(MANDOCERR_SEC_ORDER
, mdoc
->parse
,
2013 mdoc
->last
->line
, mdoc
->last
->pos
,
2016 /* Mark the last named section. */
2018 mdoc
->lastnamed
= sec
;
2020 /* Check particular section/manual conventions. */
2022 if (mdoc
->meta
.msec
== NULL
) {
2030 if (*mdoc
->meta
.msec
== '4')
2032 goodsec
= "2, 3, 4, 9";
2034 case SEC_RETURN_VALUES
:
2037 if (*mdoc
->meta
.msec
== '2')
2039 if (*mdoc
->meta
.msec
== '3')
2041 if (NULL
== goodsec
)
2042 goodsec
= "2, 3, 9";
2045 if (*mdoc
->meta
.msec
== '9')
2047 if (NULL
== goodsec
)
2049 mandoc_vmsg(MANDOCERR_SEC_MSEC
, mdoc
->parse
,
2050 mdoc
->last
->line
, mdoc
->last
->pos
,
2051 "Sh %s for %s only", secname
, goodsec
);
2060 post_ignpar(POST_ARGS
)
2062 struct mdoc_node
*np
;
2064 check_count(mdoc
, MDOC_HEAD
, CHECK_WARN
, CHECK_GT
, 0);
2067 if (MDOC_BODY
!= mdoc
->last
->type
)
2070 if (NULL
!= (np
= mdoc
->last
->child
))
2071 if (MDOC_Pp
== np
->tok
|| MDOC_Lp
== np
->tok
) {
2072 mandoc_vmsg(MANDOCERR_PAR_SKIP
,
2073 mdoc
->parse
, np
->line
, np
->pos
,
2074 "%s after %s", mdoc_macronames
[np
->tok
],
2075 mdoc_macronames
[mdoc
->last
->tok
]);
2076 mdoc_node_delete(mdoc
, np
);
2079 if (NULL
!= (np
= mdoc
->last
->last
))
2080 if (MDOC_Pp
== np
->tok
|| MDOC_Lp
== np
->tok
) {
2081 mandoc_vmsg(MANDOCERR_PAR_SKIP
, mdoc
->parse
,
2082 np
->line
, np
->pos
, "%s at the end of %s",
2083 mdoc_macronames
[np
->tok
],
2084 mdoc_macronames
[mdoc
->last
->tok
]);
2085 mdoc_node_delete(mdoc
, np
);
2093 if (NULL
== mdoc
->last
)
2095 if (MDOC_ELEM
!= n
->type
&& MDOC_BLOCK
!= n
->type
)
2099 * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
2100 * block: `Lp', `Pp', or non-compact `Bd' or `Bl'.
2103 if (MDOC_Pp
!= mdoc
->last
->tok
&&
2104 MDOC_Lp
!= mdoc
->last
->tok
&&
2105 MDOC_br
!= mdoc
->last
->tok
)
2107 if (MDOC_Bl
== n
->tok
&& n
->norm
->Bl
.comp
)
2109 if (MDOC_Bd
== n
->tok
&& n
->norm
->Bd
.comp
)
2111 if (MDOC_It
== n
->tok
&& n
->parent
->norm
->Bl
.comp
)
2114 mandoc_vmsg(MANDOCERR_PAR_SKIP
, mdoc
->parse
,
2115 mdoc
->last
->line
, mdoc
->last
->pos
,
2116 "%s before %s", mdoc_macronames
[mdoc
->last
->tok
],
2117 mdoc_macronames
[n
->tok
]);
2118 mdoc_node_delete(mdoc
, mdoc
->last
);
2124 struct mdoc_node
*np
;
2126 if (mdoc
->last
->tok
== MDOC_sp
)
2127 check_count(mdoc
, MDOC_ELEM
, CHECK_WARN
, CHECK_LT
, 2);
2129 check_count(mdoc
, MDOC_ELEM
, CHECK_WARN
, CHECK_EQ
, 0);
2131 if (MDOC_ELEM
!= mdoc
->last
->type
&&
2132 MDOC_BLOCK
!= mdoc
->last
->type
)
2135 if (NULL
== (np
= mdoc
->last
->prev
)) {
2136 np
= mdoc
->last
->parent
;
2137 if (MDOC_Sh
!= np
->tok
&& MDOC_Ss
!= np
->tok
)
2139 } else if (MDOC_Pp
!= np
->tok
&& MDOC_Lp
!= np
->tok
&&
2140 (MDOC_br
!= mdoc
->last
->tok
||
2141 (MDOC_sp
!= np
->tok
&& MDOC_br
!= np
->tok
)))
2144 mandoc_vmsg(MANDOCERR_PAR_SKIP
, mdoc
->parse
,
2145 mdoc
->last
->line
, mdoc
->last
->pos
,
2146 "%s after %s", mdoc_macronames
[mdoc
->last
->tok
],
2147 mdoc_macronames
[np
->tok
]);
2148 mdoc_node_delete(mdoc
, mdoc
->last
);
2152 pre_literal(PRE_ARGS
)
2155 pre_display(mdoc
, n
);
2157 if (MDOC_BODY
!= n
->type
)
2161 * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd
2162 * -unfilled' macros set MDOC_LITERAL on entrance to the body.
2167 mdoc
->flags
|= MDOC_LITERAL
;
2170 if (DISP_literal
== n
->norm
->Bd
.type
)
2171 mdoc
->flags
|= MDOC_LITERAL
;
2172 if (DISP_unfilled
== n
->norm
->Bd
.type
)
2173 mdoc
->flags
|= MDOC_LITERAL
;
2184 struct mdoc_node
*n
;
2187 if (mdoc
->meta
.date
)
2188 free(mdoc
->meta
.date
);
2191 if (NULL
== n
->child
|| '\0' == n
->child
->string
[0]) {
2192 mdoc
->meta
.date
= mdoc
->quick
? mandoc_strdup("") :
2193 mandoc_normdate(mdoc
->parse
, NULL
, n
->line
, n
->pos
);
2198 mdoc_deroff(&datestr
, n
);
2200 mdoc
->meta
.date
= datestr
;
2202 mdoc
->meta
.date
= mandoc_normdate(mdoc
->parse
,
2203 datestr
, n
->line
, n
->pos
);
2207 mdoc_node_delete(mdoc
, n
);
2213 struct mdoc_node
*nn
, *n
;
2219 free(mdoc
->meta
.title
);
2220 free(mdoc
->meta
.msec
);
2221 free(mdoc
->meta
.vol
);
2222 free(mdoc
->meta
.arch
);
2224 mdoc
->meta
.title
= NULL
;
2225 mdoc
->meta
.msec
= NULL
;
2226 mdoc
->meta
.vol
= NULL
;
2227 mdoc
->meta
.arch
= NULL
;
2229 /* First check that all characters are uppercase. */
2231 if (NULL
!= (nn
= n
->child
))
2232 for (p
= nn
->string
; *p
; p
++) {
2233 if (toupper((unsigned char)*p
) == *p
)
2235 mandoc_vmsg(MANDOCERR_TITLE_CASE
,
2236 mdoc
->parse
, nn
->line
,
2237 nn
->pos
+ (p
- nn
->string
),
2238 "Dt %s", nn
->string
);
2242 /* No argument: msec and arch remain NULL. */
2244 if (NULL
== (nn
= n
->child
)) {
2245 mandoc_msg(MANDOCERR_DT_NOTITLE
,
2246 mdoc
->parse
, n
->line
, n
->pos
, "Dt");
2247 mdoc
->meta
.title
= mandoc_strdup("UNTITLED");
2248 mdoc
->meta
.vol
= mandoc_strdup("LOCAL");
2252 /* One argument: msec and arch remain NULL. */
2254 mdoc
->meta
.title
= mandoc_strdup(
2255 '\0' == nn
->string
[0] ? "UNTITLED" : nn
->string
);
2257 if (NULL
== (nn
= nn
->next
)) {
2258 mandoc_vmsg(MANDOCERR_MSEC_MISSING
,
2259 mdoc
->parse
, n
->line
, n
->pos
,
2260 "Dt %s", mdoc
->meta
.title
);
2261 mdoc
->meta
.vol
= mandoc_strdup("LOCAL");
2265 /* Handles: `.Dt TITLE SEC'
2267 * volume = SEC is msec ? format(msec) : SEC,
2268 * msec = SEC is msec ? atoi(msec) : 0,
2272 cp
= mandoc_a2msec(nn
->string
);
2274 mdoc
->meta
.vol
= mandoc_strdup(cp
);
2275 mdoc
->meta
.msec
= mandoc_strdup(nn
->string
);
2277 mandoc_vmsg(MANDOCERR_MSEC_BAD
, mdoc
->parse
,
2278 nn
->line
, nn
->pos
, "Dt ... %s", nn
->string
);
2279 mdoc
->meta
.vol
= mandoc_strdup(nn
->string
);
2280 mdoc
->meta
.msec
= mandoc_strdup(nn
->string
);
2283 if (NULL
== (nn
= nn
->next
))
2286 /* Handles: `.Dt TITLE SEC VOL'
2288 * volume = VOL is vol ? format(VOL) :
2289 * VOL is arch ? format(arch) :
2293 cp
= mdoc_a2vol(nn
->string
);
2295 free(mdoc
->meta
.vol
);
2296 mdoc
->meta
.vol
= mandoc_strdup(cp
);
2298 cp
= mdoc_a2arch(nn
->string
);
2300 mandoc_vmsg(MANDOCERR_ARCH_BAD
, mdoc
->parse
,
2301 nn
->line
, nn
->pos
, "Dt ... %s", nn
->string
);
2302 free(mdoc
->meta
.vol
);
2303 mdoc
->meta
.vol
= mandoc_strdup(nn
->string
);
2305 mdoc
->meta
.arch
= mandoc_strdup(cp
);
2308 /* Ignore any subsequent parameters... */
2309 /* FIXME: warn about subsequent parameters. */
2311 mdoc_node_delete(mdoc
, n
);
2317 struct mdoc_node
*n
;
2320 * Make `Bx's second argument always start with an uppercase
2321 * letter. Groff checks if it's an "accepted" term, but we just
2322 * uppercase blindly.
2325 n
= mdoc
->last
->child
;
2326 if (n
&& NULL
!= (n
= n
->next
))
2327 *n
->string
= (char)toupper((unsigned char)*n
->string
);
2334 struct utsname utsname
;
2335 static char *defbuf
;
2337 struct mdoc_node
*n
;
2342 * Set the operating system by way of the `Os' macro.
2343 * The order of precedence is:
2344 * 1. the argument of the `Os' macro, unless empty
2345 * 2. the -Ios=foo command line argument, if provided
2346 * 3. -DOSNAME="\"foo\"", if provided during compilation
2347 * 4. "sysname release" from uname(3)
2350 free(mdoc
->meta
.os
);
2351 mdoc
->meta
.os
= NULL
;
2352 mdoc_deroff(&mdoc
->meta
.os
, n
);
2357 mdoc
->meta
.os
= mandoc_strdup(mdoc
->defos
);
2362 mdoc
->meta
.os
= mandoc_strdup(OSNAME
);
2364 if (NULL
== defbuf
) {
2365 if (-1 == uname(&utsname
)) {
2366 mandoc_msg(MANDOCERR_OS_UNAME
, mdoc
->parse
,
2367 n
->line
, n
->pos
, "Os");
2368 defbuf
= mandoc_strdup("UNKNOWN");
2370 mandoc_asprintf(&defbuf
, "%s %s",
2371 utsname
.sysname
, utsname
.release
);
2373 mdoc
->meta
.os
= mandoc_strdup(defbuf
);
2377 mdoc_node_delete(mdoc
, n
);
2381 * If no argument is provided,
2382 * fill in the name of the current manual page.
2387 struct mdoc_node
*n
;
2394 if (mdoc
->meta
.name
== NULL
) {
2395 mandoc_msg(MANDOCERR_EX_NONAME
, mdoc
->parse
,
2396 n
->line
, n
->pos
, "Ex");
2400 mdoc
->next
= MDOC_NEXT_CHILD
;
2401 mdoc_word_alloc(mdoc
, n
->line
, n
->pos
, mdoc
->meta
.name
);
2405 static enum mdoc_sec
2406 a2sec(const char *p
)
2410 for (i
= 0; i
< (int)SEC__MAX
; i
++)
2411 if (secnames
[i
] && 0 == strcmp(p
, secnames
[i
]))
2412 return((enum mdoc_sec
)i
);
2418 macro2len(enum mdoct macro
)