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

Annotation of mandoc/xml.c, Revision 1.2

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

CVSweb