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

Annotation of mandoc/html.c, Revision 1.24

1.24    ! kristaps    1: /* $Id: html.c,v 1.23 2008/12/10 12:09:47 kristaps Exp $ */
1.1       kristaps    2: /*
                      3:  * Copyright (c) 2008 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
                      7:  * above copyright notice and this permission notice appear in all
                      8:  * copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
                     11:  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
                     12:  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
                     13:  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
                     14:  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
                     15:  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
                     16:  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
                     17:  * PERFORMANCE OF THIS SOFTWARE.
                     18:  */
1.4       kristaps   19: #include <sys/param.h>
                     20: #include <sys/stat.h>
                     21:
1.1       kristaps   22: #include <assert.h>
1.4       kristaps   23: #include <err.h>
                     24: #include <fcntl.h>
1.1       kristaps   25: #include <stdlib.h>
1.4       kristaps   26: #include <stdio.h>
1.2       kristaps   27: #include <string.h>
1.4       kristaps   28: #include <unistd.h>
1.1       kristaps   29:
1.19      kristaps   30: #include "html.h"
1.2       kristaps   31: #include "ml.h"
                     32:
1.8       kristaps   33: /* TODO: allow head/tail-less invocations (just "div" start). */
                     34:
1.7       kristaps   35: struct htmlnode {
1.8       kristaps   36:        int              tok;
                     37:        enum md_ns       ns;
1.10      kristaps   38:        int              argc[ROFF_MAXLINEARG];
1.7       kristaps   39:        char            *argv[ROFF_MAXLINEARG];
                     40:        struct htmlnode *parent;
                     41: };
                     42:
                     43: struct htmlq {
                     44:        struct htmlnode *last;
                     45: };
                     46:
                     47:
1.19      kristaps   48: static int             html_loadcss(struct md_mbuf *,
                     49:                                const char *);
1.9       kristaps   50: static int             html_alloc(void **);
                     51: static void            html_free(void *);
1.8       kristaps   52: static ssize_t         html_endtag(struct md_mbuf *, void *,
1.2       kristaps   53:                                const struct md_args *,
                     54:                                enum md_ns, int);
1.14      kristaps   55: static ssize_t         html_beginstring(struct md_mbuf *,
                     56:                                const struct md_args *,
                     57:                                const char *, size_t);
                     58: static ssize_t         html_beginhttp(struct md_mbuf *,
                     59:                                const struct md_args *,
                     60:                                const char *, size_t);
                     61: static ssize_t         html_endstring(struct md_mbuf *,
                     62:                                const struct md_args *,
                     63:                                const char *, size_t);
                     64: static ssize_t         html_endhttp(struct md_mbuf *,
                     65:                                const struct md_args *,
                     66:                                const char *, size_t);
1.8       kristaps   67: static ssize_t         html_begintag(struct md_mbuf *, void *,
1.2       kristaps   68:                                const struct md_args *,
                     69:                                enum md_ns, int,
                     70:                                const int *, const char **);
1.4       kristaps   71: static int             html_begin(struct md_mbuf *,
                     72:                                const struct md_args *,
                     73:                                const struct tm *,
                     74:                                const char *, const char *,
1.21      kristaps   75:                                enum roffmsec, enum roffvol);
1.7       kristaps   76: static int             html_printargs(struct md_mbuf *, int,
                     77:                                const char *, const int *,
                     78:                                const char **, size_t *);
1.22      kristaps   79: static int             html_end(struct md_mbuf *,
                     80:                                const struct md_args *,
                     81:                                const struct tm *,
                     82:                                const char *, const char *,
                     83:                                enum roffmsec, enum roffvol);
1.7       kristaps   84: static int             html_blocktagname(struct md_mbuf *,
1.10      kristaps   85:                                const struct md_args *, int,
                     86:                                struct htmlq *, const int *,
                     87:                                const char **, size_t *);
1.7       kristaps   88: static int             html_blocktagargs(struct md_mbuf *,
1.2       kristaps   89:                                const struct md_args *, int,
1.7       kristaps   90:                                const int *, const char **, size_t *);
1.10      kristaps   91: static int             html_headtagname(struct md_mbuf *,
                     92:                                const struct md_args *, int,
                     93:                                struct htmlq *, const int *,
                     94:                                const char **, size_t *);
                     95: static int             html_headtagargs(struct md_mbuf *,
1.3       kristaps   96:                                const struct md_args *, int,
1.7       kristaps   97:                                const int *, const char **, size_t *);
1.12      kristaps   98: static int             html_bodytagname(struct md_mbuf *,
1.10      kristaps   99:                                const struct md_args *,
                    100:                                int, struct htmlq *, const int *,
                    101:                                const char **, size_t *);
1.12      kristaps  102: static int             html_bodytagargs(struct md_mbuf *,
1.3       kristaps  103:                                const struct md_args *, int,
1.7       kristaps  104:                                const int *, const char **, size_t *);
                    105: static int             html_inlinetagname(struct md_mbuf *,
                    106:                                const struct md_args *, int, size_t *);
                    107: static int             html_inlinetagargs(struct md_mbuf *,
1.2       kristaps  108:                                const struct md_args *, int,
1.7       kristaps  109:                                const int *, const char **, size_t *);
1.10      kristaps  110: static int             html_Bl_bodytagname(struct md_mbuf *,
                    111:                                struct htmlq *, const int *,
                    112:                                const char **, size_t *);
                    113: static int             html_It_blocktagname(struct md_mbuf *,
                    114:                                struct htmlq *, const int *,
                    115:                                const char **, size_t *);
                    116: static int             html_It_headtagname(struct md_mbuf *,
                    117:                                struct htmlq *, const int *,
                    118:                                const char **, size_t *);
                    119: static int             html_It_bodytagname(struct md_mbuf *,
                    120:                                struct htmlq *, const int *,
                    121:                                const char **, size_t *);
1.19      kristaps  122: static int             html_tputln(struct md_mbuf *,
                    123:                                enum ml_scope, int, enum html_tag);
                    124: static int             html_aputln(struct md_mbuf *, enum ml_scope,
                    125:                                int, enum html_tag,
                    126:                                int, const struct html_pair *);
