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