1 /* $Id: mdoc_validate.c,v 1.182 2012/03/23 05:50:25 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2010, 2011 Ingo Schwarze <schwarze@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #ifndef OSNAME
23 #include <sys/utsname.h>
24 #endif
80 static int berr_ge1(POST_ARGS);
81 static int bwarn_ge1(POST_ARGS);
82 static int ewarn_eq0(POST_ARGS);
83 static int ewarn_eq1(POST_ARGS);
84 static int ewarn_ge1(POST_ARGS);
85 static int ewarn_le1(POST_ARGS);
86 static int hwarn_eq0(POST_ARGS);
87 static int hwarn_eq1(POST_ARGS);
88 static int hwarn_ge1(POST_ARGS);
89 static int hwarn_le1(POST_ARGS);
90
91 static int post_an(POST_ARGS);
92 static int post_at(POST_ARGS);
93 static int post_bf(POST_ARGS);
94 static int post_bl(POST_ARGS);
95 static int post_bl_block(POST_ARGS);
96 static int post_bl_block_width(POST_ARGS);
97 static int post_bl_block_tag(POST_ARGS);
98 static int post_bl_head(POST_ARGS);
99 static int post_bx(POST_ARGS);
100 static int post_dd(POST_ARGS);
101 static int post_dt(POST_ARGS);
102 static int post_defaults(POST_ARGS);
103 static int post_literal(POST_ARGS);
104 static int post_eoln(POST_ARGS);
105 static int post_it(POST_ARGS);
106 static int post_lb(POST_ARGS);
107 static int post_nm(POST_ARGS);
108 static int post_ns(POST_ARGS);
109 static int post_os(POST_ARGS);
110 static int post_ignpar(POST_ARGS);
111 static int post_prol(POST_ARGS);
112 static int post_root(POST_ARGS);
113 static int post_rs(POST_ARGS);
114 static int post_sh(POST_ARGS);
115 static int post_sh_body(POST_ARGS);
116 static int post_sh_head(POST_ARGS);
117 static int post_st(POST_ARGS);
118 static int post_std(POST_ARGS);
119 static int post_vt(POST_ARGS);
120 static int pre_an(PRE_ARGS);
121 static int pre_bd(PRE_ARGS);
122 static int pre_bl(PRE_ARGS);
123 static int pre_dd(PRE_ARGS);
124 static int pre_display(PRE_ARGS);
125 static int pre_dt(PRE_ARGS);
126 static int pre_it(PRE_ARGS);
127 static int pre_literal(PRE_ARGS);
128 static int pre_os(PRE_ARGS);
129 static int pre_par(PRE_ARGS);
130 static int pre_sh(PRE_ARGS);
131 static int pre_ss(PRE_ARGS);
132 static int pre_std(PRE_ARGS);
133
134 static v_post posts_an[] = { post_an, NULL };
135 static v_post posts_at[] = { post_at, post_defaults, NULL };
136 static v_post posts_bd[] = { post_literal, hwarn_eq0, bwarn_ge1, NULL };
137 static v_post posts_bf[] = { hwarn_le1, post_bf, NULL };
138 static v_post posts_bk[] = { hwarn_eq0, bwarn_ge1, NULL };
139 static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL };
140 static v_post posts_bx[] = { post_bx, NULL };
141 static v_post posts_bool[] = { ebool, NULL };
142 static v_post posts_eoln[] = { post_eoln, NULL };
143 static v_post posts_defaults[] = { post_defaults, NULL };
144 static v_post posts_dd[] = { post_dd, post_prol, NULL };
145 static v_post posts_dl[] = { post_literal, bwarn_ge1, NULL };
146 static v_post posts_dt[] = { post_dt, post_prol, NULL };
147 static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL };
148 static v_post posts_it[] = { post_it, NULL };
149 static v_post posts_lb[] = { post_lb, NULL };
150 static v_post posts_nd[] = { berr_ge1, NULL };
151 static v_post posts_nm[] = { post_nm, NULL };
152 static v_post posts_notext[] = { ewarn_eq0, NULL };
153 static v_post posts_ns[] = { post_ns, NULL };
154 static v_post posts_os[] = { post_os, post_prol, NULL };
155 static v_post posts_rs[] = { post_rs, NULL };
156 static v_post posts_sh[] = { post_ignpar, hwarn_ge1, post_sh, NULL };
157 static v_post posts_sp[] = { ewarn_le1, NULL };
158 static v_post posts_ss[] = { post_ignpar, hwarn_ge1, NULL };
159 static v_post posts_st[] = { post_st, NULL };
160 static v_post posts_std[] = { post_std, NULL };
161 static v_post posts_text[] = { ewarn_ge1, NULL };
162 static v_post posts_text1[] = { ewarn_eq1, NULL };
163 static v_post posts_vt[] = { post_vt, NULL };
164 static v_post posts_wline[] = { bwarn_ge1, NULL };
165 static v_pre pres_an[] = { pre_an, NULL };
166 static v_pre pres_bd[] = { pre_display, pre_bd, pre_literal, pre_par, NULL };
167 static v_pre pres_bl[] = { pre_bl, pre_par, NULL };
168 static v_pre pres_d1[] = { pre_display, NULL };
169 static v_pre pres_dl[] = { pre_literal, pre_display, NULL };
170 static v_pre pres_dd[] = { pre_dd, NULL };
171 static v_pre pres_dt[] = { pre_dt, NULL };
172 static v_pre pres_er[] = { NULL, NULL };
173 static v_pre pres_fd[] = { NULL, NULL };
174 static v_pre pres_it[] = { pre_it, pre_par, NULL };
175 static v_pre pres_os[] = { pre_os, NULL };
176 static v_pre pres_pp[] = { pre_par, NULL };
177 static v_pre pres_sh[] = { pre_sh, NULL };
178 static v_pre pres_ss[] = { pre_ss, NULL };
179 static v_pre pres_std[] = { pre_std, NULL };
180
181 static const struct valids mdoc_valids[MDOC_MAX] = {
182 { NULL, NULL }, /* Ap */
183 { pres_dd, posts_dd }, /* Dd */
184 { pres_dt, posts_dt }, /* Dt */
185 { pres_os, posts_os }, /* Os */
186 { pres_sh, posts_sh }, /* Sh */
187 { pres_ss, posts_ss }, /* Ss */
188 { pres_pp, posts_notext }, /* Pp */
189 { pres_d1, posts_wline }, /* D1 */
190 { pres_dl, posts_dl }, /* Dl */
191 { pres_bd, posts_bd }, /* Bd */
192 { NULL, NULL }, /* Ed */
193 { pres_bl, posts_bl }, /* Bl */
194 { NULL, NULL }, /* El */
195 { pres_it, posts_it }, /* It */
196 { NULL, NULL }, /* Ad */
197 { pres_an, posts_an }, /* An */
198 { NULL, posts_defaults }, /* Ar */
199 { NULL, NULL }, /* Cd */
200 { NULL, NULL }, /* Cm */
201 { NULL, NULL }, /* Dv */
202 { pres_er, NULL }, /* Er */
203 { NULL, NULL }, /* Ev */
204 { pres_std, posts_std }, /* Ex */
205 { NULL, NULL }, /* Fa */
206 { pres_fd, posts_text }, /* Fd */
207 { NULL, NULL }, /* Fl */
208 { NULL, NULL }, /* Fn */
209 { NULL, NULL }, /* Ft */
210 { NULL, NULL }, /* Ic */
211 { NULL, posts_text1 }, /* In */
212 { NULL, posts_defaults }, /* Li */
213 { NULL, posts_nd }, /* Nd */
214 { NULL, posts_nm }, /* Nm */
215 { NULL, NULL }, /* Op */
216 { NULL, NULL }, /* Ot */
217 { NULL, posts_defaults }, /* Pa */
218 { pres_std, posts_std }, /* Rv */
219 { NULL, posts_st }, /* St */
220 { NULL, NULL }, /* Va */
221 { NULL, posts_vt }, /* Vt */
222 { NULL, posts_text }, /* Xr */
223 { NULL, posts_text }, /* %A */
224 { NULL, posts_text }, /* %B */ /* FIXME: can be used outside Rs/Re. */
225 { NULL, posts_text }, /* %D */
226 { NULL, posts_text }, /* %I */
227 { NULL, posts_text }, /* %J */
228 { NULL, posts_text }, /* %N */
229 { NULL, posts_text }, /* %O */
230 { NULL, posts_text }, /* %P */
231 { NULL, posts_text }, /* %R */
232 { NULL, posts_text }, /* %T */ /* FIXME: can be used outside Rs/Re. */
233 { NULL, posts_text }, /* %V */
234 { NULL, NULL }, /* Ac */
235 { NULL, NULL }, /* Ao */
236 { NULL, NULL }, /* Aq */
237 { NULL, posts_at }, /* At */
238 { NULL, NULL }, /* Bc */
239 { NULL, posts_bf }, /* Bf */
240 { NULL, NULL }, /* Bo */
241 { NULL, NULL }, /* Bq */
242 { NULL, NULL }, /* Bsx */
243 { NULL, posts_bx }, /* Bx */
244 { NULL, posts_bool }, /* Db */
245 { NULL, NULL }, /* Dc */
246 { NULL, NULL }, /* Do */
247 { NULL, NULL }, /* Dq */
248 { NULL, NULL }, /* Ec */
249 { NULL, NULL }, /* Ef */
250 { NULL, NULL }, /* Em */
251 { NULL, NULL }, /* Eo */
252 { NULL, NULL }, /* Fx */
253 { NULL, NULL }, /* Ms */
254 { NULL, posts_notext }, /* No */
255 { NULL, posts_ns }, /* Ns */
256 { NULL, NULL }, /* Nx */
257 { NULL, NULL }, /* Ox */
258 { NULL, NULL }, /* Pc */
259 { NULL, posts_text1 }, /* Pf */
260 { NULL, NULL }, /* Po */
261 { NULL, NULL }, /* Pq */
262 { NULL, NULL }, /* Qc */
263 { NULL, NULL }, /* Ql */
264 { NULL, NULL }, /* Qo */
265 { NULL, NULL }, /* Qq */
266 { NULL, NULL }, /* Re */
267 { NULL, posts_rs }, /* Rs */
268 { NULL, NULL }, /* Sc */
269 { NULL, NULL }, /* So */
270 { NULL, NULL }, /* Sq */
271 { NULL, posts_bool }, /* Sm */
272 { NULL, NULL }, /* Sx */
273 { NULL, NULL }, /* Sy */
274 { NULL, NULL }, /* Tn */
275 { NULL, NULL }, /* Ux */
276 { NULL, NULL }, /* Xc */
277 { NULL, NULL }, /* Xo */
278 { NULL, posts_fo }, /* Fo */
279 { NULL, NULL }, /* Fc */
280 { NULL, NULL }, /* Oo */
281 { NULL, NULL }, /* Oc */
282 { NULL, posts_bk }, /* Bk */
283 { NULL, NULL }, /* Ek */
284 { NULL, posts_eoln }, /* Bt */
285 { NULL, NULL }, /* Hf */
286 { NULL, NULL }, /* Fr */
287 { NULL, posts_eoln }, /* Ud */
288 { NULL, posts_lb }, /* Lb */
289 { NULL, posts_notext }, /* Lp */
290 { NULL, NULL }, /* Lk */
291 { NULL, posts_defaults }, /* Mt */
292 { NULL, NULL }, /* Brq */
293 { NULL, NULL }, /* Bro */
294 { NULL, NULL }, /* Brc */
295 { NULL, posts_text }, /* %C */
296 { NULL, NULL }, /* Es */
297 { NULL, NULL }, /* En */
298 { NULL, NULL }, /* Dx */
299 { NULL, posts_text }, /* %Q */
300 { NULL, posts_notext }, /* br */
301 { pres_pp, posts_sp }, /* sp */
302 { NULL, posts_text1 }, /* %U */
303 { NULL, NULL }, /* Ta */
304 };
305
306 #define RSORD_MAX 14 /* Number of `Rs' blocks. */
307
308 static const enum mdoct rsord[RSORD_MAX] = {
309 MDOC__A,
310 MDOC__T,
311 MDOC__B,
312 MDOC__I,
313 MDOC__J,
314 MDOC__R,
315 MDOC__N,
316 MDOC__V,
317 MDOC__P,
318 MDOC__Q,
319 MDOC__D,
320 MDOC__O,
321 MDOC__C,
322 MDOC__U
323 };
324
325 static const char * const secnames[SEC__MAX] = {
326 NULL,
327 "NAME",
328 "LIBRARY",
329 "SYNOPSIS",
330 "DESCRIPTION",
331 "IMPLEMENTATION NOTES",
332 "RETURN VALUES",
333 "ENVIRONMENT",
334 "FILES",
335 "EXIT STATUS",
336 "EXAMPLES",
337 "DIAGNOSTICS",
338 "COMPATIBILITY",
339 "ERRORS",
340 "SEE ALSO",
341 "STANDARDS",
342 "HISTORY",
397 case (MDOC_EQN):
398 /* FALLTHROUGH */
399 case (MDOC_TBL):
400 return(1);
401 case (MDOC_ROOT):
402 return(post_root(mdoc));
403 default:
404 break;
405 }
406
407 if (NULL == mdoc_valids[mdoc->last->tok].post)
408 return(1);
409 for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
410 if ( ! (*p)(mdoc))
411 return(0);
412
413 return(1);
414 }
415
416 static int
417 check_count(struct mdoc *m, enum mdoc_type type,
418 enum check_lvl lvl, enum check_ineq ineq, int val)
419 {
420 const char *p;
421 enum mandocerr t;
422
423 if (m->last->type != type)
424 return(1);
425
426 switch (ineq) {
427 case (CHECK_LT):
428 p = "less than ";
429 if (m->last->nchild < val)
430 return(1);
431 break;
432 case (CHECK_GT):
433 p = "more than ";
434 if (m->last->nchild > val)
435 return(1);
436 break;
437 case (CHECK_EQ):
438 p = "";
439 if (val == m->last->nchild)
440 return(1);
441 break;
442 default:
443 abort();
444 /* NOTREACHED */
445 }
446
447 t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT;
448 mandoc_vmsg(t, m->parse, m->last->line, m->last->pos,
449 "want %s%d children (have %d)",
450 p, val, m->last->nchild);
451 return(1);
452 }
453
454 static int
455 berr_ge1(POST_ARGS)
456 {
457
458 return(check_count(mdoc, MDOC_BODY, CHECK_ERROR, CHECK_GT, 0));
459 }
460
461 static int
462 bwarn_ge1(POST_ARGS)
463 {
464 return(check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0));
465 }
466
467 static int
468 ewarn_eq0(POST_ARGS)
469 {
470 return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0));
496
497 static int
498 hwarn_eq1(POST_ARGS)
499 {
500 return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 1));
501 }
502
503 static int
504 hwarn_ge1(POST_ARGS)
505 {
506 return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_GT, 0));
507 }
508
509 static int
510 hwarn_le1(POST_ARGS)
511 {
512 return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_LT, 2));
513 }
514
515 static void
516 check_args(struct mdoc *m, struct mdoc_node *n)
517 {
518 int i;
519
520 if (NULL == n->args)
521 return;
522
523 assert(n->args->argc);
524 for (i = 0; i < (int)n->args->argc; i++)
525 check_argv(m, n, &n->args->argv[i]);
526 }
527
528 static void
529 check_argv(struct mdoc *m, struct mdoc_node *n, struct mdoc_argv *v)
530 {
531 int i;
532
533 for (i = 0; i < (int)v->sz; i++)
534 check_text(m, v->line, v->pos, v->value[i]);
535
536 /* FIXME: move to post_std(). */
537
538 if (MDOC_Std == v->arg)
539 if ( ! (v->sz || m->meta.name))
540 mdoc_nmsg(m, n, MANDOCERR_NONAME);
541 }
542
543 static void
544 check_text(struct mdoc *m, int ln, int pos, char *p)
545 {
546 char *cp;
547
548 if (MDOC_LITERAL & m->flags)
549 return;
550
551 for (cp = p; NULL != (p = strchr(p, '\t')); p++)
552 mdoc_pmsg(m, ln, pos + (int)(p - cp), MANDOCERR_BADTAB);
553 }
554
555 static int
556 check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t)
557 {
558
559 assert(n->parent);
560 if ((MDOC_ROOT == t || tok == n->parent->tok) &&
561 (t == n->parent->type))
562 return(1);
563
564 mandoc_vmsg(MANDOCERR_SYNTCHILD, mdoc->parse, n->line,
565 n->pos, "want parent %s", MDOC_ROOT == t ?
566 "<root>" : mdoc_macronames[tok]);
567 return(0);
568 }
569
570
571 static int
572 pre_display(PRE_ARGS)
716
717 if (n->norm->Bl.type == LIST__NONE)
718 if (n->norm->Bl.width ||
719 n->norm->Bl.offs ||
720 n->norm->Bl.comp)
721 mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST);
722
723 continue;
724 }
725
726 /* Allow lists to default to LIST_item. */
727
728 if (LIST__NONE == n->norm->Bl.type) {
729 mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE);
730 n->norm->Bl.type = LIST_item;
731 }
732
733 /*
734 * Validate the width field. Some list types don't need width
735 * types and should be warned about them. Others should have it
736 * and must also be warned.
737 */
738
739 switch (n->norm->Bl.type) {
740 case (LIST_tag):
741 if (n->norm->Bl.width)
742 break;
743 mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG);
744 break;
745 case (LIST_column):
746 /* FALLTHROUGH */
747 case (LIST_diag):
748 /* FALLTHROUGH */
749 case (LIST_ohang):
750 /* FALLTHROUGH */
751 case (LIST_inset):
752 /* FALLTHROUGH */
753 case (LIST_item):
754 if (n->norm->Bl.width)
755 mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
756 break;
757 default:
758 break;
759 }
760
761 return(1);
762 }
763
764
765 static int
766 pre_bd(PRE_ARGS)
767 {
768 int i, dup, comp;
769 enum mdoc_disp dt;
770 const char *offs;
771 struct mdoc_node *np;
772
773 if (MDOC_BLOCK != n->type) {
774 if (ENDBODY_NOT != n->end) {
775 assert(n->pending);
776 np = n->pending->parent;
857 return(1);
858 }
859
860
861 static int
862 pre_ss(PRE_ARGS)
863 {
864
865 if (MDOC_BLOCK != n->type)
866 return(1);
867 return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY));
868 }
869
870
871 static int
872 pre_sh(PRE_ARGS)
873 {
874
875 if (MDOC_BLOCK != n->type)
876 return(1);
877
878 roff_regunset(mdoc->roff, REG_nS);
879 return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT));
880 }
881
882
883 static int
884 pre_it(PRE_ARGS)
885 {
886
887 if (MDOC_BLOCK != n->type)
888 return(1);
889
890 return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY));
891 }
892
893
894 static int
895 pre_an(PRE_ARGS)
896 {
897 int i;
898
1094 * specifically the BODY, should only have TEXT children.
1095 */
1096
1097 if (MDOC_BODY != mdoc->last->type)
1098 return(1);
1099
1100 for (n = mdoc->last->child; n; n = n->next)
1101 if (MDOC_TEXT != n->type)
1102 mdoc_nmsg(mdoc, n, MANDOCERR_CHILD);
1103
1104 return(1);
1105 }
1106
1107
1108 static int
1109 post_nm(POST_ARGS)
1110 {
1111 char buf[BUFSIZ];
1112 int c;
1113
1114 /* If no child specified, make sure we have the meta name. */
1115
1116 if (NULL == mdoc->last->child && NULL == mdoc->meta.name) {
1117 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME);
1118 return(1);
1119 } else if (mdoc->meta.name)
1120 return(1);
1121
1122 /* If no meta name, set it from the child. */
1123
1124 buf[0] = '\0';
1125 if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) {
1126 mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
1127 return(0);
1128 }
1129
1130 assert(c);
1131 mdoc->meta.name = mandoc_strdup(buf);
1132 return(1);
1133 }
1134
1135 static int
1136 post_literal(POST_ARGS)
1137 {
1138
1139 /*
1140 * The `Dl' (note "el" not "one") and `Bd' macros unset the
1141 * MDOC_LITERAL flag as they leave. Note that `Bd' only sets
1142 * this in literal mode, but it doesn't hurt to just switch it
1143 * off in general since displays can't be nested.
1144 */
1145
1146 if (MDOC_BODY == mdoc->last->type)
1147 mdoc->flags &= ~MDOC_LITERAL;
1148
1149 return(1);
1150 }
1151
1317 er = MANDOCERR_ARGCOUNT;
1318 else if (i == cols || i == cols + 1)
1319 break;
1320 else
1321 er = MANDOCERR_SYNTARGCOUNT;
1322
1323 mandoc_vmsg(er, mdoc->parse, mdoc->last->line,
1324 mdoc->last->pos,
1325 "columns == %d (have %d)", cols, i);
1326 return(MANDOCERR_ARGCOUNT == er);
1327 default:
1328 break;
1329 }
1330
1331 return(1);
1332 }
1333
1334 static int
1335 post_bl_block(POST_ARGS)
1336 {
1337 struct mdoc_node *n;
1338
1339 /*
1340 * These are fairly complicated, so we've broken them into two
1341 * functions. post_bl_block_tag() is called when a -tag is
1342 * specified, but no -width (it must be guessed). The second
1343 * when a -width is specified (macro indicators must be
1344 * rewritten into real lengths).
1345 */
1346
1347 n = mdoc->last;
1348
1349 if (LIST_tag == n->norm->Bl.type &&
1350 NULL == n->norm->Bl.width) {
1351 if ( ! post_bl_block_tag(mdoc))
1352 return(0);
1353 } else if (NULL != n->norm->Bl.width) {
1354 if ( ! post_bl_block_width(mdoc))
1355 return(0);
1356 } else
1357 return(1);
1358
1359 assert(n->norm->Bl.width);
1360 return(1);
1361 }
1362
1363 static int
1364 post_bl_block_width(POST_ARGS)
1365 {
1366 size_t width;
1367 int i;
1368 enum mdoct tok;
1369 struct mdoc_node *n;
1370 char buf[NUMSIZ];
1371
1372 n = mdoc->last;
1373
1374 /*
1375 * Calculate the real width of a list from the -width string,
1376 * which may contain a macro (with a known default width), a
1377 * literal string, or a scaling width.
1378 *
1379 * If the value to -width is a macro, then we re-write it to be
1380 * the macro's width as set in share/tmac/mdoc/doc-common.
1527 mdoc->last->norm->Bl.ncols = np->args->argv[j].sz;
1528 mdoc->last->norm->Bl.cols = (void *)np->args->argv[j].value;
1529
1530 for (i = 0, nn = mdoc->last->child; nn; i++) {
1531 np->args->argv[j].value[i] = nn->string;
1532 nn->string = NULL;
1533 nnp = nn;
1534 nn = nn->next;
1535 mdoc_node_delete(NULL, nnp);
1536 }
1537
1538 mdoc->last->nchild = 0;
1539 mdoc->last->child = NULL;
1540
1541 return(1);
1542 }
1543
1544 static int
1545 post_bl(POST_ARGS)
1546 {
1547 struct mdoc_node *n;
1548
1549 if (MDOC_HEAD == mdoc->last->type)
1550 return(post_bl_head(mdoc));
1551 if (MDOC_BLOCK == mdoc->last->type)
1552 return(post_bl_block(mdoc));
1553 if (MDOC_BODY != mdoc->last->type)
1554 return(1);
1555
1556 for (n = mdoc->last->child; n; n = n->next) {
1557 switch (n->tok) {
1558 case (MDOC_Lp):
1559 /* FALLTHROUGH */
1560 case (MDOC_Pp):
1561 mdoc_nmsg(mdoc, n, MANDOCERR_CHILD);
1562 /* FALLTHROUGH */
1563 case (MDOC_It):
1564 /* FALLTHROUGH */
1565 case (MDOC_Sm):
1566 continue;
1567 default:
1568 break;
1569 }
1570
1571 mdoc_nmsg(mdoc, n, MANDOCERR_SYNTCHILD);
1572 return(0);
1573 }
1574
1575 return(1);
1576 }
1577
1578 static int
1579 ebool(struct mdoc *mdoc)
1580 {
1581
1582 if (NULL == mdoc->last->child) {
1583 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY);
1584 mdoc_node_delete(mdoc, mdoc->last);
1585 return(1);
1586 }
1587 check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
1588
1589 assert(MDOC_TEXT == mdoc->last->child->type);
1590
1591 if (0 == strcmp(mdoc->last->child->string, "on"))
1592 return(1);
1593 if (0 == strcmp(mdoc->last->child->string, "off"))
1594 return(1);
1595
1596 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL);
1597 return(1);
1598 }
1599
1600 static int
1601 post_root(POST_ARGS)
1602 {
1603 int erc;
1604 struct mdoc_node *n;
1605
1606 erc = 0;
1607
1608 /* Check that we have a finished prologue. */
1609
1610 if ( ! (MDOC_PBODY & mdoc->flags)) {
1611 erc++;
1612 mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCPROLOG);
1613 }
1614
1754 * of the `prev' node.
1755 */
1756
1757 nn->prev = prev;
1758
1759 if (prev) {
1760 if (prev->next)
1761 prev->next->prev = nn;
1762 nn->next = prev->next;
1763 prev->next = nn;
1764 } else {
1765 mdoc->last->child->prev = nn;
1766 nn->next = mdoc->last->child;
1767 mdoc->last->child = nn;
1768 }
1769 }
1770
1771 return(1);
1772 }
1773
1774 static int
1775 post_ns(POST_ARGS)
1776 {
1777
1778 if (MDOC_LINE & mdoc->last->flags)
1779 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNNS);
1780 return(1);
1781 }
1782
1783 static int
1784 post_sh(POST_ARGS)
1785 {
1786
1787 if (MDOC_HEAD == mdoc->last->type)
1788 return(post_sh_head(mdoc));
1789 if (MDOC_BODY == mdoc->last->type)
1790 return(post_sh_body(mdoc));
1791
1792 return(1);
1793 }
1794
1840 * "custom". Custom sections are user-defined, while named ones
1841 * follow a conventional order and may only appear in certain
1842 * manual sections.
1843 */
1844
1845 sec = SEC_CUSTOM;
1846 buf[0] = '\0';
1847 if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) {
1848 mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
1849 return(0);
1850 } else if (1 == c)
1851 sec = a2sec(buf);
1852
1853 /* The NAME should be first. */
1854
1855 if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
1856 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NAMESECFIRST);
1857
1858 /* The SYNOPSIS gets special attention in other areas. */
1859
1860 if (SEC_SYNOPSIS == sec)
1861 mdoc->flags |= MDOC_SYNOPSIS;
1862 else
1863 mdoc->flags &= ~MDOC_SYNOPSIS;
1864
1865 /* Mark our last section. */
1866
1867 mdoc->lastsec = sec;
1868
1869 /*
1870 * Set the section attribute for the current HEAD, for its
1871 * parent BLOCK, and for the HEAD children; the latter can
1872 * only be TEXT nodes, so no recursion is needed.
1873 * For other blocks and elements, including .Sh BODY, this is
1874 * done when allocating the node data structures, but for .Sh
1875 * BLOCK and HEAD, the section is still unknown at that time.
1876 */
1877
1878 mdoc->last->parent->sec = sec;
1879 mdoc->last->sec = sec;
1880 for (n = mdoc->last->child; n; n = n->next)
1881 n->sec = sec;
1882
1883 /* We don't care about custom sections after this. */
1899 /* Mark the last named section. */
1900
1901 mdoc->lastnamed = sec;
1902
1903 /* Check particular section/manual conventions. */
1904
1905 assert(mdoc->meta.msec);
1906
1907 switch (sec) {
1908 case (SEC_RETURN_VALUES):
1909 /* FALLTHROUGH */
1910 case (SEC_ERRORS):
1911 /* FALLTHROUGH */
1912 case (SEC_LIBRARY):
1913 if (*mdoc->meta.msec == '2')
1914 break;
1915 if (*mdoc->meta.msec == '3')
1916 break;
1917 if (*mdoc->meta.msec == '9')
1918 break;
1919 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECMSEC);
1920 break;
1921 default:
1922 break;
1923 }
1924
1925 return(1);
1926 }
1927
1928 static int
1929 post_ignpar(POST_ARGS)
1930 {
1931 struct mdoc_node *np;
1932
1933 if (MDOC_BODY != mdoc->last->type)
1934 return(1);
1935
1936 if (NULL != (np = mdoc->last->child))
1937 if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
1938 mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR);
1939 mdoc_node_delete(mdoc, np);
1945 mdoc_node_delete(mdoc, np);
1946 }
1947
1948 return(1);
1949 }
1950
1951 static int
1952 pre_par(PRE_ARGS)
1953 {
1954
1955 if (NULL == mdoc->last)
1956 return(1);
1957 if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type)
1958 return(1);
1959
1960 /*
1961 * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
1962 * block: `Lp', `Pp', or non-compact `Bd' or `Bl'.
1963 */
1964
1965 if (MDOC_Pp != mdoc->last->tok && MDOC_Lp != mdoc->last->tok)
1966 return(1);
1967 if (MDOC_Bl == n->tok && n->norm->Bl.comp)
1968 return(1);
1969 if (MDOC_Bd == n->tok && n->norm->Bd.comp)
1970 return(1);
1971 if (MDOC_It == n->tok && n->parent->norm->Bl.comp)
1972 return(1);
1973
1974 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR);
1975 mdoc_node_delete(mdoc, mdoc->last);
1976 return(1);
1977 }
1978
1979 static int
1980 pre_literal(PRE_ARGS)
1981 {
1982
1983 if (MDOC_BODY != n->type)
1984 return(1);
1985
1986 /*
1987 * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd
1988 * -unfilled' macros set MDOC_LITERAL on entrance to the body.
1989 */
1990
1991 switch (n->tok) {
1992 case (MDOC_Dl):
1993 mdoc->flags |= MDOC_LITERAL;
1994 break;
1995 case (MDOC_Bd):
1996 if (DISP_literal == n->norm->Bd.type)
1997 mdoc->flags |= MDOC_LITERAL;
1998 if (DISP_unfilled == n->norm->Bd.type)
1999 mdoc->flags |= MDOC_LITERAL;
2112 mdoc_nmsg(mdoc, n, MANDOCERR_BADMSEC);
2113 mdoc->meta.vol = mandoc_strdup(nn->string);
2114 mdoc->meta.msec = mandoc_strdup(nn->string);
2115 }
2116
2117 if (NULL == (nn = nn->next))
2118 return(1);
2119
2120 /* Handles: `.Dt TITLE SEC VOL'
2121 * --> title = TITLE, volume = VOL is vol ?
2122 * format(VOL) :
2123 * VOL is arch ? format(arch) :
2124 * VOL
2125 */
2126
2127 cp = mdoc_a2vol(nn->string);
2128 if (cp) {
2129 free(mdoc->meta.vol);
2130 mdoc->meta.vol = mandoc_strdup(cp);
2131 } else {
2132 /* FIXME: warn about bad arch. */
2133 cp = mdoc_a2arch(nn->string);
2134 if (NULL == cp) {
2135 free(mdoc->meta.vol);
2136 mdoc->meta.vol = mandoc_strdup(nn->string);
2137 } else
2138 mdoc->meta.arch = mandoc_strdup(cp);
2139 }
2140
2141 /* Ignore any subsequent parameters... */
2142 /* FIXME: warn about subsequent parameters. */
2143
2144 return(1);
2145 }
2146
2147 static int
2148 post_prol(POST_ARGS)
2149 {
2150 /*
2151 * Remove prologue macros from the document after they're
2152 * processed. The final document uses mdoc_meta for these
2153 * values and discards the originals.
2154 */
2175 if (n && NULL != (n = n->next))
2176 *n->string = (char)toupper
2177 ((unsigned char)*n->string);
2178
2179 return(1);
2180 }
2181
2182 static int
2183 post_os(POST_ARGS)
2184 {
2185 struct mdoc_node *n;
2186 char buf[BUFSIZ];
2187 int c;
2188 #ifndef OSNAME
2189 struct utsname utsname;
2190 #endif
2191
2192 n = mdoc->last;
2193
2194 /*
2195 * Set the operating system by way of the `Os' macro. Note that
2196 * if an argument isn't provided and -DOSNAME="\"foo\"" is
2197 * provided during compilation, this value will be used instead
2198 * of filling in "sysname release" from uname().
2199 */
2200
2201 if (mdoc->meta.os)
2202 free(mdoc->meta.os);
2203
2204 buf[0] = '\0';
2205 if (-1 == (c = concat(buf, n->child, BUFSIZ))) {
2206 mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM);
2207 return(0);
2208 }
2209
2210 assert(c);
2211
2212 /* XXX: yes, these can all be dynamically-adjusted buffers, but
2213 * it's really not worth the extra hackery.
2214 */
2215
2216 if ('\0' == buf[0]) {
2217 #ifdef OSNAME
2218 if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) {
2219 mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2220 return(0);
2221 }
2222 #else /*!OSNAME */
2223 if (-1 == uname(&utsname)) {
2224 mdoc_nmsg(mdoc, n, MANDOCERR_UNAME);
2225 mdoc->meta.os = mandoc_strdup("UNKNOWN");
2226 return(post_prol(mdoc));
2227 }
2228
2229 if (strlcat(buf, utsname.sysname, BUFSIZ) >= BUFSIZ) {
2230 mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2231 return(0);
2232 }
2233 if (strlcat(buf, " ", BUFSIZ) >= BUFSIZ) {
2234 mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2235 return(0);
2236 }
|
1 /* $Id: mdoc_validate.c,v 1.198 2013/12/15 21:23:52 schwarze Exp $ */
2 /*
3 * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #ifndef OSNAME
23 #include <sys/utsname.h>
24 #endif
80 static int berr_ge1(POST_ARGS);
81 static int bwarn_ge1(POST_ARGS);
82 static int ewarn_eq0(POST_ARGS);
83 static int ewarn_eq1(POST_ARGS);
84 static int ewarn_ge1(POST_ARGS);
85 static int ewarn_le1(POST_ARGS);
86 static int hwarn_eq0(POST_ARGS);
87 static int hwarn_eq1(POST_ARGS);
88 static int hwarn_ge1(POST_ARGS);
89 static int hwarn_le1(POST_ARGS);
90
91 static int post_an(POST_ARGS);
92 static int post_at(POST_ARGS);
93 static int post_bf(POST_ARGS);
94 static int post_bl(POST_ARGS);
95 static int post_bl_block(POST_ARGS);
96 static int post_bl_block_width(POST_ARGS);
97 static int post_bl_block_tag(POST_ARGS);
98 static int post_bl_head(POST_ARGS);
99 static int post_bx(POST_ARGS);
100 static int post_defaults(POST_ARGS);
101 static int post_dd(POST_ARGS);
102 static int post_dt(POST_ARGS);
103 static int post_eoln(POST_ARGS);
104 static int post_hyph(POST_ARGS);
105 static int post_ignpar(POST_ARGS);
106 static int post_it(POST_ARGS);
107 static int post_lb(POST_ARGS);
108 static int post_literal(POST_ARGS);
109 static int post_nm(POST_ARGS);
110 static int post_ns(POST_ARGS);
111 static int post_os(POST_ARGS);
112 static int post_par(POST_ARGS);
113 static int post_prol(POST_ARGS);
114 static int post_root(POST_ARGS);
115 static int post_rs(POST_ARGS);
116 static int post_sh(POST_ARGS);
117 static int post_sh_body(POST_ARGS);
118 static int post_sh_head(POST_ARGS);
119 static int post_st(POST_ARGS);
120 static int post_std(POST_ARGS);
121 static int post_vt(POST_ARGS);
122 static int pre_an(PRE_ARGS);
123 static int pre_bd(PRE_ARGS);
124 static int pre_bl(PRE_ARGS);
125 static int pre_dd(PRE_ARGS);
126 static int pre_display(PRE_ARGS);
127 static int pre_dt(PRE_ARGS);
128 static int pre_it(PRE_ARGS);
129 static int pre_literal(PRE_ARGS);
130 static int pre_os(PRE_ARGS);
131 static int pre_par(PRE_ARGS);
132 static int pre_sh(PRE_ARGS);
133 static int pre_ss(PRE_ARGS);
134 static int pre_std(PRE_ARGS);
135
136 static v_post posts_an[] = { post_an, NULL };
137 static v_post posts_at[] = { post_at, post_defaults, NULL };
138 static v_post posts_bd[] = { post_literal, hwarn_eq0, bwarn_ge1, NULL };
139 static v_post posts_bf[] = { hwarn_le1, post_bf, NULL };
140 static v_post posts_bk[] = { hwarn_eq0, bwarn_ge1, NULL };
141 static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL };
142 static v_post posts_bx[] = { post_bx, NULL };
143 static v_post posts_bool[] = { ebool, NULL };
144 static v_post posts_eoln[] = { post_eoln, NULL };
145 static v_post posts_defaults[] = { post_defaults, NULL };
146 static v_post posts_d1[] = { bwarn_ge1, post_hyph, NULL };
147 static v_post posts_dd[] = { post_dd, post_prol, NULL };
148 static v_post posts_dl[] = { post_literal, bwarn_ge1, NULL };
149 static v_post posts_dt[] = { post_dt, post_prol, NULL };
150 static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL };
151 static v_post posts_hyph[] = { post_hyph, NULL };
152 static v_post posts_hyphtext[] = { ewarn_ge1, post_hyph, NULL };
153 static v_post posts_it[] = { post_it, NULL };
154 static v_post posts_lb[] = { post_lb, NULL };
155 static v_post posts_nd[] = { berr_ge1, post_hyph, NULL };
156 static v_post posts_nm[] = { post_nm, NULL };
157 static v_post posts_notext[] = { ewarn_eq0, NULL };
158 static v_post posts_ns[] = { post_ns, NULL };
159 static v_post posts_os[] = { post_os, post_prol, NULL };
160 static v_post posts_pp[] = { post_par, ewarn_eq0, NULL };
161 static v_post posts_rs[] = { post_rs, NULL };
162 static v_post posts_sh[] = { post_ignpar,hwarn_ge1,post_sh,post_hyph,NULL };
163 static v_post posts_sp[] = { post_par, ewarn_le1, NULL };
164 static v_post posts_ss[] = { post_ignpar, hwarn_ge1, post_hyph, NULL };
165 static v_post posts_st[] = { post_st, NULL };
166 static v_post posts_std[] = { post_std, NULL };
167 static v_post posts_text[] = { ewarn_ge1, NULL };
168 static v_post posts_text1[] = { ewarn_eq1, NULL };
169 static v_post posts_vt[] = { post_vt, NULL };
170 static v_pre pres_an[] = { pre_an, NULL };
171 static v_pre pres_bd[] = { pre_display, pre_bd, pre_literal, pre_par, NULL };
172 static v_pre pres_bl[] = { pre_bl, pre_par, NULL };
173 static v_pre pres_d1[] = { pre_display, NULL };
174 static v_pre pres_dl[] = { pre_literal, pre_display, NULL };
175 static v_pre pres_dd[] = { pre_dd, NULL };
176 static v_pre pres_dt[] = { pre_dt, NULL };
177 static v_pre pres_it[] = { pre_it, pre_par, NULL };
178 static v_pre pres_os[] = { pre_os, NULL };
179 static v_pre pres_pp[] = { pre_par, NULL };
180 static v_pre pres_sh[] = { pre_sh, NULL };
181 static v_pre pres_ss[] = { pre_ss, NULL };
182 static v_pre pres_std[] = { pre_std, NULL };
183
184 static const struct valids mdoc_valids[MDOC_MAX] = {
185 { NULL, NULL }, /* Ap */
186 { pres_dd, posts_dd }, /* Dd */
187 { pres_dt, posts_dt }, /* Dt */
188 { pres_os, posts_os }, /* Os */
189 { pres_sh, posts_sh }, /* Sh */
190 { pres_ss, posts_ss }, /* Ss */
191 { pres_pp, posts_pp }, /* Pp */
192 { pres_d1, posts_d1 }, /* D1 */
193 { pres_dl, posts_dl }, /* Dl */
194 { pres_bd, posts_bd }, /* Bd */
195 { NULL, NULL }, /* Ed */
196 { pres_bl, posts_bl }, /* Bl */
197 { NULL, NULL }, /* El */
198 { pres_it, posts_it }, /* It */
199 { NULL, NULL }, /* Ad */
200 { pres_an, posts_an }, /* An */
201 { NULL, posts_defaults }, /* Ar */
202 { NULL, NULL }, /* Cd */
203 { NULL, NULL }, /* Cm */
204 { NULL, NULL }, /* Dv */
205 { NULL, NULL }, /* Er */
206 { NULL, NULL }, /* Ev */
207 { pres_std, posts_std }, /* Ex */
208 { NULL, NULL }, /* Fa */
209 { NULL, posts_text }, /* Fd */
210 { NULL, NULL }, /* Fl */
211 { NULL, NULL }, /* Fn */
212 { NULL, NULL }, /* Ft */
213 { NULL, NULL }, /* Ic */
214 { NULL, posts_text1 }, /* In */
215 { NULL, posts_defaults }, /* Li */
216 { NULL, posts_nd }, /* Nd */
217 { NULL, posts_nm }, /* Nm */
218 { NULL, NULL }, /* Op */
219 { NULL, NULL }, /* Ot */
220 { NULL, posts_defaults }, /* Pa */
221 { pres_std, posts_std }, /* Rv */
222 { NULL, posts_st }, /* St */
223 { NULL, NULL }, /* Va */
224 { NULL, posts_vt }, /* Vt */
225 { NULL, posts_text }, /* Xr */
226 { NULL, posts_text }, /* %A */
227 { NULL, posts_hyphtext }, /* %B */ /* FIXME: can be used outside Rs/Re. */
228 { NULL, posts_text }, /* %D */
229 { NULL, posts_text }, /* %I */
230 { NULL, posts_text }, /* %J */
231 { NULL, posts_hyphtext }, /* %N */
232 { NULL, posts_hyphtext }, /* %O */
233 { NULL, posts_text }, /* %P */
234 { NULL, posts_hyphtext }, /* %R */
235 { NULL, posts_hyphtext }, /* %T */ /* FIXME: can be used outside Rs/Re. */
236 { NULL, posts_text }, /* %V */
237 { NULL, NULL }, /* Ac */
238 { NULL, NULL }, /* Ao */
239 { NULL, NULL }, /* Aq */
240 { NULL, posts_at }, /* At */
241 { NULL, NULL }, /* Bc */
242 { NULL, posts_bf }, /* Bf */
243 { NULL, NULL }, /* Bo */
244 { NULL, NULL }, /* Bq */
245 { NULL, NULL }, /* Bsx */
246 { NULL, posts_bx }, /* Bx */
247 { NULL, posts_bool }, /* Db */
248 { NULL, NULL }, /* Dc */
249 { NULL, NULL }, /* Do */
250 { NULL, NULL }, /* Dq */
251 { NULL, NULL }, /* Ec */
252 { NULL, NULL }, /* Ef */
253 { NULL, NULL }, /* Em */
254 { NULL, NULL }, /* Eo */
255 { NULL, NULL }, /* Fx */
256 { NULL, NULL }, /* Ms */
257 { NULL, posts_notext }, /* No */
258 { NULL, posts_ns }, /* Ns */
259 { NULL, NULL }, /* Nx */
260 { NULL, NULL }, /* Ox */
261 { NULL, NULL }, /* Pc */
262 { NULL, posts_text1 }, /* Pf */
263 { NULL, NULL }, /* Po */
264 { NULL, NULL }, /* Pq */
265 { NULL, NULL }, /* Qc */
266 { NULL, NULL }, /* Ql */
267 { NULL, NULL }, /* Qo */
268 { NULL, NULL }, /* Qq */
269 { NULL, NULL }, /* Re */
270 { NULL, posts_rs }, /* Rs */
271 { NULL, NULL }, /* Sc */
272 { NULL, NULL }, /* So */
273 { NULL, NULL }, /* Sq */
274 { NULL, posts_bool }, /* Sm */
275 { NULL, posts_hyph }, /* Sx */
276 { NULL, NULL }, /* Sy */
277 { NULL, NULL }, /* Tn */
278 { NULL, NULL }, /* Ux */
279 { NULL, NULL }, /* Xc */
280 { NULL, NULL }, /* Xo */
281 { NULL, posts_fo }, /* Fo */
282 { NULL, NULL }, /* Fc */
283 { NULL, NULL }, /* Oo */
284 { NULL, NULL }, /* Oc */
285 { NULL, posts_bk }, /* Bk */
286 { NULL, NULL }, /* Ek */
287 { NULL, posts_eoln }, /* Bt */
288 { NULL, NULL }, /* Hf */
289 { NULL, NULL }, /* Fr */
290 { NULL, posts_eoln }, /* Ud */
291 { NULL, posts_lb }, /* Lb */
292 { pres_pp, posts_pp }, /* Lp */
293 { NULL, NULL }, /* Lk */
294 { NULL, posts_defaults }, /* Mt */
295 { NULL, NULL }, /* Brq */
296 { NULL, NULL }, /* Bro */
297 { NULL, NULL }, /* Brc */
298 { NULL, posts_text }, /* %C */
299 { NULL, NULL }, /* Es */
300 { NULL, NULL }, /* En */
301 { NULL, NULL }, /* Dx */
302 { NULL, posts_text }, /* %Q */
303 { NULL, posts_pp }, /* br */
304 { NULL, posts_sp }, /* sp */
305 { NULL, posts_text1 }, /* %U */
306 { NULL, NULL }, /* Ta */
307 };
308
309 #define RSORD_MAX 14 /* Number of `Rs' blocks. */
310
311 static const enum mdoct rsord[RSORD_MAX] = {
312 MDOC__A,
313 MDOC__T,
314 MDOC__B,
315 MDOC__I,
316 MDOC__J,
317 MDOC__R,
318 MDOC__N,
319 MDOC__V,
320 MDOC__U,
321 MDOC__P,
322 MDOC__Q,
323 MDOC__C,
324 MDOC__D,
325 MDOC__O
326 };
327
328 static const char * const secnames[SEC__MAX] = {
329 NULL,
330 "NAME",
331 "LIBRARY",
332 "SYNOPSIS",
333 "DESCRIPTION",
334 "IMPLEMENTATION NOTES",
335 "RETURN VALUES",
336 "ENVIRONMENT",
337 "FILES",
338 "EXIT STATUS",
339 "EXAMPLES",
340 "DIAGNOSTICS",
341 "COMPATIBILITY",
342 "ERRORS",
343 "SEE ALSO",
344 "STANDARDS",
345 "HISTORY",
400 case (MDOC_EQN):
401 /* FALLTHROUGH */
402 case (MDOC_TBL):
403 return(1);
404 case (MDOC_ROOT):
405 return(post_root(mdoc));
406 default:
407 break;
408 }
409
410 if (NULL == mdoc_valids[mdoc->last->tok].post)
411 return(1);
412 for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
413 if ( ! (*p)(mdoc))
414 return(0);
415
416 return(1);
417 }
418
419 static int
420 check_count(struct mdoc *mdoc, enum mdoc_type type,
421 enum check_lvl lvl, enum check_ineq ineq, int val)
422 {
423 const char *p;
424 enum mandocerr t;
425
426 if (mdoc->last->type != type)
427 return(1);
428
429 switch (ineq) {
430 case (CHECK_LT):
431 p = "less than ";
432 if (mdoc->last->nchild < val)
433 return(1);
434 break;
435 case (CHECK_GT):
436 p = "more than ";
437 if (mdoc->last->nchild > val)
438 return(1);
439 break;
440 case (CHECK_EQ):
441 p = "";
442 if (val == mdoc->last->nchild)
443 return(1);
444 break;
445 default:
446 abort();
447 /* NOTREACHED */
448 }
449
450 t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT;
451 mandoc_vmsg(t, mdoc->parse, mdoc->last->line, mdoc->last->pos,
452 "want %s%d children (have %d)",
453 p, val, mdoc->last->nchild);
454 return(1);
455 }
456
457 static int
458 berr_ge1(POST_ARGS)
459 {
460
461 return(check_count(mdoc, MDOC_BODY, CHECK_ERROR, CHECK_GT, 0));
462 }
463
464 static int
465 bwarn_ge1(POST_ARGS)
466 {
467 return(check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0));
468 }
469
470 static int
471 ewarn_eq0(POST_ARGS)
472 {
473 return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0));
499
500 static int
501 hwarn_eq1(POST_ARGS)
502 {
503 return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 1));
504 }
505
506 static int
507 hwarn_ge1(POST_ARGS)
508 {
509 return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_GT, 0));
510 }
511
512 static int
513 hwarn_le1(POST_ARGS)
514 {
515 return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_LT, 2));
516 }
517
518 static void
519 check_args(struct mdoc *mdoc, struct mdoc_node *n)
520 {
521 int i;
522
523 if (NULL == n->args)
524 return;
525
526 assert(n->args->argc);
527 for (i = 0; i < (int)n->args->argc; i++)
528 check_argv(mdoc, n, &n->args->argv[i]);
529 }
530
531 static void
532 check_argv(struct mdoc *mdoc, struct mdoc_node *n, struct mdoc_argv *v)
533 {
534 int i;
535
536 for (i = 0; i < (int)v->sz; i++)
537 check_text(mdoc, v->line, v->pos, v->value[i]);
538
539 /* FIXME: move to post_std(). */
540
541 if (MDOC_Std == v->arg)
542 if ( ! (v->sz || mdoc->meta.name))
543 mdoc_nmsg(mdoc, n, MANDOCERR_NONAME);
544 }
545
546 static void
547 check_text(struct mdoc *mdoc, int ln, int pos, char *p)
548 {
549 char *cp;
550
551 if (MDOC_LITERAL & mdoc->flags)
552 return;
553
554 for (cp = p; NULL != (p = strchr(p, '\t')); p++)
555 mdoc_pmsg(mdoc, ln, pos + (int)(p - cp), MANDOCERR_BADTAB);
556 }
557
558 static int
559 check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t)
560 {
561
562 assert(n->parent);
563 if ((MDOC_ROOT == t || tok == n->parent->tok) &&
564 (t == n->parent->type))
565 return(1);
566
567 mandoc_vmsg(MANDOCERR_SYNTCHILD, mdoc->parse, n->line,
568 n->pos, "want parent %s", MDOC_ROOT == t ?
569 "<root>" : mdoc_macronames[tok]);
570 return(0);
571 }
572
573
574 static int
575 pre_display(PRE_ARGS)
719
720 if (n->norm->Bl.type == LIST__NONE)
721 if (n->norm->Bl.width ||
722 n->norm->Bl.offs ||
723 n->norm->Bl.comp)
724 mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST);
725
726 continue;
727 }
728
729 /* Allow lists to default to LIST_item. */
730
731 if (LIST__NONE == n->norm->Bl.type) {
732 mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE);
733 n->norm->Bl.type = LIST_item;
734 }
735
736 /*
737 * Validate the width field. Some list types don't need width
738 * types and should be warned about them. Others should have it
739 * and must also be warned. Yet others have a default and need
740 * no warning.
741 */
742
743 switch (n->norm->Bl.type) {
744 case (LIST_tag):
745 if (NULL == n->norm->Bl.width)
746 mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG);
747 break;
748 case (LIST_column):
749 /* FALLTHROUGH */
750 case (LIST_diag):
751 /* FALLTHROUGH */
752 case (LIST_ohang):
753 /* FALLTHROUGH */
754 case (LIST_inset):
755 /* FALLTHROUGH */
756 case (LIST_item):
757 if (n->norm->Bl.width)
758 mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
759 break;
760 case (LIST_bullet):
761 /* FALLTHROUGH */
762 case (LIST_dash):
763 /* FALLTHROUGH */
764 case (LIST_hyphen):
765 if (NULL == n->norm->Bl.width)
766 n->norm->Bl.width = "2n";
767 break;
768 case (LIST_enum):
769 if (NULL == n->norm->Bl.width)
770 n->norm->Bl.width = "3n";
771 break;
772 default:
773 break;
774 }
775
776 return(1);
777 }
778
779
780 static int
781 pre_bd(PRE_ARGS)
782 {
783 int i, dup, comp;
784 enum mdoc_disp dt;
785 const char *offs;
786 struct mdoc_node *np;
787
788 if (MDOC_BLOCK != n->type) {
789 if (ENDBODY_NOT != n->end) {
790 assert(n->pending);
791 np = n->pending->parent;
872 return(1);
873 }
874
875
876 static int
877 pre_ss(PRE_ARGS)
878 {
879
880 if (MDOC_BLOCK != n->type)
881 return(1);
882 return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY));
883 }
884
885
886 static int
887 pre_sh(PRE_ARGS)
888 {
889
890 if (MDOC_BLOCK != n->type)
891 return(1);
892 return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT));
893 }
894
895
896 static int
897 pre_it(PRE_ARGS)
898 {
899
900 if (MDOC_BLOCK != n->type)
901 return(1);
902
903 return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY));
904 }
905
906
907 static int
908 pre_an(PRE_ARGS)
909 {
910 int i;
911
1107 * specifically the BODY, should only have TEXT children.
1108 */
1109
1110 if (MDOC_BODY != mdoc->last->type)
1111 return(1);
1112
1113 for (n = mdoc->last->child; n; n = n->next)
1114 if (MDOC_TEXT != n->type)
1115 mdoc_nmsg(mdoc, n, MANDOCERR_CHILD);
1116
1117 return(1);
1118 }
1119
1120
1121 static int
1122 post_nm(POST_ARGS)
1123 {
1124 char buf[BUFSIZ];
1125 int c;
1126
1127 if (NULL != mdoc->meta.name)
1128 return(1);
1129
1130 /* Try to use our children for setting the meta name. */
1131
1132 if (NULL != mdoc->last->child) {
1133 buf[0] = '\0';
1134 c = concat(buf, mdoc->last->child, BUFSIZ);
1135 } else
1136 c = 0;
1137
1138 switch (c) {
1139 case (-1):
1140 mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
1141 return(0);
1142 case (0):
1143 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME);
1144 mdoc->meta.name = mandoc_strdup("UNKNOWN");
1145 break;
1146 default:
1147 mdoc->meta.name = mandoc_strdup(buf);
1148 break;
1149 }
1150 return(1);
1151 }
1152
1153 static int
1154 post_literal(POST_ARGS)
1155 {
1156
1157 /*
1158 * The `Dl' (note "el" not "one") and `Bd' macros unset the
1159 * MDOC_LITERAL flag as they leave. Note that `Bd' only sets
1160 * this in literal mode, but it doesn't hurt to just switch it
1161 * off in general since displays can't be nested.
1162 */
1163
1164 if (MDOC_BODY == mdoc->last->type)
1165 mdoc->flags &= ~MDOC_LITERAL;
1166
1167 return(1);
1168 }
1169
1335 er = MANDOCERR_ARGCOUNT;
1336 else if (i == cols || i == cols + 1)
1337 break;
1338 else
1339 er = MANDOCERR_SYNTARGCOUNT;
1340
1341 mandoc_vmsg(er, mdoc->parse, mdoc->last->line,
1342 mdoc->last->pos,
1343 "columns == %d (have %d)", cols, i);
1344 return(MANDOCERR_ARGCOUNT == er);
1345 default:
1346 break;
1347 }
1348
1349 return(1);
1350 }
1351
1352 static int
1353 post_bl_block(POST_ARGS)
1354 {
1355 struct mdoc_node *n, *ni, *nc;
1356
1357 /*
1358 * These are fairly complicated, so we've broken them into two
1359 * functions. post_bl_block_tag() is called when a -tag is
1360 * specified, but no -width (it must be guessed). The second
1361 * when a -width is specified (macro indicators must be
1362 * rewritten into real lengths).
1363 */
1364
1365 n = mdoc->last;
1366
1367 if (LIST_tag == n->norm->Bl.type &&
1368 NULL == n->norm->Bl.width) {
1369 if ( ! post_bl_block_tag(mdoc))
1370 return(0);
1371 assert(n->norm->Bl.width);
1372 } else if (NULL != n->norm->Bl.width) {
1373 if ( ! post_bl_block_width(mdoc))
1374 return(0);
1375 assert(n->norm->Bl.width);
1376 }
1377
1378 for (ni = n->body->child; ni; ni = ni->next) {
1379 if (NULL == ni->body)
1380 continue;
1381 nc = ni->body->last;
1382 while (NULL != nc) {
1383 switch (nc->tok) {
1384 case (MDOC_Pp):
1385 /* FALLTHROUGH */
1386 case (MDOC_Lp):
1387 /* FALLTHROUGH */
1388 case (MDOC_br):
1389 break;
1390 default:
1391 nc = NULL;
1392 continue;
1393 }
1394 if (NULL == ni->next) {
1395 mdoc_nmsg(mdoc, nc, MANDOCERR_MOVEPAR);
1396 if ( ! mdoc_node_relink(mdoc, nc))
1397 return(0);
1398 } else if (0 == n->norm->Bl.comp &&
1399 LIST_column != n->norm->Bl.type) {
1400 mdoc_nmsg(mdoc, nc, MANDOCERR_IGNPAR);
1401 mdoc_node_delete(mdoc, nc);
1402 } else
1403 break;
1404 nc = ni->body->last;
1405 }
1406 }
1407 return(1);
1408 }
1409
1410 static int
1411 post_bl_block_width(POST_ARGS)
1412 {
1413 size_t width;
1414 int i;
1415 enum mdoct tok;
1416 struct mdoc_node *n;
1417 char buf[NUMSIZ];
1418
1419 n = mdoc->last;
1420
1421 /*
1422 * Calculate the real width of a list from the -width string,
1423 * which may contain a macro (with a known default width), a
1424 * literal string, or a scaling width.
1425 *
1426 * If the value to -width is a macro, then we re-write it to be
1427 * the macro's width as set in share/tmac/mdoc/doc-common.
1574 mdoc->last->norm->Bl.ncols = np->args->argv[j].sz;
1575 mdoc->last->norm->Bl.cols = (void *)np->args->argv[j].value;
1576
1577 for (i = 0, nn = mdoc->last->child; nn; i++) {
1578 np->args->argv[j].value[i] = nn->string;
1579 nn->string = NULL;
1580 nnp = nn;
1581 nn = nn->next;
1582 mdoc_node_delete(NULL, nnp);
1583 }
1584
1585 mdoc->last->nchild = 0;
1586 mdoc->last->child = NULL;
1587
1588 return(1);
1589 }
1590
1591 static int
1592 post_bl(POST_ARGS)
1593 {
1594 struct mdoc_node *nparent, *nprev; /* of the Bl block */
1595 struct mdoc_node *nblock, *nbody; /* of the Bl */
1596 struct mdoc_node *nchild, *nnext; /* of the Bl body */
1597
1598 nbody = mdoc->last;
1599 switch (nbody->type) {
1600 case (MDOC_BLOCK):
1601 return(post_bl_block(mdoc));
1602 case (MDOC_HEAD):
1603 return(post_bl_head(mdoc));
1604 case (MDOC_BODY):
1605 break;
1606 default:
1607 return(1);
1608 }
1609
1610 nchild = nbody->child;
1611 while (NULL != nchild) {
1612 if (MDOC_It == nchild->tok || MDOC_Sm == nchild->tok) {
1613 nchild = nchild->next;
1614 continue;
1615 }
1616
1617 mdoc_nmsg(mdoc, nchild, MANDOCERR_CHILD);
1618
1619 /*
1620 * Move the node out of the Bl block.
1621 * First, collect all required node pointers.
1622 */
1623
1624 nblock = nbody->parent;
1625 nprev = nblock->prev;
1626 nparent = nblock->parent;
1627 nnext = nchild->next;
1628
1629 /*
1630 * Unlink this child.
1631 */
1632
1633 assert(NULL == nchild->prev);
1634 if (0 == --nbody->nchild) {
1635 nbody->child = NULL;
1636 nbody->last = NULL;
1637 assert(NULL == nnext);
1638 } else {
1639 nbody->child = nnext;
1640 nnext->prev = NULL;
1641 }
1642
1643 /*
1644 * Relink this child.
1645 */
1646
1647 nchild->parent = nparent;
1648 nchild->prev = nprev;
1649 nchild->next = nblock;
1650
1651 nblock->prev = nchild;
1652 nparent->nchild++;
1653 if (NULL == nprev)
1654 nparent->child = nchild;
1655 else
1656 nprev->next = nchild;
1657
1658 nchild = nnext;
1659 }
1660
1661 return(1);
1662 }
1663
1664 static int
1665 ebool(struct mdoc *mdoc)
1666 {
1667
1668 if (NULL == mdoc->last->child) {
1669 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY);
1670 mdoc_node_delete(mdoc, mdoc->last);
1671 return(1);
1672 }
1673 check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
1674
1675 assert(MDOC_TEXT == mdoc->last->child->type);
1676
1677 if (0 == strcmp(mdoc->last->child->string, "on")) {
1678 if (MDOC_Sm == mdoc->last->tok)
1679 mdoc->flags &= ~MDOC_SMOFF;
1680 return(1);
1681 }
1682 if (0 == strcmp(mdoc->last->child->string, "off")) {
1683 if (MDOC_Sm == mdoc->last->tok)
1684 mdoc->flags |= MDOC_SMOFF;
1685 return(1);
1686 }
1687
1688 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL);
1689 return(1);
1690 }
1691
1692 static int
1693 post_root(POST_ARGS)
1694 {
1695 int erc;
1696 struct mdoc_node *n;
1697
1698 erc = 0;
1699
1700 /* Check that we have a finished prologue. */
1701
1702 if ( ! (MDOC_PBODY & mdoc->flags)) {
1703 erc++;
1704 mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCPROLOG);
1705 }
1706
1846 * of the `prev' node.
1847 */
1848
1849 nn->prev = prev;
1850
1851 if (prev) {
1852 if (prev->next)
1853 prev->next->prev = nn;
1854 nn->next = prev->next;
1855 prev->next = nn;
1856 } else {
1857 mdoc->last->child->prev = nn;
1858 nn->next = mdoc->last->child;
1859 mdoc->last->child = nn;
1860 }
1861 }
1862
1863 return(1);
1864 }
1865
1866 /*
1867 * For some arguments of some macros,
1868 * convert all breakable hyphens into ASCII_HYPH.
1869 */
1870 static int
1871 post_hyph(POST_ARGS)
1872 {
1873 struct mdoc_node *n, *nch;
1874 char *cp;
1875
1876 n = mdoc->last;
1877 switch (n->type) {
1878 case (MDOC_HEAD):
1879 if (MDOC_Sh == n->tok || MDOC_Ss == n->tok)
1880 break;
1881 return(1);
1882 case (MDOC_BODY):
1883 if (MDOC_D1 == n->tok || MDOC_Nd == n->tok)
1884 break;
1885 return(1);
1886 case (MDOC_ELEM):
1887 break;
1888 default:
1889 return(1);
1890 }
1891
1892 for (nch = n->child; nch; nch = nch->next) {
1893 if (MDOC_TEXT != nch->type)
1894 continue;
1895 cp = nch->string;
1896 if (3 > strnlen(cp, 3))
1897 continue;
1898 while ('\0' != *(++cp))
1899 if ('-' == *cp &&
1900 isalpha((unsigned char)cp[-1]) &&
1901 isalpha((unsigned char)cp[1]))
1902 *cp = ASCII_HYPH;
1903 }
1904 return(1);
1905 }
1906
1907 static int
1908 post_ns(POST_ARGS)
1909 {
1910
1911 if (MDOC_LINE & mdoc->last->flags)
1912 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNNS);
1913 return(1);
1914 }
1915
1916 static int
1917 post_sh(POST_ARGS)
1918 {
1919
1920 if (MDOC_HEAD == mdoc->last->type)
1921 return(post_sh_head(mdoc));
1922 if (MDOC_BODY == mdoc->last->type)
1923 return(post_sh_body(mdoc));
1924
1925 return(1);
1926 }
1927
1973 * "custom". Custom sections are user-defined, while named ones
1974 * follow a conventional order and may only appear in certain
1975 * manual sections.
1976 */
1977
1978 sec = SEC_CUSTOM;
1979 buf[0] = '\0';
1980 if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) {
1981 mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
1982 return(0);
1983 } else if (1 == c)
1984 sec = a2sec(buf);
1985
1986 /* The NAME should be first. */
1987
1988 if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
1989 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NAMESECFIRST);
1990
1991 /* The SYNOPSIS gets special attention in other areas. */
1992
1993 if (SEC_SYNOPSIS == sec) {
1994 roff_setreg(mdoc->roff, "nS", 1, '=');
1995 mdoc->flags |= MDOC_SYNOPSIS;
1996 } else {
1997 roff_setreg(mdoc->roff, "nS", 0, '=');
1998 mdoc->flags &= ~MDOC_SYNOPSIS;
1999 }
2000
2001 /* Mark our last section. */
2002
2003 mdoc->lastsec = sec;
2004
2005 /*
2006 * Set the section attribute for the current HEAD, for its
2007 * parent BLOCK, and for the HEAD children; the latter can
2008 * only be TEXT nodes, so no recursion is needed.
2009 * For other blocks and elements, including .Sh BODY, this is
2010 * done when allocating the node data structures, but for .Sh
2011 * BLOCK and HEAD, the section is still unknown at that time.
2012 */
2013
2014 mdoc->last->parent->sec = sec;
2015 mdoc->last->sec = sec;
2016 for (n = mdoc->last->child; n; n = n->next)
2017 n->sec = sec;
2018
2019 /* We don't care about custom sections after this. */
2035 /* Mark the last named section. */
2036
2037 mdoc->lastnamed = sec;
2038
2039 /* Check particular section/manual conventions. */
2040
2041 assert(mdoc->meta.msec);
2042
2043 switch (sec) {
2044 case (SEC_RETURN_VALUES):
2045 /* FALLTHROUGH */
2046 case (SEC_ERRORS):
2047 /* FALLTHROUGH */
2048 case (SEC_LIBRARY):
2049 if (*mdoc->meta.msec == '2')
2050 break;
2051 if (*mdoc->meta.msec == '3')
2052 break;
2053 if (*mdoc->meta.msec == '9')
2054 break;
2055 mandoc_msg(MANDOCERR_SECMSEC, mdoc->parse,
2056 mdoc->last->line, mdoc->last->pos, buf);
2057 break;
2058 default:
2059 break;
2060 }
2061
2062 return(1);
2063 }
2064
2065 static int
2066 post_ignpar(POST_ARGS)
2067 {
2068 struct mdoc_node *np;
2069
2070 if (MDOC_BODY != mdoc->last->type)
2071 return(1);
2072
2073 if (NULL != (np = mdoc->last->child))
2074 if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
2075 mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR);
2076 mdoc_node_delete(mdoc, np);
2082 mdoc_node_delete(mdoc, np);
2083 }
2084
2085 return(1);
2086 }
2087
2088 static int
2089 pre_par(PRE_ARGS)
2090 {
2091
2092 if (NULL == mdoc->last)
2093 return(1);
2094 if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type)
2095 return(1);
2096
2097 /*
2098 * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
2099 * block: `Lp', `Pp', or non-compact `Bd' or `Bl'.
2100 */
2101
2102 if (MDOC_Pp != mdoc->last->tok &&
2103 MDOC_Lp != mdoc->last->tok &&
2104 MDOC_br != mdoc->last->tok)
2105 return(1);
2106 if (MDOC_Bl == n->tok && n->norm->Bl.comp)
2107 return(1);
2108 if (MDOC_Bd == n->tok && n->norm->Bd.comp)
2109 return(1);
2110 if (MDOC_It == n->tok && n->parent->norm->Bl.comp)
2111 return(1);
2112
2113 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR);
2114 mdoc_node_delete(mdoc, mdoc->last);
2115 return(1);
2116 }
2117
2118 static int
2119 post_par(POST_ARGS)
2120 {
2121
2122 if (MDOC_ELEM != mdoc->last->type &&
2123 MDOC_BLOCK != mdoc->last->type)
2124 return(1);
2125
2126 if (NULL == mdoc->last->prev) {
2127 if (MDOC_Sh != mdoc->last->parent->tok &&
2128 MDOC_Ss != mdoc->last->parent->tok)
2129 return(1);
2130 } else {
2131 if (MDOC_Pp != mdoc->last->prev->tok &&
2132 MDOC_Lp != mdoc->last->prev->tok &&
2133 (MDOC_br != mdoc->last->tok ||
2134 (MDOC_sp != mdoc->last->prev->tok &&
2135 MDOC_br != mdoc->last->prev->tok)))
2136 return(1);
2137 }
2138
2139 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR);
2140 mdoc_node_delete(mdoc, mdoc->last);
2141 return(1);
2142 }
2143
2144 static int
2145 pre_literal(PRE_ARGS)
2146 {
2147
2148 if (MDOC_BODY != n->type)
2149 return(1);
2150
2151 /*
2152 * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd
2153 * -unfilled' macros set MDOC_LITERAL on entrance to the body.
2154 */
2155
2156 switch (n->tok) {
2157 case (MDOC_Dl):
2158 mdoc->flags |= MDOC_LITERAL;
2159 break;
2160 case (MDOC_Bd):
2161 if (DISP_literal == n->norm->Bd.type)
2162 mdoc->flags |= MDOC_LITERAL;
2163 if (DISP_unfilled == n->norm->Bd.type)
2164 mdoc->flags |= MDOC_LITERAL;
2277 mdoc_nmsg(mdoc, n, MANDOCERR_BADMSEC);
2278 mdoc->meta.vol = mandoc_strdup(nn->string);
2279 mdoc->meta.msec = mandoc_strdup(nn->string);
2280 }
2281
2282 if (NULL == (nn = nn->next))
2283 return(1);
2284
2285 /* Handles: `.Dt TITLE SEC VOL'
2286 * --> title = TITLE, volume = VOL is vol ?
2287 * format(VOL) :
2288 * VOL is arch ? format(arch) :
2289 * VOL
2290 */
2291
2292 cp = mdoc_a2vol(nn->string);
2293 if (cp) {
2294 free(mdoc->meta.vol);
2295 mdoc->meta.vol = mandoc_strdup(cp);
2296 } else {
2297 cp = mdoc_a2arch(nn->string);
2298 if (NULL == cp) {
2299 mdoc_nmsg(mdoc, nn, MANDOCERR_BADVOLARCH);
2300 free(mdoc->meta.vol);
2301 mdoc->meta.vol = mandoc_strdup(nn->string);
2302 } else
2303 mdoc->meta.arch = mandoc_strdup(cp);
2304 }
2305
2306 /* Ignore any subsequent parameters... */
2307 /* FIXME: warn about subsequent parameters. */
2308
2309 return(1);
2310 }
2311
2312 static int
2313 post_prol(POST_ARGS)
2314 {
2315 /*
2316 * Remove prologue macros from the document after they're
2317 * processed. The final document uses mdoc_meta for these
2318 * values and discards the originals.
2319 */
2340 if (n && NULL != (n = n->next))
2341 *n->string = (char)toupper
2342 ((unsigned char)*n->string);
2343
2344 return(1);
2345 }
2346
2347 static int
2348 post_os(POST_ARGS)
2349 {
2350 struct mdoc_node *n;
2351 char buf[BUFSIZ];
2352 int c;
2353 #ifndef OSNAME
2354 struct utsname utsname;
2355 #endif
2356
2357 n = mdoc->last;
2358
2359 /*
2360 * Set the operating system by way of the `Os' macro.
2361 * The order of precedence is:
2362 * 1. the argument of the `Os' macro, unless empty
2363 * 2. the -Ios=foo command line argument, if provided
2364 * 3. -DOSNAME="\"foo\"", if provided during compilation
2365 * 4. "sysname release" from uname(3)
2366 */
2367
2368 free(mdoc->meta.os);
2369
2370 buf[0] = '\0';
2371 if (-1 == (c = concat(buf, n->child, BUFSIZ))) {
2372 mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM);
2373 return(0);
2374 }
2375
2376 assert(c);
2377
2378 if ('\0' == buf[0]) {
2379 if (mdoc->defos) {
2380 mdoc->meta.os = mandoc_strdup(mdoc->defos);
2381 return(1);
2382 }
2383 #ifdef OSNAME
2384 if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) {
2385 mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2386 return(0);
2387 }
2388 #else /*!OSNAME */
2389 if (-1 == uname(&utsname)) {
2390 mdoc_nmsg(mdoc, n, MANDOCERR_UNAME);
2391 mdoc->meta.os = mandoc_strdup("UNKNOWN");
2392 return(post_prol(mdoc));
2393 }
2394
2395 if (strlcat(buf, utsname.sysname, BUFSIZ) >= BUFSIZ) {
2396 mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2397 return(0);
2398 }
2399 if (strlcat(buf, " ", BUFSIZ) >= BUFSIZ) {
2400 mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2401 return(0);
2402 }
|