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

Annotation of mandoc/term.c, Revision 1.43

1.43    ! kristaps    1: /* $Id: term.c,v 1.42 2009/03/05 13:12:12 kristaps Exp $ */
1.1       kristaps    2: /*
1.10      kristaps    3:  * Copyright (c) 2009 Kristaps Dzonsons <kristaps@kth.se>
1.1       kristaps    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.25      kristaps   20: #include <ctype.h>
1.23      kristaps   21: #include <err.h>
1.22      kristaps   22: #include <stdio.h>
1.1       kristaps   23: #include <stdlib.h>
                     24: #include <string.h>
                     25:
1.10      kristaps   26: #include "term.h"
                     27:
                     28: /*
                     29:  * Performs actions on nodes of the abstract syntax tree.  Both pre- and
                     30:  * post-fix operations are defined here.
                     31:  */
                     32:
1.21      kristaps   33: /* FIXME: macro arguments can be escaped. */
1.10      kristaps   34:
                     35: #define        TTYPE_PROG        0
                     36: #define        TTYPE_CMD_FLAG    1
                     37: #define        TTYPE_CMD_ARG     2
                     38: #define        TTYPE_SECTION     3
                     39: #define        TTYPE_FUNC_DECL   4
                     40: #define        TTYPE_VAR_DECL    5
                     41: #define        TTYPE_FUNC_TYPE   6
                     42: #define        TTYPE_FUNC_NAME   7
                     43: #define        TTYPE_FUNC_ARG    8
                     44: #define        TTYPE_LINK        9
                     45: #define        TTYPE_SSECTION    10
                     46: #define        TTYPE_FILE        11
1.11      kristaps   47: #define        TTYPE_EMPH        12
1.14      kristaps   48: #define        TTYPE_CONFIG      13
                     49: #define        TTYPE_CMD         14
                     50: #define        TTYPE_INCLUDE     15
1.17      kristaps   51: #define        TTYPE_SYMB        16
                     52: #define        TTYPE_SYMBOL      17
1.37      kristaps   53: #define        TTYPE_DIAG        18
                     54: #define        TTYPE_NMAX        19
1.10      kristaps   55:
                     56: /*
                     57:  * These define "styles" for element types, like command arguments or
                     58:  * executable names.  This is useful when multiple macros must decorate
                     59:  * the same thing (like .Ex -std cmd and .Nm cmd).
                     60:  */
                     61:
1.36      kristaps   62: /* TODO: abstract this into mdocterm.c. */
                     63:
1.10      kristaps   64: const  int ttypes[TTYPE_NMAX] = {
                     65:        TERMP_BOLD,             /* TTYPE_PROG */
                     66:        TERMP_BOLD,             /* TTYPE_CMD_FLAG */
                     67:        TERMP_UNDERLINE,        /* TTYPE_CMD_ARG */
                     68:        TERMP_BOLD,             /* TTYPE_SECTION */
                     69:        TERMP_BOLD,             /* TTYPE_FUNC_DECL */
                     70:        TERMP_UNDERLINE,        /* TTYPE_VAR_DECL */
                     71:        TERMP_UNDERLINE,        /* TTYPE_FUNC_TYPE */
                     72:        TERMP_BOLD,             /* TTYPE_FUNC_NAME */
                     73:        TERMP_UNDERLINE,        /* TTYPE_FUNC_ARG */
                     74:        TERMP_UNDERLINE,        /* TTYPE_LINK */
                     75:        TERMP_BOLD,             /* TTYPE_SSECTION */
1.11      kristaps   76:        TERMP_UNDERLINE,        /* TTYPE_FILE */
1.14      kristaps   77:        TERMP_UNDERLINE,        /* TTYPE_EMPH */
                     78:        TERMP_BOLD,             /* TTYPE_CONFIG */
                     79:        TERMP_BOLD,             /* TTYPE_CMD */
1.17      kristaps   80:        TERMP_BOLD,             /* TTYPE_INCLUDE */
                     81:        TERMP_BOLD,             /* TTYPE_SYMB */
1.37      kristaps   82:        TERMP_BOLD,             /* TTYPE_SYMBOL */
                     83:        TERMP_BOLD              /* TTYPE_DIAG */
1.10      kristaps   84: };
1.7       kristaps   85:
1.10      kristaps   86: static int               arg_hasattr(int, size_t,
                     87:                                const struct mdoc_arg *);
                     88: static int               arg_getattr(int, size_t,
                     89:                                const struct mdoc_arg *);
1.12      kristaps   90: static size_t            arg_offset(const struct mdoc_arg *);
                     91: static size_t            arg_width(const struct mdoc_arg *);
1.39      kristaps   92: static int               arg_listtype(const struct mdoc_node *);
1.10      kristaps   93:
                     94: /*
                     95:  * What follows describes prefix and postfix operations for the abstract
                     96:  * syntax tree descent.
                     97:  */
1.1       kristaps   98:
1.10      kristaps   99: #define        DECL_ARGS \
                    100:        struct termp *p, \
1.18      kristaps  101:        struct termpair *pair, \
1.10      kristaps  102:        const struct mdoc_meta *meta, \
                    103:        const struct mdoc_node *node
                    104:
                    105: #define        DECL_PRE(name) \
                    106: static int               name##_pre(DECL_ARGS)
                    107: #define        DECL_POST(name) \
                    108: static void              name##_post(DECL_ARGS)
                    109: #define        DECL_PREPOST(name) \
                    110: DECL_PRE(name); \
                    111: DECL_POST(name);
                    112:
1.28      kristaps  113: DECL_PREPOST(termp__t);
1.10      kristaps  114: DECL_PREPOST(termp_aq);
1.12      kristaps  115: DECL_PREPOST(termp_bd);
1.15      kristaps  116: DECL_PREPOST(termp_bq);
1.10      kristaps  117: DECL_PREPOST(termp_d1);
                    118: DECL_PREPOST(termp_dq);
                    119: DECL_PREPOST(termp_fd);
                    120: DECL_PREPOST(termp_fn);
1.16      kristaps  121: DECL_PREPOST(termp_fo);
1.10      kristaps  122: DECL_PREPOST(termp_ft);
1.30      kristaps  123: DECL_PREPOST(termp_in);
1.10      kristaps  124: DECL_PREPOST(termp_it);
                    125: DECL_PREPOST(termp_op);
                    126: DECL_PREPOST(termp_pf);
1.15      kristaps  127: DECL_PREPOST(termp_pq);
1.10      kristaps  128: DECL_PREPOST(termp_qq);
                    129: DECL_PREPOST(termp_sh);
                    130: DECL_PREPOST(termp_ss);
                    131: DECL_PREPOST(termp_sq);
                    132: DECL_PREPOST(termp_vt);
                    133:
1.18      kristaps  134: DECL_PRE(termp_ar);
1.14      kristaps  135: DECL_PRE(termp_at);
1.18      kristaps  136: DECL_PRE(termp_bf);
1.15      kristaps  137: DECL_PRE(termp_bsx);
1.17      kristaps  138: DECL_PRE(termp_bt);
1.18      kristaps  139: DECL_PRE(termp_cd);
                    140: DECL_PRE(termp_cm);
                    141: DECL_PRE(termp_em);
1.10      kristaps  142: DECL_PRE(termp_ex);
1.18      kristaps  143: DECL_PRE(termp_fa);
                    144: DECL_PRE(termp_fl);
1.16      kristaps  145: DECL_PRE(termp_fx);
1.18      kristaps  146: DECL_PRE(termp_ic);
                    147: DECL_PRE(termp_ms);
1.10      kristaps  148: DECL_PRE(termp_nd);
1.18      kristaps  149: DECL_PRE(termp_nm);
1.10      kristaps  150: DECL_PRE(termp_ns);
                    151: DECL_PRE(termp_nx);
                    152: DECL_PRE(termp_ox);
1.18      kristaps  153: DECL_PRE(termp_pa);
1.10      kristaps  154: DECL_PRE(termp_pp);
1.28      kristaps  155: DECL_PRE(termp_rs);
1.14      kristaps  156: DECL_PRE(termp_rv);
1.22      kristaps  157: DECL_PRE(termp_sm);
1.14      kristaps  158: DECL_PRE(termp_st);
1.18      kristaps  159: DECL_PRE(termp_sx);
                    160: DECL_PRE(termp_sy);
1.10      kristaps  161: DECL_PRE(termp_ud);
1.16      kristaps  162: DECL_PRE(termp_ux);
1.18      kristaps  163: DECL_PRE(termp_va);
1.10      kristaps  164: DECL_PRE(termp_xr);
                    165:
