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

Annotation of mandoc/html.c, Revision 1.20

1.20    ! kristaps    1: /* $Id: html.c,v 1.19 2008/12/10 00:52:46 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.15      kristaps   75:                                enum roffmsec, const char *);
1.7       kristaps   76: static int             html_printargs(struct md_mbuf *, int,
                     77:                                const char *, const int *,
                     78:                                const char **, size_t *);
1.2       kristaps   79: static int             html_end(struct md_mbuf *,
                     80:                                const struct md_args *);
1.7       kristaps   81: static int             html_blocktagname(struct md_mbuf *,
1.10      kristaps   82:                                const struct md_args *, int,
                     83:                                struct htmlq *, const int *,
                     84:                                const char **, size_t *);
1.7       kristaps   85: static int             html_blocktagargs(struct md_mbuf *,
1.2       kristaps   86:                                const struct md_args *, int,
1.7       kristaps   87:                                const int *, const char **, size_t *);
1.10      kristaps   88: static int             html_headtagname(struct md_mbuf *,
                     89:                                const struct md_args *, int,
                     90:                                struct htmlq *, const int *,
                     91:                                const char **, size_t *);
                     92: static int             html_headtagargs(struct md_mbuf *,
1.3       kristaps   93:                                const struct md_args *, int,
1.7       kristaps   94:                                const int *, const char **, size_t *);
1.12      kristaps   95: static int             html_bodytagname(struct md_mbuf *,
1.10      kristaps   96:                                const struct md_args *,
                     97:                                int, struct htmlq *, const int *,
                     98:                                const char **, size_t *);
1.12      kristaps   99: static int             html_bodytagargs(struct md_mbuf *,
1.3       kristaps  100:                                const struct md_args *, int,
1.7       kristaps  101:                                const int *, const char **, size_t *);
                    102: static int             html_inlinetagname(struct md_mbuf *,
                    103:                                const struct md_args *, int, size_t *);
                    104: static int             html_inlinetagargs(struct md_mbuf *,
1.2       kristaps  105:                                const struct md_args *, int,
1.7       kristaps  106:                                const int *, const char **, size_t *);
1.10      kristaps  107: static int             html_Bl_bodytagname(struct md_mbuf *,
                    108:                                struct htmlq *, const int *,
                    109:                                const char **, size_t *);
                    110: static int             html_It_blocktagname(struct md_mbuf *,
                    111:                                struct htmlq *, const int *,
                    112:                                const char **, size_t *);
                    113: static int             html_It_headtagname(struct md_mbuf *,
                    114:                                struct htmlq *, const int *,
                    115:                                const char **, size_t *);
                    116: static int             html_It_bodytagname(struct md_mbuf *,
                    117:                                struct htmlq *, const int *,
                    118:                                const char **, size_t *);
1.19      kristaps  119: static int             html_tputln(struct md_mbuf *,
                    120:                                enum ml_scope, int, enum html_tag);
                    121: static int             html_aputln(struct md_mbuf *, enum ml_scope,
                    122:                                int, enum html_tag,
                    123:                                int, const struct html_pair *);
1.10      kristaps  124:
                    125:
                    126: /* ARGSUSED */
                    127: static int
                    128: html_It_headtagname(struct md_mbuf *mbuf, struct htmlq *q,
                    129:                const int *argc, const char **argv, size_t *res)
                    130: {
                    131:        struct htmlnode *n;
1.11      kristaps  132:        int              i;
1.10      kristaps  133:
                    134:        for (n = q->last; n; n = n->parent)
                    135:                if (n->tok == ROFF_Bl)
                    136:                        break;
                    137:
                    138:        assert(n);
1.13      kristaps  139:
                    140:        /* LINTED */
1.11      kristaps  141:        for (i = 0; ROFF_ARGMAX != n->argc[i] &&
1.10      kristaps  142:                        i < ROFF_MAXLINEARG; i++) {
                    143:                switch (n->argc[i]) {
1.14      kristaps  144:                case (ROFF_Ohang):
1.19      kristaps  145:                        return(html_stput(mbuf, HTML_TAG_DIV, res));
1.10      kristaps  146:                case (ROFF_Tag):
                    147:                        /* FALLTHROUGH */
                    148:                case (ROFF_Column):
1.19      kristaps  149:                        return(html_stput(mbuf, HTML_TAG_TD, res));
1.10      kristaps  150:                default:
                    151:                        break;
                    152:                }
                    153:        }
                    154:
1.16      kristaps  155:        return(0);
1.10      kristaps  156: }
                    157:
                    158:
                    159: /* ARGSUSED */
                    160: static int
                    161: html_It_bodytagname(struct md_mbuf *mbuf, struct htmlq *q,
                    162:                const int *argc, const char **argv, size_t *res)
                    163: {
                    164:        struct htmlnode *n;
1.11      kristaps  165:        int              i;
1.10      kristaps  166:
                    167:        for (n = q->last; n; n = n->parent)
                    168:                if (n->tok == ROFF_Bl)
                    169:                        break;
                    170:
                    171:        assert(n);
1.13      kristaps  172:
                    173:        /* LINTED */
1.11      kristaps  174:        for (i = 0; ROFF_ARGMAX != n->argc[i] &&
1.10      kristaps  175:                        i < ROFF_MAXLINEARG; i++) {
                    176:                switch (n->argc[i]) {
                    177:                case (ROFF_Enum):
                    178:                        /* FALLTHROUGH */
                    179:                case (ROFF_Bullet):
                    180:                        /* FALLTHROUGH */
                    181:                case (ROFF_Dash):
                    182:                        /* FALLTHROUGH */
                    183:                case (ROFF_Hyphen):
                    184:                        /* FALLTHROUGH */
                    185:                case (ROFF_Item):
                    186:                        /* FALLTHROUGH */
                    187:                case (ROFF_Diag):
                    188:                        /* FALLTHROUGH */
                    189:                case (ROFF_Hang):
                    190:                        /* FALLTHROUGH */
                    191:                case (ROFF_Ohang):
                    192:                        /* FALLTHROUGH */
                    193:                case (ROFF_Inset):
1.19      kristaps  194:                        return(html_stput(mbuf, HTML_TAG_DIV, res));
1.10      kristaps  195:                case (ROFF_Tag):
                    196:                        /* FALLTHROUGH */
                    197:                case (ROFF_Column):
1.19      kristaps  198:                        return(html_stput(mbuf, HTML_TAG_TD, res));
1.10      kristaps  199:                default:
                    200:                        break;
                    201:                }
                    202:        }
                    203:
                    204:        assert(i != ROFF_MAXLINEARG);
1.16      kristaps  205:        return(0);
1.10      kristaps  206: }
                    207:
                    208:
                    209: /* ARGSUSED */
                    210: static int
                    211: html_Bl_bodytagname(struct md_mbuf *mbuf, struct htmlq *q,
                    212:                const int *argc, const char **argv, size_t *res)
                    213: {
1.11      kristaps  214:        int              i;
1.10      kristaps  215:
1.11      kristaps  216:        for (i = 0; ROFF_ARGMAX != argc[i]
1.10      kristaps  217:                        && i < ROFF_MAXLINEARG; i++) {
                    218:                switch (argc[i]) {
                    219:                case (ROFF_Enum):
1.19      kristaps  220:                        return(html_stput(mbuf, HTML_TAG_OL, res));
1.10      kristaps  221:                case (ROFF_Bullet):
                    222:                        /* FALLTHROUGH */
                    223:                case (ROFF_Dash):
                    224:                        /* FALLTHROUGH */
                    225:                case (ROFF_Hyphen):
                    226:                        /* FALLTHROUGH */
                    227:                case (ROFF_Item):
                    228:                        /* FALLTHROUGH */
                    229:                case (ROFF_Diag):
                    230:                        /* FALLTHROUGH */
                    231:                case (ROFF_Hang):
                    232:                        /* FALLTHROUGH */
                    233:                case (ROFF_Ohang):
                    234:                        /* FALLTHROUGH */
                    235:                case (ROFF_Inset):
1.19      kristaps  236:                        return(html_stput(mbuf, HTML_TAG_UL, res));
1.10      kristaps  237:                case (ROFF_Tag):
                    238:                        /* FALLTHROUGH */
                    239:                case (ROFF_Column):
1.19      kristaps  240:                        return(html_stput(mbuf, HTML_TAG_TABLE, res));
1.10      kristaps  241:                default:
                    242:                        break;
                    243:                }
                    244:        }
                    245:
                    246:        assert(i != ROFF_MAXLINEARG);
1.16      kristaps  247:        return(0);
1.10      kristaps  248: }
                    249:
                    250:
                    251: /* ARGSUSED */
                    252: static int
                    253: html_It_blocktagname(struct md_mbuf *mbuf, struct htmlq *q,
                    254:                const int *argc, const char **argv, size_t *res)
                    255: {
                    256:        struct htmlnode *n;
1.11      kristaps  257:        int              i;
1.10      kristaps  258:
                    259:        for (n = q->last; n; n = n->parent)
                    260:                if (n->tok == ROFF_Bl)
                    261:                        break;
                    262:
                    263:        assert(n);
1.13      kristaps  264:
                    265:        /* LINTED */
1.11      kristaps  266:        for (i = 0; ROFF_ARGMAX != n->argc[i] &&
1.10      kristaps  267:                        i < ROFF_MAXLINEARG; i++) {
                    268:                switch (n->argc[i]) {
                    269:                case (ROFF_Enum):
                    270:                        /* FALLTHROUGH */
                    271:                case (ROFF_Bullet):
                    272:                        /* FALLTHROUGH */
                    273:                case (ROFF_Dash):
                    274:                        /* FALLTHROUGH */
                    275:                case (ROFF_Hyphen):
                    276:                        /* FALLTHROUGH */
                    277:                case (ROFF_Item):
                    278:                        /* FALLTHROUGH */
                    279:                case (ROFF_Diag):
                    280:                        /* FALLTHROUGH */
                    281:                case (ROFF_Hang):
                    282:                        /* FALLTHROUGH */
                    283:                case (ROFF_Ohang):
                    284:                        /* FALLTHROUGH */
                    285:                case (ROFF_Inset):
1.19      kristaps  286:                        return(html_stput(mbuf, HTML_TAG_LI, res));
1.10      kristaps  287:                case (ROFF_Tag):
                    288:                        /* FALLTHROUGH */
                    289:                case (ROFF_Column):
1.19      kristaps  290:                        return(html_stput(mbuf, HTML_TAG_TR, res));
1.10      kristaps  291:                default:
                    292:                        break;
                    293:                }
                    294:        }
                    295:
                    296:        assert(i != ROFF_MAXLINEARG);
1.16      kristaps  297:        return(0);
1.10      kristaps  298: }
1.2       kristaps  299:
                    300:
1.4       kristaps  301: static int
                    302: html_loadcss(struct md_mbuf *mbuf, const char *css)
                    303: {
                    304:        size_t           res, bufsz;
                    305:        char            *buf;
                    306:        struct stat      st;
                    307:        int              fd, c;
                    308:        ssize_t          ssz;
                    309:
                    310:        c = 0;
                    311:        res = 0;
                    312:        buf = NULL;
                    313:
                    314:        if (-1 == (fd = open(css, O_RDONLY, 0))) {
                    315:                warn("%s", css);
                    316:                return(0);
                    317:        }
                    318:
                    319:        if (-1 == fstat(fd, &st)) {
                    320:                warn("%s", css);
                    321:                goto out;
                    322:        }
                    323:
                    324:        bufsz = MAX(st.st_blksize, BUFSIZ);
                    325:        if (NULL == (buf = malloc(bufsz))) {
                    326:                warn("malloc");
                    327:                goto out;
                    328:        }
                    329:
                    330:        for (;;) {
                    331:                if (-1 == (ssz = read(fd, buf, bufsz))) {
                    332:                        warn("%s", css);
                    333:                        goto out;
                    334:                } else if (0 == ssz)
                    335:                        break;
                    336:                if ( ! ml_nputs(mbuf, buf, (size_t)ssz, &res))
                    337:                        goto out;
                    338:        }
                    339:
                    340:        c = 1;
                    341:
                    342: out:
                    343:        if (-1 == close(fd)) {
                    344:                warn("%s", css);
                    345:                c = 0;
                    346:        }
                    347:
                    348:        if (buf)
                    349:                free(buf);
                    350:
                    351:        return(c);
                    352: }
                    353:
                    354:
1.18      kristaps  355: static int
1.19      kristaps  356: html_tputln(struct md_mbuf *mbuf, enum ml_scope scope,
                    357:                int i, enum html_tag tag)
1.18      kristaps  358: {
                    359:
1.19      kristaps  360:        if ( ! ml_putchars(mbuf, ' ', INDENT(i) * INDENT_SZ, NULL))
1.18      kristaps  361:                return(0);
1.19      kristaps  362:        if ( ! html_tput(mbuf, scope, tag, NULL))
1.18      kristaps  363:                return(0);
1.19      kristaps  364:        return(ml_nputs(mbuf, "\n", 1, NULL));
1.18      kristaps  365: }
                    366:
                    367:
                    368: static int
1.19      kristaps  369: html_aputln(struct md_mbuf *mbuf, enum ml_scope scope, int i,
                    370:                enum html_tag tag, int sz, const struct html_pair *p)
1.18      kristaps  371: {
                    372:
1.19      kristaps  373:        if ( ! ml_putchars(mbuf, ' ', INDENT(i) * INDENT_SZ, NULL))
1.18      kristaps  374:                return(0);
1.19      kristaps  375:        if ( ! html_aput(mbuf, scope, tag, NULL, sz, p))
                    376:                return(0);
                    377:        return(ml_nputs(mbuf, "\n", 1, NULL));
1.18      kristaps  378: }
                    379:
                    380:
