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

Annotation of mandoc/term.c, Revision 1.48

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

CVSweb