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