1.3       kristaps  381: /* ARGSUSED */
1.2       kristaps  382: static int
1.4       kristaps  383: html_begin(struct md_mbuf *mbuf, const struct md_args *args,
                    384:                const struct tm *tm, const char *os,
1.19      kristaps  385:                const char *name, enum roffmsec msec, const char *vol)
1.2       kristaps  386: {
1.19      kristaps  387:        struct html_pair attr[4];
                    388:        char             ts[32];
                    389:        int              i;
1.2       kristaps  390:
1.19      kristaps  391:        (void)snprintf(ts, sizeof(ts), "%s(%s)",
                    392:                        name, roff_msecname(msec));
1.4       kristaps  393:
1.18      kristaps  394:        i = 0;
1.4       kristaps  395:
1.19      kristaps  396:        if ( ! html_typeput(mbuf, HTML_TYPE_4_01_STRICT, NULL))
1.17      kristaps  397:                return(0);
1.19      kristaps  398:        if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_HTML))
1.17      kristaps  399:                return(0);
1.19      kristaps  400:        if ( ! html_tputln(mbuf, ML_OPEN, i++, HTML_TAG_HEAD))
1.17      kristaps  401:                return(0);
1.19      kristaps  402:
                    403:        attr[0].attr = HTML_ATTR_HTTP_EQUIV;
                    404:        attr[0].val = "content-type";
                    405:        attr[1].attr = HTML_ATTR_CONTENT;
                    406:        attr[1].val = "text/html;charset=utf-8";
                    407:
                    408:        if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_META, 2, attr))
1.17      kristaps  409:                return(0);
1.19      kristaps  410:
                    411:        attr[0].attr = HTML_ATTR_NAME;
                    412:        attr[0].val = "resource-type";
                    413:        attr[1].attr = HTML_ATTR_CONTENT;
                    414:        attr[1].val = "document";
                    415:
                    416:        if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_META, 2, attr))
1.17      kristaps  417:                return(0);
1.19      kristaps  418:
                    419:        if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_TITLE))
1.17      kristaps  420:                return(0);
1.19      kristaps  421:        if ( ! ml_putstring(mbuf, ts, NULL))
1.17      kristaps  422:                return(0);
1.19      kristaps  423:        if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TITLE))
1.2       kristaps  424:                return(0);
1.4       kristaps  425:
                    426:        if (HTML_CSS_EMBED & args->params.html.flags) {
1.19      kristaps  427:                attr[0].attr = HTML_ATTR_TYPE;
                    428:                attr[0].val = "text/css";
                    429:
                    430:                if ( ! html_aputln(mbuf, ML_OPEN, i,
                    431:                                        HTML_TAG_STYLE, 1, attr))
1.4       kristaps  432:                        return(0);
1.19      kristaps  433:                if ( ! html_commentput(mbuf, ML_OPEN, NULL))
                    434:                        return(NULL);
                    435:
1.4       kristaps  436:                if ( ! html_loadcss(mbuf, args->params.html.css))
                    437:                        return(0);
1.19      kristaps  438:
                    439:                if ( ! html_commentput(mbuf, ML_CLOSE, NULL))
                    440:                        return(NULL);
                    441:                if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_STYLE))
1.4       kristaps  442:                        return(0);
1.19      kristaps  443:        } else {
                    444:                attr[0].attr = HTML_ATTR_REL;
                    445:                attr[0].val = "stylesheet";
                    446:                attr[1].attr = HTML_ATTR_TYPE;
                    447:                attr[1].val = "text/css";
                    448:                attr[2].attr = HTML_ATTR_HREF;
                    449:                attr[2].val = args->params.html.css;
                    450:
                    451:                if ( ! html_aputln(mbuf, ML_OPEN, i,
                    452:                                        HTML_TAG_LINK, 3, attr))
                    453:                        return(0);
                    454:        }
1.4       kristaps  455:
1.19      kristaps  456:        if ( ! html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_HEAD))
1.18      kristaps  457:                return(0);
1.19      kristaps  458:        if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_BODY))
1.18      kristaps  459:                return(0);
1.19      kristaps  460:
                    461:        attr[0].attr = HTML_ATTR_CLASS;
                    462:        attr[0].val = "mdoc";
                    463:
                    464:        if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_DIV, 1, attr))
1.18      kristaps  465:                return(0);
1.19      kristaps  466:
                    467:        attr[0].attr = HTML_ATTR_WIDTH;
                    468:        attr[0].val = "100%";
                    469:
                    470:        if ( ! html_aputln(mbuf, ML_OPEN, i++, HTML_TAG_TABLE, 1, attr))
1.18      kristaps  471:                return(0);
1.19      kristaps  472:        if ( ! html_tputln(mbuf, ML_OPEN, i++, HTML_TAG_TR))
1.18      kristaps  473:                return(0);
1.19      kristaps  474:
                    475:        if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_TD))
1.2       kristaps  476:                return(0);
1.19      kristaps  477:        if ( ! ml_putstring(mbuf, ts, NULL))
1.18      kristaps  478:                return(0);
1.19      kristaps  479:        if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD))
1.18      kristaps  480:                return(0);
1.19      kristaps  481:
                    482:        if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_TD))
1.18      kristaps  483:                return(0);
1.19      kristaps  484:        /* TODO: middle. */
                    485:        if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD))
1.18      kristaps  486:                return(0);
1.19      kristaps  487:
1.20    ! kristaps  488:        attr[0].attr = HTML_ATTR_ALIGN;
        !           489:        attr[0].val = "right";
        !           490:
        !           491:        if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_TD, 1, attr))
