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