[BACK]Return to mdoc_action.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mandoc

Annotation of src/usr.bin/mandoc/mdoc_action.c, Revision 1.23

1.23    ! schwarze    1: /*     $Id: mdoc_action.c,v 1.22 2009/10/19 15:44:01 schwarze Exp $ */
1.1       kristaps    2: /*
1.2       schwarze    3:  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
1.1       kristaps    4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
1.2       schwarze    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.2       schwarze    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:  */
                     17: #include <sys/utsname.h>
                     18:
                     19: #include <assert.h>
                     20: #include <errno.h>
                     21: #include <stdio.h>
                     22: #include <stdlib.h>
                     23: #include <string.h>
                     24:
                     25: #include "libmdoc.h"
                     26:
1.20      schwarze   27: #define        POST_ARGS struct mdoc *m, struct mdoc_node *n
1.1       kristaps   28: #define        PRE_ARGS  struct mdoc *m, const struct mdoc_node *n
                     29:
                     30: struct actions {
                     31:        int     (*pre)(PRE_ARGS);
                     32:        int     (*post)(POST_ARGS);
                     33: };
                     34:
1.23    ! schwarze   35: static int       concat(struct mdoc *,
        !            36:                        const struct mdoc_node *,
        !            37:                        char *, size_t);
        !            38: static inline int order_rs(int);
        !            39:
1.1       kristaps   40: static int       post_ar(POST_ARGS);
1.15      schwarze   41: static int       post_at(POST_ARGS);
1.1       kristaps   42: static int       post_bl(POST_ARGS);
1.6       schwarze   43: static int       post_bl_head(POST_ARGS);
1.15      schwarze   44: static int       post_bl_tagwidth(POST_ARGS);
1.1       kristaps   45: static int       post_bl_width(POST_ARGS);
                     46: static int       post_dd(POST_ARGS);
                     47: static int       post_display(POST_ARGS);
                     48: static int       post_dt(POST_ARGS);
1.15      schwarze   49: static int       post_lb(POST_ARGS);
1.1       kristaps   50: static int       post_nm(POST_ARGS);
                     51: static int       post_os(POST_ARGS);
                     52: static int       post_prol(POST_ARGS);
1.23    ! schwarze   53: static int       post_rs(POST_ARGS);
1.1       kristaps   54: static int       post_sh(POST_ARGS);
1.15      schwarze   55: static int       post_st(POST_ARGS);
1.1       kristaps   56: static int       post_std(POST_ARGS);
1.17      schwarze   57: static int       post_tilde(POST_ARGS);
1.1       kristaps   58:
                     59: static int       pre_bd(PRE_ARGS);
