]> git.cameronkatri.com Git - mandoc.git/blob - libmdocml.c
Considerable improvements across the board.
[mandoc.git] / libmdocml.c
1 /* $Id: libmdocml.c,v 1.6 2008/11/23 22:30:53 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 <assert.h>
20 #include <fcntl.h>
21 #include <err.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include "libmdocml.h"
28 #include "private.h"
29
30 #define BUFFER_LINE BUFSIZ
31
32 static int md_run_enter(const struct md_args *,
33 struct md_mbuf *, struct md_rbuf *, void *);
34 static int md_run_leave(const struct md_args *, struct md_mbuf *,
35 struct md_rbuf *, int, void *);
36 static ssize_t md_buf_fill(struct md_rbuf *);
37 static int md_buf_flush(struct md_mbuf *);
38
39
40 static ssize_t
41 md_buf_fill(struct md_rbuf *in)
42 {
43 ssize_t ssz;
44
45 assert(in);
46 assert(in->buf);
47 assert(in->bufsz > 0);
48 assert(in->name);
49
50 if (-1 == (ssz = read(in->fd, in->buf, in->bufsz)))
51 warn("%s", in->name);
52
53 return(ssz);
54 }
55
56
57 static int
58 md_buf_flush(struct md_mbuf *buf)
59 {
60 ssize_t sz;
61
62 assert(buf);
63 assert(buf->buf);
64 assert(buf->name);
65
66 if (0 == buf->pos)
67 return(1);
68
69 sz = write(buf->fd, buf->buf, buf->pos);
70
71 if (-1 == sz) {
72 warn("%s", buf->name);
73 return(0);
74 } else if ((size_t)sz != buf->pos) {
75 warnx("%s: short write", buf->name);
76 return(0);
77 }
78
79 buf->pos = 0;
80 return(1);
81 }
82
83
84 int
85 md_buf_putchar(struct md_mbuf *buf, char c)
86 {
87 return(md_buf_puts(buf, &c, 1));
88 }
89
90
91 int
92 md_buf_putstring(struct md_mbuf *buf, const char *p)
93 {
94 return(md_buf_puts(buf, p, strlen(p)));
95 }
96
97
98 int
99 md_buf_puts(struct md_mbuf *buf, const char *p, size_t sz)
100 {
101 size_t ssz;
102
103 assert(p);
104 assert(buf);
105 assert(buf->buf);
106
107 /* LINTED */
108 while (buf->pos + sz > buf->bufsz) {
109 ssz = buf->bufsz - buf->pos;
110 (void)memcpy(/* LINTED */
111 buf->buf + buf->pos, p, ssz);
112 p += (long)ssz;
113 sz -= ssz;
114 buf->pos += ssz;
115
116 if ( ! md_buf_flush(buf))
117 return(0);
118 }
119
120 (void)memcpy(/* LINTED */
121 buf->buf + buf->pos, p, sz);
122 buf->pos += sz;
123 return(1);
124 }
125
126
127 static int
128 md_run_leave(const struct md_args *args, struct md_mbuf *mbuf,
129 struct md_rbuf *rbuf, int c, void *data)
130 {
131 assert(args);
132 assert(mbuf);
133 assert(rbuf);
134
135 /* Run exiters. */
136 switch (args->type) {
137 case (MD_HTML4_STRICT):
138 if ( ! md_exit_html4_strict(args, mbuf, rbuf, c, data))
139 return(-1);
140 break;
141 case (MD_DUMMY):
142 break;
143 default:
144 abort();
145 }
146
147 /* Make final flush of buffer. */
148 if ( ! md_buf_flush(mbuf))
149 return(-1);
150
151 return(c);
152 }
153
154
155 static int
156 md_run_enter(const struct md_args *args, struct md_mbuf *mbuf,
157 struct md_rbuf *rbuf, void *p)
158 {
159 ssize_t sz, i;
160 char line[BUFFER_LINE];
161 size_t pos;
162 md_line fp;
163
164 assert(args);
165 assert(mbuf);
166 assert(rbuf);
167
168 /* Function ptrs to line-parsers. */
169 switch (args->type) {
170 case (MD_HTML4_STRICT):
171 fp = md_line_html4_strict;
172 break;
173 case (MD_DUMMY):
174 fp = md_line_dummy;
175 break;
176 default:
177 abort();
178 }
179
180 /* LINTED */
181 for (pos = 0; ; ) {
182 if (-1 == (sz = md_buf_fill(rbuf)))
183 return(md_run_leave(args, mbuf, rbuf, -1, p));
184 else if (0 == sz)
185 break;
186
187 for (i = 0; i < sz; i++) {
188 if ('\n' == rbuf->buf[i]) {
189 if ( ! (*fp)(args, mbuf, rbuf, line, pos, p))
190 return(md_run_leave(args, mbuf, rbuf,
191 -1, p));
192 rbuf->line++;
193 pos = 0;
194 continue;
195 }
196
197 if (pos < BUFFER_LINE) {
198 /* LINTED */
199 line[pos++] = rbuf->buf[i];
200 continue;
201 }
202
203 warnx("%s: line %zu too long",
204 rbuf->name, rbuf->line);
205 return(md_run_leave(args, mbuf, rbuf, -1, p));
206 }
207 }
208
209 if (0 != pos && ! (*fp)(args, mbuf, rbuf, line, pos, p))
210 return(md_run_leave(args, mbuf, rbuf, -1, p));
211
212 return(md_run_leave(args, mbuf, rbuf, 0, p));
213 }
214
215
216 int
217 md_run(const struct md_args *args,
218 const struct md_buf *out, const struct md_buf *in)
219 {
220 struct md_mbuf mbuf;
221 struct md_rbuf rbuf;
222 void *data;
223
224 assert(args);
225 assert(in);
226 assert(out);
227
228 (void)memcpy(&mbuf, out, sizeof(struct md_buf));
229 (void)memcpy(&rbuf, in, sizeof(struct md_buf));
230
231 mbuf.pos = 0;
232 rbuf.line = 1;
233 data = NULL;
234
235 /* Run initialisers. */
236 switch (args->type) {
237 case (MD_HTML4_STRICT):
238 if ( ! md_init_html4_strict(args, &mbuf, &rbuf, &data))
239 return(-1);
240 break;
241 case (MD_DUMMY):
242 break;
243 default:
244 abort();
245 }
246
247 /* Go into mainline. */
248 return(md_run_enter(args, &mbuf, &rbuf, data));
249 }