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