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

Annotation of mandoc/xml.c, Revision 1.8

1.8     ! kristaps    1: /* $Id: xml.c,v 1.7 2008/12/02 00:15:41 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:  */
                     19: #include <sys/param.h>
                     20:
                     21: #include <assert.h>
                     22: #include <ctype.h>
                     23: #include <err.h>
                     24: #include <stdio.h>
                     25: #include <stdlib.h>
                     26: #include <string.h>
                     27:
                     28: #include "libmdocml.h"
                     29: #include "private.h"
                     30:
1.5       kristaps   31: #define        MAXINDENT        8
1.6       kristaps   32: #define        COLUMNS          72
1.1       kristaps   33:
1.6       kristaps   34: enum   md_ns {
                     35:        MD_NS_BLOCK,
                     36:        MD_NS_INLINE,
                     37:        MD_NS_DEFAULT
                     38: };
                     39:
1.1       kristaps   40: enum   md_tok {
1.8     ! kristaps   41:        MD_BLKIN,               /* Controls spacing. */
1.1       kristaps   42:        MD_BLKOUT,
                     43:        MD_IN,
                     44:        MD_OUT,
1.8     ! kristaps   45:        MD_TEXT
1.1       kristaps   46: };
                     47:
                     48: struct md_xml {
                     49:        const struct md_args    *args;
                     50:        const struct md_rbuf    *rbuf;
                     51:
                     52:        struct md_mbuf  *mbuf;
                     53:        struct rofftree *tree;
                     54:        size_t           indent;
                     55:        size_t           pos;
                     56:        enum md_tok      last;
                     57:        int              flags;
1.8     ! kristaps   58: #define        MD_LITERAL      (1 << 0) /* TODO */
        !            59: #define        MD_OVERRIDE_ONE (1 << 1)
        !            60: #define        MD_OVERRIDE_ALL (1 << 2)
1.1       kristaps   61: };
                     62:
                     63: static void             roffmsg(void *arg, enum roffmsg,
                     64:                                const char *, const char *, char *);
                     65: static int              roffhead(void *);
                     66: static int              rofftail(void *);
                     67: static int              roffin(void *, int, int *, char **);
                     68: static int              roffdata(void *, int, char *);
                     69: static int              roffout(void *, int);
                     70: static int              roffblkin(void *, int, int *, char **);
                     71: static int              roffblkout(void *, int);
1.8     ! kristaps   72: static int              roffspecial(void *, int, int *, char **, char **);
1.1       kristaps   73:
1.8     ! kristaps   74: static void             mbuf_mode(struct md_xml *, enum md_ns);
1.1       kristaps   75: static int              mbuf_newline(struct md_xml *);
                     76: static int              mbuf_indent(struct md_xml *);
                     77: static int              mbuf_data(struct md_xml *, int, char *);
                     78: static int              mbuf_putstring(struct md_xml *,
                     79:                                const char *);
                     80: static int              mbuf_nputstring(struct md_xml *,
                     81:                                const char *, size_t);
1.2       kristaps   82: static int              mbuf_puts(struct md_xml *, const char *);
                     83: static int              mbuf_nputs(struct md_xml *,
                     84:                                const char *, size_t);
1.6       kristaps   85: static int              mbuf_begintag(struct md_xml *, const char *,
                     86:                                enum md_ns, int *, char **);
                     87: static int              mbuf_endtag(struct md_xml *,
                     88:                                const char *, enum md_ns);
                     89:
                     90:
1.8     ! kristaps   91: static void
        !            92: mbuf_mode(struct md_xml *p, enum md_ns ns)
        !            93: {
        !            94:        p->flags &= ~MD_OVERRIDE_ONE;
        !            95:        p->last = ns;
        !            96: }
        !            97:
        !            98:
