Annotation of mandoc/validate.c, Revision 1.62
1.62 ! kristaps 1: /* $Id: validate.c,v 1.61 2009/02/26 14:56:27 kristaps Exp $ */
1.1 kristaps 2: /*
3: * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the
7: * above copyright notice and this permission notice appear in all
8: * copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11: * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12: * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13: * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14: * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15: * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16: * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17: * PERFORMANCE OF THIS SOFTWARE.
18: */
19: #include <assert.h>
1.56 kristaps 20: #include <ctype.h>
1.8 kristaps 21: #include <stdlib.h>
1.1 kristaps 22:
23: #include "private.h"
24:
1.44 kristaps 25: /*
26: * Pre- and post-validate macros as they're parsed. Pre-validation
27: * occurs when the macro has been detected and its arguments parsed.
28: * Post-validation occurs when all child macros have also been parsed.
29: * In the ELEMENT case, this is simply the parameters of the macro; in
30: * the BLOCK case, this is the HEAD, BODY, TAIL and so on.
31: */
32:
1.55 kristaps 33: #define PRE_ARGS struct mdoc *mdoc, const struct mdoc_node *n
34: #define POST_ARGS struct mdoc *mdoc
35:
36: typedef int (*v_pre)(PRE_ARGS);
37: typedef int (*v_post)(POST_ARGS);
1.14 kristaps 38:
1.36 kristaps 39: /* FIXME: some sections should only occur in specific msecs. */
40: /* FIXME: ignoring Pp. */
41: /* FIXME: math symbols. */
42:
1.14 kristaps 43: struct valids {
1.24 kristaps 44: v_pre *pre;
1.17 kristaps 45: v_post *post;
1.14 kristaps 46: };
1.1 kristaps 47:
1.37 kristaps 48: /* Utility checks. */
49:
1.55 kristaps 50: static int check_parent(PRE_ARGS, int, enum mdoc_type);
51: static int check_msec(PRE_ARGS, int, enum mdoc_msec *);
52: static int check_stdarg(PRE_ARGS);
53:
54: static int check_text(struct mdoc *,
55: size_t, size_t, const char *);
56:
1.51 kristaps 57: static int err_child_lt(struct mdoc *, const char *, int);
1.59 kristaps 58: static int warn_child_lt(struct mdoc *, const char *, int);
1.51 kristaps 59: static int err_child_gt(struct mdoc *, const char *, int);
60: static int warn_child_gt(struct mdoc *, const char *, int);
61: static int err_child_eq(struct mdoc *, const char *, int);
62: static int warn_child_eq(struct mdoc *, const char *, int);
63:
64: /* Utility auxiliaries. */
65:
66: static inline int count_child(struct mdoc *);
67: static inline int warn_count(struct mdoc *, const char *,
68: int, const char *, int);
69: static inline int err_count(struct mdoc *, const char *,
70: int, const char *, int);
1.11 kristaps 71:
1.37 kristaps 72: /* Specific pre-child-parse routines. */
73:
1.55 kristaps 74: static int pre_display(PRE_ARGS);
75: static int pre_sh(PRE_ARGS);
76: static int pre_ss(PRE_ARGS);
77: static int pre_bd(PRE_ARGS);
78: static int pre_bl(PRE_ARGS);
79: static int pre_it(PRE_ARGS);
80: static int pre_cd(PRE_ARGS);
81: static int pre_er(PRE_ARGS);
82: static int pre_ex(PRE_ARGS);
83: static int pre_rv(PRE_ARGS);
84: static int pre_an(PRE_ARGS);
85: static int pre_st(PRE_ARGS);
86: static int pre_prologue(PRE_ARGS);
87: static int pre_prologue(PRE_ARGS);
88: static int pre_prologue(PRE_ARGS);
1.24 kristaps 89:
1.37 kristaps 90: /* Specific post-child-parse routines. */
91:
1.55 kristaps 92: static int herr_ge1(POST_ARGS);
1.59 kristaps 93: static int hwarn_le1(POST_ARGS);
1.55 kristaps 94: static int herr_eq0(POST_ARGS);
95: static int eerr_eq0(POST_ARGS);
96: static int eerr_le1(POST_ARGS);
97: static int eerr_le2(POST_ARGS);
98: static int eerr_eq1(POST_ARGS);
99: static int eerr_ge1(POST_ARGS);
100: static int ewarn_eq0(POST_ARGS);
101: static int ewarn_eq1(POST_ARGS);
102: static int bwarn_ge1(POST_ARGS);
1.58 kristaps 103: static int hwarn_eq1(POST_ARGS);
1.55 kristaps 104: static int ewarn_ge1(POST_ARGS);
105: static int ebool(POST_ARGS);
106:
107: static int post_sh(POST_ARGS);
108: static int post_sh_body(POST_ARGS);
109: static int post_sh_head(POST_ARGS);
1.57 kristaps 110: static int post_fd(POST_ARGS);
1.55 kristaps 111: static int post_bl(POST_ARGS);
112: static int post_it(POST_ARGS);
113: static int post_ex(POST_ARGS);
114: static int post_an(POST_ARGS);
115: static int post_at(POST_ARGS);
116: static int post_xr(POST_ARGS);
117: static int post_nm(POST_ARGS);
118: static int post_bf(POST_ARGS);
119: static int post_root(POST_ARGS);
1.37 kristaps 120:
121: /* Collections of pre-child-parse routines. */
1.17 kristaps 122:
1.24 kristaps 123: static v_pre pres_prologue[] = { pre_prologue, NULL };
124: static v_pre pres_d1[] = { pre_display, NULL };
125: static v_pre pres_bd[] = { pre_display, pre_bd, NULL };
126: static v_pre pres_bl[] = { pre_bl, NULL };
1.25 kristaps 127: static v_pre pres_it[] = { pre_it, NULL };
1.33 kristaps 128: static v_pre pres_ss[] = { pre_ss, NULL };
129: static v_pre pres_sh[] = { pre_sh, NULL };
130: static v_pre pres_cd[] = { pre_cd, NULL };
131: static v_pre pres_er[] = { pre_er, NULL };
132: static v_pre pres_ex[] = { pre_ex, NULL };
1.36 kristaps 133: static v_pre pres_rv[] = { pre_rv, NULL };
1.35 kristaps 134: static v_pre pres_an[] = { pre_an, NULL };
1.36 kristaps 135: static v_pre pres_st[] = { pre_st, NULL };
1.24 kristaps 136:
1.37 kristaps 137: /* Collections of post-child-parse routines. */
138:
139: static v_post posts_bool[] = { eerr_eq1, ebool, NULL };
140: static v_post posts_bd[] = { herr_eq0, bwarn_ge1, NULL };
141: static v_post posts_text[] = { eerr_ge1, NULL };
142: static v_post posts_wtext[] = { ewarn_ge1, NULL };
143: static v_post posts_notext[] = { eerr_eq0, NULL };
1.43 kristaps 144: static v_post posts_wline[] = { bwarn_ge1, herr_eq0, NULL };
1.37 kristaps 145: static v_post posts_sh[] = { herr_ge1, bwarn_ge1, post_sh, NULL };
146: static v_post posts_bl[] = { herr_eq0, bwarn_ge1, post_bl, NULL };
1.25 kristaps 147: static v_post posts_it[] = { post_it, NULL };
1.39 kristaps 148: static v_post posts_in[] = { ewarn_eq1, NULL };
1.37 kristaps 149: static v_post posts_ss[] = { herr_ge1, NULL };
1.52 kristaps 150: static v_post posts_pf[] = { eerr_eq1, NULL };
1.37 kristaps 151: static v_post posts_pp[] = { ewarn_eq0, NULL };
152: static v_post posts_ex[] = { eerr_le1, post_ex, NULL };
1.35 kristaps 153: static v_post posts_an[] = { post_an, NULL };
1.37 kristaps 154: static v_post posts_at[] = { post_at, NULL };
155: static v_post posts_xr[] = { eerr_ge1, eerr_le2, post_xr, NULL };
156: static v_post posts_nm[] = { post_nm, NULL };
1.59 kristaps 157: static v_post posts_bf[] = { hwarn_le1, post_bf, NULL };
1.45 kristaps 158: static v_post posts_rs[] = { herr_eq0, bwarn_ge1, NULL };
1.58 kristaps 159: static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL };
1.45 kristaps 160: static v_post posts_bk[] = { herr_eq0, bwarn_ge1, NULL };
1.57 kristaps 161: static v_post posts_fd[] = { ewarn_ge1, post_fd, NULL };
1.9 kristaps 162:
1.37 kristaps 163: /* Per-macro pre- and post-child-check routine collections. */
1.12 kristaps 164:
1.9 kristaps 165: const struct valids mdoc_valids[MDOC_MAX] = {
1.51 kristaps 166: { NULL, NULL }, /* \" */
167: { pres_prologue, posts_text }, /* Dd */
168: { pres_prologue, NULL }, /* Dt */
169: { pres_prologue, NULL }, /* Os */
170: { pres_sh, posts_sh }, /* Sh */
171: { pres_ss, posts_ss }, /* Ss */
172: { NULL, posts_pp }, /* Pp */
173: { pres_d1, posts_wline }, /* D1 */
174: { pres_d1, posts_wline }, /* Dl */
175: { pres_bd, posts_bd }, /* Bd */
176: { NULL, NULL }, /* Ed */
177: { pres_bl, posts_bl }, /* Bl */
178: { NULL, NULL }, /* El */
179: { pres_it, posts_it }, /* It */
180: { NULL, posts_text }, /* Ad */
181: { pres_an, posts_an }, /* An */
182: { NULL, NULL }, /* Ar */
183: { pres_cd, posts_text }, /* Cd */
184: { NULL, NULL }, /* Cm */
185: { NULL, posts_text }, /* Dv */
186: { pres_er, posts_text }, /* Er */
187: { NULL, posts_text }, /* Ev */
188: { pres_ex, posts_ex }, /* Ex */
189: { NULL, posts_text }, /* Fa */
1.57 kristaps 190: { NULL, posts_fd }, /* Fd */
1.51 kristaps 191: { NULL, NULL }, /* Fl */
192: { NULL, posts_text }, /* Fn */
193: { NULL, posts_wtext }, /* Ft */
194: { NULL, posts_text }, /* Ic */
195: { NULL, posts_in }, /* In */
196: { NULL, posts_text }, /* Li */
197: { NULL, posts_wtext }, /* Nd */
198: { NULL, posts_nm }, /* Nm */
199: { NULL, posts_wline }, /* Op */
200: { NULL, NULL }, /* Ot */
201: { NULL, NULL }, /* Pa */
202: { pres_rv, posts_notext }, /* Rv */
203: { pres_st, posts_notext }, /* St */
204: { NULL, posts_text }, /* Va */
205: { NULL, posts_text }, /* Vt */
206: { NULL, posts_xr }, /* Xr */
207: { NULL, posts_text }, /* %A */
208: { NULL, posts_text }, /* %B */
209: { NULL, posts_text }, /* %D */
210: { NULL, posts_text }, /* %I */
211: { NULL, posts_text }, /* %J */
212: { NULL, posts_text }, /* %N */
213: { NULL, posts_text }, /* %O */
214: { NULL, posts_text }, /* %P */
215: { NULL, posts_text }, /* %R */
216: { NULL, posts_text }, /* %T */
217: { NULL, posts_text }, /* %V */
218: { NULL, NULL }, /* Ac */
219: { NULL, NULL }, /* Ao */
220: { NULL, posts_wline }, /* Aq */
221: { NULL, posts_at }, /* At */
222: { NULL, NULL }, /* Bc */
223: { NULL, posts_bf }, /* Bf */
224: { NULL, NULL }, /* Bo */
225: { NULL, posts_wline }, /* Bq */
226: { NULL, NULL }, /* Bsx */
227: { NULL, NULL }, /* Bx */
228: { NULL, posts_bool }, /* Db */
229: { NULL, NULL }, /* Dc */
230: { NULL, NULL }, /* Do */
231: { NULL, posts_wline }, /* Dq */
232: { NULL, NULL }, /* Ec */
233: { NULL, NULL }, /* Ef */
234: { NULL, posts_text }, /* Em */
235: { NULL, NULL }, /* Eo */
236: { NULL, NULL }, /* Fx */
237: { NULL, posts_text }, /* Ms */
238: { NULL, posts_notext }, /* No */
239: { NULL, posts_notext }, /* Ns */
240: { NULL, NULL }, /* Nx */
241: { NULL, NULL }, /* Ox */
242: { NULL, NULL }, /* Pc */
1.52 kristaps 243: { NULL, posts_pf }, /* Pf */
1.51 kristaps 244: { NULL, NULL }, /* Po */
245: { NULL, posts_wline }, /* Pq */
246: { NULL, NULL }, /* Qc */
247: { NULL, posts_wline }, /* Ql */
248: { NULL, NULL }, /* Qo */
249: { NULL, posts_wline }, /* Qq */
250: { NULL, NULL }, /* Re */
251: { NULL, posts_rs }, /* Rs */
252: { NULL, NULL }, /* Sc */
253: { NULL, NULL }, /* So */
254: { NULL, posts_wline }, /* Sq */
255: { NULL, posts_bool }, /* Sm */
256: { NULL, posts_text }, /* Sx */
257: { NULL, posts_text }, /* Sy */
258: { NULL, posts_text }, /* Tn */
259: { NULL, NULL }, /* Ux */
260: { NULL, NULL }, /* Xc */
261: { NULL, NULL }, /* Xo */
262: { NULL, posts_fo }, /* Fo */
263: { NULL, NULL }, /* Fc */
264: { NULL, NULL }, /* Oo */
265: { NULL, NULL }, /* Oc */
266: { NULL, posts_bk }, /* Bk */
267: { NULL, NULL }, /* Ek */
268: { NULL, posts_notext }, /* Bt */
269: { NULL, NULL }, /* Hf */
270: { NULL, NULL }, /* Fr */
271: { NULL, posts_notext }, /* Ud */
1.9 kristaps 272: };
1.6 kristaps 273:
274:
1.57 kristaps 275: int
276: mdoc_valid_pre(struct mdoc *mdoc,
277: const struct mdoc_node *node)
278: {
279: v_pre *p;
280: struct mdoc_arg *argv;
281: size_t argc, i, j, line, pos;
282: const char *tp;
283:
284: if (MDOC_TEXT == node->type) {
285: tp = node->data.text.string;
286: line = node->line;
287: pos = node->pos;
288: return(check_text(mdoc, line, pos, tp));
289: }
290:
291: if (MDOC_BLOCK == node->type || MDOC_ELEM == node->type) {
292: argv = MDOC_BLOCK == node->type ?
293: node->data.block.argv :
294: node->data.elem.argv;
295: argc = MDOC_BLOCK == node->type ?
296: node->data.block.argc :
297: node->data.elem.argc;
298:
299: for (i = 0; i < argc; i++) {
300: if (0 == argv[i].sz)
301: continue;
302: for (j = 0; j < argv[i].sz; j++) {
303: tp = argv[i].value[j];
304: line = argv[i].line;
305: pos = argv[i].pos;
306: if ( ! check_text(mdoc, line, pos, tp))
307: return(0);
308: }
309: }
310: }
311:
312: if (NULL == mdoc_valids[node->tok].pre)
313: return(1);
314: for (p = mdoc_valids[node->tok].pre; *p; p++)
315: if ( ! (*p)(mdoc, node))
316: return(0);
317: return(1);
318: }
319:
320:
321: int
322: mdoc_valid_post(struct mdoc *mdoc)
323: {
324: v_post *p;
325:
326: /*
327: * This check occurs after the macro's children have been filled
328: * in: postfix validation. Since this happens when we're
329: * rewinding the scope tree, it's possible to have multiple
330: * invocations (as by design, for now), we set bit MDOC_VALID to
331: * indicate that we've validated.
332: */
333:
334: if (MDOC_VALID & mdoc->last->flags)
335: return(1);
336: mdoc->last->flags |= MDOC_VALID;
337:
338: if (MDOC_TEXT == mdoc->last->type)
339: return(1);
340: if (MDOC_ROOT == mdoc->last->type)
341: return(post_root(mdoc));
342:
343: if (NULL == mdoc_valids[mdoc->last->tok].post)
344: return(1);
345: for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
346: if ( ! (*p)(mdoc))
347: return(0);
348:
349: return(1);
350: }
351:
352:
353:
1.51 kristaps 354: static inline int
355: warn_count(struct mdoc *m, const char *k,
356: int want, const char *v, int has)
357: {
358:
1.55 kristaps 359: return(mdoc_warn(m, WARN_SYNTAX,
1.58 kristaps 360: "suggests %s %s %d (has %d)",
361: v, k, want, has));
1.51 kristaps 362: }
363:
364:
365: static inline int
366: err_count(struct mdoc *m, const char *k,
367: int want, const char *v, int has)
368: {
369:
1.58 kristaps 370: return(mdoc_err(m, "requires %s %s %d (has %d)",
371: v, k, want, has));
1.51 kristaps 372: }
373:
374:
375: static inline int
376: count_child(struct mdoc *mdoc)
1.36 kristaps 377: {
1.51 kristaps 378: int i;
1.36 kristaps 379: struct mdoc_node *n;
380:
381: for (i = 0, n = mdoc->last->child; n; n = n->next, i++)
382: /* Do nothing */ ;
1.53 kristaps 383:
1.36 kristaps 384: return(i);
385: }
386:
387:
1.53 kristaps 388: /*
389: * Build these up with macros because they're basically the same check
390: * for different inequalities. Yes, this could be done with functions,
391: * but this is reasonable for now.
392: */
1.36 kristaps 393:
1.53 kristaps 394: #define CHECK_CHILD_DEFN(lvl, name, ineq) \
395: static int \
396: lvl##_child_##name(struct mdoc *mdoc, const char *p, int sz) \
397: { \
398: int i; \
399: if ((i = count_child(mdoc)) ineq sz) \
400: return(1); \
401: return(lvl##_count(mdoc, #ineq, sz, p, i)); \
402: }
403:
404: #define CHECK_BODY_DEFN(name, lvl, func, num) \
405: static int \
1.55 kristaps 406: b##lvl##_##name(POST_ARGS) \
1.53 kristaps 407: { \
408: if (MDOC_BODY != mdoc->last->type) \
409: return(1); \
410: return(func(mdoc, "multiline parameters", (num))); \
411: }
412:
413: #define CHECK_ELEM_DEFN(name, lvl, func, num) \
414: static int \
1.55 kristaps 415: e##lvl##_##name(POST_ARGS) \
1.53 kristaps 416: { \
417: assert(MDOC_ELEM == mdoc->last->type); \
418: return(func(mdoc, "line parameters", (num))); \
419: }
420:
421: #define CHECK_HEAD_DEFN(name, lvl, func, num) \
422: static int \
1.55 kristaps 423: h##lvl##_##name(POST_ARGS) \
1.53 kristaps 424: { \
425: if (MDOC_HEAD != mdoc->last->type) \
426: return(1); \
1.58 kristaps 427: return(func(mdoc, "line parameters", (num))); \
1.36 kristaps 428: }
429:
430:
1.53 kristaps 431: CHECK_CHILD_DEFN(warn, gt, >) /* warn_child_gt() */
432: CHECK_CHILD_DEFN(err, gt, >) /* err_child_gt() */
433: CHECK_CHILD_DEFN(warn, eq, ==) /* warn_child_eq() */
434: CHECK_CHILD_DEFN(err, eq, ==) /* err_child_eq() */
435: CHECK_CHILD_DEFN(err, lt, <) /* err_child_lt() */
1.59 kristaps 436: CHECK_CHILD_DEFN(warn, lt, <) /* warn_child_lt() */
1.53 kristaps 437: CHECK_BODY_DEFN(ge1, warn, warn_child_gt, 0) /* bwarn_ge1() */
438: CHECK_ELEM_DEFN(eq1, warn, warn_child_eq, 1) /* ewarn_eq1() */
439: CHECK_ELEM_DEFN(eq0, warn, warn_child_eq, 0) /* ewarn_eq0() */
440: CHECK_ELEM_DEFN(ge1, warn, warn_child_gt, 0) /* ewarn_gt1() */
441: CHECK_ELEM_DEFN(eq1, err, err_child_eq, 1) /* eerr_eq1() */
442: CHECK_ELEM_DEFN(le2, err, err_child_lt, 3) /* eerr_le2() */
443: CHECK_ELEM_DEFN(le1, err, err_child_lt, 2) /* eerr_le1() */
444: CHECK_ELEM_DEFN(eq0, err, err_child_eq, 0) /* eerr_eq0() */
445: CHECK_ELEM_DEFN(ge1, err, err_child_gt, 0) /* eerr_ge1() */
446: CHECK_HEAD_DEFN(eq0, err, err_child_eq, 0) /* herr_eq0() */
1.59 kristaps 447: CHECK_HEAD_DEFN(le1, warn, warn_child_lt, 2) /* hwarn_le1() */
1.53 kristaps 448: CHECK_HEAD_DEFN(ge1, err, err_child_gt, 0) /* herr_ge1() */
1.58 kristaps 449: CHECK_HEAD_DEFN(eq1, warn, warn_child_eq, 1) /* hwarn_eq1() */
1.36 kristaps 450:
451:
452: static int
1.55 kristaps 453: check_stdarg(PRE_ARGS)
1.36 kristaps 454: {
455:
1.55 kristaps 456: if (MDOC_Std == n->data.elem.argv[0].arg &&
457: 1 == n->data.elem.argc)
1.36 kristaps 458: return(1);
1.51 kristaps 459:
1.55 kristaps 460: return(mdoc_nwarn(mdoc, n, WARN_COMPAT,
1.53 kristaps 461: "one argument suggested"));
1.36 kristaps 462: }
463:
464:
465: static int
1.55 kristaps 466: check_msec(PRE_ARGS, int sz, enum mdoc_msec *msecs)
1.33 kristaps 467: {
468: int i;
469:
470: for (i = 0; i < sz; i++)
471: if (msecs[i] == mdoc->meta.msec)
472: return(1);
1.55 kristaps 473: return(mdoc_nwarn(mdoc, n, WARN_COMPAT,
474: "invalid manual section"));
475: }
476:
477:
478: static int
479: check_text(struct mdoc *mdoc, size_t line, size_t pos, const char *p)
480: {
481: size_t c;
482:
1.62 ! kristaps 483: /* XXX - indicate deprecated escapes \*(xx and \*x. */
! 484:
1.55 kristaps 485: for ( ; *p; p++) {
1.60 kristaps 486: if ( ! isprint((int)*p) && '\t' != *p)
1.56 kristaps 487: return(mdoc_perr(mdoc, line, pos,
488: "invalid characters"));
1.55 kristaps 489: if ('\\' != *p)
490: continue;
491: if ((c = mdoc_isescape(p))) {
492: p += (c - 1);
493: continue;
494: }
495: return(mdoc_perr(mdoc, line, pos,
1.56 kristaps 496: "invalid escape sequence"));
1.55 kristaps 497: }
498:
499: return(1);
1.14 kristaps 500: }
501:
502:
1.55 kristaps 503:
504:
1.14 kristaps 505: static int
1.55 kristaps 506: check_parent(PRE_ARGS, int tok, enum mdoc_type t)
1.54 kristaps 507: {
508:
509: assert(n->parent);
510: if ((MDOC_ROOT == t || tok == n->parent->tok) &&
511: (t == n->parent->type))
512: return(1);
513:
514: return(mdoc_nerr(mdoc, n, "require parent %s",
515: MDOC_ROOT == t ? "<root>" : mdoc_macronames[tok]));
516: }
517:
518:
519:
520: static int
1.55 kristaps 521: pre_display(PRE_ARGS)
1.23 kristaps 522: {
1.55 kristaps 523: struct mdoc_node *node;
1.23 kristaps 524:
1.53 kristaps 525: /* Display elements (`Bd', `D1'...) cannot be nested. */
526:
1.55 kristaps 527: if (MDOC_BLOCK != n->type)
1.24 kristaps 528: return(1);
529:
1.38 kristaps 530: /* LINTED */
1.55 kristaps 531: for (node = mdoc->last->parent; node; node = node->parent)
532: if (MDOC_BLOCK == node->type)
533: if (MDOC_Bd == node->tok)
1.23 kristaps 534: break;
1.55 kristaps 535: if (NULL == node)
1.23 kristaps 536: return(1);
1.53 kristaps 537:
1.55 kristaps 538: return(mdoc_nerr(mdoc, n, "displays may not be nested"));
1.23 kristaps 539: }
540:
541:
542: static int
1.55 kristaps 543: pre_bl(PRE_ARGS)
1.24 kristaps 544: {
1.61 kristaps 545: int type, i, width, offset;
1.24 kristaps 546: struct mdoc_arg *argv;
1.53 kristaps 547: size_t argc;
1.24 kristaps 548:
1.55 kristaps 549: if (MDOC_BLOCK != n->type)
1.24 kristaps 550: return(1);
551:
1.55 kristaps 552: argc = n->data.block.argc;
1.24 kristaps 553:
1.53 kristaps 554: /* Make sure that only one type of list is specified. */
555:
1.61 kristaps 556: type = offset = width = -1;
557:
1.38 kristaps 558: /* LINTED */
1.61 kristaps 559: for (i = 0; i < (int)argc; i++) {
1.55 kristaps 560: argv = &n->data.block.argv[i];
1.53 kristaps 561:
1.24 kristaps 562: switch (argv->arg) {
563: case (MDOC_Bullet):
564: /* FALLTHROUGH */
565: case (MDOC_Dash):
566: /* FALLTHROUGH */
567: case (MDOC_Enum):
568: /* FALLTHROUGH */
569: case (MDOC_Hyphen):
570: /* FALLTHROUGH */
571: case (MDOC_Item):
572: /* FALLTHROUGH */
573: case (MDOC_Tag):
574: /* FALLTHROUGH */
575: case (MDOC_Diag):
576: /* FALLTHROUGH */
577: case (MDOC_Hang):
578: /* FALLTHROUGH */
579: case (MDOC_Ohang):
580: /* FALLTHROUGH */
581: case (MDOC_Inset):
1.26 kristaps 582: /* FALLTHROUGH */
583: case (MDOC_Column):
1.61 kristaps 584: if (-1 == type) {
585: type = argv->arg;
1.53 kristaps 586: break;
1.61 kristaps 587: }
1.53 kristaps 588: return(mdoc_perr(mdoc, argv->line, argv->pos,
589: "multiple types specified"));
1.61 kristaps 590: case (MDOC_Width):
591: if (-1 == width) {
592: width = argv->arg;
593: break;
594: }
595: return(mdoc_perr(mdoc, argv->line, argv->pos,
596: "multiple -%s arguments",
597: mdoc_argnames[MDOC_Width]));
598: case (MDOC_Offset):
599: if (-1 == offset) {
600: offset = argv->arg;
601: break;
602: }
603: return(mdoc_perr(mdoc, argv->line, argv->pos,
604: "multiple -%s arguments",
605: mdoc_argnames[MDOC_Offset]));
1.24 kristaps 606: default:
607: break;
608: }
609: }
1.53 kristaps 610:
1.61 kristaps 611: if (-1 == type)
612: return(mdoc_err(mdoc, "no type specified"));
613:
614: switch (type) {
615: case (MDOC_Column):
616: /* FALLTHROUGH */
617: case (MDOC_Diag):
618: /* FALLTHROUGH */
619: case (MDOC_Inset):
620: /* FALLTHROUGH */
621: case (MDOC_Item):
622: if (-1 == width)
623: break;
624: return(mdoc_nwarn(mdoc, n, WARN_SYNTAX,
625: "superfluous -%s argument",
626: mdoc_argnames[MDOC_Width]));
627: case (MDOC_Tag):
628: if (-1 != width)
629: break;
630: return(mdoc_nwarn(mdoc, n, WARN_SYNTAX,
631: "suggest -%s argument",
632: mdoc_argnames[MDOC_Width]));
633: default:
634: break;
635: }
636:
637: return(1);
1.24 kristaps 638: }
639:
640:
641: static int
1.55 kristaps 642: pre_bd(PRE_ARGS)
1.24 kristaps 643: {
1.53 kristaps 644: int type, err, i;
1.24 kristaps 645: struct mdoc_arg *argv;
1.53 kristaps 646: size_t argc;
1.24 kristaps 647:
1.55 kristaps 648: if (MDOC_BLOCK != n->type)
1.24 kristaps 649: return(1);
650:
1.55 kristaps 651: argc = n->data.block.argc;
1.24 kristaps 652:
1.53 kristaps 653: /* Make sure that only one type of display is specified. */
654:
1.38 kristaps 655: /* LINTED */
1.53 kristaps 656: for (i = 0, err = type = 0; ! err && i < (int)argc; i++) {
1.55 kristaps 657: argv = &n->data.block.argv[i];
1.53 kristaps 658:
1.24 kristaps 659: switch (argv->arg) {
660: case (MDOC_Ragged):
661: /* FALLTHROUGH */
662: case (MDOC_Unfilled):
663: /* FALLTHROUGH */
1.29 kristaps 664: case (MDOC_Filled):
665: /* FALLTHROUGH */
1.24 kristaps 666: case (MDOC_Literal):
667: /* FALLTHROUGH */
668: case (MDOC_File):
1.53 kristaps 669: if (0 == type++)
670: break;
671: return(mdoc_perr(mdoc, argv->line, argv->pos,
672: "multiple types specified"));
1.24 kristaps 673: default:
674: break;
675: }
676: }
1.53 kristaps 677:
678: if (type)
679: return(1);
680: return(mdoc_err(mdoc, "no type specified"));
1.24 kristaps 681: }
682:
683:
684: static int
1.55 kristaps 685: pre_ss(PRE_ARGS)
1.33 kristaps 686: {
687:
1.55 kristaps 688: if (MDOC_BLOCK != n->type)
1.33 kristaps 689: return(1);
1.55 kristaps 690: return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY));
1.33 kristaps 691: }
692:
693:
694: static int
1.55 kristaps 695: pre_sh(PRE_ARGS)
1.33 kristaps 696: {
697:
1.55 kristaps 698: if (MDOC_BLOCK != n->type)
1.33 kristaps 699: return(1);
1.55 kristaps 700: return(check_parent(mdoc, n, -1, MDOC_ROOT));
1.33 kristaps 701: }
702:
703:
704: static int
1.55 kristaps 705: pre_it(PRE_ARGS)
1.53 kristaps 706: {
707:
708: /* TODO: children too big for -width? */
709:
1.55 kristaps 710: if (MDOC_BLOCK != n->type)
1.53 kristaps 711: return(1);
1.55 kristaps 712: return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY));
1.53 kristaps 713: }
714:
715:
716: static int
1.55 kristaps 717: pre_st(PRE_ARGS)
1.36 kristaps 718: {
719:
1.55 kristaps 720: if (1 == n->data.elem.argc)
1.36 kristaps 721: return(1);
1.55 kristaps 722: return(mdoc_nerr(mdoc, n, "one argument required"));
1.36 kristaps 723: }
724:
725:
726: static int
1.55 kristaps 727: pre_an(PRE_ARGS)
1.35 kristaps 728: {
1.36 kristaps 729:
1.55 kristaps 730: if (1 >= n->data.elem.argc)
1.35 kristaps 731: return(1);
1.55 kristaps 732: return(mdoc_nerr(mdoc, n, "one argument allowed"));
1.35 kristaps 733: }
734:
735:
736: static int
1.55 kristaps 737: pre_rv(PRE_ARGS)
1.36 kristaps 738: {
1.53 kristaps 739: enum mdoc_msec msecs[] = { MSEC_2, MSEC_3 };
1.36 kristaps 740:
1.55 kristaps 741: if ( ! check_msec(mdoc, n, 2, msecs))
1.36 kristaps 742: return(0);
1.55 kristaps 743: return(check_stdarg(mdoc, n));
1.36 kristaps 744: }
745:
746:
747: static int
1.55 kristaps 748: pre_ex(PRE_ARGS)
1.33 kristaps 749: {
1.53 kristaps 750: enum mdoc_msec msecs[] = { MSEC_1, MSEC_6, MSEC_8 };
1.35 kristaps 751:
1.55 kristaps 752: if ( ! check_msec(mdoc, n, 3, msecs))
1.35 kristaps 753: return(0);
1.55 kristaps 754: return(check_stdarg(mdoc, n));
1.33 kristaps 755: }
756:
757:
758: static int
1.55 kristaps 759: pre_er(PRE_ARGS)
1.33 kristaps 760: {
1.53 kristaps 761: enum mdoc_msec msecs[] = { MSEC_2 };
1.33 kristaps 762:
1.55 kristaps 763: return(check_msec(mdoc, n, 1, msecs));
1.33 kristaps 764: }
765:
766:
767: static int
1.55 kristaps 768: pre_cd(PRE_ARGS)
1.33 kristaps 769: {
1.53 kristaps 770: enum mdoc_msec msecs[] = { MSEC_4 };
1.33 kristaps 771:
1.55 kristaps 772: return(check_msec(mdoc, n, 1, msecs));
1.33 kristaps 773: }
774:
775:
776: static int
1.55 kristaps 777: pre_prologue(PRE_ARGS)
1.20 kristaps 778: {
779:
1.46 kristaps 780: if (SEC_PROLOGUE != mdoc->lastnamed)
1.55 kristaps 781: return(mdoc_nerr(mdoc, n, "prologue only"));
1.20 kristaps 782:
783: /* Check for ordering. */
784:
1.55 kristaps 785: switch (n->tok) {
1.20 kristaps 786: case (MDOC_Os):
1.36 kristaps 787: if (mdoc->meta.title && mdoc->meta.date)
1.20 kristaps 788: break;
1.55 kristaps 789: return(mdoc_nerr(mdoc, n, "prologue out-of-order"));
1.20 kristaps 790: case (MDOC_Dt):
1.36 kristaps 791: if (NULL == mdoc->meta.title && mdoc->meta.date)
1.20 kristaps 792: break;
1.55 kristaps 793: return(mdoc_nerr(mdoc, n, "prologue out-of-order"));
1.20 kristaps 794: case (MDOC_Dd):
1.36 kristaps 795: if (NULL == mdoc->meta.title && 0 == mdoc->meta.date)
1.20 kristaps 796: break;
1.55 kristaps 797: return(mdoc_nerr(mdoc, n, "prologue out-of-order"));
1.20 kristaps 798: default:
799: abort();
800: /* NOTREACHED */
801: }
802:
803: /* Check for repetition. */
804:
1.55 kristaps 805: switch (n->tok) {
1.20 kristaps 806: case (MDOC_Os):
1.36 kristaps 807: if (NULL == mdoc->meta.os)
1.20 kristaps 808: return(1);
809: break;
810: case (MDOC_Dd):
811: if (0 == mdoc->meta.date)
812: return(1);
813: break;
814: case (MDOC_Dt):
1.36 kristaps 815: if (NULL == mdoc->meta.title)
1.20 kristaps 816: return(1);
817: break;
818: default:
819: abort();
820: /* NOTREACHED */
821: }
822:
1.55 kristaps 823: return(mdoc_nerr(mdoc, n, "prologue repetition"));
1.20 kristaps 824: }
825:
826:
1.35 kristaps 827: static int
1.55 kristaps 828: post_bf(POST_ARGS)
1.41 kristaps 829: {
830: char *p;
831: struct mdoc_node *head;
832:
833: if (MDOC_BLOCK != mdoc->last->type)
834: return(1);
1.53 kristaps 835:
1.41 kristaps 836: head = mdoc->last->data.block.head;
837:
838: if (0 == mdoc->last->data.block.argc) {
1.53 kristaps 839: if (NULL == head->child)
840: return(mdoc_err(mdoc, "argument expected"));
841:
842: p = head->child->data.text.string;
843: if (xstrcmp(p, "Em"))
844: return(1);
845: else if (xstrcmp(p, "Li"))
846: return(1);
847: else if (xstrcmp(p, "Sm"))
848: return(1);
849: return(mdoc_nerr(mdoc, head->child, "invalid font"));
1.41 kristaps 850: }
1.53 kristaps 851:
1.41 kristaps 852: if (head->child)
1.53 kristaps 853: return(mdoc_err(mdoc, "argument expected"));
854:
1.41 kristaps 855: if (1 == mdoc->last->data.block.argc)
856: return(1);
1.53 kristaps 857: return(mdoc_err(mdoc, "argument expected"));
1.41 kristaps 858: }
859:
860:
861: static int
1.55 kristaps 862: post_nm(POST_ARGS)
1.37 kristaps 863: {
864:
865: if (mdoc->last->child)
866: return(1);
867: if (mdoc->meta.name)
868: return(1);
1.53 kristaps 869: return(mdoc_err(mdoc, "not yet invoked with name"));
1.37 kristaps 870: }
871:
872:
873: static int
1.55 kristaps 874: post_xr(POST_ARGS)
1.36 kristaps 875: {
876: struct mdoc_node *n;
877:
878: if (NULL == (n = mdoc->last->child->next))
879: return(1);
880: if (MSEC_DEFAULT != mdoc_atomsec(n->data.text.string))
881: return(1);
882: return(mdoc_nerr(mdoc, n, "invalid manual section"));
883: }
884:
885:
886: static int
1.55 kristaps 887: post_at(POST_ARGS)
1.36 kristaps 888: {
889:
1.37 kristaps 890: if (NULL == mdoc->last->child)
891: return(1);
1.36 kristaps 892: if (ATT_DEFAULT != mdoc_atoatt(mdoc->last->child->data.text.string))
893: return(1);
1.53 kristaps 894: return(mdoc_err(mdoc, "require valid symbol"));
1.36 kristaps 895: }
896:
897:
898: static int
1.55 kristaps 899: post_an(POST_ARGS)
1.35 kristaps 900: {
901:
902: if (0 != mdoc->last->data.elem.argc) {
903: if (NULL == mdoc->last->child)
904: return(1);
1.53 kristaps 905: return(mdoc_err(mdoc, "argument(s) expected"));
1.35 kristaps 906: }
907:
908: if (mdoc->last->child)
909: return(1);
1.53 kristaps 910: return(mdoc_err(mdoc, "argument(s) expected"));
1.35 kristaps 911: }
912:
913:
914: static int
1.55 kristaps 915: post_ex(POST_ARGS)
1.35 kristaps 916: {
917:
918: if (0 == mdoc->last->data.elem.argc) {
919: if (mdoc->last->child)
920: return(1);
1.53 kristaps 921: return(mdoc_err(mdoc, "argument(s) expected"));
1.35 kristaps 922: }
923: if (mdoc->last->child)
1.53 kristaps 924: return(mdoc_err(mdoc, "argument(s) expected"));
1.35 kristaps 925: if (1 != mdoc->last->data.elem.argc)
1.53 kristaps 926: return(mdoc_err(mdoc, "argument(s) expected"));
1.35 kristaps 927: if (MDOC_Std != mdoc->last->data.elem.argv[0].arg)
1.53 kristaps 928: return(mdoc_err(mdoc, "argument(s) expected"));
929:
1.35 kristaps 930: return(1);
931: }
932:
933:
1.25 kristaps 934: static int
1.55 kristaps 935: post_it(POST_ARGS)
1.25 kristaps 936: {
1.53 kristaps 937: int type, sv, i;
1.25 kristaps 938: #define TYPE_NONE (0)
939: #define TYPE_BODY (1)
940: #define TYPE_HEAD (2)
1.47 kristaps 941: #define TYPE_OHEAD (3)
1.53 kristaps 942: size_t argc;
1.25 kristaps 943: struct mdoc_node *n;
944:
945: if (MDOC_BLOCK != mdoc->last->type)
946: return(1);
947:
1.53 kristaps 948: n = mdoc->last->parent->parent;
1.25 kristaps 949:
950: argc = n->data.block.argc;
951: type = TYPE_NONE;
1.38 kristaps 952: sv = -1;
1.26 kristaps 953:
954: /* Some types require block-head, some not. */
1.25 kristaps 955:
1.38 kristaps 956: /* LINTED */
1.53 kristaps 957: for (i = 0; TYPE_NONE == type && i < (int)argc; i++)
958: switch (n->data.block.argv[i].arg) {
1.25 kristaps 959: case (MDOC_Tag):
960: /* FALLTHROUGH */
961: case (MDOC_Diag):
962: /* FALLTHROUGH */
963: case (MDOC_Hang):
964: /* FALLTHROUGH */
965: case (MDOC_Ohang):
966: /* FALLTHROUGH */
967: case (MDOC_Inset):
968: type = TYPE_HEAD;
1.53 kristaps 969: sv = n->data.block.argv[i].arg;
1.25 kristaps 970: break;
971: case (MDOC_Bullet):
972: /* FALLTHROUGH */
973: case (MDOC_Dash):
974: /* FALLTHROUGH */
975: case (MDOC_Enum):
976: /* FALLTHROUGH */
977: case (MDOC_Hyphen):
978: /* FALLTHROUGH */
979: case (MDOC_Item):
1.47 kristaps 980: type = TYPE_BODY;
1.53 kristaps 981: sv = n->data.block.argv[i].arg;
1.47 kristaps 982: break;
1.25 kristaps 983: case (MDOC_Column):
1.47 kristaps 984: type = TYPE_OHEAD;
1.53 kristaps 985: sv = n->data.block.argv[i].arg;
1.25 kristaps 986: break;
987: default:
988: break;
989: }
990:
991: assert(TYPE_NONE != type);
992:
1.47 kristaps 993: n = mdoc->last->data.block.head;
994:
1.25 kristaps 995: if (TYPE_HEAD == type) {
1.33 kristaps 996: if (NULL == n->child)
1.53 kristaps 997: if ( ! mdoc_warn(mdoc, WARN_SYNTAX,
998: "argument(s) suggested"))
1.25 kristaps 999: return(0);
1000:
1.33 kristaps 1001: n = mdoc->last->data.block.body;
1002: if (NULL == n->child)
1.53 kristaps 1003: if ( ! mdoc_warn(mdoc, WARN_SYNTAX,
1004: "multiline body suggested"))
1.25 kristaps 1005: return(0);
1006:
1.47 kristaps 1007: } else if (TYPE_BODY == type) {
1008: if (n->child)
1.53 kristaps 1009: if ( ! mdoc_warn(mdoc, WARN_SYNTAX,
1010: "no argument suggested"))
1.47 kristaps 1011: return(0);
1012:
1013: n = mdoc->last->data.block.body;
1014: if (NULL == n->child)
1.53 kristaps 1015: if ( ! mdoc_warn(mdoc, WARN_SYNTAX,
1016: "multiline body suggested"))
1.47 kristaps 1017: return(0);
1018: } else {
1019: if (NULL == n->child)
1.53 kristaps 1020: if ( ! mdoc_warn(mdoc, WARN_SYNTAX,
1021: "argument(s) suggested"))
1.47 kristaps 1022: return(0);
1023:
1024: n = mdoc->last->data.block.body;
1025: if (n->child)
1.53 kristaps 1026: if ( ! mdoc_warn(mdoc, WARN_SYNTAX,
1027: "no multiline body suggested"))
1.47 kristaps 1028: return(0);
1.25 kristaps 1029: }
1030:
1.47 kristaps 1031: if (MDOC_Column != sv)
1.26 kristaps 1032: return(1);
1033:
1.38 kristaps 1034: argc = mdoc->last->parent->parent->data.block.argv->sz;
1.26 kristaps 1035: n = mdoc->last->data.block.head->child;
1.25 kristaps 1036:
1.26 kristaps 1037: for (i = 0; n; n = n->next)
1038: i++;
1039:
1.53 kristaps 1040: if (i == (int)argc)
1.26 kristaps 1041: return(1);
1.53 kristaps 1042:
1043: return(mdoc_err(mdoc, "need %zu columns (have %d)", argc, i));
1.25 kristaps 1044: #undef TYPE_NONE
1045: #undef TYPE_BODY
1046: #undef TYPE_HEAD
1.47 kristaps 1047: #undef TYPE_OHEAD
1.25 kristaps 1048: }
1049:
1050:
1.24 kristaps 1051: static int
1.55 kristaps 1052: post_bl(POST_ARGS)
1.24 kristaps 1053: {
1.53 kristaps 1054: struct mdoc_node *n;
1.24 kristaps 1055:
1056: if (MDOC_BODY != mdoc->last->type)
1057: return(1);
1058:
1.38 kristaps 1059: /* LINTED */
1.24 kristaps 1060: for (n = mdoc->last->child; n; n = n->next) {
1061: if (MDOC_BLOCK == n->type)
1.25 kristaps 1062: if (MDOC_It == n->tok)
1.24 kristaps 1063: continue;
1064: break;
1065: }
1.53 kristaps 1066:
1.24 kristaps 1067: if (NULL == n)
1068: return(1);
1.53 kristaps 1069:
1070: return(mdoc_nerr(mdoc, n, "bad child of parent list"));
1.24 kristaps 1071: }
1072:
1073:
1.34 kristaps 1074: static int
1.37 kristaps 1075: ebool(struct mdoc *mdoc)
1.34 kristaps 1076: {
1077: struct mdoc_node *n;
1078:
1.38 kristaps 1079: /* LINTED */
1.34 kristaps 1080: for (n = mdoc->last->child; n; n = n->next) {
1081: if (MDOC_TEXT != n->type)
1082: break;
1083: if (xstrcmp(n->data.text.string, "on"))
1084: continue;
1085: if (xstrcmp(n->data.text.string, "off"))
1086: continue;
1087: break;
1088: }
1.53 kristaps 1089:
1.34 kristaps 1090: if (NULL == n)
1091: return(1);
1.53 kristaps 1092: return(mdoc_nerr(mdoc, n, "expected boolean"));
1.37 kristaps 1093: }
1094:
1095:
1096: static int
1.55 kristaps 1097: post_root(POST_ARGS)
1.37 kristaps 1098: {
1099:
1.46 kristaps 1100: if (NULL == mdoc->first->child)
1.53 kristaps 1101: return(mdoc_err(mdoc, "document lacks data"));
1.46 kristaps 1102: if (SEC_PROLOGUE == mdoc->lastnamed)
1.53 kristaps 1103: return(mdoc_err(mdoc, "document lacks prologue"));
1104:
1.46 kristaps 1105: if (MDOC_BLOCK != mdoc->first->child->type)
1.54 kristaps 1106: return(mdoc_err(mdoc, "lacking post-prologue %s",
1.53 kristaps 1107: mdoc_macronames[MDOC_Sh]));
1.46 kristaps 1108: if (MDOC_Sh != mdoc->first->child->tok)
1.54 kristaps 1109: return(mdoc_err(mdoc, "lacking post-prologue %s",
1.53 kristaps 1110: mdoc_macronames[MDOC_Sh]));
1111:
1.37 kristaps 1112: return(1);
1.34 kristaps 1113: }
1114:
1115:
1.20 kristaps 1116: static int
1.55 kristaps 1117: post_sh(POST_ARGS)
1.14 kristaps 1118: {
1.46 kristaps 1119:
1120: if (MDOC_HEAD == mdoc->last->type)
1121: return(post_sh_head(mdoc));
1122: if (MDOC_BODY == mdoc->last->type)
1123: return(post_sh_body(mdoc));
1.53 kristaps 1124:
1.46 kristaps 1125: return(1);
1126: }
1127:
1128:
1129: static int
1.55 kristaps 1130: post_sh_body(POST_ARGS)
1.46 kristaps 1131: {
1132: struct mdoc_node *n;
1133:
1134: if (SEC_NAME != mdoc->lastnamed)
1135: return(1);
1136:
1.51 kristaps 1137: /*
1138: * Warn if the NAME section doesn't contain the `Nm' and `Nd'
1139: * macros (can have multiple `Nm' and one `Nd'). Note that the
1140: * children of the BODY declaration can also be "text".
1141: */
1142:
1.46 kristaps 1143: if (NULL == (n = mdoc->last->child))
1.54 kristaps 1144: return(mdoc_warn(mdoc, WARN_SYNTAX,
1145: "section should have %s and %s",
1.51 kristaps 1146: mdoc_macronames[MDOC_Nm],
1147: mdoc_macronames[MDOC_Nd]));
1148:
1149: for ( ; n && n->next; n = n->next) {
1150: if (MDOC_ELEM == n->type && MDOC_Nm == n->tok)
1151: continue;
1152: if (MDOC_TEXT == n->type)
1153: continue;
1.54 kristaps 1154: if ( ! (mdoc_nwarn(mdoc, n, WARN_SYNTAX,
1155: "section should have %s first",
1.51 kristaps 1156: mdoc_macronames[MDOC_Nm])))
1157: return(0);
1158: }
1159:
1160: if (MDOC_ELEM == n->type && MDOC_Nd == n->tok)
1.46 kristaps 1161: return(1);
1162:
1.54 kristaps 1163: return(mdoc_warn(mdoc, WARN_SYNTAX,
1164: "section should have %s last",
1.51 kristaps 1165: mdoc_macronames[MDOC_Nd]));
1.46 kristaps 1166: }
1167:
1168:
1169: static int
1.55 kristaps 1170: post_sh_head(POST_ARGS)
1.46 kristaps 1171: {
1.36 kristaps 1172: char buf[64];
1.21 kristaps 1173: enum mdoc_sec sec;
1174:
1.25 kristaps 1175: assert(MDOC_Sh == mdoc->last->tok);
1.21 kristaps 1176:
1.54 kristaps 1177: if ( ! xstrlcats(buf, mdoc->last->child, sizeof(buf)))
1178: return(mdoc_err(mdoc, "argument too long"));
1.14 kristaps 1179:
1.46 kristaps 1180: sec = mdoc_atosec(buf);
1181:
1182: if (SEC_BODY == mdoc->lastnamed && SEC_NAME != sec)
1.54 kristaps 1183: return(mdoc_warn(mdoc, WARN_SYNTAX,
1184: "section NAME should be first"));
1.46 kristaps 1185: if (SEC_CUSTOM == sec)
1.21 kristaps 1186: return(1);
1.46 kristaps 1187: if (sec == mdoc->lastnamed)
1.54 kristaps 1188: return(mdoc_warn(mdoc, WARN_SYNTAX,
1189: "section repeated"));
1.46 kristaps 1190: if (sec < mdoc->lastnamed)
1.54 kristaps 1191: return(mdoc_warn(mdoc, WARN_SYNTAX,
1192: "section out of order"));
1.46 kristaps 1193:
1194: return(1);
1.11 kristaps 1195: }
1196:
1197:
1.57 kristaps 1198: static int
1199: post_fd(POST_ARGS)
1.11 kristaps 1200: {
1.39 kristaps 1201:
1.57 kristaps 1202: if (SEC_SYNOPSIS == mdoc->last->sec)
1.25 kristaps 1203: return(1);
1.57 kristaps 1204: return(mdoc_warn(mdoc, WARN_COMPAT,
1205: "suggested only in section SYNOPSIS"));
1.11 kristaps 1206: }
CVSweb