]>
git.cameronkatri.com Git - mandoc.git/blob - mdoc_validate.c
1 /* $Id: mdoc_validate.c,v 1.266 2015/02/03 00:48:47 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 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
, NULL
}, /* 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
]);
1050 struct mdoc_node
*n
;
1054 if (n
->last
!= NULL
&&
1055 (n
->last
->tok
== MDOC_Pp
||
1056 n
->last
->tok
== MDOC_Lp
))
1057 mdoc_node_relink(mdoc
, n
->last
);
1059 if (NULL
!= mdoc
->meta
.name
)
1062 mdoc_deroff(&mdoc
->meta
.name
, n
);
1064 if (NULL
== mdoc
->meta
.name
)
1065 mandoc_msg(MANDOCERR_NM_NONAME
, mdoc
->parse
,
1066 n
->line
, n
->pos
, "Nm");
1073 check_count(mdoc
, MDOC_BODY
, CHECK_ERROR
, CHECK_GT
, 0);
1086 post_literal(POST_ARGS
)
1089 if (mdoc
->last
->tok
== MDOC_Bd
)
1094 * The `Dl' (note "el" not "one") and `Bd' macros unset the
1095 * MDOC_LITERAL flag as they leave. Note that `Bd' only sets
1096 * this in literal mode, but it doesn't hurt to just switch it
1097 * off in general since displays can't be nested.
1100 if (MDOC_BODY
== mdoc
->last
->type
)
1101 mdoc
->flags
&= ~MDOC_LITERAL
;
1105 post_defaults(POST_ARGS
)
1107 struct mdoc_node
*nn
;
1110 * The `Ar' defaults to "file ..." if no value is provided as an
1111 * argument; the `Mt' and `Pa' macros use "~"; the `Li' just
1112 * gets an empty string.
1115 if (mdoc
->last
->child
)
1119 mdoc
->next
= MDOC_NEXT_CHILD
;
1123 mdoc_word_alloc(mdoc
, nn
->line
, nn
->pos
, "file");
1124 mdoc_word_alloc(mdoc
, nn
->line
, nn
->pos
, "...");
1129 mdoc_word_alloc(mdoc
, nn
->line
, nn
->pos
, "~");
1141 struct mdoc_node
*n
;
1142 const char *std_att
;
1146 if (n
->child
== NULL
) {
1147 mdoc
->next
= MDOC_NEXT_CHILD
;
1148 mdoc_word_alloc(mdoc
, n
->line
, n
->pos
, "AT&T UNIX");
1154 * If we have a child, look it up in the standard keys. If a
1155 * key exist, use that instead of the child; if it doesn't,
1156 * prefix "AT&T UNIX " to the existing data.
1160 assert(MDOC_TEXT
== n
->type
);
1161 if (NULL
== (std_att
= mdoc_a2att(n
->string
))) {
1162 mandoc_vmsg(MANDOCERR_AT_BAD
, mdoc
->parse
,
1163 n
->line
, n
->pos
, "At %s", n
->string
);
1164 mandoc_asprintf(&att
, "AT&T UNIX %s", n
->string
);
1166 att
= mandoc_strdup(std_att
);
1175 struct mdoc_node
*np
;
1178 if (AUTH__NONE
== np
->norm
->An
.auth
) {
1180 check_count(mdoc
, MDOC_ELEM
, CHECK_WARN
, CHECK_GT
, 0);
1181 } else if (np
->child
)
1182 check_count(mdoc
, MDOC_ELEM
, CHECK_WARN
, CHECK_EQ
, 0);
1189 if (MDOC_BLOCK
== mdoc
->last
->type
)
1190 mdoc
->last
->norm
->Es
= mdoc
->last_es
;
1197 mdoc
->last_es
= mdoc
->last
;
1205 struct mdoc_node
*nbl
, *nit
, *nch
;
1208 if (nit
->type
!= MDOC_BLOCK
)
1211 nbl
= nit
->parent
->parent
;
1212 lt
= nbl
->norm
->Bl
.type
;
1224 if (nit
->head
->child
== NULL
)
1225 mandoc_vmsg(MANDOCERR_IT_NOHEAD
,
1226 mdoc
->parse
, nit
->line
, nit
->pos
,
1228 mdoc_argnames
[nbl
->args
->argv
[0].arg
]);
1237 if (nit
->body
== NULL
|| nit
->body
->child
== NULL
)
1238 mandoc_vmsg(MANDOCERR_IT_NOBODY
,
1239 mdoc
->parse
, nit
->line
, nit
->pos
,
1241 mdoc_argnames
[nbl
->args
->argv
[0].arg
]);
1244 if (nit
->head
->child
!= NULL
)
1245 mandoc_vmsg(MANDOCERR_ARG_SKIP
,
1246 mdoc
->parse
, nit
->line
, nit
->pos
,
1247 "It %s", nit
->head
->child
->string
);
1250 cols
= (int)nbl
->norm
->Bl
.ncols
;
1252 assert(nit
->head
->child
== NULL
);
1254 for (i
= 0, nch
= nit
->child
; nch
; nch
= nch
->next
)
1255 if (nch
->type
== MDOC_BODY
)
1258 if (i
< cols
|| i
> cols
+ 1)
1259 mandoc_vmsg(MANDOCERR_ARGCOUNT
,
1260 mdoc
->parse
, nit
->line
, nit
->pos
,
1261 "columns == %d (have %d)", cols
, i
);
1269 post_bl_block(POST_ARGS
)
1271 struct mdoc_node
*n
, *ni
, *nc
;
1274 * These are fairly complicated, so we've broken them into two
1275 * functions. post_bl_block_tag() is called when a -tag is
1276 * specified, but no -width (it must be guessed). The second
1277 * when a -width is specified (macro indicators must be
1278 * rewritten into real lengths).
1283 if (LIST_tag
== n
->norm
->Bl
.type
&&
1284 NULL
== n
->norm
->Bl
.width
) {
1285 post_bl_block_tag(mdoc
);
1286 assert(n
->norm
->Bl
.width
);
1289 for (ni
= n
->body
->child
; ni
; ni
= ni
->next
) {
1290 if (NULL
== ni
->body
)
1292 nc
= ni
->body
->last
;
1293 while (NULL
!= nc
) {
1305 if (NULL
== ni
->next
) {
1306 mandoc_msg(MANDOCERR_PAR_MOVE
,
1307 mdoc
->parse
, nc
->line
, nc
->pos
,
1308 mdoc_macronames
[nc
->tok
]);
1309 mdoc_node_relink(mdoc
, nc
);
1310 } else if (0 == n
->norm
->Bl
.comp
&&
1311 LIST_column
!= n
->norm
->Bl
.type
) {
1312 mandoc_vmsg(MANDOCERR_PAR_SKIP
,
1313 mdoc
->parse
, nc
->line
, nc
->pos
,
1315 mdoc_macronames
[nc
->tok
]);
1316 mdoc_node_delete(mdoc
, nc
);
1319 nc
= ni
->body
->last
;
1325 * If the argument of -offset or -width is a macro,
1326 * replace it with the associated default width.
1329 rewrite_macro2len(char **arg
)
1336 else if ( ! strcmp(*arg
, "Ds"))
1338 else if ((tok
= mdoc_hash_find(*arg
)) == MDOC_MAX
)
1341 width
= macro2len(tok
);
1344 mandoc_asprintf(arg
, "%zun", width
);
1348 post_bl_block_tag(POST_ARGS
)
1350 struct mdoc_node
*n
, *nn
;
1356 * Calculate the -width for a `Bl -tag' list if it hasn't been
1357 * provided. Uses the first head macro. NOTE AGAIN: this is
1358 * ONLY if the -width argument has NOT been provided. See
1359 * rewrite_macro2len() for converting the -width string.
1365 for (nn
= n
->body
->child
; nn
; nn
= nn
->next
) {
1366 if (MDOC_It
!= nn
->tok
)
1369 assert(MDOC_BLOCK
== nn
->type
);
1370 nn
= nn
->head
->child
;
1375 if (MDOC_TEXT
== nn
->type
) {
1376 sz
= strlen(nn
->string
) + 1;
1380 if (0 != (ssz
= macro2len(nn
->tok
)))
1386 /* Defaults to ten ens. */
1388 (void)snprintf(buf
, sizeof(buf
), "%un", (unsigned int)sz
);
1391 * We have to dynamically add this to the macro's argument list.
1392 * We're guaranteed that a MDOC_Width doesn't already exist.
1396 i
= (int)(n
->args
->argc
)++;
1398 n
->args
->argv
= mandoc_reallocarray(n
->args
->argv
,
1399 n
->args
->argc
, sizeof(struct mdoc_argv
));
1401 n
->args
->argv
[i
].arg
= MDOC_Width
;
1402 n
->args
->argv
[i
].line
= n
->line
;
1403 n
->args
->argv
[i
].pos
= n
->pos
;
1404 n
->args
->argv
[i
].sz
= 1;
1405 n
->args
->argv
[i
].value
= mandoc_malloc(sizeof(char *));
1406 n
->args
->argv
[i
].value
[0] = mandoc_strdup(buf
);
1408 /* Set our width! */
1409 n
->norm
->Bl
.width
= n
->args
->argv
[i
].value
[0];
1413 post_bl_head(POST_ARGS
)
1415 struct mdoc_node
*np
, *nn
, *nnp
;
1416 struct mdoc_argv
*argv
;
1419 if (LIST_column
!= mdoc
->last
->norm
->Bl
.type
) {
1420 /* FIXME: this should be ERROR class... */
1426 * Append old-style lists, where the column width specifiers
1427 * trail as macro parameters, to the new-style ("normal-form")
1428 * lists where they're argument values following -column.
1431 if (mdoc
->last
->child
== NULL
)
1434 np
= mdoc
->last
->parent
;
1437 for (j
= 0; j
< (int)np
->args
->argc
; j
++)
1438 if (MDOC_Column
== np
->args
->argv
[j
].arg
)
1441 assert(j
< (int)np
->args
->argc
);
1444 * Accommodate for new-style groff column syntax. Shuffle the
1445 * child nodes, all of which must be TEXT, as arguments for the
1446 * column field. Then, delete the head children.
1449 argv
= np
->args
->argv
+ j
;
1451 argv
->sz
+= mdoc
->last
->nchild
;
1452 argv
->value
= mandoc_reallocarray(argv
->value
,
1453 argv
->sz
, sizeof(char *));
1455 mdoc
->last
->norm
->Bl
.ncols
= argv
->sz
;
1456 mdoc
->last
->norm
->Bl
.cols
= (void *)argv
->value
;
1458 for (nn
= mdoc
->last
->child
; nn
; i
++) {
1459 argv
->value
[i
] = nn
->string
;
1463 mdoc_node_delete(NULL
, nnp
);
1466 mdoc
->last
->nchild
= 0;
1467 mdoc
->last
->child
= NULL
;
1473 struct mdoc_node
*nparent
, *nprev
; /* of the Bl block */
1474 struct mdoc_node
*nblock
, *nbody
; /* of the Bl */
1475 struct mdoc_node
*nchild
, *nnext
; /* of the Bl body */
1478 switch (nbody
->type
) {
1480 post_bl_block(mdoc
);
1493 nchild
= nbody
->child
;
1494 while (NULL
!= nchild
) {
1495 if (nchild
->tok
== MDOC_It
||
1496 (nchild
->tok
== MDOC_Sm
&&
1497 nchild
->next
!= NULL
&&
1498 nchild
->next
->tok
== MDOC_It
)) {
1499 nchild
= nchild
->next
;
1503 mandoc_msg(MANDOCERR_BL_MOVE
, mdoc
->parse
,
1504 nchild
->line
, nchild
->pos
,
1505 mdoc_macronames
[nchild
->tok
]);
1508 * Move the node out of the Bl block.
1509 * First, collect all required node pointers.
1512 nblock
= nbody
->parent
;
1513 nprev
= nblock
->prev
;
1514 nparent
= nblock
->parent
;
1515 nnext
= nchild
->next
;
1518 * Unlink this child.
1521 assert(NULL
== nchild
->prev
);
1522 if (0 == --nbody
->nchild
) {
1523 nbody
->child
= NULL
;
1525 assert(NULL
== nnext
);
1527 nbody
->child
= nnext
;
1532 * Relink this child.
1535 nchild
->parent
= nparent
;
1536 nchild
->prev
= nprev
;
1537 nchild
->next
= nblock
;
1539 nblock
->prev
= nchild
;
1542 nparent
->child
= nchild
;
1544 nprev
->next
= nchild
;
1559 post_sm(struct mdoc
*mdoc
)
1561 struct mdoc_node
*nch
;
1563 nch
= mdoc
->last
->child
;
1566 mdoc
->flags
^= MDOC_SMOFF
;
1570 assert(nch
->type
== MDOC_TEXT
);
1572 if ( ! strcmp(nch
->string
, "on")) {
1573 mdoc
->flags
&= ~MDOC_SMOFF
;
1576 if ( ! strcmp(nch
->string
, "off")) {
1577 mdoc
->flags
|= MDOC_SMOFF
;
1581 mandoc_vmsg(MANDOCERR_SM_BAD
,
1582 mdoc
->parse
, nch
->line
, nch
->pos
,
1583 "%s %s", mdoc_macronames
[mdoc
->last
->tok
], nch
->string
);
1584 mdoc_node_relink(mdoc
, nch
);
1589 post_root(POST_ARGS
)
1591 struct mdoc_node
*n
;
1593 /* Add missing prologue data. */
1595 if (mdoc
->meta
.date
== NULL
)
1596 mdoc
->meta
.date
= mdoc
->quick
?
1598 mandoc_normdate(mdoc
->parse
, NULL
, 0, 0);
1600 if (mdoc
->meta
.title
== NULL
) {
1601 mandoc_msg(MANDOCERR_DT_NOTITLE
,
1602 mdoc
->parse
, 0, 0, "EOF");
1603 mdoc
->meta
.title
= mandoc_strdup("UNTITLED");
1606 if (mdoc
->meta
.vol
== NULL
)
1607 mdoc
->meta
.vol
= mandoc_strdup("LOCAL");
1609 if (mdoc
->meta
.os
== NULL
) {
1610 mandoc_msg(MANDOCERR_OS_MISSING
,
1611 mdoc
->parse
, 0, 0, NULL
);
1612 mdoc
->meta
.os
= mandoc_strdup("");
1615 /* Check that we begin with a proper `Sh'. */
1617 n
= mdoc
->first
->child
;
1618 while (n
!= NULL
&& mdoc_macros
[n
->tok
].flags
& MDOC_PROLOGUE
)
1622 mandoc_msg(MANDOCERR_DOC_EMPTY
, mdoc
->parse
, 0, 0, NULL
);
1623 else if (n
->tok
!= MDOC_Sh
)
1624 mandoc_msg(MANDOCERR_SEC_BEFORE
, mdoc
->parse
,
1625 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
1631 struct mdoc_node
*n
, *nch
;
1638 mandoc_msg(MANDOCERR_MACRO_EMPTY
, mdoc
->parse
,
1639 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
1640 mdoc_node_delete(mdoc
, n
);
1644 assert(MDOC_TEXT
== nch
->type
);
1646 if (NULL
== (p
= mdoc_a2st(nch
->string
))) {
1647 mandoc_vmsg(MANDOCERR_ST_BAD
, mdoc
->parse
,
1648 nch
->line
, nch
->pos
, "St %s", nch
->string
);
1649 mdoc_node_delete(mdoc
, n
);
1652 nch
->string
= mandoc_strdup(p
);
1659 struct mdoc_node
*nn
, *next
, *prev
;
1662 switch (mdoc
->last
->type
) {
1664 check_count(mdoc
, MDOC_HEAD
, CHECK_WARN
, CHECK_EQ
, 0);
1667 if (mdoc
->last
->child
)
1669 check_count(mdoc
, MDOC_BODY
, CHECK_WARN
, CHECK_GT
, 0);
1676 * The full `Rs' block needs special handling to order the
1677 * sub-elements according to `rsord'. Pick through each element
1678 * and correctly order it. This is an insertion sort.
1682 for (nn
= mdoc
->last
->child
->next
; nn
; nn
= next
) {
1683 /* Determine order of `nn'. */
1684 for (i
= 0; i
< RSORD_MAX
; i
++)
1685 if (rsord
[i
] == nn
->tok
)
1688 if (i
== RSORD_MAX
) {
1689 mandoc_msg(MANDOCERR_RS_BAD
,
1690 mdoc
->parse
, nn
->line
, nn
->pos
,
1691 mdoc_macronames
[nn
->tok
]);
1693 } else if (MDOC__J
== nn
->tok
|| MDOC__B
== nn
->tok
)
1694 mdoc
->last
->norm
->Rs
.quote_T
++;
1697 * Remove `nn' from the chain. This somewhat
1698 * repeats mdoc_node_unlink(), but since we're
1699 * just re-ordering, there's no need for the
1700 * full unlink process.
1703 if (NULL
!= (next
= nn
->next
))
1704 next
->prev
= nn
->prev
;
1706 if (NULL
!= (prev
= nn
->prev
))
1707 prev
->next
= nn
->next
;
1709 nn
->prev
= nn
->next
= NULL
;
1712 * Scan back until we reach a node that's
1713 * ordered before `nn'.
1716 for ( ; prev
; prev
= prev
->prev
) {
1717 /* Determine order of `prev'. */
1718 for (j
= 0; j
< RSORD_MAX
; j
++)
1719 if (rsord
[j
] == prev
->tok
)
1729 * Set `nn' back into its correct place in front
1730 * of the `prev' node.
1737 prev
->next
->prev
= nn
;
1738 nn
->next
= prev
->next
;
1741 mdoc
->last
->child
->prev
= nn
;
1742 nn
->next
= mdoc
->last
->child
;
1743 mdoc
->last
->child
= nn
;
1749 * For some arguments of some macros,
1750 * convert all breakable hyphens into ASCII_HYPH.
1753 post_hyph(POST_ARGS
)
1755 struct mdoc_node
*n
, *nch
;
1761 if (MDOC_Sh
== n
->tok
|| MDOC_Ss
== n
->tok
)
1765 if (MDOC_D1
== n
->tok
|| MDOC_Nd
== n
->tok
)
1774 for (nch
= n
->child
; nch
; nch
= nch
->next
) {
1775 if (MDOC_TEXT
!= nch
->type
)
1780 while ('\0' != *(++cp
))
1782 isalpha((unsigned char)cp
[-1]) &&
1783 isalpha((unsigned char)cp
[1]))
1789 post_hyphtext(POST_ARGS
)
1800 if (MDOC_LINE
& mdoc
->last
->flags
)
1801 mandoc_msg(MANDOCERR_NS_SKIP
, mdoc
->parse
,
1802 mdoc
->last
->line
, mdoc
->last
->pos
, NULL
);
1811 switch (mdoc
->last
->type
) {
1816 switch (mdoc
->lastsec
) {
1821 post_sh_see_also(mdoc
);
1824 post_sh_authors(mdoc
);
1836 post_sh_name(POST_ARGS
)
1838 struct mdoc_node
*n
;
1841 * Warn if the NAME section doesn't contain the `Nm' and `Nd'
1842 * macros (can have multiple `Nm' and one `Nd'). Note that the
1843 * children of the BODY declaration can also be "text".
1846 if (NULL
== (n
= mdoc
->last
->child
)) {
1847 mandoc_msg(MANDOCERR_NAMESEC_BAD
, mdoc
->parse
,
1848 mdoc
->last
->line
, mdoc
->last
->pos
, "empty");
1852 for ( ; n
&& n
->next
; n
= n
->next
) {
1853 if (MDOC_ELEM
== n
->type
&& MDOC_Nm
== n
->tok
)
1855 if (MDOC_TEXT
== n
->type
)
1857 mandoc_msg(MANDOCERR_NAMESEC_BAD
, mdoc
->parse
,
1858 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
1862 if (MDOC_BLOCK
== n
->type
&& MDOC_Nd
== n
->tok
)
1865 mandoc_msg(MANDOCERR_NAMESEC_BAD
, mdoc
->parse
,
1866 n
->line
, n
->pos
, mdoc_macronames
[n
->tok
]);
1870 post_sh_see_also(POST_ARGS
)
1872 const struct mdoc_node
*n
;
1873 const char *name
, *sec
;
1874 const char *lastname
, *lastsec
, *lastpunct
;
1877 n
= mdoc
->last
->child
;
1878 lastname
= lastsec
= lastpunct
= NULL
;
1880 if (n
->tok
!= MDOC_Xr
|| n
->nchild
< 2)
1883 /* Process one .Xr node. */
1885 name
= n
->child
->string
;
1886 sec
= n
->child
->next
->string
;
1887 if (lastsec
!= NULL
) {
1888 if (lastpunct
[0] != ',' || lastpunct
[1] != '\0')
1889 mandoc_vmsg(MANDOCERR_XR_PUNCT
,
1890 mdoc
->parse
, n
->line
, n
->pos
,
1891 "%s before %s(%s)", lastpunct
,
1893 cmp
= strcmp(lastsec
, sec
);
1895 mandoc_vmsg(MANDOCERR_XR_ORDER
,
1896 mdoc
->parse
, n
->line
, n
->pos
,
1897 "%s(%s) after %s(%s)", name
,
1898 sec
, lastname
, lastsec
);
1899 else if (cmp
== 0 &&
1900 strcasecmp(lastname
, name
) > 0)
1901 mandoc_vmsg(MANDOCERR_XR_ORDER
,
1902 mdoc
->parse
, n
->line
, n
->pos
,
1903 "%s after %s", name
, lastname
);
1908 /* Process the following node. */
1913 if (n
->tok
== MDOC_Xr
) {
1917 if (n
->type
!= MDOC_TEXT
)
1919 for (name
= n
->string
; *name
!= '\0'; name
++)
1920 if (isalpha((const unsigned char)*name
))
1922 lastpunct
= n
->string
;
1923 if (n
->next
== NULL
)
1924 mandoc_vmsg(MANDOCERR_XR_PUNCT
, mdoc
->parse
,
1925 n
->line
, n
->pos
, "%s after %s(%s)",
1926 lastpunct
, lastname
, lastsec
);
1932 child_an(const struct mdoc_node
*n
)
1935 for (n
= n
->child
; n
!= NULL
; n
= n
->next
)
1936 if ((n
->tok
== MDOC_An
&& n
->nchild
) || child_an(n
))
1942 post_sh_authors(POST_ARGS
)
1945 if ( ! child_an(mdoc
->last
))
1946 mandoc_msg(MANDOCERR_AN_MISSING
, mdoc
->parse
,
1947 mdoc
->last
->line
, mdoc
->last
->pos
, NULL
);
1951 post_sh_head(POST_ARGS
)
1953 struct mdoc_node
*n
;
1954 const char *goodsec
;
1959 * Process a new section. Sections are either "named" or
1960 * "custom". Custom sections are user-defined, while named ones
1961 * follow a conventional order and may only appear in certain
1967 mdoc_deroff(&secname
, mdoc
->last
);
1968 sec
= NULL
== secname
? SEC_CUSTOM
: a2sec(secname
);
1970 /* The NAME should be first. */
1972 if (SEC_NAME
!= sec
&& SEC_NONE
== mdoc
->lastnamed
)
1973 mandoc_vmsg(MANDOCERR_NAMESEC_FIRST
, mdoc
->parse
,
1974 mdoc
->last
->line
, mdoc
->last
->pos
,
1977 /* The SYNOPSIS gets special attention in other areas. */
1979 if (SEC_SYNOPSIS
== sec
) {
1980 roff_setreg(mdoc
->roff
, "nS", 1, '=');
1981 mdoc
->flags
|= MDOC_SYNOPSIS
;
1983 roff_setreg(mdoc
->roff
, "nS", 0, '=');
1984 mdoc
->flags
&= ~MDOC_SYNOPSIS
;
1987 /* Mark our last section. */
1989 mdoc
->lastsec
= sec
;
1992 * Set the section attribute for the current HEAD, for its
1993 * parent BLOCK, and for the HEAD children; the latter can
1994 * only be TEXT nodes, so no recursion is needed.
1995 * For other blocks and elements, including .Sh BODY, this is
1996 * done when allocating the node data structures, but for .Sh
1997 * BLOCK and HEAD, the section is still unknown at that time.
2000 mdoc
->last
->parent
->sec
= sec
;
2001 mdoc
->last
->sec
= sec
;
2002 for (n
= mdoc
->last
->child
; n
; n
= n
->next
)
2005 /* We don't care about custom sections after this. */
2007 if (SEC_CUSTOM
== sec
) {
2013 * Check whether our non-custom section is being repeated or is
2017 if (sec
== mdoc
->lastnamed
)
2018 mandoc_vmsg(MANDOCERR_SEC_REP
, mdoc
->parse
,
2019 mdoc
->last
->line
, mdoc
->last
->pos
,
2022 if (sec
< mdoc
->lastnamed
)
2023 mandoc_vmsg(MANDOCERR_SEC_ORDER
, mdoc
->parse
,
2024 mdoc
->last
->line
, mdoc
->last
->pos
,
2027 /* Mark the last named section. */
2029 mdoc
->lastnamed
= sec
;
2031 /* Check particular section/manual conventions. */
2033 if (mdoc
->meta
.msec
== NULL
) {
2041 if (*mdoc
->meta
.msec
== '4')
2043 goodsec
= "2, 3, 4, 9";
2045 case SEC_RETURN_VALUES
:
2048 if (*mdoc
->meta
.msec
== '2')
2050 if (*mdoc
->meta
.msec
== '3')
2052 if (NULL
== goodsec
)
2053 goodsec
= "2, 3, 9";
2056 if (*mdoc
->meta
.msec
== '9')
2058 if (NULL
== goodsec
)
2060 mandoc_vmsg(MANDOCERR_SEC_MSEC
, mdoc
->parse
,
2061 mdoc
->last
->line
, mdoc
->last
->pos
,
2062 "Sh %s for %s only", secname
, goodsec
);
2071 post_ignpar(POST_ARGS
)
2073 struct mdoc_node
*np
;
2075 check_count(mdoc
, MDOC_HEAD
, CHECK_WARN
, CHECK_GT
, 0);
2078 if (MDOC_BODY
!= mdoc
->last
->type
)
2081 if (NULL
!= (np
= mdoc
->last
->child
))
2082 if (MDOC_Pp
== np
->tok
|| MDOC_Lp
== np
->tok
) {
2083 mandoc_vmsg(MANDOCERR_PAR_SKIP
,
2084 mdoc
->parse
, np
->line
, np
->pos
,
2085 "%s after %s", mdoc_macronames
[np
->tok
],
2086 mdoc_macronames
[mdoc
->last
->tok
]);
2087 mdoc_node_delete(mdoc
, np
);
2090 if (NULL
!= (np
= mdoc
->last
->last
))
2091 if (MDOC_Pp
== np
->tok
|| MDOC_Lp
== np
->tok
) {
2092 mandoc_vmsg(MANDOCERR_PAR_SKIP
, mdoc
->parse
,
2093 np
->line
, np
->pos
, "%s at the end of %s",
2094 mdoc_macronames
[np
->tok
],
2095 mdoc_macronames
[mdoc
->last
->tok
]);
2096 mdoc_node_delete(mdoc
, np
);
2104 if (NULL
== mdoc
->last
)
2106 if (MDOC_ELEM
!= n
->type
&& MDOC_BLOCK
!= n
->type
)
2110 * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
2111 * block: `Lp', `Pp', or non-compact `Bd' or `Bl'.
2114 if (MDOC_Pp
!= mdoc
->last
->tok
&&
2115 MDOC_Lp
!= mdoc
->last
->tok
&&
2116 MDOC_br
!= mdoc
->last
->tok
)
2118 if (MDOC_Bl
== n
->tok
&& n
->norm
->Bl
.comp
)
2120 if (MDOC_Bd
== n
->tok
&& n
->norm
->Bd
.comp
)
2122 if (MDOC_It
== n
->tok
&& n
->parent
->norm
->Bl
.comp
)
2125 mandoc_vmsg(MANDOCERR_PAR_SKIP
, mdoc
->parse
,
2126 mdoc
->last
->line
, mdoc
->last
->pos
,
2127 "%s before %s", mdoc_macronames
[mdoc
->last
->tok
],
2128 mdoc_macronames
[n
->tok
]);
2129 mdoc_node_delete(mdoc
, mdoc
->last
);
2135 struct mdoc_node
*np
;
2137 if (mdoc
->last
->tok
== MDOC_sp
)
2138 check_count(mdoc
, MDOC_ELEM
, CHECK_WARN
, CHECK_LT
, 2);
2140 check_count(mdoc
, MDOC_ELEM
, CHECK_WARN
, CHECK_EQ
, 0);
2142 if (MDOC_ELEM
!= mdoc
->last
->type
&&
2143 MDOC_BLOCK
!= mdoc
->last
->type
)
2146 if (NULL
== (np
= mdoc
->last
->prev
)) {
2147 np
= mdoc
->last
->parent
;
2148 if (MDOC_Sh
!= np
->tok
&& MDOC_Ss
!= np
->tok
)
2150 } else if (MDOC_Pp
!= np
->tok
&& MDOC_Lp
!= np
->tok
&&
2151 (MDOC_br
!= mdoc
->last
->tok
||
2152 (MDOC_sp
!= np
->tok
&& MDOC_br
!= np
->tok
)))
2155 mandoc_vmsg(MANDOCERR_PAR_SKIP
, mdoc
->parse
,
2156 mdoc
->last
->line
, mdoc
->last
->pos
,
2157 "%s after %s", mdoc_macronames
[mdoc
->last
->tok
],
2158 mdoc_macronames
[np
->tok
]);
2159 mdoc_node_delete(mdoc
, mdoc
->last
);
2163 pre_literal(PRE_ARGS
)
2166 pre_display(mdoc
, n
);
2168 if (MDOC_BODY
!= n
->type
)
2172 * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd
2173 * -unfilled' macros set MDOC_LITERAL on entrance to the body.
2178 mdoc
->flags
|= MDOC_LITERAL
;
2181 if (DISP_literal
== n
->norm
->Bd
.type
)
2182 mdoc
->flags
|= MDOC_LITERAL
;
2183 if (DISP_unfilled
== n
->norm
->Bd
.type
)
2184 mdoc
->flags
|= MDOC_LITERAL
;
2195 struct mdoc_node
*n
;
2198 if (mdoc
->meta
.date
)
2199 free(mdoc
->meta
.date
);
2202 if (NULL
== n
->child
|| '\0' == n
->child
->string
[0]) {
2203 mdoc
->meta
.date
= mdoc
->quick
? mandoc_strdup("") :
2204 mandoc_normdate(mdoc
->parse
, NULL
, n
->line
, n
->pos
);
2209 mdoc_deroff(&datestr
, n
);
2211 mdoc
->meta
.date
= datestr
;
2213 mdoc
->meta
.date
= mandoc_normdate(mdoc
->parse
,
2214 datestr
, n
->line
, n
->pos
);
2218 mdoc_node_delete(mdoc
, n
);
2224 struct mdoc_node
*nn
, *n
;
2230 free(mdoc
->meta
.title
);
2231 free(mdoc
->meta
.msec
);
2232 free(mdoc
->meta
.vol
);
2233 free(mdoc
->meta
.arch
);
2235 mdoc
->meta
.title
= NULL
;
2236 mdoc
->meta
.msec
= NULL
;
2237 mdoc
->meta
.vol
= NULL
;
2238 mdoc
->meta
.arch
= NULL
;
2240 /* First check that all characters are uppercase. */
2242 if (NULL
!= (nn
= n
->child
))
2243 for (p
= nn
->string
; *p
; p
++) {
2244 if (toupper((unsigned char)*p
) == *p
)
2246 mandoc_vmsg(MANDOCERR_TITLE_CASE
,
2247 mdoc
->parse
, nn
->line
,
2248 nn
->pos
+ (p
- nn
->string
),
2249 "Dt %s", nn
->string
);
2253 /* No argument: msec and arch remain NULL. */
2255 if (NULL
== (nn
= n
->child
)) {
2256 mandoc_msg(MANDOCERR_DT_NOTITLE
,
2257 mdoc
->parse
, n
->line
, n
->pos
, "Dt");
2258 mdoc
->meta
.title
= mandoc_strdup("UNTITLED");
2259 mdoc
->meta
.vol
= mandoc_strdup("LOCAL");
2263 /* One argument: msec and arch remain NULL. */
2265 mdoc
->meta
.title
= mandoc_strdup(
2266 '\0' == nn
->string
[0] ? "UNTITLED" : nn
->string
);
2268 if (NULL
== (nn
= nn
->next
)) {
2269 mandoc_vmsg(MANDOCERR_MSEC_MISSING
,
2270 mdoc
->parse
, n
->line
, n
->pos
,
2271 "Dt %s", mdoc
->meta
.title
);
2272 mdoc
->meta
.vol
= mandoc_strdup("LOCAL");
2276 /* Handles: `.Dt TITLE SEC'
2278 * volume = SEC is msec ? format(msec) : SEC,
2279 * msec = SEC is msec ? atoi(msec) : 0,
2283 cp
= mandoc_a2msec(nn
->string
);
2285 mdoc
->meta
.vol
= mandoc_strdup(cp
);
2286 mdoc
->meta
.msec
= mandoc_strdup(nn
->string
);
2288 mandoc_vmsg(MANDOCERR_MSEC_BAD
, mdoc
->parse
,
2289 nn
->line
, nn
->pos
, "Dt ... %s", nn
->string
);
2290 mdoc
->meta
.vol
= mandoc_strdup(nn
->string
);
2291 mdoc
->meta
.msec
= mandoc_strdup(nn
->string
);
2294 /* Handle an optional architecture */
2296 if ((nn
= nn
->next
) != NULL
) {
2297 for (p
= nn
->string
; *p
; p
++)
2298 *p
= tolower((unsigned char)*p
);
2299 mdoc
->meta
.arch
= mandoc_strdup(nn
->string
);
2302 /* Ignore any subsequent parameters... */
2303 /* FIXME: warn about subsequent parameters. */
2305 mdoc_node_delete(mdoc
, n
);
2311 struct mdoc_node
*n
;
2314 * Make `Bx's second argument always start with an uppercase
2315 * letter. Groff checks if it's an "accepted" term, but we just
2316 * uppercase blindly.
2319 n
= mdoc
->last
->child
;
2320 if (n
&& NULL
!= (n
= n
->next
))
2321 *n
->string
= (char)toupper((unsigned char)*n
->string
);
2328 struct utsname utsname
;
2329 static char *defbuf
;
2331 struct mdoc_node
*n
;
2336 * Set the operating system by way of the `Os' macro.
2337 * The order of precedence is:
2338 * 1. the argument of the `Os' macro, unless empty
2339 * 2. the -Ios=foo command line argument, if provided
2340 * 3. -DOSNAME="\"foo\"", if provided during compilation
2341 * 4. "sysname release" from uname(3)
2344 free(mdoc
->meta
.os
);
2345 mdoc
->meta
.os
= NULL
;
2346 mdoc_deroff(&mdoc
->meta
.os
, n
);
2351 mdoc
->meta
.os
= mandoc_strdup(mdoc
->defos
);
2356 mdoc
->meta
.os
= mandoc_strdup(OSNAME
);
2358 if (NULL
== defbuf
) {
2359 if (-1 == uname(&utsname
)) {
2360 mandoc_msg(MANDOCERR_OS_UNAME
, mdoc
->parse
,
2361 n
->line
, n
->pos
, "Os");
2362 defbuf
= mandoc_strdup("UNKNOWN");
2364 mandoc_asprintf(&defbuf
, "%s %s",
2365 utsname
.sysname
, utsname
.release
);
2367 mdoc
->meta
.os
= mandoc_strdup(defbuf
);
2371 mdoc_node_delete(mdoc
, n
);
2375 * If no argument is provided,
2376 * fill in the name of the current manual page.
2381 struct mdoc_node
*n
;
2388 if (mdoc
->meta
.name
== NULL
) {
2389 mandoc_msg(MANDOCERR_EX_NONAME
, mdoc
->parse
,
2390 n
->line
, n
->pos
, "Ex");
2394 mdoc
->next
= MDOC_NEXT_CHILD
;
2395 mdoc_word_alloc(mdoc
, n
->line
, n
->pos
, mdoc
->meta
.name
);
2399 static enum mdoc_sec
2400 a2sec(const char *p
)
2404 for (i
= 0; i
< (int)SEC__MAX
; i
++)
2405 if (secnames
[i
] && 0 == strcmp(p
, secnames
[i
]))
2406 return((enum mdoc_sec
)i
);
2412 macro2len(enum mdoct macro
)