1.10      kristaps  127:
                    128:
                    129: /* ARGSUSED */
                    130: static int
                    131: html_It_headtagname(struct md_mbuf *mbuf, struct htmlq *q,
                    132:                const int *argc, const char **argv, size_t *res)
                    133: {
                    134:        struct htmlnode *n;
1.11      kristaps  135:        int              i;
1.10      kristaps  136:
                    137:        for (n = q->last; n; n = n->parent)
                    138:                if (n->tok == ROFF_Bl)
                    139:                        break;
                    140:
                    141:        assert(n);
1.13      kristaps  142:
                    143:        /* LINTED */
1.11      kristaps  144:        for (i = 0; ROFF_ARGMAX != n->argc[i] &&
1.10      kristaps  145:                        i < ROFF_MAXLINEARG; i++) {
                    146:                switch (n->argc[i]) {
1.14      kristaps  147:                case (ROFF_Ohang):
1.19      kristaps  148:                        return(html_stput(mbuf, HTML_TAG_DIV, res));
1.10      kristaps  149:                case (ROFF_Tag):
                    150:                        /* FALLTHROUGH */
                    151:                case (ROFF_Column):
1.19      kristaps  152:                        return(html_stput(mbuf, HTML_TAG_TD, res));
1.10      kristaps  153:                default:
                    154:                        break;
                    155:                }
                    156:        }
                    157:
1.16      kristaps  158:        return(0);
1.10      kristaps  159: }
                    160:
                    161:
                    162: /* ARGSUSED */
                    163: static int
                    164: html_It_bodytagname(struct md_mbuf *mbuf, struct htmlq *q,
                    165:                const int *argc, const char **argv, size_t *res)
                    166: {
                    167:        struct htmlnode *n;
1.11      kristaps  168:        int              i;
1.10      kristaps  169:
                    170:        for (n = q->last; n; n = n->parent)
                    171:                if (n->tok == ROFF_Bl)
                    172:                        break;
                    173:
                    174:        assert(n);
1.13      kristaps  175:
                    176:        /* LINTED */
1.11      kristaps  177:        for (i = 0; ROFF_ARGMAX != n->argc[i] &&
1.10      kristaps  178:                        i < ROFF_MAXLINEARG; i++) {
                    179:                switch (n->argc[i]) {
                    180:                case (ROFF_Enum):
                    181:                        /* FALLTHROUGH */
                    182:                case (ROFF_Bullet):
                    183:                        /* FALLTHROUGH */
                    184:                case (ROFF_Dash):
                    185:                        /* FALLTHROUGH */
                    186:                case (ROFF_Hyphen):
                    187:                        /* FALLTHROUGH */
                    188:                case (ROFF_Item):
                    189:                        /* FALLTHROUGH */
                    190:                case (ROFF_Diag):
                    191:                        /* FALLTHROUGH */
                    192:                case (ROFF_Hang):
                    193:                        /* FALLTHROUGH */
                    194:                case (ROFF_Ohang):
                    195:                        /* FALLTHROUGH */
                    196:                case (ROFF_Inset):
1.19      kristaps  197:                        return(html_stput(mbuf, HTML_TAG_DIV, res));
1.10      kristaps  198:                case (ROFF_Tag):
                    199:                        /* FALLTHROUGH */
                    200:                case (ROFF_Column):
1.19      kristaps  201:                        return(html_stput(mbuf, HTML_TAG_TD, res));
1.10      kristaps  202:                default:
                    203:                        break;
                    204:                }
                    205:        }
                    206:
                    207:        assert(i != ROFF_MAXLINEARG);
1.16      kristaps  208:        return(0);
1.10      kristaps  209: }
                    210:
                    211:
                    212: /* ARGSUSED */
                    213: static int
                    214: html_Bl_bodytagname(struct md_mbuf *mbuf, struct htmlq *q,
                    215:                const int *argc, const char **argv, size_t *res)
                    216: {
1.11      kristaps  217:        int              i;
1.10      kristaps  218:
1.11      kristaps  219:        for (i = 0; ROFF_ARGMAX != argc[i]
1.10      kristaps  220:                        && i < ROFF_MAXLINEARG; i++) {
                    221:                switch (argc[i]) {
                    222:                case (ROFF_Enum):
1.19      kristaps  223:                        return(html_stput(mbuf, HTML_TAG_OL, res));
1.10      kristaps  224:                case (ROFF_Bullet):
                    225:                        /* FALLTHROUGH */
                    226:                case (ROFF_Dash):
                    227:                        /* FALLTHROUGH */
                    228:                case (ROFF_Hyphen):
                    229:                        /* FALLTHROUGH */
                    230:                case (ROFF_Item):
                    231:                        /* FALLTHROUGH */
                    232:                case (ROFF_Diag):
                    233:                        /* FALLTHROUGH */
                    234:                case (ROFF_Hang):
                    235:                        /* FALLTHROUGH */
                    236:                case (ROFF_Ohang):
                    237:                        /* FALLTHROUGH */
                    238:                case (ROFF_Inset):
1.19      kristaps  239:                        return(html_stput(mbuf, HTML_TAG_UL, res));
1.10      kristaps  240:                case (ROFF_Tag):
                    241:                        /* FALLTHROUGH */
                    242:                case (ROFF_Column):
1.19      kristaps  243:                        return(html_stput(mbuf, HTML_TAG_TABLE, res));
1.10      kristaps  244:                default:
                    245:                        break;
                    246:                }
                    247:        }
                    248:
                    249:        assert(i != ROFF_MAXLINEARG);
1.16      kristaps  250:        return(0);
1.10      kristaps  251: }
                    252:
                    253:
                    254: /* ARGSUSED */
                    255: static int
                    256: html_It_blocktagname(struct md_mbuf *mbuf, struct htmlq *q,
                    257:                const int *argc, const char **argv, size_t *res)
                    258: {
                    259:        struct htmlnode *n;
1.11      kristaps  260:        int              i;
1.10      kristaps  261:
                    262:        for (n = q->last; n; n = n->parent)
                    263:                if (n->tok == ROFF_Bl)
                    264:                        break;
                    265:
                    266:        assert(n);
1.13      kristaps  267:
                    268:        /* LINTED */
1.11      kristaps  269:        for (i = 0; ROFF_ARGMAX != n->argc[i] &&
1.10      kristaps  270:                        i < ROFF_MAXLINEARG; i++) {
                    271:                switch (n->argc[i]) {
                    272:                case (ROFF_Enum):
                    273:                        /* FALLTHROUGH */
                    274:                case (ROFF_Bullet):
                    275:                        /* FALLTHROUGH */
                    276:                case (ROFF_Dash):
                    277:                        /* FALLTHROUGH */
                    278:                case (ROFF_Hyphen):
                    279:                        /* FALLTHROUGH */
                    280:                case (ROFF_Item):
                    281:                        /* FALLTHROUGH */
                    282:                case (ROFF_Diag):
                    283:                        /* FALLTHROUGH */
                    284:                case (ROFF_Hang):
                    285:                        /* FALLTHROUGH */
                    286:                case (ROFF_Ohang):
                    287:                        /* FALLTHROUGH */
                    288:                case (ROFF_Inset):
1.19      kristaps  289:                        return(html_stput(mbuf, HTML_TAG_LI, res));
1.10      kristaps  290:                case (ROFF_Tag):
                    291:                        /* FALLTHROUGH */
                    292:                case (ROFF_Column):
1.19      kristaps  293:                        return(html_stput(mbuf, HTML_TAG_TR, res));
1.10      kristaps  294:                default:
                    295:                        break;
                    296:                }
                    297:        }
                    298:
                    299:        assert(i != ROFF_MAXLINEARG);
1.16      kristaps  300:        return(0);
1.10      kristaps  301: }
1.2       kristaps  302:
                    303:
1.4       kristaps  304: static int
                    305: html_loadcss(struct md_mbuf *mbuf, const char *css)
                    306: {
                    307:        size_t           res, bufsz;
                    308:        char            *buf;
                    309:        struct stat      st;
                    310:        int              fd, c;
                    311:        ssize_t          ssz;
                    312:
                    313:        c = 0;
                    314:        res = 0;
                    315:        buf = NULL;
                    316:
                    317:        if (-1 == (fd = open(css, O_RDONLY, 0))) {
                    318:                warn("%s", css);
                    319:                return(0);
                    320:        }
                    321:
                    322:        if (-1 == fstat(fd, &st)) {
                    323:                warn("%s", css);
                    324:                goto out;
                    325:        }
                    326:
                    327:        bufsz = MAX(st.st_blksize, BUFSIZ);
                    328:        if (NULL == (buf = malloc(bufsz))) {
                    329:                warn("malloc");
                    330:                goto out;
                    331:        }
                    332:
                    333:        for (;;) {
                    334:                if (-1 == (ssz = read(fd, buf, bufsz))) {
                    335:                        warn("%s", css);
                    336:                        goto out;
                    337:                } else if (0 == ssz)
                    338:                        break;
                    339:                if ( ! ml_nputs(mbuf, buf, (size_t)ssz, &res))
                    340:                        goto out;
                    341:        }
                    342:
                    343:        c = 1;
                    344:
                    345: out:
                    346:        if (-1 == close(fd)) {
                    347:                warn("%s", css);
                    348:                c = 0;
                    349:        }
                    350:
                    351:        if (buf)
                    352:                free(buf);
                    353:
                    354:        return(c);
                    355: }
                    356:
                    357:
1.18      kristaps  358: static int
1.19      kristaps  359: html_tputln(struct md_mbuf *mbuf, enum ml_scope scope,
                    360:                int i, enum html_tag tag)
1.18      kristaps  361: {
                    362:
1.19      kristaps  363:        if ( ! ml_putchars(mbuf, ' ', INDENT(i) * INDENT_SZ, NULL))
1.18      kristaps  364:                return(0);
1.19      kristaps  365:        if ( ! html_tput(mbuf, scope, tag, NULL))
1.18      kristaps  366:                return(0);
1.19      kristaps  367:        return(ml_nputs(mbuf, "\n", 1, NULL));
1.18      kristaps  368: }
                    369:
                    370:
                    371: static int
1.19      kristaps  372: html_aputln(struct md_mbuf *mbuf, enum ml_scope scope, int i,
                    373:                enum html_tag tag, int sz, const struct html_pair *p)
1.18      kristaps  374: {
                    375:
1.19      kristaps  376:        if ( ! ml_putchars(mbuf, ' ', INDENT(i) * INDENT_SZ, NULL))
1.18      kristaps  377:                return(0);
1.19      kristaps  378:        if ( ! html_aput(mbuf, scope, tag, NULL, sz, p))
                    379:                return(0);
                    380:        return(ml_nputs(mbuf, "\n", 1, NULL));
1.18      kristaps  381: }
                    382:
                    383:
