[BACK]Return to validate.c CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / mandoc

Annotation of mandoc/validate.c, Revision 1.25

1.25    ! kristaps    1: /* $Id: validate.c,v 1.24 2009/01/12 10:31:53 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.2       kristaps   24:
1.18      kristaps   25: typedef        int     (*v_pre)(struct mdoc *, struct mdoc_node *);
                     26: typedef        int     (*v_post)(struct mdoc *);
1.14      kristaps   27:
                     28:
                     29: struct valids {
1.24      kristaps   30:        v_pre   *pre;
1.17      kristaps   31:        v_post  *post;
1.14      kristaps   32: };
1.1       kristaps   33:
1.11      kristaps   34:
1.23      kristaps   35: static int     pre_display(struct mdoc *, struct mdoc_node *);
1.24      kristaps   36: static int     pre_bd(struct mdoc *, struct mdoc_node *);
                     37: static int     pre_bl(struct mdoc *, struct mdoc_node *);
1.25    ! kristaps   38: static int     pre_it(struct mdoc *, struct mdoc_node *);
1.20      kristaps   39: static int     pre_prologue(struct mdoc *, struct mdoc_node *);
                     40: static int     pre_prologue(struct mdoc *, struct mdoc_node *);
                     41: static int     pre_prologue(struct mdoc *, struct mdoc_node *);
1.24      kristaps   42:
                     43: static int     headchild_err_ge1(struct mdoc *);
                     44: static int     headchild_err_eq0(struct mdoc *);
                     45: static int     elemchild_err_ge1(struct mdoc *);
                     46: static int     elemchild_warn_eq0(struct mdoc *);
                     47: static int     bodychild_warn_ge1(struct mdoc *);
1.21      kristaps   48: static int     post_sh(struct mdoc *);
1.24      kristaps   49: static int     post_bl(struct mdoc *);
1.25    ! kristaps   50: static int     post_it(struct mdoc *);
1.17      kristaps   51:
1.24      kristaps   52: static v_pre   pres_prologue[] = { pre_prologue, NULL };
                     53: static v_pre   pres_d1[] = { pre_display, NULL };
                     54: static v_pre   pres_bd[] = { pre_display, pre_bd, NULL };
                     55: static v_pre   pres_bl[] = { pre_bl, NULL };
1.25    ! kristaps   56: static v_pre   pres_it[] = { pre_it, NULL };
1.24      kristaps   57: static v_post  posts_bd[] = { headchild_err_eq0,
                     58:                        bodychild_warn_ge1, NULL };
                     59:
                     60: static v_post  posts_sh[] = { headchild_err_ge1,
                     61:                        bodychild_warn_ge1, post_sh, NULL };
                     62: static v_post  posts_bl[] = { headchild_err_eq0,
                     63:                        bodychild_warn_ge1, post_bl, NULL };
1.25    ! kristaps   64: static v_post  posts_it[] = { post_it, NULL };
1.24      kristaps   65: static v_post  posts_ss[] = { headchild_err_ge1, NULL };
                     66: static v_post  posts_pp[] = { elemchild_warn_eq0, NULL };
                     67: static v_post  posts_dd[] = { elemchild_err_ge1, NULL };
                     68: static v_post  posts_d1[] = { headchild_err_ge1, NULL };
1.9       kristaps   69:
1.12      kristaps   70:
1.9       kristaps   71: const  struct valids mdoc_valids[MDOC_MAX] = {
1.17      kristaps   72:        { NULL, NULL }, /* \" */
1.24      kristaps   73:        { pres_prologue, posts_dd }, /* Dd */
                     74:        { pres_prologue, NULL }, /* Dt */
                     75:        { pres_prologue, NULL }, /* Os */
1.21      kristaps   76:        { NULL, posts_sh }, /* Sh */ /* FIXME: preceding Pp. */
1.22      kristaps   77:        { NULL, posts_ss }, /* Ss */ /* FIXME: preceding Pp. */
                     78:        { NULL, posts_pp }, /* Pp */ /* FIXME: proceeding... */