1.28      kristaps  166: DECL_POST(termp___);
1.10      kristaps  167: DECL_POST(termp_bl);
1.31      kristaps  168: DECL_POST(termp_bx);
1.43    ! kristaps  169: DECL_POST(termp_lb);
1.10      kristaps  170:
                    171: const  struct termact __termacts[MDOC_MAX] = {
                    172:        { NULL, NULL }, /* \" */
                    173:        { NULL, NULL }, /* Dd */
                    174:        { NULL, NULL }, /* Dt */
                    175:        { NULL, NULL }, /* Os */
                    176:        { termp_sh_pre, termp_sh_post }, /* Sh */
                    177:        { termp_ss_pre, termp_ss_post }, /* Ss */
                    178:        { termp_pp_pre, NULL }, /* Pp */
                    179:        { termp_d1_pre, termp_d1_post }, /* D1 */
1.29      kristaps  180:        { termp_d1_pre, termp_d1_post }, /* Dl */
1.12      kristaps  181:        { termp_bd_pre, termp_bd_post }, /* Bd */
1.10      kristaps  182:        { NULL, NULL }, /* Ed */
                    183:        { NULL, termp_bl_post }, /* Bl */
                    184:        { NULL, NULL }, /* El */
                    185:        { termp_it_pre, termp_it_post }, /* It */
                    186:        { NULL, NULL }, /* Ad */
                    187:        { NULL, NULL }, /* An */
1.18      kristaps  188:        { termp_ar_pre, NULL }, /* Ar */
                    189:        { termp_cd_pre, NULL }, /* Cd */
                    190:        { termp_cm_pre, NULL }, /* Cm */
1.10      kristaps  191:        { NULL, NULL }, /* Dv */
                    192:        { NULL, NULL }, /* Er */
                    193:        { NULL, NULL }, /* Ev */
                    194:        { termp_ex_pre, NULL }, /* Ex */
1.18      kristaps  195:        { termp_fa_pre, NULL }, /* Fa */
1.10      kristaps  196:        { termp_fd_pre, termp_fd_post }, /* Fd */
1.18      kristaps  197:        { termp_fl_pre, NULL }, /* Fl */
1.10      kristaps  198:        { termp_fn_pre, termp_fn_post }, /* Fn */
                    199:        { termp_ft_pre, termp_ft_post }, /* Ft */
1.18      kristaps  200:        { termp_ic_pre, NULL }, /* Ic */
1.30      kristaps  201:        { termp_in_pre, termp_in_post }, /* In */
1.10      kristaps  202:        { NULL, NULL }, /* Li */
                    203:        { termp_nd_pre, NULL }, /* Nd */
1.18      kristaps  204:        { termp_nm_pre, NULL }, /* Nm */
1.10      kristaps  205:        { termp_op_pre, termp_op_post }, /* Op */
                    206:        { NULL, NULL }, /* Ot */
1.18      kristaps  207:        { termp_pa_pre, NULL }, /* Pa */
1.14      kristaps  208:        { termp_rv_pre, NULL }, /* Rv */
                    209:        { termp_st_pre, NULL }, /* St */
1.18      kristaps  210:        { termp_va_pre, NULL }, /* Va */
1.10      kristaps  211:        { termp_vt_pre, termp_vt_post }, /* Vt */
                    212:        { termp_xr_pre, NULL }, /* Xr */
1.28      kristaps  213:        { NULL, termp____post }, /* %A */
1.29      kristaps  214:        { NULL, termp____post }, /* %B */
1.28      kristaps  215:        { NULL, termp____post }, /* %D */
1.29      kristaps  216:        { NULL, termp____post }, /* %I */
1.28      kristaps  217:        { NULL, termp____post }, /* %J */
1.29      kristaps  218:        { NULL, termp____post }, /* %N */
                    219:        { NULL, termp____post }, /* %O */
                    220:        { NULL, termp____post }, /* %P */
                    221:        { NULL, termp____post }, /* %R */
1.28      kristaps  222:        { termp__t_pre, termp__t_post }, /* %T */
1.29      kristaps  223:        { NULL, termp____post }, /* %V */
1.10      kristaps  224:        { NULL, NULL }, /* Ac */
1.14      kristaps  225:        { termp_aq_pre, termp_aq_post }, /* Ao */
1.10      kristaps  226:        { termp_aq_pre, termp_aq_post }, /* Aq */
1.14      kristaps  227:        { termp_at_pre, NULL }, /* At */
1.10      kristaps  228:        { NULL, NULL }, /* Bc */
1.18      kristaps  229:        { termp_bf_pre, NULL }, /* Bf */
1.15      kristaps  230:        { termp_bq_pre, termp_bq_post }, /* Bo */
                    231:        { termp_bq_pre, termp_bq_post }, /* Bq */
                    232:        { termp_bsx_pre, NULL }, /* Bsx */
1.31      kristaps  233:        { NULL, termp_bx_post }, /* Bx */
1.10      kristaps  234:        { NULL, NULL }, /* Db */
                    235:        { NULL, NULL }, /* Dc */
1.15      kristaps  236:        { termp_dq_pre, termp_dq_post }, /* Do */
1.10      kristaps  237:        { termp_dq_pre, termp_dq_post }, /* Dq */
                    238:        { NULL, NULL }, /* Ec */
                    239:        { NULL, NULL }, /* Ef */
1.18      kristaps  240:        { termp_em_pre, NULL }, /* Em */
1.10      kristaps  241:        { NULL, NULL }, /* Eo */
1.16      kristaps  242:        { termp_fx_pre, NULL }, /* Fx */
1.18      kristaps  243:        { termp_ms_pre, NULL }, /* Ms */
1.10      kristaps  244:        { NULL, NULL }, /* No */
                    245:        { termp_ns_pre, NULL }, /* Ns */
                    246:        { termp_nx_pre, NULL }, /* Nx */
                    247:        { termp_ox_pre, NULL }, /* Ox */
                    248:        { NULL, NULL }, /* Pc */
                    249:        { termp_pf_pre, termp_pf_post }, /* Pf */
1.15      kristaps  250:        { termp_pq_pre, termp_pq_post }, /* Po */
                    251:        { termp_pq_pre, termp_pq_post }, /* Pq */
1.10      kristaps  252:        { NULL, NULL }, /* Qc */
1.16      kristaps  253:        { termp_sq_pre, termp_sq_post }, /* Ql */
1.15      kristaps  254:        { termp_qq_pre, termp_qq_post }, /* Qo */
1.10      kristaps  255:        { termp_qq_pre, termp_qq_post }, /* Qq */
                    256:        { NULL, NULL }, /* Re */
1.28      kristaps  257:        { termp_rs_pre, NULL }, /* Rs */
1.10      kristaps  258:        { NULL, NULL }, /* Sc */
1.15      kristaps  259:        { termp_sq_pre, termp_sq_post }, /* So */
1.10      kristaps  260:        { termp_sq_pre, termp_sq_post }, /* Sq */
1.22      kristaps  261:        { termp_sm_pre, NULL }, /* Sm */
1.18      kristaps  262:        { termp_sx_pre, NULL }, /* Sx */
                    263:        { termp_sy_pre, NULL }, /* Sy */
1.10      kristaps  264:        { NULL, NULL }, /* Tn */
1.16      kristaps  265:        { termp_ux_pre, NULL }, /* Ux */
1.10      kristaps  266:        { NULL, NULL }, /* Xc */
                    267:        { NULL, NULL }, /* Xo */
1.16      kristaps  268:        { termp_fo_pre, termp_fo_post }, /* Fo */
1.10      kristaps  269:        { NULL, NULL }, /* Fc */
1.16      kristaps  270:        { termp_op_pre, termp_op_post }, /* Oo */
1.10      kristaps  271:        { NULL, NULL }, /* Oc */
                    272:        { NULL, NULL }, /* Bk */
                    273:        { NULL, NULL }, /* Ek */
1.17      kristaps  274:        { termp_bt_pre, NULL }, /* Bt */
1.10      kristaps  275:        { NULL, NULL }, /* Hf */
                    276:        { NULL, NULL }, /* Fr */
                    277:        { termp_ud_pre, NULL }, /* Ud */
1.43    ! kristaps  278:        { NULL, termp_lb_post }, /* lb */
1.2       kristaps  279: };
                    280:
1.10      kristaps  281: const struct termact *termacts = __termacts;
                    282:
                    283:
                    284: static size_t
