tex: move tex fmt_ops to tex.c
[ctxt.git] / fmt.c
blobd58bf9486dabaa08022c8a40d614749381bddfe3
1 #include <ctype.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "ctxt.h"
5 #include "util.h"
7 #define MAXLINE 1024
9 struct doc {
10 int fd;
11 struct txt *txt;
12 struct fmt_ops *ops;
13 int level;
16 static struct doc *doc_alloc(int fd, struct txt *txt, struct fmt_ops *ops)
18 struct doc *doc = xmalloc(sizeof(struct doc));
19 doc->fd = fd;
20 doc->txt = txt;
21 doc->ops = ops;
22 doc->level = 0;
23 return doc;
26 static void doc_free(struct doc *doc)
28 free(doc);
31 static char *doc_line(struct doc *doc, int line)
33 char *s = txt_line(doc->txt, line);
34 int i;
35 for (i = 0; i < doc->level && s && *s; i++)
36 s++;
37 return s;
40 static void doc_handle(struct doc *doc, int beg, int end, int level);
42 static int doc_head(struct doc *doc, int beg, int end)
44 char *line = doc_line(doc, beg);
45 char *next = doc_line(doc, beg + 1);
46 char c;
47 char *s = next;
48 char *signs = "=-~";
49 if (!next || !*line || beg == end || doc->level)
50 return 0;
51 c = *next;
52 if (!c || !strchr(signs, *next))
53 return 0;
54 while (*++s)
55 if (*s != c)
56 return 0;
57 doc->ops->head_beg(doc->fd, strchr(signs, *next) - signs);
58 doc->ops->put(doc->fd, line);
59 doc->ops->head_end(doc->fd);
60 return 2;
63 static char *possible_inline(char *s) {
64 char *signs = "*$@%\\";
65 char *home = s;
66 while (*s) {
67 if (strchr(signs, *s) && !isspace(*(s + 1)))
68 if (s == home || isspace(*(s - 1)))
69 return s;
70 s++;
72 return NULL;
75 static void fillbuf(char *buf, int len, char *beg, char *end)
77 int n = len - 1 < end - beg ? len - 1 : end - beg;
78 memcpy(buf, beg, n);
79 buf[n] = '\0';
82 static char *doc_put_inline(struct doc *doc, char *s)
84 char buf[1024];
85 char *r = NULL;
86 switch (*s) {
87 case '*':
88 r = strchr(s + 1, *s);
89 if (r) {
90 fillbuf(buf, LENGTH(buf), s + 1, r);
91 doc->ops->put_emph(doc->fd, buf);
92 r++;
94 return r;
95 case '$':
96 r = strchr(s + 1, *s);
97 if (r) {
98 fillbuf(buf, LENGTH(buf), s, r + 1);
99 doc->ops->put_raw(doc->fd, buf);
100 r++;
102 return r;
103 case '%':
104 r = strchr(s + 1, *s);
105 if (r) {
106 fillbuf(buf, LENGTH(buf), s + 1, r);
107 doc->ops->put_raw(doc->fd, buf);
108 r++;
110 return r;
111 case '@':
112 for (r = s + 1; isalnum(*r); r++);
113 if (r) {
114 fillbuf(buf, LENGTH(buf), s + 1, r);
115 doc->ops->put_ref(doc->fd, buf);
117 return r;
118 case '\\':
119 if (strchr("*$@\\", *(s + 1))) {
120 fillbuf(buf, LENGTH(buf), s + 1, s + 2);
121 doc->ops->put(doc->fd, buf);
122 return s + 2;
124 return NULL;
125 default:
126 break;
128 return NULL;
131 static void put_line(struct doc *doc, char *s)
133 char buf[1024];
134 char *done = s;
135 while (*s) {
136 char *r = possible_inline(s);
137 if (!r)
138 break;
139 fillbuf(buf, LENGTH(buf), done, r);
140 doc->ops->put(doc->fd, buf);
141 s = done = r;
142 if ((r = doc_put_inline(doc, r)))
143 s = done = r;
144 else
145 s++;
147 doc->ops->put(doc->fd, done);
150 static void raw_line(struct doc *doc, char *s)
152 doc->ops->put(doc->fd, s);
155 static void put_lines(struct doc *doc, int beg, int end)
157 int i;
158 for (i = beg; i < end; i++) {
159 put_line(doc, doc_line(doc, i));
160 put_line(doc, "\n");
164 static void raw_lines(struct doc *doc, int beg, int end)
166 int i;
167 for (i = beg; i < end; i++) {
168 raw_line(doc, doc_line(doc, i));
169 raw_line(doc, "\n");
173 static int indents(char *s)
175 char *r = s;
176 while (isspace(*r))
177 r++;
178 return r - s;
181 static int islist(char *first, char *line)
183 char *signs = "*-+";
184 if (!line) {
185 if (!first || strlen(first) < 2)
186 return 0;
187 if (first[1] != ' ' || !strchr(signs, first[0]))
188 return 0;
189 return 1;
191 if (strlen(line) < 2)
192 return 0;
193 return line[0] == first[0] && line[1] == first[1];
196 static int par_end(struct doc *doc, int beg, int end)
198 int i = beg;
199 char *line;
200 while (i < end && (line = doc_line(doc, i))) {
201 if (!*line || indents(line) || islist(line, NULL))
202 break;
203 i++;
205 return i;
208 static int doc_par(struct doc *doc, int beg, int end)
210 int i;
211 if (indents(doc_line(doc, beg)))
212 return 0;
213 doc->ops->par_beg(doc->fd);
214 i = par_end(doc, beg, end);
215 put_lines(doc, beg, i);
216 doc->ops->par_end(doc->fd);
217 return i - beg;
220 static int min(int a, int b)
222 return a < b ? a : b;
225 static int doc_deindent(struct doc *doc, int n, int indent)
227 char *line;
228 int result = n;
229 while ((line = doc_line(doc, n))) {
230 if (*line && indents(line) < indent)
231 break;
232 n++;
233 if (*line)
234 result = n;
236 return result;
239 static int doc_block(struct doc *doc, int beg, int end)
241 int level = indents(doc_line(doc, beg));
242 int next;
243 if (!level)
244 return 0;
245 next = min(end, doc_deindent(doc, beg + 1, level));
246 doc_handle(doc, beg, next, level);
247 return next - beg;
251 static int doc_list(struct doc *doc, int beg, int end)
253 int i = beg;
254 char *first = doc_line(doc, i);
255 char *line = first;
256 if (!islist(first, NULL))
257 return 0;
258 doc->ops->list_beg(doc->fd);
259 while ((line = doc_line(doc, i)) && islist(first, line)) {
260 int next = min(end, doc_deindent(doc, i + 1, 2));
261 int head = i;
262 doc->ops->item_beg(doc->fd);
264 doc->level += 2;
265 i = par_end(doc, i, next);
266 put_lines(doc, head, i);
267 doc->level -= 2;
269 doc_handle(doc, i, next, 2);
270 i = next;
271 doc->ops->item_end(doc->fd);
272 if (i == end)
273 break;
275 doc->ops->list_end(doc->fd);
276 return i - beg;
279 static int doc_pre(struct doc *doc, int beg, int end)
281 if (!doc->level)
282 return 0;
283 doc->ops->pre_beg(doc->fd);
284 raw_lines(doc, beg, end);
285 doc->ops->pre_end(doc->fd);
286 return end - beg;
289 static int doc_formula(struct doc *doc, int beg, int end)
291 int i;
292 if (!doc->level || *doc_line(doc, beg) != '$')
293 return 0;
294 doc->ops->formula_beg(doc->fd);
295 for (i = beg; i < end; i++) {
296 char *line = doc_line(doc, i);
297 if (i == beg)
298 line++;
299 raw_line(doc, line);
300 if (i != end - 1)
301 raw_line(doc, "\n");
303 doc->ops->formula_end(doc->fd);
304 return end - beg;
307 static int doc_raw(struct doc *doc, int beg, int end)
309 if (!doc->level || *doc_line(doc, beg) != '%')
310 return 0;
311 raw_line(doc, doc_line(doc, beg) + 1);
312 raw_line(doc, "\n");
313 raw_lines(doc, beg + 1, end);
314 return end - beg;
317 static int (*parts[])(struct doc *doc, int beg, int end) =
318 {doc_head, doc_list, doc_formula, doc_raw,
319 doc_pre, doc_par, doc_block};
321 static void doc_handle(struct doc *doc, int beg, int end, int level)
323 int line = beg;
324 int i;
325 doc->level += level;
326 while (line < end) {
327 int c = 0;
328 for (i = 0; i < LENGTH(parts); i++)
329 if ((c = parts[i](doc, line, end)))
330 break;
331 line += c;
332 if (!c) {
333 put_lines(doc, line, line + 1);
334 line++;
337 doc->level -= level;
340 void fmt(int fd, struct txt *txt, struct fmt_ops *ops)
342 struct doc *doc = doc_alloc(fd, txt, ops);
343 doc->ops->doc_beg(fd);
344 doc_handle(doc, 0, txt->n, 0);
345 doc->ops->doc_end(fd);
346 doc_free(doc);