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