Annotation of mandoc/mlg.c, Revision 1.3
1.3 ! kristaps 1: /* $Id: mlg.c,v 1.2 2008/12/03 19:21:58 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:
1.3 ! kristaps 192: count = p->indent > MAXINDENT ? (size_t)MAXINDENT : p->indent;
1.1 kristaps 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: {
1.3 ! kristaps 215:
1.1 kristaps 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);
1.3 ! kristaps 256: if (p->indent * INDENT + sz >= COLUMNS)
1.1 kristaps 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,
1.2 kristaps 308: ml_begintag begintag, ml_endtag endtag,
309: ml_begin begin, ml_end end)
1.1 kristaps 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;
1.2 kristaps 319: cb.roffblkheadin = mlg_roffblkheadin;
320: cb.roffblkheadout = mlg_roffblkheadout;
321: cb.roffblkbodyin = mlg_roffblkbodyin;
322: cb.roffblkbodyout = mlg_roffblkbodyout;
1.1 kristaps 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;
1.2 kristaps 336: p->begin = begin;
337: p->end = end;
1.1 kristaps 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);
1.2 kristaps 357: if ( ! (*p->begin)(p->mbuf, p->args))
1.1 kristaps 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);
1.2 kristaps 377: if ( ! (*p->end)(p->mbuf, p->args))
1.1 kristaps 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:
1.2 kristaps 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: }
1.1 kristaps 436:
437:
1.2 kristaps 438: static int
439: mlg_roffblkbodyout(void *arg, int tok)
440: {
1.1 kristaps 441:
1.2 kristaps 442: return(mlg_endblk((struct md_mlg *)arg, MD_NS_BODY, tok));
1.1 kristaps 443: }
444:
445:
446: static int
1.2 kristaps 447: mlg_roffblkheadin(void *arg, int tok, int *argc, char **argv)
1.1 kristaps 448: {
449:
1.2 kristaps 450: return(mlg_beginblk((struct md_mlg *)arg,
451: MD_NS_HEAD, tok, argc, argv));
452: }
1.1 kristaps 453:
454:
1.2 kristaps 455: static int
456: mlg_roffblkheadout(void *arg, int tok)
457: {
1.1 kristaps 458:
1.2 kristaps 459: return(mlg_endblk((struct md_mlg *)arg, MD_NS_HEAD, tok));
1.1 kristaps 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:
CVSweb