Annotation of mandoc/mlg.c, Revision 1.17
1.17 ! kristaps 1: /* $Id: mlg.c,v 1.16 2008/12/06 21:10:31 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.17 ! kristaps 65: static char *mlg_fmt(int);
1.16 kristaps 66: static char *mlg_St_literal(int);
1.1 kristaps 67: static void mlg_roffmsg(void *arg, enum roffmsg,
68: const char *, const char *, char *);
1.4 kristaps 69: static int mlg_roffhead(void *, const struct tm *,
70: const char *, const char *,
71: const char *, const char *);
1.1 kristaps 72: static int mlg_rofftail(void *);
73: static int mlg_roffin(void *, int, int *, char **);
1.5 kristaps 74: static int mlg_roffdata(void *, int,
75: const char *, char *);
1.1 kristaps 76: static int mlg_roffout(void *, int);
77: static int mlg_roffblkin(void *, int, int *, char **);
78: static int mlg_roffblkout(void *, int);
1.8 kristaps 79: static int mlg_roffspecial(void *, int,
1.16 kristaps 80: const char *, const int *,
81: const char **, char **);
1.5 kristaps 82: static int mlg_roffblkheadin(void *, int,
83: int *, char **);
1.2 kristaps 84: static int mlg_roffblkheadout(void *, int);
1.5 kristaps 85: static int mlg_roffblkbodyin(void *, int,
86: int *, char **);
1.2 kristaps 87: static int mlg_roffblkbodyout(void *, int);
88:
1.1 kristaps 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);
1.5 kristaps 95: static int mlg_data(struct md_mlg *, int,
96: const char *, char *);
97: static void mlg_err(struct md_mlg *, const char *,
1.13 kristaps 98: const char *, const char *, ...);
1.5 kristaps 99: static void mlg_warn(struct md_mlg *, const char *,
1.13 kristaps 100: const char *, const char *, ...);
1.5 kristaps 101: static void mlg_msg(struct md_mlg *, enum roffmsg,
102: const char *, const char *, char *);
1.13 kristaps 103: static void mlg_vmsg(struct md_mlg *, enum roffmsg,
104: const char *, const char *,
105: const char *, va_list);
1.1 kristaps 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:
1.15 kristaps 113: static char *
1.16 kristaps 114: mlg_St_literal(int argc)
115: {
116:
117: switch (argc) {
118: case(ROFF_p1003_1_88):
119: return("IEEE Std 1003.1-1988 (“POSIX”)");
120: case(ROFF_p1003_1_90):
121: return("IEEE Std 1003.1-1990 (“POSIX”)");
122: case(ROFF_p1003_1_96):
123: return("ISO/IEC 9945-1:1996 (“POSIX”)");
124: case(ROFF_p1003_1_2001):
125: return("IEEE Std 1003.1-2001 (“POSIX”)");
126: case(ROFF_p1003_1_2004):
127: return("IEEE Std 1003.1-2004 (“POSIX”)");
128: case(ROFF_p1003_1):
129: return("IEEE Std 1003.1 (“POSIX”)");
130: case(ROFF_p1003_1b):
131: return("IEEE Std 1003.1b (“POSIX”)");
132: case(ROFF_p1003_1b_93):
133: return("IEEE Std 1003.1b-1993 (“POSIX”)");
134: case(ROFF_p1003_1c_95):
135: return("IEEE Std 1003.1c-1995 (“POSIX”)");
136: case(ROFF_p1003_1g_2000):
137: return("IEEE Std 1003.1g-2000 (“POSIX”)");
138: case(ROFF_p1003_2_92):
139: return("IEEE Std 1003.2-1992 (“POSIX.2”)");
140: case(ROFF_p1387_2_95):
141: return("IEEE Std 1387.2-1995 (“POSIX.7.2”)");
142: case(ROFF_p1003_2):
143: return("IEEE Std 1003.2 (“POSIX.2”)");
144: case(ROFF_p1387_2):
145: return("IEEE Std 1387.2 (“POSIX.7.2”)");
146: case(ROFF_isoC_90):
147: return("ISO/IEC 9899:1990 (“ISO C90”)");
148: case(ROFF_isoC_amd1):
149: return("ISO/IEC 9899/AMD1:1995 (“ISO C90”)");
150: case(ROFF_isoC_tcor1):
151: return("ISO/IEC 9899/TCOR1:1994 (“ISO C90”)");
152: case(ROFF_isoC_tcor2):
153: return("ISO/IEC 9899/TCOR2:1995 (“ISO C90”)");
154: case(ROFF_isoC_99):
155: return("ISO/IEC 9899:1999 (“ISO C99”)");
156: case(ROFF_ansiC):
157: return("ANSI X3.159-1989 (“ANSI C”)");
158: case(ROFF_ansiC_89):
159: return("ANSI X3.159-1989 (“ANSI C”)");
160: case(ROFF_ansiC_99):
161: return("ANSI/ISO/IEC 9899-1999 (“ANSI C99”)");
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 (“XPG3”)");
168: case(ROFF_xpg4):
169: return("X/Open Portability Guide Issue 4 (“XPG4”)");
170: case(ROFF_xpg4_2):
171: return("X/Open Portability Guide Issue 4.2 (“XPG4.2”)");
172: case(ROFF_xpg4_3):
173: return("X/Open Portability Guide Issue 4.3 (“XPG4.3”)");
174: case(ROFF_xbd5):
175: return("X/Open System Interface Definitions Issue 5 (“XBD5”)");
176: case(ROFF_xcu5):
177: return("X/Open Commands and Utilities Issue 5 (“XCU5”)");
178: case(ROFF_xsh5):
179: return("X/Open System Interfaces and Headers Issue 5 (“XSH5”)");
180: case(ROFF_xns5):
181: return("X/Open Networking Services Issue 5 (“XNS5”)");
182: case(ROFF_xns5_2d2_0):
183: return("X/Open Networking Services Issue 5.2 Draft 2.0 (“XNS5.2D2.0”)");
184: case(ROFF_xcurses4_2):
185: return("X/Open Curses Issue 4 Version 2 (“XCURSES4.2”)");
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 (“SVID4”)");
192: default:
193: break;
194: }
195:
196: abort();
197: /* NOTREACHED */
198: }
199:
200:
201: static char *
1.15 kristaps 202: mlg_At_literal(const char *p)
203: {
1.17 ! kristaps 204:
1.15 kristaps 205: if (NULL == p)
206: return("AT&T UNIX");
207: if (0 == strcmp(p, "v6"))
208: return("Version 6 AT&T UNIX");
209: else if (0 == strcmp(p, "v7"))
210: return("Version 7 AT&T UNIX");
211: else if (0 == strcmp(p, "32v"))
212: return("Version 32v AT&T UNIX");
213: else if (0 == strcmp(p, "V.1"))
214: return("AT&T System V.1 UNIX");
215: else if (0 == strcmp(p, "V.4"))
216: return("AT&T System V.4 UNIX");
217:
218: abort();
219: /* NOTREACHED */
220: }
221:
222:
223: static char *
1.17 ! kristaps 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: ">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 *
1.15 kristaps 247: mlg_literal(int tok)
248: {
1.17 ! kristaps 249:
1.15 kristaps 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:
1.1 kristaps 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:
1.8 kristaps 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) &&
1.9 kristaps 287: p->pos + 11 >= COLUMNS)
1.8 kristaps 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: }
1.1 kristaps 312:
313: if ( ! ml_nputs(p->mbuf, "<", 1, &p->pos))
314: return(0);
315:
1.11 kristaps 316: res = (*p->cbs.ml_begintag)(p->mbuf, p->data, p->args, ns, tok,
1.1 kristaps 317: argc, (const char **)argv);
318: if (-1 == res)
319: return(0);
320:
321: assert(res >= 0);
322: p->pos += (size_t)res;
323:
1.8 kristaps 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: }
1.1 kristaps 335:
1.8 kristaps 336: return(1);
1.1 kristaps 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:
1.9 kristaps 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: }
1.1 kristaps 361:
362: if ( ! ml_nputs(p->mbuf, "</", 2, &p->pos))
363: return(0);
364:
1.11 kristaps 365: res = (*p->cbs.ml_endtag)(p->mbuf, p->data, p->args, ns, tok);
1.1 kristaps 366: if (-1 == res)
367: return(0);
368:
369: assert(res >= 0);
370: p->pos += (size_t)res;
371:
1.9 kristaps 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: }
1.1 kristaps 383:
1.9 kristaps 384: return(1);
1.1 kristaps 385: }
386:
387:
388: static int
389: mlg_indent(struct md_mlg *p)
390: {
391: size_t count;
392:
1.9 kristaps 393: count = p->indent > MAXINDENT ?
394: (size_t)MAXINDENT : p->indent;
1.1 kristaps 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;
1.11 kristaps 407: return(ml_nputs(p->mbuf, "\n", 1, NULL));
1.1 kristaps 408: }
409:
410:
411: static void
412: mlg_mode(struct md_mlg *p, enum md_tok ns)
413: {
1.3 kristaps 414:
1.1 kristaps 415: p->flags &= ~ML_OVERRIDE_ONE;
416: p->last = ns;
417: }
418:
419:
420: static int
1.5 kristaps 421: mlg_data(struct md_mlg *p, int space, const char *start, char *buf)
1.1 kristaps 422: {
423: size_t sz;
1.5 kristaps 424: int c;
1.1 kristaps 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:
1.8 kristaps 433: sz = strlen(buf);
1.1 kristaps 434:
1.8 kristaps 435: if (0 == p->pos) {
436: if ( ! mlg_indent(p))
437: return(0);
1.1 kristaps 438:
1.8 kristaps 439: c = ml_nputstring(p->mbuf, buf, sz, &p->pos);
1.1 kristaps 440:
1.8 kristaps 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);
1.1 kristaps 449:
1.8 kristaps 450: if (p->indent * INDENT + sz >= COLUMNS)
451: if ( ! mlg_newline(p))
1.1 kristaps 452: return(0);
1.5 kristaps 453:
1.8 kristaps 454: return(1);
455: }
1.5 kristaps 456:
1.8 kristaps 457: if (space && sz + p->pos >= COLUMNS) {
458: if ( ! mlg_newline(p))
1.5 kristaps 459: return(0);
1.8 kristaps 460: if ( ! mlg_indent(p))
1.5 kristaps 461: return(0);
1.8 kristaps 462: } else if (space) {
463: if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
1.1 kristaps 464: return(0);
1.8 kristaps 465: }
1.1 kristaps 466:
1.8 kristaps 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);
1.1 kristaps 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);
1.11 kristaps 497:
498: (*p->cbs.ml_free)(p->data);
499:
1.1 kristaps 500: return(c);
501: }
502:
503:
504: struct md_mlg *
1.11 kristaps 505: mlg_alloc(const struct md_args *args,
1.1 kristaps 506: const struct md_rbuf *rbuf,
507: struct md_mbuf *mbuf,
1.11 kristaps 508: const struct ml_cbs *cbs)
1.1 kristaps 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;
1.2 kristaps 518: cb.roffblkheadin = mlg_roffblkheadin;
519: cb.roffblkheadout = mlg_roffblkheadout;
520: cb.roffblkbodyin = mlg_roffblkbodyin;
521: cb.roffblkbodyout = mlg_roffblkbodyout;
1.1 kristaps 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:
1.11 kristaps 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))
1.1 kristaps 539: free(p);
1.11 kristaps 540: else
541: return(p);
1.1 kristaps 542:
1.11 kristaps 543: return(NULL);
1.1 kristaps 544: }
545:
546:
547: static int
1.4 kristaps 548: mlg_roffhead(void *arg, const struct tm *tm, const char *os,
549: const char *title, const char *sec, const char *vol)
1.1 kristaps 550: {
551: struct md_mlg *p;
552:
553: assert(arg);
554: p = (struct md_mlg *)arg;
555:
556: mlg_mode(p, MD_BLK_IN);
1.11 kristaps 557:
558: if ( ! (*p->cbs.ml_begin)(p->mbuf, p->args, tm, os, title, sec, vol))
1.1 kristaps 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:
1.11 kristaps 574: if (0 != p->pos)
575: if ( ! mlg_newline(p))
576: return(0);
577:
578: if ( ! (*p->cbs.ml_end)(p->mbuf, p->args))
1.1 kristaps 579: return(0);
580:
581: mlg_mode(p, MD_BLK_OUT);
582:
583: return(mlg_newline(p));
584: }
585:
586:
1.16 kristaps 587: /* ARGSUSED */
1.1 kristaps 588: static int
1.16 kristaps 589: mlg_roffspecial(void *arg, int tok, const char *start,
590: const int *argc, const char **argv, char **more)
1.1 kristaps 591: {
592: struct md_mlg *p;
1.17 ! kristaps 593: char buf[256];
1.1 kristaps 594:
595: assert(arg);
596: p = (struct md_mlg *)arg;
597:
1.15 kristaps 598: /*
599: * First handle macros without content.
600: */
601:
1.1 kristaps 602: switch (tok) {
1.15 kristaps 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:
1.14 kristaps 614: break;
1.15 kristaps 615: }
616:
617: if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
618: return(0);
1.14 kristaps 619:
1.15 kristaps 620: switch (tok) {
1.16 kristaps 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:
1.8 kristaps 635: case (ROFF_Xr):
636: if ( ! *more) {
1.9 kristaps 637: mlg_err(p, start, start, "missing argument");
1.8 kristaps 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);
1.9 kristaps 645: if ( ! ml_puts(p->mbuf, *more++, &p->pos))
1.8 kristaps 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;
1.15 kristaps 655: case (ROFF_Sx):
656: /* FALLTHROUGH */
1.12 kristaps 657: case (ROFF_Nm):
658: assert(*more);
659: if ( ! ml_puts(p->mbuf, *more++, &p->pos))
660: return(0);
661: assert(NULL == *more);
1.1 kristaps 662: break;
1.17 ! kristaps 663:
1.13 kristaps 664: case (ROFF_Ex):
1.17 ! kristaps 665: /* NOTREACHED */
! 666: case (ROFF_Rv):
1.13 kristaps 667: assert(*more);
1.17 ! kristaps 668: (void)snprintf(buf, sizeof(buf),
! 669: mlg_fmt(tok), *more++);
! 670: if ( ! ml_puts(p->mbuf, buf, &p->pos))
1.13 kristaps 671: return(0);
672: assert(NULL == *more);
1.15 kristaps 673: break;
674: case (ROFF_At):
675: if ( ! ml_puts(p->mbuf, mlg_At_literal(*more), &p->pos))
1.13 kristaps 676: return(0);
677: break;
1.15 kristaps 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 */
1.14 kristaps 698: case (ROFF_Ud):
1.15 kristaps 699: /* FALLTHROUGH */
700: case (ROFF_Ux):
1.14 kristaps 701: assert(NULL == *more);
1.15 kristaps 702: if ( ! ml_puts(p->mbuf, mlg_literal(tok), &p->pos))
1.14 kristaps 703: return(0);
704: break;
1.1 kristaps 705: default:
1.13 kristaps 706: mlg_err(p, start, start, "`%s' not yet supported",
707: toknames[tok]);
708: return(0);
1.1 kristaps 709: }
710:
1.15 kristaps 711: return(mlg_endtag(p, MD_NS_INLINE, tok));
1.1 kristaps 712: }
713:
714:
715: static int
716: mlg_roffblkin(void *arg, int tok, int *argc, char **argv)
717: {
718:
1.8 kristaps 719: return(mlg_begintag((struct md_mlg *)arg,
1.2 kristaps 720: MD_NS_BLOCK, tok, argc, argv));
721: }
722:
723:
724: static int
725: mlg_roffblkout(void *arg, int tok)
726: {
727:
1.9 kristaps 728: return(mlg_endtag((struct md_mlg *)arg, MD_NS_BLOCK, tok));
1.2 kristaps 729: }
730:
731:
732: static int
733: mlg_roffblkbodyin(void *arg, int tok, int *argc, char **argv)
734: {
735:
1.8 kristaps 736: return(mlg_begintag((struct md_mlg *)arg,
1.2 kristaps 737: MD_NS_BODY, tok, argc, argv));
738: }
1.1 kristaps 739:
740:
1.2 kristaps 741: static int
742: mlg_roffblkbodyout(void *arg, int tok)
743: {
1.1 kristaps 744:
1.9 kristaps 745: return(mlg_endtag((struct md_mlg *)arg, MD_NS_BODY, tok));
1.1 kristaps 746: }
747:
748:
749: static int
1.2 kristaps 750: mlg_roffblkheadin(void *arg, int tok, int *argc, char **argv)
1.1 kristaps 751: {
752:
1.8 kristaps 753: return(mlg_begintag((struct md_mlg *)arg,
1.2 kristaps 754: MD_NS_HEAD, tok, argc, argv));
755: }
1.1 kristaps 756:
757:
1.2 kristaps 758: static int
759: mlg_roffblkheadout(void *arg, int tok)
760: {
1.1 kristaps 761:
1.9 kristaps 762: return(mlg_endtag((struct md_mlg *)arg, MD_NS_HEAD, tok));
1.1 kristaps 763: }
764:
765:
766: static int
767: mlg_roffin(void *arg, int tok, int *argc, char **argv)
768: {
769:
1.8 kristaps 770: return(mlg_begintag((struct md_mlg *)arg,
771: MD_NS_INLINE, tok, argc, argv));
1.1 kristaps 772: }
773:
774:
775: static int
776: mlg_roffout(void *arg, int tok)
777: {
778:
1.9 kristaps 779: return(mlg_endtag((struct md_mlg *)arg, MD_NS_INLINE, tok));
1.1 kristaps 780: }
781:
782:
783: static void
784: mlg_roffmsg(void *arg, enum roffmsg lvl,
785: const char *buf, const char *pos, char *msg)
786: {
1.5 kristaps 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: {
1.1 kristaps 795: struct md_mlg *p;
796:
797: assert(arg);
798: p = (struct md_mlg *)arg;
799:
1.5 kristaps 800: if ( ! mlg_data(p, space, start, buf))
801: return(0);
802:
803: mlg_mode(p, MD_TEXT);
1.11 kristaps 804:
1.5 kristaps 805: return(1);
806: }
807:
808:
809: static void
1.13 kristaps 810: mlg_vmsg(struct md_mlg *p, enum roffmsg lvl, const char *start,
811: const char *pos, const char *fmt, va_list ap)
1.5 kristaps 812: {
1.13 kristaps 813: char buf[128];
1.5 kristaps 814:
1.13 kristaps 815: (void)vsnprintf(buf, sizeof(buf), fmt, ap);
816: mlg_msg(p, lvl, start, pos, buf);
1.5 kristaps 817: }
818:
819:
820: static void
1.13 kristaps 821: mlg_warn(struct md_mlg *p, const char *start,
822: const char *pos, const char *fmt, ...)
1.5 kristaps 823: {
1.13 kristaps 824: va_list ap;
1.5 kristaps 825:
1.13 kristaps 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);
1.5 kristaps 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:
1.1 kristaps 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: }
CVSweb