1.12      kristaps  285: arg_width(const struct mdoc_arg *arg)
1.10      kristaps  286: {
1.27      kristaps  287:        size_t           v;
                    288:        int              i, len;
1.12      kristaps  289:
                    290:        assert(*arg->value);
1.25      kristaps  291:        if (0 == strcmp(*arg->value, "indent"))
                    292:                return(INDENT);
                    293:        if (0 == strcmp(*arg->value, "indent-two"))
                    294:                return(INDENT * 2);
                    295:
1.27      kristaps  296:        len = (int)strlen(*arg->value);
1.25      kristaps  297:        assert(len > 0);
                    298:
                    299:        for (i = 0; i < len - 1; i++)
1.42      kristaps  300:                if ( ! isdigit((u_char)(*arg->value)[i]))
1.25      kristaps  301:                        break;
                    302:
                    303:        if (i == len - 1) {
                    304:                if ('n' == (*arg->value)[len - 1]) {
                    305:                        v = (size_t)atoi(*arg->value);
                    306:                        return(v);
                    307:                }
                    308:
                    309:        }
1.31      kristaps  310:        return(strlen(*arg->value) + 1);
1.12      kristaps  311: }
                    312:
                    313:
1.39      kristaps  314: static int
                    315: arg_listtype(const struct mdoc_node *n)
                    316: {
                    317:        const struct mdoc_block *bl;
                    318:        int              i, len;
                    319:
                    320:        bl = &n->data.block;
                    321:        len = (int)bl->argc;
                    322:
                    323:        for (i = 0; i < len; i++)
                    324:                switch (bl->argv[i].arg) {
                    325:                case (MDOC_Bullet):
                    326:                        /* FALLTHROUGH */
                    327:                case (MDOC_Dash):
                    328:                        /* FALLTHROUGH */
                    329:                case (MDOC_Enum):
                    330:                        /* FALLTHROUGH */
                    331:                case (MDOC_Hyphen):
                    332:                        /* FALLTHROUGH */
                    333:                case (MDOC_Tag):
                    334:                        /* FALLTHROUGH */
                    335:                case (MDOC_Inset):
                    336:                        /* FALLTHROUGH */
                    337:                case (MDOC_Diag):
                    338:                        /* FALLTHROUGH */
                    339:                case (MDOC_Item):
                    340:                        /* FALLTHROUGH */
                    341:                case (MDOC_Ohang):
                    342:                        return(bl->argv[i].arg);
                    343:                default:
                    344:                        break;
                    345:                }
                    346:
                    347:        errx(1, "list type not supported");
                    348:        /* NOTREACHED */
                    349: }
                    350:
                    351:
1.12      kristaps  352: static size_t
                    353: arg_offset(const struct mdoc_arg *arg)
                    354: {
                    355:
                    356:        /* TODO */
                    357:        assert(*arg->value);
                    358:        if (0 == strcmp(*arg->value, "indent"))
1.10      kristaps  359:                return(INDENT);
1.12      kristaps  360:        if (0 == strcmp(*arg->value, "indent-two"))
1.10      kristaps  361:                return(INDENT * 2);
1.12      kristaps  362:        return(strlen(*arg->value));
1.10      kristaps  363: }
                    364:
1.3       kristaps  365:
1.10      kristaps  366: static int
                    367: arg_hasattr(int arg, size_t argc, const struct mdoc_arg *argv)
1.2       kristaps  368: {
                    369:
1.10      kristaps  370:        return(-1 != arg_getattr(arg, argc, argv));
                    371: }
                    372:
                    373:
                    374: static int
                    375: arg_getattr(int arg, size_t argc, const struct mdoc_arg *argv)
                    376: {
                    377:        int              i;
                    378:
                    379:        for (i = 0; i < (int)argc; i++)
                    380:                if (argv[i].arg == arg)
                    381:                        return(i);
                    382:        return(-1);
                    383: }
                    384:
                    385:
                    386: /* ARGSUSED */
                    387: static int
                    388: termp_dq_pre(DECL_ARGS)
                    389: {
                    390:
                    391:        if (MDOC_BODY != node->type)
                    392:                return(1);
                    393:
                    394:        word(p, "``");
                    395:        p->flags |= TERMP_NOSPACE;
                    396:        return(1);
                    397: }
                    398:
                    399:
                    400: /* ARGSUSED */
                    401: static void
                    402: termp_dq_post(DECL_ARGS)
                    403: {
                    404:
                    405:        if (MDOC_BODY != node->type)
                    406:                return;
1.3       kristaps  407:
1.10      kristaps  408:        p->flags |= TERMP_NOSPACE;
                    409:        word(p, "''");
                    410: }
1.2       kristaps  411:
1.3       kristaps  412:
1.10      kristaps  413: /* ARGSUSED */
1.20      kristaps  414: static int
1.39      kristaps  415: termp_it_pre_block(DECL_ARGS)
                    416: {
                    417:        const struct mdoc_node  *n;
                    418:        const struct mdoc_block *bl;
                    419:
                    420:        n = node->parent->parent;
                    421:        bl = &n->data.block;
                    422:
                    423:        newln(p);
                    424:        if ( ! arg_hasattr(MDOC_Compact, bl->argc, bl->argv))
                    425:                if (node->prev || n->prev)
                    426:                        vspace(p);
                    427:
                    428:        return(1);
                    429: }
                    430:
                    431:
                    432: /* ARGSUSED */
                    433: static int