1.24      kristaps   79:        { pres_d1, posts_d1 }, /* D1 */
                     80:        { pres_d1, posts_d1 }, /* Dl */
                     81:        { pres_bd, posts_bd }, /* Bd */ /* FIXME: preceding Pp. */
1.17      kristaps   82:        { NULL, NULL }, /* Ed */
1.24      kristaps   83:        { pres_bl, posts_bl }, /* Bl */ /* FIXME: preceding Pp. */
1.17      kristaps   84:        { NULL, NULL }, /* El */
1.25    ! kristaps   85:        { pres_it, posts_it }, /* It */
1.17      kristaps   86:        { NULL, NULL }, /* Ad */
                     87:        { NULL, NULL }, /* An */
                     88:        { NULL, NULL }, /* Ar */
                     89:        { NULL, NULL }, /* Cd */
                     90:        { NULL, NULL }, /* Cm */
                     91:        { NULL, NULL }, /* Dv */
                     92:        { NULL, NULL }, /* Er */
                     93:        { NULL, NULL }, /* Ev */
                     94:        { NULL, NULL }, /* Ex */
                     95:        { NULL, NULL }, /* Fa */
                     96:        { NULL, NULL }, /* Fd */
                     97:        { NULL, NULL }, /* Fl */
                     98:        { NULL, NULL }, /* Fn */
                     99:        { NULL, NULL }, /* Ft */
                    100:        { NULL, NULL }, /* Ic */
                    101:        { NULL, NULL }, /* In */
                    102:        { NULL, NULL }, /* Li */
                    103:        { NULL, NULL }, /* Nd */
                    104:        { NULL, NULL }, /* Nm */
                    105:        { NULL, NULL }, /* Op */
                    106:        { NULL, NULL }, /* Ot */
                    107:        { NULL, NULL }, /* Pa */
                    108:        { NULL, NULL }, /* Rv */
                    109:        { NULL, NULL }, /* St */
                    110:        { NULL, NULL }, /* Va */
                    111:        { NULL, NULL }, /* Vt */
                    112:        { NULL, NULL }, /* Xr */
                    113:        { NULL, NULL }, /* %A */
                    114:        { NULL, NULL }, /* %B */
                    115:        { NULL, NULL }, /* %D */
                    116:        { NULL, NULL }, /* %I */
                    117:        { NULL, NULL }, /* %J */
                    118:        { NULL, NULL }, /* %N */
                    119:        { NULL, NULL }, /* %O */
                    120:        { NULL, NULL }, /* %P */
                    121:        { NULL, NULL }, /* %R */
                    122:        { NULL, NULL }, /* %T */
                    123:        { NULL, NULL }, /* %V */
                    124:        { NULL, NULL }, /* Ac */
                    125:        { NULL, NULL }, /* Ao */
                    126:        { NULL, NULL }, /* Aq */
                    127:        { NULL, NULL }, /* At */ /* FIXME */
                    128:        { NULL, NULL }, /* Bc */
                    129:        { NULL, NULL }, /* Bf */
                    130:        { NULL, NULL }, /* Bo */
                    131:        { NULL, NULL }, /* Bq */
                    132:        { NULL, NULL }, /* Bsx */
                    133:        { NULL, NULL }, /* Bx */
                    134:        { NULL, NULL }, /* Db */
                    135:        { NULL, NULL }, /* Dc */
                    136:        { NULL, NULL }, /* Do */
                    137:        { NULL, NULL }, /* Dq */
                    138:        { NULL, NULL }, /* Ec */
                    139:        { NULL, NULL }, /* Ef */ /* -symbolic, etc. */
                    140:        { NULL, NULL }, /* Em */
                    141:        { NULL, NULL }, /* Eo */
                    142:        { NULL, NULL }, /* Fx */
                    143:        { NULL, NULL }, /* Ms */
                    144:        { NULL, NULL }, /* No */
                    145:        { NULL, NULL }, /* Ns */
                    146:        { NULL, NULL }, /* Nx */
                    147:        { NULL, NULL }, /* Ox */
                    148:        { NULL, NULL }, /* Pc */
                    149:        { NULL, NULL }, /* Pf */ /* 2 or more arguments */
                    150:        { NULL, NULL }, /* Po */
                    151:        { NULL, NULL }, /* Pq */ /* FIXME: ignore following Sh/Ss */
                    152:        { NULL, NULL }, /* Qc */
                    153:        { NULL, NULL }, /* Ql */
                    154:        { NULL, NULL }, /* Qo */
                    155:        { NULL, NULL }, /* Qq */
                    156:        { NULL, NULL }, /* Re */
                    157:        { NULL, NULL }, /* Rs */
                    158:        { NULL, NULL }, /* Sc */
                    159:        { NULL, NULL }, /* So */
                    160:        { NULL, NULL }, /* Sq */
                    161:        { NULL, NULL }, /* Sm */
                    162:        { NULL, NULL }, /* Sx */
                    163:        { NULL, NULL }, /* Sy */
                    164:        { NULL, NULL }, /* Tn */
                    165:        { NULL, NULL }, /* Ux */
                    166:        { NULL, NULL }, /* Xc */
                    167:        { NULL, NULL }, /* Xo */
                    168:        { NULL, NULL }, /* Fo */
                    169:        { NULL, NULL }, /* Fc */
                    170:        { NULL, NULL }, /* Oo */
                    171:        { NULL, NULL }, /* Oc */
                    172:        { NULL, NULL }, /* Bk */
                    173:        { NULL, NULL }, /* Ek */
                    174:        { NULL, NULL }, /* Bt */
                    175:        { NULL, NULL }, /* Hf */
                    176:        { NULL, NULL }, /* Fr */
                    177:        { NULL, NULL }, /* Ud */