1.3       kristaps  384: /* ARGSUSED */
1.2       kristaps  385: static int
1.4       kristaps  386: html_begin(struct md_mbuf *mbuf, const struct md_args *args,
                    387:                const struct tm *tm, const char *os,
1.21      kristaps  388:                const char *name, enum roffmsec msec, enum roffvol vol)
1.2       kristaps  389: {
1.22      kristaps  390:        enum roffvol     bvol;
1.19      kristaps  391:        struct html_pair attr[4];
1.21      kristaps  392:        char             ts[32], title[64];
1.19      kristaps  393:        int              i;
1.2       kristaps  394:
1.19      kristaps  395:        (void)snprintf(ts, sizeof(ts), "%s(%s)",
                    396:                        name, roff_msecname(msec));
1.4       kristaps  397:
1.21      kristaps  398:        if (vol >= ROFF_ARCH_START) {
1.22      kristaps  399:                switch (msec) {
                    400:                case(ROFF_MSEC_1):
                    401:                        /* FALLTHROUGH */
                    402:                case(ROFF_MSEC_6):
                    403:                        /* FALLTHROUGH */
                    404:                case(ROFF_MSEC_7):
                    405:                        bvol = ROFF_VOL_URM;
                    406:                        break;
                    407:                case(ROFF_MSEC_2):
                    408:                        /* FALLTHROUGH */
                    409:                case(ROFF_MSEC_3):
                    410:                        /* FALLTHROUGH */
                    411:                case(ROFF_MSEC_3p):
                    412:                        /* FALLTHROUGH */
                    413:                case(ROFF_MSEC_4):
                    414:                        /* FALLTHROUGH */
                    415:                case(ROFF_MSEC_5):
                    416:                        bvol = ROFF_VOL_PRM;
                    417:                        break;
                    418:                case(ROFF_MSEC_8):
                    419:                        bvol = ROFF_VOL_PRM;
                    420:                        break;
                    421:                case(ROFF_MSEC_9):
                    422:                        bvol = ROFF_VOL_KM;
                    423:                        break;
                    424:                case(ROFF_MSEC_UNASS):
                    425:                        /* FALLTHROUGH */
                    426:                case(ROFF_MSEC_DRAFT):
                    427:                        /* FALLTHROUGH */
                    428:                case(ROFF_MSEC_PAPER):
                    429:                        bvol = ROFF_VOL_NONE;
                    430:                        break;
                    431:                default:
                    432:                        abort();
                    433:                        /* NOTREACHED */
                    434:                }
1.21      kristaps  435:
1.22      kristaps  436:                (void)snprintf(title, sizeof(title), "%s (%s)",
                    437:                                roff_volname(bvol), roff_volname(vol));
                    438:        } else
                    439:                (void)snprintf(title, sizeof(title), "%s", roff_volname(vol));
1.21      kristaps  440:
                    441:
1.18      kristaps  442:        i = 0;
1.4       kristaps  443:
1.19      kristaps  444:        if ( ! html_typeput(mbuf, HTML_TYPE_4_01_STRICT, NULL))
1.17      kristaps  445:                return(0);
1.19      kristaps  446:        if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_HTML))
1.17      kristaps  447:                return(0);
1.19      kristaps  448:        if ( ! html_tputln(mbuf, ML_OPEN, i++, HTML_TAG_HEAD))
1.17      kristaps  449:                return(0);
1.19      kristaps  450:
                    451:        attr[0].attr = HTML_ATTR_HTTP_EQUIV;
                    452:        attr[0].val = "content-type";
                    453:        attr[1].attr = HTML_ATTR_CONTENT;
                    454:        attr[1].val = "text/html;charset=utf-8";
                    455:
                    456:        if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_META, 2, attr))
1.17      kristaps  457:                return(0);
1.19      kristaps  458:
                    459:        attr[0].attr = HTML_ATTR_NAME;
                    460:        attr[0].val = "resource-type";
                    461:        attr[1].attr = HTML_ATTR_CONTENT;
                    462:        attr[1].val = "document";
                    463:
                    464:        if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_META, 2, attr))
1.17      kristaps  465:                return(0);
1.19      kristaps  466:
                    467:        if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_TITLE))
1.17      kristaps  468:                return(0);
1.19      kristaps  469:        if ( ! ml_putstring(mbuf, ts, NULL))
1.17      kristaps  470:                return(0);
1.19      kristaps  471:        if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TITLE))
1.2       kristaps  472:                return(0);
1.4       kristaps  473:
                    474:        if (HTML_CSS_EMBED & args->params.html.flags) {
1.19      kristaps  475:                attr[0].attr = HTML_ATTR_TYPE;
                    476:                attr[0].val = "text/css";
                    477:
                    478:                if ( ! html_aputln(mbuf, ML_OPEN, i,
                    479:                                        HTML_TAG_STYLE, 1, attr))
1.4       kristaps  480:                        return(0);
1.19      kristaps  481:                if ( ! html_commentput(mbuf, ML_OPEN, NULL))
1.22      kristaps  482:                        return(0);
1.19      kristaps  483:
1.4       kristaps  484:                if ( ! html_loadcss(mbuf, args->params.html.css))
                    485:                        return(0);
1.19      kristaps  486:
                    487:                if ( ! html_commentput(mbuf, ML_CLOSE, NULL))
1.22      kristaps  488:                        return(0);
1.19      kristaps  489:                if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_STYLE))
1.4       kristaps  490:                        return(0);
1.19      kristaps  491:        } else {
                    492:                attr[0].attr = HTML_ATTR_REL;
                    493:                attr[0].val = "stylesheet";
                    494:                attr[1].attr = HTML_ATTR_TYPE;
                    495:                attr[1].val = "text/css";
                    496:                attr[2].attr = HTML_ATTR_HREF;
                    497:                attr[2].val = args->params.html.css;
                    498:
                    499:                if ( ! html_aputln(mbuf, ML_OPEN, i,
                    500:                                        HTML_TAG_LINK, 3, attr))
                    501:                        return(0);
                    502:        }
1.4       kristaps  503:
1.19      kristaps  504:        if ( ! html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_HEAD))
1.18      kristaps  505:                return(0);
1.19      kristaps  506:        if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_BODY))
1.18      kristaps  507:                return(0);
1.19      kristaps  508:
                    509:        attr[0].attr = HTML_ATTR_CLASS;
                    510:        attr[0].val = "mdoc";
                    511:
                    512:        if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_DIV, 1, attr))
1.18      kristaps  513:                return(0);
1.19      kristaps  514:
                    515:        attr[0].attr = HTML_ATTR_WIDTH;
                    516:        attr[0].val = "100%";
1.22      kristaps  517:        attr[1].attr = HTML_ATTR_CLASS;
                    518:        attr[1].val = "header-table";
1.19      kristaps  519:
1.22      kristaps  520:        if ( ! html_aputln(mbuf, ML_OPEN, i++, HTML_TAG_TABLE, 2, attr))
1.18      kristaps  521:                return(0);
1.19      kristaps  522:        if ( ! html_tputln(mbuf, ML_OPEN, i++, HTML_TAG_TR))
1.18      kristaps  523:                return(0);
1.19      kristaps  524:
1.22      kristaps  525:        attr[0].attr = HTML_ATTR_ALIGN;
                    526:        attr[0].val = "left";
                    527:        attr[1].attr = HTML_ATTR_CLASS;
                    528:        attr[1].val = "header-section";
                    529:
                    530:        if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_TD, 2, attr))