1.20      kristaps  434: termp_it_pre(DECL_ARGS)
1.10      kristaps  435: {
                    436:        const struct mdoc_block *bl;
1.39      kristaps  437:        char             buf[7];
1.23      kristaps  438:        int              i, type;
1.12      kristaps  439:        size_t           width, offset;
1.2       kristaps  440:
1.39      kristaps  441:        if (MDOC_BLOCK == node->type)
                    442:                return(termp_it_pre_block(p, pair, meta, node));
1.8       kristaps  443:
1.39      kristaps  444:        /* Get ptr to list block, type, etc. */
1.10      kristaps  445:
1.39      kristaps  446:        bl = &node->parent->parent->parent->data.block;
                    447:        type = arg_listtype(node->parent->parent->parent);
1.23      kristaps  448:
1.39      kristaps  449:        /* Save parent attributes. */
1.23      kristaps  450:
1.20      kristaps  451:        pair->offset = p->offset;
                    452:        pair->rmargin = p->rmargin;
1.39      kristaps  453:        pair->flag = p->flags;
1.20      kristaps  454:
1.23      kristaps  455:        /* Get list width and offset. */
                    456:
1.20      kristaps  457:        i = arg_getattr(MDOC_Width, bl->argc, bl->argv);
1.23      kristaps  458:        width = i >= 0 ? arg_width(&bl->argv[i]) : 0;
1.20      kristaps  459:
                    460:        i = arg_getattr(MDOC_Offset, bl->argc, bl->argv);
                    461:        offset = i >= 0 ? arg_offset(&bl->argv[i]) : 0;
                    462:
1.39      kristaps  463:        /*
                    464:         * List-type can override the width in the case of fixed-head
                    465:         * values (bullet, dash/hyphen, enum).  Tags need a non-zero
                    466:         * offset.
                    467:         */
1.10      kristaps  468:
1.23      kristaps  469:        switch (type) {
                    470:        case (MDOC_Bullet):
                    471:                /* FALLTHROUGH */
                    472:        case (MDOC_Dash):
                    473:                /* FALLTHROUGH */
                    474:        case (MDOC_Enum):
                    475:                /* FALLTHROUGH */
                    476:        case (MDOC_Hyphen):
1.38      kristaps  477:                width = width > 4 ? width : 4;
1.23      kristaps  478:                break;
                    479:        case (MDOC_Tag):
1.39      kristaps  480:                if (width)
                    481:                        break;
                    482:                errx(1, "need non-zero %s for list type",
                    483:                                mdoc_argnames[MDOC_Width]);
1.23      kristaps  484:        default:
                    485:                break;
                    486:        }
1.10      kristaps  487:
1.39      kristaps  488:        /*
                    489:         * Whitespace control.  Inset bodies need an initial space.
                    490:         */
1.21      kristaps  491:
1.23      kristaps  492:        switch (type) {
1.37      kristaps  493:        case (MDOC_Diag):
                    494:                /* FALLTHROUGH */
                    495:        case (MDOC_Inset):
1.39      kristaps  496:                if (MDOC_BODY == node->type)
                    497:                        p->flags &= ~TERMP_NOSPACE;
                    498:                else
                    499:                        p->flags |= TERMP_NOSPACE;
                    500:                break;
                    501:        default:
                    502:                p->flags |= TERMP_NOSPACE;
                    503:                break;
                    504:        }
                    505:
                    506:        /*
                    507:         * Style flags.  Diagnostic heads need TTYPE_DIAG.
                    508:         */
                    509:
                    510:        switch (type) {
                    511:        case (MDOC_Diag):
1.37      kristaps  512:                if (MDOC_HEAD == node->type)
1.39      kristaps  513:                        p->flags |= ttypes[TTYPE_DIAG];
                    514:                break;
                    515:        default:
1.37      kristaps  516:                break;
1.39      kristaps  517:        }
                    518:
                    519:        /*
                    520:         * Pad and break control.  This is the tricker part.  Lists with
                    521:         * set right-margins for the head get TERMP_NOBREAK because, if
                    522:         * they overrun the margin, they wrap to the new margin.
                    523:         * Correspondingly, the body for these types don't left-pad, as
                    524:         * the head will pad out to to the right.
                    525:         */
                    526:
                    527:        switch (type) {
1.23      kristaps  528:        case (MDOC_Bullet):
                    529:                /* FALLTHROUGH */
                    530:        case (MDOC_Dash):
                    531:                /* FALLTHROUGH */
                    532:        case (MDOC_Enum):
                    533:                /* FALLTHROUGH */
                    534:        case (MDOC_Hyphen):
                    535:                /* FALLTHROUGH */
                    536:        case (MDOC_Tag):
                    537:                if (MDOC_HEAD == node->type)
                    538:                        p->flags |= TERMP_NOBREAK;
1.39      kristaps  539:                else
1.23      kristaps  540:                        p->flags |= TERMP_NOLPAD;
1.41      kristaps  541:                if (MDOC_HEAD == node->type && MDOC_Tag == type)
                    542:                        if (NULL == node->next ||
                    543:                                        NULL == node->next->child)
                    544:                                p->flags |= TERMP_NONOBREAK;
1.23      kristaps  545:                break;
1.39      kristaps  546:        case (MDOC_Diag):
                    547:                if (MDOC_HEAD == node->type)
                    548:                        p->flags |= TERMP_NOBREAK;
                    549:                break;
1.24      kristaps  550:        default:
1.23      kristaps  551:                break;
                    552:        }
1.21      kristaps  553:
1.23      kristaps  554:        /*
1.39      kristaps  555:         * Margin control.  Set-head-width lists have their right
                    556:         * margins shortened.  The body for these lists has the offset
                    557:         * necessarily lengthened.  Everybody gets the offset.
1.23      kristaps  558:         */
1.21      kristaps  559:
                    560:        p->offset += offset;
1.23      kristaps  561:
                    562:        switch (type) {
                    563:        case (MDOC_Bullet):
                    564:                /* FALLTHROUGH */
                    565:        case (MDOC_Dash):
                    566:                /* FALLTHROUGH */
                    567:        case (MDOC_Enum):
                    568:                /* FALLTHROUGH */
                    569:        case (MDOC_Hyphen):
                    570:                /* FALLTHROUGH */
                    571:        case (MDOC_Tag):
                    572:                if (MDOC_HEAD == node->type)
                    573:                        p->rmargin = p->offset + width;
1.39      kristaps  574:                else
1.23      kristaps  575:                        p->offset += width;
1.39      kristaps  576:                /* FALLTHROUGH */
1.24      kristaps  577:        default:
1.23      kristaps  578:                break;
                    579:        }
                    580:
1.39      kristaps  581:        /*
                    582:         * The dash, hyphen, bullet and enum lists all have a special
                    583:         * HEAD character.  Print it now.
                    584:         */
                    585:
                    586:        if (MDOC_HEAD == node->type)
                    587:                switch (type) {
                    588:                case (MDOC_Bullet):
                    589:                        word(p, "\\[bu]");
                    590:                        break;
                    591:                case (MDOC_Dash):
                    592:                        /* FALLTHROUGH */
                    593:                case (MDOC_Hyphen):
                    594:                        word(p, "\\-");
                    595:                        break;
                    596:                case (MDOC_Enum):
                    597:                        /* TODO: have a wordfmt or something. */
                    598:                        (pair->ppair->ppair->count)++;
                    599:                        (void)snprintf(buf, sizeof(buf), "%d.",
                    600:                                        pair->ppair->ppair->count);
                    601:                        word(p, buf);
                    602:                        break;
                    603:                default:
                    604:                        break;
                    605:                }
                    606:
                    607:        /*
                    608:         * If we're not going to process our header children, indicate
                    609:         * so here.
                    610:         */
                    611:
                    612:        if (MDOC_HEAD == node->type)
                    613:                switch (type) {
                    614:                case (MDOC_Bullet):
                    615:                        /* FALLTHROUGH */
                    616:                case (MDOC_Item):
                    617:                        /* FALLTHROUGH */
                    618:                case (MDOC_Dash):
                    619:                        /* FALLTHROUGH */
                    620:                case (MDOC_Hyphen):
                    621:                        /* FALLTHROUGH */
                    622:                case (MDOC_Enum):
                    623:                        return(0);
                    624:                default:
                    625:                        break;
                    626:        }
1.23      kristaps  627:
1.39      kristaps  628:        return(1);
1.10      kristaps  629: }
                    630:
                    631:
                    632: /* ARGSUSED */
1.20      kristaps  633: static void
                    634: termp_it_post(DECL_ARGS)
1.10      kristaps  635: {
1.39      kristaps  636:        int                type;
1.3       kristaps  637:
1.21      kristaps  638:        if (MDOC_BODY != node->type && MDOC_HEAD != node->type)
1.20      kristaps  639:                return;
1.10      kristaps  640:
1.39      kristaps  641:        type = arg_listtype(node->parent->parent->parent);
1.37      kristaps  642:
                    643:        switch (type) {
                    644:        case (MDOC_Diag):
                    645:                /* FALLTHROUGH */
1.39      kristaps  646:        case (MDOC_Item):
                    647:                /* FALLTHROUGH */
1.37      kristaps  648:        case (MDOC_Inset):
1.39      kristaps  649:                if (MDOC_BODY != node->type)
                    650:                        break;
                    651:                flushln(p);
1.37      kristaps  652:                break;
                    653:        default:
                    654:                flushln(p);
                    655:                break;
                    656:        }
1.10      kristaps  657:
1.23      kristaps  658:        p->offset = pair->offset;
                    659:        p->rmargin = pair->rmargin;
1.39      kristaps  660:        p->flags = pair->flag;
1.2       kristaps  661: }
                    662:
                    663:
1.10      kristaps  664: /* ARGSUSED */
1.18      kristaps  665: static int
                    666: termp_nm_pre(DECL_ARGS)
1.10      kristaps  667: {
                    668:
1.29      kristaps  669:        if (SEC_SYNOPSIS == node->sec)
                    670:                newln(p);
                    671:
1.31      kristaps  672:        TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_PROG]);
1.18      kristaps  673:        if (NULL == node->child)
                    674:                word(p, meta->name);
1.31      kristaps  675:
1.18      kristaps  676:        return(1);
1.10      kristaps  677: }
                    678:
                    679:
                    680: /* ARGSUSED */
1.18      kristaps  681: static int
                    682: termp_fl_pre(DECL_ARGS)
1.10      kristaps  683: {
                    684:
1.31      kristaps  685:        TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_CMD_FLAG]);
1.18      kristaps  686:        word(p, "\\-");
                    687:        p->flags |= TERMP_NOSPACE;
                    688:        return(1);
1.10      kristaps  689: }
                    690:
                    691:
                    692: /* ARGSUSED */
                    693: static int
                    694: termp_ar_pre(DECL_ARGS)
                    695: {
                    696:
1.31      kristaps  697:        TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_CMD_ARG]);
1.10      kristaps  698:        return(1);
                    699: }
                    700:
                    701:
                    702: /* ARGSUSED */
                    703: static int
                    704: termp_ns_pre(DECL_ARGS)
1.2       kristaps  705: {
                    706:
                    707:        p->flags |= TERMP_NOSPACE;
1.10      kristaps  708:        return(1);
                    709: }
                    710:
                    711:
                    712: /* ARGSUSED */
                    713: static int
                    714: termp_pp_pre(DECL_ARGS)
                    715: {
                    716:
                    717:        vspace(p);
                    718:        return(1);
                    719: }
                    720:
                    721:
                    722: /* ARGSUSED */
                    723: static int
1.14      kristaps  724: termp_st_pre(DECL_ARGS)
                    725: {
1.43    ! kristaps  726:        const char      *cp;
1.14      kristaps  727:
1.43    ! kristaps  728:        /* XXX - if child isn't text? */
        !           729:        if (node->child)
        !           730:                if ((cp = mdoc_a2st(node->child->data.text.string)))
        !           731:                        word(p, cp);
        !           732:        return(0);
1.14      kristaps  733: }
                    734:
                    735:
                    736: /* ARGSUSED */
                    737: static int