1.9       kristaps  178: };
1.6       kristaps  179:
                    180:
                    181: static int
1.24      kristaps  182: bodychild_warn_ge1(struct mdoc *mdoc)
1.6       kristaps  183: {
                    184:
1.17      kristaps  185:        if (MDOC_BODY != mdoc->last->type)
1.8       kristaps  186:                return(1);
1.17      kristaps  187:        if (mdoc->last->child)
1.9       kristaps  188:                return(1);
1.18      kristaps  189:        return(mdoc_warn(mdoc, WARN_ARGS_GE1));
1.8       kristaps  190: }
1.1       kristaps  191:
                    192:
1.8       kristaps  193: static int
1.24      kristaps  194: elemchild_warn_eq0(struct mdoc *mdoc)
1.22      kristaps  195: {
                    196:
                    197:        assert(MDOC_ELEM == mdoc->last->type);
                    198:        if (NULL == mdoc->last->child)
                    199:                return(1);
1.24      kristaps  200:        return(mdoc_pwarn(mdoc, mdoc->last->child->line,
                    201:                        mdoc->last->child->pos, WARN_ARGS_EQ0));
1.22      kristaps  202: }
                    203:
                    204:
                    205: static int
1.24      kristaps  206: elemchild_err_ge1(struct mdoc *mdoc)
1.8       kristaps  207: {
1.1       kristaps  208:
1.21      kristaps  209:        assert(MDOC_ELEM == mdoc->last->type);
1.17      kristaps  210:        if (mdoc->last->child)
1.9       kristaps  211:                return(1);
1.18      kristaps  212:        return(mdoc_err(mdoc, ERR_ARGS_GE1));
1.1       kristaps  213: }
                    214:
                    215:
1.9       kristaps  216: static int
1.24      kristaps  217: headchild_err_eq0(struct mdoc *mdoc)
                    218: {
                    219:
                    220:        if (MDOC_HEAD != mdoc->last->type)
                    221:                return(1);
                    222:        if (NULL == mdoc->last->child)
                    223:                return(1);
                    224:        return(mdoc_perr(mdoc, mdoc->last->child->line,
                    225:                        mdoc->last->child->pos, ERR_ARGS_EQ0));
                    226: }
                    227:
                    228:
                    229: static int
                    230: headchild_err_ge1(struct mdoc *mdoc)
1.14      kristaps  231: {
                    232:
1.17      kristaps  233:        if (MDOC_HEAD != mdoc->last->type)
1.14      kristaps  234:                return(1);
1.21      kristaps  235:        if (mdoc->last->child)
1.11      kristaps  236:                return(1);
1.21      kristaps  237:        return(mdoc_err(mdoc, ERR_ARGS_GE1));
1.14      kristaps  238: }
                    239:
                    240:
                    241: static int
