]> git.cameronkatri.com Git - mandoc.git/blob - validate.c
0f03b2334c3efa344697688a21b6a014b8b834cf
[mandoc.git] / validate.c
1 /* $Id: validate.c,v 1.1 2008/11/29 14:14:21 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
21 #include <assert.h>
22 #include <ctype.h>
23 #include <err.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "libmdocml.h"
29 #include "private.h"
30
31 #ifdef __linux__ /* FIXME */
32 #define strlcat strncat
33 #endif
34
35 struct md_valid {
36 const struct md_args *args;
37 const struct md_rbuf *rbuf;
38 struct md_mbuf *mbuf;
39 struct rofftree *tree;
40
41 size_t indent;
42 size_t pos;
43
44 int flags;
45 #define MD_LITERAL (1 << 0)
46 };
47
48 static void roffmsg(void *arg, enum roffmsg,
49 const char *, const char *, char *);
50 static int roffhead(void *);
51 static int rofftail(void *);
52 static int roffin(void *, int, int *, char **);
53 static int roffdata(void *, char *);
54 static int roffout(void *, int);
55 static int roffblkin(void *, int);
56 static int roffblkout(void *, int);
57 static int roffspecial(void *, int);
58
59 static int mbuf_newline(struct md_valid *);
60 static int mbuf_indent(struct md_valid *);
61 static int mbuf_data(struct md_valid *, char *);
62
63
64 static int
65 mbuf_indent(struct md_valid *p)
66 {
67 size_t i;
68
69 assert(0 == p->pos);
70
71 for (i = 0; i < MIN(p->indent, 4); i++)
72 if ( ! md_buf_putstring(p->mbuf, " "))
73 return(0);
74
75 p->pos = i * 4;
76 return(1);
77 }
78
79
80 static int
81 mbuf_atnewline(struct md_valid *p)
82 {
83
84 return(p->pos == MIN(4, p->indent));
85 }
86
87
88 static int
89 mbuf_newline(struct md_valid *p)
90 {
91
92 if (mbuf_atnewline(p))
93 return(1);
94 if ( ! md_buf_putchar(p->mbuf, '\n'))
95 return(0);
96
97 p->pos = 0;
98 return(mbuf_indent(p));
99 }
100
101
102 static int
103 mbuf_data(struct md_valid *p, char *buf)
104 {
105 size_t sz;
106 char *bufp;
107
108 assert(p->mbuf);
109 assert(0 != p->indent);
110
111 if (MD_LITERAL & p->flags)
112 return(md_buf_putstring(p->mbuf, buf));
113
114 if (0 == p->pos)
115 mbuf_indent(p);
116
117 /*
118 * Indent if we're at the beginning of a line. Don't indent
119 * more than 16 or so characters.
120 */
121
122 while (*buf) {
123 while (*buf && isspace(*buf))
124 buf++;
125
126 if (0 == *buf)
127 break;
128
129 bufp = buf;
130 while (*buf && ! isspace(*buf))
131 buf++;
132
133 if (0 != *buf)
134 *buf++ = 0;
135
136 /* Process word. */
137
138 sz = strlen(bufp);
139
140 if (sz + p->pos < 72) {
141 if ( ! md_buf_putstring(p->mbuf, bufp))
142 return(0);
143
144 /* FIXME: check punctuation. */
145
146 if ( ! md_buf_putchar(p->mbuf, ' '))
147 return(0);
148 p->pos += sz + 1;
149 continue;
150 }
151
152 if ( ! mbuf_newline(p))
153 return(0);
154
155 if ( ! md_buf_putstring(p->mbuf, bufp))
156 return(0);
157
158 /* FIXME: check punctuation. */
159
160 if ( ! md_buf_putchar(p->mbuf, ' '))
161 return(0);
162 p->pos += sz + 1;
163 }
164
165 return(1);
166 }
167
168
169 int
170 md_line_valid(void *arg, char *buf)
171 {
172 struct md_valid *p;
173
174 p = (struct md_valid *)arg;
175 return(roff_engine(p->tree, buf));
176 }
177
178
179 int
180 md_exit_valid(void *data, int flush)
181 {
182 int c;
183 struct md_valid *p;
184
185 p = (struct md_valid *)data;
186 c = roff_free(p->tree, flush);
187 free(p);
188
189 return(c);
190 }
191
192
193 void *
194 md_init_valid(const struct md_args *args,
195 struct md_mbuf *mbuf, const struct md_rbuf *rbuf)
196 {
197 struct roffcb cb;
198 struct md_valid *p;
199
200 cb.roffhead = roffhead;
201 cb.rofftail = rofftail;
202 cb.roffin = roffin;
203 cb.roffout = roffout;
204 cb.roffblkin = roffblkin;
205 cb.roffblkout = roffblkout;
206 cb.roffspecial = roffspecial;
207 cb.roffmsg = roffmsg;
208 cb.roffdata = roffdata;
209
210 if (NULL == (p = calloc(1, sizeof(struct md_valid))))
211 err(1, "malloc");
212
213 p->args = args;
214 p->mbuf = mbuf;
215 p->rbuf = rbuf;
216
217 assert(mbuf);
218
219 if (NULL == (p->tree = roff_alloc(&cb, p))) {
220 free(p);
221 return(NULL);
222 }
223
224 return(p);
225 }
226
227
228 /* ARGSUSED */
229 static int
230 roffhead(void *arg)
231 {
232
233 return(1);
234 }
235
236
237 static int
238 rofftail(void *arg)
239 {
240 struct md_valid *p;
241
242 assert(arg);
243 p = (struct md_valid *)arg;
244
245 if (mbuf_atnewline(p))
246 return(1);
247
248 return(md_buf_putchar(p->mbuf, '\n'));
249 }
250
251
252 static int
253 roffspecial(void *arg, int tok)
254 {
255
256 return(1);
257 }
258
259
260 static int
261 roffblkin(void *arg, int tok)
262 {
263 struct md_valid *p;
264
265 assert(arg);
266 p = (struct md_valid *)arg;
267
268 if ( ! mbuf_atnewline(p)) {
269 if ( ! md_buf_putchar(p->mbuf, '\n'))
270 return(0);
271 p->pos = 0;
272 if ( ! mbuf_indent(p))
273 return(0);
274 }
275
276 if ( ! md_buf_putstring(p->mbuf, toknames[tok]))
277 return(0);
278
279 if ( ! md_buf_putchar(p->mbuf, '\n'))
280 return(0);
281
282 p->pos = 0;
283 p->indent++;
284
285 return(mbuf_indent(p));
286 }
287
288
289 static int
290 roffblkout(void *arg, int tok)
291 {
292 struct md_valid *p;
293
294 assert(arg);
295 p = (struct md_valid *)arg;
296
297 if ( ! md_buf_putchar(p->mbuf, '\n'))
298 return(0);
299
300 p->pos = 0;
301 p->indent--;
302
303 return(mbuf_indent(p));
304 }
305
306
307 static int
308 roffin(void *arg, int tok, int *argcp, char **argvp)
309 {
310
311 return(1);
312 }
313
314
315 static int
316 roffout(void *arg, int tok)
317 {
318
319 return(1);
320 }
321
322
323
324 static void
325 roffmsg(void *arg, enum roffmsg lvl,
326 const char *buf, const char *pos, char *msg)
327 {
328 char *level;
329 struct md_valid *p;
330
331 assert(arg);
332 p = (struct md_valid *)arg;
333
334 switch (lvl) {
335 case (ROFF_WARN):
336 if ( ! (MD_WARN_ALL & p->args->warnings))
337 return;
338 level = "warning";
339 break;
340 case (ROFF_ERROR):
341 level = "error";
342 break;
343 default:
344 abort();
345 }
346
347 if (pos)
348 (void)fprintf(stderr, "%s:%zu: %s: %s\n",
349 p->rbuf->name, p->rbuf->line, level, msg);
350 else
351 (void)fprintf(stderr, "%s: %s: %s\n",
352 p->rbuf->name, level, msg);
353
354 }
355
356
357 static int
358 roffdata(void *arg, char *buf)
359 {
360 struct md_valid *p;
361
362 assert(arg);
363 p = (struct md_valid *)arg;
364 return(mbuf_data(p, buf));
365 }