1.22      schwarze   60: static int       pre_bl(PRE_ARGS);
1.1       kristaps   61: static int       pre_dl(PRE_ARGS);
1.22      schwarze   62: static int       pre_offset(PRE_ARGS);
1.1       kristaps   63:
1.21      schwarze   64: static const struct actions mdoc_actions[MDOC_MAX] = {
1.4       schwarze   65:        { NULL, NULL }, /* Ap */
1.1       kristaps   66:        { NULL, post_dd }, /* Dd */
                     67:        { NULL, post_dt }, /* Dt */
                     68:        { NULL, post_os }, /* Os */
                     69:        { NULL, post_sh }, /* Sh */
                     70:        { NULL, NULL }, /* Ss */
                     71:        { NULL, NULL }, /* Pp */
                     72:        { NULL, NULL }, /* D1 */
                     73:        { pre_dl, post_display }, /* Dl */
                     74:        { pre_bd, post_display }, /* Bd */
                     75:        { NULL, NULL }, /* Ed */
1.22      schwarze   76:        { pre_bl, post_bl }, /* Bl */
1.1       kristaps   77:        { NULL, NULL }, /* El */
                     78:        { NULL, NULL }, /* It */
                     79:        { NULL, NULL }, /* Ad */
                     80:        { NULL, NULL }, /* An */
                     81:        { NULL, post_ar }, /* Ar */
1.20      schwarze   82:        { NULL, NULL }, /* Cd */
1.1       kristaps   83:        { NULL, NULL }, /* Cm */
                     84:        { NULL, NULL }, /* Dv */
                     85:        { NULL, NULL }, /* Er */
                     86:        { NULL, NULL }, /* Ev */
                     87:        { NULL, post_std }, /* Ex */
                     88:        { NULL, NULL }, /* Fa */
                     89:        { NULL, NULL }, /* Fd */
                     90:        { NULL, NULL }, /* Fl */
                     91:        { NULL, NULL }, /* Fn */
                     92:        { NULL, NULL }, /* Ft */
                     93:        { NULL, NULL }, /* Ic */
                     94:        { NULL, NULL }, /* In */
                     95:        { NULL, NULL }, /* Li */
                     96:        { NULL, NULL }, /* Nd */
                     97:        { NULL, post_nm }, /* Nm */
                     98:        { NULL, NULL }, /* Op */
                     99:        { NULL, NULL }, /* Ot */
1.17      schwarze  100:        { NULL, post_tilde }, /* Pa */
1.1       kristaps  101:        { NULL, post_std }, /* Rv */
1.15      schwarze  102:        { NULL, post_st }, /* St */
1.1       kristaps  103:        { NULL, NULL }, /* Va */
                    104:        { NULL, NULL }, /* Vt */
                    105:        { NULL, NULL }, /* Xr */
                    106:        { NULL, NULL }, /* %A */
                    107:        { NULL, NULL }, /* %B */
                    108:        { NULL, NULL }, /* %D */
                    109:        { NULL, NULL }, /* %I */
                    110:        { NULL, NULL }, /* %J */
                    111:        { NULL, NULL }, /* %N */
                    112:        { NULL, NULL }, /* %O */
                    113:        { NULL, NULL }, /* %P */
                    114:        { NULL, NULL }, /* %R */
                    115:        { NULL, NULL }, /* %T */
                    116:        { NULL, NULL }, /* %V */
                    117:        { NULL, NULL }, /* Ac */
                    118:        { NULL, NULL }, /* Ao */
                    119:        { NULL, NULL }, /* Aq */
1.15      schwarze  120:        { NULL, post_at }, /* At */
1.1       kristaps  121:        { NULL, NULL }, /* Bc */
                    122:        { NULL, NULL }, /* Bf */
                    123:        { NULL, NULL }, /* Bo */
                    124:        { NULL, NULL }, /* Bq */
                    125:        { NULL, NULL }, /* Bsx */
                    126:        { NULL, NULL }, /* Bx */
                    127:        { NULL, NULL }, /* Db */
                    128:        { NULL, NULL }, /* Dc */
                    129:        { NULL, NULL }, /* Do */
                    130:        { NULL, NULL }, /* Dq */
                    131:        { NULL, NULL }, /* Ec */
                    132:        { NULL, NULL }, /* Ef */
                    133:        { NULL, NULL }, /* Em */
                    134:        { NULL, NULL }, /* Eo */
                    135:        { NULL, NULL }, /* Fx */
                    136:        { NULL, NULL }, /* Ms */
                    137:        { NULL, NULL }, /* No */
                    138:        { NULL, NULL }, /* Ns */
                    139:        { NULL, NULL }, /* Nx */
                    140:        { NULL, NULL }, /* Ox */
                    141:        { NULL, NULL }, /* Pc */
                    142:        { NULL, NULL }, /* Pf */
                    143:        { NULL, NULL }, /* Po */
                    144:        { NULL, NULL }, /* Pq */
                    145:        { NULL, NULL }, /* Qc */
                    146:        { NULL, NULL }, /* Ql */
                    147:        { NULL, NULL }, /* Qo */
                    148:        { NULL, NULL }, /* Qq */
                    149:        { NULL, NULL }, /* Re */
1.23    ! schwarze  150:        { NULL, post_rs }, /* Rs */
1.1       kristaps  151:        { NULL, NULL }, /* Sc */
                    152:        { NULL, NULL }, /* So */
                    153:        { NULL, NULL }, /* Sq */
                    154:        { NULL, NULL }, /* Sm */
                    155:        { NULL, NULL }, /* Sx */
                    156:        { NULL, NULL }, /* Sy */
                    157:        { NULL, NULL }, /* Tn */
                    158:        { NULL, NULL }, /* Ux */
                    159:        { NULL, NULL }, /* Xc */
                    160:        { NULL, NULL }, /* Xo */
                    161:        { NULL, NULL }, /* Fo */
                    162:        { NULL, NULL }, /* Fc */
                    163:        { NULL, NULL }, /* Oo */
                    164:        { NULL, NULL }, /* Oc */
                    165:        { NULL, NULL }, /* Bk */
                    166:        { NULL, NULL }, /* Ek */
                    167:        { NULL, NULL }, /* Bt */
                    168:        { NULL, NULL }, /* Hf */
                    169:        { NULL, NULL }, /* Fr */
                    170:        { NULL, NULL }, /* Ud */
1.15      schwarze  171:        { NULL, post_lb }, /* Lb */
1.1       kristaps  172:        { NULL, NULL }, /* Lp */
1.17      schwarze  173:        { NULL, post_tilde }, /* Lk */
1.1       kristaps  174:        { NULL, NULL }, /* Mt */
                    175:        { NULL, NULL }, /* Brq */
                    176:        { NULL, NULL }, /* Bro */
                    177:        { NULL, NULL }, /* Brc */
                    178:        { NULL, NULL }, /* %C */
                    179:        { NULL, NULL }, /* Es */
                    180:        { NULL, NULL }, /* En */
                    181:        { NULL, NULL }, /* Dx */
                    182:        { NULL, NULL }, /* %Q */
1.16      schwarze  183:        { NULL, NULL }, /* br */
                    184:        { NULL, NULL }, /* sp */
1.1       kristaps  185: };
                    186:
1.23    ! schwarze  187: #define        RSORD_MAX 13
        !           188:
        !           189: static const int rsord[RSORD_MAX] = {
        !           190:        MDOC__A,
        !           191:        MDOC__T,
        !           192:        MDOC__B,
        !           193:        MDOC__I,
        !           194:        MDOC__J,
        !           195:        MDOC__R,
        !           196:        MDOC__N,
        !           197:        MDOC__V,
        !           198:        MDOC__P,
        !           199:        MDOC__Q,
        !           200:        MDOC__D,
        !           201:        MDOC__O,
        !           202:        MDOC__C
        !           203: };
