Annotation of mandoc/mlg.c, Revision 1.18
1.18 ! kristaps 1: /* $Id: mlg.c,v 1.17 2008/12/07 14:38:57 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.");
1.18 ! kristaps 237: case (ROFF_In):
! 238: return("#include <%s>");
1.17 kristaps 239: default:
240: break;
241: }
242:
243: abort();
244: /* NOTREACHED */
245: }
246:
247:
248: static char *
1.15 kristaps 249: mlg_literal(int tok)
250: {
1.17 kristaps 251:
1.15 kristaps 252: switch (tok) {
253: case (ROFF_Bt):
254: return("is currently in beta test.");
255: case (ROFF_Ud):
256: return("currently under development.");
257: case (ROFF_Fx):
258: return("FreeBSD");
259: case (ROFF_Nx):
260: return("NetBSD");
261: case (ROFF_Ox):
262: return("OpenBSD");
263: case (ROFF_Ux):
264: return("UNIX");
265: case (ROFF_Bx):
266: return("BSD");
267: case (ROFF_Bsx):
268: return("BSDI BSD/OS");
269: default:
270: break;
271: }
272: abort();
273: /* NOTREACHED */
274: }
275:
276:
1.1 kristaps 277: static int
278: mlg_begintag(struct md_mlg *p, enum md_ns ns, int tok,
279: int *argc, char **argv)
280: {
281: ssize_t res;
282:
1.8 kristaps 283: assert(MD_NS_DEFAULT != ns);
284:
285: switch (ns) {
286: case (MD_NS_INLINE):
287: if ( ! (ML_OVERRIDE_ONE & p->flags) &&
288: ! (ML_OVERRIDE_ALL & p->flags) &&
1.9 kristaps 289: p->pos + 11 >= COLUMNS)
1.8 kristaps 290: if ( ! mlg_newline(p))
291: return(0);
292: if (0 != p->pos && (MD_TEXT == p->last ||
293: MD_INLINE_OUT == p->last)
294: && ! (ML_OVERRIDE_ONE & p->flags)
295: && ! (ML_OVERRIDE_ALL & p->flags))
296: if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
297: return(0);
298: if (0 == p->pos && ! mlg_indent(p))
299: return(0);
300: mlg_mode(p, MD_INLINE_IN);
301: break;
302: default:
303: if (0 != p->pos) {
304: if ( ! mlg_newline(p))
305: return(0);
306: if ( ! mlg_indent(p))
307: return(0);
308: } else if ( ! mlg_indent(p))
309: return(0);
310: p->indent++;
311: mlg_mode(p, MD_BLK_IN);
312: break;
313: }
1.1 kristaps 314:
315: if ( ! ml_nputs(p->mbuf, "<", 1, &p->pos))
316: return(0);
317:
1.11 kristaps 318: res = (*p->cbs.ml_begintag)(p->mbuf, p->data, p->args, ns, tok,
1.1 kristaps 319: argc, (const char **)argv);
320: if (-1 == res)
321: return(0);
322:
323: assert(res >= 0);
324: p->pos += (size_t)res;
325:
1.8 kristaps 326: if ( ! ml_nputs(p->mbuf, ">", 1, &p->pos))
327: return(0);
328:
329: switch (ns) {
330: case (MD_NS_INLINE):
331: break;
332: default:
333: if ( ! mlg_newline(p))
334: return(0);
335: break;
336: }
1.1 kristaps 337:
1.8 kristaps 338: return(1);
1.1 kristaps 339: }
340:
341:
342: static int
343: mlg_endtag(struct md_mlg *p, enum md_ns ns, int tok)
344: {
345: ssize_t res;
346:
1.9 kristaps 347: assert(MD_NS_DEFAULT != ns);
348:
349: switch (ns) {
350: case (MD_NS_INLINE):
351: break;
352: default:
353: p->indent--;
354: if (0 != p->pos) {
355: if ( ! mlg_newline(p))
356: return(0);
357: if ( ! mlg_indent(p))
358: return(0);
359: } else if ( ! mlg_indent(p))
360: return(0);
361: break;
362: }
1.1 kristaps 363:
364: if ( ! ml_nputs(p->mbuf, "</", 2, &p->pos))
365: return(0);
366:
1.11 kristaps 367: res = (*p->cbs.ml_endtag)(p->mbuf, p->data, p->args, ns, tok);
1.1 kristaps 368: if (-1 == res)
369: return(0);
370:
371: assert(res >= 0);
372: p->pos += (size_t)res;
373:
1.9 kristaps 374: if ( ! ml_nputs(p->mbuf, ">", 1, &p->pos))
375: return(0);
376:
377: switch (ns) {
378: case (MD_NS_INLINE):
379: mlg_mode(p, MD_INLINE_OUT);
380: break;
381: default:
382: mlg_mode(p, MD_BLK_OUT);
383: break;
384: }
1.1 kristaps 385:
1.9 kristaps 386: return(1);
1.1 kristaps 387: }
388:
389:
390: static int
391: mlg_indent(struct md_mlg *p)
392: {
393: size_t count;
394:
1.9 kristaps 395: count = p->indent > MAXINDENT ?
396: (size_t)MAXINDENT : p->indent;
1.1 kristaps 397: count *= INDENT;
398:
399: assert(0 == p->pos);
400: return(ml_putchars(p->mbuf, ' ', count, &p->pos));
401: }
402:
403:
404: static int
405: mlg_newline(struct md_mlg *p)
406: {
407:
408: p->pos = 0;
1.11 kristaps 409: return(ml_nputs(p->mbuf, "\n", 1, NULL));
1.1 kristaps 410: }
411:
412:
413: static void
414: mlg_mode(struct md_mlg *p, enum md_tok ns)
415: {
1.3 kristaps 416:
1.1 kristaps 417: p->flags &= ~ML_OVERRIDE_ONE;
418: p->last = ns;
419: }
420:
421:
422: static int
1.5 kristaps 423: mlg_data(struct md_mlg *p, int space, const char *start, char *buf)
1.1 kristaps 424: {
425: size_t sz;
1.5 kristaps 426: int c;
1.1 kristaps 427:
428: assert(p->mbuf);
429: assert(0 != p->indent);
430:
431: if (ML_OVERRIDE_ONE & p->flags ||
432: ML_OVERRIDE_ALL & p->flags)
433: space = 0;
434:
1.8 kristaps 435: sz = strlen(buf);
1.1 kristaps 436:
1.8 kristaps 437: if (0 == p->pos) {
438: if ( ! mlg_indent(p))
439: return(0);
1.1 kristaps 440:
1.8 kristaps 441: c = ml_nputstring(p->mbuf, buf, sz, &p->pos);
1.1 kristaps 442:
1.8 kristaps 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:
1.8 kristaps 452: if (p->indent * INDENT + sz >= COLUMNS)
453: if ( ! mlg_newline(p))
1.1 kristaps 454: return(0);
1.5 kristaps 455:
1.8 kristaps 456: return(1);
457: }
1.5 kristaps 458:
1.8 kristaps 459: if (space && sz + p->pos >= COLUMNS) {
460: if ( ! mlg_newline(p))
1.5 kristaps 461: return(0);
1.8 kristaps 462: if ( ! mlg_indent(p))
1.5 kristaps 463: return(0);
1.8 kristaps 464: } else if (space) {
465: if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
1.1 kristaps 466: return(0);
1.8 kristaps 467: }
1.1 kristaps 468:
1.8 kristaps 469: c = ml_nputstring(p->mbuf, buf, sz, &p->pos);
470:
471: if (0 == c) {
472: mlg_err(p, start, buf, "bad char sequence");
473: return(0);
474: } else if (c > 1) {
475: mlg_warn(p, start, buf, "bogus char sequence");
476: return(0);
477: } else if (-1 == c)
478: return(0);
1.1 kristaps 479:
480: return(1);
481: }
482:
483:
484: int
485: mlg_line(struct md_mlg *p, char *buf)
486: {
487:
488: return(roff_engine(p->tree, buf));
489: }
490:
491:
492: int
493: mlg_exit(struct md_mlg *p, int flush)
494: {
495: int c;
496:
497: c = roff_free(p->tree, flush);
498: free(p);
1.11 kristaps 499:
500: (*p->cbs.ml_free)(p->data);
501:
1.1 kristaps 502: return(c);
503: }
504:
505:
506: struct md_mlg *
1.11 kristaps 507: mlg_alloc(const struct md_args *args,
1.1 kristaps 508: const struct md_rbuf *rbuf,
509: struct md_mbuf *mbuf,
1.11 kristaps 510: const struct ml_cbs *cbs)
1.1 kristaps 511: {
512: struct roffcb cb;
513: struct md_mlg *p;
514:
515: cb.roffhead = mlg_roffhead;
516: cb.rofftail = mlg_rofftail;
517: cb.roffin = mlg_roffin;
518: cb.roffout = mlg_roffout;
519: cb.roffblkin = mlg_roffblkin;
1.2 kristaps 520: cb.roffblkheadin = mlg_roffblkheadin;
521: cb.roffblkheadout = mlg_roffblkheadout;
522: cb.roffblkbodyin = mlg_roffblkbodyin;
523: cb.roffblkbodyout = mlg_roffblkbodyout;
1.1 kristaps 524: cb.roffblkout = mlg_roffblkout;
525: cb.roffspecial = mlg_roffspecial;
526: cb.roffmsg = mlg_roffmsg;
527: cb.roffdata = mlg_roffdata;
528:
529: if (NULL == (p = calloc(1, sizeof(struct md_mlg))))
530: err(1, "calloc");
531:
532: p->args = args;
533: p->mbuf = mbuf;
534: p->rbuf = rbuf;
535:
1.11 kristaps 536: (void)memcpy(&p->cbs, cbs, sizeof(struct ml_cbs));
537:
538: if (NULL == (p->tree = roff_alloc(&cb, p)))
539: free(p);
540: else if ( ! (*p->cbs.ml_alloc)(&p->data))
1.1 kristaps 541: free(p);
1.11 kristaps 542: else
543: return(p);
1.1 kristaps 544:
1.11 kristaps 545: return(NULL);
1.1 kristaps 546: }
547:
548:
549: static int
1.4 kristaps 550: mlg_roffhead(void *arg, const struct tm *tm, const char *os,
551: const char *title, const char *sec, const char *vol)
1.1 kristaps 552: {
553: struct md_mlg *p;
554:
555: assert(arg);
556: p = (struct md_mlg *)arg;
557:
558: mlg_mode(p, MD_BLK_IN);
1.11 kristaps 559:
560: if ( ! (*p->cbs.ml_begin)(p->mbuf, p->args, tm, os, title, sec, vol))
1.1 kristaps 561: return(0);
562:
563: p->indent++;
564: return(mlg_newline(p));
565: }
566:
567:
568: static int
569: mlg_rofftail(void *arg)
570: {
571: struct md_mlg *p;
572:
573: assert(arg);
574: p = (struct md_mlg *)arg;
575:
1.11 kristaps 576: if (0 != p->pos)
577: if ( ! mlg_newline(p))
578: return(0);
579:
580: if ( ! (*p->cbs.ml_end)(p->mbuf, p->args))
1.1 kristaps 581: return(0);
582:
583: mlg_mode(p, MD_BLK_OUT);
584:
585: return(mlg_newline(p));
586: }
587:
588:
1.16 kristaps 589: /* ARGSUSED */
1.1 kristaps 590: static int
1.16 kristaps 591: mlg_roffspecial(void *arg, int tok, const char *start,
592: const int *argc, const char **argv, char **more)
1.1 kristaps 593: {
594: struct md_mlg *p;
1.17 kristaps 595: char buf[256];
1.1 kristaps 596:
597: assert(arg);
598: p = (struct md_mlg *)arg;
599:
1.15 kristaps 600: /*
601: * First handle macros without content.
602: */
603:
1.1 kristaps 604: switch (tok) {
1.15 kristaps 605: case (ROFF_Ns):
606: p->flags |= ML_OVERRIDE_ONE;
607: return(1);
608: case (ROFF_Sm):
609: assert(*more);
610: if (0 == strcmp(*more, "on"))
611: p->flags |= ML_OVERRIDE_ALL;
612: else
613: p->flags &= ~ML_OVERRIDE_ALL;
614: return(1);
615: default:
1.14 kristaps 616: break;
1.15 kristaps 617: }
618:
1.18 ! kristaps 619: /*
! 620: * Handle macros put into different-token tags.
! 621: */
! 622:
! 623: switch (tok) {
! 624: case (ROFF_Fn):
! 625: assert(*more);
! 626: if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
! 627: return(0);
! 628: if ( ! ml_putstring(p->mbuf, *more++, &p->pos))
! 629: return(0);
! 630: if ( ! mlg_endtag(p, MD_NS_INLINE, tok))
! 631: return(0);
! 632: if (*more) {
! 633: if ( ! ml_nputs(p->mbuf, "(", 1, &p->pos))
! 634: return(0);
! 635: p->flags |= ML_OVERRIDE_ONE;
! 636: if ( ! mlg_begintag(p, MD_NS_INLINE,
! 637: ROFF_Fa, NULL, more))
! 638: return(0);
! 639: if ( ! ml_putstring(p->mbuf, *more++, &p->pos))
! 640: return(0);
! 641: if ( ! mlg_endtag(p, MD_NS_INLINE, ROFF_Fa))
! 642: return(0);
! 643: while (*more) {
! 644: if ( ! ml_nputs(p->mbuf, ", ", 2, &p->pos))
! 645: return(0);
! 646: if ( ! mlg_begintag(p, MD_NS_INLINE, ROFF_Fa, NULL, more))
! 647: return(0);
! 648: if ( ! ml_putstring(p->mbuf, *more++, &p->pos))
! 649: return(0);
! 650: if ( ! mlg_endtag(p, MD_NS_INLINE, ROFF_Fa))
! 651: return(0);
! 652: }
! 653: if ( ! ml_nputs(p->mbuf, ")", 1, &p->pos))
! 654: return(0);
! 655: }
! 656: return(1);
! 657: default:
! 658: break;
! 659: }
! 660:
! 661: /*
! 662: * Now handle macros in their environments.
! 663: */
! 664:
1.15 kristaps 665: if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
666: return(0);
1.14 kristaps 667:
1.15 kristaps 668: switch (tok) {
1.16 kristaps 669: case (ROFF_St):
670: assert(NULL == *argv);
671: assert(ROFF_ARGMAX != *argc);
672: if ( ! ml_puts(p->mbuf, mlg_St_literal(*argc),
673: &p->pos))
674: return(0);
675: while (*more) {
676: if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
677: return(0);
678: if ( ! ml_putstring(p->mbuf, *more++, &p->pos))
679: return(0);
680: }
681: break;
682:
1.8 kristaps 683: case (ROFF_Xr):
684: if ( ! *more) {
1.9 kristaps 685: mlg_err(p, start, start, "missing argument");
1.8 kristaps 686: return(0);
687: }
688: if ( ! ml_puts(p->mbuf, *more++, &p->pos))
689: return(0);
690: if (*more) {
691: if ( ! ml_nputs(p->mbuf, "(", 1, &p->pos))
692: return(0);
1.9 kristaps 693: if ( ! ml_puts(p->mbuf, *more++, &p->pos))
1.8 kristaps 694: return(0);
695: if ( ! ml_nputs(p->mbuf, ")", 1, &p->pos))
696: return(0);
697: }
698: if (*more) {
699: mlg_err(p, start, start, "too many arguments");
700: return(0);
701: }
702: break;
1.15 kristaps 703: case (ROFF_Sx):
704: /* FALLTHROUGH */
1.12 kristaps 705: case (ROFF_Nm):
706: assert(*more);
1.18 ! kristaps 707: if ( ! ml_putstring(p->mbuf, *more++, &p->pos))
1.12 kristaps 708: return(0);
709: assert(NULL == *more);
1.1 kristaps 710: break;
1.18 ! kristaps 711:
! 712: case (ROFF_In):
! 713: /* NOTREACHED */
1.13 kristaps 714: case (ROFF_Ex):
1.17 kristaps 715: /* NOTREACHED */
716: case (ROFF_Rv):
1.13 kristaps 717: assert(*more);
1.18 ! kristaps 718: /* FIXME: *more must be ml-filtered. */
1.17 kristaps 719: (void)snprintf(buf, sizeof(buf),
720: mlg_fmt(tok), *more++);
721: if ( ! ml_puts(p->mbuf, buf, &p->pos))
1.13 kristaps 722: return(0);
723: assert(NULL == *more);
1.15 kristaps 724: break;
725: case (ROFF_At):
726: if ( ! ml_puts(p->mbuf, mlg_At_literal(*more), &p->pos))
1.13 kristaps 727: return(0);
728: break;
1.15 kristaps 729: case (ROFF_Bx):
730: /* FALLTHROUGH */
731: case (ROFF_Bsx):
732: /* FALLTHROUGH */
733: case (ROFF_Fx):
734: /* FALLTHROUGH */
735: case (ROFF_Nx):
736: /* FALLTHROUGH */
737: case (ROFF_Ox):
738: if ( ! ml_puts(p->mbuf, mlg_literal(tok), &p->pos))
739: return(0);
740: while (*more) {
741: if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
742: return(0);
743: if ( ! ml_putstring(p->mbuf, *more++, &p->pos))
744: return(0);
745: }
746: break;
747: case (ROFF_Bt):
748: /* FALLTHROUGH */
1.14 kristaps 749: case (ROFF_Ud):
1.15 kristaps 750: /* FALLTHROUGH */
751: case (ROFF_Ux):
1.14 kristaps 752: assert(NULL == *more);
1.15 kristaps 753: if ( ! ml_puts(p->mbuf, mlg_literal(tok), &p->pos))
1.14 kristaps 754: return(0);
755: break;
1.1 kristaps 756: default:
1.13 kristaps 757: mlg_err(p, start, start, "`%s' not yet supported",
758: toknames[tok]);
759: return(0);
1.1 kristaps 760: }
761:
1.15 kristaps 762: return(mlg_endtag(p, MD_NS_INLINE, tok));
1.1 kristaps 763: }
764:
765:
766: static int
767: mlg_roffblkin(void *arg, int tok, int *argc, char **argv)
768: {
769:
1.8 kristaps 770: return(mlg_begintag((struct md_mlg *)arg,
1.2 kristaps 771: MD_NS_BLOCK, tok, argc, argv));
772: }
773:
774:
775: static int
776: mlg_roffblkout(void *arg, int tok)
777: {
778:
1.9 kristaps 779: return(mlg_endtag((struct md_mlg *)arg, MD_NS_BLOCK, tok));
1.2 kristaps 780: }
781:
782:
783: static int
784: mlg_roffblkbodyin(void *arg, int tok, int *argc, char **argv)
785: {
786:
1.8 kristaps 787: return(mlg_begintag((struct md_mlg *)arg,
1.2 kristaps 788: MD_NS_BODY, tok, argc, argv));
789: }
1.1 kristaps 790:
791:
1.2 kristaps 792: static int
793: mlg_roffblkbodyout(void *arg, int tok)
794: {
1.1 kristaps 795:
1.9 kristaps 796: return(mlg_endtag((struct md_mlg *)arg, MD_NS_BODY, tok));
1.1 kristaps 797: }
798:
799:
800: static int
1.2 kristaps 801: mlg_roffblkheadin(void *arg, int tok, int *argc, char **argv)
1.1 kristaps 802: {
803:
1.8 kristaps 804: return(mlg_begintag((struct md_mlg *)arg,
1.2 kristaps 805: MD_NS_HEAD, tok, argc, argv));
806: }
1.1 kristaps 807:
808:
1.2 kristaps 809: static int
810: mlg_roffblkheadout(void *arg, int tok)
811: {
1.1 kristaps 812:
1.9 kristaps 813: return(mlg_endtag((struct md_mlg *)arg, MD_NS_HEAD, tok));
1.1 kristaps 814: }
815:
816:
817: static int
818: mlg_roffin(void *arg, int tok, int *argc, char **argv)
819: {
820:
1.8 kristaps 821: return(mlg_begintag((struct md_mlg *)arg,
822: MD_NS_INLINE, tok, argc, argv));
1.1 kristaps 823: }
824:
825:
826: static int
827: mlg_roffout(void *arg, int tok)
828: {
829:
1.9 kristaps 830: return(mlg_endtag((struct md_mlg *)arg, MD_NS_INLINE, tok));
1.1 kristaps 831: }
832:
833:
834: static void
835: mlg_roffmsg(void *arg, enum roffmsg lvl,
836: const char *buf, const char *pos, char *msg)
837: {
1.5 kristaps 838:
839: mlg_msg((struct md_mlg *)arg, lvl, buf, pos, msg);
840: }
841:
842:
843: static int
844: mlg_roffdata(void *arg, int space, const char *start, char *buf)
845: {
1.1 kristaps 846: struct md_mlg *p;
847:
848: assert(arg);
849: p = (struct md_mlg *)arg;
850:
1.5 kristaps 851: if ( ! mlg_data(p, space, start, buf))
852: return(0);
853:
854: mlg_mode(p, MD_TEXT);
1.11 kristaps 855:
1.5 kristaps 856: return(1);
857: }
858:
859:
860: static void
1.13 kristaps 861: mlg_vmsg(struct md_mlg *p, enum roffmsg lvl, const char *start,
862: const char *pos, const char *fmt, va_list ap)
1.5 kristaps 863: {
1.13 kristaps 864: char buf[128];
1.5 kristaps 865:
1.13 kristaps 866: (void)vsnprintf(buf, sizeof(buf), fmt, ap);
867: mlg_msg(p, lvl, start, pos, buf);
1.5 kristaps 868: }
869:
870:
871: static void
1.13 kristaps 872: mlg_warn(struct md_mlg *p, const char *start,
873: const char *pos, const char *fmt, ...)
1.5 kristaps 874: {
1.13 kristaps 875: va_list ap;
1.5 kristaps 876:
1.13 kristaps 877: va_start(ap, fmt);
878: mlg_vmsg(p, ROFF_WARN, start, pos, fmt, ap);
879: va_end(ap);
880: }
881:
882:
883: static void
884: mlg_err(struct md_mlg *p, const char *start,
885: const char *pos, const char *fmt, ...)
886: {
887: va_list ap;
888:
889: va_start(ap, fmt);
890: mlg_vmsg(p, ROFF_ERROR, start, pos, fmt, ap);
891: va_end(ap);
1.5 kristaps 892: }
893:
894:
895: static void
896: mlg_msg(struct md_mlg *p, enum roffmsg lvl,
897: const char *buf, const char *pos, char *msg)
898: {
899: char *level;
900:
1.1 kristaps 901: switch (lvl) {
902: case (ROFF_WARN):
903: if ( ! (MD_WARN_ALL & p->args->warnings))
904: return;
905: level = "warning";
906: break;
907: case (ROFF_ERROR):
908: level = "error";
909: break;
910: default:
911: abort();
912: }
913:
914: if (pos)
915: (void)fprintf(stderr, "%s:%zu: %s: %s (column %zu)\n",
916: p->rbuf->name, p->rbuf->line, level,
917: msg, pos - buf);
918: else
919: (void)fprintf(stderr, "%s: %s: %s\n",
920: p->rbuf->name, level, msg);
921: }
CVSweb