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

Annotation of mandoc/xml.c, Revision 1.3

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

CVSweb