1.15      schwarze  204:
1.1       kristaps  205:
                    206: int
                    207: mdoc_action_pre(struct mdoc *m, const struct mdoc_node *n)
                    208: {
                    209:
                    210:        switch (n->type) {
                    211:        case (MDOC_ROOT):
                    212:                /* FALLTHROUGH */
                    213:        case (MDOC_TEXT):
                    214:                return(1);
                    215:        default:
                    216:                break;
                    217:        }
                    218:
                    219:        if (NULL == mdoc_actions[n->tok].pre)
                    220:                return(1);
                    221:        return((*mdoc_actions[n->tok].pre)(m, n));
                    222: }
                    223:
                    224:
                    225: int
                    226: mdoc_action_post(struct mdoc *m)
                    227: {
                    228:
                    229:        if (MDOC_ACTED & m->last->flags)
                    230:                return(1);
                    231:        m->last->flags |= MDOC_ACTED;
                    232:
                    233:        switch (m->last->type) {
                    234:        case (MDOC_TEXT):
                    235:                /* FALLTHROUGH */
                    236:        case (MDOC_ROOT):
                    237:                return(1);
                    238:        default:
                    239:                break;
                    240:        }
                    241:
                    242:        if (NULL == mdoc_actions[m->last->tok].post)
                    243:                return(1);
1.20      schwarze  244:        return((*mdoc_actions[m->last->tok].post)(m, m->last));
1.1       kristaps  245: }
                    246:
                    247:
                    248: static int
                    249: concat(struct mdoc *m, const struct mdoc_node *n,
                    250:                char *buf, size_t sz)
                    251: {
                    252:
                    253:        for ( ; n; n = n->next) {
                    254:                assert(MDOC_TEXT == n->type);
                    255:                if (strlcat(buf, n->string, sz) >= sz)
1.12      schwarze  256:                        return(mdoc_nerr(m, n, ETOOLONG));
1.1       kristaps  257:                if (NULL == n->next)
                    258:                        continue;
                    259:                if (strlcat(buf, " ", sz) >= sz)
1.12      schwarze  260:                        return(mdoc_nerr(m, n, ETOOLONG));
1.1       kristaps  261:        }
                    262:
                    263:        return(1);
                    264: }
                    265:
                    266:
                    267: static int
                    268: post_std(POST_ARGS)
                    269: {
1.20      schwarze  270:        struct mdoc_node        *nn;
1.1       kristaps  271:
1.20      schwarze  272:        if (n->child)
1.1       kristaps  273:                return(1);
1.20      schwarze  274:
                    275:        nn = n;
                    276:        m->next = MDOC_NEXT_CHILD;
1.1       kristaps  277:        assert(m->meta.name);
1.20      schwarze  278:        if ( ! mdoc_word_alloc(m, n->line, n->pos, m->meta.name))
                    279:                return(0);
                    280:        m->last = nn;
1.1       kristaps  281:
                    282:        return(1);
                    283: }
                    284:
                    285:
                    286: static int
                    287: post_nm(POST_ARGS)
                    288: {
                    289:        char             buf[64];
                    290:
                    291:        if (m->meta.name)
                    292:                return(1);
                    293:
                    294:        buf[0] = 0;
1.20      schwarze  295:        if ( ! concat(m, n->child, buf, sizeof(buf)))
1.1       kristaps  296:                return(0);
                    297:        if (NULL == (m->meta.name = strdup(buf)))
1.20      schwarze  298:                return(mdoc_nerr(m, n, EMALLOC));
1.2       schwarze  299:
1.1       kristaps  300:        return(1);
                    301: }
                    302:
                    303:
                    304: static int
1.15      schwarze  305: post_lb(POST_ARGS)
                    306: {
                    307:        const char      *p;
                    308:        char            *buf;
                    309:        size_t           sz;
                    310:
1.20      schwarze  311:        assert(MDOC_TEXT == n->child->type);
                    312:        p = mdoc_a2lib(n->child->string);
1.15      schwarze  313:        if (NULL == p) {
1.20      schwarze  314:                sz = strlen(n->child->string) +
1.15      schwarze  315:                        2 + strlen("\\(lqlibrary\\(rq");
                    316:                buf = malloc(sz);
                    317:                if (NULL == buf)
1.20      schwarze  318:                        return(mdoc_nerr(m, n, EMALLOC));
1.15      schwarze  319:                (void)snprintf(buf, sz, "library \\(lq%s\\(rq",
1.20      schwarze  320:                                n->child->string);
                    321:                free(n->child->string);
                    322:                n->child->string = buf;
1.15      schwarze  323:                return(1);
                    324:        }
                    325:
1.20      schwarze  326:        free(n->child->string);
                    327:        n->child->string = strdup(p);
                    328:        if (NULL == n->child->string)
                    329:                return(mdoc_nerr(m, n, EMALLOC));
                    330:
1.15      schwarze  331:        return(1);
                    332: }
                    333:
                    334:
                    335: static int
                    336: post_st(POST_ARGS)
                    337: {
                    338:        const char      *p;
                    339:
1.20      schwarze  340:        assert(MDOC_TEXT == n->child->type);
                    341:        p = mdoc_a2st(n->child->string);
1.15      schwarze  342:        assert(p);
1.20      schwarze  343:        free(n->child->string);
                    344:        n->child->string = strdup(p);
                    345:        if (NULL == n->child->string)
                    346:                return(mdoc_nerr(m, n, EMALLOC));
                    347:
1.15      schwarze  348:        return(1);
                    349: }
                    350:
                    351:
                    352: static int
                    353: post_at(POST_ARGS)
                    354: {
1.20      schwarze  355:        struct mdoc_node        *nn;
                    356:        const char              *p;
1.15      schwarze  357:
1.20      schwarze  358:        if (n->child) {
                    359:                assert(MDOC_TEXT == n->child->type);
                    360:                p = mdoc_a2att(n->child->string);
1.15      schwarze  361:                assert(p);
1.20      schwarze  362:                free(n->child->string);
                    363:                n->child->string = strdup(p);
                    364:                if (NULL == n->child->string)
                    365:                        return(mdoc_nerr(m, n, EMALLOC));
1.15      schwarze  366:                return(1);
                    367:        }
                    368:
1.20      schwarze  369:        nn = n;
1.15      schwarze  370:        m->next = MDOC_NEXT_CHILD;
                    371:
1.20      schwarze  372:        if ( ! mdoc_word_alloc(m, nn->line, nn->pos, "AT&T UNIX"))
1.15      schwarze  373:                return(0);
1.20      schwarze  374:        m->last = nn;
1.15      schwarze  375:
                    376:        return(1);
                    377: }
                    378:
                    379:
                    380: static int