1.18      kristaps  492:                return(0);
1.19      kristaps  493:        if ( ! ml_putstring(mbuf, ts, NULL))
1.17      kristaps  494:                return(0);
1.19      kristaps  495:        if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD))
1.17      kristaps  496:                return(0);
1.19      kristaps  497:
                    498:        if ( ! html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_TR))
1.17      kristaps  499:                return(0);
1.19      kristaps  500:        return(html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_TABLE));
1.2       kristaps  501: }
                    502:
                    503:
1.3       kristaps  504: /* ARGSUSED */
1.2       kristaps  505: static int
                    506: html_end(struct md_mbuf *mbuf, const struct md_args *args)
                    507: {
                    508:
1.19      kristaps  509:        if ( ! html_tputln(mbuf, ML_CLOSE, 0, HTML_TAG_DIV))
1.18      kristaps  510:                return(0);
1.19      kristaps  511:        if ( ! html_tputln(mbuf, ML_CLOSE, 0, HTML_TAG_BODY))
1.18      kristaps  512:                return(0);
1.19      kristaps  513:        return(html_tputln(mbuf, ML_CLOSE, 0, HTML_TAG_HTML));
1.2       kristaps  514: }
                    515:
                    516:
1.3       kristaps  517: /* ARGSUSED */
1.7       kristaps  518: static int
1.12      kristaps  519: html_bodytagname(struct md_mbuf *mbuf,
1.10      kristaps  520:                const struct md_args *args, int tok, struct htmlq *q,
                    521:                const int *argc, const char **argv, size_t *res)
1.2       kristaps  522: {
1.3       kristaps  523:
1.10      kristaps  524:        switch (tok) {
                    525:        case (ROFF_Bl):
                    526:                return(html_Bl_bodytagname(mbuf, q, argc, argv, res));
1.12      kristaps  527:        case (ROFF_Fo):
1.19      kristaps  528:                return(html_stput(mbuf, HTML_TAG_SPAN, res));
1.10      kristaps  529:        case (ROFF_It):
                    530:                return(html_It_bodytagname(mbuf, q, argc, argv, res));
1.12      kristaps  531:        case (ROFF_Oo):
1.19      kristaps  532:                return(html_stput(mbuf, HTML_TAG_SPAN, res));
1.10      kristaps  533:        default:
                    534:                break;
                    535:        }
                    536:
1.19      kristaps  537:        return(html_stput(mbuf, HTML_TAG_DIV, res));
1.3       kristaps  538: }
                    539:
                    540:
                    541: /* ARGSUSED */
1.7       kristaps  542: static int
1.10      kristaps  543: html_headtagname(struct md_mbuf *mbuf,
                    544:                const struct md_args *args, int tok, struct htmlq *q,
                    545:                const int *argc, const char **argv, size_t *res)
1.3       kristaps  546: {
                    547:
1.10      kristaps  548:        switch (tok) {
                    549:        case (ROFF_It):
                    550:                return(html_It_headtagname(mbuf, q, argc, argv, res));
1.12      kristaps  551:        case (ROFF_Fo):
1.19      kristaps  552:                /* FALLTHROUGH */
1.12      kristaps  553:        case (ROFF_Oo):
1.19      kristaps  554:                return(html_stput(mbuf, HTML_TAG_SPAN, res));
1.10      kristaps  555:        case (ROFF_Sh):
1.19      kristaps  556:                return(html_stput(mbuf, HTML_TAG_H1, res));
1.10      kristaps  557:        case (ROFF_Ss):
1.19      kristaps  558:                return(html_stput(mbuf, HTML_TAG_H2, res));
1.10      kristaps  559:        default:
                    560:                break;
                    561:        }
                    562:
1.19      kristaps  563:        return(html_stput(mbuf, HTML_TAG_DIV, res));
1.3       kristaps  564: }
                    565:
                    566:
                    567: /* ARGSUSED */
1.7       kristaps  568: static int
1.10      kristaps  569: html_blocktagname(struct md_mbuf *mbuf, const struct md_args *args,
                    570:                int tok, struct htmlq *q, const int *argc,
                    571:                const char **argv, size_t *res)
1.3       kristaps  572: {
                    573:
1.10      kristaps  574:        switch (tok) {
1.12      kristaps  575:        case (ROFF_Fo):
1.19      kristaps  576:                /* FALLTHROUGH */
1.12      kristaps  577:        case (ROFF_Oo):
1.19      kristaps  578:                return(html_stput(mbuf, HTML_TAG_SPAN, res));
1.10      kristaps  579:        case (ROFF_It):
                    580:                return(html_It_blocktagname(mbuf, q, argc, argv, res));
                    581:        default:
                    582:                break;
                    583:        }
                    584:
1.19      kristaps  585:        return(html_stput(mbuf, HTML_TAG_DIV, res));
1.3       kristaps  586: }
                    587:
                    588:
1.9       kristaps  589: /* ARGSUSED */
1.7       kristaps  590: static int
                    591: html_printargs(struct md_mbuf *mbuf, int tok, const char *ns,
                    592:                const int *argc, const char **argv, size_t *res)
1.3       kristaps  593: {
                    594:
1.19      kristaps  595:        /* FIXME: use API in ml.h. */
                    596:
1.7       kristaps  597:        if ( ! ml_puts(mbuf, " class=\"", res))
                    598:                return(0);
                    599:        if ( ! ml_puts(mbuf, ns, res))
                    600:                return(0);
                    601:        if ( ! ml_puts(mbuf, "-", res))
1.3       kristaps  602:                return(0);
1.7       kristaps  603:        if ( ! ml_puts(mbuf, toknames[tok], res))
1.3       kristaps  604:                return(0);
1.9       kristaps  605:        return(ml_puts(mbuf, "\"", res));
1.3       kristaps  606: }
                    607:
                    608:
                    609: /* ARGSUSED */
1.7       kristaps  610: static int
1.10      kristaps  611: html_headtagargs(struct md_mbuf *mbuf,
1.7       kristaps  612:                const struct md_args *args, int tok,
                    613:                const int *argc, const char **argv, size_t *res)
1.3       kristaps  614: {
                    615:
1.7       kristaps  616:        return(html_printargs(mbuf, tok, "head", argc, argv, res));
                    617: }
1.3       kristaps  618:
                    619:
1.7       kristaps  620: /* ARGSUSED */
                    621: static int
1.12      kristaps  622: html_bodytagargs(struct md_mbuf *mbuf,
1.7       kristaps  623:                const struct md_args *args, int tok,
                    624:                const int *argc, const char **argv, size_t *res)
                    625: {
1.3       kristaps  626:
1.7       kristaps  627:        return(html_printargs(mbuf, tok, "body", argc, argv, res));
1.2       kristaps  628: }
                    629:
                    630:
                    631: /* ARGSUSED */
1.7       kristaps  632: static int
                    633: html_blocktagargs(struct md_mbuf *mbuf,
                    634:                const struct md_args *args, int tok,
                    635:                const int *argc, const char **argv, size_t *res)
1.2       kristaps  636: {
1.3       kristaps  637:
1.7       kristaps  638:        return(html_printargs(mbuf, tok, "block", argc, argv, res));
1.2       kristaps  639: }
1.1       kristaps  640:
                    641:
                    642: /* ARGSUSED */
1.7       kristaps  643: static int
                    644: html_inlinetagargs(struct md_mbuf *mbuf,
                    645:                const struct md_args *args, int tok,
                    646:                const int *argc, const char **argv, size_t *res)
1.2       kristaps  647: {
                    648:
1.12      kristaps  649:        if ( ! html_printargs(mbuf, tok, "inline", argc, argv, res))
                    650:                return(0);
                    651:
                    652:        switch (tok) {
                    653:        case (ROFF_Sx):
1.19      kristaps  654:
                    655:                /* FIXME: use API in ml.h. */
                    656:
1.12      kristaps  657:                assert(*argv);
                    658:                if ( ! ml_nputs(mbuf, " href=\"#", 8, res))
                    659:                        return(0);
                    660:                if ( ! ml_putstring(mbuf, *argv, res))
                    661:                        return(0);
                    662:                if ( ! ml_nputs(mbuf, "\"", 1, res))
                    663:                        return(0);
1.13      kristaps  664:                break;
1.12      kristaps  665:        default:
                    666:                break;
                    667:        }
                    668:
                    669:        return(1);
1.2       kristaps  670: }
                    671:
                    672:
1.3       kristaps  673: /* ARGSUSED */
1.7       kristaps  674: static int
1.2       kristaps  675: html_inlinetagname(struct md_mbuf *mbuf,
1.7       kristaps  676:                const struct md_args *args, int tok, size_t *res)
1.2       kristaps  677: {
                    678:
                    679:        switch (tok) {
1.4       kristaps  680:        case (ROFF_Pp):
1.19      kristaps  681:                return(html_stput(mbuf, HTML_TAG_DIV, res));
1.12      kristaps  682:        case (ROFF_Sx):
1.19      kristaps  683:                return(html_stput(mbuf, HTML_TAG_A, res));
1.2       kristaps  684:        default:
1.9       kristaps  685:                break;
1.2       kristaps  686:        }
1.9       kristaps  687:
1.19      kristaps  688:        return(html_stput(mbuf, HTML_TAG_SPAN, res));
1.2       kristaps  689: }
                    690:
                    691:
                    692: static ssize_t
1.8       kristaps  693: html_begintag(struct md_mbuf *mbuf, void *data,
                    694:                const struct md_args *args, enum md_ns ns,
                    695:                int tok, const int *argc, const char **argv)
