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

Annotation of mandoc/html.c, Revision 1.32

1.32    ! kristaps    1: /*     $Id: html.c,v 1.31 2009/09/17 07:41:28 kristaps Exp $ */
1.1       kristaps    2: /*
1.29      kristaps    3:  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
1.1       kristaps    4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
1.29      kristaps    6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
1.1       kristaps    8:  *
1.29      kristaps    9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1       kristaps   16:  */
1.30      kristaps   17: #include <sys/queue.h>
                     18:
1.1       kristaps   19: #include <assert.h>
1.4       kristaps   20: #include <err.h>
1.29      kristaps   21: #include <stdio.h>
1.1       kristaps   22: #include <stdlib.h>
                     23:
1.32    ! kristaps   24: #include "chars.h"
1.29      kristaps   25: #include "mdoc.h"
                     26: #include "man.h"
1.2       kristaps   27:
1.29      kristaps   28: #define        DOCTYPE         "-//W3C//DTD HTML 4.01//EN"
                     29: #define        DTD             "http://www.w3.org/TR/html4/strict.dtd"
1.8       kristaps   30:
1.29      kristaps   31: enum   htmltag {
                     32:        TAG_HTML,
                     33:        TAG_HEAD,
                     34:        TAG_BODY,
                     35:        TAG_META,
                     36:        TAG_TITLE,
                     37:        TAG_DIV,
                     38:        TAG_H1,
                     39:        TAG_H2,
                     40:        TAG_P,
                     41:        TAG_SPAN,
                     42:        TAG_LINK,
1.30      kristaps   43:        TAG_BR,
                     44:        TAG_A,
1.29      kristaps   45:        TAG_MAX
1.7       kristaps   46: };
                     47:
1.29      kristaps   48: enum   htmlattr {
                     49:        ATTR_HTTPEQUIV,
                     50:        ATTR_CONTENT,
                     51:        ATTR_NAME,
                     52:        ATTR_REL,
                     53:        ATTR_HREF,
                     54:        ATTR_TYPE,
                     55:        ATTR_MEDIA,
                     56:        ATTR_CLASS,
                     57:        ATTR_MAX
1.7       kristaps   58: };
                     59:
1.29      kristaps   60: struct htmldata {
                     61:        char             *name;
                     62:        int               flags;
1.30      kristaps   63: #define        HTML_CLRLINE     (1 << 0)
                     64: #define        HTML_NOSTACK     (1 << 1)
1.29      kristaps   65: };
1.7       kristaps   66:
1.29      kristaps   67: static const struct htmldata htmltags[TAG_MAX] = {
1.30      kristaps   68:        {"html",        HTML_CLRLINE}, /* TAG_HTML */
                     69:        {"head",        HTML_CLRLINE}, /* TAG_HEAD */
                     70:        {"body",        HTML_CLRLINE}, /* TAG_BODY */
                     71:        {"meta",        HTML_CLRLINE | HTML_NOSTACK}, /* TAG_META */
                     72:        {"title",       HTML_CLRLINE | HTML_NOSTACK}, /* TAG_TITLE */
                     73:        {"div",         HTML_CLRLINE}, /* TAG_DIV */
1.29      kristaps   74:        {"h1",          0}, /* TAG_H1 */
                     75:        {"h2",          0}, /* TAG_H2 */
1.30      kristaps   76:        {"p",           HTML_CLRLINE}, /* TAG_P */
1.29      kristaps   77:        {"span",        0}, /* TAG_SPAN */
1.30      kristaps   78:        {"link",        HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */
                     79:        {"br",          HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */
                     80:        {"a",           0}, /* TAG_A */
1.29      kristaps   81: };
1.10      kristaps   82:
1.29      kristaps   83: static const char       *const htmlattrs[ATTR_MAX] = {
                     84:        "http-equiv",
                     85:        "content",
                     86:        "name",
                     87:        "rel",
                     88:        "href",
                     89:        "type",
                     90:        "media",
                     91:        "class"
                     92: };
1.10      kristaps   93:
1.29      kristaps   94: struct htmlpair {
                     95:        enum htmlattr     key;
                     96:        char             *val;
                     97: };
1.10      kristaps   98:
1.30      kristaps   99: struct tag {
                    100:        enum htmltag      tag;
                    101:        SLIST_ENTRY(tag)  entry;
                    102: };
                    103:
                    104: SLIST_HEAD(tagq, tag);
                    105:
1.29      kristaps  106: struct html {
                    107:        int               flags;
                    108: #define        HTML_NOSPACE     (1 << 0)
1.30      kristaps  109: #define        HTML_NEWLINE     (1 << 1)
                    110:        struct tagq       stack;
1.32    ! kristaps  111:        void             *symtab;
1.29      kristaps  112: };
1.10      kristaps  113:
1.29      kristaps  114: #define        MDOC_ARGS         const struct mdoc_meta *m, \
                    115:                          const struct mdoc_node *n, \
                    116:                          struct html *h
                    117: #define        MAN_ARGS          const struct man_meta *m, \
                    118:                          const struct man_node *n, \
                    119:                          struct html *h
                    120: struct htmlmdoc {
                    121:        int             (*pre)(MDOC_ARGS);
                    122:        void            (*post)(MDOC_ARGS);
                    123: };
1.13      kristaps  124:
1.29      kristaps  125: static void              print_gen_doctype(struct html *);
                    126: static void              print_gen_head(struct html *);
                    127: static void              print_mdoc(MDOC_ARGS);
                    128: static void              print_mdoc_head(MDOC_ARGS);
1.30      kristaps  129: static void              print_mdoc_title(MDOC_ARGS);
1.29      kristaps  130: static void              print_mdoc_node(MDOC_ARGS);
                    131: static void              print_man(MAN_ARGS);
                    132: static void              print_man_head(MAN_ARGS);
                    133: static void              print_man_body(MAN_ARGS);
1.30      kristaps  134: static struct tag       *print_otag(struct html *, enum htmltag,
1.29      kristaps  135:                                int, const struct htmlpair *);
1.30      kristaps  136: static void              print_tagq(struct html *, const struct tag *);
                    137: static void              print_stagq(struct html *, const struct tag *);
1.29      kristaps  138: static void              print_ctag(struct html *, enum htmltag);
1.32    ! kristaps  139: static void              print_encode(struct html *, const char *);
        !           140: static void              print_escape(struct html *, const char **);
1.29      kristaps  141: static void              print_text(struct html *, const char *);
1.32    ! kristaps  142: static void              print_res(struct html *, const char *, int);
        !           143: static void              print_spec(struct html *, const char *, int);
1.29      kristaps  144: static int               mdoc_root_pre(MDOC_ARGS);
                    145:
1.31      kristaps  146: static int               mdoc_ar_pre(MDOC_ARGS);
1.30      kristaps  147: static int               mdoc_fl_pre(MDOC_ARGS);
1.29      kristaps  148: static int               mdoc_nd_pre(MDOC_ARGS);
                    149: static int               mdoc_nm_pre(MDOC_ARGS);
1.31      kristaps  150: static int               mdoc_ns_pre(MDOC_ARGS);
1.30      kristaps  151: static int               mdoc_op_pre(MDOC_ARGS);
                    152: static void              mdoc_op_post(MDOC_ARGS);
1.29      kristaps  153: static int               mdoc_pp_pre(MDOC_ARGS);
                    154: static int               mdoc_sh_pre(MDOC_ARGS);
                    155: static int               mdoc_ss_pre(MDOC_ARGS);
1.30      kristaps  156: static int               mdoc_xr_pre(MDOC_ARGS);
1.29      kristaps  157:
                    158: static const struct htmlmdoc mdocs[MDOC_MAX] = {
                    159:        {NULL, NULL}, /* Ap */
                    160:        {NULL, NULL}, /* Dd */
                    161:        {NULL, NULL}, /* Dt */
                    162:        {NULL, NULL}, /* Os */
1.30      kristaps  163:        {mdoc_sh_pre, NULL }, /* Sh */
                    164:        {mdoc_ss_pre, NULL }, /* Ss */
1.29      kristaps  165:        {mdoc_pp_pre, NULL}, /* Pp */
                    166:        {NULL, NULL}, /* D1 */
                    167:        {NULL, NULL}, /* Dl */
                    168:        {NULL, NULL}, /* Bd */
                    169:        {NULL, NULL}, /* Ed */
                    170:        {NULL, NULL}, /* Bl */
                    171:        {NULL, NULL}, /* El */
                    172:        {NULL, NULL}, /* It */
                    173:        {NULL, NULL}, /* Ad */
                    174:        {NULL, NULL}, /* An */
1.31      kristaps  175:        {mdoc_ar_pre, NULL}, /* Ar */
1.29      kristaps  176:        {NULL, NULL}, /* Cd */
                    177:        {NULL, NULL}, /* Cm */
                    178:        {NULL, NULL}, /* Dv */
                    179:        {NULL, NULL}, /* Er */
                    180:        {NULL, NULL}, /* Ev */
                    181:        {NULL, NULL}, /* Ex */
                    182:        {NULL, NULL}, /* Fa */
                    183:        {NULL, NULL}, /* Fd */
1.30      kristaps  184:        {mdoc_fl_pre, NULL}, /* Fl */
1.29      kristaps  185:        {NULL, NULL}, /* Fn */
                    186:        {NULL, NULL}, /* Ft */
                    187:        {NULL, NULL}, /* Ic */
                    188:        {NULL, NULL}, /* In */
                    189:        {NULL, NULL}, /* Li */
                    190:        {mdoc_nd_pre, NULL}, /* Nd */
1.30      kristaps  191:        {mdoc_nm_pre, NULL}, /* Nm */
                    192:        {mdoc_op_pre, mdoc_op_post}, /* Op */
1.29      kristaps  193:        {NULL, NULL}, /* Ot */
                    194:        {NULL, NULL}, /* Pa */
                    195:        {NULL, NULL}, /* Rv */
                    196:        {NULL, NULL}, /* St */
                    197:        {NULL, NULL}, /* Va */
                    198:        {NULL, NULL}, /* Vt */
1.30      kristaps  199:        {mdoc_xr_pre, NULL}, /* Xr */
1.29      kristaps  200:        {NULL, NULL}, /* %A */
                    201:        {NULL, NULL}, /* %B */
                    202:        {NULL, NULL}, /* %D */
                    203:        {NULL, NULL}, /* %I */
                    204:        {NULL, NULL}, /* %J */
                    205:        {NULL, NULL}, /* %N */
                    206:        {NULL, NULL}, /* %O */
                    207:        {NULL, NULL}, /* %P */
                    208:        {NULL, NULL}, /* %R */
                    209:        {NULL, NULL}, /* %T */
                    210:        {NULL, NULL}, /* %V */
                    211:        {NULL, NULL}, /* Ac */
                    212:        {NULL, NULL}, /* Ao */
                    213:        {NULL, NULL}, /* Aq */
                    214:        {NULL, NULL}, /* At */
                    215:        {NULL, NULL}, /* Bc */
                    216:        {NULL, NULL}, /* Bf */
                    217:        {NULL, NULL}, /* Bo */
                    218:        {NULL, NULL}, /* Bq */
                    219:        {NULL, NULL}, /* Bsx */
                    220:        {NULL, NULL}, /* Bx */
                    221:        {NULL, NULL}, /* Db */
                    222:        {NULL, NULL}, /* Dc */
                    223:        {NULL, NULL}, /* Do */
                    224:        {NULL, NULL}, /* Dq */
                    225:        {NULL, NULL}, /* Ec */
                    226:        {NULL, NULL}, /* Ef */
                    227:        {NULL, NULL}, /* Em */
                    228:        {NULL, NULL}, /* Eo */
                    229:        {NULL, NULL}, /* Fx */
                    230:        {NULL, NULL}, /* Ms */
                    231:        {NULL, NULL}, /* No */
1.31      kristaps  232:        {mdoc_ns_pre, NULL}, /* Ns */
1.29      kristaps  233:        {NULL, NULL}, /* Nx */
                    234:        {NULL, NULL}, /* Ox */
                    235:        {NULL, NULL}, /* Pc */
                    236:        {NULL, NULL}, /* Pf */
                    237:        {NULL, NULL}, /* Po */
                    238:        {NULL, NULL}, /* Pq */
                    239:        {NULL, NULL}, /* Qc */
                    240:        {NULL, NULL}, /* Ql */
                    241:        {NULL, NULL}, /* Qo */
                    242:        {NULL, NULL}, /* Qq */
                    243:        {NULL, NULL}, /* Re */
                    244:        {NULL, NULL}, /* Rs */
                    245:        {NULL, NULL}, /* Sc */
                    246:        {NULL, NULL}, /* So */
                    247:        {NULL, NULL}, /* Sq */
                    248:        {NULL, NULL}, /* Sm */
                    249:        {NULL, NULL}, /* Sx */
                    250:        {NULL, NULL}, /* Sy */
                    251:        {NULL, NULL}, /* Tn */
                    252:        {NULL, NULL}, /* Ux */
                    253:        {NULL, NULL}, /* Xc */
                    254:        {NULL, NULL}, /* Xo */
                    255:        {NULL, NULL}, /* Fo */
                    256:        {NULL, NULL}, /* Fc */
                    257:        {NULL, NULL}, /* Oo */
                    258:        {NULL, NULL}, /* Oc */
                    259:        {NULL, NULL}, /* Bk */
                    260:        {NULL, NULL}, /* Ek */
                    261:        {NULL, NULL}, /* Bt */
                    262:        {NULL, NULL}, /* Hf */
                    263:        {NULL, NULL}, /* Fr */
                    264:        {NULL, NULL}, /* Ud */
                    265:        {NULL, NULL}, /* Lb */
                    266:        {NULL, NULL}, /* Lp */
                    267:        {NULL, NULL}, /* Lk */
                    268:        {NULL, NULL}, /* Mt */
                    269:        {NULL, NULL}, /* Brq */
                    270:        {NULL, NULL}, /* Bro */
                    271:        {NULL, NULL}, /* Brc */
                    272:        {NULL, NULL}, /* %C */
                    273:        {NULL, NULL}, /* Es */
                    274:        {NULL, NULL}, /* En */
                    275:        {NULL, NULL}, /* Dx */
                    276:        {NULL, NULL}, /* %Q */
                    277:        {NULL, NULL}, /* br */
                    278:        {NULL, NULL}, /* sp */
                    279: };
1.10      kristaps  280:
1.30      kristaps  281: void
1.29      kristaps  282: html_mdoc(void *arg, const struct mdoc *m)
1.10      kristaps  283: {
1.29      kristaps  284:        struct html     *h;
1.30      kristaps  285:        struct tag      *t;
1.10      kristaps  286:
1.29      kristaps  287:        h = (struct html *)arg;
1.10      kristaps  288:
1.29      kristaps  289:        print_gen_doctype(h);
1.30      kristaps  290:        t = print_otag(h, TAG_HTML, 0, NULL);
1.29      kristaps  291:        print_mdoc(mdoc_meta(m), mdoc_node(m), h);
1.30      kristaps  292:        print_tagq(h, t);
                    293:
1.29      kristaps  294:        printf("\n");
1.10      kristaps  295: }
                    296:
1.30      kristaps  297: void
1.29      kristaps  298: html_man(void *arg, const struct man *m)
1.10      kristaps  299: {
1.29      kristaps  300:        struct html     *h;
1.30      kristaps  301:        struct tag      *t;
1.10      kristaps  302:
1.29      kristaps  303:        h = (struct html *)arg;
1.10      kristaps  304:
1.29      kristaps  305:        print_gen_doctype(h);
1.30      kristaps  306:        t = print_otag(h, TAG_HTML, 0, NULL);
1.29      kristaps  307:        print_man(man_meta(m), man_node(m), h);
1.30      kristaps  308:        print_tagq(h, t);
                    309:
1.29      kristaps  310:        printf("\n");
1.10      kristaps  311: }
                    312:
1.29      kristaps  313: void *
                    314: html_alloc(void)
1.10      kristaps  315: {
1.30      kristaps  316:        struct html     *h;
                    317:
                    318:        if (NULL == (h = calloc(1, sizeof(struct html))))
                    319:                return(NULL);
1.10      kristaps  320:
1.30      kristaps  321:        SLIST_INIT(&h->stack);
1.32    ! kristaps  322:        if (NULL == (h->symtab = chars_init(CHARS_HTML))) {
        !           323:                free(h);
        !           324:                return(NULL);
        !           325:        }
1.30      kristaps  326:        return(h);
1.29      kristaps  327: }
1.10      kristaps  328:
1.29      kristaps  329: void
                    330: html_free(void *p)
                    331: {
1.30      kristaps  332:        struct tag      *tag;
                    333:        struct html     *h;
                    334:
                    335:        h = (struct html *)p;
1.10      kristaps  336:
1.30      kristaps  337:        while ( ! SLIST_EMPTY(&h->stack)) {
                    338:                tag = SLIST_FIRST(&h->stack);
                    339:                SLIST_REMOVE_HEAD(&h->stack, entry);
                    340:                free(tag);
                    341:        }
                    342:        free(h);
1.10      kristaps  343: }
1.2       kristaps  344:
1.29      kristaps  345: static void
                    346: print_mdoc(MDOC_ARGS)
1.4       kristaps  347: {
1.30      kristaps  348:        struct tag      *t;
1.4       kristaps  349:
1.30      kristaps  350:        t = print_otag(h, TAG_HEAD, 0, NULL);
1.29      kristaps  351:        print_mdoc_head(m, n, h);
1.30      kristaps  352:        print_tagq(h, t);
                    353:
                    354:        t = print_otag(h, TAG_BODY, 0, NULL);
                    355:        print_mdoc_title(m, n, h);
1.29      kristaps  356:        print_mdoc_node(m, n, h);
1.30      kristaps  357:        print_tagq(h, t);
1.29      kristaps  358: }
1.4       kristaps  359:
1.29      kristaps  360: static void
                    361: print_gen_head(struct html *h)
                    362: {
                    363:        struct htmlpair  meta0[2];
                    364:        struct htmlpair  meta1[2];
                    365:        struct htmlpair  link[4];
                    366:
                    367:        meta0[0].key = ATTR_HTTPEQUIV;
                    368:        meta0[0].val = "Content-Type";
                    369:        meta0[1].key = ATTR_CONTENT;
                    370:        meta0[1].val = "text/html; charest-utf-8";
                    371:
                    372:        meta1[0].key = ATTR_NAME;
                    373:        meta1[0].val = "resource-type";
                    374:        meta1[1].key = ATTR_CONTENT;
                    375:        meta1[1].val = "document";
                    376:
                    377:        link[0].key = ATTR_REL;
                    378:        link[0].val = "stylesheet";
                    379:        link[1].key = ATTR_HREF;
1.30      kristaps  380:        link[1].val = "style.css"; /* XXX */
1.29      kristaps  381:        link[2].key = ATTR_TYPE;
                    382:        link[2].val = "text/css";
                    383:        link[3].key = ATTR_MEDIA;
                    384:        link[3].val = "all";
                    385:
                    386:        print_otag(h, TAG_META, 2, meta0);
                    387:        print_otag(h, TAG_META, 2, meta1);
                    388:        print_otag(h, TAG_LINK, 4, link);
1.4       kristaps  389: }
                    390:
1.30      kristaps  391: /* ARGSUSED */
1.29      kristaps  392: static void
                    393: print_mdoc_head(MDOC_ARGS)
1.18      kristaps  394: {
                    395:
1.29      kristaps  396:        print_gen_head(h);
                    397:        print_otag(h, TAG_TITLE, 0, NULL);
1.32    ! kristaps  398:        print_encode(h, m->title);
1.2       kristaps  399: }
                    400:
1.30      kristaps  401: /* ARGSUSED */
1.29      kristaps  402: static void
1.30      kristaps  403: print_mdoc_title(MDOC_ARGS)
1.2       kristaps  404: {
                    405:
1.30      kristaps  406:        /* TODO */
1.2       kristaps  407: }
                    408:
1.29      kristaps  409: static void
                    410: print_mdoc_node(MDOC_ARGS)
1.2       kristaps  411: {
1.29      kristaps  412:        int              child;
1.30      kristaps  413:        struct tag      *t;
1.8       kristaps  414:
1.29      kristaps  415:        child = 1;
1.30      kristaps  416:        t = SLIST_FIRST(&h->stack);
1.8       kristaps  417:
1.29      kristaps  418:        switch (n->type) {
                    419:        case (MDOC_ROOT):
                    420:                child = mdoc_root_pre(m, n, h);
1.7       kristaps  421:                break;
1.29      kristaps  422:        case (MDOC_TEXT):
                    423:                print_text(h, n->string);
1.7       kristaps  424:                break;
1.3       kristaps  425:        default:
1.29      kristaps  426:                if (mdocs[n->tok].pre)
                    427:                        child = (*mdocs[n->tok].pre)(m, n, h);
1.3       kristaps  428:                break;
1.2       kristaps  429:        }
                    430:
1.29      kristaps  431:        if (child && n->child)
                    432:                print_mdoc_node(m, n->child, h);
1.8       kristaps  433:
1.30      kristaps  434:        print_stagq(h, t);
                    435:
1.29      kristaps  436:        switch (n->type) {
                    437:        case (MDOC_ROOT):
1.7       kristaps  438:                break;
1.29      kristaps  439:        case (MDOC_TEXT):
1.7       kristaps  440:                break;
1.3       kristaps  441:        default:
1.29      kristaps  442:                if (mdocs[n->tok].post)
                    443:                        (*mdocs[n->tok].post)(m, n, h);
1.3       kristaps  444:                break;
                    445:        }
1.2       kristaps  446:
1.29      kristaps  447:        if (n->next)
                    448:                print_mdoc_node(m, n->next, h);
1.2       kristaps  449: }
                    450:
1.29      kristaps  451: static void
                    452: print_man(MAN_ARGS)
1.9       kristaps  453: {
1.30      kristaps  454:        struct tag      *t;
1.9       kristaps  455:
1.30      kristaps  456:        t = print_otag(h, TAG_HEAD, 0, NULL);
1.29      kristaps  457:        print_man_head(m, n, h);
1.30      kristaps  458:        print_tagq(h, t);
                    459:
                    460:        t = print_otag(h, TAG_BODY, 0, NULL);
1.29      kristaps  461:        print_man_body(m, n, h);
1.30      kristaps  462:        print_tagq(h, t);
1.9       kristaps  463: }
                    464:
1.30      kristaps  465: /* ARGSUSED */
1.9       kristaps  466: static void
1.29      kristaps  467: print_man_head(MAN_ARGS)
1.9       kristaps  468: {
                    469:
1.29      kristaps  470:        print_gen_head(h);
                    471:        print_otag(h, TAG_TITLE, 0, NULL);
1.32    ! kristaps  472:        print_encode(h, m->title);
1.29      kristaps  473: }
1.9       kristaps  474:
1.30      kristaps  475: /* ARGSUSED */
1.29      kristaps  476: static void
                    477: print_man_body(MAN_ARGS)
                    478: {
1.30      kristaps  479:
                    480:        /* TODO */
1.9       kristaps  481: }
                    482:
1.32    ! kristaps  483: static void
        !           484: print_spec(struct html *h, const char *p, int len)
        !           485: {
        !           486:        const char      *rhs;
        !           487:        int              i;
        !           488:        size_t           sz;
        !           489:
        !           490:        rhs = chars_a2ascii(h->symtab, p, (size_t)len, &sz);
        !           491:
        !           492:        if (NULL == rhs)
        !           493:                return;
        !           494:        for (i = 0; i < (int)sz; i++)
        !           495:                putchar(rhs[i]);
        !           496: }
        !           497:
        !           498: static void
        !           499: print_res(struct html *h, const char *p, int len)
        !           500: {
        !           501:        const char      *rhs;
        !           502:        int              i;
        !           503:        size_t           sz;
        !           504:
        !           505:        rhs = chars_a2res(h->symtab, p, (size_t)len, &sz);
        !           506:
        !           507:        if (NULL == rhs)
        !           508:                return;
        !           509:        for (i = 0; i < (int)sz; i++)
        !           510:                putchar(rhs[i]);
        !           511: }
        !           512:
        !           513: static void
        !           514: print_escape(struct html *h, const char **p)
        !           515: {
        !           516:        int              j, type;
        !           517:        const char      *wp;
        !           518:
        !           519:        wp = *p;
        !           520:        type = 1;
        !           521:
        !           522:        if (0 == *(++wp)) {
        !           523:                *p = wp;
        !           524:                return;
        !           525:        }
        !           526:
        !           527:        if ('(' == *wp) {
        !           528:                wp++;
        !           529:                if (0 == *wp || 0 == *(wp + 1)) {
        !           530:                        *p = 0 == *wp ? wp : wp + 1;
        !           531:                        return;
        !           532:                }
        !           533:
        !           534:                print_spec(h, wp, 2);
        !           535:                *p = ++wp;
        !           536:                return;
        !           537:
        !           538:        } else if ('*' == *wp) {
        !           539:                if (0 == *(++wp)) {
        !           540:                        *p = wp;
        !           541:                        return;
        !           542:                }
        !           543:
        !           544:                switch (*wp) {
        !           545:                case ('('):
        !           546:                        wp++;
        !           547:                        if (0 == *wp || 0 == *(wp + 1)) {
        !           548:                                *p = 0 == *wp ? wp : wp + 1;
        !           549:                                return;
        !           550:                        }
        !           551:
        !           552:                        print_res(h, wp, 2);
        !           553:                        *p = ++wp;
        !           554:                        return;
        !           555:                case ('['):
        !           556:                        type = 0;
        !           557:                        break;
        !           558:                default:
        !           559:                        print_res(h, wp, 1);
        !           560:                        *p = wp;
        !           561:                        return;
        !           562:                }
        !           563:
        !           564:        } else if ('f' == *wp) {
        !           565:                if (0 == *(++wp)) {
        !           566:                        *p = wp;
        !           567:                        return;
        !           568:                }
        !           569:
        !           570:                switch (*wp) {
        !           571:                case ('B'):
        !           572:                        /* TODO */
        !           573:                        break;
        !           574:                case ('I'):
        !           575:                        /* TODO */
        !           576:                        break;
        !           577:                case ('P'):
        !           578:                        /* FALLTHROUGH */
        !           579:                case ('R'):
        !           580:                        /* TODO */
        !           581:                        break;
        !           582:                default:
        !           583:                        break;
        !           584:                }
        !           585:
        !           586:                *p = wp;
        !           587:                return;
        !           588:
        !           589:        } else if ('[' != *wp) {
        !           590:                print_spec(h, wp, 1);
        !           591:                *p = wp;
        !           592:                return;
        !           593:        }
        !           594:
        !           595:        wp++;
        !           596:        for (j = 0; *wp && ']' != *wp; wp++, j++)
        !           597:                /* Loop... */ ;
        !           598:
        !           599:        if (0 == *wp) {
        !           600:                *p = wp;
        !           601:                return;
        !           602:        }
        !           603:
        !           604:        if (type)
        !           605:                print_spec(h, wp - j, j);
        !           606:        else
        !           607:                print_res(h, wp - j, j);
        !           608:
        !           609:        *p = wp;
        !           610: }
        !           611:
1.9       kristaps  612:
1.29      kristaps  613: static void
1.32    ! kristaps  614: print_encode(struct html *h, const char *p)
1.29      kristaps  615: {
1.14      kristaps  616:
1.32    ! kristaps  617:        for (; *p; p++) {
        !           618:                if ('\\' != *p) {
        !           619:                        putchar(*p);
        !           620:                        continue;
        !           621:                }
        !           622:                print_escape(h, &p);
        !           623:        }
1.14      kristaps  624: }
                    625:
                    626:
1.30      kristaps  627: static struct tag *
1.29      kristaps  628: print_otag(struct html *h, enum htmltag tag,
                    629:                int sz, const struct htmlpair *p)
1.14      kristaps  630: {
1.29      kristaps  631:        int              i;
1.30      kristaps  632:        struct tag      *t;
                    633:
                    634:        if ( ! (HTML_NOSTACK & htmltags[tag].flags)) {
                    635:                if (NULL == (t = malloc(sizeof(struct tag))))
                    636:                        err(EXIT_FAILURE, "malloc");
                    637:                t->tag = tag;
                    638:                SLIST_INSERT_HEAD(&h->stack, t, entry);
                    639:        } else
                    640:                t = NULL;
1.29      kristaps  641:
                    642:        if ( ! (HTML_NOSPACE & h->flags))
1.30      kristaps  643:                if ( ! (HTML_CLRLINE & htmltags[tag].flags))
1.29      kristaps  644:                        printf(" ");
                    645:
                    646:        printf("<%s", htmltags[tag].name);
                    647:        for (i = 0; i < sz; i++) {
                    648:                printf(" %s=\"", htmlattrs[p[i].key]);
                    649:                assert(p->val);
1.32    ! kristaps  650:                print_encode(h, p[i].val);
1.29      kristaps  651:                printf("\"");
                    652:        }
                    653:        printf(">");
1.14      kristaps  654:
1.29      kristaps  655:        h->flags |= HTML_NOSPACE;
1.30      kristaps  656:        if (HTML_CLRLINE & htmltags[tag].flags)
                    657:                h->flags |= HTML_NEWLINE;
                    658:        else
                    659:                h->flags &= ~HTML_NEWLINE;
1.14      kristaps  660:
1.30      kristaps  661:        return(t);
1.14      kristaps  662: }
                    663:
                    664:
                    665: /* ARGSUSED */
1.29      kristaps  666: static void
                    667: print_ctag(struct html *h, enum htmltag tag)
1.14      kristaps  668: {
                    669:
1.29      kristaps  670:        printf("</%s>", htmltags[tag].name);
1.30      kristaps  671:        if (HTML_CLRLINE & htmltags[tag].flags)
1.29      kristaps  672:                h->flags |= HTML_NOSPACE;
1.30      kristaps  673:        if (HTML_CLRLINE & htmltags[tag].flags)
                    674:                h->flags |= HTML_NEWLINE;
                    675:        else
                    676:                h->flags &= ~HTML_NEWLINE;
1.14      kristaps  677: }
                    678:
                    679:
1.29      kristaps  680: /* ARGSUSED */
                    681: static void
                    682: print_gen_doctype(struct html *h)
1.1       kristaps  683: {
1.29      kristaps  684:
                    685:        printf("<!DOCTYPE HTML PUBLIC \"%s\" \"%s\">\n", DOCTYPE, DTD);
1.1       kristaps  686: }
                    687:
                    688:
1.29      kristaps  689: static void
                    690: print_text(struct html *h, const char *p)
1.1       kristaps  691: {
                    692:
1.29      kristaps  693:        if (*p && 0 == *(p + 1))
                    694:                switch (*p) {
                    695:                case('.'):
                    696:                        /* FALLTHROUGH */
                    697:                case(','):
                    698:                        /* FALLTHROUGH */
                    699:                case(';'):
                    700:                        /* FALLTHROUGH */
                    701:                case(':'):
                    702:                        /* FALLTHROUGH */
                    703:                case('?'):
                    704:                        /* FALLTHROUGH */
                    705:                case('!'):
                    706:                        /* FALLTHROUGH */
                    707:                case(')'):
                    708:                        /* FALLTHROUGH */
                    709:                case(']'):
                    710:                        /* FALLTHROUGH */
                    711:                case('}'):
                    712:                        h->flags |= HTML_NOSPACE;
1.30      kristaps  713:                        break;
1.29      kristaps  714:                default:
                    715:                        break;
                    716:                }
1.1       kristaps  717:
1.29      kristaps  718:        if ( ! (h->flags & HTML_NOSPACE))
                    719:                printf(" ");
1.30      kristaps  720:
1.29      kristaps  721:        h->flags &= ~HTML_NOSPACE;
1.30      kristaps  722:        h->flags &= ~HTML_NEWLINE;
1.1       kristaps  723:
1.29      kristaps  724:        if (p)
1.32    ! kristaps  725:                print_encode(h, p);
1.8       kristaps  726:
1.29      kristaps  727:        if (*p && 0 == *(p + 1))
                    728:                switch (*p) {
                    729:                case('('):
                    730:                        /* FALLTHROUGH */
                    731:                case('['):
                    732:                        /* FALLTHROUGH */
                    733:                case('{'):
                    734:                        h->flags |= HTML_NOSPACE;
1.30      kristaps  735:                        break;
1.29      kristaps  736:                default:
                    737:                        break;
                    738:                }
1.1       kristaps  739: }
1.30      kristaps  740:
                    741:
                    742: static void
                    743: print_tagq(struct html *h, const struct tag *until)
                    744: {
                    745:        struct tag      *tag;
                    746:
                    747:        while ( ! SLIST_EMPTY(&h->stack)) {
                    748:                tag = SLIST_FIRST(&h->stack);
                    749:                print_ctag(h, tag->tag);
                    750:                SLIST_REMOVE_HEAD(&h->stack, entry);
                    751:                free(tag);
                    752:                if (until && tag == until)
                    753:                        return;
                    754:        }
                    755: }
                    756:
                    757:
                    758: static void
                    759: print_stagq(struct html *h, const struct tag *suntil)
                    760: {
                    761:        struct tag      *tag;
                    762:
                    763:        while ( ! SLIST_EMPTY(&h->stack)) {
                    764:                tag = SLIST_FIRST(&h->stack);
                    765:                if (suntil && tag == suntil)
                    766:                        return;
                    767:                print_ctag(h, tag->tag);
                    768:                SLIST_REMOVE_HEAD(&h->stack, entry);
                    769:                free(tag);
                    770:        }
                    771: }
                    772:
                    773:
                    774: /* ARGSUSED */
                    775: static int
                    776: mdoc_root_pre(MDOC_ARGS)
                    777: {
                    778:        struct htmlpair  tag;
                    779:
                    780:        tag.key = ATTR_CLASS;
                    781:        tag.val = "body";
                    782:
                    783:        print_otag(h, TAG_DIV, 1, &tag);
                    784:        return(1);
                    785: }
                    786:
                    787:
                    788: /* ARGSUSED */
                    789: static int
                    790: mdoc_ss_pre(MDOC_ARGS)
                    791: {
                    792:
                    793:        if (MDOC_BODY == n->type)
                    794:                print_otag(h, TAG_P, 0, NULL);
                    795:        if (MDOC_HEAD == n->type)
                    796:                print_otag(h, TAG_H2, 0, NULL);
                    797:        return(1);
                    798: }
                    799:
                    800:
                    801: /* ARGSUSED */
                    802: static int
                    803: mdoc_fl_pre(MDOC_ARGS)
                    804: {
                    805:        struct htmlpair  tag;
                    806:
                    807:        tag.key = ATTR_CLASS;
                    808:        tag.val = "flag";
                    809:
                    810:        print_otag(h, TAG_SPAN, 1, &tag);
                    811:        print_text(h, "\\-");
                    812:        h->flags |= HTML_NOSPACE;
                    813:        return(1);
                    814: }
                    815:
                    816:
                    817: /* ARGSUSED */
                    818: static int
                    819: mdoc_pp_pre(MDOC_ARGS)
                    820: {
                    821:
                    822:        print_otag(h, TAG_BR, 0, NULL);
                    823:        print_otag(h, TAG_BR, 0, NULL);
                    824:        return(0);
                    825: }
                    826:
                    827:
                    828: /* ARGSUSED */
                    829: static int
                    830: mdoc_nd_pre(MDOC_ARGS)
                    831: {
                    832:
                    833:        if (MDOC_BODY == n->type)
1.31      kristaps  834:                print_text(h, "\\(en");
1.30      kristaps  835:        return(1);
                    836: }
                    837:
                    838:
                    839: /* ARGSUSED */
                    840: static int
                    841: mdoc_op_pre(MDOC_ARGS)
                    842: {
                    843:
                    844:        if (MDOC_BODY == n->type) {
                    845:                print_text(h, "\\(lB");
                    846:                h->flags |= HTML_NOSPACE;
                    847:        }
                    848:        return(1);
                    849: }
                    850:
                    851:
                    852: /* ARGSUSED */
                    853: static void
                    854: mdoc_op_post(MDOC_ARGS)
                    855: {
                    856:
                    857:        if (MDOC_BODY != n->type)
                    858:                return;
                    859:        h->flags |= HTML_NOSPACE;
                    860:        print_text(h, "\\(rB");
                    861: }
                    862:
                    863:
                    864: static int
                    865: mdoc_nm_pre(MDOC_ARGS)
                    866: {
                    867:        struct htmlpair class;
                    868:
                    869:        if ( ! (HTML_NEWLINE & h->flags))
                    870:                if (SEC_SYNOPSIS == n->sec)
                    871:                        print_otag(h, TAG_BR, 0, NULL);
                    872:
                    873:        class.key = ATTR_CLASS;
                    874:        class.val = "name";
                    875:
                    876:        print_otag(h, TAG_SPAN, 1, &class);
                    877:        if (NULL == n->child)
                    878:                print_text(h, m->name);
                    879:
                    880:        return(1);
                    881: }
                    882:
                    883:
                    884: /* ARGSUSED */
                    885: static int
                    886: mdoc_sh_pre(MDOC_ARGS)
                    887: {
                    888:
                    889:        if (MDOC_BODY == n->type)
                    890:                print_otag(h, TAG_P, 0, NULL);
                    891:        if (MDOC_HEAD == n->type)
                    892:                print_otag(h, TAG_H1, 0, NULL);
                    893:        return(1);
                    894: }
                    895:
                    896:
                    897: /* ARGSUSED */
                    898: static int
                    899: mdoc_xr_pre(MDOC_ARGS)
                    900: {
                    901:        struct htmlpair tag;
                    902:
                    903:        tag.key = ATTR_HREF;
                    904:        tag.val = "#"; /* TODO */
                    905:
                    906:        print_otag(h, TAG_A, 1, &tag);
                    907:
                    908:        n = n->child;
                    909:        print_text(h, n->string);
                    910:        if (NULL == (n = n->next))
                    911:                return(0);
                    912:
                    913:        h->flags |= HTML_NOSPACE;
                    914:        print_text(h, "(");
                    915:        h->flags |= HTML_NOSPACE;
                    916:        print_text(h, n->string);
                    917:        h->flags |= HTML_NOSPACE;
                    918:        print_text(h, ")");
                    919:
                    920:        return(0);
                    921: }
1.31      kristaps  922:
                    923:
                    924: /* ARGSUSED */
                    925: static int
                    926: mdoc_ns_pre(MDOC_ARGS)
                    927: {
                    928:
                    929:        h->flags |= HTML_NOSPACE;
                    930:        return(1);
                    931: }
                    932:
                    933:
                    934: /* ARGSUSED */
                    935: static int
                    936: mdoc_ar_pre(MDOC_ARGS)
                    937: {
                    938:        struct htmlpair tag;
                    939:
                    940:        tag.key = ATTR_CLASS;
                    941:        tag.val = "arg";
                    942:
                    943:        print_otag(h, TAG_SPAN, 1, &tag);
                    944:        return(1);
                    945: }

CVSweb