1.28      kristaps  738: termp_rs_pre(DECL_ARGS)
                    739: {
                    740:
1.30      kristaps  741:        if (MDOC_BLOCK == node->type && node->prev)
1.28      kristaps  742:                vspace(p);
                    743:        return(1);
                    744: }
                    745:
                    746:
                    747: /* ARGSUSED */
                    748: static int
1.14      kristaps  749: termp_rv_pre(DECL_ARGS)
                    750: {
                    751:        int              i;
                    752:
                    753:        i = arg_getattr(MDOC_Std, node->data.elem.argc,
                    754:                        node->data.elem.argv);
                    755:        assert(i >= 0);
                    756:
                    757:        newln(p);
                    758:        word(p, "The");
                    759:
                    760:        p->flags |= ttypes[TTYPE_FUNC_NAME];
                    761:        word(p, *node->data.elem.argv[i].value);
                    762:        p->flags &= ~ttypes[TTYPE_FUNC_NAME];
                    763:
                    764:                word(p, "() function returns the value 0 if successful;");
                    765:                word(p, "otherwise the value -1 is returned and the");
                    766:                word(p, "global variable");
                    767:
                    768:        p->flags |= ttypes[TTYPE_VAR_DECL];
                    769:        word(p, "errno");
                    770:        p->flags &= ~ttypes[TTYPE_VAR_DECL];
                    771:
                    772:                word(p, "is set to indicate the error.");
                    773:
                    774:        return(1);
                    775: }
                    776:
                    777:
                    778: /* ARGSUSED */
                    779: static int
1.10      kristaps  780: termp_ex_pre(DECL_ARGS)
                    781: {
                    782:        int              i;
                    783:
                    784:        i = arg_getattr(MDOC_Std, node->data.elem.argc,
                    785:                        node->data.elem.argv);
                    786:        assert(i >= 0);
                    787:
                    788:        word(p, "The");
                    789:        p->flags |= ttypes[TTYPE_PROG];
                    790:        word(p, *node->data.elem.argv[i].value);
                    791:        p->flags &= ~ttypes[TTYPE_PROG];
                    792:                word(p, "utility exits 0 on success, and >0 if an error occurs.");
                    793:
                    794:        return(1);
                    795: }
                    796:
                    797:
                    798: /* ARGSUSED */
                    799: static int
                    800: termp_nd_pre(DECL_ARGS)
                    801: {
                    802:
                    803:        word(p, "\\-");
                    804:        return(1);
                    805: }
                    806:
                    807:
                    808: /* ARGSUSED */
                    809: static void
                    810: termp_bl_post(DECL_ARGS)
                    811: {
                    812:
                    813:        if (MDOC_BLOCK == node->type)
                    814:                newln(p);
                    815: }
                    816:
                    817:
                    818: /* ARGSUSED */
                    819: static void
                    820: termp_op_post(DECL_ARGS)
                    821: {
                    822:
                    823:        if (MDOC_BODY != node->type)
1.2       kristaps  824:                return;
1.10      kristaps  825:        p->flags |= TERMP_NOSPACE;
                    826:        word(p, "\\(rB");
                    827: }
                    828:
                    829:
                    830: /* ARGSUSED */
                    831: static int
                    832: termp_xr_pre(DECL_ARGS)
                    833: {
                    834:        const struct mdoc_node *n;
                    835:
                    836:        n = node->child;
                    837:        assert(n);
                    838:
                    839:        assert(MDOC_TEXT == n->type);
                    840:        word(p, n->data.text.string);
                    841:
                    842:        if (NULL == (n = n->next))
                    843:                return(0);
                    844:
                    845:        assert(MDOC_TEXT == n->type);
                    846:        p->flags |= TERMP_NOSPACE;
                    847:        word(p, "(");
                    848:        p->flags |= TERMP_NOSPACE;
                    849:        word(p, n->data.text.string);
                    850:        p->flags |= TERMP_NOSPACE;
                    851:        word(p, ")");
                    852:
                    853:        return(0);
1.2       kristaps  854: }
                    855:
                    856:
1.10      kristaps  857: /* ARGSUSED */
                    858: static int
                    859: termp_vt_pre(DECL_ARGS)
1.2       kristaps  860: {
                    861:
1.10      kristaps  862:        /* FIXME: this can be "type name". */
1.31      kristaps  863:        TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_VAR_DECL]);
1.10      kristaps  864:        return(1);
1.2       kristaps  865: }
                    866:
                    867:
1.10      kristaps  868: /* ARGSUSED */
1.2       kristaps  869: static void
1.10      kristaps  870: termp_vt_post(DECL_ARGS)
                    871: {
                    872:
                    873:        if (node->sec == SEC_SYNOPSIS)
                    874:                vspace(p);
                    875: }
                    876:
                    877:
                    878: /* ARGSUSED */
                    879: static int
                    880: termp_fd_pre(DECL_ARGS)
1.2       kristaps  881: {
                    882:
1.10      kristaps  883:        /*
                    884:         * FIXME: this naming is bad.  This value is used, in general,
                    885:         * for the #include header or other preprocessor statement.
                    886:         */
1.31      kristaps  887:        TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_FUNC_DECL]);
1.10      kristaps  888:        return(1);
1.2       kristaps  889: }
                    890:
                    891:
1.10      kristaps  892: /* ARGSUSED */
1.2       kristaps  893: static void
1.10      kristaps  894: termp_fd_post(DECL_ARGS)
1.2       kristaps  895: {
                    896:
1.30      kristaps  897:        if (node->sec != SEC_SYNOPSIS)
                    898:                return;
                    899:        newln(p);
                    900:        if (node->next && MDOC_Fd != node->next->tok)
1.10      kristaps  901:                vspace(p);
                    902: }
                    903:
                    904:
                    905: /* ARGSUSED */
                    906: static int
                    907: termp_sh_pre(DECL_ARGS)
                    908: {
1.2       kristaps  909:
1.10      kristaps  910:        switch (node->type) {
                    911:        case (MDOC_HEAD):
                    912:                vspace(p);
1.31      kristaps  913:                TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_SECTION]);
1.2       kristaps  914:                break;
1.10      kristaps  915:        case (MDOC_BODY):
                    916:                p->offset = INDENT;
1.2       kristaps  917:                break;
1.10      kristaps  918:        default:
                    919:                break;
                    920:        }
                    921:        return(1);
                    922: }
                    923:
                    924:
                    925: /* ARGSUSED */
1.19      kristaps  926: static void
                    927: termp_sh_post(DECL_ARGS)
                    928: {
                    929:
                    930:        switch (node->type) {
                    931:        case (MDOC_HEAD):
                    932:                newln(p);
                    933:                break;
                    934:        case (MDOC_BODY):
                    935:                newln(p);
                    936:                p->offset = 0;
                    937:                break;
                    938:        default:
                    939:                break;
                    940:        }
                    941: }
                    942:
                    943:
                    944: /* ARGSUSED */
1.10      kristaps  945: static int
                    946: termp_op_pre(DECL_ARGS)
                    947: {
                    948:
                    949:        switch (node->type) {
                    950:        case (MDOC_BODY):
                    951:                word(p, "\\(lB");
                    952:                p->flags |= TERMP_NOSPACE;
1.2       kristaps  953:                break;
                    954:        default:
1.10      kristaps  955:                break;
1.2       kristaps  956:        }
1.10      kristaps  957:        return(1);
                    958: }
                    959:
                    960:
                    961: /* ARGSUSED */
                    962: static int
1.17      kristaps  963: termp_bt_pre(DECL_ARGS)
                    964: {
                    965:
                    966:        word(p, "is currently in beta test.");
                    967:        return(1);
                    968: }
                    969:
                    970:
                    971: /* ARGSUSED */
1.43    ! kristaps  972: static void
        !           973: termp_lb_post(DECL_ARGS)
        !           974: {
        !           975:
        !           976:        newln(p);
        !           977: }
        !           978:
        !           979:
        !           980: /* ARGSUSED */
1.17      kristaps  981: static int
1.10      kristaps  982: termp_ud_pre(DECL_ARGS)
                    983: {
                    984:
                    985:        word(p, "currently under development.");
                    986:        return(1);
                    987: }
                    988:
                    989:
                    990: /* ARGSUSED */
                    991: static int
                    992: termp_d1_pre(DECL_ARGS)
                    993: {
                    994:
                    995:        if (MDOC_BODY != node->type)
                    996:                return(1);
                    997:        newln(p);
1.19      kristaps  998:        p->offset += (pair->offset = INDENT);
1.10      kristaps  999:        return(1);
1.2       kristaps 1000: }
                   1001:
                   1002:
1.10      kristaps 1003: /* ARGSUSED */
1.2       kristaps 1004: static void
1.10      kristaps 1005: termp_d1_post(DECL_ARGS)
                   1006: {
                   1007:
                   1008:        if (MDOC_BODY != node->type)
                   1009:                return;
                   1010:        newln(p);
1.19      kristaps 1011:        p->offset -= pair->offset;
1.10      kristaps 1012: }
                   1013:
                   1014:
                   1015: /* ARGSUSED */
                   1016: static int
                   1017: termp_aq_pre(DECL_ARGS)
1.6       kristaps 1018: {
                   1019:
1.10      kristaps 1020:        if (MDOC_BODY != node->type)
                   1021:                return(1);
1.40      kristaps 1022:        word(p, "\\(la");
1.10      kristaps 1023:        p->flags |= TERMP_NOSPACE;
                   1024:        return(1);
                   1025: }
1.6       kristaps 1026:
                   1027:
1.10      kristaps 1028: /* ARGSUSED */
                   1029: static void
                   1030: termp_aq_post(DECL_ARGS)
                   1031: {
1.6       kristaps 1032:
1.10      kristaps 1033:        if (MDOC_BODY != node->type)
1.6       kristaps 1034:                return;
1.10      kristaps 1035:        p->flags |= TERMP_NOSPACE;
1.40      kristaps 1036:        word(p, "\\(ra");
1.10      kristaps 1037: }
1.6       kristaps 1038:
1.10      kristaps 1039:
                   1040: /* ARGSUSED */
                   1041: static int
                   1042: termp_ft_pre(DECL_ARGS)
                   1043: {
                   1044:
1.34      kristaps 1045:        if (SEC_SYNOPSIS == node->sec)
                   1046:                if (node->prev && MDOC_Fo == node->prev->tok)
                   1047:                        vspace(p);
1.31      kristaps 1048:        TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_FUNC_TYPE]);
1.10      kristaps 1049:        return(1);
1.6       kristaps 1050: }
                   1051:
                   1052:
1.10      kristaps 1053: /* ARGSUSED */
1.6       kristaps 1054: static void
1.10      kristaps 1055: termp_ft_post(DECL_ARGS)
1.2       kristaps 1056: {
                   1057:
1.34      kristaps 1058:        if (SEC_SYNOPSIS == node->sec)
1.10      kristaps 1059:                newln(p);
                   1060: }
1.2       kristaps 1061:
                   1062:
1.10      kristaps 1063: /* ARGSUSED */
                   1064: static int
                   1065: termp_fn_pre(DECL_ARGS)
                   1066: {
                   1067:        const struct mdoc_node *n;
                   1068:
                   1069:        assert(node->child);
                   1070:        assert(MDOC_TEXT == node->child->type);
1.2       kristaps 1071:
1.10      kristaps 1072:        /* FIXME: can be "type funcname" "type varname"... */
1.2       kristaps 1073:
1.10      kristaps 1074:        p->flags |= ttypes[TTYPE_FUNC_NAME];
                   1075:        word(p, node->child->data.text.string);
                   1076:        p->flags &= ~ttypes[TTYPE_FUNC_NAME];
                   1077:
                   1078:        word(p, "(");
                   1079:
                   1080:        p->flags |= TERMP_NOSPACE;
                   1081:        for (n = node->child->next; n; n = n->next) {
                   1082:                assert(MDOC_TEXT == n->type);
                   1083:                p->flags |= ttypes[TTYPE_FUNC_ARG];
                   1084:                word(p, n->data.text.string);
                   1085:                p->flags &= ~ttypes[TTYPE_FUNC_ARG];
1.16      kristaps 1086:                if (n->next)
1.10      kristaps 1087:                        word(p, ",");
1.6       kristaps 1088:        }
1.2       kristaps 1089:
1.10      kristaps 1090:        word(p, ")");
                   1091:
                   1092:        if (SEC_SYNOPSIS == node->sec)
                   1093:                word(p, ";");
                   1094:
                   1095:        return(0);
1.2       kristaps 1096: }
                   1097:
                   1098:
1.10      kristaps 1099: /* ARGSUSED */
                   1100: static void
                   1101: termp_fn_post(DECL_ARGS)
1.2       kristaps 1102: {
                   1103:
1.30      kristaps 1104:        if (node->sec == SEC_SYNOPSIS && node->next)
1.10      kristaps 1105:                vspace(p);
                   1106:
                   1107: }
1.2       kristaps 1108:
                   1109:
1.10      kristaps 1110: /* ARGSUSED */
                   1111: static int
                   1112: termp_sx_pre(DECL_ARGS)
                   1113: {
1.8       kristaps 1114:
1.31      kristaps 1115:        TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_LINK]);
1.10      kristaps 1116:        return(1);
1.2       kristaps 1117: }
                   1118:
                   1119:
1.10      kristaps 1120: /* ARGSUSED */
                   1121: static int
                   1122: termp_fa_pre(DECL_ARGS)
                   1123: {
1.16      kristaps 1124:        struct mdoc_node *n;
                   1125:
                   1126:        if (node->parent->tok != MDOC_Fo) {
1.31      kristaps 1127:                TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_FUNC_ARG]);
1.16      kristaps 1128:                return(1);
                   1129:        }
                   1130:
                   1131:        for (n = node->child; n; n = n->next) {
                   1132:                assert(MDOC_TEXT == n->type);
                   1133:
                   1134:                p->flags |= ttypes[TTYPE_FUNC_ARG];
                   1135:                word(p, n->data.text.string);
                   1136:                p->flags &= ~ttypes[TTYPE_FUNC_ARG];
                   1137:
                   1138:                if (n->next)
                   1139:                        word(p, ",");
                   1140:        }
                   1141:
                   1142:        if (node->next && node->next->tok == MDOC_Fa)
                   1143:                word(p, ",");
1.2       kristaps 1144:
1.16      kristaps 1145:        return(0);
1.10      kristaps 1146: }
1.2       kristaps 1147:
                   1148:
1.10      kristaps 1149: /* ARGSUSED */
                   1150: static int
                   1151: termp_va_pre(DECL_ARGS)
                   1152: {
1.2       kristaps 1153:
1.31      kristaps 1154:        TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_VAR_DECL]);
1.10      kristaps 1155:        return(1);
1.2       kristaps 1156: }
                   1157:
                   1158:
1.10      kristaps 1159: /* ARGSUSED */
                   1160: static int
                   1161: termp_bd_pre(DECL_ARGS)
                   1162: {
                   1163:        const struct mdoc_block *bl;
1.35      kristaps 1164:        const struct mdoc_node  *n;
                   1165:        int              i, type;
1.1       kristaps 1166:
1.10      kristaps 1167:        if (MDOC_BLOCK == node->type) {
1.30      kristaps 1168:                if (node->prev)
                   1169:                        vspace(p);
1.10      kristaps 1170:                return(1);
                   1171:        } else if (MDOC_BODY != node->type)
                   1172:                return(1);
                   1173:
1.20      kristaps 1174:        pair->offset = p->offset;
1.35      kristaps 1175:        bl = &node->parent->data.block;
1.10      kristaps 1176:
1.35      kristaps 1177:        for (type = -1, i = 0; i < (int)bl->argc; i++) {
                   1178:                switch (bl->argv[i].arg) {
                   1179:                case (MDOC_Ragged):
                   1180:                        /* FALLTHROUGH */
                   1181:                case (MDOC_Filled):
                   1182:                        /* FALLTHROUGH */
                   1183:                case (MDOC_Unfilled):
                   1184:                        /* FALLTHROUGH */
                   1185:                case (MDOC_Literal):
                   1186:                        type = bl->argv[i].arg;
                   1187:                        i = (int)bl->argc;
                   1188:                        break;
                   1189:                default:
                   1190:                        errx(1, "display type not supported");
                   1191:                }
                   1192:        }
                   1193:
                   1194:        assert(-1 != type);
1.12      kristaps 1195:
                   1196:        i = arg_getattr(MDOC_Offset, bl->argc, bl->argv);
                   1197:        if (-1 != i) {
                   1198:                assert(1 == bl->argv[i].sz);
1.20      kristaps 1199:                p->offset += arg_offset(&bl->argv[i]);
1.12      kristaps 1200:        }
                   1201:
1.35      kristaps 1202:
                   1203:        switch (type) {
                   1204:        case (MDOC_Literal):
                   1205:                /* FALLTHROUGH */
                   1206:        case (MDOC_Unfilled):
                   1207:                break;
                   1208:        default:
                   1209:                return(1);
                   1210:        }
                   1211:
1.10      kristaps 1212:        p->flags |= TERMP_LITERAL;
                   1213:
                   1214:        for (n = node->child; n; n = n->next) {
1.35      kristaps 1215:                if (MDOC_TEXT != n->type) {
                   1216:                        warnx("non-text children not yet allowed");
                   1217:                        continue;
                   1218:                }
                   1219:                word(p, n->data.text.string);
                   1220:                flushln(p);
1.10      kristaps 1221:        }
1.1       kristaps 1222:
1.10      kristaps 1223:        return(0);
                   1224: }
