Annotation of mandoc/mlg.c, Revision 1.26
1.26 ! kristaps 1: /* $Id: mlg.c,v 1.25 2008/12/10 10:43:57 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>
1.13 kristaps 22: #include <stdarg.h>
1.1 kristaps 23: #include <stdlib.h>
24: #include <stdio.h>
25: #include <string.h>
26:
27: #include "ml.h"
28:
29: /* TODO: literal tokens. */
30:
31: enum md_tok {
32: MD_TEXT,
33: MD_INLINE_IN,
34: MD_INLINE_OUT,
35: MD_BLK_IN,
36: MD_BLK_OUT,
37: };
38:
39: struct md_mlg {
40: const struct md_args *args;
41: const struct md_rbuf *rbuf;
42:
43: struct md_mbuf *mbuf;
44: struct rofftree *tree;
45: size_t indent;
46: size_t pos;
47: enum md_tok last;
48: void *arg;
1.11 kristaps 49: struct ml_cbs cbs;
1.1 kristaps 50: int flags;
51: #define ML_OVERRIDE_ONE (1 << 0)
52: #define ML_OVERRIDE_ALL (1 << 1)
1.10 kristaps 53: void *data;
1.1 kristaps 54: };
55:
1.23 kristaps 56: static int mlg_roffmsg(void *arg,
1.20 kristaps 57: enum roffmsg, const char *,
58: const char *, const char *);
1.4 kristaps 59: static int mlg_roffhead(void *, const struct tm *,
60: const char *, const char *,
1.25 kristaps 61: enum roffmsec, enum roffvol);
1.26 ! kristaps 62: static int mlg_rofftail(void *, const struct tm *,
! 63: const char *, const char *,
! 64: enum roffmsec, enum roffvol);
1.20 kristaps 65: static int mlg_roffin(void *, int,
66: int *, const char **);
1.5 kristaps 67: static int mlg_roffdata(void *, int,
1.20 kristaps 68: const char *, const char *);
1.1 kristaps 69: static int mlg_roffout(void *, int);
1.20 kristaps 70: static int mlg_roffblkin(void *, int, int *,
71: const char **);
1.1 kristaps 72: static int mlg_roffblkout(void *, int);
1.8 kristaps 73: static int mlg_roffspecial(void *, int,
1.16 kristaps 74: const char *, const int *,
1.20 kristaps 75: const char **, const char **);
1.5 kristaps 76: static int mlg_roffblkheadin(void *, int,
1.20 kristaps 77: int *, const char **);
1.2 kristaps 78: static int mlg_roffblkheadout(void *, int);
1.5 kristaps 79: static int mlg_roffblkbodyin(void *, int,
1.20 kristaps 80: int *, const char **);
1.2 kristaps 81: static int mlg_roffblkbodyout(void *, int);
82:
1.20 kristaps 83: static int mlg_ref_special(struct md_mlg *, int,
84: const char *, const char **);
85: static int mlg_formatted_special(struct md_mlg *,
1.23 kristaps 86: int, const char *, const int *,
1.20 kristaps 87: const char **, const char **);
88: static int mlg_literal_special(struct md_mlg *,
89: int, const char *, const int *,
90: const char **, const char **);
91: static int mlg_function_special(struct md_mlg *,
92: const char *, const char **);
93: static int mlg_atom_special(struct md_mlg *, int,
94: const char *, const char **);
95:
1.1 kristaps 96: static int mlg_begintag(struct md_mlg *, enum md_ns,
1.20 kristaps 97: int, int *, const char **);
1.1 kristaps 98: static int mlg_endtag(struct md_mlg *, enum md_ns, int);
99: static int mlg_indent(struct md_mlg *);
100: static int mlg_newline(struct md_mlg *);
101: static void mlg_mode(struct md_mlg *, enum md_tok);
1.19 kristaps 102: static int mlg_nstring(struct md_mlg *,
103: const char *, const char *, size_t);
104: static int mlg_string(struct md_mlg *,
105: const char *, const char *);
1.5 kristaps 106: static int mlg_data(struct md_mlg *, int,
1.20 kristaps 107: const char *, const char *);
1.23 kristaps 108: static int mlg_err(struct md_mlg *, const char *,
1.13 kristaps 109: const char *, const char *, ...);
1.23 kristaps 110: static int mlg_msg(struct md_mlg *,
1.20 kristaps 111: enum roffmsg, const char *,
112: const char *, const char *);
1.23 kristaps 113: static int mlg_vmsg(struct md_mlg *, enum roffmsg,
1.13 kristaps 114: const char *, const char *,
115: const char *, va_list);
1.1 kristaps 116:
117: #ifdef __linux__
118: extern size_t strlcat(char *, const char *, size_t);
119: extern size_t strlcpy(char *, const char *, size_t);
120: #endif
121:
122:
123: static int
124: mlg_begintag(struct md_mlg *p, enum md_ns ns, int tok,
1.20 kristaps 125: int *argc, const char **argv)
1.1 kristaps 126: {
127: ssize_t res;
128:
1.8 kristaps 129: assert(MD_NS_DEFAULT != ns);
130:
131: switch (ns) {
132: case (MD_NS_INLINE):
133: if ( ! (ML_OVERRIDE_ONE & p->flags) &&
134: ! (ML_OVERRIDE_ALL & p->flags) &&
1.9 kristaps 135: p->pos + 11 >= COLUMNS)
1.8 kristaps 136: if ( ! mlg_newline(p))
137: return(0);
138: if (0 != p->pos && (MD_TEXT == p->last ||
139: MD_INLINE_OUT == p->last)
140: && ! (ML_OVERRIDE_ONE & p->flags)
141: && ! (ML_OVERRIDE_ALL & p->flags))
142: if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
143: return(0);
144: if (0 == p->pos && ! mlg_indent(p))
145: return(0);
146: mlg_mode(p, MD_INLINE_IN);
147: break;
148: default:
149: if (0 != p->pos) {
150: if ( ! mlg_newline(p))
151: return(0);
152: if ( ! mlg_indent(p))
153: return(0);
154: } else if ( ! mlg_indent(p))
155: return(0);
156: p->indent++;
157: mlg_mode(p, MD_BLK_IN);
158: break;
159: }
1.1 kristaps 160:
161: if ( ! ml_nputs(p->mbuf, "<", 1, &p->pos))
162: return(0);
163:
1.20 kristaps 164: res = (*p->cbs.ml_begintag)(p->mbuf, p->data,
165: p->args, ns, tok, argc, argv);
1.1 kristaps 166: if (-1 == res)
167: return(0);
168:
169: assert(res >= 0);
170: p->pos += (size_t)res;
171:
1.8 kristaps 172: if ( ! ml_nputs(p->mbuf, ">", 1, &p->pos))
173: return(0);
174:
175: switch (ns) {
176: case (MD_NS_INLINE):
177: break;
178: default:
179: if ( ! mlg_newline(p))
180: return(0);
181: break;
182: }
1.1 kristaps 183:
1.8 kristaps 184: return(1);
1.1 kristaps 185: }
186:
187:
188: static int
189: mlg_endtag(struct md_mlg *p, enum md_ns ns, int tok)
190: {
191: ssize_t res;
192:
1.9 kristaps 193: assert(MD_NS_DEFAULT != ns);
194:
195: switch (ns) {
196: case (MD_NS_INLINE):
197: break;
198: default:
199: p->indent--;
200: if (0 != p->pos) {
201: if ( ! mlg_newline(p))
202: return(0);
203: if ( ! mlg_indent(p))
204: return(0);
205: } else if ( ! mlg_indent(p))
206: return(0);
207: break;
208: }
1.1 kristaps 209:
210: if ( ! ml_nputs(p->mbuf, "</", 2, &p->pos))
211: return(0);
212:
1.11 kristaps 213: res = (*p->cbs.ml_endtag)(p->mbuf, p->data, p->args, ns, tok);
1.1 kristaps 214: if (-1 == res)
215: return(0);
216:
217: assert(res >= 0);
218: p->pos += (size_t)res;
219:
1.9 kristaps 220: if ( ! ml_nputs(p->mbuf, ">", 1, &p->pos))
221: return(0);
222:
223: switch (ns) {
224: case (MD_NS_INLINE):
225: mlg_mode(p, MD_INLINE_OUT);
226: break;
227: default:
228: mlg_mode(p, MD_BLK_OUT);
229: break;
230: }
1.1 kristaps 231:
1.9 kristaps 232: return(1);
1.1 kristaps 233: }
234:
235:
236: static int
237: mlg_indent(struct md_mlg *p)
238: {
239:
240: assert(0 == p->pos);
1.24 kristaps 241: return(ml_putchars(p->mbuf, ' ', INDENT_SZ *
242: INDENT(p->indent), &p->pos));
1.1 kristaps 243: }
244:
245:
246: static int
247: mlg_newline(struct md_mlg *p)
248: {
249:
250: p->pos = 0;
1.11 kristaps 251: return(ml_nputs(p->mbuf, "\n", 1, NULL));
1.1 kristaps 252: }
253:
254:
255: static void
256: mlg_mode(struct md_mlg *p, enum md_tok ns)
257: {
1.3 kristaps 258:
1.1 kristaps 259: p->flags &= ~ML_OVERRIDE_ONE;
260: p->last = ns;
261: }
262:
263:
264: static int
1.19 kristaps 265: mlg_string(struct md_mlg *p, const char *start, const char *buf)
266: {
267:
268: return(mlg_nstring(p, start, buf, strlen(buf)));
269: }
270:
271:
272: static int
273: mlg_nstring(struct md_mlg *p, const char *start,
274: const char *buf, size_t sz)
275: {
276: int c;
277: ssize_t res;
278:
279: assert(p->mbuf);
280: assert(0 != p->indent);
281:
282: res = (*p->cbs.ml_beginstring)(p->mbuf, p->args, buf, sz);
283: if (-1 == res)
284: return(0);
285:
1.23 kristaps 286: if (0 == (c = ml_nputstring(p->mbuf, buf, sz, &p->pos)))
287: return(mlg_err(p, start, buf, "bad string "
288: "encoding: `%s'", buf));
289: else if (-1 == c)
1.19 kristaps 290: return(0);
291:
292: res = (*p->cbs.ml_endstring)(p->mbuf, p->args, buf, sz);
293: if (-1 == res)
294: return(0);
295:
296: return(1);
297: }
298:
299:
300: static int
1.20 kristaps 301: mlg_data(struct md_mlg *p, int space,
302: const char *start, const char *buf)
1.1 kristaps 303: {
304: size_t sz;
305:
306: assert(p->mbuf);
307: assert(0 != p->indent);
308:
309: if (ML_OVERRIDE_ONE & p->flags ||
310: ML_OVERRIDE_ALL & p->flags)
311: space = 0;
312:
1.8 kristaps 313: sz = strlen(buf);
1.1 kristaps 314:
1.8 kristaps 315: if (0 == p->pos) {
316: if ( ! mlg_indent(p))
317: return(0);
1.19 kristaps 318: if ( ! mlg_nstring(p, start, buf, sz))
1.8 kristaps 319: return(0);
1.1 kristaps 320:
1.24 kristaps 321: if (INDENT(p->indent) * INDENT_SZ + sz >= COLUMNS)
1.8 kristaps 322: if ( ! mlg_newline(p))
1.1 kristaps 323: return(0);
1.5 kristaps 324:
1.8 kristaps 325: return(1);
326: }
1.5 kristaps 327:
1.8 kristaps 328: if (space && sz + p->pos >= COLUMNS) {
329: if ( ! mlg_newline(p))
1.5 kristaps 330: return(0);
1.8 kristaps 331: if ( ! mlg_indent(p))
1.5 kristaps 332: return(0);
1.8 kristaps 333: } else if (space) {
334: if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
1.1 kristaps 335: return(0);
1.8 kristaps 336: }
1.1 kristaps 337:
1.19 kristaps 338: return(mlg_nstring(p, start, buf, sz));
1.1 kristaps 339: }
340:
341:
342: int
343: mlg_line(struct md_mlg *p, char *buf)
344: {
345:
346: return(roff_engine(p->tree, buf));
347: }
348:
349:
350: int
351: mlg_exit(struct md_mlg *p, int flush)
352: {
353: int c;
354:
355: c = roff_free(p->tree, flush);
1.21 kristaps 356: (*p->cbs.ml_free)(p->data);
357:
1.1 kristaps 358: free(p);
1.11 kristaps 359:
1.1 kristaps 360: return(c);
361: }
362:
363:
364: struct md_mlg *
1.11 kristaps 365: mlg_alloc(const struct md_args *args,
1.1 kristaps 366: const struct md_rbuf *rbuf,
367: struct md_mbuf *mbuf,
1.11 kristaps 368: const struct ml_cbs *cbs)
1.1 kristaps 369: {
370: struct roffcb cb;
371: struct md_mlg *p;
372:
373: cb.roffhead = mlg_roffhead;
374: cb.rofftail = mlg_rofftail;
375: cb.roffin = mlg_roffin;
376: cb.roffout = mlg_roffout;
377: cb.roffblkin = mlg_roffblkin;
1.2 kristaps 378: cb.roffblkheadin = mlg_roffblkheadin;
379: cb.roffblkheadout = mlg_roffblkheadout;
380: cb.roffblkbodyin = mlg_roffblkbodyin;
381: cb.roffblkbodyout = mlg_roffblkbodyout;
1.1 kristaps 382: cb.roffblkout = mlg_roffblkout;
383: cb.roffspecial = mlg_roffspecial;
384: cb.roffmsg = mlg_roffmsg;
385: cb.roffdata = mlg_roffdata;
386:
387: if (NULL == (p = calloc(1, sizeof(struct md_mlg))))
388: err(1, "calloc");
389:
390: p->args = args;
391: p->mbuf = mbuf;
392: p->rbuf = rbuf;
393:
1.11 kristaps 394: (void)memcpy(&p->cbs, cbs, sizeof(struct ml_cbs));
395:
396: if (NULL == (p->tree = roff_alloc(&cb, p)))
397: free(p);
398: else if ( ! (*p->cbs.ml_alloc)(&p->data))
1.1 kristaps 399: free(p);
1.11 kristaps 400: else
401: return(p);
1.1 kristaps 402:
1.11 kristaps 403: return(NULL);
1.1 kristaps 404: }
405:
406:
407: static int
1.4 kristaps 408: mlg_roffhead(void *arg, const struct tm *tm, const char *os,
1.25 kristaps 409: const char *title, enum roffmsec sec, enum roffvol vol)
1.1 kristaps 410: {
411: struct md_mlg *p;
412:
413: assert(arg);
414: p = (struct md_mlg *)arg;
415:
416: mlg_mode(p, MD_BLK_IN);
1.11 kristaps 417:
1.26 ! kristaps 418: if ( ! (*p->cbs.ml_begin)(p->mbuf, p->args,
! 419: tm, os, title, sec, vol))
1.1 kristaps 420: return(0);
421:
422: p->indent++;
423: return(mlg_newline(p));
424: }
425:
426:
427: static int
1.26 ! kristaps 428: mlg_rofftail(void *arg, const struct tm *tm, const char *os,
! 429: const char *title, enum roffmsec sec, enum roffvol vol)
1.1 kristaps 430: {
431: struct md_mlg *p;
432:
433: assert(arg);
434: p = (struct md_mlg *)arg;
435:
1.11 kristaps 436: if (0 != p->pos)
437: if ( ! mlg_newline(p))
438: return(0);
439:
1.26 ! kristaps 440: if ( ! (*p->cbs.ml_end)(p->mbuf, p->args,
! 441: tm, os, title, sec, vol))
1.1 kristaps 442: return(0);
443:
444: mlg_mode(p, MD_BLK_OUT);
445: return(mlg_newline(p));
446: }
447:
448:
1.20 kristaps 449: static int
450: mlg_literal_special(struct md_mlg *p, int tok, const char *start,
451: const int *argc, const char **argv, const char **more)
452: {
453: char *lit;
454:
455: if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
456: return(0);
457:
1.23 kristaps 458: lit = roff_literal(tok, argc, argv, more);
1.20 kristaps 459: assert(lit);
460:
1.23 kristaps 461: if ( ! mlg_string(p, start, lit))
1.20 kristaps 462: return(0);
1.23 kristaps 463:
1.20 kristaps 464: while (*more) {
465: if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
466: return(0);
467: if ( ! mlg_string(p, start, *more++))
468: return(0);
469: }
470:
471: return(mlg_endtag(p, MD_NS_INLINE, tok));
472: }
473:
474:
475: static int
476: mlg_ref_special(struct md_mlg *p, int tok,
477: const char *start, const char **more)
478: {
479:
480: if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
481: return(0);
482:
483: assert(*more);
484: if ( ! ml_puts(p->mbuf, *more++, &p->pos))
485: return(0);
486:
487: if (*more) {
488: if ( ! ml_nputs(p->mbuf, "(", 1, &p->pos))
489: return(0);
490: if ( ! mlg_string(p, start, *more++))
491: return(0);
492: if ( ! ml_nputs(p->mbuf, ")", 1, &p->pos))
493: return(0);
494: }
495:
496: assert(NULL == *more);
497: return(mlg_endtag(p, MD_NS_INLINE, tok));
498: }
499:
500:
501: static int
1.23 kristaps 502: mlg_formatted_special(struct md_mlg *p, int tok, const char *start,
1.20 kristaps 503: const int *argc, const char **argv, const char **more)
504: {
505: char buf[256], *lit;
506:
507: if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
508: return(0);
509:
1.23 kristaps 510: lit = roff_fmtstring(tok);
1.21 kristaps 511:
1.20 kristaps 512: assert(lit);
513: assert(*more);
514: (void)snprintf(buf, sizeof(buf), lit, *more++);
515: assert(NULL == *more);
516:
1.23 kristaps 517: if ( ! mlg_string(p, start, buf))
1.20 kristaps 518: return(0);
519:
520: return(mlg_endtag(p, MD_NS_INLINE, tok));
521: }
522:
523:
524: static int
525: mlg_atom_special(struct md_mlg *p, int tok,
526: const char *start, const char **more)
527: {
528:
529: if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
530: return(0);
531:
532: assert(*more);
533: if ( ! mlg_string(p, start, *more++))
534: return(0);
535:
1.22 kristaps 536: /*assert(NULL == *more);*/ /* FIXME: ROFF_Sx */
1.20 kristaps 537: return(mlg_endtag(p, MD_NS_INLINE, tok));
538: }
539:
540:
541: static int
542: mlg_function_special(struct md_mlg *p,
543: const char *start, const char **more)
544: {
545:
546: assert(*more);
547:
548: if ( ! mlg_begintag(p, MD_NS_INLINE, ROFF_Fn, NULL, more))
549: return(0);
550: if ( ! mlg_string(p, start, *more++))
551: return(0);
552: if ( ! mlg_endtag(p, MD_NS_INLINE, ROFF_Fn))
553: return(0);
554:
555: if (NULL == *more)
556: return(1);
557:
558: if ( ! ml_nputs(p->mbuf, "(", 1, &p->pos))
559: return(0);
560:
561: p->flags |= ML_OVERRIDE_ONE;
562:
563: if ( ! mlg_begintag(p, MD_NS_INLINE, ROFF_Fa, NULL, more))
564: return(0);
565: if ( ! mlg_string(p, start, *more++))
566: return(0);
567: if ( ! mlg_endtag(p, MD_NS_INLINE, ROFF_Fa))
568: return(0);
569:
570: while (*more) {
571: if ( ! ml_nputs(p->mbuf, ", ", 2, &p->pos))
572: return(0);
573: if ( ! mlg_begintag(p, MD_NS_INLINE, ROFF_Fa, NULL, more))
574: return(0);
575: if ( ! mlg_string(p, start, *more++))
576: return(0);
577: if ( ! mlg_endtag(p, MD_NS_INLINE, ROFF_Fa))
578: return(0);
579: }
580:
581: return(ml_nputs(p->mbuf, ")", 1, &p->pos));
582: }
583:
584:
1.16 kristaps 585: /* ARGSUSED */
1.1 kristaps 586: static int
1.16 kristaps 587: mlg_roffspecial(void *arg, int tok, const char *start,
1.20 kristaps 588: const int *argc, const char **argv, const char **more)
1.1 kristaps 589: {
590: struct md_mlg *p;
591:
592: assert(arg);
593: p = (struct md_mlg *)arg;
594:
595: switch (tok) {
1.15 kristaps 596: case (ROFF_Ns):
597: p->flags |= ML_OVERRIDE_ONE;
598: return(1);
1.20 kristaps 599:
1.15 kristaps 600: case (ROFF_Sm):
601: assert(*more);
602: if (0 == strcmp(*more, "on"))
603: p->flags |= ML_OVERRIDE_ALL;
604: else
605: p->flags &= ~ML_OVERRIDE_ALL;
606: return(1);
1.18 kristaps 607:
608: case (ROFF_Fn):
1.20 kristaps 609: return(mlg_function_special(p, start, more));
1.16 kristaps 610:
1.8 kristaps 611: case (ROFF_Xr):
1.20 kristaps 612: return(mlg_ref_special(p, tok, start, more));
613:
614: case (ROFF_Sx): /* FIXME */
1.15 kristaps 615: /* FALLTHROUGH */
1.12 kristaps 616: case (ROFF_Nm):
1.20 kristaps 617: return(mlg_atom_special(p, tok, start, more));
1.18 kristaps 618:
619: case (ROFF_In):
620: /* NOTREACHED */
1.13 kristaps 621: case (ROFF_Ex):
1.17 kristaps 622: /* NOTREACHED */
623: case (ROFF_Rv):
1.23 kristaps 624: return(mlg_formatted_special(p, tok, start,
1.20 kristaps 625: argc, argv, more));
1.19 kristaps 626:
1.15 kristaps 627: case (ROFF_At):
1.20 kristaps 628: /* FALLTHROUGH */
629: case (ROFF_Bt):
630: /* FALLTHROUGH */
631: case (ROFF_Ud):
632: /* FALLTHROUGH */
633: case (ROFF_Ux):
634: /* FALLTHROUGH */
1.15 kristaps 635: case (ROFF_Bx):
636: /* FALLTHROUGH */
637: case (ROFF_Bsx):
638: /* FALLTHROUGH */
639: case (ROFF_Fx):
640: /* FALLTHROUGH */
641: case (ROFF_Nx):
642: /* FALLTHROUGH */
1.20 kristaps 643: case (ROFF_St):
644: /* FALLTHROUGH */
1.15 kristaps 645: case (ROFF_Ox):
1.20 kristaps 646: return(mlg_literal_special(p, tok, start,
647: argc, argv, more));
648: default:
1.15 kristaps 649: break;
1.1 kristaps 650: }
651:
1.23 kristaps 652: return(mlg_err(p, start, start, "`%s' not yet supported",
653: toknames[tok]));
1.1 kristaps 654: }
655:
656:
657: static int
1.20 kristaps 658: mlg_roffblkin(void *arg, int tok,
659: int *argc, const char **argv)
1.1 kristaps 660: {
661:
1.8 kristaps 662: return(mlg_begintag((struct md_mlg *)arg,
1.2 kristaps 663: MD_NS_BLOCK, tok, argc, argv));
664: }
665:
666:
667: static int
668: mlg_roffblkout(void *arg, int tok)
669: {
670:
1.9 kristaps 671: return(mlg_endtag((struct md_mlg *)arg, MD_NS_BLOCK, tok));
1.2 kristaps 672: }
673:
674:
675: static int
1.20 kristaps 676: mlg_roffblkbodyin(void *arg, int tok,
677: int *argc, const char **argv)
1.2 kristaps 678: {
679:
1.8 kristaps 680: return(mlg_begintag((struct md_mlg *)arg,
1.2 kristaps 681: MD_NS_BODY, tok, argc, argv));
682: }
1.1 kristaps 683:
684:
1.2 kristaps 685: static int
686: mlg_roffblkbodyout(void *arg, int tok)
687: {
1.1 kristaps 688:
1.9 kristaps 689: return(mlg_endtag((struct md_mlg *)arg, MD_NS_BODY, tok));
1.1 kristaps 690: }
691:
692:
693: static int
1.20 kristaps 694: mlg_roffblkheadin(void *arg, int tok,
695: int *argc, const char **argv)
1.1 kristaps 696: {
697:
1.8 kristaps 698: return(mlg_begintag((struct md_mlg *)arg,
1.2 kristaps 699: MD_NS_HEAD, tok, argc, argv));
700: }
1.1 kristaps 701:
702:
1.2 kristaps 703: static int
704: mlg_roffblkheadout(void *arg, int tok)
705: {
1.1 kristaps 706:
1.9 kristaps 707: return(mlg_endtag((struct md_mlg *)arg, MD_NS_HEAD, tok));
1.1 kristaps 708: }
709:
710:
711: static int
1.20 kristaps 712: mlg_roffin(void *arg, int tok, int *argc, const char **argv)
1.1 kristaps 713: {
714:
1.8 kristaps 715: return(mlg_begintag((struct md_mlg *)arg,
716: MD_NS_INLINE, tok, argc, argv));
1.1 kristaps 717: }
718:
719:
720: static int
721: mlg_roffout(void *arg, int tok)
722: {
723:
1.9 kristaps 724: return(mlg_endtag((struct md_mlg *)arg, MD_NS_INLINE, tok));
1.1 kristaps 725: }
726:
727:
1.23 kristaps 728: static int
1.20 kristaps 729: mlg_roffmsg(void *arg, enum roffmsg lvl, const char *buf,
730: const char *pos, const char *msg)
1.1 kristaps 731: {
1.5 kristaps 732:
1.23 kristaps 733: return(mlg_msg((struct md_mlg *)arg, lvl, buf, pos, msg));
1.5 kristaps 734: }
735:
736:
737: static int
1.20 kristaps 738: mlg_roffdata(void *arg, int space,
739: const char *start, const char *buf)
1.5 kristaps 740: {
1.1 kristaps 741: struct md_mlg *p;
742:
743: assert(arg);
744: p = (struct md_mlg *)arg;
745:
1.5 kristaps 746: if ( ! mlg_data(p, space, start, buf))
747: return(0);
748:
749: mlg_mode(p, MD_TEXT);
750: return(1);
751: }
752:
753:
1.23 kristaps 754: static int
1.13 kristaps 755: mlg_vmsg(struct md_mlg *p, enum roffmsg lvl, const char *start,
756: const char *pos, const char *fmt, va_list ap)
1.5 kristaps 757: {
1.13 kristaps 758: char buf[128];
1.5 kristaps 759:
1.13 kristaps 760: (void)vsnprintf(buf, sizeof(buf), fmt, ap);
1.23 kristaps 761: return(mlg_msg(p, lvl, start, pos, buf));
1.5 kristaps 762: }
763:
764:
1.23 kristaps 765: static int
1.13 kristaps 766: mlg_err(struct md_mlg *p, const char *start,
767: const char *pos, const char *fmt, ...)
768: {
769: va_list ap;
1.23 kristaps 770: int c;
1.13 kristaps 771:
772: va_start(ap, fmt);
1.23 kristaps 773: c = mlg_vmsg(p, ROFF_ERROR, start, pos, fmt, ap);
1.13 kristaps 774: va_end(ap);
1.23 kristaps 775: return(c);
1.5 kristaps 776: }
777:
778:
1.23 kristaps 779: static int
1.5 kristaps 780: mlg_msg(struct md_mlg *p, enum roffmsg lvl,
1.20 kristaps 781: const char *buf, const char *pos, const char *msg)
1.5 kristaps 782: {
783: char *level;
1.22 kristaps 784: char b[256];
785: int i;
1.5 kristaps 786:
1.1 kristaps 787: switch (lvl) {
788: case (ROFF_WARN):
1.23 kristaps 789: level = "warning";
1.1 kristaps 790: if ( ! (MD_WARN_ALL & p->args->warnings))
1.23 kristaps 791: return(1);
1.1 kristaps 792: break;
793: case (ROFF_ERROR):
794: level = "error";
795: break;
796: default:
797: abort();
1.23 kristaps 798: /* NOTREACHED */
1.1 kristaps 799: }
1.22 kristaps 800:
801: if (pos) {
802: assert(pos >= buf);
803: if (0 < p->args->verbosity) {
804: (void)snprintf(b, sizeof(b),
805: "%s:%zu: %s: %s\n",
806: p->rbuf->name, p->rbuf->line,
807: level, msg);
808: (void)strlcat(b, "Error at: ", sizeof(b));
809: (void)strlcat(b, p->rbuf->linebuf, sizeof(b));
810:
811: (void)strlcat(b, "\n ", sizeof(b));
812: for (i = 0; i < pos - buf; i++)
813: (void)strlcat(b, " ", sizeof(b));
814: (void)strlcat(b, "^", sizeof(b));
815:
816: } else
817: (void)snprintf(b, sizeof(b),
818: "%s:%zu: %s: %s (col %zu)",
819: p->rbuf->name, p->rbuf->line,
820: level, msg, pos - buf);
821: } else
822: (void)snprintf(b, sizeof(b), "%s: %s: %s",
1.1 kristaps 823: p->rbuf->name, level, msg);
1.22 kristaps 824:
825: (void)fprintf(stderr, "%s\n", b);
1.23 kristaps 826: return(lvl == ROFF_WARN ? 1 : 0);
1.1 kristaps 827: }
1.22 kristaps 828:
CVSweb