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

Annotation of mandoc/term.c, Revision 1.53

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

CVSweb