1.1       kristaps 1225:
                   1226:
1.10      kristaps 1227: /* ARGSUSED */
1.12      kristaps 1228: static void
                   1229: termp_bd_post(DECL_ARGS)
                   1230: {
                   1231:
1.20      kristaps 1232:        if (MDOC_BODY != node->type)
                   1233:                return;
1.35      kristaps 1234:
                   1235:        if ( ! (p->flags & TERMP_LITERAL))
                   1236:                flushln(p);
                   1237:
                   1238:        p->flags &= ~TERMP_LITERAL;
1.20      kristaps 1239:        p->offset = pair->offset;
1.12      kristaps 1240: }
                   1241:
                   1242:
                   1243: /* ARGSUSED */
1.10      kristaps 1244: static int
                   1245: termp_qq_pre(DECL_ARGS)
                   1246: {
1.1       kristaps 1247:
1.10      kristaps 1248:        if (MDOC_BODY != node->type)
                   1249:                return(1);
                   1250:        word(p, "\"");
                   1251:        p->flags |= TERMP_NOSPACE;
                   1252:        return(1);
1.1       kristaps 1253: }
                   1254:
                   1255:
1.10      kristaps 1256: /* ARGSUSED */
1.1       kristaps 1257: static void
1.10      kristaps 1258: termp_qq_post(DECL_ARGS)
1.1       kristaps 1259: {
                   1260:
1.10      kristaps 1261:        if (MDOC_BODY != node->type)
                   1262:                return;
                   1263:        p->flags |= TERMP_NOSPACE;
                   1264:        word(p, "\"");
                   1265: }
                   1266:
                   1267:
                   1268: /* ARGSUSED */
                   1269: static int
1.15      kristaps 1270: termp_bsx_pre(DECL_ARGS)
                   1271: {
                   1272:
                   1273:        word(p, "BSDI BSD/OS");
                   1274:        return(1);
                   1275: }
                   1276:
                   1277:
                   1278: /* ARGSUSED */
1.31      kristaps 1279: static void
                   1280: termp_bx_post(DECL_ARGS)
1.10      kristaps 1281: {
1.1       kristaps 1282:
1.34      kristaps 1283:        if (node->child)
                   1284:                p->flags |= TERMP_NOSPACE;
1.10      kristaps 1285:        word(p, "BSD");
                   1286: }
                   1287:
                   1288:
                   1289: /* ARGSUSED */
                   1290: static int
                   1291: termp_ox_pre(DECL_ARGS)
                   1292: {
                   1293:
                   1294:        word(p, "OpenBSD");
                   1295:        return(1);
                   1296: }
                   1297:
                   1298:
                   1299: /* ARGSUSED */
                   1300: static int
1.16      kristaps 1301: termp_ux_pre(DECL_ARGS)
                   1302: {
                   1303:
                   1304:        word(p, "UNIX");
                   1305:        return(1);
                   1306: }
                   1307:
                   1308:
                   1309: /* ARGSUSED */
                   1310: static int
                   1311: termp_fx_pre(DECL_ARGS)
                   1312: {
                   1313:
                   1314:        word(p, "FreeBSD");
                   1315:        return(1);
                   1316: }
                   1317:
                   1318:
                   1319: /* ARGSUSED */
                   1320: static int
1.10      kristaps 1321: termp_nx_pre(DECL_ARGS)
                   1322: {
                   1323:
                   1324:        word(p, "NetBSD");
                   1325:        return(1);
                   1326: }
                   1327:
                   1328:
                   1329: /* ARGSUSED */
                   1330: static int
                   1331: termp_sq_pre(DECL_ARGS)
                   1332: {
                   1333:
                   1334:        if (MDOC_BODY != node->type)
                   1335:                return(1);
1.28      kristaps 1336:        word(p, "`");
1.10      kristaps 1337:        p->flags |= TERMP_NOSPACE;
                   1338:        return(1);
                   1339: }
1.1       kristaps 1340:
                   1341:
1.10      kristaps 1342: /* ARGSUSED */
                   1343: static void
                   1344: termp_sq_post(DECL_ARGS)
                   1345: {
                   1346:
                   1347:        if (MDOC_BODY != node->type)
                   1348:                return;
                   1349:        p->flags |= TERMP_NOSPACE;
                   1350:        word(p, "\'");
                   1351: }
1.2       kristaps 1352:
                   1353:
1.10      kristaps 1354: /* ARGSUSED */
                   1355: static int
                   1356: termp_pf_pre(DECL_ARGS)
                   1357: {
1.1       kristaps 1358:
1.10      kristaps 1359:        p->flags |= TERMP_IGNDELIM;
                   1360:        return(1);
                   1361: }
1.1       kristaps 1362:
                   1363:
1.10      kristaps 1364: /* ARGSUSED */
                   1365: static void
                   1366: termp_pf_post(DECL_ARGS)
                   1367: {
1.1       kristaps 1368:
1.10      kristaps 1369:        p->flags &= ~TERMP_IGNDELIM;
                   1370:        p->flags |= TERMP_NOSPACE;
                   1371: }
1.1       kristaps 1372:
                   1373:
1.10      kristaps 1374: /* ARGSUSED */
                   1375: static int
                   1376: termp_ss_pre(DECL_ARGS)
                   1377: {
1.1       kristaps 1378:
1.10      kristaps 1379:        switch (node->type) {
                   1380:        case (MDOC_HEAD):
                   1381:                vspace(p);
1.31      kristaps 1382:                TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_SSECTION]);
1.10      kristaps 1383:                p->offset = INDENT / 2;
                   1384:                break;
                   1385:        default:
                   1386:                break;
                   1387:        }
1.1       kristaps 1388:
1.10      kristaps 1389:        return(1);
1.1       kristaps 1390: }
                   1391:
                   1392:
1.10      kristaps 1393: /* ARGSUSED */
                   1394: static void
                   1395: termp_ss_post(DECL_ARGS)
1.1       kristaps 1396: {
                   1397:
1.10      kristaps 1398:        switch (node->type) {
                   1399:        case (MDOC_HEAD):
                   1400:                newln(p);
                   1401:                p->offset = INDENT;
                   1402:                break;
                   1403:        default:
                   1404:                break;
                   1405:        }
                   1406: }
1.2       kristaps 1407:
                   1408:
1.10      kristaps 1409: /* ARGSUSED */
                   1410: static int
                   1411: termp_pa_pre(DECL_ARGS)
                   1412: {
1.2       kristaps 1413:
1.31      kristaps 1414:        TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_FILE]);
1.10      kristaps 1415:        return(1);
1.1       kristaps 1416: }
                   1417:
                   1418:
1.10      kristaps 1419: /* ARGSUSED */
1.11      kristaps 1420: static int
                   1421: termp_em_pre(DECL_ARGS)
                   1422: {
                   1423:
1.31      kristaps 1424:        TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_EMPH]);
1.11      kristaps 1425:        return(1);
                   1426: }
                   1427:
                   1428:
                   1429: /* ARGSUSED */
1.14      kristaps 1430: static int
                   1431: termp_cd_pre(DECL_ARGS)
                   1432: {
                   1433:
1.31      kristaps 1434:        TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_CONFIG]);
1.33      kristaps 1435:        newln(p);
1.14      kristaps 1436:        return(1);
                   1437: }
                   1438:
                   1439:
                   1440: /* ARGSUSED */
                   1441: static int
                   1442: termp_cm_pre(DECL_ARGS)
                   1443: {
                   1444:
1.31      kristaps 1445:        TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_CMD_FLAG]);
1.14      kristaps 1446:        return(1);
                   1447: }
                   1448:
                   1449:
                   1450: /* ARGSUSED */
                   1451: static int
                   1452: termp_ic_pre(DECL_ARGS)
                   1453: {
                   1454:
1.31      kristaps 1455:        TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_CMD]);
1.14      kristaps 1456:        return(1);
                   1457: }
                   1458:
                   1459:
                   1460: /* ARGSUSED */
                   1461: static int
                   1462: termp_in_pre(DECL_ARGS)
                   1463: {
                   1464:
1.31      kristaps 1465:        TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_INCLUDE]);
1.30      kristaps 1466:        word(p, "#include");
                   1467:        word(p, "<");
                   1468:        p->flags |= TERMP_NOSPACE;
