]> git.cameronkatri.com Git - mandoc.git/blob - mlg.c
*** empty log message ***
[mandoc.git] / mlg.c
1 /* $Id: mlg.c,v 1.17 2008/12/07 14:38: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
63 static char *mlg_literal(int);
64 static char *mlg_At_literal(const char *);
65 static char *mlg_fmt(int);
66 static char *mlg_St_literal(int);
67 static void mlg_roffmsg(void *arg, enum roffmsg,
68 const char *, const char *, char *);
69 static int mlg_roffhead(void *, const struct tm *,
70 const char *, const char *,
71 const char *, const char *);
72 static int mlg_rofftail(void *);
73 static int mlg_roffin(void *, int, int *, char **);
74 static int mlg_roffdata(void *, int,
75 const char *, char *);
76 static int mlg_roffout(void *, int);
77 static int mlg_roffblkin(void *, int, int *, char **);
78 static int mlg_roffblkout(void *, int);
79 static int mlg_roffspecial(void *, int,
80 const char *, const int *,
81 const char **, char **);
82 static int mlg_roffblkheadin(void *, int,
83 int *, char **);
84 static int mlg_roffblkheadout(void *, int);
85 static int mlg_roffblkbodyin(void *, int,
86 int *, char **);
87 static int mlg_roffblkbodyout(void *, int);
88
89 static int mlg_begintag(struct md_mlg *, enum md_ns,
90 int, int *, char **);
91 static int mlg_endtag(struct md_mlg *, enum md_ns, int);
92 static int mlg_indent(struct md_mlg *);
93 static int mlg_newline(struct md_mlg *);
94 static void mlg_mode(struct md_mlg *, enum md_tok);
95 static int mlg_data(struct md_mlg *, int,
96 const char *, char *);
97 static void mlg_err(struct md_mlg *, const char *,
98 const char *, const char *, ...);
99 static void mlg_warn(struct md_mlg *, const char *,
100 const char *, const char *, ...);
101 static void mlg_msg(struct md_mlg *, enum roffmsg,
102 const char *, const char *, char *);
103 static void mlg_vmsg(struct md_mlg *, enum roffmsg,
104 const char *, const char *,
105 const char *, va_list);
106
107 #ifdef __linux__
108 extern size_t strlcat(char *, const char *, size_t);
109 extern size_t strlcpy(char *, const char *, size_t);
110 #endif
111
112
113 static char *
114 mlg_St_literal(int argc)
115 {
116
117 switch (argc) {
118 case(ROFF_p1003_1_88):
119 return("IEEE Std 1003.1-1988 (&#8220;POSIX&#8221;)");
120 case(ROFF_p1003_1_90):
121 return("IEEE Std 1003.1-1990 (&#8220;POSIX&#8221;)");
122 case(ROFF_p1003_1_96):
123 return("ISO/IEC 9945-1:1996 (&#8220;POSIX&#8221;)");
124 case(ROFF_p1003_1_2001):
125 return("IEEE Std 1003.1-2001 (&#8220;POSIX&#8221;)");
126 case(ROFF_p1003_1_2004):
127 return("IEEE Std 1003.1-2004 (&#8220;POSIX&#8221;)");
128 case(ROFF_p1003_1):
129 return("IEEE Std 1003.1 (&#8220;POSIX&#8221;)");
130 case(ROFF_p1003_1b):
131 return("IEEE Std 1003.1b (&#8220;POSIX&#8221;)");
132 case(ROFF_p1003_1b_93):
133 return("IEEE Std 1003.1b-1993 (&#8220;POSIX&#8221;)");
134 case(ROFF_p1003_1c_95):
135 return("IEEE Std 1003.1c-1995 (&#8220;POSIX&#8221;)");
136 case(ROFF_p1003_1g_2000):
137 return("IEEE Std 1003.1g-2000 (&#8220;POSIX&#8221;)");
138 case(ROFF_p1003_2_92):
139 return("IEEE Std 1003.2-1992 (&#8220;POSIX.2&#8221;)");
140 case(ROFF_p1387_2_95):
141 return("IEEE Std 1387.2-1995 (&#8220;POSIX.7.2&#8221;)");
142 case(ROFF_p1003_2):
143 return("IEEE Std 1003.2 (&#8220;POSIX.2&#8221;)");
144 case(ROFF_p1387_2):
145 return("IEEE Std 1387.2 (&#8220;POSIX.7.2&#8221;)");
146 case(ROFF_isoC_90):
147 return("ISO/IEC 9899:1990 (&#8220;ISO C90&#8221;)");
148 case(ROFF_isoC_amd1):
149 return("ISO/IEC 9899/AMD1:1995 (&#8220;ISO C90&#8221;)");
150 case(ROFF_isoC_tcor1):
151 return("ISO/IEC 9899/TCOR1:1994 (&#8220;ISO C90&#8221;)");
152 case(ROFF_isoC_tcor2):
153 return("ISO/IEC 9899/TCOR2:1995 (&#8220;ISO C90&#8221;)");
154 case(ROFF_isoC_99):
155 return("ISO/IEC 9899:1999 (&#8220;ISO C99&#8221;)");
156 case(ROFF_ansiC):
157 return("ANSI X3.159-1989 (&#8220;ANSI C&#8221;)");
158 case(ROFF_ansiC_89):
159 return("ANSI X3.159-1989 (&#8220;ANSI C&#8221;)");
160 case(ROFF_ansiC_99):
161 return("ANSI/ISO/IEC 9899-1999 (&#8220;ANSI C99&#8221;)");
162 case(ROFF_ieee754):
163 return("IEEE Std 754-1985");
164 case(ROFF_iso8802_3):
165 return("ISO 8802-3: 1989");
166 case(ROFF_xpg3):
167 return("X/Open Portability Guide Issue 3 (&#8220;XPG3&#8221;)");
168 case(ROFF_xpg4):
169 return("X/Open Portability Guide Issue 4 (&#8220;XPG4&#8221;)");
170 case(ROFF_xpg4_2):
171 return("X/Open Portability Guide Issue 4.2 (&#8220;XPG4.2&#8221;)");
172 case(ROFF_xpg4_3):
173 return("X/Open Portability Guide Issue 4.3 (&#8220;XPG4.3&#8221;)");
174 case(ROFF_xbd5):
175 return("X/Open System Interface Definitions Issue 5 (&#8220;XBD5&#8221;)");
176 case(ROFF_xcu5):
177 return("X/Open Commands and Utilities Issue 5 (&#8220;XCU5&#8221;)");
178 case(ROFF_xsh5):
179 return("X/Open System Interfaces and Headers Issue 5 (&#8220;XSH5&#8221;)");
180 case(ROFF_xns5):
181 return("X/Open Networking Services Issue 5 (&#8220;XNS5&#8221;)");
182 case(ROFF_xns5_2d2_0):
183 return("X/Open Networking Services Issue 5.2 Draft 2.0 (&#8220;XNS5.2D2.0&#8221;)");
184 case(ROFF_xcurses4_2):
185 return("X/Open Curses Issue 4 Version 2 (&#8220;XCURSES4.2&#8221;)");
186 case(ROFF_susv2):
187 return("Version 2 of the Single UNIX Specification");
188 case(ROFF_susv3):
189 return("Version 3 of the Single UNIX Specification");
190 case(ROFF_svid4):
191 return("System V Interface Definition, Fourth Edition (&#8220;SVID4&#8221;)");
192 default:
193 break;
194 }
195
196 abort();
197 /* NOTREACHED */
198 }
199
200
201 static char *
202 mlg_At_literal(const char *p)
203 {
204
205 if (NULL == p)
206 return("AT&amp;T UNIX");
207 if (0 == strcmp(p, "v6"))
208 return("Version 6 AT&amp;T UNIX");
209 else if (0 == strcmp(p, "v7"))
210 return("Version 7 AT&amp;T UNIX");
211 else if (0 == strcmp(p, "32v"))
212 return("Version 32v AT&amp;T UNIX");
213 else if (0 == strcmp(p, "V.1"))
214 return("AT&amp;T System V.1 UNIX");
215 else if (0 == strcmp(p, "V.4"))
216 return("AT&amp;T System V.4 UNIX");
217
218 abort();
219 /* NOTREACHED */
220 }
221
222
223 static char *
224 mlg_fmt(int tok)
225 {
226
227 switch (tok) {
228 case (ROFF_Ex):
229 return ("The %s utility exits 0 on success, and "
230 "&gt;0 if an error occurs.");
231 case (ROFF_Rv):
232 return ("The %s() function returns the value 0 if "
233 "successful; otherwise the value -1 "
234 "is returned and the global variable "
235 "<span class=\"inline-Va\">errno</span> "
236 "is set to indicate the error.");
237 default:
238 break;
239 }
240
241 abort();
242 /* NOTREACHED */
243 }
244
245
246 static char *
247 mlg_literal(int tok)
248 {
249
250 switch (tok) {
251 case (ROFF_Bt):
252 return("is currently in beta test.");
253 case (ROFF_Ud):
254 return("currently under development.");
255 case (ROFF_Fx):
256 return("FreeBSD");
257 case (ROFF_Nx):
258 return("NetBSD");
259 case (ROFF_Ox):
260 return("OpenBSD");
261 case (ROFF_Ux):
262 return("UNIX");
263 case (ROFF_Bx):
264 return("BSD");
265 case (ROFF_Bsx):
266 return("BSDI BSD/OS");
267 default:
268 break;
269 }
270 abort();
271 /* NOTREACHED */
272 }
273
274
275 static int
276 mlg_begintag(struct md_mlg *p, enum md_ns ns, int tok,
277 int *argc, char **argv)
278 {
279 ssize_t res;
280
281 assert(MD_NS_DEFAULT != ns);
282
283 switch (ns) {
284 case (MD_NS_INLINE):
285 if ( ! (ML_OVERRIDE_ONE & p->flags) &&
286 ! (ML_OVERRIDE_ALL & p->flags) &&
287 p->pos + 11 >= COLUMNS)
288 if ( ! mlg_newline(p))
289 return(0);
290 if (0 != p->pos && (MD_TEXT == p->last ||
291 MD_INLINE_OUT == p->last)
292 && ! (ML_OVERRIDE_ONE & p->flags)
293 && ! (ML_OVERRIDE_ALL & p->flags))
294 if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
295 return(0);
296 if (0 == p->pos && ! mlg_indent(p))
297 return(0);
298 mlg_mode(p, MD_INLINE_IN);
299 break;
300 default:
301 if (0 != p->pos) {
302 if ( ! mlg_newline(p))
303 return(0);
304 if ( ! mlg_indent(p))
305 return(0);
306 } else if ( ! mlg_indent(p))
307 return(0);
308 p->indent++;
309 mlg_mode(p, MD_BLK_IN);
310 break;
311 }
312
313 if ( ! ml_nputs(p->mbuf, "<", 1, &p->pos))
314 return(0);
315
316 res = (*p->cbs.ml_begintag)(p->mbuf, p->data, p->args, ns, tok,
317 argc, (const char **)argv);
318 if (-1 == res)
319 return(0);
320
321 assert(res >= 0);
322 p->pos += (size_t)res;
323
324 if ( ! ml_nputs(p->mbuf, ">", 1, &p->pos))
325 return(0);
326
327 switch (ns) {
328 case (MD_NS_INLINE):
329 break;
330 default:
331 if ( ! mlg_newline(p))
332 return(0);
333 break;
334 }
335
336 return(1);
337 }
338
339
340 static int
341 mlg_endtag(struct md_mlg *p, enum md_ns ns, int tok)
342 {
343 ssize_t res;
344
345 assert(MD_NS_DEFAULT != ns);
346
347 switch (ns) {
348 case (MD_NS_INLINE):
349 break;
350 default:
351 p->indent--;
352 if (0 != p->pos) {
353 if ( ! mlg_newline(p))
354 return(0);
355 if ( ! mlg_indent(p))
356 return(0);
357 } else if ( ! mlg_indent(p))
358 return(0);
359 break;
360 }
361
362 if ( ! ml_nputs(p->mbuf, "</", 2, &p->pos))
363 return(0);
364
365 res = (*p->cbs.ml_endtag)(p->mbuf, p->data, p->args, ns, tok);
366 if (-1 == res)
367 return(0);
368
369 assert(res >= 0);
370 p->pos += (size_t)res;
371
372 if ( ! ml_nputs(p->mbuf, ">", 1, &p->pos))
373 return(0);
374
375 switch (ns) {
376 case (MD_NS_INLINE):
377 mlg_mode(p, MD_INLINE_OUT);
378 break;
379 default:
380 mlg_mode(p, MD_BLK_OUT);
381 break;
382 }
383
384 return(1);
385 }
386
387
388 static int
389 mlg_indent(struct md_mlg *p)
390 {
391 size_t count;
392
393 count = p->indent > MAXINDENT ?
394 (size_t)MAXINDENT : p->indent;
395 count *= INDENT;
396
397 assert(0 == p->pos);
398 return(ml_putchars(p->mbuf, ' ', count, &p->pos));
399 }
400
401
402 static int
403 mlg_newline(struct md_mlg *p)
404 {
405
406 p->pos = 0;
407 return(ml_nputs(p->mbuf, "\n", 1, NULL));
408 }
409
410
411 static void
412 mlg_mode(struct md_mlg *p, enum md_tok ns)
413 {
414
415 p->flags &= ~ML_OVERRIDE_ONE;
416 p->last = ns;
417 }
418
419
420 static int
421 mlg_data(struct md_mlg *p, int space, const char *start, char *buf)
422 {
423 size_t sz;
424 int c;
425
426 assert(p->mbuf);
427 assert(0 != p->indent);
428
429 if (ML_OVERRIDE_ONE & p->flags ||
430 ML_OVERRIDE_ALL & p->flags)
431 space = 0;
432
433 sz = strlen(buf);
434
435 if (0 == p->pos) {
436 if ( ! mlg_indent(p))
437 return(0);
438
439 c = ml_nputstring(p->mbuf, buf, sz, &p->pos);
440
441 if (0 == c) {
442 mlg_err(p, start, buf, "bad char sequence");
443 return(0);
444 } else if (c > 1) {
445 mlg_warn(p, start, buf, "bogus char sequence");
446 return(0);
447 } else if (-1 == c)
448 return(0);
449
450 if (p->indent * INDENT + sz >= COLUMNS)
451 if ( ! mlg_newline(p))
452 return(0);
453
454 return(1);
455 }
456
457 if (space && sz + p->pos >= COLUMNS) {
458 if ( ! mlg_newline(p))
459 return(0);
460 if ( ! mlg_indent(p))
461 return(0);
462 } else if (space) {
463 if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
464 return(0);
465 }
466
467 c = ml_nputstring(p->mbuf, buf, sz, &p->pos);
468
469 if (0 == c) {
470 mlg_err(p, start, buf, "bad char sequence");
471 return(0);
472 } else if (c > 1) {
473 mlg_warn(p, start, buf, "bogus char sequence");
474 return(0);
475 } else if (-1 == c)
476 return(0);
477
478 return(1);
479 }
480
481
482 int
483 mlg_line(struct md_mlg *p, char *buf)
484 {
485
486 return(roff_engine(p->tree, buf));
487 }
488
489
490 int
491 mlg_exit(struct md_mlg *p, int flush)
492 {
493 int c;
494
495 c = roff_free(p->tree, flush);
496 free(p);
497
498 (*p->cbs.ml_free)(p->data);
499
500 return(c);
501 }
502
503
504 struct md_mlg *
505 mlg_alloc(const struct md_args *args,
506 const struct md_rbuf *rbuf,
507 struct md_mbuf *mbuf,
508 const struct ml_cbs *cbs)
509 {
510 struct roffcb cb;
511 struct md_mlg *p;
512
513 cb.roffhead = mlg_roffhead;
514 cb.rofftail = mlg_rofftail;
515 cb.roffin = mlg_roffin;
516 cb.roffout = mlg_roffout;
517 cb.roffblkin = mlg_roffblkin;
518 cb.roffblkheadin = mlg_roffblkheadin;
519 cb.roffblkheadout = mlg_roffblkheadout;
520 cb.roffblkbodyin = mlg_roffblkbodyin;
521 cb.roffblkbodyout = mlg_roffblkbodyout;
522 cb.roffblkout = mlg_roffblkout;
523 cb.roffspecial = mlg_roffspecial;
524 cb.roffmsg = mlg_roffmsg;
525 cb.roffdata = mlg_roffdata;
526
527 if (NULL == (p = calloc(1, sizeof(struct md_mlg))))
528 err(1, "calloc");
529
530 p->args = args;
531 p->mbuf = mbuf;
532 p->rbuf = rbuf;
533
534 (void)memcpy(&p->cbs, cbs, sizeof(struct ml_cbs));
535
536 if (NULL == (p->tree = roff_alloc(&cb, p)))
537 free(p);
538 else if ( ! (*p->cbs.ml_alloc)(&p->data))
539 free(p);
540 else
541 return(p);
542
543 return(NULL);
544 }
545
546
547 static int
548 mlg_roffhead(void *arg, const struct tm *tm, const char *os,
549 const char *title, const char *sec, const char *vol)
550 {
551 struct md_mlg *p;
552
553 assert(arg);
554 p = (struct md_mlg *)arg;
555
556 mlg_mode(p, MD_BLK_IN);
557
558 if ( ! (*p->cbs.ml_begin)(p->mbuf, p->args, tm, os, title, sec, vol))
559 return(0);
560
561 p->indent++;
562 return(mlg_newline(p));
563 }
564
565
566 static int
567 mlg_rofftail(void *arg)
568 {
569 struct md_mlg *p;
570
571 assert(arg);
572 p = (struct md_mlg *)arg;
573
574 if (0 != p->pos)
575 if ( ! mlg_newline(p))
576 return(0);
577
578 if ( ! (*p->cbs.ml_end)(p->mbuf, p->args))
579 return(0);
580
581 mlg_mode(p, MD_BLK_OUT);
582
583 return(mlg_newline(p));
584 }
585
586
587 /* ARGSUSED */
588 static int
589 mlg_roffspecial(void *arg, int tok, const char *start,
590 const int *argc, const char **argv, char **more)
591 {
592 struct md_mlg *p;
593 char buf[256];
594
595 assert(arg);
596 p = (struct md_mlg *)arg;
597
598 /*
599 * First handle macros without content.
600 */
601
602 switch (tok) {
603 case (ROFF_Ns):
604 p->flags |= ML_OVERRIDE_ONE;
605 return(1);
606 case (ROFF_Sm):
607 assert(*more);
608 if (0 == strcmp(*more, "on"))
609 p->flags |= ML_OVERRIDE_ALL;
610 else
611 p->flags &= ~ML_OVERRIDE_ALL;
612 return(1);
613 default:
614 break;
615 }
616
617 if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
618 return(0);
619
620 switch (tok) {
621 case (ROFF_St):
622 assert(NULL == *argv);
623 assert(ROFF_ARGMAX != *argc);
624 if ( ! ml_puts(p->mbuf, mlg_St_literal(*argc),
625 &p->pos))
626 return(0);
627 while (*more) {
628 if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
629 return(0);
630 if ( ! ml_putstring(p->mbuf, *more++, &p->pos))
631 return(0);
632 }
633 break;
634
635 case (ROFF_Xr):
636 if ( ! *more) {
637 mlg_err(p, start, start, "missing argument");
638 return(0);
639 }
640 if ( ! ml_puts(p->mbuf, *more++, &p->pos))
641 return(0);
642 if (*more) {
643 if ( ! ml_nputs(p->mbuf, "(", 1, &p->pos))
644 return(0);
645 if ( ! ml_puts(p->mbuf, *more++, &p->pos))
646 return(0);
647 if ( ! ml_nputs(p->mbuf, ")", 1, &p->pos))
648 return(0);
649 }
650 if (*more) {
651 mlg_err(p, start, start, "too many arguments");
652 return(0);
653 }
654 break;
655 case (ROFF_Sx):
656 /* FALLTHROUGH */
657 case (ROFF_Nm):
658 assert(*more);
659 if ( ! ml_puts(p->mbuf, *more++, &p->pos))
660 return(0);
661 assert(NULL == *more);
662 break;
663
664 case (ROFF_Ex):
665 /* NOTREACHED */
666 case (ROFF_Rv):
667 assert(*more);
668 (void)snprintf(buf, sizeof(buf),
669 mlg_fmt(tok), *more++);
670 if ( ! ml_puts(p->mbuf, buf, &p->pos))
671 return(0);
672 assert(NULL == *more);
673 break;
674 case (ROFF_At):
675 if ( ! ml_puts(p->mbuf, mlg_At_literal(*more), &p->pos))
676 return(0);
677 break;
678 case (ROFF_Bx):
679 /* FALLTHROUGH */
680 case (ROFF_Bsx):
681 /* FALLTHROUGH */
682 case (ROFF_Fx):
683 /* FALLTHROUGH */
684 case (ROFF_Nx):
685 /* FALLTHROUGH */
686 case (ROFF_Ox):
687 if ( ! ml_puts(p->mbuf, mlg_literal(tok), &p->pos))
688 return(0);
689 while (*more) {
690 if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
691 return(0);
692 if ( ! ml_putstring(p->mbuf, *more++, &p->pos))
693 return(0);
694 }
695 break;
696 case (ROFF_Bt):
697 /* FALLTHROUGH */
698 case (ROFF_Ud):
699 /* FALLTHROUGH */
700 case (ROFF_Ux):
701 assert(NULL == *more);
702 if ( ! ml_puts(p->mbuf, mlg_literal(tok), &p->pos))
703 return(0);
704 break;
705 default:
706 mlg_err(p, start, start, "`%s' not yet supported",
707 toknames[tok]);
708 return(0);
709 }
710
711 return(mlg_endtag(p, MD_NS_INLINE, tok));
712 }
713
714
715 static int
716 mlg_roffblkin(void *arg, int tok, int *argc, char **argv)
717 {
718
719 return(mlg_begintag((struct md_mlg *)arg,
720 MD_NS_BLOCK, tok, argc, argv));
721 }
722
723
724 static int
725 mlg_roffblkout(void *arg, int tok)
726 {
727
728 return(mlg_endtag((struct md_mlg *)arg, MD_NS_BLOCK, tok));
729 }
730
731
732 static int
733 mlg_roffblkbodyin(void *arg, int tok, int *argc, char **argv)
734 {
735
736 return(mlg_begintag((struct md_mlg *)arg,
737 MD_NS_BODY, tok, argc, argv));
738 }
739
740
741 static int
742 mlg_roffblkbodyout(void *arg, int tok)
743 {
744
745 return(mlg_endtag((struct md_mlg *)arg, MD_NS_BODY, tok));
746 }
747
748
749 static int
750 mlg_roffblkheadin(void *arg, int tok, int *argc, char **argv)
751 {
752
753 return(mlg_begintag((struct md_mlg *)arg,
754 MD_NS_HEAD, tok, argc, argv));
755 }
756
757
758 static int
759 mlg_roffblkheadout(void *arg, int tok)
760 {
761
762 return(mlg_endtag((struct md_mlg *)arg, MD_NS_HEAD, tok));
763 }
764
765
766 static int
767 mlg_roffin(void *arg, int tok, int *argc, char **argv)
768 {
769
770 return(mlg_begintag((struct md_mlg *)arg,
771 MD_NS_INLINE, tok, argc, argv));
772 }
773
774
775 static int
776 mlg_roffout(void *arg, int tok)
777 {
778
779 return(mlg_endtag((struct md_mlg *)arg, MD_NS_INLINE, tok));
780 }
781
782
783 static void
784 mlg_roffmsg(void *arg, enum roffmsg lvl,
785 const char *buf, const char *pos, char *msg)
786 {
787
788 mlg_msg((struct md_mlg *)arg, lvl, buf, pos, msg);
789 }
790
791
792 static int
793 mlg_roffdata(void *arg, int space, const char *start, char *buf)
794 {
795 struct md_mlg *p;
796
797 assert(arg);
798 p = (struct md_mlg *)arg;
799
800 if ( ! mlg_data(p, space, start, buf))
801 return(0);
802
803 mlg_mode(p, MD_TEXT);
804
805 return(1);
806 }
807
808
809 static void
810 mlg_vmsg(struct md_mlg *p, enum roffmsg lvl, const char *start,
811 const char *pos, const char *fmt, va_list ap)
812 {
813 char buf[128];
814
815 (void)vsnprintf(buf, sizeof(buf), fmt, ap);
816 mlg_msg(p, lvl, start, pos, buf);
817 }
818
819
820 static void
821 mlg_warn(struct md_mlg *p, const char *start,
822 const char *pos, const char *fmt, ...)
823 {
824 va_list ap;
825
826 va_start(ap, fmt);
827 mlg_vmsg(p, ROFF_WARN, start, pos, fmt, ap);
828 va_end(ap);
829 }
830
831
832 static void
833 mlg_err(struct md_mlg *p, const char *start,
834 const char *pos, const char *fmt, ...)
835 {
836 va_list ap;
837
838 va_start(ap, fmt);
839 mlg_vmsg(p, ROFF_ERROR, start, pos, fmt, ap);
840 va_end(ap);
841 }
842
843
844 static void
845 mlg_msg(struct md_mlg *p, enum roffmsg lvl,
846 const char *buf, const char *pos, char *msg)
847 {
848 char *level;
849
850 switch (lvl) {
851 case (ROFF_WARN):
852 if ( ! (MD_WARN_ALL & p->args->warnings))
853 return;
854 level = "warning";
855 break;
856 case (ROFF_ERROR):
857 level = "error";
858 break;
859 default:
860 abort();
861 }
862
863 if (pos)
864 (void)fprintf(stderr, "%s:%zu: %s: %s (column %zu)\n",
865 p->rbuf->name, p->rbuf->line, level,
866 msg, pos - buf);
867 else
868 (void)fprintf(stderr, "%s: %s: %s\n",
869 p->rbuf->name, level, msg);
870 }