Annotation of mandoc/mdoc_validate.c, Revision 1.122
1.122 ! kristaps 1: /* $Id: mdoc_validate.c,v 1.121 2010/10/11 15:46:19 kristaps Exp $ */
1.1 kristaps 2: /*
1.110 schwarze 3: * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
1.1 kristaps 4: *
5: * Permission to use, copy, modify, and distribute this software for any
1.5 kristaps 6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 8: *
1.5 kristaps 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 kristaps 16: */
1.56 kristaps 17: #ifdef HAVE_CONFIG_H
18: #include "config.h"
19: #endif
20:
1.1 kristaps 21: #include <sys/types.h>
22:
23: #include <assert.h>
24: #include <ctype.h>
1.35 kristaps 25: #include <limits.h>
1.81 kristaps 26: #include <stdio.h>
1.1 kristaps 27: #include <stdlib.h>
1.2 kristaps 28: #include <string.h>
1.1 kristaps 29:
1.79 kristaps 30: #include "mandoc.h"
1.1 kristaps 31: #include "libmdoc.h"
1.18 kristaps 32: #include "libmandoc.h"
1.1 kristaps 33:
34: /* FIXME: .Bl -diag can't have non-text children in HEAD. */
35:
1.91 kristaps 36: #define PRE_ARGS struct mdoc *mdoc, struct mdoc_node *n
1.32 kristaps 37: #define POST_ARGS struct mdoc *mdoc
1.1 kristaps 38:
1.120 kristaps 39: enum check_ineq {
40: CHECK_LT,
41: CHECK_GT,
42: CHECK_EQ
43: };
44:
45: enum check_lvl {
46: CHECK_WARN,
47: CHECK_ERROR,
48: CHECK_FATAL
49: };
50:
1.1 kristaps 51: typedef int (*v_pre)(PRE_ARGS);
52: typedef int (*v_post)(POST_ARGS);
53:
54: struct valids {
55: v_pre *pre;
56: v_post *post;
57: };
58:
1.120 kristaps 59: static int check_count(struct mdoc *, enum mdoc_type,
60: enum check_lvl, enum check_ineq, int);
1.59 kristaps 61: static int check_parent(PRE_ARGS, enum mdoct, enum mdoc_type);
1.32 kristaps 62: static int check_stdarg(PRE_ARGS);
1.92 kristaps 63: static int check_text(struct mdoc *, int, int, char *);
1.32 kristaps 64: static int check_argv(struct mdoc *,
1.92 kristaps 65: struct mdoc_node *, struct mdoc_argv *);
66: static int check_args(struct mdoc *, struct mdoc_node *);
1.32 kristaps 67:
1.120 kristaps 68: static int ebool(POST_ARGS);
1.32 kristaps 69: static int berr_ge1(POST_ARGS);
70: static int bwarn_ge1(POST_ARGS);
1.120 kristaps 71: static int eerr_eq0(POST_ARGS);
1.32 kristaps 72: static int eerr_eq1(POST_ARGS);
73: static int eerr_ge1(POST_ARGS);
1.46 kristaps 74: static int eerr_le1(POST_ARGS);
1.116 kristaps 75: static int ewarn_eq0(POST_ARGS);
1.32 kristaps 76: static int ewarn_ge1(POST_ARGS);
77: static int herr_eq0(POST_ARGS);
78: static int herr_ge1(POST_ARGS);
1.120 kristaps 79: static int hwarn_eq0(POST_ARGS);
1.32 kristaps 80: static int hwarn_eq1(POST_ARGS);
81: static int hwarn_le1(POST_ARGS);
82:
83: static int post_an(POST_ARGS);
84: static int post_at(POST_ARGS);
85: static int post_bf(POST_ARGS);
86: static int post_bl(POST_ARGS);
87: static int post_bl_head(POST_ARGS);
1.85 kristaps 88: static int post_dt(POST_ARGS);
1.32 kristaps 89: static int post_it(POST_ARGS);
90: static int post_lb(POST_ARGS);
91: static int post_nm(POST_ARGS);
92: static int post_root(POST_ARGS);
1.43 kristaps 93: static int post_rs(POST_ARGS);
1.32 kristaps 94: static int post_sh(POST_ARGS);
95: static int post_sh_body(POST_ARGS);
96: static int post_sh_head(POST_ARGS);
97: static int post_st(POST_ARGS);
1.84 kristaps 98: static int post_eoln(POST_ARGS);
1.57 kristaps 99: static int post_vt(POST_ARGS);
1.32 kristaps 100: static int pre_an(PRE_ARGS);
101: static int pre_bd(PRE_ARGS);
102: static int pre_bl(PRE_ARGS);
103: static int pre_dd(PRE_ARGS);
104: static int pre_display(PRE_ARGS);
105: static int pre_dt(PRE_ARGS);
106: static int pre_it(PRE_ARGS);
107: static int pre_os(PRE_ARGS);
1.117 kristaps 108: static int pre_pp(PRE_ARGS);
1.32 kristaps 109: static int pre_rv(PRE_ARGS);
110: static int pre_sh(PRE_ARGS);
111: static int pre_ss(PRE_ARGS);
112:
113: static v_post posts_an[] = { post_an, NULL };
114: static v_post posts_at[] = { post_at, NULL };
1.101 schwarze 115: static v_post posts_bd_bk[] = { hwarn_eq0, bwarn_ge1, NULL };
1.32 kristaps 116: static v_post posts_bf[] = { hwarn_le1, post_bf, NULL };
117: static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL };
118: static v_post posts_bool[] = { eerr_eq1, ebool, NULL };
1.84 kristaps 119: static v_post posts_eoln[] = { post_eoln, NULL };
1.85 kristaps 120: static v_post posts_dt[] = { post_dt, NULL };
1.32 kristaps 121: static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL };
122: static v_post posts_it[] = { post_it, NULL };
123: static v_post posts_lb[] = { eerr_eq1, post_lb, NULL };
124: static v_post posts_nd[] = { berr_ge1, NULL };
125: static v_post posts_nm[] = { post_nm, NULL };
1.116 kristaps 126: static v_post posts_notext[] = { ewarn_eq0, NULL };
1.44 kristaps 127: static v_post posts_rs[] = { berr_ge1, herr_eq0, post_rs, NULL };
1.32 kristaps 128: static v_post posts_sh[] = { herr_ge1, bwarn_ge1, post_sh, NULL };
1.46 kristaps 129: static v_post posts_sp[] = { eerr_le1, NULL };
1.32 kristaps 130: static v_post posts_ss[] = { herr_ge1, NULL };
131: static v_post posts_st[] = { eerr_eq1, post_st, NULL };
132: static v_post posts_text[] = { eerr_ge1, NULL };
1.51 kristaps 133: static v_post posts_text1[] = { eerr_eq1, NULL };
1.57 kristaps 134: static v_post posts_vt[] = { post_vt, NULL };
1.32 kristaps 135: static v_post posts_wline[] = { bwarn_ge1, herr_eq0, NULL };
136: static v_post posts_wtext[] = { ewarn_ge1, NULL };
137: static v_pre pres_an[] = { pre_an, NULL };
1.117 kristaps 138: static v_pre pres_bd[] = { pre_display, pre_bd, pre_pp, NULL };
139: static v_pre pres_bl[] = { pre_bl, pre_pp, NULL };
1.32 kristaps 140: static v_pre pres_d1[] = { pre_display, NULL };
141: static v_pre pres_dd[] = { pre_dd, NULL };
142: static v_pre pres_dt[] = { pre_dt, NULL };
1.67 kristaps 143: static v_pre pres_er[] = { NULL, NULL };
1.76 kristaps 144: static v_pre pres_ex[] = { NULL, NULL };
1.77 kristaps 145: static v_pre pres_fd[] = { NULL, NULL };
1.32 kristaps 146: static v_pre pres_it[] = { pre_it, NULL };
147: static v_pre pres_os[] = { pre_os, NULL };
1.117 kristaps 148: static v_pre pres_pp[] = { pre_pp, NULL };
1.32 kristaps 149: static v_pre pres_rv[] = { pre_rv, NULL };
150: static v_pre pres_sh[] = { pre_sh, NULL };
151: static v_pre pres_ss[] = { pre_ss, NULL };
1.1 kristaps 152:
153: const struct valids mdoc_valids[MDOC_MAX] = {
1.10 kristaps 154: { NULL, NULL }, /* Ap */
1.114 kristaps 155: { pres_dd, posts_wtext }, /* Dd */
1.85 kristaps 156: { pres_dt, posts_dt }, /* Dt */
1.1 kristaps 157: { pres_os, NULL }, /* Os */
158: { pres_sh, posts_sh }, /* Sh */
159: { pres_ss, posts_ss }, /* Ss */
1.117 kristaps 160: { pres_pp, posts_notext }, /* Pp */
1.1 kristaps 161: { pres_d1, posts_wline }, /* D1 */
162: { pres_d1, posts_wline }, /* Dl */
1.104 kristaps 163: { pres_bd, posts_bd_bk }, /* Bd */
1.1 kristaps 164: { NULL, NULL }, /* Ed */
165: { pres_bl, posts_bl }, /* Bl */
166: { NULL, NULL }, /* El */
167: { pres_it, posts_it }, /* It */
168: { NULL, posts_text }, /* Ad */
169: { pres_an, posts_an }, /* An */
170: { NULL, NULL }, /* Ar */
1.69 kristaps 171: { NULL, posts_text }, /* Cd */
1.1 kristaps 172: { NULL, NULL }, /* Cm */
173: { NULL, NULL }, /* Dv */
174: { pres_er, posts_text }, /* Er */
175: { NULL, NULL }, /* Ev */
1.42 kristaps 176: { pres_ex, NULL }, /* Ex */
1.1 kristaps 177: { NULL, NULL }, /* Fa */
178: { pres_fd, posts_wtext }, /* Fd */
179: { NULL, NULL }, /* Fl */
180: { NULL, posts_text }, /* Fn */
181: { NULL, posts_wtext }, /* Ft */
182: { NULL, posts_text }, /* Ic */
1.51 kristaps 183: { NULL, posts_text1 }, /* In */
1.1 kristaps 184: { NULL, NULL }, /* Li */
1.27 kristaps 185: { NULL, posts_nd }, /* Nd */
1.1 kristaps 186: { NULL, posts_nm }, /* Nm */
187: { NULL, posts_wline }, /* Op */
188: { NULL, NULL }, /* Ot */
189: { NULL, NULL }, /* Pa */
1.42 kristaps 190: { pres_rv, NULL }, /* Rv */
1.1 kristaps 191: { NULL, posts_st }, /* St */
192: { NULL, NULL }, /* Va */
1.57 kristaps 193: { NULL, posts_vt }, /* Vt */
1.84 kristaps 194: { NULL, posts_wtext }, /* Xr */
1.1 kristaps 195: { NULL, posts_text }, /* %A */
1.47 kristaps 196: { NULL, posts_text }, /* %B */ /* FIXME: can be used outside Rs/Re. */
1.54 kristaps 197: { NULL, posts_text }, /* %D */ /* FIXME: check date with mandoc_a2time(). */
1.1 kristaps 198: { NULL, posts_text }, /* %I */
199: { NULL, posts_text }, /* %J */
200: { NULL, posts_text }, /* %N */
201: { NULL, posts_text }, /* %O */
202: { NULL, posts_text }, /* %P */
203: { NULL, posts_text }, /* %R */
1.47 kristaps 204: { NULL, posts_text }, /* %T */ /* FIXME: can be used outside Rs/Re. */
1.1 kristaps 205: { NULL, posts_text }, /* %V */
206: { NULL, NULL }, /* Ac */
207: { NULL, NULL }, /* Ao */
208: { NULL, posts_wline }, /* Aq */
209: { NULL, posts_at }, /* At */
210: { NULL, NULL }, /* Bc */
211: { NULL, posts_bf }, /* Bf */
212: { NULL, NULL }, /* Bo */
213: { NULL, posts_wline }, /* Bq */
214: { NULL, NULL }, /* Bsx */
215: { NULL, NULL }, /* Bx */
216: { NULL, posts_bool }, /* Db */
217: { NULL, NULL }, /* Dc */
218: { NULL, NULL }, /* Do */
219: { NULL, posts_wline }, /* Dq */
220: { NULL, NULL }, /* Ec */
221: { NULL, NULL }, /* Ef */
222: { NULL, NULL }, /* Em */
223: { NULL, NULL }, /* Eo */
224: { NULL, NULL }, /* Fx */
225: { NULL, posts_text }, /* Ms */
226: { NULL, posts_notext }, /* No */
227: { NULL, posts_notext }, /* Ns */
228: { NULL, NULL }, /* Nx */
229: { NULL, NULL }, /* Ox */
230: { NULL, NULL }, /* Pc */
1.51 kristaps 231: { NULL, posts_text1 }, /* Pf */
1.1 kristaps 232: { NULL, NULL }, /* Po */
233: { NULL, posts_wline }, /* Pq */
234: { NULL, NULL }, /* Qc */
235: { NULL, posts_wline }, /* Ql */
236: { NULL, NULL }, /* Qo */
237: { NULL, posts_wline }, /* Qq */
238: { NULL, NULL }, /* Re */
1.43 kristaps 239: { NULL, posts_rs }, /* Rs */
1.1 kristaps 240: { NULL, NULL }, /* Sc */
241: { NULL, NULL }, /* So */
242: { NULL, posts_wline }, /* Sq */
243: { NULL, posts_bool }, /* Sm */
244: { NULL, posts_text }, /* Sx */
245: { NULL, posts_text }, /* Sy */
246: { NULL, posts_text }, /* Tn */
247: { NULL, NULL }, /* Ux */
248: { NULL, NULL }, /* Xc */
249: { NULL, NULL }, /* Xo */
250: { NULL, posts_fo }, /* Fo */
251: { NULL, NULL }, /* Fc */
252: { NULL, NULL }, /* Oo */
253: { NULL, NULL }, /* Oc */
1.101 schwarze 254: { NULL, posts_bd_bk }, /* Bk */
1.1 kristaps 255: { NULL, NULL }, /* Ek */
1.84 kristaps 256: { NULL, posts_eoln }, /* Bt */
1.1 kristaps 257: { NULL, NULL }, /* Hf */
258: { NULL, NULL }, /* Fr */
1.84 kristaps 259: { NULL, posts_eoln }, /* Ud */
1.83 kristaps 260: { NULL, posts_lb }, /* Lb */
1.34 kristaps 261: { NULL, posts_notext }, /* Lp */
1.51 kristaps 262: { NULL, posts_text }, /* Lk */
1.1 kristaps 263: { NULL, posts_text }, /* Mt */
264: { NULL, posts_wline }, /* Brq */
265: { NULL, NULL }, /* Bro */
266: { NULL, NULL }, /* Brc */
267: { NULL, posts_text }, /* %C */
268: { NULL, NULL }, /* Es */
269: { NULL, NULL }, /* En */
270: { NULL, NULL }, /* Dx */
271: { NULL, posts_text }, /* %Q */
1.33 kristaps 272: { NULL, posts_notext }, /* br */
1.119 schwarze 273: { pres_pp, posts_sp }, /* sp */
1.51 kristaps 274: { NULL, posts_text1 }, /* %U */
1.88 kristaps 275: { NULL, NULL }, /* Ta */
1.1 kristaps 276: };
277:
1.122 ! kristaps 278: #define RSORD_MAX 14 /* Number of `Rs' blocks. */
! 279:
! 280: static const enum mdoct rsord[RSORD_MAX] = {
! 281: MDOC__A,
! 282: MDOC__T,
! 283: MDOC__B,
! 284: MDOC__I,
! 285: MDOC__J,
! 286: MDOC__R,
! 287: MDOC__N,
! 288: MDOC__V,
! 289: MDOC__P,
! 290: MDOC__Q,
! 291: MDOC__D,
! 292: MDOC__O,
! 293: MDOC__C,
! 294: MDOC__U
! 295: };
! 296:
1.1 kristaps 297:
298: int
1.91 kristaps 299: mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n)
1.1 kristaps 300: {
301: v_pre *p;
302: int line, pos;
1.92 kristaps 303: char *tp;
1.1 kristaps 304:
305: if (MDOC_TEXT == n->type) {
306: tp = n->string;
307: line = n->line;
308: pos = n->pos;
309: return(check_text(mdoc, line, pos, tp));
310: }
311:
312: if ( ! check_args(mdoc, n))
313: return(0);
314: if (NULL == mdoc_valids[n->tok].pre)
315: return(1);
316: for (p = mdoc_valids[n->tok].pre; *p; p++)
317: if ( ! (*p)(mdoc, n))
318: return(0);
319: return(1);
320: }
321:
322:
323: int
324: mdoc_valid_post(struct mdoc *mdoc)
325: {
326: v_post *p;
327:
328: if (MDOC_VALID & mdoc->last->flags)
329: return(1);
330: mdoc->last->flags |= MDOC_VALID;
331:
332: if (MDOC_TEXT == mdoc->last->type)
333: return(1);
334: if (MDOC_ROOT == mdoc->last->type)
335: return(post_root(mdoc));
336:
337: if (NULL == mdoc_valids[mdoc->last->tok].post)
338: return(1);
339: for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
340: if ( ! (*p)(mdoc))
341: return(0);
342:
343: return(1);
344: }
345:
1.120 kristaps 346: static int
347: check_count(struct mdoc *m, enum mdoc_type type,
348: enum check_lvl lvl, enum check_ineq ineq, int val)
349: {
350: const char *p;
351:
352: if (m->last->type != type)
353: return(1);
354:
355: switch (ineq) {
356: case (CHECK_LT):
357: p = "less than ";
358: if (m->last->nchild < val)
359: return(1);
360: break;
361: case (CHECK_GT):
362: p = "greater than ";
363: if (m->last->nchild > val)
364: return(1);
365: break;
366: case (CHECK_EQ):
367: p = "";
368: if (val == m->last->nchild)
369: return(1);
370: break;
371: }
372:
373: if (CHECK_WARN == lvl) {
374: return(mdoc_vmsg(m, MANDOCERR_ARGCOUNT,
375: m->last->line, m->last->pos,
376: "want %s%d children (have %d)",
377: p, val, m->last->nchild));
378: }
379:
380: return(mdoc_vmsg(m, MANDOCERR_ARGCOUNT,
381: m->last->line, m->last->pos,
382: "require %s%d children (have %d)",
383: p, val, m->last->nchild));
384: }
385:
386: static int
387: berr_ge1(POST_ARGS)
388: {
389:
390: return(check_count(mdoc, MDOC_BODY, CHECK_FATAL, CHECK_GT, 0));
391: }
392:
393: static int
394: bwarn_ge1(POST_ARGS)
395: {
396: return(check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0));
397: }
398:
399: static int
400: eerr_eq0(POST_ARGS)
401: {
402: return(check_count(mdoc, MDOC_ELEM, CHECK_FATAL, CHECK_EQ, 0));
403: }
1.1 kristaps 404:
1.120 kristaps 405: static int
406: eerr_eq1(POST_ARGS)
1.1 kristaps 407: {
1.120 kristaps 408: return(check_count(mdoc, MDOC_ELEM, CHECK_FATAL, CHECK_EQ, 1));
409: }
1.1 kristaps 410:
1.120 kristaps 411: static int
412: eerr_ge1(POST_ARGS)
413: {
414: return(check_count(mdoc, MDOC_ELEM, CHECK_FATAL, CHECK_GT, 0));
1.1 kristaps 415: }
416:
1.120 kristaps 417: static int
418: eerr_le1(POST_ARGS)
419: {
420: return(check_count(mdoc, MDOC_ELEM, CHECK_FATAL, CHECK_LT, 2));
421: }
1.1 kristaps 422:
1.120 kristaps 423: static int
424: ewarn_eq0(POST_ARGS)
1.1 kristaps 425: {
1.120 kristaps 426: return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0));
427: }
1.1 kristaps 428:
1.120 kristaps 429: static int
430: ewarn_ge1(POST_ARGS)
431: {
432: return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0));
1.1 kristaps 433: }
434:
1.120 kristaps 435: static int
436: herr_eq0(POST_ARGS)
437: {
438: return(check_count(mdoc, MDOC_HEAD, CHECK_FATAL, CHECK_EQ, 0));
439: }
1.1 kristaps 440:
1.120 kristaps 441: static int
442: herr_ge1(POST_ARGS)
443: {
444: return(check_count(mdoc, MDOC_HEAD, CHECK_FATAL, CHECK_GT, 0));
445: }
1.1 kristaps 446:
1.120 kristaps 447: static int
448: hwarn_eq0(POST_ARGS)
449: {
450: return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0));
1.1 kristaps 451: }
452:
1.120 kristaps 453: static int
454: hwarn_eq1(POST_ARGS)
455: {
456: return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 1));
457: }
1.1 kristaps 458:
1.120 kristaps 459: static int
460: hwarn_le1(POST_ARGS)
461: {
462: return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_LT, 2));
463: }
1.1 kristaps 464:
465:
466: static int
467: check_stdarg(PRE_ARGS)
468: {
469:
470: if (n->args && 1 == n->args->argc)
471: if (MDOC_Std == n->args->argv[0].arg)
472: return(1);
1.79 kristaps 473: return(mdoc_nmsg(mdoc, n, MANDOCERR_NOARGV));
1.1 kristaps 474: }
475:
476:
477: static int
1.92 kristaps 478: check_args(struct mdoc *m, struct mdoc_node *n)
1.1 kristaps 479: {
480: int i;
481:
482: if (NULL == n->args)
483: return(1);
484:
485: assert(n->args->argc);
486: for (i = 0; i < (int)n->args->argc; i++)
487: if ( ! check_argv(m, n, &n->args->argv[i]))
488: return(0);
489:
490: return(1);
491: }
492:
493:
494: static int
1.92 kristaps 495: check_argv(struct mdoc *m, struct mdoc_node *n, struct mdoc_argv *v)
1.1 kristaps 496: {
497: int i;
498:
499: for (i = 0; i < (int)v->sz; i++)
500: if ( ! check_text(m, v->line, v->pos, v->value[i]))
501: return(0);
502:
503: if (MDOC_Std == v->arg) {
504: if (v->sz || m->meta.name)
505: return(1);
1.79 kristaps 506: if ( ! mdoc_nmsg(m, n, MANDOCERR_NONAME))
507: return(0);
1.1 kristaps 508: }
509:
510: return(1);
511: }
512:
513:
514: static int
1.112 kristaps 515: check_text(struct mdoc *m, int ln, int pos, char *p)
1.1 kristaps 516: {
1.18 kristaps 517: int c;
1.112 kristaps 518: size_t sz;
1.102 kristaps 519:
1.112 kristaps 520: for ( ; *p; p++, pos++) {
521: sz = strcspn(p, "\t\\");
522: p += (int)sz;
523:
524: if ('\0' == *p)
525: break;
526:
527: pos += (int)sz;
1.1 kristaps 528:
529: if ('\t' == *p) {
1.112 kristaps 530: if (MDOC_LITERAL & m->flags)
531: continue;
532: if (mdoc_pmsg(m, ln, pos, MANDOCERR_BADTAB))
533: continue;
534: return(0);
535: }
1.1 kristaps 536:
1.112 kristaps 537: /* Check the special character. */
1.1 kristaps 538:
1.18 kristaps 539: c = mandoc_special(p);
1.1 kristaps 540: if (c) {
1.18 kristaps 541: p += c - 1;
542: pos += c - 1;
1.115 schwarze 543: } else
544: mdoc_pmsg(m, ln, pos, MANDOCERR_BADESCAPE);
1.1 kristaps 545: }
546:
547: return(1);
548: }
549:
550:
551: static int
1.59 kristaps 552: check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t)
1.1 kristaps 553: {
554:
555: assert(n->parent);
556: if ((MDOC_ROOT == t || tok == n->parent->tok) &&
557: (t == n->parent->type))
558: return(1);
559:
1.79 kristaps 560: mdoc_vmsg(mdoc, MANDOCERR_SYNTCHILD,
561: n->line, n->pos, "want parent %s",
562: MDOC_ROOT == t ? "<root>" :
563: mdoc_macronames[tok]);
564: return(0);
1.1 kristaps 565: }
566:
567:
568: static int
569: pre_display(PRE_ARGS)
570: {
571: struct mdoc_node *node;
572:
573: /* Display elements (`Bd', `D1'...) cannot be nested. */
574:
575: if (MDOC_BLOCK != n->type)
576: return(1);
577:
578: /* LINTED */
579: for (node = mdoc->last->parent; node; node = node->parent)
580: if (MDOC_BLOCK == node->type)
581: if (MDOC_Bd == node->tok)
582: break;
583: if (NULL == node)
584: return(1);
585:
1.79 kristaps 586: mdoc_nmsg(mdoc, n, MANDOCERR_NESTEDDISP);
587: return(0);
1.1 kristaps 588: }
589:
590:
591: static int
592: pre_bl(PRE_ARGS)
593: {
1.104 kristaps 594: int i, comp, dup;
595: const char *offs, *width;
596: enum mdoc_list lt;
597: struct mdoc_node *np;
1.1 kristaps 598:
1.91 kristaps 599: if (MDOC_BLOCK != n->type) {
1.104 kristaps 600: if (ENDBODY_NOT != n->end) {
601: assert(n->pending);
602: np = n->pending->parent;
603: } else
604: np = n->parent;
605:
606: assert(np);
607: assert(MDOC_BLOCK == np->type);
608: assert(MDOC_Bl == np->tok);
609: assert(np->data.Bl);
610: n->data.Bl = np->data.Bl;
1.1 kristaps 611: return(1);
1.79 kristaps 612: }
1.1 kristaps 613:
1.91 kristaps 614: /*
615: * First figure out which kind of list to use: bind ourselves to
616: * the first mentioned list type and warn about any remaining
617: * ones. If we find no list type, we default to LIST_item.
618: */
1.1 kristaps 619:
1.104 kristaps 620: assert(NULL == n->data.Bl);
621: n->data.Bl = mandoc_calloc(1, sizeof(struct mdoc_bl));
1.1 kristaps 622:
623: /* LINTED */
1.91 kristaps 624: for (i = 0; n->args && i < (int)n->args->argc; i++) {
625: lt = LIST__NONE;
1.97 kristaps 626: dup = comp = 0;
1.99 kristaps 627: width = offs = NULL;
1.91 kristaps 628: switch (n->args->argv[i].arg) {
629: /* Set list types. */
1.1 kristaps 630: case (MDOC_Bullet):
1.91 kristaps 631: lt = LIST_bullet;
632: break;
1.1 kristaps 633: case (MDOC_Dash):
1.91 kristaps 634: lt = LIST_dash;
635: break;
1.1 kristaps 636: case (MDOC_Enum):
1.91 kristaps 637: lt = LIST_enum;
638: break;
1.1 kristaps 639: case (MDOC_Hyphen):
1.91 kristaps 640: lt = LIST_hyphen;
641: break;
1.1 kristaps 642: case (MDOC_Item):
1.91 kristaps 643: lt = LIST_item;
644: break;
1.1 kristaps 645: case (MDOC_Tag):
1.91 kristaps 646: lt = LIST_tag;
647: break;
1.1 kristaps 648: case (MDOC_Diag):
1.91 kristaps 649: lt = LIST_diag;
650: break;
1.1 kristaps 651: case (MDOC_Hang):
1.91 kristaps 652: lt = LIST_hang;
653: break;
1.1 kristaps 654: case (MDOC_Ohang):
1.91 kristaps 655: lt = LIST_ohang;
656: break;
1.1 kristaps 657: case (MDOC_Inset):
1.91 kristaps 658: lt = LIST_inset;
659: break;
1.1 kristaps 660: case (MDOC_Column):
1.91 kristaps 661: lt = LIST_column;
662: break;
663: /* Set list arguments. */
1.45 kristaps 664: case (MDOC_Compact):
1.104 kristaps 665: dup = n->data.Bl->comp;
1.97 kristaps 666: comp = 1;
1.91 kristaps 667: break;
1.1 kristaps 668: case (MDOC_Width):
1.104 kristaps 669: dup = (NULL != n->data.Bl->width);
1.99 kristaps 670: width = n->args->argv[i].value[0];
1.8 kristaps 671: break;
1.1 kristaps 672: case (MDOC_Offset):
1.98 kristaps 673: /* NB: this can be empty! */
674: if (n->args->argv[i].sz) {
675: offs = n->args->argv[i].value[0];
1.104 kristaps 676: dup = (NULL != n->data.Bl->offs);
1.98 kristaps 677: break;
678: }
679: if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV))
680: return(0);
1.1 kristaps 681: break;
1.113 kristaps 682: default:
683: continue;
1.1 kristaps 684: }
685:
1.91 kristaps 686: /* Check: duplicate auxiliary arguments. */
687:
1.97 kristaps 688: if (dup && ! mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP))
689: return(0);
690:
691: if (comp && ! dup)
1.104 kristaps 692: n->data.Bl->comp = comp;
1.98 kristaps 693: if (offs && ! dup)
1.104 kristaps 694: n->data.Bl->offs = offs;
1.99 kristaps 695: if (width && ! dup)
1.104 kristaps 696: n->data.Bl->width = width;
1.91 kristaps 697:
698: /* Check: multiple list types. */
699:
1.104 kristaps 700: if (LIST__NONE != lt && n->data.Bl->type != LIST__NONE)
1.91 kristaps 701: if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_LISTREP))
702: return(0);
703:
704: /* Assign list type. */
705:
1.109 kristaps 706: if (LIST__NONE != lt && n->data.Bl->type == LIST__NONE) {
1.104 kristaps 707: n->data.Bl->type = lt;
1.109 kristaps 708: /* Set column information, too. */
709: if (LIST_column == lt) {
710: n->data.Bl->ncols =
711: n->args->argv[i].sz;
712: n->data.Bl->cols = (const char **)
713: n->args->argv[i].value;
714: }
715: }
1.91 kristaps 716:
717: /* The list type should come first. */
718:
1.104 kristaps 719: if (n->data.Bl->type == LIST__NONE)
720: if (n->data.Bl->width ||
721: n->data.Bl->offs ||
722: n->data.Bl->comp)
1.91 kristaps 723: if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST))
724: return(0);
725:
726: continue;
727: }
728:
729: /* Allow lists to default to LIST_item. */
730:
1.104 kristaps 731: if (LIST__NONE == n->data.Bl->type) {
1.91 kristaps 732: if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE))
733: return(0);
1.104 kristaps 734: n->data.Bl->type = LIST_item;
1.79 kristaps 735: }
1.1 kristaps 736:
1.8 kristaps 737: /*
738: * Validate the width field. Some list types don't need width
739: * types and should be warned about them. Others should have it
740: * and must also be warned.
741: */
742:
1.104 kristaps 743: switch (n->data.Bl->type) {
1.91 kristaps 744: case (LIST_tag):
1.104 kristaps 745: if (n->data.Bl->width)
1.91 kristaps 746: break;
747: if (mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG))
748: break;
749: return(0);
750: case (LIST_column):
1.1 kristaps 751: /* FALLTHROUGH */
1.91 kristaps 752: case (LIST_diag):
1.1 kristaps 753: /* FALLTHROUGH */
1.91 kristaps 754: case (LIST_ohang):
1.53 kristaps 755: /* FALLTHROUGH */
1.91 kristaps 756: case (LIST_inset):
1.1 kristaps 757: /* FALLTHROUGH */
1.91 kristaps 758: case (LIST_item):
1.104 kristaps 759: if (NULL == n->data.Bl->width)
1.91 kristaps 760: break;
761: if (mdoc_nmsg(mdoc, n, MANDOCERR_WIDTHARG))
762: break;
763: return(0);
1.8 kristaps 764: default:
765: break;
766: }
767:
1.1 kristaps 768: return(1);
769: }
770:
771:
772: static int
773: pre_bd(PRE_ARGS)
774: {
1.104 kristaps 775: int i, dup, comp;
776: enum mdoc_disp dt;
777: const char *offs;
778: struct mdoc_node *np;
1.1 kristaps 779:
1.93 kristaps 780: if (MDOC_BLOCK != n->type) {
1.104 kristaps 781: if (ENDBODY_NOT != n->end) {
782: assert(n->pending);
783: np = n->pending->parent;
784: } else
785: np = n->parent;
786:
787: assert(np);
788: assert(MDOC_BLOCK == np->type);
789: assert(MDOC_Bd == np->tok);
790: assert(np->data.Bd);
791: n->data.Bd = np->data.Bd;
1.1 kristaps 792: return(1);
1.79 kristaps 793: }
1.1 kristaps 794:
1.104 kristaps 795: assert(NULL == n->data.Bd);
796: n->data.Bd = mandoc_calloc(1, sizeof(struct mdoc_bd));
1.1 kristaps 797:
798: /* LINTED */
1.93 kristaps 799: for (i = 0; n->args && i < (int)n->args->argc; i++) {
800: dt = DISP__NONE;
1.94 kristaps 801: dup = comp = 0;
802: offs = NULL;
803:
1.1 kristaps 804: switch (n->args->argv[i].arg) {
1.49 kristaps 805: case (MDOC_Centred):
1.93 kristaps 806: dt = DISP_centred;
807: break;
1.1 kristaps 808: case (MDOC_Ragged):
1.93 kristaps 809: dt = DISP_ragged;
810: break;
1.1 kristaps 811: case (MDOC_Unfilled):
1.93 kristaps 812: dt = DISP_unfilled;
813: break;
1.1 kristaps 814: case (MDOC_Filled):
1.93 kristaps 815: dt = DISP_filled;
816: break;
1.1 kristaps 817: case (MDOC_Literal):
1.93 kristaps 818: dt = DISP_literal;
1.79 kristaps 819: break;
1.93 kristaps 820: case (MDOC_File):
821: mdoc_nmsg(mdoc, n, MANDOCERR_BADDISP);
822: return(0);
823: case (MDOC_Offset):
1.94 kristaps 824: /* NB: this can be empty! */
825: if (n->args->argv[i].sz) {
826: offs = n->args->argv[i].value[0];
1.104 kristaps 827: dup = (NULL != n->data.Bd->offs);
1.94 kristaps 828: break;
829: }
1.95 kristaps 830: if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV))
831: return(0);
1.94 kristaps 832: break;
1.93 kristaps 833: case (MDOC_Compact):
1.94 kristaps 834: comp = 1;
1.104 kristaps 835: dup = n->data.Bd->comp;
1.94 kristaps 836: break;
1.1 kristaps 837: default:
1.94 kristaps 838: abort();
839: /* NOTREACHED */
1.1 kristaps 840: }
841:
1.94 kristaps 842: /* Check whether we have duplicates. */
843:
844: if (dup && ! mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP))
845: return(0);
846:
847: /* Make our auxiliary assignments. */
848:
849: if (offs && ! dup)
1.104 kristaps 850: n->data.Bd->offs = offs;
1.94 kristaps 851: if (comp && ! dup)
1.104 kristaps 852: n->data.Bd->comp = comp;
1.94 kristaps 853:
854: /* Check whether a type has already been assigned. */
855:
1.104 kristaps 856: if (DISP__NONE != dt && n->data.Bd->type != DISP__NONE)
1.93 kristaps 857: if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_DISPREP))
858: return(0);
859:
1.94 kristaps 860: /* Make our type assignment. */
861:
1.104 kristaps 862: if (DISP__NONE != dt && n->data.Bd->type == DISP__NONE)
863: n->data.Bd->type = dt;
1.93 kristaps 864: }
865:
1.104 kristaps 866: if (DISP__NONE == n->data.Bd->type) {
1.93 kristaps 867: if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_DISPTYPE))
868: return(0);
1.104 kristaps 869: n->data.Bd->type = DISP_ragged;
1.93 kristaps 870: }
871:
872: return(1);
1.1 kristaps 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);
1.100 kristaps 892:
893: mdoc->regs->regs[(int)REG_nS].set = 0;
1.70 kristaps 894: return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT));
1.1 kristaps 895: }
896:
897:
898: static int
899: pre_it(PRE_ARGS)
900: {
901:
902: if (MDOC_BLOCK != n->type)
903: return(1);
1.79 kristaps 904: /*
905: * FIXME: this can probably be lifted if we make the It into
906: * something else on-the-fly?
907: */
1.1 kristaps 908: return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY));
909: }
910:
911:
912: static int
913: pre_an(PRE_ARGS)
914: {
1.121 kristaps 915: int i;
1.1 kristaps 916:
1.107 kristaps 917: if (NULL == n->args)
1.1 kristaps 918: return(1);
1.121 kristaps 919:
920: for (i = 1; i < (int)n->args->argc; i++)
921: if ( ! mdoc_pmsg(mdoc, n->args->argv[i].line,
922: n->args->argv[i].pos, MANDOCERR_IGNARGV))
1.107 kristaps 923: return(0);
1.120 kristaps 924:
1.107 kristaps 925: if (MDOC_Split == n->args->argv[0].arg)
926: n->data.An.auth = AUTH_split;
927: else if (MDOC_Nosplit == n->args->argv[0].arg)
928: n->data.An.auth = AUTH_nosplit;
929: else
930: abort();
931:
932: return(1);
1.1 kristaps 933: }
934:
935:
936: static int
937: pre_rv(PRE_ARGS)
938: {
939:
940: return(check_stdarg(mdoc, n));
941: }
942:
943:
944: static int
1.85 kristaps 945: post_dt(POST_ARGS)
946: {
947: const struct mdoc_node *nn;
948: const char *p;
949:
950: if (NULL != (nn = mdoc->last->child))
951: for (p = nn->string; *p; p++) {
1.86 kristaps 952: if (toupper((u_char)*p) == *p)
1.85 kristaps 953: continue;
954: if ( ! mdoc_nmsg(mdoc, nn, MANDOCERR_UPPERCASE))
955: return(0);
956: break;
957: }
958:
959: return(1);
960: }
961:
962:
963: static int
1.1 kristaps 964: pre_dt(PRE_ARGS)
965: {
1.54 kristaps 966:
1.1 kristaps 967: if (0 == mdoc->meta.date || mdoc->meta.os)
1.79 kristaps 968: if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO))
1.1 kristaps 969: return(0);
970: if (mdoc->meta.title)
1.79 kristaps 971: if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP))
1.1 kristaps 972: return(0);
973: return(1);
974: }
975:
976:
977: static int
978: pre_os(PRE_ARGS)
979: {
980:
981: if (NULL == mdoc->meta.title || 0 == mdoc->meta.date)
1.79 kristaps 982: if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO))
1.1 kristaps 983: return(0);
984: if (mdoc->meta.os)
1.79 kristaps 985: if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP))
1.1 kristaps 986: return(0);
987: return(1);
988: }
989:
990:
991: static int
992: pre_dd(PRE_ARGS)
993: {
994:
995: if (mdoc->meta.title || mdoc->meta.os)
1.79 kristaps 996: if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO))
1.1 kristaps 997: return(0);
998: if (mdoc->meta.date)
1.79 kristaps 999: if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP))
1.1 kristaps 1000: return(0);
1001: return(1);
1002: }
1003:
1004:
1005: static int
1006: post_bf(POST_ARGS)
1007: {
1.105 kristaps 1008: struct mdoc_node *np;
1.113 kristaps 1009: enum mdocargt arg;
1.105 kristaps 1010:
1011: /*
1012: * Unlike other data pointers, these are "housed" by the HEAD
1013: * element, which contains the goods.
1014: */
1.1 kristaps 1015:
1.105 kristaps 1016: if (MDOC_HEAD != mdoc->last->type) {
1017: if (ENDBODY_NOT != mdoc->last->end) {
1018: assert(mdoc->last->pending);
1019: np = mdoc->last->pending->parent->head;
1020: } else if (MDOC_BLOCK != mdoc->last->type) {
1021: np = mdoc->last->parent->head;
1022: } else
1023: np = mdoc->last->head;
1024:
1025: assert(np);
1026: assert(MDOC_HEAD == np->type);
1027: assert(MDOC_Bf == np->tok);
1028: assert(np->data.Bf);
1029: mdoc->last->data.Bf = np->data.Bf;
1.1 kristaps 1030: return(1);
1.105 kristaps 1031: }
1.1 kristaps 1032:
1.105 kristaps 1033: np = mdoc->last;
1.106 kristaps 1034: assert(MDOC_BLOCK == np->parent->type);
1035: assert(MDOC_Bf == np->parent->tok);
1.105 kristaps 1036: np->data.Bf = mandoc_calloc(1, sizeof(struct mdoc_bf));
1.1 kristaps 1037:
1.105 kristaps 1038: /*
1039: * Cannot have both argument and parameter.
1040: * If neither is specified, let it through with a warning.
1041: */
1042:
1.106 kristaps 1043: if (np->parent->args && np->child) {
1.105 kristaps 1044: mdoc_nmsg(mdoc, np, MANDOCERR_SYNTARGVCOUNT);
1.79 kristaps 1045: return(0);
1.106 kristaps 1046: } else if (NULL == np->parent->args && NULL == np->child)
1.105 kristaps 1047: return(mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE));
1048:
1049: /* Extract argument into data. */
1050:
1.106 kristaps 1051: if (np->parent->args) {
1052: arg = np->parent->args->argv[0].arg;
1.105 kristaps 1053: if (MDOC_Emphasis == arg)
1054: np->data.Bf->font = FONT_Em;
1055: else if (MDOC_Literal == arg)
1056: np->data.Bf->font = FONT_Li;
1057: else if (MDOC_Symbolic == arg)
1058: np->data.Bf->font = FONT_Sy;
1059: else
1060: abort();
1.13 kristaps 1061: return(1);
1.79 kristaps 1062: }
1.1 kristaps 1063:
1.105 kristaps 1064: /* Extract parameter into data. */
1.1 kristaps 1065:
1.105 kristaps 1066: if (0 == strcmp(np->child->string, "Em"))
1067: np->data.Bf->font = FONT_Em;
1068: else if (0 == strcmp(np->child->string, "Li"))
1069: np->data.Bf->font = FONT_Li;
1070: else if (0 == strcmp(np->child->string, "Sy"))
1071: np->data.Bf->font = FONT_Sy;
1072: else if ( ! mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE))
1073: return(0);
1.1 kristaps 1074:
1.105 kristaps 1075: return(1);
1.1 kristaps 1076: }
1077:
1078:
1079: static int
1.31 kristaps 1080: post_lb(POST_ARGS)
1081: {
1082:
1083: if (mdoc_a2lib(mdoc->last->child->string))
1084: return(1);
1.79 kristaps 1085: return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADLIB));
1.84 kristaps 1086: }
1087:
1088:
1089: static int
1090: post_eoln(POST_ARGS)
1091: {
1092:
1093: if (NULL == mdoc->last->child)
1094: return(1);
1095: return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST));
1.31 kristaps 1096: }
1097:
1098:
1099: static int
1.57 kristaps 1100: post_vt(POST_ARGS)
1101: {
1102: const struct mdoc_node *n;
1103:
1104: /*
1105: * The Vt macro comes in both ELEM and BLOCK form, both of which
1106: * have different syntaxes (yet more context-sensitive
1107: * behaviour). ELEM types must have a child; BLOCK types,
1108: * specifically the BODY, should only have TEXT children.
1109: */
1110:
1111: if (MDOC_ELEM == mdoc->last->type)
1112: return(eerr_ge1(mdoc));
1113: if (MDOC_BODY != mdoc->last->type)
1114: return(1);
1115:
1116: for (n = mdoc->last->child; n; n = n->next)
1117: if (MDOC_TEXT != n->type)
1.79 kristaps 1118: if ( ! mdoc_nmsg(mdoc, n, MANDOCERR_CHILD))
1.57 kristaps 1119: return(0);
1120:
1121: return(1);
1122: }
1123:
1124:
1125: static int
1.1 kristaps 1126: post_nm(POST_ARGS)
1127: {
1128:
1129: if (mdoc->last->child)
1130: return(1);
1131: if (mdoc->meta.name)
1132: return(1);
1.79 kristaps 1133: return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME));
1.1 kristaps 1134: }
1135:
1136:
1137: static int
1138: post_at(POST_ARGS)
1139: {
1140:
1141: if (NULL == mdoc->last->child)
1142: return(1);
1.79 kristaps 1143: assert(MDOC_TEXT == mdoc->last->child->type);
1.1 kristaps 1144: if (mdoc_a2att(mdoc->last->child->string))
1145: return(1);
1.79 kristaps 1146: return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADATT));
1.1 kristaps 1147: }
1148:
1149:
1150: static int
1151: post_an(POST_ARGS)
1152: {
1.107 kristaps 1153: struct mdoc_node *np;
1.1 kristaps 1154:
1.107 kristaps 1155: np = mdoc->last;
1156: if (AUTH__NONE != np->data.An.auth && np->child)
1.120 kristaps 1157: return(eerr_eq0(mdoc));
1158: /*
1159: * FIXME: make this ewarn and make sure that the front-ends
1160: * don't print the arguments.
1161: */
1.107 kristaps 1162: if (AUTH__NONE != np->data.An.auth || np->child)
1.1 kristaps 1163: return(1);
1.107 kristaps 1164: return(mdoc_nmsg(mdoc, np, MANDOCERR_NOARGS));
1.1 kristaps 1165: }
1166:
1167:
1168: static int
1169: post_it(POST_ARGS)
1170: {
1.89 kristaps 1171: int i, cols, rc;
1172: enum mdoc_list lt;
1.1 kristaps 1173: struct mdoc_node *n, *c;
1.89 kristaps 1174: enum mandocerr er;
1.1 kristaps 1175:
1176: if (MDOC_BLOCK != mdoc->last->type)
1177: return(1);
1178:
1179: n = mdoc->last->parent->parent;
1.104 kristaps 1180: assert(n->data.Bl);
1181: lt = n->data.Bl->type;
1.89 kristaps 1182:
1183: if (LIST__NONE == lt) {
1.79 kristaps 1184: mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_LISTTYPE);
1185: return(0);
1186: }
1.1 kristaps 1187:
1.89 kristaps 1188: switch (lt) {
1189: case (LIST_tag):
1190: if (mdoc->last->head->child)
1.1 kristaps 1191: break;
1.89 kristaps 1192: /* FIXME: give this a dummy value. */
1193: if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS))
1194: return(0);
1.1 kristaps 1195: break;
1.89 kristaps 1196: case (LIST_hang):
1.1 kristaps 1197: /* FALLTHROUGH */
1.89 kristaps 1198: case (LIST_ohang):
1.1 kristaps 1199: /* FALLTHROUGH */
1.89 kristaps 1200: case (LIST_inset):
1.1 kristaps 1201: /* FALLTHROUGH */
1.89 kristaps 1202: case (LIST_diag):
1.1 kristaps 1203: if (NULL == mdoc->last->head->child)
1.79 kristaps 1204: if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS))
1.1 kristaps 1205: return(0);
1206: break;
1.89 kristaps 1207: case (LIST_bullet):
1.1 kristaps 1208: /* FALLTHROUGH */
1.89 kristaps 1209: case (LIST_dash):
1.1 kristaps 1210: /* FALLTHROUGH */
1.89 kristaps 1211: case (LIST_enum):
1.1 kristaps 1212: /* FALLTHROUGH */
1.89 kristaps 1213: case (LIST_hyphen):
1.108 schwarze 1214: if (NULL == mdoc->last->body->child)
1215: if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY))
1216: return(0);
1.1 kristaps 1217: /* FALLTHROUGH */
1.89 kristaps 1218: case (LIST_item):
1.1 kristaps 1219: if (mdoc->last->head->child)
1.79 kristaps 1220: if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST))
1.1 kristaps 1221: return(0);
1222: break;
1.89 kristaps 1223: case (LIST_column):
1.109 kristaps 1224: cols = (int)n->data.Bl->ncols;
1.89 kristaps 1225:
1.87 kristaps 1226: assert(NULL == mdoc->last->head->child);
1.89 kristaps 1227:
1.87 kristaps 1228: if (NULL == mdoc->last->body->child)
1229: if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY))
1.1 kristaps 1230: return(0);
1.87 kristaps 1231:
1.89 kristaps 1232: for (i = 0, c = mdoc->last->child; c; c = c->next)
1.87 kristaps 1233: if (MDOC_BODY == c->type)
1234: i++;
1.38 kristaps 1235:
1.89 kristaps 1236: if (i < cols)
1237: er = MANDOCERR_ARGCOUNT;
1238: else if (i == cols || i == cols + 1)
1.38 kristaps 1239: break;
1.89 kristaps 1240: else
1241: er = MANDOCERR_SYNTARGCOUNT;
1.38 kristaps 1242:
1.89 kristaps 1243: rc = mdoc_vmsg(mdoc, er,
1.79 kristaps 1244: mdoc->last->line, mdoc->last->pos,
1245: "columns == %d (have %d)", cols, i);
1.89 kristaps 1246: return(rc);
1.1 kristaps 1247: default:
1248: break;
1249: }
1250:
1251: return(1);
1252: }
1253:
1254:
1255: static int
1.14 kristaps 1256: post_bl_head(POST_ARGS)
1257: {
1.90 kristaps 1258: struct mdoc_node *n;
1.14 kristaps 1259:
1.90 kristaps 1260: assert(mdoc->last->parent);
1.14 kristaps 1261: n = mdoc->last->parent;
1262:
1.104 kristaps 1263: if (LIST_column == n->data.Bl->type) {
1.109 kristaps 1264: if (n->data.Bl->ncols && mdoc->last->nchild) {
1.90 kristaps 1265: mdoc_nmsg(mdoc, n, MANDOCERR_COLUMNS);
1266: return(0);
1.65 kristaps 1267: }
1.90 kristaps 1268: return(1);
1.65 kristaps 1269: }
1.14 kristaps 1270:
1.120 kristaps 1271: /* FIXME: should be ERROR class. */
1272: return(hwarn_eq0(mdoc));
1.14 kristaps 1273: }
1274:
1275:
1276: static int
1.1 kristaps 1277: post_bl(POST_ARGS)
1278: {
1279: struct mdoc_node *n;
1280:
1.14 kristaps 1281: if (MDOC_HEAD == mdoc->last->type)
1282: return(post_bl_head(mdoc));
1.1 kristaps 1283: if (MDOC_BODY != mdoc->last->type)
1284: return(1);
1285: if (NULL == mdoc->last->child)
1286: return(1);
1287:
1.55 kristaps 1288: /*
1289: * We only allow certain children of `Bl'. This is usually on
1290: * `It', but apparently `Sm' occurs here and there, so we let
1291: * that one through, too.
1292: */
1293:
1.1 kristaps 1294: /* LINTED */
1295: for (n = mdoc->last->child; n; n = n->next) {
1.55 kristaps 1296: if (MDOC_BLOCK == n->type && MDOC_It == n->tok)
1297: continue;
1298: if (MDOC_Sm == n->tok)
1299: continue;
1.79 kristaps 1300: mdoc_nmsg(mdoc, n, MANDOCERR_SYNTCHILD);
1301: return(0);
1.1 kristaps 1302: }
1303:
1304: return(1);
1305: }
1306:
1307:
1308: static int
1309: ebool(struct mdoc *mdoc)
1310: {
1311: struct mdoc_node *n;
1312:
1313: /* LINTED */
1314: for (n = mdoc->last->child; n; n = n->next) {
1315: if (MDOC_TEXT != n->type)
1316: break;
1.2 kristaps 1317: if (0 == strcmp(n->string, "on"))
1.1 kristaps 1318: continue;
1.2 kristaps 1319: if (0 == strcmp(n->string, "off"))
1.1 kristaps 1320: continue;
1321: break;
1322: }
1323:
1324: if (NULL == n)
1325: return(1);
1.79 kristaps 1326: return(mdoc_nmsg(mdoc, n, MANDOCERR_BADBOOL));
1.1 kristaps 1327: }
1328:
1329:
1330: static int
1331: post_root(POST_ARGS)
1332: {
1333:
1334: if (NULL == mdoc->first->child)
1.79 kristaps 1335: mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCBODY);
1336: else if ( ! (MDOC_PBODY & mdoc->flags))
1337: mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCPROLOG);
1338: else if (MDOC_BLOCK != mdoc->first->child->type)
1339: mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCBODY);
1340: else if (MDOC_Sh != mdoc->first->child->tok)
1341: mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCBODY);
1342: else
1343: return(1);
1.1 kristaps 1344:
1.79 kristaps 1345: return(0);
1.1 kristaps 1346: }
1347:
1348:
1349: static int
1350: post_st(POST_ARGS)
1351: {
1352:
1353: if (mdoc_a2st(mdoc->last->child->string))
1354: return(1);
1.79 kristaps 1355: return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADSTANDARD));
1.1 kristaps 1356: }
1357:
1358:
1359: static int
1.43 kristaps 1360: post_rs(POST_ARGS)
1361: {
1.122 ! kristaps 1362: struct mdoc_node *nn, *next, *prev;
! 1363: int i, j;
1.43 kristaps 1364:
1365: if (MDOC_BODY != mdoc->last->type)
1366: return(1);
1367:
1.122 ! kristaps 1368: /*
! 1369: * Make sure only certain types of nodes are allowed within the
! 1370: * the `Rs' body. Delete offending nodes and raise a warning.
! 1371: * Do this before re-ordering for the sake of clarity.
! 1372: */
! 1373:
! 1374: next = NULL;
! 1375: for (nn = mdoc->last->child; nn; nn = next) {
! 1376: for (i = 0; i < RSORD_MAX; i++)
! 1377: if (nn->tok == rsord[i])
! 1378: break;
! 1379:
! 1380: if (i < RSORD_MAX) {
! 1381: next = nn->next;
! 1382: continue;
! 1383: }
! 1384:
! 1385: next = nn->next;
! 1386: mdoc_nmsg(mdoc, nn, MANDOCERR_CHILD);
! 1387: mdoc_node_delete(mdoc, nn);
! 1388: }
! 1389:
! 1390: /*
! 1391: * The full `Rs' block needs special handling to order the
! 1392: * sub-elements according to `rsord'. Pick through each element
! 1393: * and correctly order it. This is a insertion sort.
! 1394: */
! 1395:
! 1396: next = NULL;
! 1397: for (nn = mdoc->last->child->next; nn; nn = next) {
! 1398: /* Determine order of `nn'. */
! 1399: for (i = 0; i < RSORD_MAX; i++)
! 1400: if (rsord[i] == nn->tok)
! 1401: break;
! 1402:
! 1403: /*
! 1404: * Remove `nn' from the chain. This somewhat
! 1405: * repeats mdoc_node_unlink(), but since we're
! 1406: * just re-ordering, there's no need for the
! 1407: * full unlink process.
! 1408: */
! 1409:
! 1410: if (NULL != (next = nn->next))
! 1411: next->prev = nn->prev;
! 1412:
! 1413: if (NULL != (prev = nn->prev))
! 1414: prev->next = nn->next;
! 1415:
! 1416: nn->prev = nn->next = NULL;
! 1417:
! 1418: /*
! 1419: * Scan back until we reach a node that's
! 1420: * ordered before `nn'.
! 1421: */
! 1422:
! 1423: for ( ; prev ; prev = prev->prev) {
! 1424: /* Determine order of `prev'. */
! 1425: for (j = 0; j < RSORD_MAX; j++)
! 1426: if (rsord[j] == prev->tok)
! 1427: break;
! 1428:
! 1429: if (j <= i)
! 1430: break;
! 1431: }
! 1432:
! 1433: /*
! 1434: * Set `nn' back into its correct place in front
! 1435: * of the `prev' node.
! 1436: */
! 1437:
! 1438: nn->prev = prev;
! 1439:
! 1440: if (prev) {
! 1441: if (prev->next)
! 1442: prev->next->prev = nn;
! 1443: nn->next = prev->next;
! 1444: prev->next = nn;
! 1445: } else {
! 1446: mdoc->last->child->prev = nn;
! 1447: nn->next = mdoc->last->child;
! 1448: mdoc->last->child = nn;
1.43 kristaps 1449: }
1.122 ! kristaps 1450: }
1.43 kristaps 1451:
1452: return(1);
1453: }
1454:
1455:
1456: static int
1.1 kristaps 1457: post_sh(POST_ARGS)
1458: {
1459:
1460: if (MDOC_HEAD == mdoc->last->type)
1461: return(post_sh_head(mdoc));
1462: if (MDOC_BODY == mdoc->last->type)
1463: return(post_sh_body(mdoc));
1464:
1465: return(1);
1466: }
1467:
1468:
1469: static int
1470: post_sh_body(POST_ARGS)
1471: {
1472: struct mdoc_node *n;
1473:
1.29 kristaps 1474: if (SEC_NAME != mdoc->lastsec)
1.1 kristaps 1475: return(1);
1476:
1477: /*
1478: * Warn if the NAME section doesn't contain the `Nm' and `Nd'
1479: * macros (can have multiple `Nm' and one `Nd'). Note that the
1480: * children of the BODY declaration can also be "text".
1481: */
1482:
1483: if (NULL == (n = mdoc->last->child))
1.79 kristaps 1484: return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC));
1.1 kristaps 1485:
1486: for ( ; n && n->next; n = n->next) {
1487: if (MDOC_ELEM == n->type && MDOC_Nm == n->tok)
1488: continue;
1.28 kristaps 1489: if (MDOC_TEXT == n->type)
1490: continue;
1.79 kristaps 1491: if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC))
1.1 kristaps 1492: return(0);
1493: }
1494:
1.41 kristaps 1495: assert(n);
1.27 kristaps 1496: if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok)
1.1 kristaps 1497: return(1);
1.79 kristaps 1498: return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC));
1.1 kristaps 1499: }
1500:
1501:
1502: static int
1503: post_sh_head(POST_ARGS)
1504: {
1.81 kristaps 1505: char buf[BUFSIZ];
1.2 kristaps 1506: enum mdoc_sec sec;
1507: const struct mdoc_node *n;
1.1 kristaps 1508:
1509: /*
1510: * Process a new section. Sections are either "named" or
1511: * "custom"; custom sections are user-defined, while named ones
1512: * usually follow a conventional order and may only appear in
1513: * certain manual sections.
1514: */
1515:
1.79 kristaps 1516: buf[0] = '\0';
1517:
1518: /*
1519: * FIXME: yes, these can use a dynamic buffer, but I don't do so
1520: * in the interests of simplicity.
1521: */
1.1 kristaps 1522:
1.2 kristaps 1523: for (n = mdoc->last->child; n; n = n->next) {
1.12 kristaps 1524: /* XXX - copied from compact(). */
1.2 kristaps 1525: assert(MDOC_TEXT == n->type);
1.12 kristaps 1526:
1.81 kristaps 1527: if (strlcat(buf, n->string, BUFSIZ) >= BUFSIZ) {
1.79 kristaps 1528: mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
1529: return(0);
1530: }
1.2 kristaps 1531: if (NULL == n->next)
1532: continue;
1.81 kristaps 1533: if (strlcat(buf, " ", BUFSIZ) >= BUFSIZ) {
1.79 kristaps 1534: mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
1535: return(0);
1536: }
1.2 kristaps 1537: }
1.1 kristaps 1538:
1.72 kristaps 1539: sec = mdoc_str2sec(buf);
1.1 kristaps 1540:
1.12 kristaps 1541: /*
1542: * Check: NAME should always be first, CUSTOM has no roles,
1543: * non-CUSTOM has a conventional order to be followed.
1544: */
1.1 kristaps 1545:
1.72 kristaps 1546: if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
1.79 kristaps 1547: if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NAMESECFIRST))
1.72 kristaps 1548: return(0);
1549:
1.1 kristaps 1550: if (SEC_CUSTOM == sec)
1551: return(1);
1.72 kristaps 1552:
1.1 kristaps 1553: if (sec == mdoc->lastnamed)
1.79 kristaps 1554: if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECREP))
1.26 kristaps 1555: return(0);
1.72 kristaps 1556:
1.1 kristaps 1557: if (sec < mdoc->lastnamed)
1.79 kristaps 1558: if ( ! mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECOOO))
1.26 kristaps 1559: return(0);
1.1 kristaps 1560:
1.12 kristaps 1561: /*
1562: * Check particular section/manual conventions. LIBRARY can
1.78 kristaps 1563: * only occur in manual section 2, 3, and 9.
1.12 kristaps 1564: */
1.1 kristaps 1565:
1566: switch (sec) {
1567: case (SEC_LIBRARY):
1.78 kristaps 1568: assert(mdoc->meta.msec);
1569: if (*mdoc->meta.msec == '2')
1570: break;
1571: if (*mdoc->meta.msec == '3')
1572: break;
1573: if (*mdoc->meta.msec == '9')
1.1 kristaps 1574: break;
1.79 kristaps 1575: return(mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECMSEC));
1.1 kristaps 1576: default:
1577: break;
1578: }
1579:
1.117 kristaps 1580: return(1);
1581: }
1582:
1583:
1584: static int
1585: pre_pp(PRE_ARGS)
1586: {
1587:
1.118 kristaps 1588: if (NULL == mdoc->last)
1589: return(1);
1590:
1591: /* Don't allow prior `Lp' or `Pp'. */
1592:
1593: if (MDOC_Pp != mdoc->last->tok && MDOC_Lp != mdoc->last->tok)
1.117 kristaps 1594: return(1);
1595:
1596: if (MDOC_Bl == n->tok && n->data.Bl->comp)
1597: return(1);
1598: if (MDOC_Bd == n->tok && n->data.Bd->comp)
1599: return(1);
1600:
1601: mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR);
1602: mdoc_node_delete(mdoc, mdoc->last);
1.1 kristaps 1603: return(1);
1604: }
CVSweb