1.1       kristaps  381: post_sh(POST_ARGS)
                    382: {
                    383:        enum mdoc_sec    sec;
                    384:        char             buf[64];
                    385:
                    386:        /*
                    387:         * We keep track of the current section /and/ the "named"
                    388:         * section, which is one of the conventional ones, in order to
                    389:         * check ordering.
                    390:         */
                    391:
1.20      schwarze  392:        if (MDOC_HEAD != n->type)
1.1       kristaps  393:                return(1);
                    394:
                    395:        buf[0] = 0;
1.20      schwarze  396:        if ( ! concat(m, n->child, buf, sizeof(buf)))
1.1       kristaps  397:                return(0);
                    398:        if (SEC_CUSTOM != (sec = mdoc_atosec(buf)))
                    399:                m->lastnamed = sec;
                    400:
                    401:        switch ((m->lastsec = sec)) {
                    402:        case (SEC_RETURN_VALUES):
                    403:                /* FALLTHROUGH */
                    404:        case (SEC_ERRORS):
                    405:                switch (m->meta.msec) {
                    406:                case (2):
                    407:                        /* FALLTHROUGH */
                    408:                case (3):
                    409:                        /* FALLTHROUGH */
                    410:                case (9):
                    411:                        break;
                    412:                default:
1.20      schwarze  413:                        return(mdoc_nwarn(m, n, EBADSEC));
1.1       kristaps  414:                }
                    415:                break;
                    416:        default:
                    417:                break;
                    418:        }
                    419:        return(1);
                    420: }
                    421:
                    422:
                    423: static int
                    424: post_dt(POST_ARGS)
                    425: {
1.20      schwarze  426:        struct mdoc_node *nn;
1.1       kristaps  427:        const char       *cp;
                    428:        char             *ep;
                    429:        long              lval;
                    430:
                    431:        if (m->meta.title)
                    432:                free(m->meta.title);
                    433:        if (m->meta.vol)
                    434:                free(m->meta.vol);
                    435:        if (m->meta.arch)
                    436:                free(m->meta.arch);
                    437:
                    438:        m->meta.title = m->meta.vol = m->meta.arch = NULL;
                    439:        m->meta.msec = 0;
                    440:
                    441:        /* Handles: `.Dt'
                    442:         *   --> title = unknown, volume = local, msec = 0, arch = NULL
                    443:         */
                    444:
1.20      schwarze  445:        if (NULL == (nn = n->child)) {
1.1       kristaps  446:                if (NULL == (m->meta.title = strdup("unknown")))
1.20      schwarze  447:                        return(mdoc_nerr(m, n, EMALLOC));
1.1       kristaps  448:                if (NULL == (m->meta.vol = strdup("local")))
1.20      schwarze  449:                        return(mdoc_nerr(m, n, EMALLOC));
                    450:                return(post_prol(m, n));
1.1       kristaps  451:        }
                    452:
                    453:        /* Handles: `.Dt TITLE'
                    454:         *   --> title = TITLE, volume = local, msec = 0, arch = NULL
                    455:         */
                    456:
1.20      schwarze  457:        if (NULL == (m->meta.title = strdup(nn->string)))
                    458:                return(mdoc_nerr(m, n, EMALLOC));
1.1       kristaps  459:
1.20      schwarze  460:        if (NULL == (nn = nn->next)) {
1.1       kristaps  461:                if (NULL == (m->meta.vol = strdup("local")))
1.20      schwarze  462:                        return(mdoc_nerr(m, n, EMALLOC));
                    463:                return(post_prol(m, n));
1.1       kristaps  464:        }
                    465:
                    466:        /* Handles: `.Dt TITLE SEC'
                    467:         *   --> title = TITLE, volume = SEC is msec ?
                    468:         *           format(msec) : SEC,
                    469:         *       msec = SEC is msec ? atoi(msec) : 0,
                    470:         *       arch = NULL
                    471:         */
                    472:
1.20      schwarze  473:        cp = mdoc_a2msec(nn->string);
1.1       kristaps  474:        if (cp) {
                    475:                if (NULL == (m->meta.vol = strdup(cp)))
1.20      schwarze  476:                        return(mdoc_nerr(m, n, EMALLOC));
1.1       kristaps  477:                errno = 0;
1.20      schwarze  478:                lval = strtol(nn->string, &ep, 10);
                    479:                if (nn->string[0] != '\0' && *ep == '\0')
1.1       kristaps  480:                        m->meta.msec = (int)lval;
1.20      schwarze  481:        } else if (NULL == (m->meta.vol = strdup(nn->string)))
                    482:                return(mdoc_nerr(m, n, EMALLOC));
1.1       kristaps  483:
1.20      schwarze  484:        if (NULL == (nn = nn->next))
                    485:                return(post_prol(m, n));
1.1       kristaps  486:
                    487:        /* Handles: `.Dt TITLE SEC VOL'
                    488:         *   --> title = TITLE, volume = VOL is vol ?
                    489:         *       format(VOL) :
                    490:         *           VOL is arch ? format(arch) :
                    491:         *               VOL
                    492:         */
                    493:
1.20      schwarze  494:        cp = mdoc_a2vol(nn->string);
1.1       kristaps  495:        if (cp) {
                    496:                free(m->meta.vol);
                    497:                if (NULL == (m->meta.vol = strdup(cp)))
1.20      schwarze  498:                        return(mdoc_nerr(m, n, EMALLOC));
1.1       kristaps  499:        } else {
1.20      schwarze  500:                cp = mdoc_a2arch(nn->string);
1.1       kristaps  501:                if (NULL == cp) {
                    502:                        free(m->meta.vol);
1.20      schwarze  503:                        if (NULL == (m->meta.vol = strdup(nn->string)))
                    504:                                return(mdoc_nerr(m, n, EMALLOC));
1.1       kristaps  505:                } else if (NULL == (m->meta.arch = strdup(cp)))
1.20      schwarze  506:                        return(mdoc_nerr(m, n, EMALLOC));
1.1       kristaps  507:        }
                    508:
                    509:        /* Ignore any subsequent parameters... */
                    510:
1.20      schwarze  511:        return(post_prol(m, n));
1.1       kristaps  512: }
                    513:
                    514:
                    515: static int
                    516: post_os(POST_ARGS)
                    517: {
                    518:        char              buf[64];
                    519:        struct utsname    utsname;
                    520:
                    521:        if (m->meta.os)
                    522:                free(m->meta.os);
                    523:
                    524:        buf[0] = 0;
1.20      schwarze  525:        if ( ! concat(m, n->child, buf, sizeof(buf)))
1.1       kristaps  526:                return(0);
                    527:
                    528:        if (0 == buf[0]) {
                    529:                if (-1 == uname(&utsname))
1.20      schwarze  530:                        return(mdoc_nerr(m, n, EUTSNAME));
1.1       kristaps  531:                if (strlcat(buf, utsname.sysname, 64) >= 64)
1.20      schwarze  532:                        return(mdoc_nerr(m, n, ETOOLONG));
1.1       kristaps  533:                if (strlcat(buf, " ", 64) >= 64)
1.20      schwarze  534:                        return(mdoc_nerr(m, n, ETOOLONG));
1.1       kristaps  535:                if (strlcat(buf, utsname.release, 64) >= 64)
1.20      schwarze  536:                        return(mdoc_nerr(m, n, ETOOLONG));
1.1       kristaps  537:        }
                    538:
                    539:        if (NULL == (m->meta.os = strdup(buf)))
1.20      schwarze  540:                return(mdoc_nerr(m, n, EMALLOC));
1.1       kristaps  541:
1.20      schwarze  542:        return(post_prol(m, n));
1.1       kristaps  543: }
                    544:
                    545:
                    546: /*
                    547:  * Calculate the -width for a `Bl -tag' list if it hasn't been provided.
                    548:  * Uses the first head macro.
                    549:  */
                    550: static int
