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