Annotation of mandoc/mlg.c, Revision 1.27
1.27 ! kristaps 1: /* $Id: mlg.c,v 1.26 2008/12/10 12:05:33 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,
1.27 ! kristaps 36: MD_BLK_OUT
1.1 kristaps 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:
1.27 ! kristaps 501: /* ARGSUSED */
1.20 kristaps 502: static int
1.23 kristaps 503: mlg_formatted_special(struct md_mlg *p, int tok, const char *start,
1.20 kristaps 504: const int *argc, const char **argv, const char **more)
505: {
506: char buf[256], *lit;
507:
508: if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
509: return(0);
510:
1.23 kristaps 511: lit = roff_fmtstring(tok);
1.21 kristaps 512:
1.20 kristaps 513: assert(lit);
514: assert(*more);
515: (void)snprintf(buf, sizeof(buf), lit, *more++);
516: assert(NULL == *more);
517:
1.23 kristaps 518: if ( ! mlg_string(p, start, buf))
1.20 kristaps 519: return(0);
520:
521: return(mlg_endtag(p, MD_NS_INLINE, tok));
522: }
523:
524:
525: static int
526: mlg_atom_special(struct md_mlg *p, int tok,
527: const char *start, const char **more)
528: {
529:
530: if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
531: return(0);
532:
533: assert(*more);
534: if ( ! mlg_string(p, start, *more++))
535: return(0);
536:
1.22 kristaps 537: /*assert(NULL == *more);*/ /* FIXME: ROFF_Sx */
1.20 kristaps 538: return(mlg_endtag(p, MD_NS_INLINE, tok));
539: }
540:
541:
542: static int
543: mlg_function_special(struct md_mlg *p,
544: const char *start, const char **more)
545: {
546:
547: assert(*more);
548:
549: if ( ! mlg_begintag(p, MD_NS_INLINE, ROFF_Fn, NULL, more))
550: return(0);
551: if ( ! mlg_string(p, start, *more++))
552: return(0);
553: if ( ! mlg_endtag(p, MD_NS_INLINE, ROFF_Fn))
554: return(0);
555:
556: if (NULL == *more)
557: return(1);
558:
559: if ( ! ml_nputs(p->mbuf, "(", 1, &p->pos))
560: return(0);
561:
562: p->flags |= ML_OVERRIDE_ONE;
563:
564: if ( ! mlg_begintag(p, MD_NS_INLINE, ROFF_Fa, NULL, more))
565: return(0);
566: if ( ! mlg_string(p, start, *more++))
567: return(0);
568: if ( ! mlg_endtag(p, MD_NS_INLINE, ROFF_Fa))
569: return(0);
570:
571: while (*more) {
572: if ( ! ml_nputs(p->mbuf, ", ", 2, &p->pos))
573: return(0);
574: if ( ! mlg_begintag(p, MD_NS_INLINE, ROFF_Fa, NULL, more))
575: return(0);
576: if ( ! mlg_string(p, start, *more++))
577: return(0);
578: if ( ! mlg_endtag(p, MD_NS_INLINE, ROFF_Fa))
579: return(0);
580: }
581:
582: return(ml_nputs(p->mbuf, ")", 1, &p->pos));
583: }
584:
585:
1.16 kristaps 586: /* ARGSUSED */
1.1 kristaps 587: static int
1.16 kristaps 588: mlg_roffspecial(void *arg, int tok, const char *start,
1.20 kristaps 589: const int *argc, const char **argv, const char **more)
1.1 kristaps 590: {
591: struct md_mlg *p;
592:
593: assert(arg);
594: p = (struct md_mlg *)arg;
595:
596: switch (tok) {
1.15 kristaps 597: case (ROFF_Ns):
598: p->flags |= ML_OVERRIDE_ONE;
599: return(1);
1.20 kristaps 600:
1.15 kristaps 601: case (ROFF_Sm):
602: assert(*more);
603: if (0 == strcmp(*more, "on"))
604: p->flags |= ML_OVERRIDE_ALL;
605: else
606: p->flags &= ~ML_OVERRIDE_ALL;
607: return(1);
1.18 kristaps 608:
609: case (ROFF_Fn):
1.20 kristaps 610: return(mlg_function_special(p, start, more));
1.16 kristaps 611:
1.8 kristaps 612: case (ROFF_Xr):
1.20 kristaps 613: return(mlg_ref_special(p, tok, start, more));
614:
615: case (ROFF_Sx): /* FIXME */
1.15 kristaps 616: /* FALLTHROUGH */
1.12 kristaps 617: case (ROFF_Nm):
1.20 kristaps 618: return(mlg_atom_special(p, tok, start, more));
1.18 kristaps 619:
620: case (ROFF_In):
621: /* NOTREACHED */
1.13 kristaps 622: case (ROFF_Ex):
1.17 kristaps 623: /* NOTREACHED */
624: case (ROFF_Rv):
1.23 kristaps 625: return(mlg_formatted_special(p, tok, start,
1.20 kristaps 626: argc, argv, more));
1.19 kristaps 627:
1.15 kristaps 628: case (ROFF_At):
1.20 kristaps 629: /* FALLTHROUGH */
630: case (ROFF_Bt):
631: /* FALLTHROUGH */
632: case (ROFF_Ud):
633: /* FALLTHROUGH */
634: case (ROFF_Ux):
635: /* FALLTHROUGH */
1.15 kristaps 636: case (ROFF_Bx):
637: /* FALLTHROUGH */
638: case (ROFF_Bsx):
639: /* FALLTHROUGH */
640: case (ROFF_Fx):
641: /* FALLTHROUGH */
642: case (ROFF_Nx):
643: /* FALLTHROUGH */
1.20 kristaps 644: case (ROFF_St):
645: /* FALLTHROUGH */
1.15 kristaps 646: case (ROFF_Ox):
1.20 kristaps 647: return(mlg_literal_special(p, tok, start,
648: argc, argv, more));
649: default:
1.15 kristaps 650: break;
1.1 kristaps 651: }
652:
1.23 kristaps 653: return(mlg_err(p, start, start, "`%s' not yet supported",
654: toknames[tok]));
1.1 kristaps 655: }
656:
657:
658: static int
1.20 kristaps 659: mlg_roffblkin(void *arg, int tok,
660: int *argc, const char **argv)
1.1 kristaps 661: {
662:
1.8 kristaps 663: return(mlg_begintag((struct md_mlg *)arg,
1.2 kristaps 664: MD_NS_BLOCK, tok, argc, argv));
665: }
666:
667:
668: static int
669: mlg_roffblkout(void *arg, int tok)
670: {
671:
1.9 kristaps 672: return(mlg_endtag((struct md_mlg *)arg, MD_NS_BLOCK, tok));
1.2 kristaps 673: }
674:
675:
676: static int
1.20 kristaps 677: mlg_roffblkbodyin(void *arg, int tok,
678: int *argc, const char **argv)
1.2 kristaps 679: {
680:
1.8 kristaps 681: return(mlg_begintag((struct md_mlg *)arg,
1.2 kristaps 682: MD_NS_BODY, tok, argc, argv));
683: }
1.1 kristaps 684:
685:
1.2 kristaps 686: static int
687: mlg_roffblkbodyout(void *arg, int tok)
688: {
1.1 kristaps 689:
1.9 kristaps 690: return(mlg_endtag((struct md_mlg *)arg, MD_NS_BODY, tok));
1.1 kristaps 691: }
692:
693:
694: static int
1.20 kristaps 695: mlg_roffblkheadin(void *arg, int tok,
696: int *argc, const char **argv)
1.1 kristaps 697: {
698:
1.8 kristaps 699: return(mlg_begintag((struct md_mlg *)arg,
1.2 kristaps 700: MD_NS_HEAD, tok, argc, argv));
701: }
1.1 kristaps 702:
703:
1.2 kristaps 704: static int
705: mlg_roffblkheadout(void *arg, int tok)
706: {
1.1 kristaps 707:
1.9 kristaps 708: return(mlg_endtag((struct md_mlg *)arg, MD_NS_HEAD, tok));
1.1 kristaps 709: }
710:
711:
712: static int
1.20 kristaps 713: mlg_roffin(void *arg, int tok, int *argc, const char **argv)
1.1 kristaps 714: {
715:
1.8 kristaps 716: return(mlg_begintag((struct md_mlg *)arg,
717: MD_NS_INLINE, tok, argc, argv));
1.1 kristaps 718: }
719:
720:
721: static int
722: mlg_roffout(void *arg, int tok)
723: {
724:
1.9 kristaps 725: return(mlg_endtag((struct md_mlg *)arg, MD_NS_INLINE, tok));
1.1 kristaps 726: }
727:
728:
1.23 kristaps 729: static int
1.20 kristaps 730: mlg_roffmsg(void *arg, enum roffmsg lvl, const char *buf,
731: const char *pos, const char *msg)
1.1 kristaps 732: {
1.5 kristaps 733:
1.23 kristaps 734: return(mlg_msg((struct md_mlg *)arg, lvl, buf, pos, msg));
1.5 kristaps 735: }
736:
737:
738: static int
1.20 kristaps 739: mlg_roffdata(void *arg, int space,
740: const char *start, const char *buf)
1.5 kristaps 741: {
1.1 kristaps 742: struct md_mlg *p;
743:
744: assert(arg);
745: p = (struct md_mlg *)arg;
746:
1.5 kristaps 747: if ( ! mlg_data(p, space, start, buf))
748: return(0);
749:
750: mlg_mode(p, MD_TEXT);
751: return(1);
752: }
753:
754:
1.23 kristaps 755: static int
1.13 kristaps 756: mlg_vmsg(struct md_mlg *p, enum roffmsg lvl, const char *start,
757: const char *pos, const char *fmt, va_list ap)
1.5 kristaps 758: {
1.13 kristaps 759: char buf[128];
1.5 kristaps 760:
1.13 kristaps 761: (void)vsnprintf(buf, sizeof(buf), fmt, ap);
1.23 kristaps 762: return(mlg_msg(p, lvl, start, pos, buf));
1.5 kristaps 763: }
764:
765:
1.23 kristaps 766: static int
1.13 kristaps 767: mlg_err(struct md_mlg *p, const char *start,
768: const char *pos, const char *fmt, ...)
769: {
770: va_list ap;
1.23 kristaps 771: int c;
1.13 kristaps 772:
773: va_start(ap, fmt);
1.23 kristaps 774: c = mlg_vmsg(p, ROFF_ERROR, start, pos, fmt, ap);
1.13 kristaps 775: va_end(ap);
1.23 kristaps 776: return(c);
1.5 kristaps 777: }
778:
779:
1.23 kristaps 780: static int
1.5 kristaps 781: mlg_msg(struct md_mlg *p, enum roffmsg lvl,
1.20 kristaps 782: const char *buf, const char *pos, const char *msg)
1.5 kristaps 783: {
784: char *level;
1.22 kristaps 785: char b[256];
786: int i;
1.5 kristaps 787:
1.1 kristaps 788: switch (lvl) {
789: case (ROFF_WARN):
1.23 kristaps 790: level = "warning";
1.1 kristaps 791: if ( ! (MD_WARN_ALL & p->args->warnings))
1.23 kristaps 792: return(1);
1.1 kristaps 793: break;
794: case (ROFF_ERROR):
795: level = "error";
796: break;
797: default:
798: abort();
1.23 kristaps 799: /* NOTREACHED */
1.1 kristaps 800: }
1.22 kristaps 801:
802: if (pos) {
803: assert(pos >= buf);
804: if (0 < p->args->verbosity) {
805: (void)snprintf(b, sizeof(b),
806: "%s:%zu: %s: %s\n",
807: p->rbuf->name, p->rbuf->line,
808: level, msg);
809: (void)strlcat(b, "Error at: ", sizeof(b));
810: (void)strlcat(b, p->rbuf->linebuf, sizeof(b));
811:
812: (void)strlcat(b, "\n ", sizeof(b));
813: for (i = 0; i < pos - buf; i++)
814: (void)strlcat(b, " ", sizeof(b));
815: (void)strlcat(b, "^", sizeof(b));
816:
817: } else
818: (void)snprintf(b, sizeof(b),
819: "%s:%zu: %s: %s (col %zu)",
820: p->rbuf->name, p->rbuf->line,
821: level, msg, pos - buf);
822: } else
823: (void)snprintf(b, sizeof(b), "%s: %s: %s",
1.1 kristaps 824: p->rbuf->name, level, msg);
1.22 kristaps 825:
826: (void)fprintf(stderr, "%s\n", b);
1.23 kristaps 827: return(lvl == ROFF_WARN ? 1 : 0);
1.1 kristaps 828: }
1.22 kristaps 829:
CVSweb