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

Annotation of mandoc/mdocml.c, Revision 1.2

1.2     ! kristaps    1: /* $Id: mdocml.c,v 1.1.1.1 2008/11/22 14:53:29 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: #include <sys/stat.h>
                     21:
                     22: #include <assert.h>
                     23: #include <err.h>
                     24: #include <fcntl.h>
                     25: #include <getopt.h>
                     26: #include <stdio.h>
                     27: #include <stdlib.h>
                     28: #include <string.h>
                     29: #include <unistd.h>
                     30:
                     31: #include "libmdocml.h"
                     32:
                     33: struct md_file {
                     34:        int              fd;
                     35:        const char      *name;
                     36: };
                     37:
                     38: struct md_buf {
                     39:        struct md_file  *file;
                     40:        char            *buf;
                     41:        size_t           bufsz;
                     42:        size_t           line;
                     43: };
                     44:
1.2     ! kristaps   45: struct md_mbuf {
        !            46:        struct md_buf   *buf;
        !            47:        size_t           pos;
        !            48: };
        !            49:
1.1       kristaps   50: static void             usage(void);
                     51:
                     52: static int              md_begin(const char *, const char *);
                     53: static int              md_begin_io(const char *, const char *);
                     54: static int              md_begin_bufs(struct md_file *, struct md_file *);
                     55: static int              md_run(struct md_buf *, struct md_buf *);
1.2     ! kristaps   56: static int              md_line(struct md_mbuf *, const struct md_buf *,
1.1       kristaps   57:                                const char *, size_t);
                     58:
                     59: static ssize_t          md_buf_fill(struct md_buf *);
1.2     ! kristaps   60: static int              md_buf_flush(struct md_mbuf *);
        !            61:
        !            62: static int              md_buf_putchar(struct md_mbuf *, char);
        !            63: static int              md_buf_puts(struct md_mbuf *,
        !            64:                                const char *, size_t);
1.1       kristaps   65:
                     66:
                     67: int
                     68: main(int argc, char *argv[])
                     69: {
                     70:        int              c;
                     71:        char            *out, *in;
                     72:
                     73:        extern char     *optarg;
                     74:        extern int       optind;
                     75:
                     76:        out = NULL;
                     77:
                     78:        while (-1 != (c = getopt(argc, argv, "o:")))
                     79:                switch (c) {
                     80:                case ('o'):
                     81:                        out = optarg;
                     82:                        break;
                     83:                default:
                     84:                        usage();
                     85:                        return(1);
                     86:                }
                     87:
                     88:        argv += optind;
                     89:        if (1 != (argc -= optind)) {
                     90:                usage();
                     91:                return(1);
                     92:        }
                     93:
                     94:        argc--;
                     95:        in = *argv++;
                     96:
                     97:        return(md_begin(out, in));
                     98: }
                     99:
                    100:
                    101: static int
                    102: md_begin(const char *out, const char *in)
                    103: {
                    104:        char             buf[MAXPATHLEN];
                    105:
                    106:        assert(in);
                    107:        if (out)
                    108:                return(md_begin_io(out, in));
                    109:
                    110:        if (strlcpy(buf, in, MAXPATHLEN) >= MAXPATHLEN)
                    111:                warnx("output filename too long");
                    112:        else if (strlcat(buf, ".html", MAXPATHLEN) >= MAXPATHLEN)
                    113:                warnx("output filename too long");
                    114:        else
                    115:                return(md_begin_io(buf, in));
                    116:
                    117:        return(1);
                    118: }
                    119:
                    120:
                    121: static int
                    122: md_begin_io(const char *out, const char *in)
                    123: {
                    124:        int              c;
                    125:        struct md_file   fin, fout;
                    126:
                    127:        assert(out);
                    128:        assert(in);
                    129:
1.2     ! kristaps  130:        /* TODO: accept "-" as both input and output. */
1.1       kristaps  131:
                    132:        fin.name = in;
                    133:
                    134:        if (-1 == (fin.fd = open(fin.name, O_RDONLY, 0))) {
                    135:                warn("%s", fin.name);
                    136:                return(1);
                    137:        }
                    138:
                    139:        fout.name = out;
                    140:
1.2     ! kristaps  141:        fout.fd = open(fout.name, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1.1       kristaps  142:        if (-1 == fout.fd) {
                    143:                warn("%s", fout.name);
                    144:                if (-1 == close(fin.fd))
                    145:                        warn("%s", fin.name);
                    146:                return(1);
                    147:        }
                    148:
                    149:        c = md_begin_bufs(&fout, &fin);
                    150:
                    151:        if (-1 == close(fin.fd)) {
                    152:                warn("%s", in);
                    153:                c = 1;
                    154:        }
                    155:        if (-1 == close(fout.fd)) {
                    156:                warn("%s", out);
                    157:                c = 1;
                    158:        }
                    159:
                    160:        return(c);
                    161: }
                    162:
                    163:
                    164: static int
                    165: md_begin_bufs(struct md_file *out, struct md_file *in)
                    166: {
                    167:        struct stat      stin, stout;
                    168:        struct md_buf    inbuf, outbuf;
                    169:        int              c;
                    170:
                    171:        assert(in);
                    172:        assert(out);
                    173:
                    174:        if (-1 == fstat(in->fd, &stin)) {
                    175:                warn("fstat: %s", in->name);
                    176:                return(1);
                    177:        } else if (-1 == fstat(out->fd, &stout)) {
                    178:                warn("fstat: %s", out->name);
                    179:                return(1);
                    180:        }
                    181:
                    182:        inbuf.file = in;
                    183:        inbuf.line = 1;
1.2     ! kristaps  184:        /*inbuf.bufsz = MAX(stin.st_blksize, BUFSIZ);*/
        !           185:        inbuf.bufsz = 256;
1.1       kristaps  186:
                    187:        outbuf.file = out;
                    188:        outbuf.line = 1;
1.2     ! kristaps  189:        /*outbuf.bufsz = MAX(stout.st_blksize, BUFSIZ);*/
        !           190:        outbuf.bufsz = 256;
1.1       kristaps  191:
                    192:        if (NULL == (inbuf.buf = malloc(inbuf.bufsz))) {
                    193:                warn("malloc");
                    194:                return(1);
                    195:        } else if (NULL == (outbuf.buf = malloc(outbuf.bufsz))) {
                    196:                warn("malloc");
                    197:                free(inbuf.buf);
                    198:                return(1);
                    199:        }
                    200:
                    201:        c = md_run(&outbuf, &inbuf);
                    202:
                    203:        free(inbuf.buf);
                    204:        free(outbuf.buf);
                    205:
                    206:        return(c);
                    207: }
                    208:
                    209:
                    210: static ssize_t
                    211: md_buf_fill(struct md_buf *in)
                    212: {
                    213:        ssize_t          ssz;
                    214:
                    215:        assert(in);
                    216:        assert(in->file);
                    217:        assert(in->buf);
                    218:        assert(in->bufsz > 0);
                    219:        assert(in->file->name);
                    220:
                    221:        if (-1 == (ssz = read(in->file->fd, in->buf, in->bufsz)))
                    222:                warn("%s", in->file->name);
1.2     ! kristaps  223:        else
        !           224:                (void)printf("%s: filled %zd bytes\n",
        !           225:                                in->file->name, ssz);
1.1       kristaps  226:
                    227:        return(ssz);
                    228: }
                    229:
                    230:
                    231: static int
                    232: md_run(struct md_buf *out, struct md_buf *in)
                    233: {
1.2     ! kristaps  234:        struct md_mbuf   mbuf;
1.1       kristaps  235:        ssize_t          sz, i;
                    236:        char             line[BUFSIZ];
                    237:        size_t           pos;
                    238:
                    239:        assert(in);
                    240:        assert(out);
                    241:
1.2     ! kristaps  242:        mbuf.buf = out;
        !           243:        mbuf.pos = 0;
        !           244:
1.1       kristaps  245:        /* LINTED */
                    246:        for (pos = 0; ; ) {
                    247:                if (-1 == (sz = md_buf_fill(in)))
                    248:                        return(1);
                    249:                else if (0 == sz)
                    250:                        break;
                    251:
                    252:                for (i = 0; i < sz; i++) {
                    253:                        if ('\n' == in->buf[i]) {
1.2     ! kristaps  254:                                if (md_line(&mbuf, in, line, pos))
1.1       kristaps  255:                                        return(1);
                    256:                                in->line++;
                    257:                                pos = 0;
                    258:                                continue;
                    259:                        }
                    260:
                    261:                        if (pos < BUFSIZ) {
                    262:                                /* LINTED */
                    263:                                line[pos++] = in->buf[i];
                    264:                                continue;
                    265:                        }
                    266:
                    267:                        warnx("%s: line %zu too long",
                    268:                                        in->file->name, in->line);
                    269:                        return(1);
                    270:                }
                    271:        }
                    272:
1.2     ! kristaps  273:        if (0 != pos && md_line(&mbuf, in, line, pos))
        !           274:                return(1);
        !           275:
        !           276:        return(md_buf_flush(&mbuf) ? 0 : 1);
        !           277: }
        !           278:
        !           279:
        !           280: static int
        !           281: md_buf_flush(struct md_mbuf *buf)
        !           282: {
        !           283:        ssize_t          sz;
        !           284:
        !           285:        assert(buf);
        !           286:        assert(buf->buf);
        !           287:        assert(buf->buf->file);
        !           288:        assert(buf->buf->buf);
        !           289:        assert(buf->buf->file->name);
        !           290:
        !           291:        (void)printf("%s: flushing %zu bytes\n",
        !           292:                        buf->buf->file->name, buf->pos);
        !           293:
        !           294:        if (0 == buf->pos)
        !           295:                return(1);
        !           296:
        !           297:        sz = write(buf->buf->file->fd, buf->buf->buf, buf->pos);
        !           298:
        !           299:        if (-1 == sz) {
        !           300:                warn("%s", buf->buf->file->name);
        !           301:                return(0);
        !           302:        } else if ((size_t)sz != buf->pos) {
        !           303:                warnx("%s: short write", buf->buf->file->name);
        !           304:                return(0);
        !           305:        }
        !           306:
        !           307:        buf->pos = 0;
        !           308:        return(1);
        !           309: }
        !           310:
