]> git.cameronkatri.com Git - mandoc.git/blob - mlg.c
17ef1efd9a8217e8c3e7081a6d2c21c46e544dda
[mandoc.git] / mlg.c
1 /* $Id: mlg.c,v 1.3 2008/12/03 21:27:56 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 <err.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25
26 #include "libmdocml.h"
27 #include "private.h"
28 #include "ml.h"
29
30 /* TODO: literal tokens. */
31
32 #define COLUMNS 72
33 #define INDENT 4
34 #define MAXINDENT 10
35
36 enum md_tok {
37 MD_TEXT,
38 MD_INLINE_IN,
39 MD_INLINE_OUT,
40 MD_BLK_IN,
41 MD_BLK_OUT,
42 };
43
44 struct md_mlg {
45 const struct md_args *args;
46 const struct md_rbuf *rbuf;
47
48 struct md_mbuf *mbuf;
49 struct rofftree *tree;
50 size_t indent;
51 size_t pos;
52 enum md_tok last;
53 void *arg;
54 ml_begintag begintag;
55 ml_endtag endtag;
56 ml_begin begin;
57 ml_end end;
58 int flags;
59 #define ML_OVERRIDE_ONE (1 << 0)
60 #define ML_OVERRIDE_ALL (1 << 1)
61 };
62
63
64 static void mlg_roffmsg(void *arg, enum roffmsg,
65 const char *, const char *, char *);
66 static int mlg_roffhead(void *);
67 static int mlg_rofftail(void *);
68 static int mlg_roffin(void *, int, int *, char **);
69 static int mlg_roffdata(void *, int, char *);
70 static int mlg_roffout(void *, int);
71 static int mlg_roffblkin(void *, int, int *, char **);
72 static int mlg_roffblkout(void *, int);
73 static int mlg_roffspecial(void *, int, int *,
74 char **, char **);
75 static int mlg_roffblkheadin(void *, int, int *, char **);
76 static int mlg_roffblkheadout(void *, int);
77 static int mlg_roffblkbodyin(void *, int, int *, char **);
78 static int mlg_roffblkbodyout(void *, int);
79
80 static int mlg_beginblk(struct md_mlg *, enum md_ns, int,
81 int *, char **);
82 static int mlg_endblk(struct md_mlg *, enum md_ns, int);
83 static int mlg_begintag(struct md_mlg *, enum md_ns,
84 int, int *, char **);
85 static int mlg_endtag(struct md_mlg *, enum md_ns, int);
86 static int mlg_indent(struct md_mlg *);
87 static int mlg_newline(struct md_mlg *);
88 static void mlg_mode(struct md_mlg *, enum md_tok);
89 static int mlg_data(struct md_mlg *, int, char *);
90
91 #ifdef __linux__
92 extern size_t strlcat(char *, const char *, size_t);
93 extern size_t strlcpy(char *, const char *, size_t);
94 #endif
95
96
97 static int
98 mlg_beginblk(struct md_mlg *p, enum md_ns ns, int tok,
99 int *argc, char **argv)
100 {
101 if (0 != p->pos) {
102 if ( ! mlg_newline(p))
103 return(0);
104 if ( ! mlg_indent(p))
105 return(0);
106 } else if ( ! mlg_indent(p))
107 return(0);
108
109 p->indent++;
110 mlg_mode(p, MD_BLK_IN);
111
112 if ( ! mlg_begintag(p, ns, tok, argc, argv))
113 return(0);
114 return(mlg_newline(p));
115 }
116
117
118 static int
119 mlg_endblk(struct md_mlg *p, enum md_ns ns, int tok)
120 {
121
122 p->indent--;
123
124 if (0 != p->pos) {
125 if ( ! mlg_newline(p))
126 return(0);
127 if ( ! mlg_indent(p))
128 return(0);
129 } else if ( ! mlg_indent(p))
130 return(0);
131
132 mlg_mode(p, MD_BLK_OUT);
133 if ( ! mlg_endtag(p, ns, tok))
134 return(0);
135 return(mlg_newline(p));
136 }
137
138
139 static int
140 mlg_begintag(struct md_mlg *p, enum md_ns ns, int tok,
141 int *argc, char **argv)
142 {
143 ssize_t res;
144
145 /* TODO: extra rules for block/inline. */
146
147 if ( ! ml_nputs(p->mbuf, "<", 1, &p->pos))
148 return(0);
149
150 res = (*p->begintag)(p->mbuf, p->args, ns, tok,
151 argc, (const char **)argv);
152 if (-1 == res)
153 return(0);
154
155 assert(res >= 0);
156 p->pos += (size_t)res;
157
158 /* TODO: extra rules for block/inline. */
159
160 return(ml_nputs(p->mbuf, ">", 1, &p->pos));
161 }
162
163
164 static int
165 mlg_endtag(struct md_mlg *p, enum md_ns ns, int tok)
166 {
167 ssize_t res;
168
169 /* TODO: extra rules for block/inline. */
170
171 if ( ! ml_nputs(p->mbuf, "</", 2, &p->pos))
172 return(0);
173
174 res = (*p->endtag)(p->mbuf, p->args, ns, tok);
175 if (-1 == res)
176 return(0);
177
178 assert(res >= 0);
179 p->pos += (size_t)res;
180
181 /* TODO: extra rules for block/inline. */
182
183 return(ml_nputs(p->mbuf, ">", 1, &p->pos));
184 }
185
186
187 static int
188 mlg_indent(struct md_mlg *p)
189 {
190 size_t count;
191
192 count = p->indent > MAXINDENT ? (size_t)MAXINDENT : p->indent;
193 count *= INDENT;
194
195 assert(0 == p->pos);
196 return(ml_putchars(p->mbuf, ' ', count, &p->pos));
197 }
198
199
200 static int
201 mlg_newline(struct md_mlg *p)
202 {
203 size_t dummy;
204
205 if ( ! ml_nputs(p->mbuf, "\n", 1, &dummy))
206 return(0);
207 p->pos = 0;
208 return(1);
209 }
210
211
212 static void
213 mlg_mode(struct md_mlg *p, enum md_tok ns)
214 {
215
216 p->flags &= ~ML_OVERRIDE_ONE;
217 p->last = ns;
218 }
219
220
221 static int
222 mlg_data(struct md_mlg *p, int space, char *buf)
223 {
224 size_t sz;
225 char *bufp;
226
227 assert(p->mbuf);
228 assert(0 != p->indent);
229
230 if (ML_OVERRIDE_ONE & p->flags ||
231 ML_OVERRIDE_ALL & p->flags)
232 space = 0;
233
234 while (*buf) {
235 while (*buf && isspace(*buf))
236 buf++;
237
238 if (0 == *buf)
239 break;
240
241 bufp = buf;
242 while (*buf && ! isspace(*buf))
243 buf++;
244
245 if (0 != *buf)
246 *buf++ = 0;
247
248 sz = strlen(bufp);
249
250 if (0 == p->pos) {
251 if ( ! mlg_indent(p))
252 return(0);
253 if ( ! ml_nputstring(p->mbuf, bufp,
254 sz, &p->pos))
255 return(0);
256 if (p->indent * INDENT + sz >= COLUMNS)
257 if ( ! mlg_newline(p))
258 return(0);
259 if ( ! (ML_OVERRIDE_ALL & p->flags))
260 space = 1;
261 continue;
262 }
263
264 if (space && sz + p->pos >= COLUMNS) {
265 if ( ! mlg_newline(p))
266 return(0);
267 if ( ! mlg_indent(p))
268 return(0);
269 } else if (space) {
270 if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
271 return(0);
272 }
273
274 if ( ! ml_nputstring(p->mbuf, bufp, sz, &p->pos))
275 return(0);
276
277 if ( ! (ML_OVERRIDE_ALL & p->flags))
278 space = 1;
279 }
280
281 return(1);
282 }
283
284
285 int
286 mlg_line(struct md_mlg *p, char *buf)
287 {
288
289 return(roff_engine(p->tree, buf));
290 }
291
292
293 int
294 mlg_exit(struct md_mlg *p, int flush)
295 {
296 int c;
297
298 c = roff_free(p->tree, flush);
299 free(p);
300 return(c);
301 }
302
303
304 struct md_mlg *
305 mlg_alloc(const struct md_args *args,
306 const struct md_rbuf *rbuf,
307 struct md_mbuf *mbuf,
308 ml_begintag begintag, ml_endtag endtag,
309 ml_begin begin, ml_end end)
310 {
311 struct roffcb cb;
312 struct md_mlg *p;
313
314 cb.roffhead = mlg_roffhead;
315 cb.rofftail = mlg_rofftail;
316 cb.roffin = mlg_roffin;
317 cb.roffout = mlg_roffout;
318 cb.roffblkin = mlg_roffblkin;
319 cb.roffblkheadin = mlg_roffblkheadin;
320 cb.roffblkheadout = mlg_roffblkheadout;
321 cb.roffblkbodyin = mlg_roffblkbodyin;
322 cb.roffblkbodyout = mlg_roffblkbodyout;
323 cb.roffblkout = mlg_roffblkout;
324 cb.roffspecial = mlg_roffspecial;
325 cb.roffmsg = mlg_roffmsg;
326 cb.roffdata = mlg_roffdata;
327
328 if (NULL == (p = calloc(1, sizeof(struct md_mlg))))
329 err(1, "calloc");
330
331 p->args = args;
332 p->mbuf = mbuf;
333 p->rbuf = rbuf;
334 p->begintag = begintag;
335 p->endtag = endtag;
336 p->begin = begin;
337 p->end = end;
338
339 if (NULL == (p->tree = roff_alloc(&cb, p))) {
340 free(p);
341 return(NULL);
342 }
343
344 return(p);
345 }
346
347
348 static int
349 mlg_roffhead(void *arg)
350 {
351 struct md_mlg *p;
352
353 assert(arg);
354 p = (struct md_mlg *)arg;
355
356 mlg_mode(p, MD_BLK_IN);
357 if ( ! (*p->begin)(p->mbuf, p->args))
358 return(0);
359
360 p->indent++;
361 return(mlg_newline(p));
362 }
363
364
365 static int
366 mlg_rofftail(void *arg)
367 {
368 struct md_mlg *p;
369
370 assert(arg);
371 p = (struct md_mlg *)arg;
372
373 if (0 != p->pos && ! mlg_newline(p))
374 return(0);
375
376 mlg_mode(p, MD_BLK_OUT);
377 if ( ! (*p->end)(p->mbuf, p->args))
378 return(0);
379
380 return(mlg_newline(p));
381 }
382
383
384 /* ARGSUSED */
385 static int
386 mlg_roffspecial(void *arg, int tok, int *argc, char **argv, char **more)
387 {
388 struct md_mlg *p;
389
390 assert(arg);
391 p = (struct md_mlg *)arg;
392
393 switch (tok) {
394 case (ROFF_Ns):
395 p->flags |= ML_OVERRIDE_ONE;
396 break;
397 case (ROFF_Sm):
398 assert(*more);
399 if (0 == strcmp(*more, "on"))
400 p->flags |= ML_OVERRIDE_ALL;
401 else
402 p->flags &= ~ML_OVERRIDE_ALL;
403 break;
404 default:
405 break;
406 }
407
408 return(1);
409 }
410
411
412 static int
413 mlg_roffblkin(void *arg, int tok, int *argc, char **argv)
414 {
415
416 return(mlg_beginblk((struct md_mlg *)arg,
417 MD_NS_BLOCK, tok, argc, argv));
418 }
419
420
421 static int
422 mlg_roffblkout(void *arg, int tok)
423 {
424
425 return(mlg_endblk((struct md_mlg *)arg, MD_NS_BLOCK, tok));
426 }
427
428
429 static int
430 mlg_roffblkbodyin(void *arg, int tok, int *argc, char **argv)
431 {
432
433 return(mlg_beginblk((struct md_mlg *)arg,
434 MD_NS_BODY, tok, argc, argv));
435 }
436
437
438 static int
439 mlg_roffblkbodyout(void *arg, int tok)
440 {
441
442 return(mlg_endblk((struct md_mlg *)arg, MD_NS_BODY, tok));
443 }
444
445
446 static int
447 mlg_roffblkheadin(void *arg, int tok, int *argc, char **argv)
448 {
449
450 return(mlg_beginblk((struct md_mlg *)arg,
451 MD_NS_HEAD, tok, argc, argv));
452 }
453
454
455 static int
456 mlg_roffblkheadout(void *arg, int tok)
457 {
458
459 return(mlg_endblk((struct md_mlg *)arg, MD_NS_HEAD, tok));
460 }
461
462
463 static int
464 mlg_roffin(void *arg, int tok, int *argc, char **argv)
465 {
466 struct md_mlg *p;
467
468 assert(arg);
469 p = (struct md_mlg *)arg;
470
471 /* FIXME: this part. */
472
473 if ( ! (ML_OVERRIDE_ONE & p->flags) &&
474 ! (ML_OVERRIDE_ALL & p->flags) &&
475 p->pos + 11 > COLUMNS)
476 if ( ! mlg_newline(p))
477 return(0);
478
479 if (0 != p->pos && (MD_TEXT == p->last ||
480 MD_INLINE_OUT == p->last)
481 && ! (ML_OVERRIDE_ONE & p->flags)
482 && ! (ML_OVERRIDE_ALL & p->flags))
483 if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
484 return(0);
485
486 if (0 == p->pos && ! mlg_indent(p))
487 return(0);
488
489 mlg_mode(p, MD_INLINE_IN);
490 return(mlg_begintag(p, MD_NS_INLINE, tok, argc, argv));
491 }
492
493
494 static int
495 mlg_roffout(void *arg, int tok)
496 {
497 struct md_mlg *p;
498
499 assert(arg);
500 p = (struct md_mlg *)arg;
501
502 if (0 == p->pos && ! mlg_indent(p))
503 return(0);
504
505 mlg_mode(p, MD_INLINE_OUT);
506 return(mlg_endtag(p, MD_NS_INLINE, tok));
507 }
508
509
510 static void
511 mlg_roffmsg(void *arg, enum roffmsg lvl,
512 const char *buf, const char *pos, char *msg)
513 {
514 char *level;
515 struct md_mlg *p;
516
517 assert(arg);
518 p = (struct md_mlg *)arg;
519
520 switch (lvl) {
521 case (ROFF_WARN):
522 if ( ! (MD_WARN_ALL & p->args->warnings))
523 return;
524 level = "warning";
525 break;
526 case (ROFF_ERROR):
527 level = "error";
528 break;
529 default:
530 abort();
531 }
532
533 if (pos)
534 (void)fprintf(stderr, "%s:%zu: %s: %s (column %zu)\n",
535 p->rbuf->name, p->rbuf->line, level,
536 msg, pos - buf);
537 else
538 (void)fprintf(stderr, "%s: %s: %s\n",
539 p->rbuf->name, level, msg);
540
541 }
542
543
544 static int
545 mlg_roffdata(void *arg, int space, char *buf)
546 {
547 struct md_mlg *p;
548
549 assert(arg);
550 p = (struct md_mlg *)arg;
551
552 if ( ! mlg_data(p, space, buf))
553 return(0);
554
555 mlg_mode(p, MD_TEXT);
556 return(1);
557 }
558