1.2       kristaps  696: {
1.7       kristaps  697:        size_t           res;
1.8       kristaps  698:        struct htmlq    *q;
                    699:        struct htmlnode *node;
1.11      kristaps  700:        int              i;
1.2       kristaps  701:
                    702:        assert(ns != MD_NS_DEFAULT);
1.7       kristaps  703:        res = 0;
                    704:
1.8       kristaps  705:        assert(data);
                    706:        q = (struct htmlq *)data;
                    707:
                    708:        if (NULL == (node = calloc(1, sizeof(struct htmlnode)))) {
                    709:                warn("calloc");
                    710:                return(-1);
                    711:        }
                    712:
                    713:        node->parent = q->last;
                    714:        node->tok = tok;
                    715:        node->ns = ns;
                    716:
1.10      kristaps  717:        if (argc)  {
                    718:                /* TODO: argv. */
                    719:
                    720:                assert(argv);
1.13      kristaps  721:                /* LINTED */
1.11      kristaps  722:                for (i = 0; ROFF_ARGMAX != argc[i]
1.10      kristaps  723:                                && i < ROFF_MAXLINEARG; i++)
                    724:                        node->argc[i] = argc[i];
                    725:                assert(i != ROFF_MAXLINEARG);
1.12      kristaps  726:        }
1.10      kristaps  727:
                    728:
1.8       kristaps  729:        q->last = node;
                    730:
1.3       kristaps  731:        switch (ns) {
                    732:        case (MD_NS_BLOCK):
1.10      kristaps  733:                if ( ! html_blocktagname(mbuf, args, tok,
                    734:                                        q, argc, argv, &res))
1.7       kristaps  735:                        return(-1);
                    736:                if ( ! html_blocktagargs(mbuf, args, tok,
                    737:                                        argc, argv, &res))
                    738:                        return(-1);
                    739:                break;
1.3       kristaps  740:        case (MD_NS_BODY):
1.12      kristaps  741:                if ( ! html_bodytagname(mbuf, args, tok,
1.10      kristaps  742:                                        q, argc, argv, &res))
1.7       kristaps  743:                        return(-1);
1.12      kristaps  744:                if ( ! html_bodytagargs(mbuf, args, tok,
1.7       kristaps  745:                                        argc, argv, &res))
                    746:                        return(-1);
                    747:                break;
1.3       kristaps  748:        case (MD_NS_HEAD):
1.10      kristaps  749:                if ( ! html_headtagname(mbuf, args, tok, q,
                    750:                                        argc, argv, &res))
1.7       kristaps  751:                        return(-1);
1.10      kristaps  752:                if ( ! html_headtagargs(mbuf, args, tok,
1.7       kristaps  753:                                        argc, argv, &res))
                    754:                        return(-1);
                    755:                break;
1.3       kristaps  756:        default:
1.7       kristaps  757:                if ( ! html_inlinetagname(mbuf, args, tok, &res))
                    758:                        return(-1);
                    759:                if ( ! html_inlinetagargs(mbuf, args, tok,
                    760:                                        argc, argv, &res))
                    761:                        return(-1);
1.3       kristaps  762:                break;
1.2       kristaps  763:        }
                    764:
1.7       kristaps  765:        return((ssize_t)res);
1.2       kristaps  766: }
                    767:
                    768:
                    769: static ssize_t
1.8       kristaps  770: html_endtag(struct md_mbuf *mbuf, void *data,
                    771:                const struct md_args *args, enum md_ns ns, int tok)
1.2       kristaps  772: {
1.7       kristaps  773:        size_t           res;
1.8       kristaps  774:        struct htmlq    *q;
                    775:        struct htmlnode *node;
1.2       kristaps  776:
                    777:        assert(ns != MD_NS_DEFAULT);
1.7       kristaps  778:        res = 0;
                    779:
1.8       kristaps  780:        assert(data);
                    781:        q = (struct htmlq *)data;
1.10      kristaps  782:        node = q->last;
1.8       kristaps  783:
1.3       kristaps  784:        switch (ns) {
                    785:        case (MD_NS_BLOCK):
1.10      kristaps  786:                if ( ! html_blocktagname(mbuf, args, tok,
                    787:                                        q, node->argc,
                    788:                                        (const char **)node->argv, &res))
1.7       kristaps  789:                        return(-1);
                    790:                break;
1.3       kristaps  791:        case (MD_NS_BODY):
1.12      kristaps  792:                if ( ! html_bodytagname(mbuf, args, tok,
1.10      kristaps  793:                                        q, node->argc,
                    794:                                        (const char **)node->argv, &res))
1.7       kristaps  795:                        return(-1);
                    796:                break;
1.3       kristaps  797:        case (MD_NS_HEAD):
1.10      kristaps  798:                if ( ! html_headtagname(mbuf, args, tok,
                    799:                                        q, node->argc,
                    800:                                        (const char **)node->argv, &res))
1.7       kristaps  801:                        return(-1);
                    802:                break;
1.3       kristaps  803:        default:
1.7       kristaps  804:                if ( ! html_inlinetagname(mbuf, args, tok, &res))
                    805:                        return(-1);
1.3       kristaps  806:                break;
                    807:        }
1.2       kristaps  808:
1.8       kristaps  809:        q->last = node->parent;
                    810:
1.9       kristaps  811:        free(node);
1.8       kristaps  812:
1.7       kristaps  813:        return((ssize_t)res);
1.2       kristaps  814: }
                    815:
                    816:
1.9       kristaps  817: static int
                    818: html_alloc(void **p)
                    819: {
                    820:
                    821:        if (NULL == (*p = calloc(1, sizeof(struct htmlq)))) {
                    822:                warn("calloc");
                    823:                return(0);
                    824:        }
                    825:        return(1);
                    826: }
                    827:
                    828:
                    829: static void
                    830: html_free(void *p)
                    831: {
                    832:        struct htmlq    *q;
                    833:        struct htmlnode *n;
                    834:
                    835:        assert(p);
                    836:        q = (struct htmlq *)p;
                    837:
1.13      kristaps  838:        /* LINTED */
1.9       kristaps  839:        while ((n = q->last)) {
                    840:                q->last = n->parent;
                    841:                free(n);
                    842:        }
                    843:
                    844:        free(q);
                    845: }
                    846:
                    847:
1.14      kristaps  848: static ssize_t
                    849: html_beginhttp(struct md_mbuf *mbuf,
                    850:                const struct md_args *args,
                    851:                const char *buf, size_t sz)
                    852: {
                    853:        size_t           res;
1.19      kristaps  854:        struct html_pair pair;
1.14      kristaps  855:
                    856:        res = 0;
1.19      kristaps  857:        pair.attr = HTML_ATTR_HREF;
                    858:        pair.val = (char *)buf;
1.14      kristaps  859:
1.19      kristaps  860:        if ( ! html_aput(mbuf, ML_OPEN, HTML_TAG_A, &res, 1, &pair))
1.14      kristaps  861:                return(-1);
                    862:        return((ssize_t)res);
                    863: }
                    864:
                    865:
                    866: static ssize_t
                    867: html_endhttp(struct md_mbuf *mbuf,
                    868:                const struct md_args *args,
                    869:                const char *buf, size_t sz)
                    870: {
                    871:        size_t           res;
                    872:
                    873:        res = 0;
1.19      kristaps  874:        if ( ! html_tput(mbuf, ML_CLOSE, HTML_TAG_A, &res))
1.14      kristaps  875:                return(-1);
                    876:        return((ssize_t)res);
                    877: }
                    878:
                    879:
                    880: /* ARGSUSED */
                    881: static ssize_t
                    882: html_beginstring(struct md_mbuf *mbuf,
                    883:                const struct md_args *args,
                    884:                const char *buf, size_t sz)
                    885: {
                    886:
                    887:        if (0 == strncmp(buf, "http://", 7))
                    888:                return(html_beginhttp(mbuf, args, buf, sz));
                    889:
                    890:        return(0);
                    891: }
                    892:
                    893:
                    894: /* ARGSUSED */
                    895: static ssize_t
                    896: html_endstring(struct md_mbuf *mbuf,
                    897:                const struct md_args *args,
                    898:                const char *buf, size_t sz)
                    899: {
                    900:
                    901:        if (0 == strncmp(buf, "http://", 7))
                    902:                return(html_endhttp(mbuf, args, buf, sz));
                    903:
                    904:        return(0);
                    905: }
                    906:
                    907:
1.1       kristaps  908: int
                    909: md_line_html(void *data, char *buf)
                    910: {
                    911:
1.2       kristaps  912:        return(mlg_line((struct md_mlg *)data, buf));
1.1       kristaps  913: }
                    914:
                    915:
                    916: int
                    917: md_exit_html(void *data, int flush)
                    918: {
                    919:
1.2       kristaps  920:        return(mlg_exit((struct md_mlg *)data, flush));
1.1       kristaps  921: }
                    922:
                    923:
                    924: void *
                    925: md_init_html(const struct md_args *args,
                    926:                struct md_mbuf *mbuf, const struct md_rbuf *rbuf)
                    927: {
1.9       kristaps  928:        struct ml_cbs    cbs;
1.8       kristaps  929:
1.9       kristaps  930:        cbs.ml_alloc = html_alloc;
                    931:        cbs.ml_free = html_free;
                    932:        cbs.ml_begintag = html_begintag;
                    933:        cbs.ml_endtag = html_endtag;
                    934:        cbs.ml_begin = html_begin;
                    935:        cbs.ml_end = html_end;
1.14      kristaps  936:        cbs.ml_beginstring = html_beginstring;
                    937:        cbs.ml_endstring = html_endstring;
1.1       kristaps  938:
1.9       kristaps  939:        return(mlg_alloc(args, rbuf, mbuf, &cbs));
1.1       kristaps  940: }

CVSweb