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

Annotation of mandoc/html.c, Revision 1.30

1.30    ! kristaps    1: /*     $Id: html.c,v 1.29 2009/09/16 09:41:24 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.29      kristaps   24: #include "mdoc.h"
                     25: #include "man.h"
1.2       kristaps   26:
1.29      kristaps   27: #define        DOCTYPE         "-//W3C//DTD HTML 4.01//EN"
                     28: #define        DTD             "http://www.w3.org/TR/html4/strict.dtd"
1.8       kristaps   29:
1.29      kristaps   30: enum   htmltag {
                     31:        TAG_HTML,
                     32:        TAG_HEAD,
                     33:        TAG_BODY,
                     34:        TAG_META,
                     35:        TAG_TITLE,
                     36:        TAG_DIV,
                     37:        TAG_H1,
                     38:        TAG_H2,
                     39:        TAG_P,
                     40:        TAG_SPAN,
                     41:        TAG_LINK,
1.30    ! kristaps   42:        TAG_BR,
        !            43:        TAG_A,
1.29      kristaps   44:        TAG_MAX
1.7       kristaps   45: };
                     46:
1.29      kristaps   47: enum   htmlattr {
                     48:        ATTR_HTTPEQUIV,
                     49:        ATTR_CONTENT,
                     50:        ATTR_NAME,
                     51:        ATTR_REL,
                     52:        ATTR_HREF,
                     53:        ATTR_TYPE,
                     54:        ATTR_MEDIA,
                     55:        ATTR_CLASS,
                     56:        ATTR_MAX
1.7       kristaps   57: };
                     58:
1.29      kristaps   59: struct htmldata {
                     60:        char             *name;
                     61:        int               flags;
1.30    ! kristaps   62: #define        HTML_CLRLINE     (1 << 0)
        !            63: #define        HTML_NOSTACK     (1 << 1)
1.29      kristaps   64: };
1.7       kristaps   65:
1.29      kristaps   66: static const struct htmldata htmltags[TAG_MAX] = {
1.30    ! kristaps   67:        {"html",        HTML_CLRLINE}, /* TAG_HTML */
        !            68:        {"head",        HTML_CLRLINE}, /* TAG_HEAD */
        !            69:        {"body",        HTML_CLRLINE}, /* TAG_BODY */
        !            70:        {"meta",        HTML_CLRLINE | HTML_NOSTACK}, /* TAG_META */
        !            71:        {"title",       HTML_CLRLINE | HTML_NOSTACK}, /* TAG_TITLE */
        !            72:        {"div",         HTML_CLRLINE}, /* TAG_DIV */
1.29      kristaps   73:        {"h1",          0}, /* TAG_H1 */
                     74:        {"h2",          0}, /* TAG_H2 */