1.2       kristaps  531:                return(0);
1.19      kristaps  532:        if ( ! ml_putstring(mbuf, ts, NULL))
1.18      kristaps  533:                return(0);
1.19      kristaps  534:        if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD))
1.18      kristaps  535:                return(0);
1.19      kristaps  536:
1.22      kristaps  537:        attr[0].attr = HTML_ATTR_ALIGN;
                    538:        attr[0].val = "center";
                    539:        attr[1].attr = HTML_ATTR_CLASS;
                    540:        attr[1].val = "header-volume";
                    541:
                    542:        if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_TD, 2, attr))
                    543:                return(0);
                    544:        if ( ! ml_putstring(mbuf, title, NULL))
1.18      kristaps  545:                return(0);
1.19      kristaps  546:        if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD))
1.18      kristaps  547:                return(0);
1.19      kristaps  548:
1.20      kristaps  549:        attr[0].attr = HTML_ATTR_ALIGN;
                    550:        attr[0].val = "right";
1.22      kristaps  551:        attr[1].attr = HTML_ATTR_CLASS;
                    552:        attr[1].val = "header-section";
1.20      kristaps  553:
1.22      kristaps  554:        if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_TD, 2, attr))
1.18      kristaps  555:                return(0);
1.19      kristaps  556:        if ( ! ml_putstring(mbuf, ts, NULL))
1.17      kristaps  557:                return(0);
1.19      kristaps  558:        if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD))
1.17      kristaps  559:                return(0);
1.19      kristaps  560:
                    561:        if ( ! html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_TR))
1.17      kristaps  562:                return(0);
1.19      kristaps  563:        return(html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_TABLE));
1.2       kristaps  564: }
                    565:
                    566:
1.3       kristaps  567: /* ARGSUSED */
1.2       kristaps  568: static int
1.22      kristaps  569: html_end(struct md_mbuf *mbuf, const struct md_args *args,
                    570:                const struct tm *tm, const char *os,
                    571:                const char *name, enum roffmsec msec, enum roffvol vol)
1.2       kristaps  572: {
1.22      kristaps  573:        struct html_pair attr[4];
                    574:        int              i;
                    575:        char             ts[64];
                    576:
                    577:        if (0 == strftime(ts, sizeof(ts), "%B %d, %Y", tm)) {
                    578:                warn("strftime");
                    579:                return(0);
                    580:        }
                    581:
                    582:        i = 0;
                    583:
                    584:        attr[0].attr = HTML_ATTR_WIDTH;
                    585:        attr[0].val = "100%";
                    586:        attr[1].attr = HTML_ATTR_CLASS;
                    587:        attr[1].val = "header-footer";
                    588:
                    589:        if ( ! html_aputln(mbuf, ML_OPEN, i++, HTML_TAG_TABLE, 2, attr))
                    590:                return(0);
                    591:        if ( ! html_tputln(mbuf, ML_OPEN, i++, HTML_TAG_TR))
                    592:                return(0);
                    593:
                    594:        attr[0].attr = HTML_ATTR_ALIGN;
                    595:        attr[0].val = "left";
                    596:        attr[1].attr = HTML_ATTR_CLASS;
                    597:        attr[1].val = "footer-os";
                    598:
                    599:        if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_TD, 2, attr))
                    600:                return(0);
                    601:        if ( ! ml_putstring(mbuf, os, NULL))
                    602:                return(0);
                    603:        if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD))
                    604:                return(0);
                    605:
                    606:        attr[0].attr = HTML_ATTR_ALIGN;
                    607:        attr[0].val = "right";
                    608:        attr[1].attr = HTML_ATTR_CLASS;
                    609:        attr[1].val = "footer-date";
                    610:
                    611:        if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_TD, 2, attr))
                    612:                return(0);
                    613:        if ( ! ml_putstring(mbuf, ts, NULL))
                    614:                return(0);
                    615:        if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD))
                    616:                return(0);
                    617:
                    618:        if ( ! html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_TR))
                    619:                return(0);
                    620:        if ( ! html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_TABLE))
                    621:                return(0);
1.2       kristaps  622:
1.19      kristaps  623:        if ( ! html_tputln(mbuf, ML_CLOSE, 0, HTML_TAG_DIV))
1.18      kristaps  624:                return(0);
1.19      kristaps  625:        if ( ! html_tputln(mbuf, ML_CLOSE, 0, HTML_TAG_BODY))
1.18      kristaps  626:                return(0);
1.19      kristaps  627:        return(html_tputln(mbuf, ML_CLOSE, 0, HTML_TAG_HTML));
1.2       kristaps  628: }
                    629:
                    630:
1.3       kristaps  631: /* ARGSUSED */
1.7       kristaps  632: static int
1.12      kristaps  633: html_bodytagname(struct md_mbuf *mbuf,
1.10      kristaps  634:                const struct md_args *args, int tok, struct htmlq *q,
                    635:                const int *argc, const char **argv, size_t *res)
1.2       kristaps  636: {
1.3       kristaps  637:
1.10      kristaps  638:        switch (tok) {
                    639:        case (ROFF_Bl):
                    640:                return(html_Bl_bodytagname(mbuf, q, argc, argv, res));
1.12      kristaps  641:        case (ROFF_Fo):
1.19      kristaps  642:                return(html_stput(mbuf, HTML_TAG_SPAN, res));
1.10      kristaps  643:        case (ROFF_It):
                    644:                return(html_It_bodytagname(mbuf, q, argc, argv, res));
1.12      kristaps  645:        case (ROFF_Oo):
1.19      kristaps  646:                return(html_stput(mbuf, HTML_TAG_SPAN, res));
1.10      kristaps  647:        default:
                    648:                break;
                    649:        }
                    650:
1.19      kristaps  651:        return(html_stput(mbuf, HTML_TAG_DIV, res));
1.3       kristaps  652: }
                    653:
                    654:
                    655: /* ARGSUSED */
1.7       kristaps  656: static int
1.10      kristaps  657: html_headtagname(struct md_mbuf *mbuf,
                    658:                const struct md_args *args, int tok, struct htmlq *q,
                    659:                const int *argc, const char **argv, size_t *res)