1.6       kristaps   99: static int
                    100: mbuf_begintag(struct md_xml *p, const char *name, enum md_ns ns,
                    101:                int *argc, char **argv)
                    102: {
                    103:        int              i;
                    104:
                    105:        if ( ! mbuf_nputs(p, "<", 1))
                    106:                return(0);
                    107:
                    108:        switch (ns) {
                    109:                case (MD_NS_BLOCK):
                    110:                        if ( ! mbuf_nputs(p, "block:", 6))
                    111:                                return(0);
                    112:                        break;
                    113:                case (MD_NS_INLINE):
                    114:                        if ( ! mbuf_nputs(p, "inline:", 7))
                    115:                                return(0);
                    116:                        break;
                    117:                default:
                    118:                        break;
                    119:        }
                    120:
                    121:        if ( ! mbuf_puts(p, name))
                    122:                return(0);
                    123:
                    124:        for (i = 0; ROFF_ARGMAX != argc[i]; i++) {
                    125:                if ( ! mbuf_nputs(p, " ", 1))
                    126:                        return(0);
                    127:                if ( ! mbuf_puts(p, tokargnames[argc[i]]))
                    128:                        return(0);
                    129:                if ( ! mbuf_nputs(p, "=\"", 2))
                    130:                        return(0);
                    131:                if ( ! mbuf_putstring(p, argv[i] ? argv[i] : "true"))
                    132:                        return(0);
                    133:                if ( ! mbuf_nputs(p, "\"", 1))
                    134:                        return(0);
                    135:        }
                    136:        return(mbuf_nputs(p, ">", 1));
                    137: }
                    138:
                    139:
                    140: static int
                    141: mbuf_endtag(struct md_xml *p, const char *tag, enum md_ns ns)
                    142: {
                    143:        if ( ! mbuf_nputs(p, "</", 2))
                    144:                return(0);
                    145:
                    146:        switch (ns) {
                    147:                case (MD_NS_BLOCK):
                    148:                        if ( ! mbuf_nputs(p, "block:", 6))
                    149:                                return(0);
                    150:                        break;
                    151:                case (MD_NS_INLINE):
                    152:                        if ( ! mbuf_nputs(p, "inline:", 7))
                    153:                                return(0);
                    154:                        break;
                    155:                default:
                    156:                        break;
                    157:        }
                    158:
                    159:        if ( ! mbuf_puts(p, tag))
                    160:                return(0);
                    161:        return(mbuf_nputs(p, ">", 1));
                    162: }
1.1       kristaps  163:
                    164:
                    165: static int
                    166: mbuf_putstring(struct md_xml *p, const char *buf)
                    167: {
                    168:
                    169:        return(mbuf_nputstring(p, buf, strlen(buf)));
                    170: }
                    171:
                    172:
                    173: static int
                    174: mbuf_nputstring(struct md_xml *p, const char *buf, size_t sz)
                    175: {
1.7       kristaps  176:        int              i;
1.2       kristaps  177:
1.7       kristaps  178:        for (i = 0; i < (int)sz; i++) {
1.2       kristaps  179:                switch (buf[i]) {
                    180:                case ('&'):
                    181:                        if ( ! md_buf_puts(p->mbuf, "&amp;", 5))
                    182:                                return(0);
                    183:                        p->pos += 5;
                    184:                        break;
                    185:                case ('"'):
                    186:                        if ( ! md_buf_puts(p->mbuf, "&quot;", 6))
                    187:                                return(0);
                    188:                        p->pos += 6;
                    189:                        break;
1.6       kristaps  190:                case ('<'):
                    191:                        if ( ! md_buf_puts(p->mbuf, "&lt;", 4))
                    192:                                return(0);
                    193:                        p->pos += 4;
                    194:                        break;
                    195:                case ('>'):
                    196:                        if ( ! md_buf_puts(p->mbuf, "&gt;", 4))
                    197:                                return(0);
                    198:                        p->pos += 4;
                    199:                        break;
1.2       kristaps  200:                default:
                    201:                        if ( ! md_buf_putchar(p->mbuf, buf[i]))
                    202:                                return(0);
                    203:                        p->pos++;
                    204:                        break;
                    205:                }
                    206:        }
                    207:        return(1);
                    208: }
                    209:
                    210:
                    211: static int
                    212: mbuf_nputs(struct md_xml *p, const char *buf, size_t sz)
                    213: {
1.1       kristaps  214:
                    215:        p->pos += sz;
                    216:        return(md_buf_puts(p->mbuf, buf, sz));
                    217: }
                    218:
                    219:
                    220: static int
1.2       kristaps  221: mbuf_puts(struct md_xml *p, const char *buf)
                    222: {
                    223:
                    224:        return(mbuf_nputs(p, buf, strlen(buf)));
                    225: }
                    226:
                    227:
                    228: static int
