]>
git.cameronkatri.com Git - mandoc.git/blob - mlg.c
1 /* $Id: mlg.c,v 1.17 2008/12/07 14:38:57 kristaps Exp $ */
3 * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
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
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.
27 #include "libmdocml.h"
31 /* TODO: literal tokens. */
46 const struct md_args
*args
;
47 const struct md_rbuf
*rbuf
;
50 struct rofftree
*tree
;
57 #define ML_OVERRIDE_ONE (1 << 0)
58 #define ML_OVERRIDE_ALL (1 << 1)
63 static char *mlg_literal(int);
64 static char *mlg_At_literal(const char *);
65 static char *mlg_fmt(int);
66 static char *mlg_St_literal(int);
67 static void mlg_roffmsg(void *arg
, enum roffmsg
,
68 const char *, const char *, char *);
69 static int mlg_roffhead(void *, const struct tm
*,
70 const char *, const char *,
71 const char *, const char *);
72 static int mlg_rofftail(void *);
73 static int mlg_roffin(void *, int, int *, char **);
74 static int mlg_roffdata(void *, int,
75 const char *, char *);
76 static int mlg_roffout(void *, int);
77 static int mlg_roffblkin(void *, int, int *, char **);
78 static int mlg_roffblkout(void *, int);
79 static int mlg_roffspecial(void *, int,
80 const char *, const int *,
81 const char **, char **);
82 static int mlg_roffblkheadin(void *, int,
84 static int mlg_roffblkheadout(void *, int);
85 static int mlg_roffblkbodyin(void *, int,
87 static int mlg_roffblkbodyout(void *, int);
89 static int mlg_begintag(struct md_mlg
*, enum md_ns
,
91 static int mlg_endtag(struct md_mlg
*, enum md_ns
, int);
92 static int mlg_indent(struct md_mlg
*);
93 static int mlg_newline(struct md_mlg
*);
94 static void mlg_mode(struct md_mlg
*, enum md_tok
);
95 static int mlg_data(struct md_mlg
*, int,
96 const char *, char *);
97 static void mlg_err(struct md_mlg
*, const char *,
98 const char *, const char *, ...);
99 static void mlg_warn(struct md_mlg
*, const char *,
100 const char *, const char *, ...);
101 static void mlg_msg(struct md_mlg
*, enum roffmsg
,
102 const char *, const char *, char *);
103 static void mlg_vmsg(struct md_mlg
*, enum roffmsg
,
104 const char *, const char *,
105 const char *, va_list);
108 extern size_t strlcat(char *, const char *, size_t);
109 extern size_t strlcpy(char *, const char *, size_t);
114 mlg_St_literal(int 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”)");
129 return("IEEE Std 1003.1 (“POSIX”)");
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”)");
143 return("IEEE Std 1003.2 (“POSIX.2”)");
145 return("IEEE Std 1387.2 (“POSIX.7.2”)");
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”)");
155 return("ISO/IEC 9899:1999 (“ISO C99”)");
157 return("ANSI X3.159-1989 (“ANSI C”)");
159 return("ANSI X3.159-1989 (“ANSI C”)");
161 return("ANSI/ISO/IEC 9899-1999 (“ANSI C99”)");
163 return("IEEE Std 754-1985");
164 case(ROFF_iso8802_3
):
165 return("ISO 8802-3: 1989");
167 return("X/Open Portability Guide Issue 3 (“XPG3”)");
169 return("X/Open Portability Guide Issue 4 (“XPG4”)");
171 return("X/Open Portability Guide Issue 4.2 (“XPG4.2”)");
173 return("X/Open Portability Guide Issue 4.3 (“XPG4.3”)");
175 return("X/Open System Interface Definitions Issue 5 (“XBD5”)");
177 return("X/Open Commands and Utilities Issue 5 (“XCU5”)");
179 return("X/Open System Interfaces and Headers Issue 5 (“XSH5”)");
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”)");
187 return("Version 2 of the Single UNIX Specification");
189 return("Version 3 of the Single UNIX Specification");
191 return("System V Interface Definition, Fourth Edition (“SVID4”)");
202 mlg_At_literal(const char *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");
229 return ("The %s utility exits 0 on success, and "
230 ">0 if an error occurs.");
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.");
252 return("is currently in beta test.");
254 return("currently under development.");
266 return("BSDI BSD/OS");
276 mlg_begintag(struct md_mlg
*p
, enum md_ns ns
, int tok
,
277 int *argc
, char **argv
)
281 assert(MD_NS_DEFAULT
!= ns
);
285 if ( ! (ML_OVERRIDE_ONE
& p
->flags
) &&
286 ! (ML_OVERRIDE_ALL
& p
->flags
) &&
287 p
->pos
+ 11 >= COLUMNS
)
288 if ( ! mlg_newline(p
))
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
))
296 if (0 == p
->pos
&& ! mlg_indent(p
))
298 mlg_mode(p
, MD_INLINE_IN
);
302 if ( ! mlg_newline(p
))
304 if ( ! mlg_indent(p
))
306 } else if ( ! mlg_indent(p
))
309 mlg_mode(p
, MD_BLK_IN
);
313 if ( ! ml_nputs(p
->mbuf
, "<", 1, &p
->pos
))
316 res
= (*p
->cbs
.ml_begintag
)(p
->mbuf
, p
->data
, p
->args
, ns
, tok
,
317 argc
, (const char **)argv
);
322 p
->pos
+= (size_t)res
;
324 if ( ! ml_nputs(p
->mbuf
, ">", 1, &p
->pos
))
331 if ( ! mlg_newline(p
))
341 mlg_endtag(struct md_mlg
*p
, enum md_ns ns
, int tok
)
345 assert(MD_NS_DEFAULT
!= ns
);
353 if ( ! mlg_newline(p
))
355 if ( ! mlg_indent(p
))
357 } else if ( ! mlg_indent(p
))
362 if ( ! ml_nputs(p
->mbuf
, "</", 2, &p
->pos
))
365 res
= (*p
->cbs
.ml_endtag
)(p
->mbuf
, p
->data
, p
->args
, ns
, tok
);
370 p
->pos
+= (size_t)res
;
372 if ( ! ml_nputs(p
->mbuf
, ">", 1, &p
->pos
))
377 mlg_mode(p
, MD_INLINE_OUT
);
380 mlg_mode(p
, MD_BLK_OUT
);
389 mlg_indent(struct md_mlg
*p
)
393 count
= p
->indent
> MAXINDENT
?
394 (size_t)MAXINDENT
: p
->indent
;
398 return(ml_putchars(p
->mbuf
, ' ', count
, &p
->pos
));
403 mlg_newline(struct md_mlg
*p
)
407 return(ml_nputs(p
->mbuf
, "\n", 1, NULL
));
412 mlg_mode(struct md_mlg
*p
, enum md_tok ns
)
415 p
->flags
&= ~ML_OVERRIDE_ONE
;
421 mlg_data(struct md_mlg
*p
, int space
, const char *start
, char *buf
)
427 assert(0 != p
->indent
);
429 if (ML_OVERRIDE_ONE
& p
->flags
||
430 ML_OVERRIDE_ALL
& p
->flags
)
436 if ( ! mlg_indent(p
))
439 c
= ml_nputstring(p
->mbuf
, buf
, sz
, &p
->pos
);
442 mlg_err(p
, start
, buf
, "bad char sequence");
445 mlg_warn(p
, start
, buf
, "bogus char sequence");
450 if (p
->indent
* INDENT
+ sz
>= COLUMNS
)
451 if ( ! mlg_newline(p
))
457 if (space
&& sz
+ p
->pos
>= COLUMNS
) {
458 if ( ! mlg_newline(p
))
460 if ( ! mlg_indent(p
))
463 if ( ! ml_nputs(p
->mbuf
, " ", 1, &p
->pos
))
467 c
= ml_nputstring(p
->mbuf
, buf
, sz
, &p
->pos
);
470 mlg_err(p
, start
, buf
, "bad char sequence");
473 mlg_warn(p
, start
, buf
, "bogus char sequence");
483 mlg_line(struct md_mlg
*p
, char *buf
)
486 return(roff_engine(p
->tree
, buf
));
491 mlg_exit(struct md_mlg
*p
, int flush
)
495 c
= roff_free(p
->tree
, flush
);
498 (*p
->cbs
.ml_free
)(p
->data
);
505 mlg_alloc(const struct md_args
*args
,
506 const struct md_rbuf
*rbuf
,
507 struct md_mbuf
*mbuf
,
508 const struct ml_cbs
*cbs
)
513 cb
.roffhead
= mlg_roffhead
;
514 cb
.rofftail
= mlg_rofftail
;
515 cb
.roffin
= mlg_roffin
;
516 cb
.roffout
= mlg_roffout
;
517 cb
.roffblkin
= mlg_roffblkin
;
518 cb
.roffblkheadin
= mlg_roffblkheadin
;
519 cb
.roffblkheadout
= mlg_roffblkheadout
;
520 cb
.roffblkbodyin
= mlg_roffblkbodyin
;
521 cb
.roffblkbodyout
= mlg_roffblkbodyout
;
522 cb
.roffblkout
= mlg_roffblkout
;
523 cb
.roffspecial
= mlg_roffspecial
;
524 cb
.roffmsg
= mlg_roffmsg
;
525 cb
.roffdata
= mlg_roffdata
;
527 if (NULL
== (p
= calloc(1, sizeof(struct md_mlg
))))
534 (void)memcpy(&p
->cbs
, cbs
, sizeof(struct ml_cbs
));
536 if (NULL
== (p
->tree
= roff_alloc(&cb
, p
)))
538 else if ( ! (*p
->cbs
.ml_alloc
)(&p
->data
))
548 mlg_roffhead(void *arg
, const struct tm
*tm
, const char *os
,
549 const char *title
, const char *sec
, const char *vol
)
554 p
= (struct md_mlg
*)arg
;
556 mlg_mode(p
, MD_BLK_IN
);
558 if ( ! (*p
->cbs
.ml_begin
)(p
->mbuf
, p
->args
, tm
, os
, title
, sec
, vol
))
562 return(mlg_newline(p
));
567 mlg_rofftail(void *arg
)
572 p
= (struct md_mlg
*)arg
;
575 if ( ! mlg_newline(p
))
578 if ( ! (*p
->cbs
.ml_end
)(p
->mbuf
, p
->args
))
581 mlg_mode(p
, MD_BLK_OUT
);
583 return(mlg_newline(p
));
589 mlg_roffspecial(void *arg
, int tok
, const char *start
,
590 const int *argc
, const char **argv
, char **more
)
596 p
= (struct md_mlg
*)arg
;
599 * First handle macros without content.
604 p
->flags
|= ML_OVERRIDE_ONE
;
608 if (0 == strcmp(*more
, "on"))
609 p
->flags
|= ML_OVERRIDE_ALL
;
611 p
->flags
&= ~ML_OVERRIDE_ALL
;
617 if ( ! mlg_begintag(p
, MD_NS_INLINE
, tok
, NULL
, more
))
622 assert(NULL
== *argv
);
623 assert(ROFF_ARGMAX
!= *argc
);
624 if ( ! ml_puts(p
->mbuf
, mlg_St_literal(*argc
),
628 if ( ! ml_nputs(p
->mbuf
, " ", 1, &p
->pos
))
630 if ( ! ml_putstring(p
->mbuf
, *more
++, &p
->pos
))
637 mlg_err(p
, start
, start
, "missing argument");
640 if ( ! ml_puts(p
->mbuf
, *more
++, &p
->pos
))
643 if ( ! ml_nputs(p
->mbuf
, "(", 1, &p
->pos
))
645 if ( ! ml_puts(p
->mbuf
, *more
++, &p
->pos
))
647 if ( ! ml_nputs(p
->mbuf
, ")", 1, &p
->pos
))
651 mlg_err(p
, start
, start
, "too many arguments");
659 if ( ! ml_puts(p
->mbuf
, *more
++, &p
->pos
))
661 assert(NULL
== *more
);
668 (void)snprintf(buf
, sizeof(buf
),
669 mlg_fmt(tok
), *more
++);
670 if ( ! ml_puts(p
->mbuf
, buf
, &p
->pos
))
672 assert(NULL
== *more
);
675 if ( ! ml_puts(p
->mbuf
, mlg_At_literal(*more
), &p
->pos
))
687 if ( ! ml_puts(p
->mbuf
, mlg_literal(tok
), &p
->pos
))
690 if ( ! ml_nputs(p
->mbuf
, " ", 1, &p
->pos
))
692 if ( ! ml_putstring(p
->mbuf
, *more
++, &p
->pos
))
701 assert(NULL
== *more
);
702 if ( ! ml_puts(p
->mbuf
, mlg_literal(tok
), &p
->pos
))
706 mlg_err(p
, start
, start
, "`%s' not yet supported",
711 return(mlg_endtag(p
, MD_NS_INLINE
, tok
));
716 mlg_roffblkin(void *arg
, int tok
, int *argc
, char **argv
)
719 return(mlg_begintag((struct md_mlg
*)arg
,
720 MD_NS_BLOCK
, tok
, argc
, argv
));
725 mlg_roffblkout(void *arg
, int tok
)
728 return(mlg_endtag((struct md_mlg
*)arg
, MD_NS_BLOCK
, tok
));
733 mlg_roffblkbodyin(void *arg
, int tok
, int *argc
, char **argv
)
736 return(mlg_begintag((struct md_mlg
*)arg
,
737 MD_NS_BODY
, tok
, argc
, argv
));
742 mlg_roffblkbodyout(void *arg
, int tok
)
745 return(mlg_endtag((struct md_mlg
*)arg
, MD_NS_BODY
, tok
));
750 mlg_roffblkheadin(void *arg
, int tok
, int *argc
, char **argv
)
753 return(mlg_begintag((struct md_mlg
*)arg
,
754 MD_NS_HEAD
, tok
, argc
, argv
));
759 mlg_roffblkheadout(void *arg
, int tok
)
762 return(mlg_endtag((struct md_mlg
*)arg
, MD_NS_HEAD
, tok
));
767 mlg_roffin(void *arg
, int tok
, int *argc
, char **argv
)
770 return(mlg_begintag((struct md_mlg
*)arg
,
771 MD_NS_INLINE
, tok
, argc
, argv
));
776 mlg_roffout(void *arg
, int tok
)
779 return(mlg_endtag((struct md_mlg
*)arg
, MD_NS_INLINE
, tok
));
784 mlg_roffmsg(void *arg
, enum roffmsg lvl
,
785 const char *buf
, const char *pos
, char *msg
)
788 mlg_msg((struct md_mlg
*)arg
, lvl
, buf
, pos
, msg
);
793 mlg_roffdata(void *arg
, int space
, const char *start
, char *buf
)
798 p
= (struct md_mlg
*)arg
;
800 if ( ! mlg_data(p
, space
, start
, buf
))
803 mlg_mode(p
, MD_TEXT
);
810 mlg_vmsg(struct md_mlg
*p
, enum roffmsg lvl
, const char *start
,
811 const char *pos
, const char *fmt
, va_list ap
)
815 (void)vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
816 mlg_msg(p
, lvl
, start
, pos
, buf
);
821 mlg_warn(struct md_mlg
*p
, const char *start
,
822 const char *pos
, const char *fmt
, ...)
827 mlg_vmsg(p
, ROFF_WARN
, start
, pos
, fmt
, ap
);
833 mlg_err(struct md_mlg
*p
, const char *start
,
834 const char *pos
, const char *fmt
, ...)
839 mlg_vmsg(p
, ROFF_ERROR
, start
, pos
, fmt
, ap
);
845 mlg_msg(struct md_mlg
*p
, enum roffmsg lvl
,
846 const char *buf
, const char *pos
, char *msg
)
852 if ( ! (MD_WARN_ALL
& p
->args
->warnings
))
864 (void)fprintf(stderr
, "%s:%zu: %s: %s (column %zu)\n",
865 p
->rbuf
->name
, p
->rbuf
->line
, level
,
868 (void)fprintf(stderr
, "%s: %s: %s\n",
869 p
->rbuf
->name
, level
, msg
);