]>
git.cameronkatri.com Git - mandoc.git/blob - mlg.c
1 /* $Id: mlg.c,v 1.18 2008/12/07 16:41:04 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.");
238 return("#include <%s>");
254 return("is currently in beta test.");
256 return("currently under development.");
268 return("BSDI BSD/OS");
278 mlg_begintag(struct md_mlg
*p
, enum md_ns ns
, int tok
,
279 int *argc
, char **argv
)
283 assert(MD_NS_DEFAULT
!= ns
);
287 if ( ! (ML_OVERRIDE_ONE
& p
->flags
) &&
288 ! (ML_OVERRIDE_ALL
& p
->flags
) &&
289 p
->pos
+ 11 >= COLUMNS
)
290 if ( ! mlg_newline(p
))
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
))
298 if (0 == p
->pos
&& ! mlg_indent(p
))
300 mlg_mode(p
, MD_INLINE_IN
);
304 if ( ! mlg_newline(p
))
306 if ( ! mlg_indent(p
))
308 } else if ( ! mlg_indent(p
))
311 mlg_mode(p
, MD_BLK_IN
);
315 if ( ! ml_nputs(p
->mbuf
, "<", 1, &p
->pos
))
318 res
= (*p
->cbs
.ml_begintag
)(p
->mbuf
, p
->data
, p
->args
, ns
, tok
,
319 argc
, (const char **)argv
);
324 p
->pos
+= (size_t)res
;
326 if ( ! ml_nputs(p
->mbuf
, ">", 1, &p
->pos
))
333 if ( ! mlg_newline(p
))
343 mlg_endtag(struct md_mlg
*p
, enum md_ns ns
, int tok
)
347 assert(MD_NS_DEFAULT
!= ns
);
355 if ( ! mlg_newline(p
))
357 if ( ! mlg_indent(p
))
359 } else if ( ! mlg_indent(p
))
364 if ( ! ml_nputs(p
->mbuf
, "</", 2, &p
->pos
))
367 res
= (*p
->cbs
.ml_endtag
)(p
->mbuf
, p
->data
, p
->args
, ns
, tok
);
372 p
->pos
+= (size_t)res
;
374 if ( ! ml_nputs(p
->mbuf
, ">", 1, &p
->pos
))
379 mlg_mode(p
, MD_INLINE_OUT
);
382 mlg_mode(p
, MD_BLK_OUT
);
391 mlg_indent(struct md_mlg
*p
)
395 count
= p
->indent
> MAXINDENT
?
396 (size_t)MAXINDENT
: p
->indent
;
400 return(ml_putchars(p
->mbuf
, ' ', count
, &p
->pos
));
405 mlg_newline(struct md_mlg
*p
)
409 return(ml_nputs(p
->mbuf
, "\n", 1, NULL
));
414 mlg_mode(struct md_mlg
*p
, enum md_tok ns
)
417 p
->flags
&= ~ML_OVERRIDE_ONE
;
423 mlg_data(struct md_mlg
*p
, int space
, const char *start
, char *buf
)
429 assert(0 != p
->indent
);
431 if (ML_OVERRIDE_ONE
& p
->flags
||
432 ML_OVERRIDE_ALL
& p
->flags
)
438 if ( ! mlg_indent(p
))
441 c
= ml_nputstring(p
->mbuf
, buf
, sz
, &p
->pos
);
444 mlg_err(p
, start
, buf
, "bad char sequence");
447 mlg_warn(p
, start
, buf
, "bogus char sequence");
452 if (p
->indent
* INDENT
+ sz
>= COLUMNS
)
453 if ( ! mlg_newline(p
))
459 if (space
&& sz
+ p
->pos
>= COLUMNS
) {
460 if ( ! mlg_newline(p
))
462 if ( ! mlg_indent(p
))
465 if ( ! ml_nputs(p
->mbuf
, " ", 1, &p
->pos
))
469 c
= ml_nputstring(p
->mbuf
, buf
, sz
, &p
->pos
);
472 mlg_err(p
, start
, buf
, "bad char sequence");
475 mlg_warn(p
, start
, buf
, "bogus char sequence");
485 mlg_line(struct md_mlg
*p
, char *buf
)
488 return(roff_engine(p
->tree
, buf
));
493 mlg_exit(struct md_mlg
*p
, int flush
)
497 c
= roff_free(p
->tree
, flush
);
500 (*p
->cbs
.ml_free
)(p
->data
);
507 mlg_alloc(const struct md_args
*args
,
508 const struct md_rbuf
*rbuf
,
509 struct md_mbuf
*mbuf
,
510 const struct ml_cbs
*cbs
)
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
;
520 cb
.roffblkheadin
= mlg_roffblkheadin
;
521 cb
.roffblkheadout
= mlg_roffblkheadout
;
522 cb
.roffblkbodyin
= mlg_roffblkbodyin
;
523 cb
.roffblkbodyout
= mlg_roffblkbodyout
;
524 cb
.roffblkout
= mlg_roffblkout
;
525 cb
.roffspecial
= mlg_roffspecial
;
526 cb
.roffmsg
= mlg_roffmsg
;
527 cb
.roffdata
= mlg_roffdata
;
529 if (NULL
== (p
= calloc(1, sizeof(struct md_mlg
))))
536 (void)memcpy(&p
->cbs
, cbs
, sizeof(struct ml_cbs
));
538 if (NULL
== (p
->tree
= roff_alloc(&cb
, p
)))
540 else if ( ! (*p
->cbs
.ml_alloc
)(&p
->data
))
550 mlg_roffhead(void *arg
, const struct tm
*tm
, const char *os
,
551 const char *title
, const char *sec
, const char *vol
)
556 p
= (struct md_mlg
*)arg
;
558 mlg_mode(p
, MD_BLK_IN
);
560 if ( ! (*p
->cbs
.ml_begin
)(p
->mbuf
, p
->args
, tm
, os
, title
, sec
, vol
))
564 return(mlg_newline(p
));
569 mlg_rofftail(void *arg
)
574 p
= (struct md_mlg
*)arg
;
577 if ( ! mlg_newline(p
))
580 if ( ! (*p
->cbs
.ml_end
)(p
->mbuf
, p
->args
))
583 mlg_mode(p
, MD_BLK_OUT
);
585 return(mlg_newline(p
));
591 mlg_roffspecial(void *arg
, int tok
, const char *start
,
592 const int *argc
, const char **argv
, char **more
)
598 p
= (struct md_mlg
*)arg
;
601 * First handle macros without content.
606 p
->flags
|= ML_OVERRIDE_ONE
;
610 if (0 == strcmp(*more
, "on"))
611 p
->flags
|= ML_OVERRIDE_ALL
;
613 p
->flags
&= ~ML_OVERRIDE_ALL
;
620 * Handle macros put into different-token tags.
626 if ( ! mlg_begintag(p
, MD_NS_INLINE
, tok
, NULL
, more
))
628 if ( ! ml_putstring(p
->mbuf
, *more
++, &p
->pos
))
630 if ( ! mlg_endtag(p
, MD_NS_INLINE
, tok
))
633 if ( ! ml_nputs(p
->mbuf
, "(", 1, &p
->pos
))
635 p
->flags
|= ML_OVERRIDE_ONE
;
636 if ( ! mlg_begintag(p
, MD_NS_INLINE
,
637 ROFF_Fa
, NULL
, more
))
639 if ( ! ml_putstring(p
->mbuf
, *more
++, &p
->pos
))
641 if ( ! mlg_endtag(p
, MD_NS_INLINE
, ROFF_Fa
))
644 if ( ! ml_nputs(p
->mbuf
, ", ", 2, &p
->pos
))
646 if ( ! mlg_begintag(p
, MD_NS_INLINE
, ROFF_Fa
, NULL
, more
))
648 if ( ! ml_putstring(p
->mbuf
, *more
++, &p
->pos
))
650 if ( ! mlg_endtag(p
, MD_NS_INLINE
, ROFF_Fa
))
653 if ( ! ml_nputs(p
->mbuf
, ")", 1, &p
->pos
))
662 * Now handle macros in their environments.
665 if ( ! mlg_begintag(p
, MD_NS_INLINE
, tok
, NULL
, more
))
670 assert(NULL
== *argv
);
671 assert(ROFF_ARGMAX
!= *argc
);
672 if ( ! ml_puts(p
->mbuf
, mlg_St_literal(*argc
),
676 if ( ! ml_nputs(p
->mbuf
, " ", 1, &p
->pos
))
678 if ( ! ml_putstring(p
->mbuf
, *more
++, &p
->pos
))
685 mlg_err(p
, start
, start
, "missing argument");
688 if ( ! ml_puts(p
->mbuf
, *more
++, &p
->pos
))
691 if ( ! ml_nputs(p
->mbuf
, "(", 1, &p
->pos
))
693 if ( ! ml_puts(p
->mbuf
, *more
++, &p
->pos
))
695 if ( ! ml_nputs(p
->mbuf
, ")", 1, &p
->pos
))
699 mlg_err(p
, start
, start
, "too many arguments");
707 if ( ! ml_putstring(p
->mbuf
, *more
++, &p
->pos
))
709 assert(NULL
== *more
);
718 /* FIXME: *more must be ml-filtered. */
719 (void)snprintf(buf
, sizeof(buf
),
720 mlg_fmt(tok
), *more
++);
721 if ( ! ml_puts(p
->mbuf
, buf
, &p
->pos
))
723 assert(NULL
== *more
);
726 if ( ! ml_puts(p
->mbuf
, mlg_At_literal(*more
), &p
->pos
))
738 if ( ! ml_puts(p
->mbuf
, mlg_literal(tok
), &p
->pos
))
741 if ( ! ml_nputs(p
->mbuf
, " ", 1, &p
->pos
))
743 if ( ! ml_putstring(p
->mbuf
, *more
++, &p
->pos
))
752 assert(NULL
== *more
);
753 if ( ! ml_puts(p
->mbuf
, mlg_literal(tok
), &p
->pos
))
757 mlg_err(p
, start
, start
, "`%s' not yet supported",
762 return(mlg_endtag(p
, MD_NS_INLINE
, tok
));
767 mlg_roffblkin(void *arg
, int tok
, int *argc
, char **argv
)
770 return(mlg_begintag((struct md_mlg
*)arg
,
771 MD_NS_BLOCK
, tok
, argc
, argv
));
776 mlg_roffblkout(void *arg
, int tok
)
779 return(mlg_endtag((struct md_mlg
*)arg
, MD_NS_BLOCK
, tok
));
784 mlg_roffblkbodyin(void *arg
, int tok
, int *argc
, char **argv
)
787 return(mlg_begintag((struct md_mlg
*)arg
,
788 MD_NS_BODY
, tok
, argc
, argv
));
793 mlg_roffblkbodyout(void *arg
, int tok
)
796 return(mlg_endtag((struct md_mlg
*)arg
, MD_NS_BODY
, tok
));
801 mlg_roffblkheadin(void *arg
, int tok
, int *argc
, char **argv
)
804 return(mlg_begintag((struct md_mlg
*)arg
,
805 MD_NS_HEAD
, tok
, argc
, argv
));
810 mlg_roffblkheadout(void *arg
, int tok
)
813 return(mlg_endtag((struct md_mlg
*)arg
, MD_NS_HEAD
, tok
));
818 mlg_roffin(void *arg
, int tok
, int *argc
, char **argv
)
821 return(mlg_begintag((struct md_mlg
*)arg
,
822 MD_NS_INLINE
, tok
, argc
, argv
));
827 mlg_roffout(void *arg
, int tok
)
830 return(mlg_endtag((struct md_mlg
*)arg
, MD_NS_INLINE
, tok
));
835 mlg_roffmsg(void *arg
, enum roffmsg lvl
,
836 const char *buf
, const char *pos
, char *msg
)
839 mlg_msg((struct md_mlg
*)arg
, lvl
, buf
, pos
, msg
);
844 mlg_roffdata(void *arg
, int space
, const char *start
, char *buf
)
849 p
= (struct md_mlg
*)arg
;
851 if ( ! mlg_data(p
, space
, start
, buf
))
854 mlg_mode(p
, MD_TEXT
);
861 mlg_vmsg(struct md_mlg
*p
, enum roffmsg lvl
, const char *start
,
862 const char *pos
, const char *fmt
, va_list ap
)
866 (void)vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
867 mlg_msg(p
, lvl
, start
, pos
, buf
);
872 mlg_warn(struct md_mlg
*p
, const char *start
,
873 const char *pos
, const char *fmt
, ...)
878 mlg_vmsg(p
, ROFF_WARN
, start
, pos
, fmt
, ap
);
884 mlg_err(struct md_mlg
*p
, const char *start
,
885 const char *pos
, const char *fmt
, ...)
890 mlg_vmsg(p
, ROFF_ERROR
, start
, pos
, fmt
, ap
);
896 mlg_msg(struct md_mlg
*p
, enum roffmsg lvl
,
897 const char *buf
, const char *pos
, char *msg
)
903 if ( ! (MD_WARN_ALL
& p
->args
->warnings
))
915 (void)fprintf(stderr
, "%s:%zu: %s: %s (column %zu)\n",
916 p
->rbuf
->name
, p
->rbuf
->line
, level
,
919 (void)fprintf(stderr
, "%s: %s: %s\n",
920 p
->rbuf
->name
, level
, msg
);