1.20      schwarze  551: post_bl_tagwidth(POST_ARGS)
1.1       kristaps  552: {
1.20      schwarze  553:        struct mdoc_node  *nn;
1.1       kristaps  554:        int                sz;
                    555:        char               buf[32];
                    556:
                    557:        /*
                    558:         * Use the text width, if a text node, or the default macro
                    559:         * width if a macro.
                    560:         */
                    561:
1.20      schwarze  562:        nn = n->body->child;
                    563:        if (nn) {
                    564:                assert(MDOC_BLOCK == nn->type);
                    565:                assert(MDOC_It == nn->tok);
                    566:                nn = nn->head->child;
1.1       kristaps  567:        }
                    568:
                    569:        sz = 10; /* Default size. */
                    570:
1.20      schwarze  571:        if (nn) {
                    572:                if (MDOC_TEXT != nn->type) {
                    573:                        if (0 == (sz = (int)mdoc_macro2len(nn->tok)))
                    574:                                if ( ! mdoc_nwarn(m, n, ENOWIDTH))
1.1       kristaps  575:                                        return(0);
                    576:                } else
1.20      schwarze  577:                        sz = (int)strlen(nn->string) + 1;
1.1       kristaps  578:        }
                    579:
                    580:        if (-1 == snprintf(buf, sizeof(buf), "%dn", sz))
1.20      schwarze  581:                return(mdoc_nerr(m, n, ENUMFMT));
1.1       kristaps  582:
                    583:        /*
                    584:         * We have to dynamically add this to the macro's argument list.
                    585:         * We're guaranteed that a MDOC_Width doesn't already exist.
                    586:         */
                    587:
1.20      schwarze  588:        nn = n;
                    589:        assert(nn->args);
                    590:        sz = (int)(nn->args->argc)++;
1.1       kristaps  591:
1.20      schwarze  592:        nn->args->argv = realloc(nn->args->argv,
                    593:                        nn->args->argc * sizeof(struct mdoc_argv));
1.1       kristaps  594:
1.20      schwarze  595:        if (NULL == nn->args->argv)
                    596:                return(mdoc_nerr(m, n, EMALLOC));
1.1       kristaps  597:
1.20      schwarze  598:        nn->args->argv[sz].arg = MDOC_Width;
                    599:        nn->args->argv[sz].line = n->line;
                    600:        nn->args->argv[sz].pos = n->pos;
                    601:        nn->args->argv[sz].sz = 1;
                    602:        nn->args->argv[sz].value = calloc(1, sizeof(char *));
1.1       kristaps  603:
1.20      schwarze  604:        if (NULL == nn->args->argv[sz].value)
                    605:                return(mdoc_nerr(m, n, EMALLOC));
                    606:        if (NULL == (nn->args->argv[sz].value[0] = strdup(buf)))
                    607:                return(mdoc_nerr(m, n, EMALLOC));
1.1       kristaps  608:
                    609:        return(1);
                    610: }
                    611:
                    612:
                    613: static int