1.3       kristaps  660: {
                    661:
1.10      kristaps  662:        switch (tok) {
                    663:        case (ROFF_It):
                    664:                return(html_It_headtagname(mbuf, q, argc, argv, res));
1.12      kristaps  665:        case (ROFF_Fo):
1.19      kristaps  666:                /* FALLTHROUGH */
1.12      kristaps  667:        case (ROFF_Oo):
1.19      kristaps  668:                return(html_stput(mbuf, HTML_TAG_SPAN, res));
1.10      kristaps  669:        case (ROFF_Sh):
1.19      kristaps  670:                return(html_stput(mbuf, HTML_TAG_H1, res));
1.10      kristaps  671:        case (ROFF_Ss):
1.19      kristaps  672:                return(html_stput(mbuf, HTML_TAG_H2, res));
1.10      kristaps  673:        default:
                    674:                break;
                    675:        }
                    676:
1.19      kristaps  677:        return(html_stput(mbuf, HTML_TAG_DIV, res));
1.3       kristaps  678: }
                    679:
                    680:
                    681: /* ARGSUSED */
1.7       kristaps  682: static int
1.10      kristaps  683: html_blocktagname(struct md_mbuf *mbuf, const struct md_args *args,
                    684:                int tok, struct htmlq *q, const int *argc,
                    685:                const char **argv, size_t *res)
1.3       kristaps  686: {
                    687:
1.10      kristaps  688:        switch (tok) {
1.12      kristaps  689:        case (ROFF_Fo):
1.19      kristaps  690:                /* FALLTHROUGH */
1.12      kristaps  691:        case (ROFF_Oo):
1.19      kristaps  692:                return(html_stput(mbuf, HTML_TAG_SPAN, res));
1.10      kristaps  693:        case (ROFF_It):
                    694:                return(html_It_blocktagname(mbuf, q, argc, argv, res));
                    695:        default:
                    696:                break;
                    697:        }
                    698:
1.19      kristaps  699:        return(html_stput(mbuf, HTML_TAG_DIV, res));
1.3       kristaps  700: }
                    701:
                    702:
1.9       kristaps  703: /* ARGSUSED */
1.7       kristaps  704: static int
                    705: html_printargs(struct md_mbuf *mbuf, int tok, const char *ns,
                    706:                const int *argc, const char **argv, size_t *res)
1.3       kristaps  707: {
                    708:
1.19      kristaps  709:        /* FIXME: use API in ml.h. */
                    710:
1.7       kristaps  711:        if ( ! ml_puts(mbuf, " class=\"", res))
                    712:                return(0);
                    713:        if ( ! ml_puts(mbuf, ns, res))
                    714:                return(0);
                    715:        if ( ! ml_puts(mbuf, "-", res))
1.3       kristaps  716:                return(0);
1.7       kristaps  717:        if ( ! ml_puts(mbuf, toknames[tok], res))
1.3       kristaps  718:                return(0);
1.9       kristaps  719:        return(ml_puts(mbuf, "\"", res));
1.3       kristaps  720: }
                    721:
                    722:
                    723: /* ARGSUSED */
1.7       kristaps  724: static int
1.10      kristaps  725: html_headtagargs(struct md_mbuf *mbuf,
1.7       kristaps  726:                const struct md_args *args, int tok,
                    727:                const int *argc, const char **argv, size_t *res)
1.3       kristaps  728: {
                    729:
1.7       kristaps  730:        return(html_printargs(mbuf, tok, "head", argc, argv, res));
                    731: }
1.3       kristaps  732:
                    733:
1.7       kristaps  734: /* ARGSUSED */
                    735: static int
1.12      kristaps  736: html_bodytagargs(struct md_mbuf *mbuf,
1.7       kristaps  737:                const struct md_args *args, int tok,
                    738:                const int *argc, const char **argv, size_t *res)
                    739: {
1.3       kristaps  740:
1.7       kristaps  741:        return(html_printargs(mbuf, tok, "body", argc, argv, res));
1.2       kristaps  742: }
                    743:
                    744:
                    745: /* ARGSUSED */
1.7       kristaps  746: static int
                    747: html_blocktagargs(struct md_mbuf *mbuf,
                    748:                const struct md_args *args, int tok,
                    749:                const int *argc, const char **argv, size_t *res)
1.2       kristaps  750: {
1.3       kristaps  751:
1.7       kristaps  752:        return(html_printargs(mbuf, tok, "block", argc, argv, res));
1.2       kristaps  753: }
1.1       kristaps  754:
                    755:
                    756: /* ARGSUSED */
1.7       kristaps  757: static int
                    758: html_inlinetagargs(struct md_mbuf *mbuf,
                    759:                const struct md_args *args, int tok,
                    760:                const int *argc, const char **argv, size_t *res)
1.2       kristaps  761: {
                    762:
1.12      kristaps  763:        if ( ! html_printargs(mbuf, tok, "inline", argc, argv, res))
                    764:                return(0);
                    765:
                    766:        switch (tok) {
1.24    ! kristaps  767:        case (ROFF_Sh):
        !           768:
        !           769:                /* FIXME: use API in ml.h. */
        !           770:
        !           771:                assert(*argv);
        !           772:                if ( ! ml_nputs(mbuf, " name=\"", 7, res))
        !           773:                        return(0);
        !           774:                if ( ! ml_putstring(mbuf, *argv++, res))
        !           775:                        return(0);
        !           776:                while (*argv) {
        !           777:                        if ( ! ml_putstring(mbuf, "_", res))
        !           778:                                return(0);
        !           779:                        if ( ! ml_putstring(mbuf, *argv++, res))
        !           780:                                return(0);
        !           781:                }
        !           782:                if ( ! ml_nputs(mbuf, "\"", 1, res))
        !           783:                        return(0);
        !           784:                break;
        !           785:
1.12      kristaps  786:        case (ROFF_Sx):
1.19      kristaps  787:
                    788:                /* FIXME: use API in ml.h. */
                    789:
1.12      kristaps  790:                assert(*argv);
                    791:                if ( ! ml_nputs(mbuf, " href=\"#", 8, res))
                    792:                        return(0);
1.24    ! kristaps  793:                if ( ! ml_putstring(mbuf, *argv++, res))
1.12      kristaps  794:                        return(0);
1.24    ! kristaps  795:                while (*argv) {
        !           796:                        if ( ! ml_putstring(mbuf, "_", res))
        !           797:                                return(0);
        !           798:                        if ( ! ml_putstring(mbuf, *argv++, res))
        !           799:                                return(0);
        !           800:                }
1.12      kristaps  801:                if ( ! ml_nputs(mbuf, "\"", 1, res))
                    802:                        return(0);
1.24    ! kristaps  803:
1.13      kristaps  804:                break;
1.12      kristaps  805:        default:
                    806:                break;
                    807:        }
                    808:
                    809:        return(1);
1.2       kristaps  810: }
                    811:
                    812:
1.3       kristaps  813: /* ARGSUSED */
1.7       kristaps  814: static int
1.2       kristaps  815: html_inlinetagname(struct md_mbuf *mbuf,
1.7       kristaps  816:                const struct md_args *args, int tok, size_t *res)
1.2       kristaps  817: {
                    818:
                    819:        switch (tok) {
1.24    ! kristaps  820:        case (ROFF_Sh):
        !           821:                return(html_stput(mbuf, HTML_TAG_A, res));
1.4       kristaps  822:        case (ROFF_Pp):
1.19      kristaps  823:                return(html_stput(mbuf, HTML_TAG_DIV, res));
1.12      kristaps  824:        case (ROFF_Sx):
1.19      kristaps  825:                return(html_stput(mbuf, HTML_TAG_A, res));
1.2       kristaps  826:        default:
1.9       kristaps  827:                break;
1.2       kristaps  828:        }
1.9       kristaps  829:
1.19      kristaps  830:        return(html_stput(mbuf, HTML_TAG_SPAN, res));
1.2       kristaps  831: }
                    832:
                    833:
                    834: static ssize_t
1.8       kristaps  835: html_begintag(struct md_mbuf *mbuf, void *data,
                    836:                const struct md_args *args, enum md_ns ns,
                    837:                int tok, const int *argc, const char **argv)
1.2       kristaps  838: {
1.7       kristaps  839:        size_t           res;
1.8       kristaps  840:        struct htmlq    *q;
                    841:        struct htmlnode *node;
1.11      kristaps  842:        int              i;
1.2       kristaps  843:
                    844:        assert(ns != MD_NS_DEFAULT);
1.7       kristaps  845:        res = 0;
                    846:
1.8       kristaps  847:        assert(data);
                    848:        q = (struct htmlq *)data;
                    849:
                    850:        if (NULL == (node = calloc(1, sizeof(struct htmlnode)))) {
                    851:                warn("calloc");
                    852:                return(-1);
                    853:        }
                    854:
                    855:        node->parent = q->last;
                    856:        node->tok = tok;
                    857:        node->ns = ns;
                    858:
1.10      kristaps  859:        if (argc)  {
                    860:                /* TODO: argv. */
                    861:
                    862:                assert(argv);
1.13      kristaps  863:                /* LINTED */
1.11      kristaps  864:                for (i = 0; ROFF_ARGMAX != argc[i]
1.10      kristaps  865:                                && i < ROFF_MAXLINEARG; i++)
                    866:                        node->argc[i] = argc[i];
                    867:                assert(i != ROFF_MAXLINEARG);
1.12      kristaps  868:        }
1.10      kristaps  869:
                    870:
1.8       kristaps  871:        q->last = node;
                    872:
1.3       kristaps  873:        switch (ns) {
                    874:        case (MD_NS_BLOCK):
1.10      kristaps  875:                if ( ! html_blocktagname(mbuf, args, tok,
                    876:                                        q, argc, argv, &res))
1.7       kristaps  877:                        return(-1);
                    878:                if ( ! html_blocktagargs(mbuf, args, tok,
                    879:                                        argc, argv, &res))
                    880:                        return(-1);
                    881:                break;
1.3       kristaps  882:        case (MD_NS_BODY):
1.12      kristaps  883:                if ( ! html_bodytagname(mbuf, args, tok,
1.10      kristaps  884:                                        q, argc, argv, &res))
1.7       kristaps  885:                        return(-1);
1.12      kristaps  886:                if ( ! html_bodytagargs(mbuf, args, tok,
1.7       kristaps  887:                                        argc, argv, &res))
                    888:                        return(-1);
                    889:                break;
1.3       kristaps  890:        case (MD_NS_HEAD):
1.10      kristaps  891:                if ( ! html_headtagname(mbuf, args, tok, q,
                    892:                                        argc, argv, &res))
1.7       kristaps  893:                        return(-1);
1.10      kristaps  894:                if ( ! html_headtagargs(mbuf, args, tok,
1.7       kristaps  895:                                        argc, argv, &res))
                    896:                        return(-1);
                    897:                break;
1.3       kristaps  898:        default:
1.7       kristaps  899:                if ( ! html_inlinetagname(mbuf, args, tok, &res))
                    900:                        return(-1);
                    901:                if ( ! html_inlinetagargs(mbuf, args, tok,
                    902:                                        argc, argv, &res))
                    903:                        return(-1);
1.3       kristaps  904:                break;
1.2       kristaps  905:        }
                    906:
1.7       kristaps  907:        return((ssize_t)res);
1.2       kristaps  908: }
                    909:
                    910:
                    911: static ssize_t
1.8       kristaps  912: html_endtag(struct md_mbuf *mbuf, void *data,
                    913:                const struct md_args *args, enum md_ns ns, int tok)
