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