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