]> git.cameronkatri.com Git - mandoc.git/blob - mdocml.c
Abstract ml/mlg/html/xml.
[mandoc.git] / mdocml.c
1 /* $Id: mdocml.c,v 1.15 2008/12/02 00:10:37 kristaps Exp $ */
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 #define BUFFER_IN_DEF BUFSIZ /* See begin_bufs. */
34 #define BUFFER_OUT_DEF BUFSIZ /* See begin_bufs. */
35
36 static void usage(void);
37
38 static int begin_io(const struct md_args *,
39 char *, char *);
40 static int leave_io(const struct md_buf *,
41 const struct md_buf *, int);
42 static int begin_bufs(const struct md_args *,
43 struct md_buf *, struct md_buf *);
44 static int leave_bufs(const struct md_buf *,
45 const struct md_buf *, int);
46
47 int
48 main(int argc, char *argv[])
49 {
50 int c;
51 char *out, *in;
52 struct md_args args;
53
54 extern char *optarg;
55 extern int optind;
56
57 out = in = NULL;
58
59 (void)memset(&args, 0, sizeof(struct md_args));
60
61 while (-1 != (c = getopt(argc, argv, "o:vW")))
62 switch (c) {
63 case ('o'):
64 out = optarg;
65 break;
66 case ('v'):
67 args.verbosity++;
68 break;
69 case ('W'):
70 args.warnings |= MD_WARN_ALL;
71 break;
72 default:
73 usage();
74 return(1);
75 }
76
77 argv += optind;
78 argc -= optind;
79
80 if (1 == argc)
81 in = *argv++;
82
83 return(begin_io(&args, out ? out : "-", in ? in : "-"));
84 }
85
86
87 /*
88 * Close out file descriptors opened in begin_io. If the descriptor
89 * refers to stdin/stdout, then do nothing.
90 */
91 static int
92 leave_io(const struct md_buf *out,
93 const struct md_buf *in, int c)
94 {
95 assert(out);
96 assert(in);
97
98 if (-1 != in->fd && -1 == close(in->fd)) {
99 assert(in->name);
100 warn("%s", in->name);
101 c = 1;
102 }
103 if (-1 != out->fd && STDOUT_FILENO != out->fd &&
104 -1 == close(out->fd)) {
105 assert(out->name);
106 warn("%s", out->name);
107 c = 1;
108 }
109 if (1 == c && STDOUT_FILENO != out->fd)
110 if (-1 == unlink(out->name))
111 warn("%s", out->name);
112
113 return(c);
114 }
115
116
117 /*
118 * Open file descriptors or assign stdin/stdout, if dictated by the "-"
119 * token instead of a filename.
120 */
121 static int
122 begin_io(const struct md_args *args, char *out, char *in)
123 {
124 struct md_buf fi;
125 struct md_buf fo;
126
127 #define FI_FL O_RDONLY
128 #define FO_FL O_WRONLY|O_CREAT|O_TRUNC
129
130 assert(args);
131 assert(out);
132 assert(in);
133
134 bzero(&fi, sizeof(struct md_buf));
135 bzero(&fo, sizeof(struct md_buf));
136
137 fi.fd = STDIN_FILENO;
138 fo.fd = STDOUT_FILENO;
139
140 fi.name = in;
141 fo.name = out;
142
143 if (0 != strncmp(fi.name, "-", 1))
144 if (-1 == (fi.fd = open(fi.name, FI_FL, 0))) {
145 warn("%s", fi.name);
146 return(leave_io(&fo, &fi, 1));
147 }
148
149 if (0 != strncmp(fo.name, "-", 1))
150 if (-1 == (fo.fd = open(fo.name, FO_FL, 0644))) {
151 warn("%s", fo.name);
152 return(leave_io(&fo, &fi, 1));
153 }
154
155 return(leave_io(&fo, &fi, begin_bufs(args, &fo, &fi)));
156 }
157
158
159 /*
160 * Free buffers allocated in begin_bufs.
161 */
162 static int
163 leave_bufs(const struct md_buf *out,
164 const struct md_buf *in, int c)
165 {
166 assert(out);
167 assert(in);
168 if (out->buf)
169 free(out->buf);
170 if (in->buf)
171 free(in->buf);
172 return(c);
173 }
174
175
176 /*
177 * Allocate buffers to the maximum of either the input file's blocksize
178 * or BUFFER_IN_DEF/BUFFER_OUT_DEF, which should be around BUFSIZE.
179 */
180 static int
181 begin_bufs(const struct md_args *args,
182 struct md_buf *out, struct md_buf *in)
183 {
184 struct stat stin, stout;
185 int c;
186
187 assert(args);
188 assert(in);
189 assert(out);
190
191 if (-1 == fstat(in->fd, &stin)) {
192 warn("%s", in->name);
193 return(1);
194 } else if (STDIN_FILENO != in->fd && 0 == stin.st_size) {
195 warnx("%s: empty file", in->name);
196 return(1);
197 } else if (-1 == fstat(out->fd, &stout)) {
198 warn("%s", out->name);
199 return(1);
200 }
201
202 in->bufsz = MAX(stin.st_blksize, BUFFER_IN_DEF);
203 out->bufsz = MAX(stout.st_blksize, BUFFER_OUT_DEF);
204
205 if (NULL == (in->buf = malloc(in->bufsz))) {
206 warn("malloc");
207 return(leave_bufs(out, in, 1));
208 } else if (NULL == (out->buf = malloc(out->bufsz))) {
209 warn("malloc");
210 return(leave_bufs(out, in, 1));
211 }
212
213 c = md_run(args, out, in);
214 return(leave_bufs(out, in, -1 == c ? 1 : 0));
215 }
216
217
218 static void
219 usage(void)
220 {
221 extern char *__progname;
222
223 (void)printf("usage: %s [-vW] [-o outfile] [infile]\n", __progname);
224 }