1.23      kristaps  242: pre_display(struct mdoc *mdoc, struct mdoc_node *node)
                    243: {
                    244:        struct mdoc_node *n;
                    245:
1.24      kristaps  246:        if (MDOC_BLOCK != node->type)
                    247:                return(1);
                    248:
1.23      kristaps  249:        for (n = mdoc->last; n; n = n->parent)
                    250:                if (MDOC_BLOCK == n->type)
1.25    ! kristaps  251:                        if (MDOC_Bd == n->tok)
1.23      kristaps  252:                                break;
                    253:        if (NULL == n)
                    254:                return(1);
                    255:        return(mdoc_verr(mdoc, node, ERR_SCOPE_NONEST));
                    256: }
                    257:
                    258:
                    259: static int
1.24      kristaps  260: pre_bl(struct mdoc *mdoc, struct mdoc_node *node)
                    261: {
                    262:        int              type, err;
                    263:        struct mdoc_arg *argv;
                    264:        size_t           i, argc;
                    265:
                    266:        if (MDOC_BLOCK != node->type)
                    267:                return(1);
1.25    ! kristaps  268:        assert(MDOC_Bl == node->tok);
1.24      kristaps  269:
                    270:        argv = NULL;
                    271:        argc = node->data.block.argc;
                    272:
                    273:        for (i = type = err = 0; i < argc; i++) {
                    274:                argv = &node->data.block.argv[(int)i];
                    275:                assert(argv);
                    276:                switch (argv->arg) {
                    277:                case (MDOC_Bullet):
                    278:                        /* FALLTHROUGH */
                    279:                case (MDOC_Dash):
                    280:                        /* FALLTHROUGH */
                    281:                case (MDOC_Enum):
                    282:                        /* FALLTHROUGH */
                    283:                case (MDOC_Hyphen):
                    284:                        /* FALLTHROUGH */
                    285:                case (MDOC_Item):
                    286:                        /* FALLTHROUGH */
                    287:                case (MDOC_Tag):
                    288:                        /* FALLTHROUGH */
                    289:                case (MDOC_Diag):
                    290:                        /* FALLTHROUGH */
                    291:                case (MDOC_Hang):
                    292:                        /* FALLTHROUGH */
                    293:                case (MDOC_Ohang):
                    294:                        /* FALLTHROUGH */
                    295:                case (MDOC_Inset):
                    296:                        if (type)
                    297:                                err++;
                    298:                        type++;
                    299:                        break;
                    300:                default:
                    301:                        break;
                    302:                }
                    303:        }
                    304:        if (0 == type)
                    305:                return(mdoc_err(mdoc, ERR_SYNTAX_ARGMISS));
                    306:        if (0 == err)
                    307:                return(1);
                    308:        assert(argv);
                    309:        return(mdoc_perr(mdoc, argv->line,
                    310:                        argv->pos, ERR_SYNTAX_ARGBAD));
                    311: }
                    312:
                    313:
                    314: static int
                    315: pre_bd(struct mdoc *mdoc, struct mdoc_node *node)
                    316: {
                    317:        int              type, err;
                    318:        struct mdoc_arg *argv;
                    319:        size_t           i, argc;
                    320:
                    321:        if (MDOC_BLOCK != node->type)
                    322:                return(1);
1.25    ! kristaps  323:        assert(MDOC_Bd == node->tok);
1.24      kristaps  324:
                    325:        argv = NULL;
                    326:        argc = node->data.block.argc;
                    327:
                    328:        for (err = i = type = 0; 0 == err && i < argc; i++) {
                    329:                argv = &node->data.block.argv[(int)i];
                    330:                assert(argv);
                    331:                switch (argv->arg) {
                    332:                case (MDOC_Ragged):
                    333:                        /* FALLTHROUGH */
                    334:                case (MDOC_Unfilled):
                    335:                        /* FALLTHROUGH */
                    336:                case (MDOC_Literal):
                    337:                        /* FALLTHROUGH */
                    338:                case (MDOC_File):
                    339:                        if (type)
                    340:                                err++;
                    341:                        type++;
                    342:                        break;
                    343:                default:
                    344:                        break;
                    345:                }
                    346:        }
                    347:        if (0 == type)
                    348:                return(mdoc_err(mdoc, ERR_SYNTAX_ARGMISS));
                    349:        if (0 == err)
                    350:                return(1);
                    351:        assert(argv);
                    352:        return(mdoc_perr(mdoc, argv->line,
                    353:                        argv->pos, ERR_SYNTAX_ARGBAD));
                    354: }
                    355:
                    356:
                    357: static int
