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