1.30    ! kristaps   75:        {"p",           HTML_CLRLINE}, /* TAG_P */
1.29      kristaps   76:        {"span",        0}, /* TAG_SPAN */
1.30    ! kristaps   77:        {"link",        HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */
        !            78:        {"br",          HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */
        !            79:        {"a",           0}, /* TAG_A */
1.29      kristaps   80: };
1.10      kristaps   81:
1.29      kristaps   82: static const char       *const htmlattrs[ATTR_MAX] = {
                     83:        "http-equiv",
                     84:        "content",
                     85:        "name",
                     86:        "rel",
                     87:        "href",
                     88:        "type",
                     89:        "media",
                     90:        "class"
                     91: };
1.10      kristaps   92:
1.29      kristaps   93: struct htmlpair {
                     94:        enum htmlattr     key;
                     95:        char             *val;
                     96: };
1.10      kristaps   97:
1.30    ! kristaps   98: struct tag {
        !            99:        enum htmltag      tag;
        !           100:        SLIST_ENTRY(tag)  entry;
        !           101: };
        !           102:
        !           103: SLIST_HEAD(tagq, tag);
        !           104:
1.29      kristaps  105: struct html {
                    106:        int               flags;
                    107: #define        HTML_NOSPACE     (1 << 0)
1.30    ! kristaps  108: #define        HTML_NEWLINE     (1 << 1)
        !           109:        struct tagq       stack;
1.29      kristaps  110: };
1.10      kristaps  111:
1.29      kristaps  112: #define        MDOC_ARGS         const struct mdoc_meta *m, \
                    113:                          const struct mdoc_node *n, \
                    114:                          struct html *h
                    115: #define        MAN_ARGS          const struct man_meta *m, \
                    116:                          const struct man_node *n, \
                    117:                          struct html *h
                    118: struct htmlmdoc {
                    119:        int             (*pre)(MDOC_ARGS);
                    120:        void            (*post)(MDOC_ARGS);
                    121: };
1.13      kristaps  122:
1.29      kristaps  123: static void              print_gen_doctype(struct html *);
                    124: static void              print_gen_head(struct html *);
                    125: static void              print_mdoc(MDOC_ARGS);
                    126: static void              print_mdoc_head(MDOC_ARGS);
1.30    ! kristaps  127: static void              print_mdoc_title(MDOC_ARGS);
1.29      kristaps  128: static void              print_mdoc_node(MDOC_ARGS);
                    129: static void              print_man(MAN_ARGS);
                    130: static void              print_man_head(MAN_ARGS);
                    131: static void              print_man_body(MAN_ARGS);
1.30    ! kristaps  132: static struct tag       *print_otag(struct html *, enum htmltag,
1.29      kristaps  133:                                int, const struct htmlpair *);
1.30    ! kristaps  134: static void              print_tagq(struct html *, const struct tag *);
        !           135: static void              print_stagq(struct html *, const struct tag *);
1.29      kristaps  136: static void              print_ctag(struct html *, enum htmltag);
                    137: static void              print_encode(const char *);
                    138: static void              print_text(struct html *, const char *);
                    139: static int               mdoc_root_pre(MDOC_ARGS);
                    140:
1.30    ! kristaps  141: static int               mdoc_fl_pre(MDOC_ARGS);
1.29      kristaps  142: static int               mdoc_nd_pre(MDOC_ARGS);
                    143: static int               mdoc_nm_pre(MDOC_ARGS);
1.30    ! kristaps  144: static int               mdoc_op_pre(MDOC_ARGS);
        !           145: static void              mdoc_op_post(MDOC_ARGS);
1.29      kristaps  146: static int               mdoc_pp_pre(MDOC_ARGS);
                    147: static int               mdoc_sh_pre(MDOC_ARGS);
                    148: static int               mdoc_ss_pre(MDOC_ARGS);
1.30    ! kristaps  149: static int               mdoc_xr_pre(MDOC_ARGS);
1.29      kristaps  150:
                    151: static const struct htmlmdoc mdocs[MDOC_MAX] = {
                    152:        {NULL, NULL}, /* Ap */
                    153:        {NULL, NULL}, /* Dd */
                    154:        {NULL, NULL}, /* Dt */
                    155:        {NULL, NULL}, /* Os */
1.30    ! kristaps  156:        {mdoc_sh_pre, NULL }, /* Sh */
        !           157:        {mdoc_ss_pre, NULL }, /* Ss */
1.29      kristaps  158:        {mdoc_pp_pre, NULL}, /* Pp */
                    159:        {NULL, NULL}, /* D1 */
                    160:        {NULL, NULL}, /* Dl */
                    161:        {NULL, NULL}, /* Bd */
                    162:        {NULL, NULL}, /* Ed */
                    163:        {NULL, NULL}, /* Bl */
                    164:        {NULL, NULL}, /* El */
                    165:        {NULL, NULL}, /* It */
                    166:        {NULL, NULL}, /* Ad */
                    167:        {NULL, NULL}, /* An */
                    168:        {NULL, NULL}, /* Ar */
                    169:        {NULL, NULL}, /* Cd */
                    170:        {NULL, NULL}, /* Cm */
                    171:        {NULL, NULL}, /* Dv */
                    172:        {NULL, NULL}, /* Er */
                    173:        {NULL, NULL}, /* Ev */
                    174:        {NULL, NULL}, /* Ex */
                    175:        {NULL, NULL}, /* Fa */
                    176:        {NULL, NULL}, /* Fd */
1.30    ! kristaps  177:        {mdoc_fl_pre, NULL}, /* Fl */
1.29      kristaps  178:        {NULL, NULL}, /* Fn */
                    179:        {NULL, NULL}, /* Ft */
                    180:        {NULL, NULL}, /* Ic */
                    181:        {NULL, NULL}, /* In */
                    182:        {NULL, NULL}, /* Li */
                    183:        {mdoc_nd_pre, NULL}, /* Nd */
1.30    ! kristaps  184:        {mdoc_nm_pre, NULL}, /* Nm */
        !           185:        {mdoc_op_pre, mdoc_op_post}, /* Op */
1.29      kristaps  186:        {NULL, NULL}, /* Ot */
                    187:        {NULL, NULL}, /* Pa */
                    188:        {NULL, NULL}, /* Rv */
                    189:        {NULL, NULL}, /* St */
                    190:        {NULL, NULL}, /* Va */
                    191:        {NULL, NULL}, /* Vt */
1.30    ! kristaps  192:        {mdoc_xr_pre, NULL}, /* Xr */
1.29      kristaps  193:        {NULL, NULL}, /* %A */
                    194:        {NULL, NULL}, /* %B */
                    195:        {NULL, NULL}, /* %D */
                    196:        {NULL, NULL}, /* %I */
                    197:        {NULL, NULL}, /* %J */
                    198:        {NULL, NULL}, /* %N */
                    199:        {NULL, NULL}, /* %O */
                    200:        {NULL, NULL}, /* %P */
                    201:        {NULL, NULL}, /* %R */
                    202:        {NULL, NULL}, /* %T */
                    203:        {NULL, NULL}, /* %V */
                    204:        {NULL, NULL}, /* Ac */
                    205:        {NULL, NULL}, /* Ao */
                    206:        {NULL, NULL}, /* Aq */
                    207:        {NULL, NULL}, /* At */
                    208:        {NULL, NULL}, /* Bc */
                    209:        {NULL, NULL}, /* Bf */
                    210:        {NULL, NULL}, /* Bo */
                    211:        {NULL, NULL}, /* Bq */
                    212:        {NULL, NULL}, /* Bsx */
                    213:        {NULL, NULL}, /* Bx */
                    214:        {NULL, NULL}, /* Db */
                    215:        {NULL, NULL}, /* Dc */
                    216:        {NULL, NULL}, /* Do */
                    217:        {NULL, NULL}, /* Dq */
                    218:        {NULL, NULL}, /* Ec */
                    219:        {NULL, NULL}, /* Ef */
                    220:        {NULL, NULL}, /* Em */
                    221:        {NULL, NULL}, /* Eo */
                    222:        {NULL, NULL}, /* Fx */
                    223:        {NULL, NULL}, /* Ms */
                    224:        {NULL, NULL}, /* No */
                    225:        {NULL, NULL}, /* Ns */
                    226:        {NULL, NULL}, /* Nx */
                    227:        {NULL, NULL}, /* Ox */
                    228:        {NULL, NULL}, /* Pc */
                    229:        {NULL, NULL}, /* Pf */
                    230:        {NULL, NULL}, /* Po */
                    231:        {NULL, NULL}, /* Pq */
                    232:        {NULL, NULL}, /* Qc */
                    233:        {NULL, NULL}, /* Ql */
                    234:        {NULL, NULL}, /* Qo */
                    235:        {NULL, NULL}, /* Qq */
                    236:        {NULL, NULL}, /* Re */
                    237:        {NULL, NULL}, /* Rs */
                    238:        {NULL, NULL}, /* Sc */
                    239:        {NULL, NULL}, /* So */
                    240:        {NULL, NULL}, /* Sq */
                    241:        {NULL, NULL}, /* Sm */
                    242:        {NULL, NULL}, /* Sx */
                    243:        {NULL, NULL}, /* Sy */
                    244:        {NULL, NULL}, /* Tn */
                    245:        {NULL, NULL}, /* Ux */
                    246:        {NULL, NULL}, /* Xc */
                    247:        {NULL, NULL}, /* Xo */
                    248:        {NULL, NULL}, /* Fo */
                    249:        {NULL, NULL}, /* Fc */
                    250:        {NULL, NULL}, /* Oo */
                    251:        {NULL, NULL}, /* Oc */
                    252:        {NULL, NULL}, /* Bk */
                    253:        {NULL, NULL}, /* Ek */
                    254:        {NULL, NULL}, /* Bt */
                    255:        {NULL, NULL}, /* Hf */
                    256:        {NULL, NULL}, /* Fr */
                    257:        {NULL, NULL}, /* Ud */
                    258:        {NULL, NULL}, /* Lb */
                    259:        {NULL, NULL}, /* Lp */
                    260:        {NULL, NULL}, /* Lk */
                    261:        {NULL, NULL}, /* Mt */
                    262:        {NULL, NULL}, /* Brq */
                    263:        {NULL, NULL}, /* Bro */
                    264:        {NULL, NULL}, /* Brc */
                    265:        {NULL, NULL}, /* %C */
                    266:        {NULL, NULL}, /* Es */
                    267:        {NULL, NULL}, /* En */
                    268:        {NULL, NULL}, /* Dx */
                    269:        {NULL, NULL}, /* %Q */
                    270:        {NULL, NULL}, /* br */
                    271:        {NULL, NULL}, /* sp */
                    272: };
1.10      kristaps  273:
                    274:
1.30    ! kristaps  275: void
1.29      kristaps  276: html_mdoc(void *arg, const struct mdoc *m)
1.10      kristaps  277: {
1.29      kristaps  278:        struct html     *h;
1.30    ! kristaps  279:        struct tag      *t;
1.10      kristaps  280:
1.29      kristaps  281:        h = (struct html *)arg;
1.10      kristaps  282:
1.29      kristaps  283:        print_gen_doctype(h);
1.30    ! kristaps  284:        t = print_otag(h, TAG_HTML, 0, NULL);
1.29      kristaps  285:        print_mdoc(mdoc_meta(m), mdoc_node(m), h);
1.30    ! kristaps  286:        print_tagq(h, t);
        !           287:
1.29      kristaps  288:        printf("\n");
1.10      kristaps  289: }
                    290:
                    291:
1.30    ! kristaps  292: void
1.29      kristaps  293: html_man(void *arg, const struct man *m)
1.10      kristaps  294: {
1.29      kristaps  295:        struct html     *h;
1.30    ! kristaps  296:        struct tag      *t;
1.10      kristaps  297:
1.29      kristaps  298:        h = (struct html *)arg;
1.10      kristaps  299:
1.29      kristaps  300:        print_gen_doctype(h);
1.30    ! kristaps  301:        t = print_otag(h, TAG_HTML, 0, NULL);
1.29      kristaps  302:        print_man(man_meta(m), man_node(m), h);
1.30    ! kristaps  303:        print_tagq(h, t);
        !           304:
1.29      kristaps  305:        printf("\n");
1.10      kristaps  306: }
                    307:
                    308:
1.29      kristaps  309: void *
                    310: html_alloc(void)
1.10      kristaps  311: {
1.30    ! kristaps  312:        struct html     *h;
        !           313:
        !           314:        if (NULL == (h = calloc(1, sizeof(struct html))))
        !           315:                return(NULL);
1.10      kristaps  316:
1.30    ! kristaps  317:        SLIST_INIT(&h->stack);
        !           318:        return(h);
1.29      kristaps  319: }
1.10      kristaps  320:
1.13      kristaps  321:
1.29      kristaps  322: void
                    323: html_free(void *p)
                    324: {
1.30    ! kristaps  325:        struct tag      *tag;
        !           326:        struct html     *h;
        !           327:
        !           328:        h = (struct html *)p;
1.10      kristaps  329:
1.30    ! kristaps  330:        while ( ! SLIST_EMPTY(&h->stack)) {
        !           331:                tag = SLIST_FIRST(&h->stack);
        !           332:                SLIST_REMOVE_HEAD(&h->stack, entry);
        !           333:                free(tag);
        !           334:        }
        !           335:        free(h);
1.10      kristaps  336: }
1.2       kristaps  337:
                    338:
1.29      kristaps  339: static void
                    340: print_mdoc(MDOC_ARGS)
1.4       kristaps  341: {
1.30    ! kristaps  342:        struct tag      *t;
1.4       kristaps  343:
1.30    ! kristaps  344:        t = print_otag(h, TAG_HEAD, 0, NULL);
1.29      kristaps  345:        print_mdoc_head(m, n, h);
1.30    ! kristaps  346:        print_tagq(h, t);
        !           347:
        !           348:        t = print_otag(h, TAG_BODY, 0, NULL);
        !           349:        print_mdoc_title(m, n, h);
1.29      kristaps  350:        print_mdoc_node(m, n, h);
1.30    ! kristaps  351:        print_tagq(h, t);
1.29      kristaps  352: }
1.4       kristaps  353:
                    354:
1.29      kristaps  355: static void
                    356: print_gen_head(struct html *h)
                    357: {
                    358:        struct htmlpair  meta0[2];
                    359:        struct htmlpair  meta1[2];
                    360:        struct htmlpair  link[4];
                    361:
                    362:        meta0[0].key = ATTR_HTTPEQUIV;
                    363:        meta0[0].val = "Content-Type";
                    364:        meta0[1].key = ATTR_CONTENT;
                    365:        meta0[1].val = "text/html; charest-utf-8";
                    366:
                    367:        meta1[0].key = ATTR_NAME;
                    368:        meta1[0].val = "resource-type";
                    369:        meta1[1].key = ATTR_CONTENT;
                    370:        meta1[1].val = "document";
                    371:
                    372:        link[0].key = ATTR_REL;
                    373:        link[0].val = "stylesheet";
                    374:        link[1].key = ATTR_HREF;
1.30    ! kristaps  375:        link[1].val = "style.css"; /* XXX */
1.29      kristaps  376:        link[2].key = ATTR_TYPE;
                    377:        link[2].val = "text/css";
                    378:        link[3].key = ATTR_MEDIA;
                    379:        link[3].val = "all";
                    380:
                    381:        print_otag(h, TAG_META, 2, meta0);
                    382:        print_otag(h, TAG_META, 2, meta1);
                    383:        print_otag(h, TAG_LINK, 4, link);
1.4       kristaps  384: }
                    385:
                    386:
1.30    ! kristaps  387: /* ARGSUSED */
1.29      kristaps  388: static void
                    389: print_mdoc_head(MDOC_ARGS)
1.18      kristaps  390: {
                    391:
1.29      kristaps  392:        print_gen_head(h);
                    393:        print_otag(h, TAG_TITLE, 0, NULL);
                    394:        print_encode(m->title);
1.2       kristaps  395: }
                    396:
                    397:
1.30    ! kristaps  398: /* ARGSUSED */
1.29      kristaps  399: static void
1.30    ! kristaps  400: print_mdoc_title(MDOC_ARGS)
1.2       kristaps  401: {
                    402:
1.30    ! kristaps  403:        /* TODO */
1.2       kristaps  404: }
                    405:
                    406:
1.29      kristaps  407: static void
                    408: print_mdoc_node(MDOC_ARGS)
1.2       kristaps  409: {
1.29      kristaps  410:        int              child;
1.30    ! kristaps  411:        struct tag      *t;
1.8       kristaps  412:
1.29      kristaps  413:        child = 1;
1.30    ! kristaps  414:        t = SLIST_FIRST(&h->stack);
1.8       kristaps  415:
1.29      kristaps  416:        switch (n->type) {
                    417:        case (MDOC_ROOT):
                    418:                child = mdoc_root_pre(m, n, h);
1.7       kristaps  419:                break;
1.29      kristaps  420:        case (MDOC_TEXT):
                    421:                print_text(h, n->string);
1.7       kristaps  422:                break;
1.3       kristaps  423:        default:
1.29      kristaps  424:                if (mdocs[n->tok].pre)
                    425:                        child = (*mdocs[n->tok].pre)(m, n, h);
1.3       kristaps  426:                break;
1.2       kristaps  427:        }
                    428:
1.29      kristaps  429:        if (child && n->child)
                    430:                print_mdoc_node(m, n->child, h);
1.8       kristaps  431:
1.30    ! kristaps  432:        print_stagq(h, t);
        !           433:
1.29      kristaps  434:        switch (n->type) {
                    435:        case (MDOC_ROOT):
1.7       kristaps  436:                break;
1.29      kristaps  437:        case (MDOC_TEXT):
1.7       kristaps  438:                break;
1.3       kristaps  439:        default:
1.29      kristaps  440:                if (mdocs[n->tok].post)
                    441:                        (*mdocs[n->tok].post)(m, n, h);
1.3       kristaps  442:                break;
                    443:        }
1.2       kristaps  444:
1.29      kristaps  445:        if (n->next)
                    446:                print_mdoc_node(m, n->next, h);
1.2       kristaps  447: }
                    448:
                    449:
1.29      kristaps  450: static void
                    451: print_man(MAN_ARGS)
1.9       kristaps  452: {
1.30    ! kristaps  453:        struct tag      *t;
1.9       kristaps  454:
1.30    ! kristaps  455:        t = print_otag(h, TAG_HEAD, 0, NULL);
1.29      kristaps  456:        print_man_head(m, n, h);
1.30    ! kristaps  457:        print_tagq(h, t);
        !           458:
        !           459:        t = print_otag(h, TAG_BODY, 0, NULL);
1.29      kristaps  460:        print_man_body(m, n, h);
1.30    ! kristaps  461:        print_tagq(h, t);
1.9       kristaps  462: }
                    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);
                    472:        print_encode(m->title);
                    473: }