1.25    ! kristaps  358: pre_it(struct mdoc *mdoc, struct mdoc_node *node)
        !           359: {
        !           360:
        !           361:        if (MDOC_BLOCK != mdoc->last->type)
        !           362:                return(1);
        !           363:        assert(MDOC_It == mdoc->last->tok);
        !           364:
        !           365:        if (MDOC_BODY != mdoc->last->parent->type)
        !           366:                return(mdoc_verr(mdoc, node, ERR_SYNTAX_PARENTBAD));
        !           367:        if (MDOC_Bl != mdoc->last->parent->tok)
        !           368:                return(mdoc_verr(mdoc, node, ERR_SYNTAX_PARENTBAD));
        !           369:
        !           370:        return(1);
        !           371: }
        !           372:
        !           373:
        !           374: static int
1.20      kristaps  375: pre_prologue(struct mdoc *mdoc, struct mdoc_node *node)
                    376: {
                    377:
                    378:        if (SEC_PROLOGUE != mdoc->sec_lastn)
                    379:                return(mdoc_verr(mdoc, node, ERR_SEC_NPROLOGUE));
                    380:        assert(MDOC_ELEM == node->type);
                    381:
                    382:        /* Check for ordering. */
                    383:
1.25    ! kristaps  384:        switch (node->tok) {
1.20      kristaps  385:        case (MDOC_Os):
                    386:                if (mdoc->meta.title[0] && mdoc->meta.date)
                    387:                        break;
                    388:                return(mdoc_verr(mdoc, node, ERR_SEC_PROLOGUE_OO));
                    389:        case (MDOC_Dt):
                    390:                if (0 == mdoc->meta.title[0] && mdoc->meta.date)
                    391:                        break;
                    392:                return(mdoc_verr(mdoc, node, ERR_SEC_PROLOGUE_OO));
                    393:        case (MDOC_Dd):
                    394:                if (0 == mdoc->meta.title[0] && 0 == mdoc->meta.date)
                    395:                        break;
                    396:                return(mdoc_verr(mdoc, node, ERR_SEC_PROLOGUE_OO));
                    397:        default:
                    398:                abort();
                    399:                /* NOTREACHED */
                    400:        }
                    401:
                    402:        /* Check for repetition. */
                    403:
1.25    ! kristaps  404:        switch (node->tok) {
1.20      kristaps  405:        case (MDOC_Os):
                    406:                if (0 == mdoc->meta.os[0])
                    407:                        return(1);
                    408:                break;
                    409:        case (MDOC_Dd):
                    410:                if (0 == mdoc->meta.date)
                    411:                        return(1);
                    412:                break;
                    413:        case (MDOC_Dt):
                    414:                if (0 == mdoc->meta.title[0])
                    415:                        return(1);
                    416:                break;
                    417:        default:
                    418:                abort();
                    419:                /* NOTREACHED */
                    420:        }
                    421:
                    422:        return(mdoc_verr(mdoc, node, ERR_SEC_PROLOGUE_REP));
                    423: }
                    424:
                    425:
1.25    ! kristaps  426: /* Warn if `Bl' type-specific syntax isn't reflected in items. */
        !           427: static int
        !           428: post_it(struct mdoc *mdoc)
        !           429: {
        !           430:        int               type, sv;
        !           431: #define        TYPE_NONE        (0)
        !           432: #define        TYPE_BODY        (1)
        !           433: #define        TYPE_HEAD        (2)
        !           434:        size_t            i, argc;
        !           435:        struct mdoc_node *n;
        !           436:
        !           437:        if (MDOC_BLOCK != mdoc->last->type)
        !           438:                return(1);
        !           439:
        !           440:        assert(MDOC_It == mdoc->last->tok);
        !           441:
        !           442:        n = mdoc->last->parent;
        !           443:        assert(n);
        !           444:        assert(MDOC_Bl == n->tok);
        !           445:
        !           446:        n = n->parent;
        !           447:        assert(MDOC_BLOCK == n->type);
        !           448:        assert(MDOC_Bl == n->tok);
        !           449:
        !           450:        argc = n->data.block.argc;
        !           451:        type = TYPE_NONE;
        !           452:
        !           453:        for (i = 0; TYPE_NONE == type && i < argc; i++)
        !           454:                switch (n->data.block.argv[(int)i].arg) {
        !           455:                case (MDOC_Tag):
        !           456:                        /* FALLTHROUGH */
        !           457:                case (MDOC_Diag):
        !           458:                        /* FALLTHROUGH */
        !           459:                case (MDOC_Hang):
        !           460:                        /* FALLTHROUGH */
        !           461:                case (MDOC_Ohang):
        !           462:                        /* FALLTHROUGH */
        !           463:                case (MDOC_Inset):
        !           464:                        type = TYPE_HEAD;
        !           465:                        sv = n->data.block.argv[(int)i].arg;
        !           466:                        break;
        !           467:                case (MDOC_Bullet):
        !           468:                        /* FALLTHROUGH */
        !           469:                case (MDOC_Dash):
        !           470:                        /* FALLTHROUGH */
        !           471:                case (MDOC_Enum):
        !           472:                        /* FALLTHROUGH */
        !           473:                case (MDOC_Hyphen):
        !           474:                        /* FALLTHROUGH */
        !           475:                case (MDOC_Item):
        !           476:                        /* FALLTHROUGH */
        !           477:                case (MDOC_Column):
        !           478:                        type = TYPE_BODY;
        !           479:                        sv = n->data.block.argv[(int)i].arg;
        !           480:                        break;
        !           481:                default:
        !           482:                        break;
        !           483:                }
        !           484:
        !           485:        assert(TYPE_NONE != type);
        !           486:
        !           487:        if (TYPE_HEAD == type) {
        !           488:                if (NULL == (n = mdoc->last->data.block.head)) {
        !           489:                        if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYHEAD))
        !           490:                                return(0);
        !           491:                } else if (NULL == n->child)
        !           492:                        if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYHEAD))
        !           493:                                return(0);
        !           494:
        !           495:                if (NULL == (n = mdoc->last->data.block.body)) {
        !           496:                        if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYBODY))
        !           497:                                return(0);
        !           498:                } else if (NULL == n->child)
        !           499:                        if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYBODY))
        !           500:                                return(0);
        !           501:
        !           502:                return(1);
        !           503:        }
        !           504:
        !           505:        if (NULL == (n = mdoc->last->data.block.head)) {
        !           506:                if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYHEAD))
        !           507:                        return(0);
        !           508:        } else if (NULL == n->child)
        !           509:                if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYHEAD))
        !           510:                        return(0);
        !           511:
        !           512:        if ((n = mdoc->last->data.block.body) && n->child)
        !           513:                if ( ! mdoc_warn(mdoc, WARN_SYNTAX_NOBODY))
        !           514:                        return(0);
        !           515:
        !           516:        /* TODO: make sure columns are aligned. */
        !           517:        assert(MDOC_Column != sv);
        !           518:
        !           519:        return(1);
        !           520:
        !           521: #undef TYPE_NONE
        !           522: #undef TYPE_BODY
        !           523: #undef TYPE_HEAD
        !           524: }
        !           525:
        !           526:
        !           527: /* Make sure that only `It' macros are our body-children. */
