Annotation of mandoc/mlg.c, Revision 1.2
1.2 ! kristaps 1: /* $Id: mlg.c,v 1.1 2008/12/03 14:39:59 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 *);
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);
1.2 ! kristaps 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);
1.1 kristaps 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
1.2 ! kristaps 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
1.1 kristaps 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 ? 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: p->flags &= ~ML_OVERRIDE_ONE;
216: p->last = ns;
217: }
218:
219:
220: static int
221: mlg_data(struct md_mlg *p, int space, char *buf)
222: {
223: size_t sz;
224: char *bufp;
225:
226: assert(p->mbuf);
227: assert(0 != p->indent);
228:
229: if (ML_OVERRIDE_ONE & p->flags ||
230: ML_OVERRIDE_ALL & p->flags)
231: space = 0;
232:
233: while (*buf) {
234: while (*buf && isspace(*buf))
235: buf++;
236:
237: if (0 == *buf)
238: break;
239:
240: bufp = buf;
241: while (*buf && ! isspace(*buf))
242: buf++;
243:
244: if (0 != *buf)
245: *buf++ = 0;
246:
247: sz = strlen(bufp);
248:
249: if (0 == p->pos) {
250: if ( ! mlg_indent(p))
251: return(0);
252: if ( ! ml_nputstring(p->mbuf, bufp,
253: sz, &p->pos))
254: return(0);
255: if (p->indent * MAXINDENT + sz >= COLUMNS)
256: if ( ! mlg_newline(p))
257: return(0);
258: if ( ! (ML_OVERRIDE_ALL & p->flags))
259: space = 1;
260: continue;
261: }
262:
263: if (space && sz + p->pos >= COLUMNS) {
264: if ( ! mlg_newline(p))
265: return(0);
266: if ( ! mlg_indent(p))
267: return(0);
268: } else if (space) {
269: if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
270: return(0);
271: }
272:
273: if ( ! ml_nputstring(p->mbuf, bufp, sz, &p->pos))
274: return(0);
275:
276: if ( ! (ML_OVERRIDE_ALL & p->flags))
277: space = 1;
278: }
279:
280: return(1);
281: }
282:
283:
284: int
285: mlg_line(struct md_mlg *p, char *buf)
286: {
287:
288: return(roff_engine(p->tree, buf));
289: }
290:
291:
292: int
293: mlg_exit(struct md_mlg *p, int flush)
294: {
295: int c;
296:
297: c = roff_free(p->tree, flush);
298: free(p);
299: return(c);
300: }
301:
302:
303: struct md_mlg *
304: mlg_alloc(const struct md_args *args,
305: const struct md_rbuf *rbuf,
306: struct md_mbuf *mbuf,
1.2 ! kristaps 307: ml_begintag begintag, ml_endtag endtag,
! 308: ml_begin begin, ml_end end)
1.1 kristaps 309: {
310: struct roffcb cb;
311: struct md_mlg *p;
312:
313: cb.roffhead = mlg_roffhead;
314: cb.rofftail = mlg_rofftail;
315: cb.roffin = mlg_roffin;
316: cb.roffout = mlg_roffout;
317: cb.roffblkin = mlg_roffblkin;
1.2 ! kristaps 318: cb.roffblkheadin = mlg_roffblkheadin;
! 319: cb.roffblkheadout = mlg_roffblkheadout;
! 320: cb.roffblkbodyin = mlg_roffblkbodyin;
! 321: cb.roffblkbodyout = mlg_roffblkbodyout;
1.1 kristaps 322: cb.roffblkout = mlg_roffblkout;
323: cb.roffspecial = mlg_roffspecial;
324: cb.roffmsg = mlg_roffmsg;
325: cb.roffdata = mlg_roffdata;
326:
327: if (NULL == (p = calloc(1, sizeof(struct md_mlg))))
328: err(1, "calloc");
329:
330: p->args = args;
331: p->mbuf = mbuf;
332: p->rbuf = rbuf;
333: p->begintag = begintag;
334: p->endtag = endtag;
1.2 ! kristaps 335: p->begin = begin;
! 336: p->end = end;
1.1 kristaps 337:
338: if (NULL == (p->tree = roff_alloc(&cb, p))) {
339: free(p);
340: return(NULL);
341: }
342:
343: return(p);
344: }
345:
346:
347: static int
348: mlg_roffhead(void *arg)
349: {
350: struct md_mlg *p;
351:
352: assert(arg);
353: p = (struct md_mlg *)arg;
354:
355: mlg_mode(p, MD_BLK_IN);
1.2 ! kristaps 356: if ( ! (*p->begin)(p->mbuf, p->args))
1.1 kristaps 357: return(0);
358:
359: p->indent++;
360: return(mlg_newline(p));
361: }
362:
363:
364: static int
365: mlg_rofftail(void *arg)
366: {
367: struct md_mlg *p;
368:
369: assert(arg);
370: p = (struct md_mlg *)arg;
371:
372: if (0 != p->pos && ! mlg_newline(p))
373: return(0);
374:
375: mlg_mode(p, MD_BLK_OUT);
1.2 ! kristaps 376: if ( ! (*p->end)(p->mbuf, p->args))
1.1 kristaps 377: return(0);
378:
379: return(mlg_newline(p));
380: }
381:
382:
383: /* ARGSUSED */
384: static int
385: mlg_roffspecial(void *arg, int tok, int *argc, char **argv, char **more)
386: {
387: struct md_mlg *p;
388:
389: assert(arg);
390: p = (struct md_mlg *)arg;
391:
392: switch (tok) {
393: case (ROFF_Ns):
394: p->flags |= ML_OVERRIDE_ONE;
395: break;
396: case (ROFF_Sm):
397: assert(*more);
398: if (0 == strcmp(*more, "on"))
399: p->flags |= ML_OVERRIDE_ALL;
400: else
401: p->flags &= ~ML_OVERRIDE_ALL;
402: break;
403: default:
404: break;
405: }
406:
407: return(1);
408: }
409:
410:
411: static int
412: mlg_roffblkin(void *arg, int tok, int *argc, char **argv)
413: {
414:
1.2 ! kristaps 415: return(mlg_beginblk((struct md_mlg *)arg,
! 416: MD_NS_BLOCK, tok, argc, argv));
! 417: }
! 418:
! 419:
! 420: static int
! 421: mlg_roffblkout(void *arg, int tok)
! 422: {
! 423:
! 424: return(mlg_endblk((struct md_mlg *)arg, MD_NS_BLOCK, tok));
! 425: }
! 426:
! 427:
! 428: static int
! 429: mlg_roffblkbodyin(void *arg, int tok, int *argc, char **argv)
! 430: {
! 431:
! 432: return(mlg_beginblk((struct md_mlg *)arg,
! 433: MD_NS_BODY, tok, argc, argv));
! 434: }
1.1 kristaps 435:
436:
1.2 ! kristaps 437: static int
! 438: mlg_roffblkbodyout(void *arg, int tok)
! 439: {
1.1 kristaps 440:
1.2 ! kristaps 441: return(mlg_endblk((struct md_mlg *)arg, MD_NS_BODY, tok));
1.1 kristaps 442: }
443:
444:
445: static int
1.2 ! kristaps 446: mlg_roffblkheadin(void *arg, int tok, int *argc, char **argv)
1.1 kristaps 447: {
448:
1.2 ! kristaps 449: return(mlg_beginblk((struct md_mlg *)arg,
! 450: MD_NS_HEAD, tok, argc, argv));
! 451: }
1.1 kristaps 452:
453:
1.2 ! kristaps 454: static int
! 455: mlg_roffblkheadout(void *arg, int tok)
! 456: {
1.1 kristaps 457:
1.2 ! kristaps 458: return(mlg_endblk((struct md_mlg *)arg, MD_NS_HEAD, tok));
1.1 kristaps 459: }
460:
461:
462: static int
463: mlg_roffin(void *arg, int tok, int *argc, char **argv)
464: {
465: struct md_mlg *p;
466:
467: assert(arg);
468: p = (struct md_mlg *)arg;
469:
470: /* FIXME: this part. */
471:
472: if ( ! (ML_OVERRIDE_ONE & p->flags) &&
473: ! (ML_OVERRIDE_ALL & p->flags) &&
474: p->pos + 11 > COLUMNS)
475: if ( ! mlg_newline(p))
476: return(0);
477:
478: if (0 != p->pos && (MD_TEXT == p->last ||
479: MD_INLINE_OUT == p->last)
480: && ! (ML_OVERRIDE_ONE & p->flags)
481: && ! (ML_OVERRIDE_ALL & p->flags))
482: if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
483: return(0);
484:
485: if (0 == p->pos && ! mlg_indent(p))
486: return(0);
487:
488: mlg_mode(p, MD_INLINE_IN);
489: return(mlg_begintag(p, MD_NS_INLINE, tok, argc, argv));
490: }
491:
492:
493: static int
494: mlg_roffout(void *arg, int tok)
495: {
496: struct md_mlg *p;
497:
498: assert(arg);
499: p = (struct md_mlg *)arg;
500:
501: if (0 == p->pos && ! mlg_indent(p))
502: return(0);
503:
504: mlg_mode(p, MD_INLINE_OUT);
505: return(mlg_endtag(p, MD_NS_INLINE, tok));
506: }
507:
508:
509: static void
510: mlg_roffmsg(void *arg, enum roffmsg lvl,
511: const char *buf, const char *pos, char *msg)
512: {
513: char *level;
514: struct md_mlg *p;
515:
516: assert(arg);
517: p = (struct md_mlg *)arg;
518:
519: switch (lvl) {
520: case (ROFF_WARN):
521: if ( ! (MD_WARN_ALL & p->args->warnings))
522: return;
523: level = "warning";
524: break;
525: case (ROFF_ERROR):
526: level = "error";
527: break;
528: default:
529: abort();
530: }
531:
532: if (pos)
533: (void)fprintf(stderr, "%s:%zu: %s: %s (column %zu)\n",
534: p->rbuf->name, p->rbuf->line, level,
535: msg, pos - buf);
536: else
537: (void)fprintf(stderr, "%s: %s: %s\n",
538: p->rbuf->name, level, msg);
539:
540: }
541:
542:
543: static int
544: mlg_roffdata(void *arg, int space, char *buf)
545: {
546: struct md_mlg *p;
547:
548: assert(arg);
549: p = (struct md_mlg *)arg;
550:
551: if ( ! mlg_data(p, space, buf))
552: return(0);
553:
554: mlg_mode(p, MD_TEXT);
555: return(1);
556: }
557:
CVSweb