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