1.14      kristaps 1469:        return(1);
                   1470: }
                   1471:
                   1472:
                   1473: /* ARGSUSED */
1.30      kristaps 1474: static void
                   1475: termp_in_post(DECL_ARGS)
                   1476: {
                   1477:
                   1478:        p->flags |= TERMP_NOSPACE;
                   1479:        word(p, ">");
                   1480:
                   1481:        newln(p);
                   1482:        if (SEC_SYNOPSIS != node->sec)
                   1483:                return;
                   1484:        if (node->next && MDOC_In != node->next->tok)
                   1485:                vspace(p);
                   1486: }
                   1487:
                   1488:
                   1489: /* ARGSUSED */
1.14      kristaps 1490: static int
                   1491: termp_at_pre(DECL_ARGS)
                   1492: {
1.43    ! kristaps 1493:        const char      *att;
        !          1494:
        !          1495:        att = NULL;
1.14      kristaps 1496:
                   1497:        if (node->child) {
                   1498:                assert(MDOC_TEXT == node->child->type);
1.43    ! kristaps 1499:                att = mdoc_a2att(node->child->data.text.string);
1.14      kristaps 1500:        }
                   1501:
1.43    ! kristaps 1502:        if (NULL == att)
        !          1503:                att = "AT&T UNIX";
        !          1504:
        !          1505:        word(p, att);
1.14      kristaps 1506:        return(0);
                   1507: }
1.15      kristaps 1508:
                   1509:
                   1510: /* ARGSUSED */
                   1511: static int
                   1512: termp_bq_pre(DECL_ARGS)
                   1513: {
                   1514:
                   1515:        if (MDOC_BODY != node->type)
                   1516:                return(1);
1.30      kristaps 1517:        word(p, "[");
1.15      kristaps 1518:        p->flags |= TERMP_NOSPACE;
                   1519:        return(1);
                   1520: }
                   1521:
                   1522:
                   1523: /* ARGSUSED */
                   1524: static void
                   1525: termp_bq_post(DECL_ARGS)
                   1526: {
                   1527:
                   1528:        if (MDOC_BODY != node->type)
                   1529:                return;
                   1530:        word(p, "]");
                   1531: }
                   1532:
                   1533:
                   1534: /* ARGSUSED */
                   1535: static int
                   1536: termp_pq_pre(DECL_ARGS)
                   1537: {
                   1538:
                   1539:        if (MDOC_BODY != node->type)
                   1540:                return(1);
1.31      kristaps 1541:        word(p, "\\&(");
1.15      kristaps 1542:        p->flags |= TERMP_NOSPACE;
                   1543:        return(1);
                   1544: }
                   1545:
                   1546:
                   1547: /* ARGSUSED */
                   1548: static void
                   1549: termp_pq_post(DECL_ARGS)
                   1550: {
                   1551:
                   1552:        if (MDOC_BODY != node->type)
                   1553:                return;
                   1554:        word(p, ")");
                   1555: }
                   1556:
                   1557:
1.16      kristaps 1558: /* ARGSUSED */
                   1559: static int
                   1560: termp_fo_pre(DECL_ARGS)
                   1561: {
                   1562:        const struct mdoc_node *n;
                   1563:
                   1564:        if (MDOC_BODY == node->type) {
                   1565:                word(p, "(");
                   1566:                p->flags |= TERMP_NOSPACE;
                   1567:                return(1);
                   1568:        } else if (MDOC_HEAD != node->type)
                   1569:                return(1);
                   1570:
1.17      kristaps 1571:        /* XXX - groff shows only first parameter */
                   1572:
1.16      kristaps 1573:        p->flags |= ttypes[TTYPE_FUNC_NAME];
                   1574:        for (n = node->child; n; n = n->next) {
                   1575:                assert(MDOC_TEXT == n->type);
                   1576:                word(p, n->data.text.string);
                   1577:        }
                   1578:        p->flags &= ~ttypes[TTYPE_FUNC_NAME];
                   1579:
                   1580:        return(0);
                   1581: }
                   1582:
                   1583:
                   1584: /* ARGSUSED */
                   1585: static void
                   1586: termp_fo_post(DECL_ARGS)
                   1587: {
                   1588:
                   1589:        if (MDOC_BODY != node->type)
                   1590:                return;
                   1591:        word(p, ")");
                   1592:        word(p, ";");
                   1593:        newln(p);
                   1594: }
                   1595:
                   1596:
1.17      kristaps 1597: /* ARGSUSED */
                   1598: static int
                   1599: termp_bf_pre(DECL_ARGS)
                   1600: {
                   1601:        const struct mdoc_node  *n;
                   1602:        const struct mdoc_block *b;
                   1603:
                   1604:        /* XXX - we skip over possible trailing HEAD tokens. */
                   1605:
                   1606:        if (MDOC_HEAD == node->type)
                   1607:                return(0);
                   1608:        else if (MDOC_BLOCK != node->type)
                   1609:                return(1);
                   1610:
                   1611:        b = &node->data.block;
                   1612:
                   1613:        if (NULL == (n = b->head->child)) {
                   1614:                if (arg_hasattr(MDOC_Emphasis, b->argc, b->argv))
1.31      kristaps 1615:                        TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_EMPH]);
1.17      kristaps 1616:                else if (arg_hasattr(MDOC_Symbolic, b->argc, b->argv))
1.31      kristaps 1617:                        TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_SYMB]);
1.17      kristaps 1618:
                   1619:                return(1);
                   1620:        }
                   1621:
                   1622:        assert(MDOC_TEXT == n->type);
                   1623:
                   1624:        if (0 == strcmp("Em", n->data.text.string))
1.31      kristaps 1625:                TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_EMPH]);
1.17      kristaps 1626:        else if (0 == strcmp("Sy", n->data.text.string))
1.31      kristaps 1627:                TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_EMPH]);
1.17      kristaps 1628:
                   1629:        return(1);
                   1630: }
                   1631:
                   1632:
                   1633: /* ARGSUSED */
                   1634: static int
                   1635: termp_sy_pre(DECL_ARGS)
                   1636: {
                   1637:
1.31      kristaps 1638:        TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_SYMB]);
1.17      kristaps 1639:        return(1);
                   1640: }
                   1641:
                   1642:
                   1643: /* ARGSUSED */
                   1644: static int
                   1645: termp_ms_pre(DECL_ARGS)
                   1646: {
                   1647:
1.31      kristaps 1648:        TERMPAIR_SETFLAG(p, pair, ttypes[TTYPE_SYMBOL]);
1.17      kristaps 1649:        return(1);
                   1650: }
                   1651:
1.22      kristaps 1652:
                   1653:
                   1654: /* ARGSUSED */
                   1655: static int
                   1656: termp_sm_pre(DECL_ARGS)
                   1657: {
                   1658:
                   1659: #if notyet
                   1660:        assert(node->child);
                   1661:        if (0 == strcmp("off", node->child->data.text.string)) {
                   1662:                p->flags &= ~TERMP_NONOSPACE;
                   1663:                p->flags &= ~TERMP_NOSPACE;
                   1664:        } else {
                   1665:                p->flags |= TERMP_NONOSPACE;
                   1666:                p->flags |= TERMP_NOSPACE;
                   1667:        }
                   1668: #endif
                   1669:
                   1670:        return(0);
                   1671: }
1.28      kristaps 1672:
                   1673:
                   1674: /* ARGSUSED */
                   1675: static int
                   1676: termp__t_pre(DECL_ARGS)
                   1677: {
                   1678:
1.41      kristaps 1679:        /* FIXME: titles are underlined. */
1.28      kristaps 1680:        word(p, "\"");
                   1681:        p->flags |= TERMP_NOSPACE;
                   1682:        return(1);
                   1683: }
                   1684:
                   1685:
                   1686: /* ARGSUSED */
                   1687: static void
                   1688: termp__t_post(DECL_ARGS)
                   1689: {
                   1690:
                   1691:        p->flags |= TERMP_NOSPACE;
1.41      kristaps 1692:        /* FIXME: titles are underlined. */
1.28      kristaps 1693:        word(p, "\"");
                   1694:        word(p, node->next ? "," : ".");
                   1695: }
                   1696:
                   1697:
                   1698: /* ARGSUSED */
                   1699: static void
                   1700: termp____post(DECL_ARGS)
                   1701: {
                   1702:
                   1703:        p->flags |= TERMP_NOSPACE;
                   1704:        word(p, node->next ? "," : ".");
                   1705: }

CVSweb