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

Annotation of src/usr.bin/mandoc/mdoc_html.c, Revision 1.1

1.1     ! schwarze    1: /*     $Id: mdoc_html.c,v 1.35 2009/10/20 05:45:21 kristaps Exp $ */
        !             2: /*
        !             3:  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
        !             4:  *
        !             5:  * Permission to use, copy, modify, and distribute this software for any
        !             6:  * purpose with or without fee is hereby granted, provided that the above
        !             7:  * copyright notice and this permission notice appear in all copies.
        !             8:  *
        !             9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            16:  */
        !            17: #include <sys/types.h>
        !            18: #include <sys/param.h>
        !            19: #include <sys/queue.h>
        !            20:
        !            21: #include <assert.h>
        !            22: #include <ctype.h>
        !            23: #include <err.h>
        !            24: #include <stdio.h>
        !            25: #include <stdlib.h>
        !            26: #include <string.h>
        !            27: #include <unistd.h>
        !            28:
        !            29: #include "out.h"
        !            30: #include "html.h"
        !            31: #include "mdoc.h"
        !            32: #include "main.h"
        !            33:
        !            34: #define        INDENT           5
        !            35: #define        HALFINDENT       3
        !            36:
        !            37: #define        MDOC_ARGS         const struct mdoc_meta *m, \
        !            38:                          const struct mdoc_node *n, \
        !            39:                          struct html *h
        !            40:
        !            41: struct htmlmdoc {
        !            42:        int             (*pre)(MDOC_ARGS);
        !            43:        void            (*post)(MDOC_ARGS);
        !            44: };
        !            45:
        !            46: static void              print_mdoc(MDOC_ARGS);
        !            47: static void              print_mdoc_head(MDOC_ARGS);
        !            48: static void              print_mdoc_node(MDOC_ARGS);
        !            49: static void              print_mdoc_nodelist(MDOC_ARGS);
        !            50:
        !            51: static void              a2width(const char *, struct roffsu *);
        !            52: static void              a2offs(const char *, struct roffsu *);
        !            53:
        !            54: static int               a2list(const struct mdoc_node *);
        !            55:
        !            56: static void              mdoc_root_post(MDOC_ARGS);
        !            57: static int               mdoc_root_pre(MDOC_ARGS);
        !            58:
        !            59: static void              mdoc__x_post(MDOC_ARGS);
        !            60: static int               mdoc__x_pre(MDOC_ARGS);
        !            61: static int               mdoc_ad_pre(MDOC_ARGS);
        !            62: static int               mdoc_an_pre(MDOC_ARGS);
        !            63: static int               mdoc_ap_pre(MDOC_ARGS);
        !            64: static void              mdoc_aq_post(MDOC_ARGS);
        !            65: static int               mdoc_aq_pre(MDOC_ARGS);
        !            66: static int               mdoc_ar_pre(MDOC_ARGS);
        !            67: static int               mdoc_bd_pre(MDOC_ARGS);
        !            68: static int               mdoc_bf_pre(MDOC_ARGS);
        !            69: static void              mdoc_bl_post(MDOC_ARGS);
        !            70: static int               mdoc_bl_pre(MDOC_ARGS);
        !            71: static void              mdoc_bq_post(MDOC_ARGS);
        !            72: static int               mdoc_bq_pre(MDOC_ARGS);
        !            73: static void              mdoc_brq_post(MDOC_ARGS);
        !            74: static int               mdoc_brq_pre(MDOC_ARGS);
        !            75: static int               mdoc_bt_pre(MDOC_ARGS);
        !            76: static int               mdoc_bx_pre(MDOC_ARGS);
        !            77: static int               mdoc_cd_pre(MDOC_ARGS);
        !            78: static int               mdoc_d1_pre(MDOC_ARGS);
        !            79: static void              mdoc_dq_post(MDOC_ARGS);
        !            80: static int               mdoc_dq_pre(MDOC_ARGS);
        !            81: static int               mdoc_dv_pre(MDOC_ARGS);
        !            82: static int               mdoc_fa_pre(MDOC_ARGS);
        !            83: static int               mdoc_fd_pre(MDOC_ARGS);
        !            84: static int               mdoc_fl_pre(MDOC_ARGS);
        !            85: static int               mdoc_fn_pre(MDOC_ARGS);
        !            86: static int               mdoc_ft_pre(MDOC_ARGS);
        !            87: static int               mdoc_em_pre(MDOC_ARGS);
        !            88: static int               mdoc_er_pre(MDOC_ARGS);
        !            89: static int               mdoc_ev_pre(MDOC_ARGS);
        !            90: static int               mdoc_ex_pre(MDOC_ARGS);
        !            91: static void              mdoc_fo_post(MDOC_ARGS);
        !            92: static int               mdoc_fo_pre(MDOC_ARGS);
        !            93: static int               mdoc_ic_pre(MDOC_ARGS);
        !            94: static int               mdoc_in_pre(MDOC_ARGS);
        !            95: static int               mdoc_it_block_pre(MDOC_ARGS, int, int,
        !            96:                                struct roffsu *, struct roffsu *);
        !            97: static int               mdoc_it_head_pre(MDOC_ARGS, int,
        !            98:                                struct roffsu *);
        !            99: static int               mdoc_it_body_pre(MDOC_ARGS, int);
        !           100: static int               mdoc_it_pre(MDOC_ARGS);
        !           101: static int               mdoc_lb_pre(MDOC_ARGS);
        !           102: static int               mdoc_li_pre(MDOC_ARGS);
        !           103: static int               mdoc_lk_pre(MDOC_ARGS);
        !           104: static int               mdoc_mt_pre(MDOC_ARGS);
        !           105: static int               mdoc_ms_pre(MDOC_ARGS);
        !           106: static int               mdoc_nd_pre(MDOC_ARGS);
        !           107: static int               mdoc_nm_pre(MDOC_ARGS);
        !           108: static int               mdoc_ns_pre(MDOC_ARGS);
        !           109: static void              mdoc_op_post(MDOC_ARGS);
        !           110: static int               mdoc_op_pre(MDOC_ARGS);
        !           111: static int               mdoc_pa_pre(MDOC_ARGS);
        !           112: static void              mdoc_pf_post(MDOC_ARGS);
        !           113: static int               mdoc_pf_pre(MDOC_ARGS);
        !           114: static void              mdoc_pq_post(MDOC_ARGS);
        !           115: static int               mdoc_pq_pre(MDOC_ARGS);
        !           116: static int               mdoc_rs_pre(MDOC_ARGS);
        !           117: static int               mdoc_rv_pre(MDOC_ARGS);
        !           118: static int               mdoc_sh_pre(MDOC_ARGS);
        !           119: static int               mdoc_sp_pre(MDOC_ARGS);
        !           120: static void              mdoc_sq_post(MDOC_ARGS);
        !           121: static int               mdoc_sq_pre(MDOC_ARGS);
        !           122: static int               mdoc_ss_pre(MDOC_ARGS);
        !           123: static int               mdoc_sx_pre(MDOC_ARGS);
        !           124: static int               mdoc_sy_pre(MDOC_ARGS);
        !           125: static int               mdoc_ud_pre(MDOC_ARGS);
        !           126: static int               mdoc_va_pre(MDOC_ARGS);
        !           127: static int               mdoc_vt_pre(MDOC_ARGS);
        !           128: static int               mdoc_xr_pre(MDOC_ARGS);
        !           129: static int               mdoc_xx_pre(MDOC_ARGS);
        !           130:
        !           131: static const struct htmlmdoc mdocs[MDOC_MAX] = {
        !           132:        {mdoc_ap_pre, NULL}, /* Ap */
        !           133:        {NULL, NULL}, /* Dd */
        !           134:        {NULL, NULL}, /* Dt */
        !           135:        {NULL, NULL}, /* Os */
        !           136:        {mdoc_sh_pre, NULL }, /* Sh */
        !           137:        {mdoc_ss_pre, NULL }, /* Ss */
        !           138:        {mdoc_sp_pre, NULL}, /* Pp */
        !           139:        {mdoc_d1_pre, NULL}, /* D1 */
        !           140:        {mdoc_d1_pre, NULL}, /* Dl */
        !           141:        {mdoc_bd_pre, NULL}, /* Bd */
        !           142:        {NULL, NULL}, /* Ed */
        !           143:        {mdoc_bl_pre, mdoc_bl_post}, /* Bl */
        !           144:        {NULL, NULL}, /* El */
        !           145:        {mdoc_it_pre, NULL}, /* It */
        !           146:        {mdoc_ad_pre, NULL}, /* Ad */
        !           147:        {mdoc_an_pre, NULL}, /* An */
        !           148:        {mdoc_ar_pre, NULL}, /* Ar */
        !           149:        {mdoc_cd_pre, NULL}, /* Cd */
        !           150:        {mdoc_fl_pre, NULL}, /* Cm */
        !           151:        {mdoc_dv_pre, NULL}, /* Dv */
        !           152:        {mdoc_er_pre, NULL}, /* Er */
        !           153:        {mdoc_ev_pre, NULL}, /* Ev */
        !           154:        {mdoc_ex_pre, NULL}, /* Ex */
        !           155:        {mdoc_fa_pre, NULL}, /* Fa */
        !           156:        {mdoc_fd_pre, NULL}, /* Fd */
        !           157:        {mdoc_fl_pre, NULL}, /* Fl */
        !           158:        {mdoc_fn_pre, NULL}, /* Fn */
        !           159:        {mdoc_ft_pre, NULL}, /* Ft */
        !           160:        {mdoc_ic_pre, NULL}, /* Ic */
        !           161:        {mdoc_in_pre, NULL}, /* In */
        !           162:        {mdoc_li_pre, NULL}, /* Li */
        !           163:        {mdoc_nd_pre, NULL}, /* Nd */
        !           164:        {mdoc_nm_pre, NULL}, /* Nm */
        !           165:        {mdoc_op_pre, mdoc_op_post}, /* Op */
        !           166:        {NULL, NULL}, /* Ot */
        !           167:        {mdoc_pa_pre, NULL}, /* Pa */
        !           168:        {mdoc_rv_pre, NULL}, /* Rv */
        !           169:        {NULL, NULL}, /* St */
        !           170:        {mdoc_va_pre, NULL}, /* Va */
        !           171:        {mdoc_vt_pre, NULL}, /* Vt */
        !           172:        {mdoc_xr_pre, NULL}, /* Xr */
        !           173:        {mdoc__x_pre, mdoc__x_post}, /* %A */
        !           174:        {mdoc__x_pre, mdoc__x_post}, /* %B */
        !           175:        {mdoc__x_pre, mdoc__x_post}, /* %D */
        !           176:        {mdoc__x_pre, mdoc__x_post}, /* %I */
        !           177:        {mdoc__x_pre, mdoc__x_post}, /* %J */
        !           178:        {mdoc__x_pre, mdoc__x_post}, /* %N */
        !           179:        {mdoc__x_pre, mdoc__x_post}, /* %O */
        !           180:        {mdoc__x_pre, mdoc__x_post}, /* %P */
        !           181:        {mdoc__x_pre, mdoc__x_post}, /* %R */
        !           182:        {mdoc__x_pre, mdoc__x_post}, /* %T */
        !           183:        {mdoc__x_pre, mdoc__x_post}, /* %V */
        !           184:        {NULL, NULL}, /* Ac */
        !           185:        {mdoc_aq_pre, mdoc_aq_post}, /* Ao */
        !           186:        {mdoc_aq_pre, mdoc_aq_post}, /* Aq */
        !           187:        {NULL, NULL}, /* At */
        !           188:        {NULL, NULL}, /* Bc */
        !           189:        {mdoc_bf_pre, NULL}, /* Bf */
        !           190:        {mdoc_bq_pre, mdoc_bq_post}, /* Bo */
        !           191:        {mdoc_bq_pre, mdoc_bq_post}, /* Bq */
        !           192:        {mdoc_xx_pre, NULL}, /* Bsx */
        !           193:        {mdoc_bx_pre, NULL}, /* Bx */
        !           194:        {NULL, NULL}, /* Db */
        !           195:        {NULL, NULL}, /* Dc */
        !           196:        {mdoc_dq_pre, mdoc_dq_post}, /* Do */
        !           197:        {mdoc_dq_pre, mdoc_dq_post}, /* Dq */
        !           198:        {NULL, NULL}, /* Ec */
        !           199:        {NULL, NULL}, /* Ef */
        !           200:        {mdoc_em_pre, NULL}, /* Em */
        !           201:        {NULL, NULL}, /* Eo */
        !           202:        {mdoc_xx_pre, NULL}, /* Fx */
        !           203:        {mdoc_ms_pre, NULL}, /* Ms */ /* FIXME: convert to symbol? */
        !           204:        {NULL, NULL}, /* No */
        !           205:        {mdoc_ns_pre, NULL}, /* Ns */
        !           206:        {mdoc_xx_pre, NULL}, /* Nx */
        !           207:        {mdoc_xx_pre, NULL}, /* Ox */
        !           208:        {NULL, NULL}, /* Pc */
        !           209:        {mdoc_pf_pre, mdoc_pf_post}, /* Pf */
        !           210:        {mdoc_pq_pre, mdoc_pq_post}, /* Po */
        !           211:        {mdoc_pq_pre, mdoc_pq_post}, /* Pq */
        !           212:        {NULL, NULL}, /* Qc */
        !           213:        {mdoc_sq_pre, mdoc_sq_post}, /* Ql */
        !           214:        {mdoc_dq_pre, mdoc_dq_post}, /* Qo */
        !           215:        {mdoc_dq_pre, mdoc_dq_post}, /* Qq */
        !           216:        {NULL, NULL}, /* Re */
        !           217:        {mdoc_rs_pre, NULL}, /* Rs */
        !           218:        {NULL, NULL}, /* Sc */
        !           219:        {mdoc_sq_pre, mdoc_sq_post}, /* So */
        !           220:        {mdoc_sq_pre, mdoc_sq_post}, /* Sq */
        !           221:        {NULL, NULL}, /* Sm */ /* FIXME - no idea. */
        !           222:        {mdoc_sx_pre, NULL}, /* Sx */
        !           223:        {mdoc_sy_pre, NULL}, /* Sy */
        !           224:        {NULL, NULL}, /* Tn */
        !           225:        {mdoc_xx_pre, NULL}, /* Ux */
        !           226:        {NULL, NULL}, /* Xc */
        !           227:        {NULL, NULL}, /* Xo */
        !           228:        {mdoc_fo_pre, mdoc_fo_post}, /* Fo */
        !           229:        {NULL, NULL}, /* Fc */
        !           230:        {mdoc_op_pre, mdoc_op_post}, /* Oo */
        !           231:        {NULL, NULL}, /* Oc */
        !           232:        {NULL, NULL}, /* Bk */
        !           233:        {NULL, NULL}, /* Ek */
        !           234:        {mdoc_bt_pre, NULL}, /* Bt */
        !           235:        {NULL, NULL}, /* Hf */
        !           236:        {NULL, NULL}, /* Fr */
        !           237:        {mdoc_ud_pre, NULL}, /* Ud */
        !           238:        {mdoc_lb_pre, NULL}, /* Lb */
        !           239:        {mdoc_sp_pre, NULL}, /* Lp */
        !           240:        {mdoc_lk_pre, NULL}, /* Lk */
        !           241:        {mdoc_mt_pre, NULL}, /* Mt */
        !           242:        {mdoc_brq_pre, mdoc_brq_post}, /* Brq */
        !           243:        {mdoc_brq_pre, mdoc_brq_post}, /* Bro */
        !           244:        {NULL, NULL}, /* Brc */
        !           245:        {mdoc__x_pre, mdoc__x_post}, /* %C */
        !           246:        {NULL, NULL}, /* Es */  /* TODO */
        !           247:        {NULL, NULL}, /* En */  /* TODO */
        !           248:        {mdoc_xx_pre, NULL}, /* Dx */
        !           249:        {mdoc__x_pre, mdoc__x_post}, /* %Q */
        !           250:        {mdoc_sp_pre, NULL}, /* br */
        !           251:        {mdoc_sp_pre, NULL}, /* sp */
        !           252: };
        !           253:
        !           254:
        !           255: void
        !           256: html_mdoc(void *arg, const struct mdoc *m)
        !           257: {
        !           258:        struct html     *h;
        !           259:        struct tag      *t;
        !           260:
        !           261:        h = (struct html *)arg;
        !           262:
        !           263:        print_gen_doctype(h);
        !           264:        t = print_otag(h, TAG_HTML, 0, NULL);
        !           265:        print_mdoc(mdoc_meta(m), mdoc_node(m), h);
        !           266:        print_tagq(h, t);
        !           267:
        !           268:        printf("\n");
        !           269: }
        !           270:
        !           271:
        !           272: /*
        !           273:  * Return the list type for `Bl', e.g., `Bl -column' returns
        !           274:  * MDOC_Column.  This can ONLY be run for lists; it will abort() if no
        !           275:  * list type is found.
        !           276:  */
        !           277: static int
        !           278: a2list(const struct mdoc_node *n)
        !           279: {
        !           280:        int              i;
        !           281:
        !           282:        assert(n->args);
        !           283:        for (i = 0; i < (int)n->args->argc; i++)
        !           284:                switch (n->args->argv[i].arg) {
        !           285:                case (MDOC_Enum):
        !           286:                        /* FALLTHROUGH */
        !           287:                case (MDOC_Dash):
        !           288:                        /* FALLTHROUGH */
        !           289:                case (MDOC_Hyphen):
        !           290:                        /* FALLTHROUGH */
        !           291:                case (MDOC_Bullet):
        !           292:                        /* FALLTHROUGH */
        !           293:                case (MDOC_Tag):
        !           294:                        /* FALLTHROUGH */
        !           295:                case (MDOC_Hang):
        !           296:                        /* FALLTHROUGH */
        !           297:                case (MDOC_Inset):
        !           298:                        /* FALLTHROUGH */
        !           299:                case (MDOC_Diag):
        !           300:                        /* FALLTHROUGH */
        !           301:                case (MDOC_Item):
        !           302:                        /* FALLTHROUGH */
        !           303:                case (MDOC_Column):
        !           304:                        /* FALLTHROUGH */
        !           305:                case (MDOC_Ohang):
        !           306:                        return(n->args->argv[i].arg);
        !           307:                default:
        !           308:                        break;
        !           309:                }
        !           310:
        !           311:        abort();
        !           312:        /* NOTREACHED */
        !           313: }
        !           314:
        !           315:
        !           316: /*
        !           317:  * Calculate the scaling unit passed in a `-width' argument.  This uses
        !           318:  * either a native scaling unit (e.g., 1i, 2m) or the string length of
        !           319:  * the value.
        !           320:  */
        !           321: static void
        !           322: a2width(const char *p, struct roffsu *su)
        !           323: {
        !           324:
        !           325:        if ( ! a2roffsu(p, su, SCALE_MAX)) {
        !           326:                su->unit = SCALE_EM;
        !           327:                su->scale = (int)strlen(p);
        !           328:        }
        !           329: }
        !           330:
        !           331:
        !           332: /*
        !           333:  * Calculate the scaling unit passed in an `-offset' argument.  This
        !           334:  * uses either a native scaling unit (e.g., 1i, 2m), one of a set of
        !           335:  * predefined strings (indent, etc.), or the string length of the value.
        !           336:  */
        !           337: static void
        !           338: a2offs(const char *p, struct roffsu *su)
        !           339: {
        !           340:
        !           341:        /* FIXME: "right"? */
        !           342:
        !           343:        if (0 == strcmp(p, "left"))
        !           344:                SCALE_HS_INIT(su, 0);
        !           345:        else if (0 == strcmp(p, "indent"))
        !           346:                SCALE_HS_INIT(su, INDENT);
        !           347:        else if (0 == strcmp(p, "indent-two"))
        !           348:                SCALE_HS_INIT(su, INDENT * 2);
        !           349:        else if ( ! a2roffsu(p, su, SCALE_MAX)) {
        !           350:                su->unit = SCALE_EM;
        !           351:                su->scale = (int)strlen(p);
        !           352:        }
        !           353: }
        !           354:
        !           355:
        !           356: static void
        !           357: print_mdoc(MDOC_ARGS)
        !           358: {
        !           359:        struct tag      *t;
        !           360:        struct htmlpair  tag;
        !           361:
        !           362:        t = print_otag(h, TAG_HEAD, 0, NULL);
        !           363:        print_mdoc_head(m, n, h);
        !           364:        print_tagq(h, t);
        !           365:
        !           366:        t = print_otag(h, TAG_BODY, 0, NULL);
        !           367:
        !           368:        tag.key = ATTR_CLASS;
        !           369:        tag.val = "body";
        !           370:        print_otag(h, TAG_DIV, 1, &tag);
        !           371:
        !           372:        print_mdoc_nodelist(m, n, h);
        !           373:        print_tagq(h, t);
        !           374: }
        !           375:
        !           376:
        !           377: /* ARGSUSED */
        !           378: static void
        !           379: print_mdoc_head(MDOC_ARGS)
        !           380: {
        !           381:
        !           382:        print_gen_head(h);
        !           383:        bufinit(h);
        !           384:        buffmt(h, "%s(%d)", m->title, m->msec);
        !           385:
        !           386:        if (m->arch) {
        !           387:                bufcat(h, " (");
        !           388:                bufcat(h, m->arch);
        !           389:                bufcat(h, ")");
        !           390:        }
        !           391:
        !           392:        print_otag(h, TAG_TITLE, 0, NULL);
        !           393:        print_text(h, h->buf);
        !           394: }
        !           395:
        !           396:
        !           397: static void
        !           398: print_mdoc_nodelist(MDOC_ARGS)
        !           399: {
        !           400:
        !           401:        print_mdoc_node(m, n, h);
        !           402:        if (n->next)
        !           403:                print_mdoc_nodelist(m, n->next, h);
        !           404: }
        !           405:
        !           406:
        !           407: static void
        !           408: print_mdoc_node(MDOC_ARGS)
        !           409: {
        !           410:        int              child;
        !           411:        struct tag      *t;
        !           412:
        !           413:        child = 1;
        !           414:        t = SLIST_FIRST(&h->tags);
        !           415:
        !           416:        bufinit(h);
        !           417:        switch (n->type) {
        !           418:        case (MDOC_ROOT):
        !           419:                child = mdoc_root_pre(m, n, h);
        !           420:                break;
        !           421:        case (MDOC_TEXT):
        !           422:                print_text(h, n->string);
        !           423:                break;
        !           424:        default:
        !           425:                if (mdocs[n->tok].pre)
        !           426:                        child = (*mdocs[n->tok].pre)(m, n, h);
        !           427:                break;
        !           428:        }
        !           429:
        !           430:        if (child && n->child)
        !           431:                print_mdoc_nodelist(m, n->child, h);
        !           432:
        !           433:        print_stagq(h, t);
        !           434:
        !           435:        bufinit(h);
        !           436:        switch (n->type) {
        !           437:        case (MDOC_ROOT):
        !           438:                mdoc_root_post(m, n, h);
        !           439:                break;
        !           440:        case (MDOC_TEXT):
        !           441:                break;
        !           442:        default:
        !           443:                if (mdocs[n->tok].post)
        !           444:                        (*mdocs[n->tok].post)(m, n, h);
        !           445:                break;
        !           446:        }
        !           447: }
        !           448:
        !           449:
        !           450: /* ARGSUSED */
        !           451: static void
        !           452: mdoc_root_post(MDOC_ARGS)
        !           453: {
        !           454:        struct tm        tm;
        !           455:        struct htmlpair  tag[2];
        !           456:        struct tag      *t, *tt;
        !           457:        char             b[BUFSIZ];
        !           458:
        !           459:        /*
        !           460:         * XXX: this should use divs, but in Firefox, divs with nested
        !           461:         * divs for some reason puke when trying to put a border line
        !           462:         * below.  So I use tables, instead.
        !           463:         */
        !           464:
        !           465:        (void)localtime_r(&m->date, &tm);
        !           466:
        !           467:        if (0 == strftime(b, BUFSIZ - 1, "%B %e, %Y", &tm))
        !           468:                err(EXIT_FAILURE, "strftime");
        !           469:
        !           470:        PAIR_CLASS_INIT(&tag[0], "footer");
        !           471:        bufcat_style(h, "width", "100%");
        !           472:        PAIR_STYLE_INIT(&tag[1], h);
        !           473:        t = print_otag(h, TAG_TABLE, 2, tag);
        !           474:        tt = print_otag(h, TAG_TR, 0, NULL);
        !           475:
        !           476:        bufinit(h);
        !           477:        bufcat_style(h, "width", "50%");
        !           478:        PAIR_STYLE_INIT(&tag[0], h);
        !           479:        print_otag(h, TAG_TD, 1, tag);
        !           480:        print_text(h, b);
        !           481:        print_stagq(h, tt);
        !           482:
        !           483:        bufinit(h);
        !           484:        bufcat_style(h, "width", "50%");
        !           485:        bufcat_style(h, "text-align", "right");
        !           486:        PAIR_STYLE_INIT(&tag[0], h);
        !           487:        print_otag(h, TAG_TD, 1, tag);
        !           488:        print_text(h, m->os);
        !           489:        print_tagq(h, t);
        !           490: }
        !           491:
        !           492:
        !           493: /* ARGSUSED */
        !           494: static int
        !           495: mdoc_root_pre(MDOC_ARGS)
        !           496: {
        !           497:        struct htmlpair  tag[2];
        !           498:        struct tag      *t, *tt;
        !           499:        char             b[BUFSIZ], title[BUFSIZ];
        !           500:
        !           501:        (void)strlcpy(b, m->vol, BUFSIZ);
        !           502:
        !           503:        if (m->arch) {
        !           504:                (void)strlcat(b, " (", BUFSIZ);
        !           505:                (void)strlcat(b, m->arch, BUFSIZ);
        !           506:                (void)strlcat(b, ")", BUFSIZ);
        !           507:        }
        !           508:
        !           509:        (void)snprintf(title, BUFSIZ - 1,
        !           510:                        "%s(%d)", m->title, m->msec);
        !           511:
        !           512:        /* XXX: see note in mdoc_root_post() about divs. */
        !           513:
        !           514:        PAIR_CLASS_INIT(&tag[0], "header");
        !           515:        bufcat_style(h, "width", "100%");
        !           516:        PAIR_STYLE_INIT(&tag[1], h);
        !           517:        t = print_otag(h, TAG_TABLE, 2, tag);
        !           518:        tt = print_otag(h, TAG_TR, 0, NULL);
        !           519:
        !           520:        bufinit(h);
        !           521:        bufcat_style(h, "width", "10%");
        !           522:        PAIR_STYLE_INIT(&tag[0], h);
        !           523:        print_otag(h, TAG_TD, 1, tag);
        !           524:        print_text(h, title);
        !           525:        print_stagq(h, tt);
        !           526:
        !           527:        bufinit(h);
        !           528:        bufcat_style(h, "text-align", "center");
        !           529:        bufcat_style(h, "white-space", "nowrap");
        !           530:        bufcat_style(h, "width", "80%");
        !           531:        PAIR_STYLE_INIT(&tag[0], h);
        !           532:        print_otag(h, TAG_TD, 1, tag);
        !           533:        print_text(h, b);
        !           534:        print_stagq(h, tt);
        !           535:
        !           536:        bufinit(h);
        !           537:        bufcat_style(h, "text-align", "right");
        !           538:        bufcat_style(h, "width", "10%");
        !           539:        PAIR_STYLE_INIT(&tag[0], h);
        !           540:        print_otag(h, TAG_TD, 1, tag);
        !           541:        print_text(h, title);
        !           542:        print_tagq(h, t);
        !           543:        return(1);
        !           544: }
        !           545:
        !           546:
        !           547: /* ARGSUSED */
        !           548: static int
        !           549: mdoc_sh_pre(MDOC_ARGS)
        !           550: {
        !           551:        struct htmlpair          tag[2];
        !           552:        const struct mdoc_node  *nn;
        !           553:        char                     lbuf[BUFSIZ];
        !           554:        struct roffsu            su;
        !           555:
        !           556:        if (MDOC_BODY == n->type) {
        !           557:                SCALE_HS_INIT(&su, INDENT);
        !           558:                bufcat_su(h, "margin-left", &su);
        !           559:                PAIR_CLASS_INIT(&tag[0], "sec-body");
        !           560:                PAIR_STYLE_INIT(&tag[1], h);
        !           561:                print_otag(h, TAG_DIV, 2, tag);
        !           562:                return(1);
        !           563:        } else if (MDOC_BLOCK == n->type) {
        !           564:                PAIR_CLASS_INIT(&tag[0], "sec-block");
        !           565:                if (n->prev && NULL == n->prev->body->child) {
        !           566:                        print_otag(h, TAG_DIV, 1, tag);
        !           567:                        return(1);
        !           568:                }
        !           569:
        !           570:                SCALE_VS_INIT(&su, 1);
        !           571:                bufcat_su(h, "margin-top", &su);
        !           572:                if (NULL == n->next)
        !           573:                        bufcat_su(h, "margin-bottom", &su);
        !           574:
        !           575:                PAIR_STYLE_INIT(&tag[1], h);
        !           576:                print_otag(h, TAG_DIV, 2, tag);
        !           577:                return(1);
        !           578:        }
        !           579:
        !           580:        lbuf[0] = 0;
        !           581:        for (nn = n->child; nn; nn = nn->next) {
        !           582:                (void)strlcat(lbuf, nn->string, BUFSIZ);
        !           583:                if (nn->next)
        !           584:                        (void)strlcat(lbuf, "_", BUFSIZ);
        !           585:        }
        !           586:
        !           587:        /*
        !           588:         * TODO: make sure there are no duplicates, as HTML does not
        !           589:         * allow for multiple `id' tags of the same name.
        !           590:         */
        !           591:
        !           592:        PAIR_CLASS_INIT(&tag[0], "sec-head");
        !           593:        tag[1].key = ATTR_ID;
        !           594:        tag[1].val = lbuf;
        !           595:        print_otag(h, TAG_DIV, 2, tag);
        !           596:        return(1);
        !           597: }
        !           598:
        !           599:
        !           600: /* ARGSUSED */
        !           601: static int
        !           602: mdoc_ss_pre(MDOC_ARGS)
        !           603: {
        !           604:        struct htmlpair          tag[3];
        !           605:        const struct mdoc_node  *nn;
        !           606:        char                     lbuf[BUFSIZ];
        !           607:        struct roffsu            su;
        !           608:
        !           609:        SCALE_VS_INIT(&su, 1);
        !           610:
        !           611:        if (MDOC_BODY == n->type) {
        !           612:                PAIR_CLASS_INIT(&tag[0], "ssec-body");
        !           613:                if (n->parent->next && n->child) {
        !           614:                        bufcat_su(h, "margin-bottom", &su);
        !           615:                        PAIR_STYLE_INIT(&tag[1], h);
        !           616:                        print_otag(h, TAG_DIV, 2, tag);
        !           617:                } else
        !           618:                        print_otag(h, TAG_DIV, 1, tag);
        !           619:                return(1);
        !           620:        } else if (MDOC_BLOCK == n->type) {
        !           621:                PAIR_CLASS_INIT(&tag[0], "ssec-block");
        !           622:                if (n->prev) {
        !           623:                        bufcat_su(h, "margin-top", &su);
        !           624:                        PAIR_STYLE_INIT(&tag[1], h);
        !           625:                        print_otag(h, TAG_DIV, 2, tag);
        !           626:                } else
        !           627:                        print_otag(h, TAG_DIV, 1, tag);
        !           628:                return(1);
        !           629:        }
        !           630:
        !           631:        /* TODO: see note in mdoc_sh_pre() about duplicates. */
        !           632:
        !           633:        lbuf[0] = 0;
        !           634:        for (nn = n->child; nn; nn = nn->next) {
        !           635:                (void)strlcat(lbuf, nn->string, BUFSIZ);
        !           636:                if (nn->next)
        !           637:                        (void)strlcat(lbuf, "_", BUFSIZ);
        !           638:        }
        !           639:
        !           640:        SCALE_HS_INIT(&su, INDENT - HALFINDENT);
        !           641:        su.scale = -su.scale;
        !           642:        bufcat_su(h, "margin-left", &su);
        !           643:
        !           644:        PAIR_CLASS_INIT(&tag[0], "ssec-head");
        !           645:        PAIR_STYLE_INIT(&tag[1], h);
        !           646:        tag[2].key = ATTR_ID;
        !           647:        tag[2].val = lbuf;
        !           648:        print_otag(h, TAG_DIV, 3, tag);
        !           649:        return(1);
        !           650: }
        !           651:
        !           652:
        !           653: /* ARGSUSED */
        !           654: static int
        !           655: mdoc_fl_pre(MDOC_ARGS)
        !           656: {
        !           657:        struct htmlpair  tag;
        !           658:
        !           659:        PAIR_CLASS_INIT(&tag, "flag");
        !           660:        print_otag(h, TAG_SPAN, 1, &tag);
        !           661:        if (MDOC_Fl == n->tok) {
        !           662:                print_text(h, "\\-");
        !           663:                h->flags |= HTML_NOSPACE;
        !           664:        }
        !           665:        return(1);
        !           666: }
        !           667:
        !           668:
        !           669: /* ARGSUSED */
        !           670: static int
        !           671: mdoc_nd_pre(MDOC_ARGS)
        !           672: {
        !           673:        struct htmlpair  tag;
        !           674:
        !           675:        if (MDOC_BODY != n->type)
        !           676:                return(1);
        !           677:
        !           678:        /* XXX: this tag in theory can contain block elements. */
        !           679:
        !           680:        print_text(h, "\\(em");
        !           681:        PAIR_CLASS_INIT(&tag, "desc-body");
        !           682:        print_otag(h, TAG_SPAN, 1, &tag);
        !           683:        return(1);
        !           684: }
        !           685:
        !           686:
        !           687: /* ARGSUSED */
        !           688: static int
        !           689: mdoc_op_pre(MDOC_ARGS)
        !           690: {
        !           691:        struct htmlpair  tag;
        !           692:
        !           693:        if (MDOC_BODY != n->type)
        !           694:                return(1);
        !           695:
        !           696:        /* XXX: this tag in theory can contain block elements. */
        !           697:
        !           698:        print_text(h, "\\(lB");
        !           699:        h->flags |= HTML_NOSPACE;
        !           700:        PAIR_CLASS_INIT(&tag, "opt");
        !           701:        print_otag(h, TAG_SPAN, 1, &tag);
        !           702:        return(1);
        !           703: }
        !           704:
        !           705:
        !           706: /* ARGSUSED */
        !           707: static void
        !           708: mdoc_op_post(MDOC_ARGS)
        !           709: {
        !           710:
        !           711:        if (MDOC_BODY != n->type)
        !           712:                return;
        !           713:        h->flags |= HTML_NOSPACE;
        !           714:        print_text(h, "\\(rB");
        !           715: }
        !           716:
        !           717:
        !           718: static int
        !           719: mdoc_nm_pre(MDOC_ARGS)
        !           720: {
        !           721:        struct htmlpair tag;
        !           722:
        !           723:        if ( ! (HTML_NEWLINE & h->flags))
        !           724:                if (SEC_SYNOPSIS == n->sec) {
        !           725:                        bufcat_style(h, "clear", "both");
        !           726:                        PAIR_STYLE_INIT(&tag, h);
        !           727:                        print_otag(h, TAG_BR, 1, &tag);
        !           728:                }
        !           729:
        !           730:        PAIR_CLASS_INIT(&tag, "name");
        !           731:        print_otag(h, TAG_SPAN, 1, &tag);
        !           732:        if (NULL == n->child)
        !           733:                print_text(h, m->name);
        !           734:
        !           735:        return(1);
        !           736: }
        !           737:
        !           738:
        !           739: /* ARGSUSED */
        !           740: static int
        !           741: mdoc_xr_pre(MDOC_ARGS)
        !           742: {
        !           743:        struct htmlpair          tag[2];
        !           744:        const struct mdoc_node  *nn;
        !           745:
        !           746:        PAIR_CLASS_INIT(&tag[0], "link-man");
        !           747:
        !           748:        if (h->base_man) {
        !           749:                buffmt_man(h, n->child->string,
        !           750:                                n->child->next ?
        !           751:                                n->child->next->string : NULL);
        !           752:                tag[1].key = ATTR_HREF;
        !           753:                tag[1].val = h->buf;
        !           754:                print_otag(h, TAG_A, 2, tag);
        !           755:        } else
        !           756:                print_otag(h, TAG_A, 1, tag);
        !           757:
        !           758:        nn = n->child;
        !           759:        print_text(h, nn->string);
        !           760:
        !           761:        if (NULL == (nn = nn->next))
        !           762:                return(0);
        !           763:
        !           764:        h->flags |= HTML_NOSPACE;
        !           765:        print_text(h, "(");
        !           766:        h->flags |= HTML_NOSPACE;
        !           767:        print_text(h, nn->string);
        !           768:        h->flags |= HTML_NOSPACE;
        !           769:        print_text(h, ")");
        !           770:        return(0);
        !           771: }
        !           772:
        !           773:
        !           774: /* ARGSUSED */
        !           775: static int
        !           776: mdoc_ns_pre(MDOC_ARGS)
        !           777: {
        !           778:
        !           779:        h->flags |= HTML_NOSPACE;
        !           780:        return(1);
        !           781: }
        !           782:
        !           783:
        !           784: /* ARGSUSED */
        !           785: static int
        !           786: mdoc_ar_pre(MDOC_ARGS)
        !           787: {
        !           788:        struct htmlpair tag;
        !           789:
        !           790:        PAIR_CLASS_INIT(&tag, "arg");
        !           791:        print_otag(h, TAG_SPAN, 1, &tag);
        !           792:        return(1);
        !           793: }
        !           794:
        !           795:
        !           796: /* ARGSUSED */
        !           797: static int
        !           798: mdoc_xx_pre(MDOC_ARGS)
        !           799: {
        !           800:        const char      *pp;
        !           801:        struct htmlpair  tag;
        !           802:
        !           803:        switch (n->tok) {
        !           804:        case (MDOC_Bsx):
        !           805:                pp = "BSDI BSD/OS";
        !           806:                break;
        !           807:        case (MDOC_Dx):
        !           808:                pp = "DragonFlyBSD";
        !           809:                break;
        !           810:        case (MDOC_Fx):
        !           811:                pp = "FreeBSD";
        !           812:                break;
        !           813:        case (MDOC_Nx):
        !           814:                pp = "NetBSD";
        !           815:                break;
        !           816:        case (MDOC_Ox):
        !           817:                pp = "OpenBSD";
        !           818:                break;
        !           819:        case (MDOC_Ux):
        !           820:                pp = "UNIX";
        !           821:                break;
        !           822:        default:
        !           823:                return(1);
        !           824:        }
        !           825:
        !           826:        PAIR_CLASS_INIT(&tag, "unix");
        !           827:        print_otag(h, TAG_SPAN, 1, &tag);
        !           828:        print_text(h, pp);
        !           829:        return(1);
        !           830: }
        !           831:
        !           832:
        !           833: /* ARGSUSED */
        !           834: static int
        !           835: mdoc_bx_pre(MDOC_ARGS)
        !           836: {
        !           837:        const struct mdoc_node  *nn;
        !           838:        struct htmlpair          tag;
        !           839:
        !           840:        PAIR_CLASS_INIT(&tag, "unix");
        !           841:        print_otag(h, TAG_SPAN, 1, &tag);
        !           842:
        !           843:        for (nn = n->child; nn; nn = nn->next)
        !           844:                print_mdoc_node(m, nn, h);
        !           845:
        !           846:        if (n->child)
        !           847:                h->flags |= HTML_NOSPACE;
        !           848:
        !           849:        print_text(h, "BSD");
        !           850:        return(0);
        !           851: }
        !           852:
        !           853:
        !           854: /* ARGSUSED */
        !           855: static int
        !           856: mdoc_it_block_pre(MDOC_ARGS, int type, int comp,
        !           857:                struct roffsu *offs, struct roffsu *width)
        !           858: {
        !           859:        struct htmlpair          tag;
        !           860:        const struct mdoc_node  *nn;
        !           861:        struct roffsu            su;
        !           862:
        !           863:        nn = n->parent->parent;
        !           864:        assert(nn->args);
        !           865:
        !           866:        /* XXX: see notes in mdoc_it_pre(). */
        !           867:
        !           868:        if (MDOC_Column == type) {
        !           869:                /* Don't width-pad on the left. */
        !           870:                SCALE_HS_INIT(width, 0);
        !           871:                /* Also disallow non-compact. */
        !           872:                comp = 1;
        !           873:        }
        !           874:        if (MDOC_Diag == type)
        !           875:                /* Mandate non-compact with empty prior. */
        !           876:                if (n->prev && NULL == n->prev->body->child)
        !           877:                        comp = 1;
        !           878:
        !           879:        bufcat_style(h, "clear", "both");
        !           880:        if (offs->scale > 0)
        !           881:                bufcat_su(h, "margin-left", offs);
        !           882:        if (width->scale > 0)
        !           883:                bufcat_su(h, "padding-left", width);
        !           884:
        !           885:        PAIR_STYLE_INIT(&tag, h);
        !           886:
        !           887:        /* Mandate compact following `Ss' and `Sh' starts. */
        !           888:
        !           889:        for (nn = n; nn && ! comp; nn = nn->parent) {
        !           890:                if (MDOC_BLOCK != nn->type)
        !           891:                        continue;
        !           892:                if (MDOC_Ss == nn->tok || MDOC_Sh == nn->tok)
        !           893:                        comp = 1;
        !           894:                if (nn->prev)
        !           895:                        break;
        !           896:        }
        !           897:
        !           898:        if ( ! comp) {
        !           899:                SCALE_VS_INIT(&su, 1);
        !           900:                bufcat_su(h, "padding-top", &su);
        !           901:        }
        !           902:
        !           903:        PAIR_STYLE_INIT(&tag, h);
        !           904:        print_otag(h, TAG_DIV, 1, &tag);
        !           905:        return(1);
        !           906: }
        !           907:
        !           908:
        !           909: /* ARGSUSED */
        !           910: static int
        !           911: mdoc_it_body_pre(MDOC_ARGS, int type)
        !           912: {
        !           913:        struct htmlpair  tag;
        !           914:        struct roffsu    su;
        !           915:
        !           916:        switch (type) {
        !           917:        case (MDOC_Item):
        !           918:                /* FALLTHROUGH */
        !           919:        case (MDOC_Ohang):
        !           920:                /* FALLTHROUGH */
        !           921:        case (MDOC_Column):
        !           922:                break;
        !           923:        default:
        !           924:                /*
        !           925:                 * XXX: this tricks CSS into aligning the bodies with
        !           926:                 * the right-padding in the head.
        !           927:                 */
        !           928:                SCALE_HS_INIT(&su, 2);
        !           929:                bufcat_su(h, "margin-left", &su);
        !           930:                PAIR_STYLE_INIT(&tag, h);
        !           931:                print_otag(h, TAG_DIV, 1, &tag);
        !           932:                break;
        !           933:        }
        !           934:
        !           935:        return(1);
        !           936: }
        !           937:
        !           938:
        !           939: /* ARGSUSED */
        !           940: static int
        !           941: mdoc_it_head_pre(MDOC_ARGS, int type, struct roffsu *width)
        !           942: {
        !           943:        struct htmlpair  tag;
        !           944:        struct ord      *ord;
        !           945:        char             nbuf[BUFSIZ];
        !           946:
        !           947:        switch (type) {
        !           948:        case (MDOC_Item):
        !           949:                /* FALLTHROUGH */
        !           950:        case (MDOC_Ohang):
        !           951:                print_otag(h, TAG_DIV, 0, NULL);
        !           952:                break;
        !           953:        case (MDOC_Column):
        !           954:                bufcat_su(h, "min-width", width);
        !           955:                bufcat_style(h, "clear", "none");
        !           956:                if (n->next && MDOC_HEAD == n->next->type)
        !           957:                        bufcat_style(h, "float", "left");
        !           958:                PAIR_STYLE_INIT(&tag, h);
        !           959:                print_otag(h, TAG_DIV, 1, &tag);
        !           960:                break;
        !           961:        default:
        !           962:                bufcat_su(h, "min-width", width);
        !           963:                SCALE_INVERT(width);
        !           964:                bufcat_su(h, "margin-left", width);
        !           965:                if (n->next && n->next->child)
        !           966:                        bufcat_style(h, "float", "left");
        !           967:
        !           968:                /* XXX: buffer if we run into body. */
        !           969:                SCALE_HS_INIT(width, 1);
        !           970:                bufcat_su(h, "margin-right", width);
        !           971:                PAIR_STYLE_INIT(&tag, h);
        !           972:                print_otag(h, TAG_DIV, 1, &tag);
        !           973:                break;
        !           974:        }
        !           975:
        !           976:        switch (type) {
        !           977:        case (MDOC_Diag):
        !           978:                PAIR_CLASS_INIT(&tag, "diag");
        !           979:                print_otag(h, TAG_SPAN, 1, &tag);
        !           980:                break;
        !           981:        case (MDOC_Enum):
        !           982:                ord = SLIST_FIRST(&h->ords);
        !           983:                assert(ord);
        !           984:                nbuf[BUFSIZ - 1] = 0;
        !           985:                (void)snprintf(nbuf, BUFSIZ - 1, "%d.", ord->pos++);
        !           986:                print_text(h, nbuf);
        !           987:                return(0);
        !           988:        case (MDOC_Dash):
        !           989:                print_text(h, "\\(en");
        !           990:                return(0);
        !           991:        case (MDOC_Hyphen):
        !           992:                print_text(h, "\\(hy");
        !           993:                return(0);
        !           994:        case (MDOC_Bullet):
        !           995:                print_text(h, "\\(bu");
        !           996:                return(0);
        !           997:        default:
        !           998:                break;
        !           999:        }
        !          1000:
        !          1001:        return(1);
        !          1002: }
        !          1003:
        !          1004:
        !          1005: static int
        !          1006: mdoc_it_pre(MDOC_ARGS)
        !          1007: {
        !          1008:        int                      i, type, wp, comp;
        !          1009:        const struct mdoc_node  *bl, *nn;
        !          1010:        struct roffsu            width, offs;
        !          1011:
        !          1012:        /*
        !          1013:         * XXX: be very careful in changing anything, here.  Lists in
        !          1014:         * mandoc have many peculiarities; furthermore, they don't
        !          1015:         * translate well into HTML and require a bit of mangling.
        !          1016:         */
        !          1017:
        !          1018:        bl = n->parent->parent;
        !          1019:        if (MDOC_BLOCK != n->type)
        !          1020:                bl = bl->parent;
        !          1021:
        !          1022:        type = a2list(bl);
        !          1023:
        !          1024:        /* Set default width and offset. */
        !          1025:
        !          1026:        SCALE_HS_INIT(&offs, 0);
        !          1027:
        !          1028:        switch (type) {
        !          1029:        case (MDOC_Enum):
        !          1030:                /* FALLTHROUGH */
        !          1031:        case (MDOC_Dash):
        !          1032:                /* FALLTHROUGH */
        !          1033:        case (MDOC_Hyphen):
        !          1034:                /* FALLTHROUGH */
        !          1035:        case (MDOC_Bullet):
        !          1036:                SCALE_HS_INIT(&width, 2);
        !          1037:                break;
        !          1038:        default:
        !          1039:                SCALE_HS_INIT(&width, INDENT);
        !          1040:                break;
        !          1041:        }
        !          1042:
        !          1043:        /* Get width, offset, and compact arguments. */
        !          1044:
        !          1045:        for (wp = -1, comp = i = 0; i < (int)bl->args->argc; i++)
        !          1046:                switch (bl->args->argv[i].arg) {
        !          1047:                case (MDOC_Column):
        !          1048:                        wp = i; /* Save for later. */
        !          1049:                        break;
        !          1050:                case (MDOC_Width):
        !          1051:                        a2width(bl->args->argv[i].value[0], &width);
        !          1052:                        break;
        !          1053:                case (MDOC_Offset):
        !          1054:                        a2offs(bl->args->argv[i].value[0], &offs);
        !          1055:                        break;
        !          1056:                case (MDOC_Compact):
        !          1057:                        comp = 1;
        !          1058:                        break;
        !          1059:                default:
        !          1060:                        break;
        !          1061:                }
        !          1062:
        !          1063:        /* Override width in some cases. */
        !          1064:
        !          1065:        switch (type) {
        !          1066:        case (MDOC_Item):
        !          1067:                /* FALLTHROUGH */
        !          1068:        case (MDOC_Inset):
        !          1069:                /* FALLTHROUGH */
        !          1070:        case (MDOC_Diag):
        !          1071:                SCALE_HS_INIT(&width, 0);
        !          1072:                break;
        !          1073:        default:
        !          1074:                if (0 == width.scale)
        !          1075:                        SCALE_HS_INIT(&width, INDENT);
        !          1076:                break;
        !          1077:        }
        !          1078:
        !          1079:        /* Flip to body/block processing. */
        !          1080:
        !          1081:        if (MDOC_BODY == n->type)
        !          1082:                return(mdoc_it_body_pre(m, n, h, type));
        !          1083:        if (MDOC_BLOCK == n->type)
        !          1084:                return(mdoc_it_block_pre(m, n, h, type, comp,
        !          1085:                                        &offs, &width));
        !          1086:
        !          1087:        /* Override column widths. */
        !          1088:
        !          1089:        if (MDOC_Column == type) {
        !          1090:                nn = n->parent->child;
        !          1091:                for (i = 0; nn && nn != n; nn = nn->next, i++)
        !          1092:                        /* Counter... */ ;
        !          1093:                if (i < (int)bl->args->argv[wp].sz)
        !          1094:                        a2width(bl->args->argv[wp].value[i], &width);
        !          1095:        }
        !          1096:
        !          1097:        return(mdoc_it_head_pre(m, n, h, type, &width));
        !          1098: }
        !          1099:
        !          1100:
        !          1101: /* ARGSUSED */
        !          1102: static int
        !          1103: mdoc_bl_pre(MDOC_ARGS)
        !          1104: {
        !          1105:        struct ord      *ord;
        !          1106:
        !          1107:        if (MDOC_BLOCK != n->type)
        !          1108:                return(1);
        !          1109:        if (MDOC_Enum != a2list(n))
        !          1110:                return(1);
        !          1111:
        !          1112:        ord = malloc(sizeof(struct ord));
        !          1113:        if (NULL == ord)
        !          1114:                err(EXIT_FAILURE, "malloc");
        !          1115:        ord->cookie = n;
        !          1116:        ord->pos = 1;
        !          1117:        SLIST_INSERT_HEAD(&h->ords, ord, entry);
        !          1118:        return(1);
        !          1119: }
        !          1120:
        !          1121:
        !          1122: /* ARGSUSED */
        !          1123: static void
        !          1124: mdoc_bl_post(MDOC_ARGS)
        !          1125: {
        !          1126:        struct ord      *ord;
        !          1127:
        !          1128:        if (MDOC_BLOCK != n->type)
        !          1129:                return;
        !          1130:        if (MDOC_Enum != a2list(n))
        !          1131:                return;
        !          1132:
        !          1133:        ord = SLIST_FIRST(&h->ords);
        !          1134:        assert(ord);
        !          1135:        SLIST_REMOVE_HEAD(&h->ords, entry);
        !          1136:        free(ord);
        !          1137: }
        !          1138:
        !          1139:
        !          1140: /* ARGSUSED */
        !          1141: static int
        !          1142: mdoc_ex_pre(MDOC_ARGS)
        !          1143: {
        !          1144:        const struct mdoc_node  *nn;
        !          1145:        struct tag              *t;
        !          1146:        struct htmlpair          tag;
        !          1147:
        !          1148:        PAIR_CLASS_INIT(&tag, "utility");
        !          1149:
        !          1150:        print_text(h, "The");
        !          1151:        for (nn = n->child; nn; nn = nn->next) {
        !          1152:                t = print_otag(h, TAG_SPAN, 1, &tag);
        !          1153:                print_text(h, nn->string);
        !          1154:                print_tagq(h, t);
        !          1155:
        !          1156:                h->flags |= HTML_NOSPACE;
        !          1157:
        !          1158:                if (nn->next && NULL == nn->next->next)
        !          1159:                        print_text(h, ", and");
        !          1160:                else if (nn->next)
        !          1161:                        print_text(h, ",");
        !          1162:                else
        !          1163:                        h->flags &= ~HTML_NOSPACE;
        !          1164:        }
        !          1165:
        !          1166:        if (n->child->next)
        !          1167:                print_text(h, "utilities exit");
        !          1168:        else
        !          1169:                print_text(h, "utility exits");
        !          1170:
        !          1171:                print_text(h, "0 on success, and >0 if an error occurs.");
        !          1172:        return(0);
        !          1173: }
        !          1174:
        !          1175:
        !          1176: /* ARGSUSED */
        !          1177: static int
        !          1178: mdoc_dq_pre(MDOC_ARGS)
        !          1179: {
        !          1180:
        !          1181:        if (MDOC_BODY != n->type)
        !          1182:                return(1);
        !          1183:        print_text(h, "\\(lq");
        !          1184:        h->flags |= HTML_NOSPACE;
        !          1185:        return(1);
        !          1186: }
        !          1187:
        !          1188:
        !          1189: /* ARGSUSED */
        !          1190: static void
        !          1191: mdoc_dq_post(MDOC_ARGS)
        !          1192: {
        !          1193:
        !          1194:        if (MDOC_BODY != n->type)
        !          1195:                return;
        !          1196:        h->flags |= HTML_NOSPACE;
        !          1197:        print_text(h, "\\(rq");
        !          1198: }
        !          1199:
        !          1200:
        !          1201: /* ARGSUSED */
        !          1202: static int
        !          1203: mdoc_pq_pre(MDOC_ARGS)
        !          1204: {
        !          1205:
        !          1206:        if (MDOC_BODY != n->type)
        !          1207:                return(1);
        !          1208:        print_text(h, "\\&(");
        !          1209:        h->flags |= HTML_NOSPACE;
        !          1210:        return(1);
        !          1211: }
        !          1212:
        !          1213:
        !          1214: /* ARGSUSED */
        !          1215: static void
        !          1216: mdoc_pq_post(MDOC_ARGS)
        !          1217: {
        !          1218:
        !          1219:        if (MDOC_BODY != n->type)
        !          1220:                return;
        !          1221:        print_text(h, ")");
        !          1222: }
        !          1223:
        !          1224:
        !          1225: /* ARGSUSED */
        !          1226: static int
        !          1227: mdoc_sq_pre(MDOC_ARGS)
        !          1228: {
        !          1229:
        !          1230:        if (MDOC_BODY != n->type)
        !          1231:                return(1);
        !          1232:        print_text(h, "\\(oq");
        !          1233:        h->flags |= HTML_NOSPACE;
        !          1234:        return(1);
        !          1235: }
        !          1236:
        !          1237:
        !          1238: /* ARGSUSED */
        !          1239: static void
        !          1240: mdoc_sq_post(MDOC_ARGS)
        !          1241: {
        !          1242:
        !          1243:        if (MDOC_BODY != n->type)
        !          1244:                return;
        !          1245:        h->flags |= HTML_NOSPACE;
        !          1246:        print_text(h, "\\(aq");
        !          1247: }
        !          1248:
        !          1249:
        !          1250: /* ARGSUSED */
        !          1251: static int
        !          1252: mdoc_em_pre(MDOC_ARGS)
        !          1253: {
        !          1254:        struct htmlpair tag;
        !          1255:
        !          1256:        PAIR_CLASS_INIT(&tag, "emph");
        !          1257:        print_otag(h, TAG_SPAN, 1, &tag);
        !          1258:        return(1);
        !          1259: }
        !          1260:
        !          1261:
        !          1262: /* ARGSUSED */
        !          1263: static int
        !          1264: mdoc_d1_pre(MDOC_ARGS)
        !          1265: {
        !          1266:        struct htmlpair  tag[2];
        !          1267:        struct roffsu    su;
        !          1268:
        !          1269:        if (MDOC_BLOCK != n->type)
        !          1270:                return(1);
        !          1271:
        !          1272:        /* FIXME: D1 shouldn't be literal. */
        !          1273:
        !          1274:        SCALE_VS_INIT(&su, INDENT - 2);
        !          1275:        bufcat_su(h, "margin-left", &su);
        !          1276:        PAIR_CLASS_INIT(&tag[0], "lit");
        !          1277:        PAIR_STYLE_INIT(&tag[1], h);
        !          1278:        print_otag(h, TAG_DIV, 2, tag);
        !          1279:        return(1);
        !          1280: }
        !          1281:
        !          1282:
        !          1283: /* ARGSUSED */
        !          1284: static int
        !          1285: mdoc_sx_pre(MDOC_ARGS)
        !          1286: {
        !          1287:        struct htmlpair          tag[2];
        !          1288:        const struct mdoc_node  *nn;
        !          1289:        char                     buf[BUFSIZ];
        !          1290:
        !          1291:        /* FIXME: duplicates? */
        !          1292:
        !          1293:        (void)strlcpy(buf, "#", BUFSIZ);
        !          1294:        for (nn = n->child; nn; nn = nn->next) {
        !          1295:                (void)strlcat(buf, nn->string, BUFSIZ);
        !          1296:                if (nn->next)
        !          1297:                        (void)strlcat(buf, "_", BUFSIZ);
        !          1298:        }
        !          1299:
        !          1300:        PAIR_CLASS_INIT(&tag[0], "link-sec");
        !          1301:        tag[1].key = ATTR_HREF;
        !          1302:        tag[1].val = buf;
        !          1303:
        !          1304:        print_otag(h, TAG_A, 2, tag);
        !          1305:        return(1);
        !          1306: }
        !          1307:
        !          1308:
        !          1309: /* ARGSUSED */
        !          1310: static int
        !          1311: mdoc_aq_pre(MDOC_ARGS)
        !          1312: {
        !          1313:
        !          1314:        if (MDOC_BODY != n->type)
        !          1315:                return(1);
        !          1316:        print_text(h, "\\(la");
        !          1317:        h->flags |= HTML_NOSPACE;
        !          1318:        return(1);
        !          1319: }
        !          1320:
        !          1321:
        !          1322: /* ARGSUSED */
        !          1323: static void
        !          1324: mdoc_aq_post(MDOC_ARGS)
        !          1325: {
        !          1326:
        !          1327:        if (MDOC_BODY != n->type)
        !          1328:                return;
        !          1329:        h->flags |= HTML_NOSPACE;
        !          1330:        print_text(h, "\\(ra");
        !          1331: }
        !          1332:
        !          1333:
        !          1334: /* ARGSUSED */
        !          1335: static int
        !          1336: mdoc_bd_pre(MDOC_ARGS)
        !          1337: {
        !          1338:        struct htmlpair          tag[2];
        !          1339:        int                      type, comp, i;
        !          1340:        const struct mdoc_node  *bl, *nn;
        !          1341:        struct roffsu            su;
        !          1342:
        !          1343:        if (MDOC_BLOCK == n->type)
        !          1344:                bl = n;
        !          1345:        else if (MDOC_HEAD == n->type)
        !          1346:                return(0);
        !          1347:        else
        !          1348:                bl = n->parent;
        !          1349:
        !          1350:        SCALE_VS_INIT(&su, 0);
        !          1351:
        !          1352:        type = comp = 0;
        !          1353:        for (i = 0; i < (int)bl->args->argc; i++)
        !          1354:                switch (bl->args->argv[i].arg) {
        !          1355:                case (MDOC_Offset):
        !          1356:                        a2offs(bl->args->argv[i].value[0], &su);
        !          1357:                        break;
        !          1358:                case (MDOC_Compact):
        !          1359:                        comp = 1;
        !          1360:                        break;
        !          1361:                case (MDOC_Centred):
        !          1362:                        /* FALLTHROUGH */
        !          1363:                case (MDOC_Ragged):
        !          1364:                        /* FALLTHROUGH */
        !          1365:                case (MDOC_Filled):
        !          1366:                        /* FALLTHROUGH */
        !          1367:                case (MDOC_Unfilled):
        !          1368:                        /* FALLTHROUGH */
        !          1369:                case (MDOC_Literal):
        !          1370:                        type = bl->args->argv[i].arg;
        !          1371:                        break;
        !          1372:                default:
        !          1373:                        break;
        !          1374:                }
        !          1375:
        !          1376:        /* FIXME: -centered, etc. formatting. */
        !          1377:
        !          1378:        if (MDOC_BLOCK == n->type) {
        !          1379:                bufcat_su(h, "margin-left", &su);
        !          1380:                for (nn = n; nn && ! comp; nn = nn->parent) {
        !          1381:                        if (MDOC_BLOCK != nn->type)
        !          1382:                                continue;
        !          1383:                        if (MDOC_Ss == nn->tok || MDOC_Sh == nn->tok)
        !          1384:                                comp = 1;
        !          1385:                        if (nn->prev)
        !          1386:                                break;
        !          1387:                }
        !          1388:                if (comp) {
        !          1389:                        print_otag(h, TAG_DIV, 0, tag);
        !          1390:                        return(1);
        !          1391:                }
        !          1392:                SCALE_VS_INIT(&su, 1);
        !          1393:                bufcat_su(h, "margin-top", &su);
        !          1394:                PAIR_STYLE_INIT(&tag[0], h);
        !          1395:                print_otag(h, TAG_DIV, 1, tag);
        !          1396:                return(1);
        !          1397:        }
        !          1398:
        !          1399:        if (MDOC_Unfilled != type && MDOC_Literal != type)
        !          1400:                return(1);
        !          1401:
        !          1402:        PAIR_CLASS_INIT(&tag[0], "lit");
        !          1403:        bufcat_style(h, "white-space", "pre");
        !          1404:        PAIR_STYLE_INIT(&tag[1], h);
        !          1405:        print_otag(h, TAG_DIV, 2, tag);
        !          1406:
        !          1407:        for (nn = n->child; nn; nn = nn->next) {
        !          1408:                h->flags |= HTML_NOSPACE;
        !          1409:                print_mdoc_node(m, nn, h);
        !          1410:                if (NULL == nn->next)
        !          1411:                        continue;
        !          1412:                if (nn->prev && nn->prev->line < nn->line)
        !          1413:                        print_text(h, "\n");
        !          1414:                else if (NULL == nn->prev)
        !          1415:                        print_text(h, "\n");
        !          1416:        }
        !          1417:
        !          1418:        return(0);
        !          1419: }
        !          1420:
        !          1421:
        !          1422: /* ARGSUSED */
        !          1423: static int
        !          1424: mdoc_pa_pre(MDOC_ARGS)
        !          1425: {
        !          1426:        struct htmlpair tag;
        !          1427:
        !          1428:        PAIR_CLASS_INIT(&tag, "file");
        !          1429:        print_otag(h, TAG_SPAN, 1, &tag);
        !          1430:        return(1);
        !          1431: }
        !          1432:
        !          1433:
        !          1434: /* ARGSUSED */
        !          1435: static int
        !          1436: mdoc_ad_pre(MDOC_ARGS)
        !          1437: {
        !          1438:        struct htmlpair tag;
        !          1439:
        !          1440:        PAIR_CLASS_INIT(&tag, "addr");
        !          1441:        print_otag(h, TAG_SPAN, 1, &tag);
        !          1442:        return(1);
        !          1443: }
        !          1444:
        !          1445:
        !          1446: /* ARGSUSED */
        !          1447: static int
        !          1448: mdoc_an_pre(MDOC_ARGS)
        !          1449: {
        !          1450:        struct htmlpair tag;
        !          1451:
        !          1452:        /* TODO: -split and -nosplit (see termp_an_pre()). */
        !          1453:
        !          1454:        PAIR_CLASS_INIT(&tag, "author");
        !          1455:        print_otag(h, TAG_SPAN, 1, &tag);
        !          1456:        return(1);
        !          1457: }
        !          1458:
        !          1459:
        !          1460: /* ARGSUSED */
        !          1461: static int
        !          1462: mdoc_cd_pre(MDOC_ARGS)
        !          1463: {
        !          1464:        struct htmlpair tag;
        !          1465:
        !          1466:        print_otag(h, TAG_DIV, 0, NULL);
        !          1467:        PAIR_CLASS_INIT(&tag, "config");
        !          1468:        print_otag(h, TAG_SPAN, 1, &tag);
        !          1469:        return(1);
        !          1470: }
        !          1471:
        !          1472:
        !          1473: /* ARGSUSED */
        !          1474: static int
        !          1475: mdoc_dv_pre(MDOC_ARGS)
        !          1476: {
        !          1477:        struct htmlpair tag;
        !          1478:
        !          1479:        PAIR_CLASS_INIT(&tag, "define");
        !          1480:        print_otag(h, TAG_SPAN, 1, &tag);
        !          1481:        return(1);
        !          1482: }
        !          1483:
        !          1484:
        !          1485: /* ARGSUSED */
        !          1486: static int
        !          1487: mdoc_ev_pre(MDOC_ARGS)
        !          1488: {
        !          1489:        struct htmlpair tag;
        !          1490:
        !          1491:        PAIR_CLASS_INIT(&tag, "env");
        !          1492:        print_otag(h, TAG_SPAN, 1, &tag);
        !          1493:        return(1);
        !          1494: }
        !          1495:
        !          1496:
        !          1497: /* ARGSUSED */
        !          1498: static int
        !          1499: mdoc_er_pre(MDOC_ARGS)
        !          1500: {
        !          1501:        struct htmlpair tag;
        !          1502:
        !          1503:        PAIR_CLASS_INIT(&tag, "errno");
        !          1504:        print_otag(h, TAG_SPAN, 1, &tag);
        !          1505:        return(1);
        !          1506: }
        !          1507:
        !          1508:
        !          1509: /* ARGSUSED */
        !          1510: static int
        !          1511: mdoc_fa_pre(MDOC_ARGS)
        !          1512: {
        !          1513:        const struct mdoc_node  *nn;
        !          1514:        struct htmlpair          tag;
        !          1515:        struct tag              *t;
        !          1516:
        !          1517:        PAIR_CLASS_INIT(&tag, "farg");
        !          1518:        if (n->parent->tok != MDOC_Fo) {
        !          1519:                print_otag(h, TAG_SPAN, 1, &tag);
        !          1520:                return(1);
        !          1521:        }
        !          1522:
        !          1523:        for (nn = n->child; nn; nn = nn->next) {
        !          1524:                t = print_otag(h, TAG_SPAN, 1, &tag);
        !          1525:                print_text(h, nn->string);
        !          1526:                print_tagq(h, t);
        !          1527:                if (nn->next)
        !          1528:                        print_text(h, ",");
        !          1529:        }
        !          1530:
        !          1531:        if (n->child && n->next && n->next->tok == MDOC_Fa)
        !          1532:                print_text(h, ",");
        !          1533:
        !          1534:        return(0);
        !          1535: }
        !          1536:
        !          1537:
        !          1538: /* ARGSUSED */
        !          1539: static int
        !          1540: mdoc_fd_pre(MDOC_ARGS)
        !          1541: {
        !          1542:        struct htmlpair  tag;
        !          1543:        struct roffsu    su;
        !          1544:
        !          1545:        if (SEC_SYNOPSIS == n->sec) {
        !          1546:                if (n->next && MDOC_Fd != n->next->tok) {
        !          1547:                        SCALE_VS_INIT(&su, 1);
        !          1548:                        bufcat_su(h, "margin-bottom", &su);
        !          1549:                        PAIR_STYLE_INIT(&tag, h);
        !          1550:                        print_otag(h, TAG_DIV, 1, &tag);
        !          1551:                } else
        !          1552:                        print_otag(h, TAG_DIV, 0, NULL);
        !          1553:        }
        !          1554:
        !          1555:        PAIR_CLASS_INIT(&tag, "macro");
        !          1556:        print_otag(h, TAG_SPAN, 1, &tag);
        !          1557:        return(1);
        !          1558: }
        !          1559:
        !          1560:
        !          1561: /* ARGSUSED */
        !          1562: static int
        !          1563: mdoc_vt_pre(MDOC_ARGS)
        !          1564: {
        !          1565:        struct htmlpair  tag;
        !          1566:        struct roffsu    su;
        !          1567:
        !          1568:        if (SEC_SYNOPSIS == n->sec) {
        !          1569:                if (n->next && MDOC_Vt != n->next->tok) {
        !          1570:                        SCALE_VS_INIT(&su, 1);
        !          1571:                        bufcat_su(h, "margin-bottom", &su);
        !          1572:                        PAIR_STYLE_INIT(&tag, h);
        !          1573:                        print_otag(h, TAG_DIV, 1, &tag);
        !          1574:                } else
        !          1575:                        print_otag(h, TAG_DIV, 0, NULL);
        !          1576:        }
        !          1577:
        !          1578:        PAIR_CLASS_INIT(&tag, "type");
        !          1579:        print_otag(h, TAG_SPAN, 1, &tag);
        !          1580:        return(1);
        !          1581: }
        !          1582:
        !          1583:
        !          1584: /* ARGSUSED */
        !          1585: static int
        !          1586: mdoc_ft_pre(MDOC_ARGS)
        !          1587: {
        !          1588:        struct htmlpair  tag;
        !          1589:        struct roffsu    su;
        !          1590:
        !          1591:        if (SEC_SYNOPSIS == n->sec) {
        !          1592:                if (n->prev && MDOC_Fo == n->prev->tok) {
        !          1593:                        SCALE_VS_INIT(&su, 1);
        !          1594:                        bufcat_su(h, "margin-top", &su);
        !          1595:                        PAIR_STYLE_INIT(&tag, h);
        !          1596:                        print_otag(h, TAG_DIV, 1, &tag);
        !          1597:                } else
        !          1598:                        print_otag(h, TAG_DIV, 0, NULL);
        !          1599:        }
        !          1600:
        !          1601:        PAIR_CLASS_INIT(&tag, "ftype");
        !          1602:        print_otag(h, TAG_SPAN, 1, &tag);
        !          1603:        return(1);
        !          1604: }
        !          1605:
        !          1606:
        !          1607: /* ARGSUSED */
        !          1608: static int
        !          1609: mdoc_fn_pre(MDOC_ARGS)
        !          1610: {
        !          1611:        struct tag              *t;
        !          1612:        struct htmlpair          tag[2];
        !          1613:        const struct mdoc_node  *nn;
        !          1614:        char                     nbuf[BUFSIZ];
        !          1615:        const char              *sp, *ep;
        !          1616:        int                      sz, i;
        !          1617:        struct roffsu            su;
        !          1618:
        !          1619:        if (SEC_SYNOPSIS == n->sec) {
        !          1620:                SCALE_HS_INIT(&su, INDENT);
        !          1621:                bufcat_su(h, "margin-left", &su);
        !          1622:                su.scale = -su.scale;
        !          1623:                bufcat_su(h, "text-indent", &su);
        !          1624:                if (n->next) {
        !          1625:                        SCALE_VS_INIT(&su, 1);
        !          1626:                        bufcat_su(h, "margin-bottom", &su);
        !          1627:                }
        !          1628:                PAIR_STYLE_INIT(&tag[0], h);
        !          1629:                print_otag(h, TAG_DIV, 1, tag);
        !          1630:        }
        !          1631:
        !          1632:        /* Split apart into type and name. */
        !          1633:        assert(n->child->string);
        !          1634:        sp = n->child->string;
        !          1635:
        !          1636:        ep = strchr(sp, ' ');
        !          1637:        if (NULL != ep) {
        !          1638:                PAIR_CLASS_INIT(&tag[0], "ftype");
        !          1639:                t = print_otag(h, TAG_SPAN, 1, tag);
        !          1640:
        !          1641:                while (ep) {
        !          1642:                        sz = MIN((int)(ep - sp), BUFSIZ - 1);
        !          1643:                        (void)memcpy(nbuf, sp, (size_t)sz);
        !          1644:                        nbuf[sz] = '\0';
        !          1645:                        print_text(h, nbuf);
        !          1646:                        sp = ++ep;
        !          1647:                        ep = strchr(sp, ' ');
        !          1648:                }
        !          1649:                print_tagq(h, t);
        !          1650:        }
        !          1651:
        !          1652:        PAIR_CLASS_INIT(&tag[0], "fname");
        !          1653:        t = print_otag(h, TAG_SPAN, 1, tag);
        !          1654:
        !          1655:        if (sp) {
        !          1656:                (void)strlcpy(nbuf, sp, BUFSIZ);
        !          1657:                print_text(h, nbuf);
        !          1658:        }
        !          1659:
        !          1660:        print_tagq(h, t);
        !          1661:
        !          1662:        h->flags |= HTML_NOSPACE;
        !          1663:        print_text(h, "(");
        !          1664:
        !          1665:        bufinit(h);
        !          1666:        PAIR_CLASS_INIT(&tag[0], "farg");
        !          1667:        bufcat_style(h, "white-space", "nowrap");
        !          1668:        PAIR_STYLE_INIT(&tag[1], h);
        !          1669:
        !          1670:        for (nn = n->child->next; nn; nn = nn->next) {
        !          1671:                i = 1;
        !          1672:                if (SEC_SYNOPSIS == n->sec)
        !          1673:                        i = 2;
        !          1674:                t = print_otag(h, TAG_SPAN, i, tag);
        !          1675:                print_text(h, nn->string);
        !          1676:                print_tagq(h, t);
        !          1677:                if (nn->next)
        !          1678:                        print_text(h, ",");
        !          1679:        }
        !          1680:
        !          1681:        print_text(h, ")");
        !          1682:        if (SEC_SYNOPSIS == n->sec)
        !          1683:                print_text(h, ";");
        !          1684:
        !          1685:        return(0);
        !          1686: }
        !          1687:
        !          1688:
        !          1689: /* ARGSUSED */
        !          1690: static int
        !          1691: mdoc_sp_pre(MDOC_ARGS)
        !          1692: {
        !          1693:        int              len;
        !          1694:        struct htmlpair  tag;
        !          1695:        struct roffsu    su;
        !          1696:
        !          1697:        switch (n->tok) {
        !          1698:        case (MDOC_sp):
        !          1699:                /* FIXME: can this have a scaling indicator? */
        !          1700:                len = n->child ? atoi(n->child->string) : 1;
        !          1701:                break;
        !          1702:        case (MDOC_br):
        !          1703:                len = 0;
        !          1704:                break;
        !          1705:        default:
        !          1706:                len = 1;
        !          1707:                break;
        !          1708:        }
        !          1709:
        !          1710:        SCALE_VS_INIT(&su, len);
        !          1711:        bufcat_su(h, "height", &su);
        !          1712:        PAIR_STYLE_INIT(&tag, h);
        !          1713:        print_otag(h, TAG_DIV, 1, &tag);
        !          1714:        return(1);
        !          1715:
        !          1716: }
        !          1717:
        !          1718:
        !          1719: /* ARGSUSED */
        !          1720: static int
        !          1721: mdoc_brq_pre(MDOC_ARGS)
        !          1722: {
        !          1723:
        !          1724:        if (MDOC_BODY != n->type)
        !          1725:                return(1);
        !          1726:        print_text(h, "\\(lC");
        !          1727:        h->flags |= HTML_NOSPACE;
        !          1728:        return(1);
        !          1729: }
        !          1730:
        !          1731:
        !          1732: /* ARGSUSED */
        !          1733: static void
        !          1734: mdoc_brq_post(MDOC_ARGS)
        !          1735: {
        !          1736:
        !          1737:        if (MDOC_BODY != n->type)
        !          1738:                return;
        !          1739:        h->flags |= HTML_NOSPACE;
        !          1740:        print_text(h, "\\(rC");
        !          1741: }
        !          1742:
        !          1743:
        !          1744: /* ARGSUSED */
        !          1745: static int
        !          1746: mdoc_lk_pre(MDOC_ARGS)
        !          1747: {
        !          1748:        const struct mdoc_node  *nn;
        !          1749:        struct htmlpair          tag[2];
        !          1750:
        !          1751:        nn = n->child;
        !          1752:
        !          1753:        PAIR_CLASS_INIT(&tag[0], "link-ext");
        !          1754:        tag[1].key = ATTR_HREF;
        !          1755:        tag[1].val = nn->string;
        !          1756:        print_otag(h, TAG_A, 2, tag);
        !          1757:
        !          1758:        for (nn = nn->next; nn; nn = nn->next)
        !          1759:                print_text(h, nn->string);
        !          1760:
        !          1761:        return(0);
        !          1762: }
        !          1763:
        !          1764:
        !          1765: /* ARGSUSED */
        !          1766: static int
        !          1767: mdoc_mt_pre(MDOC_ARGS)
        !          1768: {
        !          1769:        struct htmlpair          tag[2];
        !          1770:        struct tag              *t;
        !          1771:        const struct mdoc_node  *nn;
        !          1772:
        !          1773:        PAIR_CLASS_INIT(&tag[0], "link-mail");
        !          1774:
        !          1775:        for (nn = n->child; nn; nn = nn->next) {
        !          1776:                bufinit(h);
        !          1777:                bufcat(h, "mailto:");
        !          1778:                bufcat(h, nn->string);
        !          1779:                PAIR_STYLE_INIT(&tag[1], h);
        !          1780:                t = print_otag(h, TAG_A, 2, tag);
        !          1781:                print_text(h, nn->string);
        !          1782:                print_tagq(h, t);
        !          1783:        }
        !          1784:
        !          1785:        return(0);
        !          1786: }
        !          1787:
        !          1788:
        !          1789: /* ARGSUSED */
        !          1790: static int
        !          1791: mdoc_fo_pre(MDOC_ARGS)
        !          1792: {
        !          1793:        struct htmlpair tag;
        !          1794:
        !          1795:        if (MDOC_BODY == n->type) {
        !          1796:                h->flags |= HTML_NOSPACE;
        !          1797:                print_text(h, "(");
        !          1798:                h->flags |= HTML_NOSPACE;
        !          1799:                return(1);
        !          1800:        } else if (MDOC_BLOCK == n->type)
        !          1801:                return(1);
        !          1802:
        !          1803:        PAIR_CLASS_INIT(&tag, "fname");
        !          1804:        print_otag(h, TAG_SPAN, 1, &tag);
        !          1805:        return(1);
        !          1806: }
        !          1807:
        !          1808:
        !          1809: /* ARGSUSED */
        !          1810: static void
        !          1811: mdoc_fo_post(MDOC_ARGS)
        !          1812: {
        !          1813:        if (MDOC_BODY != n->type)
        !          1814:                return;
        !          1815:        h->flags |= HTML_NOSPACE;
        !          1816:        print_text(h, ")");
        !          1817:        h->flags |= HTML_NOSPACE;
        !          1818:        print_text(h, ";");
        !          1819: }
        !          1820:
        !          1821:
        !          1822: /* ARGSUSED */
        !          1823: static int
        !          1824: mdoc_in_pre(MDOC_ARGS)
        !          1825: {
        !          1826:        const struct mdoc_node  *nn;
        !          1827:        struct tag              *t;
        !          1828:        struct htmlpair          tag[2];
        !          1829:        int                      i;
        !          1830:        struct roffsu            su;
        !          1831:
        !          1832:        if (SEC_SYNOPSIS == n->sec) {
        !          1833:                if (n->next && MDOC_In != n->next->tok) {
        !          1834:                        SCALE_VS_INIT(&su, 1);
        !          1835:                        bufcat_su(h, "margin-bottom", &su);
        !          1836:                        PAIR_STYLE_INIT(&tag[0], h);
        !          1837:                        print_otag(h, TAG_DIV, 1, tag);
        !          1838:                } else
        !          1839:                        print_otag(h, TAG_DIV, 0, NULL);
        !          1840:        }
        !          1841:
        !          1842:        /* FIXME: there's a buffer bug in here somewhere. */
        !          1843:
        !          1844:        PAIR_CLASS_INIT(&tag[0], "includes");
        !          1845:        print_otag(h, TAG_SPAN, 1, tag);
        !          1846:
        !          1847:        if (SEC_SYNOPSIS == n->sec)
        !          1848:                print_text(h, "#include");
        !          1849:
        !          1850:        print_text(h, "<");
        !          1851:        h->flags |= HTML_NOSPACE;
        !          1852:
        !          1853:        /* XXX -- see warning in termp_in_post(). */
        !          1854:
        !          1855:        for (nn = n->child; nn; nn = nn->next) {
        !          1856:                PAIR_CLASS_INIT(&tag[0], "link-includes");
        !          1857:                i = 1;
        !          1858:                if (h->base_includes) {
        !          1859:                        buffmt_includes(h, nn->string);
        !          1860:                        tag[i].key = ATTR_HREF;
        !          1861:                        tag[i++].val = h->buf;
        !          1862:                }
        !          1863:                t = print_otag(h, TAG_A, i, tag);
        !          1864:                print_mdoc_node(m, nn, h);
        !          1865:                print_tagq(h, t);
        !          1866:        }
        !          1867:
        !          1868:        h->flags |= HTML_NOSPACE;
        !          1869:        print_text(h, ">");
        !          1870:
        !          1871:        return(0);
        !          1872: }
        !          1873:
        !          1874:
        !          1875: /* ARGSUSED */
        !          1876: static int
        !          1877: mdoc_ic_pre(MDOC_ARGS)
        !          1878: {
        !          1879:        struct htmlpair tag;
        !          1880:
        !          1881:        PAIR_CLASS_INIT(&tag, "cmd");
        !          1882:        print_otag(h, TAG_SPAN, 1, &tag);
        !          1883:        return(1);
        !          1884: }
        !          1885:
        !          1886:
        !          1887: /* ARGSUSED */
        !          1888: static int
        !          1889: mdoc_rv_pre(MDOC_ARGS)
        !          1890: {
        !          1891:        const struct mdoc_node  *nn;
        !          1892:        struct htmlpair          tag;
        !          1893:        struct tag              *t;
        !          1894:
        !          1895:        print_otag(h, TAG_DIV, 0, NULL);
        !          1896:        print_text(h, "The");
        !          1897:
        !          1898:        for (nn = n->child; nn; nn = nn->next) {
        !          1899:                PAIR_CLASS_INIT(&tag, "fname");
        !          1900:                t = print_otag(h, TAG_SPAN, 1, &tag);
        !          1901:                print_text(h, nn->string);
        !          1902:                print_tagq(h, t);
        !          1903:
        !          1904:                h->flags |= HTML_NOSPACE;
        !          1905:                if (nn->next && NULL == nn->next->next)
        !          1906:                        print_text(h, "(), and");
        !          1907:                else if (nn->next)
        !          1908:                        print_text(h, "(),");
        !          1909:                else
        !          1910:                        print_text(h, "()");
        !          1911:        }
        !          1912:
        !          1913:        if (n->child->next)
        !          1914:                print_text(h, "functions return");
        !          1915:        else
        !          1916:                print_text(h, "function returns");
        !          1917:
        !          1918:                print_text(h, "the value 0 if successful; otherwise the value "
        !          1919:                        "-1 is returned and the global variable");
        !          1920:
        !          1921:        PAIR_CLASS_INIT(&tag, "var");
        !          1922:        t = print_otag(h, TAG_SPAN, 1, &tag);
        !          1923:        print_text(h, "errno");
        !          1924:        print_tagq(h, t);
        !          1925:                print_text(h, "is set to indicate the error.");
        !          1926:        return(0);
        !          1927: }
        !          1928:
        !          1929:
        !          1930: /* ARGSUSED */
        !          1931: static int
        !          1932: mdoc_va_pre(MDOC_ARGS)
        !          1933: {
        !          1934:        struct htmlpair tag;
        !          1935:
        !          1936:        PAIR_CLASS_INIT(&tag, "var");
        !          1937:        print_otag(h, TAG_SPAN, 1, &tag);
        !          1938:        return(1);
        !          1939: }
        !          1940:
        !          1941:
        !          1942: /* ARGSUSED */
        !          1943: static int
        !          1944: mdoc_bq_pre(MDOC_ARGS)
        !          1945: {
        !          1946:
        !          1947:        if (MDOC_BODY != n->type)
        !          1948:                return(1);
        !          1949:        print_text(h, "\\(lB");
        !          1950:        h->flags |= HTML_NOSPACE;
        !          1951:        return(1);
        !          1952: }
        !          1953:
        !          1954:
        !          1955: /* ARGSUSED */
        !          1956: static void
        !          1957: mdoc_bq_post(MDOC_ARGS)
        !          1958: {
        !          1959:
        !          1960:        if (MDOC_BODY != n->type)
        !          1961:                return;
        !          1962:        h->flags |= HTML_NOSPACE;
        !          1963:        print_text(h, "\\(rB");
        !          1964: }
        !          1965:
        !          1966:
        !          1967: /* ARGSUSED */
        !          1968: static int
        !          1969: mdoc_ap_pre(MDOC_ARGS)
        !          1970: {
        !          1971:
        !          1972:        h->flags |= HTML_NOSPACE;
        !          1973:        print_text(h, "\\(aq");
        !          1974:        h->flags |= HTML_NOSPACE;
        !          1975:        return(1);
        !          1976: }
        !          1977:
        !          1978:
        !          1979: /* ARGSUSED */
        !          1980: static int
        !          1981: mdoc_bf_pre(MDOC_ARGS)
        !          1982: {
        !          1983:        int              i;
        !          1984:        struct htmlpair  tag[2];
        !          1985:        struct roffsu    su;
        !          1986:
        !          1987:        if (MDOC_HEAD == n->type)
        !          1988:                return(0);
        !          1989:        else if (MDOC_BLOCK != n->type)
        !          1990:                return(1);
        !          1991:
        !          1992:        PAIR_CLASS_INIT(&tag[0], "lit");
        !          1993:
        !          1994:        if (n->head->child) {
        !          1995:                if ( ! strcmp("Em", n->head->child->string))
        !          1996:                        PAIR_CLASS_INIT(&tag[0], "emph");
        !          1997:                else if ( ! strcmp("Sy", n->head->child->string))
        !          1998:                        PAIR_CLASS_INIT(&tag[0], "symb");
        !          1999:                else if ( ! strcmp("Li", n->head->child->string))
        !          2000:                        PAIR_CLASS_INIT(&tag[0], "lit");
        !          2001:        } else {
        !          2002:                assert(n->args);
        !          2003:                for (i = 0; i < (int)n->args->argc; i++)
        !          2004:                        switch (n->args->argv[i].arg) {
        !          2005:                        case (MDOC_Symbolic):
        !          2006:                                PAIR_CLASS_INIT(&tag[0], "symb");
        !          2007:                                break;
        !          2008:                        case (MDOC_Literal):
        !          2009:                                PAIR_CLASS_INIT(&tag[0], "lit");
        !          2010:                                break;
        !          2011:                        case (MDOC_Emphasis):
        !          2012:                                PAIR_CLASS_INIT(&tag[0], "emph");
        !          2013:                                break;
        !          2014:                        default:
        !          2015:                                break;
        !          2016:                        }
        !          2017:        }
        !          2018:
        !          2019:        /* FIXME: div's have spaces stripped--we want them. */
        !          2020:
        !          2021:        bufcat_style(h, "display", "inline");
        !          2022:        SCALE_HS_INIT(&su, 1);
        !          2023:        bufcat_su(h, "margin-right", &su);
        !          2024:        PAIR_STYLE_INIT(&tag[1], h);
        !          2025:        print_otag(h, TAG_DIV, 2, tag);
        !          2026:        return(1);
        !          2027: }
        !          2028:
        !          2029:
        !          2030: /* ARGSUSED */
        !          2031: static int
        !          2032: mdoc_ms_pre(MDOC_ARGS)
        !          2033: {
        !          2034:        struct htmlpair tag;
        !          2035:
        !          2036:        PAIR_CLASS_INIT(&tag, "symb");
        !          2037:        print_otag(h, TAG_SPAN, 1, &tag);
        !          2038:        return(1);
        !          2039: }
        !          2040:
        !          2041:
        !          2042: /* ARGSUSED */
        !          2043: static int
        !          2044: mdoc_pf_pre(MDOC_ARGS)
        !          2045: {
        !          2046:
        !          2047:        h->flags |= HTML_IGNDELIM;
        !          2048:        return(1);
        !          2049: }
        !          2050:
        !          2051:
        !          2052: /* ARGSUSED */
        !          2053: static void
        !          2054: mdoc_pf_post(MDOC_ARGS)
        !          2055: {
        !          2056:
        !          2057:        h->flags &= ~HTML_IGNDELIM;
        !          2058:        h->flags |= HTML_NOSPACE;
        !          2059: }
        !          2060:
        !          2061:
        !          2062: /* ARGSUSED */
        !          2063: static int
        !          2064: mdoc_rs_pre(MDOC_ARGS)
        !          2065: {
        !          2066:        struct htmlpair  tag;
        !          2067:        struct roffsu    su;
        !          2068:
        !          2069:        if (MDOC_BLOCK != n->type)
        !          2070:                return(1);
        !          2071:
        !          2072:        if (n->prev && SEC_SEE_ALSO == n->sec) {
        !          2073:                SCALE_VS_INIT(&su, 1);
        !          2074:                bufcat_su(h, "margin-top", &su);
        !          2075:                PAIR_STYLE_INIT(&tag, h);
        !          2076:                print_otag(h, TAG_DIV, 1, &tag);
        !          2077:        }
        !          2078:
        !          2079:        PAIR_CLASS_INIT(&tag, "ref");
        !          2080:        print_otag(h, TAG_SPAN, 1, &tag);
        !          2081:        return(1);
        !          2082: }
        !          2083:
        !          2084:
        !          2085:
        !          2086: /* ARGSUSED */
        !          2087: static int
        !          2088: mdoc_li_pre(MDOC_ARGS)
        !          2089: {
        !          2090:        struct htmlpair tag;
        !          2091:
        !          2092:        PAIR_CLASS_INIT(&tag, "lit");
        !          2093:        print_otag(h, TAG_SPAN, 1, &tag);
        !          2094:        return(1);
        !          2095: }
        !          2096:
        !          2097:
        !          2098: /* ARGSUSED */
        !          2099: static int
        !          2100: mdoc_sy_pre(MDOC_ARGS)
        !          2101: {
        !          2102:        struct htmlpair tag;
        !          2103:
        !          2104:        PAIR_CLASS_INIT(&tag, "symb");
        !          2105:        print_otag(h, TAG_SPAN, 1, &tag);
        !          2106:        return(1);
        !          2107: }
        !          2108:
        !          2109:
        !          2110: /* ARGSUSED */
        !          2111: static int
        !          2112: mdoc_bt_pre(MDOC_ARGS)
        !          2113: {
        !          2114:
        !          2115:        print_text(h, "is currently in beta test.");
        !          2116:        return(0);
        !          2117: }
        !          2118:
        !          2119:
        !          2120: /* ARGSUSED */
        !          2121: static int
        !          2122: mdoc_ud_pre(MDOC_ARGS)
        !          2123: {
        !          2124:
        !          2125:        print_text(h, "currently under development.");
        !          2126:        return(0);
        !          2127: }
        !          2128:
        !          2129:
        !          2130: /* ARGSUSED */
        !          2131: static int
        !          2132: mdoc_lb_pre(MDOC_ARGS)
        !          2133: {
        !          2134:        struct htmlpair tag;
        !          2135:
        !          2136:        if (SEC_SYNOPSIS == n->sec)
        !          2137:                print_otag(h, TAG_DIV, 0, NULL);
        !          2138:        PAIR_CLASS_INIT(&tag, "lib");
        !          2139:        print_otag(h, TAG_SPAN, 1, &tag);
        !          2140:        return(1);
        !          2141: }
        !          2142:
        !          2143:
        !          2144: /* ARGSUSED */
        !          2145: static int
        !          2146: mdoc__x_pre(MDOC_ARGS)
        !          2147: {
        !          2148:        struct htmlpair tag;
        !          2149:
        !          2150:        switch (n->tok) {
        !          2151:        case(MDOC__A):
        !          2152:                PAIR_CLASS_INIT(&tag, "ref-auth");
        !          2153:                break;
        !          2154:        case(MDOC__B):
        !          2155:                PAIR_CLASS_INIT(&tag, "ref-book");
        !          2156:                break;
        !          2157:        case(MDOC__C):
        !          2158:                PAIR_CLASS_INIT(&tag, "ref-city");
        !          2159:                break;
        !          2160:        case(MDOC__D):
        !          2161:                PAIR_CLASS_INIT(&tag, "ref-date");
        !          2162:                break;
        !          2163:        case(MDOC__I):
        !          2164:                PAIR_CLASS_INIT(&tag, "ref-issue");
        !          2165:                break;
        !          2166:        case(MDOC__J):
        !          2167:                PAIR_CLASS_INIT(&tag, "ref-jrnl");
        !          2168:                break;
        !          2169:        case(MDOC__N):
        !          2170:                PAIR_CLASS_INIT(&tag, "ref-num");
        !          2171:                break;
        !          2172:        case(MDOC__O):
        !          2173:                PAIR_CLASS_INIT(&tag, "ref-opt");
        !          2174:                break;
        !          2175:        case(MDOC__P):
        !          2176:                PAIR_CLASS_INIT(&tag, "ref-page");
        !          2177:                break;
        !          2178:        case(MDOC__Q):
        !          2179:                PAIR_CLASS_INIT(&tag, "ref-corp");
        !          2180:                break;
        !          2181:        case(MDOC__R):
        !          2182:                PAIR_CLASS_INIT(&tag, "ref-rep");
        !          2183:                break;
        !          2184:        case(MDOC__T):
        !          2185:                PAIR_CLASS_INIT(&tag, "ref-title");
        !          2186:                print_text(h, "\\(lq");
        !          2187:                h->flags |= HTML_NOSPACE;
        !          2188:                break;
        !          2189:        case(MDOC__V):
        !          2190:                PAIR_CLASS_INIT(&tag, "ref-vol");
        !          2191:                break;
        !          2192:        default:
        !          2193:                abort();
        !          2194:                /* NOTREACHED */
        !          2195:        }
        !          2196:
        !          2197:        print_otag(h, TAG_SPAN, 1, &tag);
        !          2198:        return(1);
        !          2199: }
        !          2200:
        !          2201:
        !          2202: /* ARGSUSED */
        !          2203: static void
        !          2204: mdoc__x_post(MDOC_ARGS)
        !          2205: {
        !          2206:
        !          2207:        h->flags |= HTML_NOSPACE;
        !          2208:        switch (n->tok) {
        !          2209:        case (MDOC__T):
        !          2210:                print_text(h, "\\(rq");
        !          2211:                h->flags |= HTML_NOSPACE;
        !          2212:                break;
        !          2213:        default:
        !          2214:                break;
        !          2215:        }
        !          2216:        print_text(h, n->next ? "," : ".");
        !          2217: }