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

Annotation of mandoc/html.c, Revision 1.17

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

CVSweb