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

Annotation of mandoc/html.c, Revision 1.57

1.57    ! kristaps    1: /*     $Id: html.c,v 1.56 2009/10/03 16:37:23 kristaps Exp $ */
1.1       kristaps    2: /*
1.29      kristaps    3:  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
1.1       kristaps    4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
1.29      kristaps    6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
1.1       kristaps    8:  *
1.29      kristaps    9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1       kristaps   16:  */
1.41      kristaps   17: #include <sys/types.h>
1.30      kristaps   18: #include <sys/queue.h>
                     19:
1.1       kristaps   20: #include <assert.h>
1.4       kristaps   21: #include <err.h>
1.29      kristaps   22: #include <stdio.h>
1.55      kristaps   23: #include <stdarg.h>
1.1       kristaps   24: #include <stdlib.h>
1.33      kristaps   25: #include <string.h>
1.45      kristaps   26: #include <unistd.h>
1.1       kristaps   27:
1.32      kristaps   28: #include "chars.h"
1.51      kristaps   29: #include "html.h"
1.2       kristaps   30:
1.29      kristaps   31: #define        DOCTYPE         "-//W3C//DTD HTML 4.01//EN"
                     32: #define        DTD             "http://www.w3.org/TR/html4/strict.dtd"
1.8       kristaps   33:
1.29      kristaps   34: struct htmldata {
                     35:        char             *name;
                     36:        int               flags;
1.30      kristaps   37: #define        HTML_CLRLINE     (1 << 0)
                     38: #define        HTML_NOSTACK     (1 << 1)
1.29      kristaps   39: };
1.7       kristaps   40:
1.29      kristaps   41: static const struct htmldata htmltags[TAG_MAX] = {
1.30      kristaps   42:        {"html",        HTML_CLRLINE}, /* TAG_HTML */
                     43:        {"head",        HTML_CLRLINE}, /* TAG_HEAD */
                     44:        {"body",        HTML_CLRLINE}, /* TAG_BODY */
                     45:        {"meta",        HTML_CLRLINE | HTML_NOSTACK}, /* TAG_META */
1.33      kristaps   46:        {"title",       HTML_CLRLINE}, /* TAG_TITLE */
1.30      kristaps   47:        {"div",         HTML_CLRLINE}, /* TAG_DIV */
1.29      kristaps   48:        {"h1",          0}, /* TAG_H1 */
                     49:        {"h2",          0}, /* TAG_H2 */
1.30      kristaps   50:        {"p",           HTML_CLRLINE}, /* TAG_P */
1.29      kristaps   51:        {"span",        0}, /* TAG_SPAN */
1.30      kristaps   52:        {"link",        HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */
                     53:        {"br",          HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */
                     54:        {"a",           0}, /* TAG_A */
1.33      kristaps   55:        {"table",       HTML_CLRLINE}, /* TAG_TABLE */
                     56:        {"col",         HTML_CLRLINE | HTML_NOSTACK}, /* TAG_COL */
                     57:        {"tr",          HTML_CLRLINE}, /* TAG_TR */
                     58:        {"td",          HTML_CLRLINE}, /* TAG_TD */
1.34      kristaps   59:        {"li",          HTML_CLRLINE}, /* TAG_LI */
                     60:        {"ul",          HTML_CLRLINE}, /* TAG_UL */
                     61:        {"ol",          HTML_CLRLINE}, /* TAG_OL */
1.41      kristaps   62:        {"base",        HTML_CLRLINE | HTML_NOSTACK}, /* TAG_BASE */
1.29      kristaps   63: };
1.10      kristaps   64:
1.29      kristaps   65: static const char       *const htmlattrs[ATTR_MAX] = {
                     66:        "http-equiv",
                     67:        "content",
                     68:        "name",
                     69:        "rel",
                     70:        "href",
                     71:        "type",
                     72:        "media",
1.33      kristaps   73:        "class",
                     74:        "style",
                     75:        "width",
                     76:        "valign",
1.54      kristaps   77:        "target",
1.57    ! kristaps   78:        "id",
1.29      kristaps   79: };
1.10      kristaps   80:
1.33      kristaps   81: #ifdef __linux__
1.43      kristaps   82: extern int               getsubopt(char **, char * const *, char **);
1.33      kristaps   83: #endif
1.29      kristaps   84:
                     85: void *
1.43      kristaps   86: html_alloc(char *outopts)
1.10      kristaps   87: {
1.30      kristaps   88:        struct html     *h;
1.53      kristaps   89:        char            *toks[4], *v;
1.43      kristaps   90:
                     91:        toks[0] = "style";
1.53      kristaps   92:        toks[1] = "man";
1.54      kristaps   93:        toks[2] = "includes";
                     94:        toks[3] = NULL;
1.30      kristaps   95:
                     96:        if (NULL == (h = calloc(1, sizeof(struct html))))
                     97:                return(NULL);
1.10      kristaps   98:
1.37      kristaps   99:        SLIST_INIT(&h->tags);
                    100:        SLIST_INIT(&h->ords);
                    101:
1.32      kristaps  102:        if (NULL == (h->symtab = chars_init(CHARS_HTML))) {
                    103:                free(h);
                    104:                return(NULL);
                    105:        }
1.41      kristaps  106:
1.47      kristaps  107:        while (outopts && *outopts)
1.43      kristaps  108:                switch (getsubopt(&outopts, toks, &v)) {
                    109:                case (0):
                    110:                        h->style = v;
                    111:                        break;
                    112:                case (1):
1.53      kristaps  113:                        h->base_man = v;
1.43      kristaps  114:                        break;
1.54      kristaps  115:                case (2):
                    116:                        h->base_includes = v;
                    117:                        break;
1.43      kristaps  118:                default:
                    119:                        break;
                    120:                }
                    121:
1.30      kristaps  122:        return(h);
1.29      kristaps  123: }
1.10      kristaps  124:
1.33      kristaps  125:
1.29      kristaps  126: void
                    127: html_free(void *p)
                    128: {
1.30      kristaps  129:        struct tag      *tag;
1.37      kristaps  130:        struct ord      *ord;
1.30      kristaps  131:        struct html     *h;
                    132:
                    133:        h = (struct html *)p;
1.10      kristaps  134:
1.37      kristaps  135:        while ( ! SLIST_EMPTY(&h->ords)) {
                    136:                ord = SLIST_FIRST(&h->ords);
                    137:                SLIST_REMOVE_HEAD(&h->ords, entry);
                    138:                free(ord);
                    139:        }
                    140:
                    141:        while ( ! SLIST_EMPTY(&h->tags)) {
                    142:                tag = SLIST_FIRST(&h->tags);
                    143:                SLIST_REMOVE_HEAD(&h->tags, entry);
1.30      kristaps  144:                free(tag);
                    145:        }
1.36      kristaps  146:
                    147:        if (h->symtab)
                    148:                chars_free(h->symtab);
1.53      kristaps  149:
1.30      kristaps  150:        free(h);
1.10      kristaps  151: }
1.2       kristaps  152:
1.33      kristaps  153:
1.51      kristaps  154: void
1.29      kristaps  155: print_gen_head(struct html *h)
                    156: {
1.41      kristaps  157:        struct htmlpair  tag[4];
                    158:
                    159:        tag[0].key = ATTR_HTTPEQUIV;
                    160:        tag[0].val = "Content-Type";
                    161:        tag[1].key = ATTR_CONTENT;
                    162:        tag[1].val = "text/html; charset=utf-8";
                    163:        print_otag(h, TAG_META, 2, tag);
                    164:
                    165:        tag[0].key = ATTR_NAME;
                    166:        tag[0].val = "resource-type";
                    167:        tag[1].key = ATTR_CONTENT;
                    168:        tag[1].val = "document";
                    169:        print_otag(h, TAG_META, 2, tag);
                    170:
                    171:        if (h->style) {
                    172:                tag[0].key = ATTR_REL;
                    173:                tag[0].val = "stylesheet";
                    174:                tag[1].key = ATTR_HREF;
                    175:                tag[1].val = h->style;
                    176:                tag[2].key = ATTR_TYPE;
                    177:                tag[2].val = "text/css";
                    178:                tag[3].key = ATTR_MEDIA;
                    179:                tag[3].val = "all";
                    180:                print_otag(h, TAG_LINK, 4, tag);
                    181:        }
1.4       kristaps  182: }
                    183:
1.33      kristaps  184:
1.29      kristaps  185: static void
1.32      kristaps  186: print_spec(struct html *h, const char *p, int len)
                    187: {
                    188:        const char      *rhs;
                    189:        int              i;
                    190:        size_t           sz;
                    191:
                    192:        rhs = chars_a2ascii(h->symtab, p, (size_t)len, &sz);
                    193:
                    194:        if (NULL == rhs)
                    195:                return;
                    196:        for (i = 0; i < (int)sz; i++)
                    197:                putchar(rhs[i]);
                    198: }
                    199:
1.33      kristaps  200:
1.32      kristaps  201: static void
                    202: print_res(struct html *h, const char *p, int len)
                    203: {
                    204:        const char      *rhs;
                    205:        int              i;
                    206:        size_t           sz;
                    207:
                    208:        rhs = chars_a2res(h->symtab, p, (size_t)len, &sz);
                    209:
                    210:        if (NULL == rhs)
                    211:                return;
                    212:        for (i = 0; i < (int)sz; i++)
                    213:                putchar(rhs[i]);
                    214: }
                    215:
1.33      kristaps  216:
1.32      kristaps  217: static void
                    218: print_escape(struct html *h, const char **p)
                    219: {
                    220:        int              j, type;
                    221:        const char      *wp;
                    222:
                    223:        wp = *p;
                    224:        type = 1;
                    225:
                    226:        if (0 == *(++wp)) {
                    227:                *p = wp;
                    228:                return;
                    229:        }
                    230:
                    231:        if ('(' == *wp) {
                    232:                wp++;
                    233:                if (0 == *wp || 0 == *(wp + 1)) {
                    234:                        *p = 0 == *wp ? wp : wp + 1;
                    235:                        return;
                    236:                }
                    237:
                    238:                print_spec(h, wp, 2);
                    239:                *p = ++wp;
                    240:                return;
                    241:
                    242:        } else if ('*' == *wp) {
                    243:                if (0 == *(++wp)) {
                    244:                        *p = wp;
                    245:                        return;
                    246:                }
                    247:
                    248:                switch (*wp) {
                    249:                case ('('):
                    250:                        wp++;
                    251:                        if (0 == *wp || 0 == *(wp + 1)) {
                    252:                                *p = 0 == *wp ? wp : wp + 1;
                    253:                                return;
                    254:                        }
                    255:
                    256:                        print_res(h, wp, 2);
                    257:                        *p = ++wp;
                    258:                        return;
                    259:                case ('['):
                    260:                        type = 0;
                    261:                        break;
                    262:                default:
                    263:                        print_res(h, wp, 1);
                    264:                        *p = wp;
                    265:                        return;
                    266:                }
                    267:
                    268:        } else if ('f' == *wp) {
                    269:                if (0 == *(++wp)) {
                    270:                        *p = wp;
                    271:                        return;
                    272:                }
                    273:
                    274:                switch (*wp) {
                    275:                case ('B'):
                    276:                        /* TODO */
                    277:                        break;
                    278:                case ('I'):
                    279:                        /* TODO */
                    280:                        break;
                    281:                case ('P'):
                    282:                        /* FALLTHROUGH */
                    283:                case ('R'):
                    284:                        /* TODO */
                    285:                        break;
                    286:                default:
                    287:                        break;
                    288:                }
                    289:
                    290:                *p = wp;
                    291:                return;
                    292:
                    293:        } else if ('[' != *wp) {
                    294:                print_spec(h, wp, 1);
                    295:                *p = wp;
                    296:                return;
                    297:        }
                    298:
                    299:        wp++;
                    300:        for (j = 0; *wp && ']' != *wp; wp++, j++)
                    301:                /* Loop... */ ;
                    302:
                    303:        if (0 == *wp) {
                    304:                *p = wp;
                    305:                return;
                    306:        }
                    307:
                    308:        if (type)
                    309:                print_spec(h, wp - j, j);
                    310:        else
                    311:                print_res(h, wp - j, j);
                    312:
                    313:        *p = wp;
                    314: }
                    315:
1.9       kristaps  316:
1.29      kristaps  317: static void
1.32      kristaps  318: print_encode(struct html *h, const char *p)
1.29      kristaps  319: {
1.14      kristaps  320:
1.32      kristaps  321:        for (; *p; p++) {
1.34      kristaps  322:                if ('\\' == *p) {
                    323:                        print_escape(h, &p);
                    324:                        continue;
                    325:                }
                    326:                switch (*p) {
                    327:                case ('<'):
                    328:                        printf("&lt;");
                    329:                        break;
                    330:                case ('>'):
                    331:                        printf("&gt;");
                    332:                        break;
                    333:                case ('&'):
                    334:                        printf("&amp;");
                    335:                        break;
                    336:                default:
1.32      kristaps  337:                        putchar(*p);
1.34      kristaps  338:                        break;
1.32      kristaps  339:                }
                    340:        }
1.14      kristaps  341: }
                    342:
                    343:
1.51      kristaps  344: struct tag *
1.29      kristaps  345: print_otag(struct html *h, enum htmltag tag,
                    346:                int sz, const struct htmlpair *p)
1.14      kristaps  347: {
1.29      kristaps  348:        int              i;
1.30      kristaps  349:        struct tag      *t;
                    350:
                    351:        if ( ! (HTML_NOSTACK & htmltags[tag].flags)) {
                    352:                if (NULL == (t = malloc(sizeof(struct tag))))
                    353:                        err(EXIT_FAILURE, "malloc");
                    354:                t->tag = tag;
1.37      kristaps  355:                SLIST_INSERT_HEAD(&h->tags, t, entry);
1.30      kristaps  356:        } else
                    357:                t = NULL;
1.29      kristaps  358:
                    359:        if ( ! (HTML_NOSPACE & h->flags))
1.30      kristaps  360:                if ( ! (HTML_CLRLINE & htmltags[tag].flags))
1.29      kristaps  361:                        printf(" ");
                    362:
                    363:        printf("<%s", htmltags[tag].name);
                    364:        for (i = 0; i < sz; i++) {
                    365:                printf(" %s=\"", htmlattrs[p[i].key]);
                    366:                assert(p->val);
1.32      kristaps  367:                print_encode(h, p[i].val);
1.29      kristaps  368:                printf("\"");
                    369:        }
                    370:        printf(">");
1.14      kristaps  371:
1.29      kristaps  372:        h->flags |= HTML_NOSPACE;
1.30      kristaps  373:        if (HTML_CLRLINE & htmltags[tag].flags)
                    374:                h->flags |= HTML_NEWLINE;
                    375:        else
                    376:                h->flags &= ~HTML_NEWLINE;
1.14      kristaps  377:
1.30      kristaps  378:        return(t);
1.14      kristaps  379: }
                    380:
                    381:
                    382: /* ARGSUSED */
1.29      kristaps  383: static void
                    384: print_ctag(struct html *h, enum htmltag tag)
1.14      kristaps  385: {
                    386:
1.29      kristaps  387:        printf("</%s>", htmltags[tag].name);
1.30      kristaps  388:        if (HTML_CLRLINE & htmltags[tag].flags)
1.29      kristaps  389:                h->flags |= HTML_NOSPACE;
1.30      kristaps  390:        if (HTML_CLRLINE & htmltags[tag].flags)
                    391:                h->flags |= HTML_NEWLINE;
                    392:        else
                    393:                h->flags &= ~HTML_NEWLINE;
1.14      kristaps  394: }
                    395:
                    396:
1.29      kristaps  397: /* ARGSUSED */
1.51      kristaps  398: void
1.29      kristaps  399: print_gen_doctype(struct html *h)
1.1       kristaps  400: {
1.29      kristaps  401:
1.46      kristaps  402:        printf("<!DOCTYPE HTML PUBLIC \"%s\" \"%s\">", DOCTYPE, DTD);
1.1       kristaps  403: }
                    404:
                    405:
1.51      kristaps  406: void
1.29      kristaps  407: print_text(struct html *h, const char *p)
1.1       kristaps  408: {
                    409:
1.29      kristaps  410:        if (*p && 0 == *(p + 1))
                    411:                switch (*p) {
                    412:                case('.'):
                    413:                        /* FALLTHROUGH */
                    414:                case(','):
                    415:                        /* FALLTHROUGH */
                    416:                case(';'):
                    417:                        /* FALLTHROUGH */
                    418:                case(':'):
                    419:                        /* FALLTHROUGH */
                    420:                case('?'):
                    421:                        /* FALLTHROUGH */
                    422:                case('!'):
                    423:                        /* FALLTHROUGH */
                    424:                case(')'):
                    425:                        /* FALLTHROUGH */
                    426:                case(']'):
                    427:                        /* FALLTHROUGH */
                    428:                case('}'):
1.52      kristaps  429:                        if ( ! (HTML_IGNDELIM & h->flags))
                    430:                                h->flags |= HTML_NOSPACE;
1.30      kristaps  431:                        break;
1.29      kristaps  432:                default:
                    433:                        break;
                    434:                }
1.1       kristaps  435:
1.29      kristaps  436:        if ( ! (h->flags & HTML_NOSPACE))
                    437:                printf(" ");
1.30      kristaps  438:
1.29      kristaps  439:        h->flags &= ~HTML_NOSPACE;
1.30      kristaps  440:        h->flags &= ~HTML_NEWLINE;
1.1       kristaps  441:
1.29      kristaps  442:        if (p)
1.32      kristaps  443:                print_encode(h, p);
1.8       kristaps  444:
1.29      kristaps  445:        if (*p && 0 == *(p + 1))
                    446:                switch (*p) {
                    447:                case('('):
                    448:                        /* FALLTHROUGH */
                    449:                case('['):
                    450:                        /* FALLTHROUGH */
                    451:                case('{'):
                    452:                        h->flags |= HTML_NOSPACE;
1.30      kristaps  453:                        break;
1.29      kristaps  454:                default:
                    455:                        break;
                    456:                }
1.1       kristaps  457: }
1.30      kristaps  458:
                    459:
1.51      kristaps  460: void
1.30      kristaps  461: print_tagq(struct html *h, const struct tag *until)
                    462: {
                    463:        struct tag      *tag;
                    464:
1.37      kristaps  465:        while ( ! SLIST_EMPTY(&h->tags)) {
                    466:                tag = SLIST_FIRST(&h->tags);
1.30      kristaps  467:                print_ctag(h, tag->tag);
1.37      kristaps  468:                SLIST_REMOVE_HEAD(&h->tags, entry);
1.30      kristaps  469:                free(tag);
                    470:                if (until && tag == until)
                    471:                        return;
                    472:        }
                    473: }
                    474:
                    475:
1.51      kristaps  476: void
1.30      kristaps  477: print_stagq(struct html *h, const struct tag *suntil)
                    478: {
                    479:        struct tag      *tag;
                    480:
1.37      kristaps  481:        while ( ! SLIST_EMPTY(&h->tags)) {
                    482:                tag = SLIST_FIRST(&h->tags);
1.30      kristaps  483:                if (suntil && tag == suntil)
                    484:                        return;
                    485:                print_ctag(h, tag->tag);
1.37      kristaps  486:                SLIST_REMOVE_HEAD(&h->tags, entry);
1.30      kristaps  487:                free(tag);
                    488:        }
                    489: }
1.55      kristaps  490:
                    491:
                    492: void
                    493: bufinit(struct html *h)
                    494: {
                    495:
                    496:        h->buf[0] = '\0';
                    497:        h->buflen = 0;
                    498: }
                    499:
                    500:
                    501: void
                    502: bufcat(struct html *h, const char *p)
                    503: {
                    504:
                    505:        bufncat(h, p, strlen(p));
                    506: }
                    507:
                    508:
                    509: void
                    510: buffmt(struct html *h, const char *fmt, ...)
                    511: {
                    512:        va_list          ap;
                    513:
                    514:        va_start(ap, fmt);
1.56      kristaps  515:        (void)vsnprintf(h->buf + (int)h->buflen,
1.55      kristaps  516:                        BUFSIZ - h->buflen - 1, fmt, ap);
                    517:        va_end(ap);
                    518:        h->buflen = strlen(h->buf);
                    519: }
                    520:
                    521:
                    522: void
                    523: bufncat(struct html *h, const char *p, size_t sz)
                    524: {
                    525:
                    526:        if (h->buflen + sz > BUFSIZ - 1)
                    527:                sz = BUFSIZ - 1 - h->buflen;
                    528:
                    529:        (void)strncat(h->buf, p, sz);
                    530:        h->buflen += sz;
                    531: }
                    532:
                    533:
                    534: void
                    535: buffmt_includes(struct html *h, const char *name)
                    536: {
                    537:        const char      *p, *pp;
                    538:
                    539:        pp = h->base_includes;
                    540:        while ((p = strchr(pp, '%'))) {
1.56      kristaps  541:                bufncat(h, pp, (size_t)(p - pp));
1.55      kristaps  542:                switch (*(p + 1)) {
                    543:                case('I'):
                    544:                        bufcat(h, name);
                    545:                        break;
                    546:                default:
                    547:                        bufncat(h, p, 2);
                    548:                        break;
                    549:                }
                    550:                pp = p + 2;
                    551:        }
                    552:        if (pp)
                    553:                bufcat(h, pp);
                    554: }
                    555:
                    556:
                    557: void
                    558: buffmt_man(struct html *h,
                    559:                const char *name, const char *sec)
                    560: {
                    561:        const char      *p, *pp;
                    562:
                    563:        pp = h->base_man;
                    564:        while ((p = strchr(pp, '%'))) {
1.56      kristaps  565:                bufncat(h, pp, (size_t)(p - pp));
1.55      kristaps  566:                switch (*(p + 1)) {
                    567:                case('S'):
                    568:                        bufcat(h, sec);
                    569:                        break;
                    570:                case('N'):
                    571:                        buffmt(h, name ? name : "1");
                    572:                        break;
                    573:                default:
                    574:                        bufncat(h, p, 2);
                    575:                        break;
                    576:                }
                    577:                pp = p + 2;
                    578:        }
                    579:        if (pp)
                    580:                bufcat(h, pp);
                    581: }

CVSweb