1.9       kristaps  474:
                    475:
1.30    ! kristaps  476: /* ARGSUSED */
1.29      kristaps  477: static void
                    478: print_man_body(MAN_ARGS)
                    479: {
1.30    ! kristaps  480:
        !           481:        /* TODO */
1.9       kristaps  482: }
                    483:
                    484:
1.29      kristaps  485: static void
                    486: print_encode(const char *p)
                    487: {
1.14      kristaps  488:
1.29      kristaps  489:        printf("%s", p); /* XXX */
1.14      kristaps  490: }
                    491:
                    492:
1.30    ! kristaps  493: static struct tag *
1.29      kristaps  494: print_otag(struct html *h, enum htmltag tag,
                    495:                int sz, const struct htmlpair *p)
1.14      kristaps  496: {
1.29      kristaps  497:        int              i;
1.30    ! kristaps  498:        struct tag      *t;
        !           499:
        !           500:        if ( ! (HTML_NOSTACK & htmltags[tag].flags)) {
        !           501:                if (NULL == (t = malloc(sizeof(struct tag))))
        !           502:                        err(EXIT_FAILURE, "malloc");
        !           503:                t->tag = tag;
        !           504:                SLIST_INSERT_HEAD(&h->stack, t, entry);
        !           505:        } else
        !           506:                t = NULL;
1.29      kristaps  507:
                    508:        if ( ! (HTML_NOSPACE & h->flags))
1.30    ! kristaps  509:                if ( ! (HTML_CLRLINE & htmltags[tag].flags))
1.29      kristaps  510:                        printf(" ");
                    511:
                    512:        printf("<%s", htmltags[tag].name);
                    513:        for (i = 0; i < sz; i++) {
                    514:                printf(" %s=\"", htmlattrs[p[i].key]);
                    515:                assert(p->val);
                    516:                print_encode(p[i].val);
                    517:                printf("\"");
                    518:        }
                    519:        printf(">");
1.14      kristaps  520:
1.29      kristaps  521:        h->flags |= HTML_NOSPACE;
1.30    ! kristaps  522:        if (HTML_CLRLINE & htmltags[tag].flags)
        !           523:                h->flags |= HTML_NEWLINE;
        !           524:        else
        !           525:                h->flags &= ~HTML_NEWLINE;
1.14      kristaps  526:
1.30    ! kristaps  527:        return(t);
1.14      kristaps  528: }
                    529:
                    530:
                    531: /* ARGSUSED */