1.20      schwarze  614: post_bl_width(POST_ARGS)
1.1       kristaps  615: {
                    616:        size_t            width;
                    617:        int               i, tok;
                    618:        char              buf[32];
                    619:        char             *p;
                    620:
1.20      schwarze  621:        if (NULL == n->args)
1.1       kristaps  622:                return(1);
                    623:
1.20      schwarze  624:        for (i = 0; i < (int)n->args->argc; i++)
                    625:                if (MDOC_Width == n->args->argv[i].arg)
1.1       kristaps  626:                        break;
                    627:
1.20      schwarze  628:        if (i == (int)n->args->argc)
1.1       kristaps  629:                return(1);
1.20      schwarze  630:        p = n->args->argv[i].value[0];
1.1       kristaps  631:
                    632:        /*
                    633:         * If the value to -width is a macro, then we re-write it to be
                    634:         * the macro's width as set in share/tmac/mdoc/doc-common.
                    635:         */
                    636:
                    637:        if (0 == strcmp(p, "Ds"))
1.9       schwarze  638:                width = 6;
1.21      schwarze  639:        else if (MDOC_MAX == (tok = mdoc_hash_find(p)))
1.1       kristaps  640:                return(1);
                    641:        else if (0 == (width = mdoc_macro2len(tok)))
1.20      schwarze  642:                return(mdoc_nwarn(m, n, ENOWIDTH));
1.1       kristaps  643:
                    644:        /* The value already exists: free and reallocate it. */
                    645:
                    646:        if (-1 == snprintf(buf, sizeof(buf), "%zun", width))
1.20      schwarze  647:                return(mdoc_nerr(m, n, ENUMFMT));
1.1       kristaps  648:
1.20      schwarze  649:        free(n->args->argv[i].value[0]);
                    650:        n->args->argv[i].value[0] = strdup(buf);
                    651:        if (NULL == n->args->argv[i].value[0])
                    652:                return(mdoc_nerr(m, n, EMALLOC));
1.1       kristaps  653:
                    654:        return(1);
                    655: }
                    656:
                    657:
1.20      schwarze  658: /* ARGSUSED */
1.1       kristaps  659: static int
1.6       schwarze  660: post_bl_head(POST_ARGS)
                    661: {
                    662:        int                      i, c;
1.20      schwarze  663:        struct mdoc_node        *np, *nn, *nnp;
1.6       schwarze  664:
1.20      schwarze  665:        if (NULL == n->child)
1.6       schwarze  666:                return(1);
                    667:
1.20      schwarze  668:        np = n->parent;
                    669:        assert(np->args);
1.6       schwarze  670:
1.20      schwarze  671:        for (c = 0; c < (int)np->args->argc; c++)
                    672:                if (MDOC_Column == np->args->argv[c].arg)
1.6       schwarze  673:                        break;
                    674:
                    675:        /* Only process -column. */
                    676:
1.20      schwarze  677:        if (c == (int)np->args->argc)
1.6       schwarze  678:                return(1);
                    679:
1.20      schwarze  680:        assert(0 == np->args->argv[c].sz);
1.6       schwarze  681:
                    682:        /*
                    683:         * Accomodate for new-style groff column syntax.  Shuffle the
                    684:         * child nodes, all of which must be TEXT, as arguments for the
                    685:         * column field.  Then, delete the head children.
                    686:         */
                    687:
1.20      schwarze  688:        np->args->argv[c].sz = (size_t)n->nchild;
                    689:        np->args->argv[c].value = malloc
                    690:                ((size_t)n->nchild * sizeof(char *));
1.6       schwarze  691:
1.20      schwarze  692:        for (i = 0, nn = n->child; nn; i++) {
                    693:                np->args->argv[c].value[i] = nn->string;
1.6       schwarze  694:                nn->string = NULL;
                    695:                nnp = nn;
                    696:                nn = nn->next;
                    697:                mdoc_node_free(nnp);
                    698:        }
                    699:
1.20      schwarze  700:        n->nchild = 0;
                    701:        n->child = NULL;
1.8       schwarze  702:
1.6       schwarze  703:        return(1);
                    704: }
                    705:
                    706:
                    707: static int
