Annotation of mandoc/mdocml.c, Revision 1.1.1.1
1.1 kristaps 1: /* $Id$ */
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:
45: static void usage(void);
46:
47: static int md_begin(const char *, const char *);
48: static int md_begin_io(const char *, const char *);
49: static int md_begin_bufs(struct md_file *, struct md_file *);
50: static int md_run(struct md_buf *, struct md_buf *);
51: static int md_line(struct md_buf *, const struct md_buf *,
52: const char *, size_t);
53:
54: static ssize_t md_buf_fill(struct md_buf *);
55:
56:
57: int
58: main(int argc, char *argv[])
59: {
60: int c;
61: char *out, *in;
62:
63: extern char *optarg;
64: extern int optind;
65:
66: out = NULL;
67:
68: while (-1 != (c = getopt(argc, argv, "o:")))
69: switch (c) {
70: case ('o'):
71: out = optarg;
72: break;
73: default:
74: usage();
75: return(1);
76: }
77:
78: argv += optind;
79: if (1 != (argc -= optind)) {
80: usage();
81: return(1);
82: }
83:
84: argc--;
85: in = *argv++;
86:
87: return(md_begin(out, in));
88: }
89:
90:
91: static int
92: md_begin(const char *out, const char *in)
93: {
94: char buf[MAXPATHLEN];
95:
96: assert(in);
97: if (out)
98: return(md_begin_io(out, in));
99:
100: if (strlcpy(buf, in, MAXPATHLEN) >= MAXPATHLEN)
101: warnx("output filename too long");
102: else if (strlcat(buf, ".html", MAXPATHLEN) >= MAXPATHLEN)
103: warnx("output filename too long");
104: else
105: return(md_begin_io(buf, in));
106:
107: return(1);
108: }
109:
110:
111: static int
112: md_begin_io(const char *out, const char *in)
113: {
114: int c;
115: struct md_file fin, fout;
116:
117: assert(out);
118: assert(in);
119:
120: /* XXX: put an output file in TMPDIR and switch it out when the
121: * true file is ready to be written.
122: */
123:
124: fin.name = in;
125:
126: if (-1 == (fin.fd = open(fin.name, O_RDONLY, 0))) {
127: warn("%s", fin.name);
128: return(1);
129: }
130:
131: fout.name = out;
132:
133: fout.fd = open(fout.name, O_WRONLY | O_CREAT | O_EXCL, 0644);
134: if (-1 == fout.fd) {
135: warn("%s", fout.name);
136: if (-1 == close(fin.fd))
137: warn("%s", fin.name);
138: return(1);
139: }
140:
141: c = md_begin_bufs(&fout, &fin);
142:
143: if (-1 == close(fin.fd)) {
144: warn("%s", in);
145: c = 1;
146: }
147: if (-1 == close(fout.fd)) {
148: warn("%s", out);
149: c = 1;
150: }
151:
152: return(c);
153: }
154:
155:
156: static int
157: md_begin_bufs(struct md_file *out, struct md_file *in)
158: {
159: struct stat stin, stout;
160: struct md_buf inbuf, outbuf;
161: int c;
162:
163: assert(in);
164: assert(out);
165:
166: if (-1 == fstat(in->fd, &stin)) {
167: warn("fstat: %s", in->name);
168: return(1);
169: } else if (-1 == fstat(out->fd, &stout)) {
170: warn("fstat: %s", out->name);
171: return(1);
172: }
173:
174: inbuf.file = in;
175: inbuf.line = 1;
176: inbuf.bufsz = MAX(stin.st_blksize, BUFSIZ);
177:
178: outbuf.file = out;
179: outbuf.line = 1;
180: outbuf.bufsz = MAX(stout.st_blksize, BUFSIZ);
181:
182: if (NULL == (inbuf.buf = malloc(inbuf.bufsz))) {
183: warn("malloc");
184: return(1);
185: } else if (NULL == (outbuf.buf = malloc(outbuf.bufsz))) {
186: warn("malloc");
187: free(inbuf.buf);
188: return(1);
189: }
190:
191: c = md_run(&outbuf, &inbuf);
192:
193: free(inbuf.buf);
194: free(outbuf.buf);
195:
196: return(c);
197: }
198:
199:
200: static ssize_t
201: md_buf_fill(struct md_buf *in)
202: {
203: ssize_t ssz;
204:
205: assert(in);
206: assert(in->file);
207: assert(in->buf);
208: assert(in->bufsz > 0);
209: assert(in->file->name);
210:
211: if (-1 == (ssz = read(in->file->fd, in->buf, in->bufsz)))
212: warn("%s", in->file->name);
213:
214: return(ssz);
215: }
216:
217:
218: static int
219: md_run(struct md_buf *out, struct md_buf *in)
220: {
221: ssize_t sz, i;
222: char line[BUFSIZ];
223: size_t pos;
224:
225: assert(in);
226: assert(out);
227:
228: /* LINTED */
229: for (pos = 0; ; ) {
230: if (-1 == (sz = md_buf_fill(in)))
231: return(1);
232: else if (0 == sz)
233: break;
234:
235: for (i = 0; i < sz; i++) {
236: if ('\n' == in->buf[i]) {
237: if (md_line(out, in, line, pos))
238: return(1);
239: in->line++;
240: pos = 0;
241: continue;
242: }
243:
244: if (pos < BUFSIZ) {
245: /* LINTED */
246: line[pos++] = in->buf[i];
247: continue;
248: }
249:
250: warnx("%s: line %zu too long",
251: in->file->name, in->line);
252: return(1);
253: }
254: }
255:
256: if (0 != pos)
257: return(md_line(out, in, line, pos));
258:
259: return(0);
260: }
261:
262:
263: static int
264: md_line(struct md_buf *out, const struct md_buf *in,
265: const char *buf, size_t sz)
266: {
267: size_t i;
268:
269: assert(buf);
270: assert(out);
271: assert(in);
272:
273: for (i = 0; i < sz; i++)
274: (void)putchar(buf[i]);
275:
276: (void)putchar('\n');
277: return(0);
278: }
279:
280:
281: static void
282: usage(void)
283: {
284: extern char *__progname;
285:
286: (void)printf("usage: %s [-o outfile] infile\n", __progname);
287: }
CVSweb