1.2       kristaps  914: {
1.7       kristaps  915:        size_t           res;
1.8       kristaps  916:        struct htmlq    *q;
                    917:        struct htmlnode *node;
1.2       kristaps  918:
                    919:        assert(ns != MD_NS_DEFAULT);
1.7       kristaps  920:        res = 0;
                    921:
1.8       kristaps  922:        assert(data);
                    923:        q = (struct htmlq *)data;
1.10      kristaps  924:        node = q->last;
1.8       kristaps  925:
1.3       kristaps  926:        switch (ns) {
                    927:        case (MD_NS_BLOCK):
1.10      kristaps  928:                if ( ! html_blocktagname(mbuf, args, tok,
                    929:                                        q, node->argc,
                    930:                                        (const char **)node->argv, &res))
1.7       kristaps  931:                        return(-1);
                    932:                break;
1.3       kristaps  933:        case (MD_NS_BODY):
1.12      kristaps  934:                if ( ! html_bodytagname(mbuf, args, tok,
1.10      kristaps  935:                                        q, node->argc,
                    936:                                        (const char **)node->argv, &res))
1.7       kristaps  937:                        return(-1);
                    938:                break;
1.3       kristaps  939:        case (MD_NS_HEAD):
1.10      kristaps  940:                if ( ! html_headtagname(mbuf, args, tok,
                    941:                                        q, node->argc,
                    942:                                        (const char **)node->argv, &res))
1.7       kristaps  943:                        return(-1);
                    944:                break;
1.3       kristaps  945:        default:
1.7       kristaps  946:                if ( ! html_inlinetagname(mbuf, args, tok, &res))
                    947:                        return(-1);
1.3       kristaps  948:                break;
                    949:        }
1.2       kristaps  950:
1.8       kristaps  951:        q->last = node->parent;
                    952:
1.9       kristaps  953:        free(node);
1.8       kristaps  954:
1.7       kristaps  955:        return((ssize_t)res);
1.2       kristaps  956: }
                    957:
                    958:
1.9       kristaps  959: static int
                    960: html_alloc(void **p)
                    961: {
                    962:
                    963:        if (NULL == (*p = calloc(1, sizeof(struct htmlq)))) {
                    964:                warn("calloc");
                    965:                return(0);
                    966:        }
                    967:        return(1);
                    968: }
                    969:
                    970:
                    971: static void
                    972: html_free(void *p)
                    973: {
                    974:        struct htmlq    *q;
                    975:        struct htmlnode *n;
                    976:
                    977:        assert(p);
                    978:        q = (struct htmlq *)p;
                    979:
1.13      kristaps  980:        /* LINTED */
1.9       kristaps  981:        while ((n = q->last)) {
                    982:                q->last = n->parent;
                    983:                free(n);
                    984:        }
                    985:
                    986:        free(q);
                    987: }
                    988:
                    989:
1.23      kristaps  990: /* ARGSUSED */
1.14      kristaps  991: static ssize_t
                    992: html_beginhttp(struct md_mbuf *mbuf,
                    993:                const struct md_args *args,
                    994:                const char *buf, size_t sz)
                    995: {
                    996:        size_t           res;
1.19      kristaps  997:        struct html_pair pair;
1.14      kristaps  998:
                    999:        res = 0;
1.19      kristaps 1000:        pair.attr = HTML_ATTR_HREF;
                   1001:        pair.val = (char *)buf;
1.14      kristaps 1002:
1.19      kristaps 1003:        if ( ! html_aput(mbuf, ML_OPEN, HTML_TAG_A, &res, 1, &pair))
1.14      kristaps 1004:                return(-1);
                   1005:        return((ssize_t)res);
                   1006: }
                   1007:
                   1008:
1.23      kristaps 1009: /* ARGSUSED */
1.14      kristaps 1010: static ssize_t
                   1011: html_endhttp(struct md_mbuf *mbuf,
                   1012:                const struct md_args *args,
                   1013:                const char *buf, size_t sz)
                   1014: {
                   1015:        size_t           res;
                   1016:
                   1017:        res = 0;
1.19      kristaps 1018:        if ( ! html_tput(mbuf, ML_CLOSE, HTML_TAG_A, &res))
1.14      kristaps 1019:                return(-1);
                   1020:        return((ssize_t)res);
                   1021: }
                   1022:
                   1023:
                   1024: /* ARGSUSED */
                   1025: static ssize_t
                   1026: html_beginstring(struct md_mbuf *mbuf,
                   1027:                const struct md_args *args,
                   1028:                const char *buf, size_t sz)
                   1029: {
                   1030:
                   1031:        if (0 == strncmp(buf, "http://", 7))
                   1032:                return(html_beginhttp(mbuf, args, buf, sz));
                   1033:
                   1034:        return(0);
                   1035: }
                   1036:
                   1037:
                   1038: /* ARGSUSED */
                   1039: static ssize_t
                   1040: html_endstring(struct md_mbuf *mbuf,
                   1041:                const struct md_args *args,
                   1042:                const char *buf, size_t sz)
                   1043: {
                   1044:
                   1045:        if (0 == strncmp(buf, "http://", 7))
                   1046:                return(html_endhttp(mbuf, args, buf, sz));
                   1047:
                   1048:        return(0);
                   1049: }
                   1050:
                   1051:
1.1       kristaps 1052: int
                   1053: md_line_html(void *data, char *buf)
                   1054: {
                   1055:
1.2       kristaps 1056:        return(mlg_line((struct md_mlg *)data, buf));
1.1       kristaps 1057: }
                   1058:
                   1059:
                   1060: int
                   1061: md_exit_html(void *data, int flush)
                   1062: {
                   1063:
1.2       kristaps 1064:        return(mlg_exit((struct md_mlg *)data, flush));
1.1       kristaps 1065: }
                   1066:
                   1067:
                   1068: void *
                   1069: md_init_html(const struct md_args *args,
                   1070:                struct md_mbuf *mbuf, const struct md_rbuf *rbuf)
                   1071: {
1.9       kristaps 1072:        struct ml_cbs    cbs;
1.8       kristaps 1073:
1.9       kristaps 1074:        cbs.ml_alloc = html_alloc;
                   1075:        cbs.ml_free = html_free;
                   1076:        cbs.ml_begintag = html_begintag;
                   1077:        cbs.ml_endtag = html_endtag;
                   1078:        cbs.ml_begin = html_begin;
                   1079:        cbs.ml_end = html_end;
1.14      kristaps 1080:        cbs.ml_beginstring = html_beginstring;
                   1081:        cbs.ml_endstring = html_endstring;
1.1       kristaps 1082:
1.9       kristaps 1083:        return(mlg_alloc(args, rbuf, mbuf, &cbs));
1.1       kristaps 1084: }

CVSweb