1.1       kristaps  708: post_bl(POST_ARGS)
                    709: {
                    710:        int               i, r, len;
                    711:
1.20      schwarze  712:        if (MDOC_HEAD == n->type)
                    713:                return(post_bl_head(m, n));
                    714:        if (MDOC_BLOCK != n->type)
1.1       kristaps  715:                return(1);
                    716:
                    717:        /*
                    718:         * These are fairly complicated, so we've broken them into two
                    719:         * functions.  post_bl_tagwidth() is called when a -tag is
                    720:         * specified, but no -width (it must be guessed).  The second
                    721:         * when a -width is specified (macro indicators must be
                    722:         * rewritten into real lengths).
                    723:         */
                    724:
1.20      schwarze  725:        len = (int)(n->args ? n->args->argc : 0);
1.1       kristaps  726:
                    727:        for (r = i = 0; i < len; i++) {
1.20      schwarze  728:                if (MDOC_Tag == n->args->argv[i].arg)
1.1       kristaps  729:                        r |= 1 << 0;
1.20      schwarze  730:                if (MDOC_Width == n->args->argv[i].arg)
1.1       kristaps  731:                        r |= 1 << 1;
                    732:        }
                    733:
                    734:        if (r & (1 << 0) && ! (r & (1 << 1))) {
1.20      schwarze  735:                if ( ! post_bl_tagwidth(m, n))
1.1       kristaps  736:                        return(0);
                    737:        } else if (r & (1 << 1))
1.20      schwarze  738:                if ( ! post_bl_width(m, n))
1.1       kristaps  739:                        return(0);
                    740:
1.3       schwarze  741:        return(1);
                    742: }
                    743:
                    744:
                    745: static int
1.17      schwarze  746: post_tilde(POST_ARGS)
1.3       schwarze  747: {
1.20      schwarze  748:        struct mdoc_node *np;
1.3       schwarze  749:
1.20      schwarze  750:        if (n->child)
1.3       schwarze  751:                return(1);
                    752:
1.20      schwarze  753:        np = n;
1.3       schwarze  754:        m->next = MDOC_NEXT_CHILD;
1.15      schwarze  755:
1.17      schwarze  756:        /* XXX: not documented for `Lk'. */
1.20      schwarze  757:        if ( ! mdoc_word_alloc(m, n->line, n->pos, "~"))
1.3       schwarze  758:                return(0);
1.20      schwarze  759:        m->last = np;
1.3       schwarze  760:
1.1       kristaps  761:        return(1);
                    762: }
                    763:
                    764:
                    765: static int
                    766: post_ar(POST_ARGS)
                    767: {
1.20      schwarze  768:        struct mdoc_node *np;
1.1       kristaps  769:
1.20      schwarze  770:        if (n->child)
1.1       kristaps  771:                return(1);
                    772:
1.20      schwarze  773:        np = n;
1.1       kristaps  774:        m->next = MDOC_NEXT_CHILD;
1.20      schwarze  775:        if ( ! mdoc_word_alloc(m, n->line, n->pos, "file"))
1.1       kristaps  776:                return(0);
1.20      schwarze  777:        if ( ! mdoc_word_alloc(m, n->line, n->pos, "..."))
1.1       kristaps  778:                return(0);
1.20      schwarze  779:        m->last = np;
1.1       kristaps  780:
                    781:        return(1);
                    782: }
                    783:
                    784:
                    785: static int
                    786: post_dd(POST_ARGS)
                    787: {
                    788:        char              buf[64];
                    789:
                    790:        buf[0] = 0;
1.20      schwarze  791:        if ( ! concat(m, n->child, buf, sizeof(buf)))
1.1       kristaps  792:                return(0);
                    793:
                    794:        if (0 == (m->meta.date = mdoc_atotime(buf))) {
1.20      schwarze  795:                if ( ! mdoc_nwarn(m, n, EBADDATE))
1.1       kristaps  796:                        return(0);
                    797:                m->meta.date = time(NULL);
                    798:        }
                    799:
1.20      schwarze  800:        return(post_prol(m, n));
1.1       kristaps  801: }
                    802:
                    803:
                    804: static int
                    805: post_prol(POST_ARGS)
                    806: {
1.20      schwarze  807:        struct mdoc_node *np;
1.1       kristaps  808:
1.20      schwarze  809:        /* Remove prologue macros from AST.  */
1.1       kristaps  810:
1.20      schwarze  811:        if (n->parent->child == n)
                    812:                n->parent->child = n->prev;
                    813:        if (n->prev)
                    814:                n->prev->next = NULL;
1.1       kristaps  815:
1.20      schwarze  816:        np = n;
                    817:        assert(NULL == n->next);
1.1       kristaps  818:
1.20      schwarze  819:        if (n->prev) {
                    820:                m->last = n->prev;
1.1       kristaps  821:                m->next = MDOC_NEXT_SIBLING;
                    822:        } else {
1.20      schwarze  823:                m->last = n->parent;
1.1       kristaps  824:                m->next = MDOC_NEXT_CHILD;
                    825:        }
                    826:
1.20      schwarze  827:        mdoc_node_freelist(np);
1.18      schwarze  828:
                    829:        if (m->meta.title && m->meta.date && m->meta.os)
                    830:                m->flags |= MDOC_PBODY;
1.20      schwarze  831:
1.1       kristaps  832:        return(1);
                    833: }
                    834:
                    835:
                    836: static int
                    837: pre_dl(PRE_ARGS)
                    838: {
                    839:
1.7       schwarze  840:        if (MDOC_BODY == n->type)
                    841:                m->flags |= MDOC_LITERAL;
1.1       kristaps  842:        return(1);
                    843: }
                    844:
                    845:
                    846: static int
