]>
git.cameronkatri.com Git - mandoc.git/blob - mlg.c
1 /* $Id: mlg.c,v 1.22 2008/12/08 16:29: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)
62 static void mlg_roffmsg(void *arg
,
63 enum roffmsg
, const char *,
64 const char *, const char *);
65 static int mlg_roffhead(void *, const struct tm
*,
66 const char *, const char *,
67 enum roffmsec
, const char *);
68 static int mlg_rofftail(void *);
69 static int mlg_roffin(void *, int,
70 int *, const char **);
71 static int mlg_roffdata(void *, int,
72 const char *, const char *);
73 static int mlg_roffout(void *, int);
74 static int mlg_roffblkin(void *, int, int *,
76 static int mlg_roffblkout(void *, int);
77 static int mlg_roffspecial(void *, int,
78 const char *, const int *,
79 const char **, const char **);
80 static int mlg_roffblkheadin(void *, int,
81 int *, const char **);
82 static int mlg_roffblkheadout(void *, int);
83 static int mlg_roffblkbodyin(void *, int,
84 int *, const char **);
85 static int mlg_roffblkbodyout(void *, int);
87 static int mlg_ref_special(struct md_mlg
*, int,
88 const char *, const char **);
89 static int mlg_formatted_special(struct md_mlg
*,
91 const char **, const char **);
92 static int mlg_literal_special(struct md_mlg
*,
93 int, const char *, const int *,
94 const char **, const char **);
95 static int mlg_function_special(struct md_mlg
*,
96 const char *, const char **);
97 static int mlg_atom_special(struct md_mlg
*, int,
98 const char *, const char **);
100 static int mlg_begintag(struct md_mlg
*, enum md_ns
,
101 int, int *, const char **);
102 static int mlg_endtag(struct md_mlg
*, enum md_ns
, int);
103 static int mlg_indent(struct md_mlg
*);
104 static int mlg_newline(struct md_mlg
*);
105 static void mlg_mode(struct md_mlg
*, enum md_tok
);
106 static int mlg_nstring(struct md_mlg
*,
107 const char *, const char *, size_t);
108 static int mlg_string(struct md_mlg
*,
109 const char *, const char *);
110 static int mlg_data(struct md_mlg
*, int,
111 const char *, const char *);
112 static void mlg_err(struct md_mlg
*, const char *,
113 const char *, const char *, ...);
114 static void mlg_msg(struct md_mlg
*,
115 enum roffmsg
, const char *,
116 const char *, const char *);
117 static void mlg_vmsg(struct md_mlg
*, enum roffmsg
,
118 const char *, const char *,
119 const char *, va_list);
122 extern size_t strlcat(char *, const char *, size_t);
123 extern size_t strlcpy(char *, const char *, size_t);
128 mlg_begintag(struct md_mlg
*p
, enum md_ns ns
, int tok
,
129 int *argc
, const char **argv
)
133 assert(MD_NS_DEFAULT
!= ns
);
137 if ( ! (ML_OVERRIDE_ONE
& p
->flags
) &&
138 ! (ML_OVERRIDE_ALL
& p
->flags
) &&
139 p
->pos
+ 11 >= COLUMNS
)
140 if ( ! mlg_newline(p
))
142 if (0 != p
->pos
&& (MD_TEXT
== p
->last
||
143 MD_INLINE_OUT
== p
->last
)
144 && ! (ML_OVERRIDE_ONE
& p
->flags
)
145 && ! (ML_OVERRIDE_ALL
& p
->flags
))
146 if ( ! ml_nputs(p
->mbuf
, " ", 1, &p
->pos
))
148 if (0 == p
->pos
&& ! mlg_indent(p
))
150 mlg_mode(p
, MD_INLINE_IN
);
154 if ( ! mlg_newline(p
))
156 if ( ! mlg_indent(p
))
158 } else if ( ! mlg_indent(p
))
161 mlg_mode(p
, MD_BLK_IN
);
165 if ( ! ml_nputs(p
->mbuf
, "<", 1, &p
->pos
))
168 res
= (*p
->cbs
.ml_begintag
)(p
->mbuf
, p
->data
,
169 p
->args
, ns
, tok
, argc
, argv
);
174 p
->pos
+= (size_t)res
;
176 if ( ! ml_nputs(p
->mbuf
, ">", 1, &p
->pos
))
183 if ( ! mlg_newline(p
))
193 mlg_endtag(struct md_mlg
*p
, enum md_ns ns
, int tok
)
197 assert(MD_NS_DEFAULT
!= ns
);
205 if ( ! mlg_newline(p
))
207 if ( ! mlg_indent(p
))
209 } else if ( ! mlg_indent(p
))
214 if ( ! ml_nputs(p
->mbuf
, "</", 2, &p
->pos
))
217 res
= (*p
->cbs
.ml_endtag
)(p
->mbuf
, p
->data
, p
->args
, ns
, tok
);
222 p
->pos
+= (size_t)res
;
224 if ( ! ml_nputs(p
->mbuf
, ">", 1, &p
->pos
))
229 mlg_mode(p
, MD_INLINE_OUT
);
232 mlg_mode(p
, MD_BLK_OUT
);
241 mlg_indent(struct md_mlg
*p
)
245 count
= p
->indent
> MAXINDENT
?
246 (size_t)MAXINDENT
: p
->indent
;
250 return(ml_putchars(p
->mbuf
, ' ', count
, &p
->pos
));
255 mlg_newline(struct md_mlg
*p
)
259 return(ml_nputs(p
->mbuf
, "\n", 1, NULL
));
264 mlg_mode(struct md_mlg
*p
, enum md_tok ns
)
267 p
->flags
&= ~ML_OVERRIDE_ONE
;
273 mlg_string(struct md_mlg
*p
, const char *start
, const char *buf
)
276 return(mlg_nstring(p
, start
, buf
, strlen(buf
)));
281 mlg_nstring(struct md_mlg
*p
, const char *start
,
282 const char *buf
, size_t sz
)
288 assert(0 != p
->indent
);
290 res
= (*p
->cbs
.ml_beginstring
)(p
->mbuf
, p
->args
, buf
, sz
);
294 if (0 == (c
= ml_nputstring(p
->mbuf
, buf
, sz
, &p
->pos
))) {
295 mlg_err(p
, start
, buf
, "bad string "
296 "encoding: `%s'", buf
);
301 res
= (*p
->cbs
.ml_endstring
)(p
->mbuf
, p
->args
, buf
, sz
);
310 mlg_data(struct md_mlg
*p
, int space
,
311 const char *start
, const char *buf
)
316 assert(0 != p
->indent
);
318 if (ML_OVERRIDE_ONE
& p
->flags
||
319 ML_OVERRIDE_ALL
& p
->flags
)
325 if ( ! mlg_indent(p
))
327 if ( ! mlg_nstring(p
, start
, buf
, sz
))
330 if (p
->indent
* INDENT
+ sz
>= COLUMNS
)
331 if ( ! mlg_newline(p
))
337 if (space
&& sz
+ p
->pos
>= COLUMNS
) {
338 if ( ! mlg_newline(p
))
340 if ( ! mlg_indent(p
))
343 if ( ! ml_nputs(p
->mbuf
, " ", 1, &p
->pos
))
347 return(mlg_nstring(p
, start
, buf
, sz
));
352 mlg_line(struct md_mlg
*p
, char *buf
)
355 return(roff_engine(p
->tree
, buf
));
360 mlg_exit(struct md_mlg
*p
, int flush
)
364 c
= roff_free(p
->tree
, flush
);
365 (*p
->cbs
.ml_free
)(p
->data
);
374 mlg_alloc(const struct md_args
*args
,
375 const struct md_rbuf
*rbuf
,
376 struct md_mbuf
*mbuf
,
377 const struct ml_cbs
*cbs
)
382 cb
.roffhead
= mlg_roffhead
;
383 cb
.rofftail
= mlg_rofftail
;
384 cb
.roffin
= mlg_roffin
;
385 cb
.roffout
= mlg_roffout
;
386 cb
.roffblkin
= mlg_roffblkin
;
387 cb
.roffblkheadin
= mlg_roffblkheadin
;
388 cb
.roffblkheadout
= mlg_roffblkheadout
;
389 cb
.roffblkbodyin
= mlg_roffblkbodyin
;
390 cb
.roffblkbodyout
= mlg_roffblkbodyout
;
391 cb
.roffblkout
= mlg_roffblkout
;
392 cb
.roffspecial
= mlg_roffspecial
;
393 cb
.roffmsg
= mlg_roffmsg
;
394 cb
.roffdata
= mlg_roffdata
;
396 if (NULL
== (p
= calloc(1, sizeof(struct md_mlg
))))
403 (void)memcpy(&p
->cbs
, cbs
, sizeof(struct ml_cbs
));
405 if (NULL
== (p
->tree
= roff_alloc(&cb
, p
)))
407 else if ( ! (*p
->cbs
.ml_alloc
)(&p
->data
))
417 mlg_roffhead(void *arg
, const struct tm
*tm
, const char *os
,
418 const char *title
, enum roffmsec sec
, const char *vol
)
423 p
= (struct md_mlg
*)arg
;
425 mlg_mode(p
, MD_BLK_IN
);
427 if ( ! (*p
->cbs
.ml_begin
)(p
->mbuf
, p
->args
, tm
, os
, title
, sec
, vol
))
431 return(mlg_newline(p
));
436 mlg_rofftail(void *arg
)
441 p
= (struct md_mlg
*)arg
;
444 if ( ! mlg_newline(p
))
447 if ( ! (*p
->cbs
.ml_end
)(p
->mbuf
, p
->args
))
450 mlg_mode(p
, MD_BLK_OUT
);
452 return(mlg_newline(p
));
457 mlg_literal_special(struct md_mlg
*p
, int tok
, const char *start
,
458 const int *argc
, const char **argv
, const char **more
)
462 if ( ! mlg_begintag(p
, MD_NS_INLINE
, tok
, NULL
, more
))
465 /* FIXME: must be ml-filtered. */
467 lit
= ml_literal(tok
, argc
, argv
, more
);
470 if ( ! ml_puts(p
->mbuf
, lit
, &p
->pos
))
473 if ( ! ml_nputs(p
->mbuf
, " ", 1, &p
->pos
))
475 if ( ! mlg_string(p
, start
, *more
++))
479 return(mlg_endtag(p
, MD_NS_INLINE
, tok
));
484 mlg_ref_special(struct md_mlg
*p
, int tok
,
485 const char *start
, const char **more
)
488 if ( ! mlg_begintag(p
, MD_NS_INLINE
, tok
, NULL
, more
))
492 if ( ! ml_puts(p
->mbuf
, *more
++, &p
->pos
))
496 if ( ! ml_nputs(p
->mbuf
, "(", 1, &p
->pos
))
498 if ( ! mlg_string(p
, start
, *more
++))
500 if ( ! ml_nputs(p
->mbuf
, ")", 1, &p
->pos
))
504 assert(NULL
== *more
);
505 return(mlg_endtag(p
, MD_NS_INLINE
, tok
));
510 mlg_formatted_special(struct md_mlg
*p
, int tok
,
511 const int *argc
, const char **argv
, const char **more
)
515 if ( ! mlg_begintag(p
, MD_NS_INLINE
, tok
, NULL
, more
))
518 /* FIXME: must be ml-filtered. */
520 lit
= ml_literal(tok
, argc
, argv
, more
);
524 (void)snprintf(buf
, sizeof(buf
), lit
, *more
++);
525 assert(NULL
== *more
);
527 if ( ! ml_puts(p
->mbuf
, buf
, &p
->pos
))
530 return(mlg_endtag(p
, MD_NS_INLINE
, tok
));
535 mlg_atom_special(struct md_mlg
*p
, int tok
,
536 const char *start
, const char **more
)
539 if ( ! mlg_begintag(p
, MD_NS_INLINE
, tok
, NULL
, more
))
543 if ( ! mlg_string(p
, start
, *more
++))
546 /*assert(NULL == *more);*/ /* FIXME: ROFF_Sx */
547 return(mlg_endtag(p
, MD_NS_INLINE
, tok
));
552 mlg_function_special(struct md_mlg
*p
,
553 const char *start
, const char **more
)
558 if ( ! mlg_begintag(p
, MD_NS_INLINE
, ROFF_Fn
, NULL
, more
))
560 if ( ! mlg_string(p
, start
, *more
++))
562 if ( ! mlg_endtag(p
, MD_NS_INLINE
, ROFF_Fn
))
568 if ( ! ml_nputs(p
->mbuf
, "(", 1, &p
->pos
))
571 p
->flags
|= ML_OVERRIDE_ONE
;
573 if ( ! mlg_begintag(p
, MD_NS_INLINE
, ROFF_Fa
, NULL
, more
))
575 if ( ! mlg_string(p
, start
, *more
++))
577 if ( ! mlg_endtag(p
, MD_NS_INLINE
, ROFF_Fa
))
581 if ( ! ml_nputs(p
->mbuf
, ", ", 2, &p
->pos
))
583 if ( ! mlg_begintag(p
, MD_NS_INLINE
, ROFF_Fa
, NULL
, more
))
585 if ( ! mlg_string(p
, start
, *more
++))
587 if ( ! mlg_endtag(p
, MD_NS_INLINE
, ROFF_Fa
))
591 return(ml_nputs(p
->mbuf
, ")", 1, &p
->pos
));
597 mlg_roffspecial(void *arg
, int tok
, const char *start
,
598 const int *argc
, const char **argv
, const char **more
)
603 p
= (struct md_mlg
*)arg
;
607 p
->flags
|= ML_OVERRIDE_ONE
;
612 if (0 == strcmp(*more
, "on"))
613 p
->flags
|= ML_OVERRIDE_ALL
;
615 p
->flags
&= ~ML_OVERRIDE_ALL
;
619 return(mlg_function_special(p
, start
, more
));
622 return(mlg_ref_special(p
, tok
, start
, more
));
624 case (ROFF_Sx
): /* FIXME */
627 return(mlg_atom_special(p
, tok
, start
, more
));
634 return(mlg_formatted_special(p
, tok
,
656 return(mlg_literal_special(p
, tok
, start
,
662 mlg_err(p
, start
, start
, "`%s' not yet supported",
669 mlg_roffblkin(void *arg
, int tok
,
670 int *argc
, const char **argv
)
673 return(mlg_begintag((struct md_mlg
*)arg
,
674 MD_NS_BLOCK
, tok
, argc
, argv
));
679 mlg_roffblkout(void *arg
, int tok
)
682 return(mlg_endtag((struct md_mlg
*)arg
, MD_NS_BLOCK
, tok
));
687 mlg_roffblkbodyin(void *arg
, int tok
,
688 int *argc
, const char **argv
)
691 return(mlg_begintag((struct md_mlg
*)arg
,
692 MD_NS_BODY
, tok
, argc
, argv
));
697 mlg_roffblkbodyout(void *arg
, int tok
)
700 return(mlg_endtag((struct md_mlg
*)arg
, MD_NS_BODY
, tok
));
705 mlg_roffblkheadin(void *arg
, int tok
,
706 int *argc
, const char **argv
)
709 return(mlg_begintag((struct md_mlg
*)arg
,
710 MD_NS_HEAD
, tok
, argc
, argv
));
715 mlg_roffblkheadout(void *arg
, int tok
)
718 return(mlg_endtag((struct md_mlg
*)arg
, MD_NS_HEAD
, tok
));
723 mlg_roffin(void *arg
, int tok
, int *argc
, const char **argv
)
726 return(mlg_begintag((struct md_mlg
*)arg
,
727 MD_NS_INLINE
, tok
, argc
, argv
));
732 mlg_roffout(void *arg
, int tok
)
735 return(mlg_endtag((struct md_mlg
*)arg
, MD_NS_INLINE
, tok
));
740 mlg_roffmsg(void *arg
, enum roffmsg lvl
, const char *buf
,
741 const char *pos
, const char *msg
)
744 mlg_msg((struct md_mlg
*)arg
, lvl
, buf
, pos
, msg
);
749 mlg_roffdata(void *arg
, int space
,
750 const char *start
, const char *buf
)
755 p
= (struct md_mlg
*)arg
;
757 if ( ! mlg_data(p
, space
, start
, buf
))
760 mlg_mode(p
, MD_TEXT
);
766 mlg_vmsg(struct md_mlg
*p
, enum roffmsg lvl
, const char *start
,
767 const char *pos
, const char *fmt
, va_list ap
)
771 (void)vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
772 mlg_msg(p
, lvl
, start
, pos
, buf
);
777 mlg_err(struct md_mlg
*p
, const char *start
,
778 const char *pos
, const char *fmt
, ...)
783 mlg_vmsg(p
, ROFF_ERROR
, start
, pos
, fmt
, ap
);
789 mlg_msg(struct md_mlg
*p
, enum roffmsg lvl
,
790 const char *buf
, const char *pos
, const char *msg
)
798 if ( ! (MD_WARN_ALL
& p
->args
->warnings
))
811 if (0 < p
->args
->verbosity
) {
812 (void)snprintf(b
, sizeof(b
),
814 p
->rbuf
->name
, p
->rbuf
->line
,
816 (void)strlcat(b
, "Error at: ", sizeof(b
));
817 (void)strlcat(b
, p
->rbuf
->linebuf
, sizeof(b
));
819 (void)strlcat(b
, "\n ", sizeof(b
));
820 for (i
= 0; i
< pos
- buf
; i
++)
821 (void)strlcat(b
, " ", sizeof(b
));
822 (void)strlcat(b
, "^", sizeof(b
));
825 (void)snprintf(b
, sizeof(b
),
826 "%s:%zu: %s: %s (col %zu)",
827 p
->rbuf
->name
, p
->rbuf
->line
,
828 level
, msg
, pos
- buf
);
830 (void)snprintf(b
, sizeof(b
), "%s: %s: %s",
831 p
->rbuf
->name
, level
, msg
);
833 (void)fprintf(stderr
, "%s\n", b
);