1.24      kristaps  528: static int
                    529: post_bl(struct mdoc *mdoc)
                    530: {
                    531:        struct mdoc_node *n;
                    532:
                    533:        if (MDOC_BODY != mdoc->last->type)
                    534:                return(1);
1.25    ! kristaps  535:        assert(MDOC_Bl == mdoc->last->tok);
1.24      kristaps  536:
                    537:        for (n = mdoc->last->child; n; n = n->next) {
                    538:                if (MDOC_BLOCK == n->type)
1.25    ! kristaps  539:                        if (MDOC_It == n->tok)
1.24      kristaps  540:                                continue;
                    541:                break;
                    542:        }
                    543:        if (NULL == n)
                    544:                return(1);
                    545:        return(mdoc_verr(mdoc, n, ERR_SYNTAX_CHILDBAD));
                    546: }
                    547:
                    548:
1.25    ! kristaps  549: /* Warn if conventional sections are out of order. */
1.20      kristaps  550: static int
1.21      kristaps  551: post_sh(struct mdoc *mdoc)
1.14      kristaps  552: {
1.21      kristaps  553:        enum mdoc_sec     sec;
                    554:        int               i;
                    555:        struct mdoc_node *n;
                    556:        char             *args[MDOC_LINEARG_MAX];
                    557:
                    558:        if (MDOC_HEAD != mdoc->last->type)
                    559:                return(1);
                    560:
1.25    ! kristaps  561:        assert(MDOC_Sh == mdoc->last->tok);
1.21      kristaps  562:
                    563:        n = mdoc->last->child;
                    564:        assert(n);
1.14      kristaps  565:
1.21      kristaps  566:        for (i = 0; n && i < MDOC_LINEARG_MAX; n = n->next, i++) {
                    567:                assert(MDOC_TEXT == n->type);
                    568:                assert(NULL == n->child);
                    569:                assert(n->data.text.string);
                    570:                args[i] = n->data.text.string;
                    571:        }
                    572:
                    573:        sec = mdoc_atosec((size_t)i, (const char **)args);
                    574:        if (SEC_CUSTOM == sec)
                    575:                return(1);
                    576:        if (sec > mdoc->sec_lastn)
                    577:                return(1);
                    578:
                    579:        if (sec == mdoc->sec_lastn)
                    580:                return(mdoc_warn(mdoc, WARN_SEC_REP));
                    581:        return(mdoc_warn(mdoc, WARN_SEC_OO));
1.11      kristaps  582: }
                    583:
                    584:
1.17      kristaps  585: int
1.18      kristaps  586: mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *node)
1.11      kristaps  587: {
1.24      kristaps  588:        v_pre           *p;
1.18      kristaps  589:
1.25    ! kristaps  590:        /* TODO: character-escape checks. */
        !           591:
        !           592:        if (MDOC_TEXT == node->type)
1.18      kristaps  593:                return(1);
1.25    ! kristaps  594:        assert(MDOC_ROOT != node->type);
1.11      kristaps  595:
1.25    ! kristaps  596:        if (NULL == mdoc_valids[node->tok].pre)
1.11      kristaps  597:                return(1);
1.25    ! kristaps  598:        for (p = mdoc_valids[node->tok].pre; *p; p++)
1.24      kristaps  599:                if ( ! (*p)(mdoc, node))
                    600:                        return(0);
                    601:        return(1);
1.11      kristaps  602: }
                    603:
                    604:
1.17      kristaps  605: int
1.18      kristaps  606: mdoc_valid_post(struct mdoc *mdoc)
1.11      kristaps  607: {
1.17      kristaps  608:        v_post          *p;
1.11      kristaps  609:
1.25    ! kristaps  610:        if (MDOC_TEXT == mdoc->last->type)
        !           611:                return(1);
        !           612:        if (MDOC_ROOT == mdoc->last->type)
1.8       kristaps  613:                return(1);
1.14      kristaps  614:
1.25    ! kristaps  615:        if (NULL == mdoc_valids[mdoc->last->tok].post)
1.9       kristaps  616:                return(1);
1.25    ! kristaps  617:        for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
1.18      kristaps  618:                if ( ! (*p)(mdoc))
1.17      kristaps  619:                        return(0);
1.11      kristaps  620:
1.14      kristaps  621:        return(1);
1.11      kristaps  622: }
1.14      kristaps  623:

CVSweb