1.1       kristaps  229: mbuf_indent(struct md_xml *p)
                    230: {
                    231:        size_t           i;
                    232:
                    233:        assert(p->pos == 0);
                    234:
                    235:        /* LINTED */
1.5       kristaps  236:        for (i = 0; i < MIN(p->indent, MAXINDENT); i++)
1.1       kristaps  237:                if ( ! md_buf_putstring(p->mbuf, "    "))
                    238:                        return(0);
                    239:
1.5       kristaps  240:        p->pos += i * 4;
1.1       kristaps  241:        return(1);
                    242: }
                    243:
                    244:
                    245: static int
                    246: mbuf_newline(struct md_xml *p)
                    247: {
                    248:
                    249:        if ( ! md_buf_putchar(p->mbuf, '\n'))
                    250:                return(0);
                    251:
                    252:        p->pos = 0;
                    253:        return(1);
                    254: }
                    255:
                    256:
                    257: static int
                    258: mbuf_data(struct md_xml *p, int space, char *buf)
                    259: {
                    260:        size_t           sz;
                    261:        char            *bufp;
                    262:
                    263:        assert(p->mbuf);
                    264:        assert(0 != p->indent);
                    265:
1.8     ! kristaps  266:        if (MD_OVERRIDE_ONE & p->flags || MD_OVERRIDE_ALL & p->flags)
        !           267:                space = 0;
        !           268:
1.1       kristaps  269:        if (MD_LITERAL & p->flags)
                    270:                return(mbuf_putstring(p, buf));
                    271:
                    272:        while (*buf) {
                    273:                while (*buf && isspace(*buf))
                    274:                        buf++;
                    275:
                    276:                if (0 == *buf)
                    277:                        break;
                    278:
                    279:                bufp = buf;
                    280:                while (*buf && ! isspace(*buf))
                    281:                        buf++;
                    282:
                    283:                if (0 != *buf)
                    284:                        *buf++ = 0;
                    285:
                    286:                sz = strlen(bufp);
                    287:
                    288:                if (0 == p->pos) {
                    289:                        if ( ! mbuf_indent(p))
                    290:                                return(0);
                    291:                        if ( ! mbuf_nputstring(p, bufp, sz))
                    292:                                return(0);
1.8     ! kristaps  293:                        if (p->indent * MAXINDENT + sz >= COLUMNS)
1.1       kristaps  294:                                if ( ! mbuf_newline(p))
                    295:                                        return(0);
1.8     ! kristaps  296:                        if ( ! (MD_OVERRIDE_ALL & p->flags))
        !           297:                                space = 1;
1.1       kristaps  298:                        continue;
                    299:                }
                    300:
                    301:                if (space && sz + p->pos >= COLUMNS) {
                    302:                        if ( ! mbuf_newline(p))
                    303:                                return(0);
                    304:                        if ( ! mbuf_indent(p))
                    305:                                return(0);
                    306:                } else if (space) {
1.2       kristaps  307:                        if ( ! mbuf_nputs(p, " ", 1))
1.1       kristaps  308:                                return(0);
                    309:                }
                    310:
                    311:                if ( ! mbuf_nputstring(p, bufp, sz))
                    312:                        return(0);
                    313:
1.8     ! kristaps  314:                if ( ! (MD_OVERRIDE_ALL & p->flags))
        !           315:                        space = 1;
1.1       kristaps  316:        }
                    317:
                    318:        return(1);
                    319: }
                    320:
                    321:
                    322: int
                    323: md_line_xml(void *arg, char *buf)
                    324: {
                    325:        struct md_xml   *p;
                    326:
                    327:        p = (struct md_xml *)arg;
                    328:        return(roff_engine(p->tree, buf));
                    329: }
                    330:
                    331:
                    332: int
                    333: md_exit_xml(void *data, int flush)
                    334: {
                    335:        int              c;
                    336:        struct md_xml   *p;
                    337:
                    338:        p = (struct md_xml *)data;
                    339:        c = roff_free(p->tree, flush);
                    340:        free(p);
                    341:
                    342:        return(c);
                    343: }
                    344:
                    345:
                    346: void *
                    347: md_init_xml(const struct md_args *args,
                    348:                struct md_mbuf *mbuf, const struct md_rbuf *rbuf)
                    349: {
                    350:        struct roffcb    cb;
                    351:        struct md_xml   *p;
                    352:
                    353:        cb.roffhead = roffhead;
                    354:        cb.rofftail = rofftail;
                    355:        cb.roffin = roffin;
                    356:        cb.roffout = roffout;
                    357:        cb.roffblkin = roffblkin;
                    358:        cb.roffblkout = roffblkout;
                    359:        cb.roffspecial = roffspecial;
                    360:        cb.roffmsg = roffmsg;
                    361:        cb.roffdata = roffdata;
                    362:
                    363:        if (NULL == (p = calloc(1, sizeof(struct md_xml))))
                    364:                err(1, "malloc");
                    365:
                    366:        p->args = args;
                    367:        p->mbuf = mbuf;
                    368:        p->rbuf = rbuf;
                    369:
                    370:        assert(mbuf);
                    371:
                    372:        if (NULL == (p->tree = roff_alloc(&cb, p))) {
                    373:                free(p);
                    374:                return(NULL);
                    375:        }
                    376:
                    377:        return(p);
                    378: }
                    379:
                    380:
                    381: /* ARGSUSED */
                    382: static int
                    383: roffhead(void *arg)
                    384: {
                    385:        struct md_xml   *p;
                    386:
                    387:        assert(arg);
                    388:        p = (struct md_xml *)arg;
                    389:
1.2       kristaps  390:        if ( ! mbuf_puts(p, "<?xml version=\"1.0\" "
1.1       kristaps  391:                                "encoding=\"UTF-8\"?>\n"))
                    392:                return(0);
1.2       kristaps  393:        if ( ! mbuf_puts(p, "<mdoc xmlns:block=\"block\" "
                    394:                                "xmlns:special=\"special\" "
                    395:                                "xmlns:inline=\"inline\">"))
1.1       kristaps  396:                return(0);
                    397:
                    398:        p->indent++;
1.8     ! kristaps  399:        mbuf_mode(p, MD_BLKIN);
1.1       kristaps  400:        return(mbuf_newline(p));
                    401: }
                    402:
                    403:
                    404: static int
                    405: rofftail(void *arg)
                    406: {
                    407:        struct md_xml   *p;
                    408:
                    409:        assert(arg);
                    410:        p = (struct md_xml *)arg;
                    411:
                    412:        if (0 != p->pos && ! mbuf_newline(p))
                    413:                return(0);
                    414:
1.8     ! kristaps  415:        mbuf_mode(p, MD_BLKOUT);
1.6       kristaps  416:        if ( ! mbuf_endtag(p, "mdoc", MD_NS_DEFAULT))
1.1       kristaps  417:                return(0);
                    418:        return(mbuf_newline(p));
                    419: }
                    420:
                    421:
1.8     ! kristaps  422: /* ARGSUSED */
1.1       kristaps  423: static int
1.8     ! kristaps  424: roffspecial(void *arg, int tok, int *argc, char **argv, char **more)
1.1       kristaps  425: {
1.3       kristaps  426:        struct md_xml   *p;
                    427:
                    428:        assert(arg);
                    429:        p = (struct md_xml *)arg;
                    430:
1.6       kristaps  431:        /* FIXME: this is completely ad hoc. */
                    432:
1.3       kristaps  433:        switch (tok) {
                    434:        case (ROFF_Ns):
1.8     ! kristaps  435:                p->flags |= MD_OVERRIDE_ONE;
        !           436:                break;
        !           437:        case (ROFF_Sm):
        !           438:                assert(*more);
        !           439:                if (0 == strcmp(*more, "on"))
        !           440:                        p->flags |= MD_OVERRIDE_ALL;
        !           441:                else
        !           442:                        p->flags &= ~MD_OVERRIDE_ALL;
1.3       kristaps  443:                break;
                    444:        default:
                    445:                break;
                    446:        }
1.1       kristaps  447:
                    448:        return(1);
                    449: }
                    450:
                    451:
                    452: static int
                    453: roffblkin(void *arg, int tok, int *argc, char **argv)
                    454: {
                    455:        struct md_xml   *p;
                    456:
                    457:        assert(arg);
                    458:        p = (struct md_xml *)arg;
                    459:
                    460:        if (0 != p->pos) {
                    461:                if ( ! mbuf_newline(p))
                    462:                        return(0);
                    463:                if ( ! mbuf_indent(p))
                    464:                        return(0);
                    465:        } else if ( ! mbuf_indent(p))
                    466:                return(0);
                    467:
1.2       kristaps  468:        /* FIXME: xml won't like standards args (e.g., p1003.1-90). */
                    469:
1.6       kristaps  470:        p->indent++;
1.8     ! kristaps  471:        mbuf_mode(p, MD_BLKIN);
1.1       kristaps  472:
1.6       kristaps  473:        if ( ! mbuf_begintag(p, toknames[tok], MD_NS_BLOCK,
                    474:                                argc, argv))
1.1       kristaps  475:                return(0);
                    476:        return(mbuf_newline(p));
                    477: }
                    478:
                    479:
                    480: static int
                    481: roffblkout(void *arg, int tok)
                    482: {
                    483:        struct md_xml   *p;
                    484:
                    485:        assert(arg);
                    486:        p = (struct md_xml *)arg;
                    487:
                    488:        p->indent--;
                    489:
                    490:        if (0 != p->pos) {
                    491:                if ( ! mbuf_newline(p))
                    492:                        return(0);
                    493:                if ( ! mbuf_indent(p))
                    494:                        return(0);
                    495:        } else if ( ! mbuf_indent(p))
                    496:                return(0);
                    497:
1.8     ! kristaps  498:        mbuf_mode(p, MD_BLKOUT);
1.6       kristaps  499:        if ( ! mbuf_endtag(p, toknames[tok], MD_NS_BLOCK))
1.1       kristaps  500:                return(0);
                    501:        return(mbuf_newline(p));
                    502: }
                    503:
                    504:
                    505: static int
                    506: roffin(void *arg, int tok, int *argc, char **argv)
                    507: {
                    508:        struct md_xml   *p;
                    509:
                    510:        assert(arg);
                    511:        p = (struct md_xml *)arg;
                    512:
1.8     ! kristaps  513:        if ( ! (MD_OVERRIDE_ONE & p->flags) &&
        !           514:                        ! (MD_OVERRIDE_ALL & p->flags) &&
        !           515:                        p->pos + 11 > COLUMNS)
        !           516:                if ( ! mbuf_newline(p))
        !           517:                        return(0);
1.1       kristaps  518:
1.8     ! kristaps  519:        if (0 != p->pos && (MD_TEXT == p->last || MD_OUT == p->last)
        !           520:                        && ! (MD_OVERRIDE_ONE & p->flags)
        !           521:                        && ! (MD_OVERRIDE_ALL & p->flags))
        !           522:                if ( ! mbuf_nputs(p, " ", 1))
1.1       kristaps  523:                        return(0);
                    524:
1.8     ! kristaps  525:        if (0 == p->pos && ! mbuf_indent(p))
1.1       kristaps  526:                return(0);
                    527:
1.8     ! kristaps  528:        mbuf_mode(p, MD_IN);
1.6       kristaps  529:        return(mbuf_begintag(p, toknames[tok],
                    530:                                MD_NS_INLINE, argc, argv));
1.1       kristaps  531: }
                    532:
                    533:
                    534: static int
                    535: roffout(void *arg, int tok)
                    536: {
                    537:        struct md_xml   *p;
                    538:
                    539:        assert(arg);
                    540:        p = (struct md_xml *)arg;
                    541:
                    542:        if (0 == p->pos && ! mbuf_indent(p))
                    543:                return(0);
                    544:
1.8     ! kristaps  545:        mbuf_mode(p, MD_OUT);
1.6       kristaps  546:        return(mbuf_endtag(p, toknames[tok], MD_NS_INLINE));
1.1       kristaps  547: }
                    548:
                    549:
                    550: static void
                    551: roffmsg(void *arg, enum roffmsg lvl,
                    552:                const char *buf, const char *pos, char *msg)
                    553: {
                    554:        char            *level;
                    555:        struct md_xml   *p;
                    556:
                    557:        assert(arg);
                    558:        p = (struct md_xml *)arg;
                    559:
                    560:        switch (lvl) {
                    561:        case (ROFF_WARN):
                    562:                if ( ! (MD_WARN_ALL & p->args->warnings))
                    563:                        return;
                    564:                level = "warning";
                    565:                break;
                    566:        case (ROFF_ERROR):
                    567:                level = "error";
                    568:                break;
                    569:        default:
                    570:                abort();
                    571:        }
                    572:
                    573:        if (pos)
                    574:                (void)fprintf(stderr, "%s:%zu: %s: %s (column %zu)\n",
                    575:                                p->rbuf->name, p->rbuf->line, level,
                    576:                                msg, pos - buf);
                    577:        else
                    578:                (void)fprintf(stderr, "%s: %s: %s\n",
                    579:                                p->rbuf->name, level, msg);
                    580:
                    581: }
                    582:
                    583:
                    584: static int
                    585: roffdata(void *arg, int space, char *buf)
                    586: {
                    587:        struct md_xml   *p;
                    588:
                    589:        assert(arg);
                    590:        p = (struct md_xml *)arg;
                    591:        if ( ! mbuf_data(p, space, buf))
                    592:                return(0);
                    593:
1.8     ! kristaps  594:        mbuf_mode(p, MD_TEXT);
1.1       kristaps  595:        return(1);
                    596: }
1.4       kristaps  597:

CVSweb