1.1       kristaps  311:
1.2     ! kristaps  312: static int
        !           313: md_buf_putchar(struct md_mbuf *buf, char c)
        !           314: {
        !           315:        return(md_buf_puts(buf, &c, 1));
        !           316: }
        !           317:
        !           318:
        !           319: static int
        !           320: md_buf_puts(struct md_mbuf *buf, const char *p, size_t sz)
        !           321: {
        !           322:        size_t           ssz;
        !           323:
        !           324:        assert(p);
        !           325:        assert(buf);
        !           326:        assert(buf->buf);
        !           327:
        !           328:        while (buf->pos + sz > buf->buf->bufsz) {
        !           329:                ssz = buf->buf->bufsz - buf->pos;
        !           330:                (void)memcpy(buf->buf->buf + buf->pos, p, ssz);
        !           331:                p += ssz;
        !           332:                sz -= ssz;
        !           333:                buf->pos += ssz;
        !           334:
        !           335:                if ( ! md_buf_flush(buf))
        !           336:                        return(0);
        !           337:        }
        !           338:
        !           339:        (void)memcpy(buf->buf->buf + buf->pos, p, sz);
        !           340:        buf->pos += sz;
        !           341:        return(1);
1.1       kristaps  342: }
                    343:
                    344:
                    345: static int
1.2     ! kristaps  346: md_line(struct md_mbuf *out, const struct md_buf *in,
1.1       kristaps  347:                const char *buf, size_t sz)
                    348: {
                    349:
                    350:        assert(buf);
                    351:        assert(out);
                    352:        assert(in);
                    353:
1.2     ! kristaps  354:        if ( ! md_buf_puts(out, buf, sz))
        !           355:                return(1);
        !           356:        if ( ! md_buf_putchar(out, '\n'))
        !           357:                return(1);
1.1       kristaps  358:
                    359:        return(0);
                    360: }
                    361:
                    362:
                    363: static void
                    364: usage(void)
                    365: {
                    366:        extern char     *__progname;
                    367:
                    368:        (void)printf("usage: %s [-o outfile] infile\n", __progname);
                    369: }

CVSweb