1.29      kristaps  532: static void
                    533: print_ctag(struct html *h, enum htmltag tag)
1.14      kristaps  534: {
                    535:
1.29      kristaps  536:        printf("</%s>", htmltags[tag].name);
1.30    ! kristaps  537:        if (HTML_CLRLINE & htmltags[tag].flags)
1.29      kristaps  538:                h->flags |= HTML_NOSPACE;
1.30    ! kristaps  539:        if (HTML_CLRLINE & htmltags[tag].flags)
        !           540:                h->flags |= HTML_NEWLINE;
        !           541:        else
        !           542:                h->flags &= ~HTML_NEWLINE;
1.14      kristaps  543: }
                    544:
                    545:
1.29      kristaps  546: /* ARGSUSED */
                    547: static void
                    548: print_gen_doctype(struct html *h)
1.1       kristaps  549: {
1.29      kristaps  550:
                    551:        printf("<!DOCTYPE HTML PUBLIC \"%s\" \"%s\">\n", DOCTYPE, DTD);
1.1       kristaps  552: }
                    553:
                    554:
1.29      kristaps  555: static void
                    556: print_text(struct html *h, const char *p)
1.1       kristaps  557: {
                    558:
1.29      kristaps  559:        if (*p && 0 == *(p + 1))
                    560:                switch (*p) {
                    561:                case('.'):
                    562:                        /* FALLTHROUGH */
                    563:                case(','):
                    564:                        /* FALLTHROUGH */
                    565:                case(';'):
                    566:                        /* FALLTHROUGH */
                    567:                case(':'):
                    568:                        /* FALLTHROUGH */
                    569:                case('?'):
                    570:                        /* FALLTHROUGH */
                    571:                case('!'):
                    572:                        /* FALLTHROUGH */
                    573:                case(')'):
                    574:                        /* FALLTHROUGH */
                    575:                case(']'):
                    576:                        /* FALLTHROUGH */
                    577:                case('}'):
                    578:                        h->flags |= HTML_NOSPACE;
1.30    ! kristaps  579:                        break;
1.29      kristaps  580:                default:
                    581:                        break;
                    582:                }
1.1       kristaps  583:
1.29      kristaps  584:        if ( ! (h->flags & HTML_NOSPACE))
                    585:                printf(" ");
1.30    ! kristaps  586:
1.29      kristaps  587:        h->flags &= ~HTML_NOSPACE;
1.30    ! kristaps  588:        h->flags &= ~HTML_NEWLINE;
1.1       kristaps  589:
1.29      kristaps  590:        if (p)
                    591:                print_encode(p);
1.8       kristaps  592:
1.29      kristaps  593:        if (*p && 0 == *(p + 1))
                    594:                switch (*p) {
                    595:                case('('):
                    596:                        /* FALLTHROUGH */
                    597:                case('['):
                    598:                        /* FALLTHROUGH */
                    599:                case('{'):
                    600:                        h->flags |= HTML_NOSPACE;
1.30    ! kristaps  601:                        break;
1.29      kristaps  602:                default:
                    603:                        break;
                    604:                }
1.1       kristaps  605: }
1.30    ! kristaps  606:
        !           607:
        !           608: static void
        !           609: print_tagq(struct html *h, const struct tag *until)
        !           610: {
        !           611:        struct tag      *tag;
        !           612:
        !           613:        while ( ! SLIST_EMPTY(&h->stack)) {
        !           614:                tag = SLIST_FIRST(&h->stack);
        !           615:                print_ctag(h, tag->tag);
        !           616:                SLIST_REMOVE_HEAD(&h->stack, entry);
        !           617:                free(tag);
        !           618:                if (until && tag == until)
        !           619:                        return;
        !           620:        }
        !           621: }
        !           622:
        !           623:
        !           624: static void
        !           625: print_stagq(struct html *h, const struct tag *suntil)
        !           626: {
        !           627:        struct tag      *tag;
        !           628:
        !           629:        while ( ! SLIST_EMPTY(&h->stack)) {
        !           630:                tag = SLIST_FIRST(&h->stack);
        !           631:                if (suntil && tag == suntil)
        !           632:                        return;
        !           633:                print_ctag(h, tag->tag);
        !           634:                SLIST_REMOVE_HEAD(&h->stack, entry);
        !           635:                free(tag);
        !           636:        }
        !           637: }
        !           638:
        !           639:
        !           640: /* ARGSUSED */
        !           641: static int
        !           642: mdoc_root_pre(MDOC_ARGS)
        !           643: {
        !           644:        struct htmlpair  tag;
        !           645:
        !           646:        tag.key = ATTR_CLASS;
        !           647:        tag.val = "body";
        !           648:
        !           649:        print_otag(h, TAG_DIV, 1, &tag);
        !           650:        return(1);
        !           651: }
        !           652:
        !           653:
        !           654: /* ARGSUSED */
        !           655: static int
        !           656: mdoc_ss_pre(MDOC_ARGS)
        !           657: {
        !           658:
        !           659:        if (MDOC_BODY == n->type)
        !           660:                print_otag(h, TAG_P, 0, NULL);
        !           661:        if (MDOC_HEAD == n->type)
        !           662:                print_otag(h, TAG_H2, 0, NULL);
        !           663:        return(1);
        !           664: }
        !           665:
        !           666:
        !           667: /* ARGSUSED */
        !           668: static int
        !           669: mdoc_fl_pre(MDOC_ARGS)
        !           670: {
        !           671:        struct htmlpair  tag;
        !           672:
        !           673:        tag.key = ATTR_CLASS;
        !           674:        tag.val = "flag";
        !           675:
        !           676:        print_otag(h, TAG_SPAN, 1, &tag);
        !           677:        print_text(h, "\\-");
        !           678:        h->flags |= HTML_NOSPACE;
        !           679:        return(1);
        !           680: }
        !           681:
        !           682:
        !           683: /* ARGSUSED */
        !           684: static int
        !           685: mdoc_pp_pre(MDOC_ARGS)
        !           686: {
        !           687:
        !           688:        print_otag(h, TAG_BR, 0, NULL);
        !           689:        print_otag(h, TAG_BR, 0, NULL);
        !           690:        return(0);
        !           691: }
        !           692:
        !           693:
        !           694: /* ARGSUSED */
        !           695: static int
        !           696: mdoc_nd_pre(MDOC_ARGS)
        !           697: {
        !           698:
        !           699:        if (MDOC_BODY == n->type)
        !           700:                print_text(h, "--");
        !           701:        return(1);
        !           702: }
        !           703:
        !           704:
        !           705: /* ARGSUSED */
        !           706: static int
        !           707: mdoc_op_pre(MDOC_ARGS)
        !           708: {
        !           709:
        !           710:        if (MDOC_BODY == n->type) {
        !           711:                print_text(h, "\\(lB");
        !           712:                h->flags |= HTML_NOSPACE;
        !           713:        }
        !           714:        return(1);
        !           715: }
        !           716:
        !           717:
        !           718: /* ARGSUSED */
        !           719: static void
        !           720: mdoc_op_post(MDOC_ARGS)
        !           721: {
        !           722:
        !           723:        if (MDOC_BODY != n->type)
        !           724:                return;
        !           725:        h->flags |= HTML_NOSPACE;
        !           726:        print_text(h, "\\(rB");
        !           727: }
        !           728:
        !           729:
        !           730: static int
        !           731: mdoc_nm_pre(MDOC_ARGS)
        !           732: {
        !           733:        struct htmlpair class;
        !           734:
        !           735:        if ( ! (HTML_NEWLINE & h->flags))
        !           736:                if (SEC_SYNOPSIS == n->sec)
        !           737:                        print_otag(h, TAG_BR, 0, NULL);
        !           738:
        !           739:        class.key = ATTR_CLASS;
        !           740:        class.val = "name";
        !           741:
        !           742:        print_otag(h, TAG_SPAN, 1, &class);
        !           743:        if (NULL == n->child)
        !           744:                print_text(h, m->name);
        !           745:
        !           746:        return(1);
        !           747: }
        !           748:
        !           749:
        !           750: /* ARGSUSED */
        !           751: static int
        !           752: mdoc_sh_pre(MDOC_ARGS)
        !           753: {
        !           754:
        !           755:        if (MDOC_BODY == n->type)
        !           756:                print_otag(h, TAG_P, 0, NULL);
        !           757:        if (MDOC_HEAD == n->type)
        !           758:                print_otag(h, TAG_H1, 0, NULL);
        !           759:        return(1);
        !           760: }
        !           761:
        !           762:
        !           763: /* ARGSUSED */
        !           764: static int
        !           765: mdoc_xr_pre(MDOC_ARGS)
        !           766: {
        !           767:        struct htmlpair tag;
        !           768:
        !           769:        tag.key = ATTR_HREF;
        !           770:        tag.val = "#"; /* TODO */
        !           771:
        !           772:        print_otag(h, TAG_A, 1, &tag);
        !           773:
        !           774:        n = n->child;
        !           775:        print_text(h, n->string);
        !           776:        if (NULL == (n = n->next))
        !           777:                return(0);
        !           778:
        !           779:        h->flags |= HTML_NOSPACE;
        !           780:        print_text(h, "(");
        !           781:        h->flags |= HTML_NOSPACE;
        !           782:        print_text(h, n->string);
        !           783:        h->flags |= HTML_NOSPACE;
        !           784:        print_text(h, ")");
        !           785:
        !           786:        return(0);
        !           787: }

CVSweb