1.22      schwarze  847: pre_offset(PRE_ARGS)
                    848: {
                    849:        int              i;
                    850:
                    851:        /*
                    852:         * Make sure that an empty offset produces an 8n length space as
                    853:         * stipulated by mdoc.samples.
                    854:         */
                    855:
                    856:        assert(n->args);
                    857:        for (i = 0; i < (int)n->args->argc; i++) {
                    858:                if (MDOC_Offset != n->args->argv[i].arg)
                    859:                        continue;
                    860:                if (n->args->argv[i].sz)
                    861:                        break;
                    862:                assert(1 == n->args->refcnt);
                    863:                /* If no value set, length of <string>. */
                    864:                n->args->argv[i].value =
                    865:                calloc(1, sizeof(char *));
                    866:                if (NULL == n->args->argv[i].value)
                    867:                        return(mdoc_nerr(m, n, EMALLOC));
                    868:                n->args->argv[i].sz++;
                    869:                n->args->argv[i].value[0] = strdup("8n");
                    870:                if (NULL == n->args->argv[i].value[0])
                    871:                        return(mdoc_nerr(m, n, EMALLOC));
                    872:                break;
                    873:        }
                    874:
                    875:        return(1);
                    876: }
                    877:
                    878:
                    879: static int
                    880: pre_bl(PRE_ARGS)
                    881: {
                    882:
                    883:        return(MDOC_BLOCK == n->type ? pre_offset(m, n) : 1);
                    884: }
                    885:
                    886:
                    887: static int
1.1       kristaps  888: pre_bd(PRE_ARGS)
                    889: {
                    890:        int              i;
                    891:
1.22      schwarze  892:        if (MDOC_BLOCK == n->type)
                    893:                return(pre_offset(m, n));
1.1       kristaps  894:        if (MDOC_BODY != n->type)
                    895:                return(1);
                    896:
1.19      schwarze  897:        /* Enter literal context if `Bd -literal' or `-unfilled'. */
                    898:
1.1       kristaps  899:        for (n = n->parent, i = 0; i < (int)n->args->argc; i++)
                    900:                if (MDOC_Literal == n->args->argv[i].arg)
1.22      schwarze  901:                        m->flags |= MDOC_LITERAL;
1.1       kristaps  902:                else if (MDOC_Unfilled == n->args->argv[i].arg)
1.22      schwarze  903:                        m->flags |= MDOC_LITERAL;
1.1       kristaps  904:
                    905:        return(1);
                    906: }
                    907:
                    908:
                    909: static int
                    910: post_display(POST_ARGS)
                    911: {
                    912:
1.20      schwarze  913:        if (MDOC_BODY == n->type)
1.1       kristaps  914:                m->flags &= ~MDOC_LITERAL;
                    915:        return(1);
                    916: }
                    917:
                    918:
1.23    ! schwarze  919: static inline int
        !           920: order_rs(int t)
        !           921: {
        !           922:        int             i;
        !           923:
        !           924:        for (i = 0; i < RSORD_MAX; i++)
        !           925:                if (rsord[i] == t)
        !           926:                        return(i);
        !           927:
        !           928:        abort();
        !           929:        /* NOTREACHED */
        !           930: }
        !           931:
        !           932:
        !           933: /* ARGSUSED */
        !           934: static int
        !           935: post_rs(POST_ARGS)
        !           936: {
        !           937:        struct mdoc_node        *nn, *next, *prev;
        !           938:        int                      o;
        !           939:
        !           940:        if (MDOC_BLOCK != n->type)
        !           941:                return(1);
        !           942:
        !           943:        assert(n->body->child);
        !           944:        for (next = NULL, nn = n->body->child->next; nn; nn = next) {
        !           945:                o = order_rs(nn->tok);
        !           946:
        !           947:                /* Remove `nn' from the chain. */
        !           948:                next = nn->next;
        !           949:                if (next)
        !           950:                        next->prev = nn->prev;
        !           951:
        !           952:                prev = nn->prev;
        !           953:                if (prev)
        !           954:                        prev->next = nn->next;
        !           955:
        !           956:                nn->prev = nn->next = NULL;
        !           957:
        !           958:                /*
        !           959:                 * Scan back until we reach a node that's ordered before
        !           960:                 * us, then set ourselves as being the next.
        !           961:                 */
        !           962:                for ( ; prev; prev = prev->prev)
        !           963:                        if (order_rs(prev->tok) <= o)
        !           964:                                break;
        !           965:
        !           966:                nn->prev = prev;
        !           967:                if (prev) {
        !           968:                        if (prev->next)
        !           969:                                prev->next->prev = nn;
        !           970:                        nn->next = prev->next;
        !           971:                        prev->next = nn;
        !           972:                        continue;
        !           973:                }
        !           974:
        !           975:                n->body->child->prev = nn;
        !           976:                nn->next = n->body->child;
        !           977:                n->body->child = nn;
        !           978:        }
        !           979:        return(1);
        !           980: }