]>
git.cameronkatri.com Git - mandoc.git/blob - mlg.c
1 /* $Id: mlg.c,v 1.15 2008/12/06 19:41:41 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 void mlg_roffmsg(void *arg
, enum roffmsg
,
66 const char *, const char *, char *);
67 static int mlg_roffhead(void *, const struct tm
*,
68 const char *, const char *,
69 const char *, const char *);
70 static int mlg_rofftail(void *);
71 static int mlg_roffin(void *, int, int *, char **);
72 static int mlg_roffdata(void *, int,
73 const char *, char *);
74 static int mlg_roffout(void *, int);
75 static int mlg_roffblkin(void *, int, int *, char **);
76 static int mlg_roffblkout(void *, int);
77 static int mlg_roffspecial(void *, int,
78 const char *, char **);
79 static int mlg_roffblkheadin(void *, int,
81 static int mlg_roffblkheadout(void *, int);
82 static int mlg_roffblkbodyin(void *, int,
84 static int mlg_roffblkbodyout(void *, int);
86 static int mlg_begintag(struct md_mlg
*, enum md_ns
,
88 static int mlg_endtag(struct md_mlg
*, enum md_ns
, int);
89 static int mlg_indent(struct md_mlg
*);
90 static int mlg_newline(struct md_mlg
*);
91 static void mlg_mode(struct md_mlg
*, enum md_tok
);
92 static int mlg_data(struct md_mlg
*, int,
93 const char *, char *);
94 static void mlg_err(struct md_mlg
*, const char *,
95 const char *, const char *, ...);
96 static void mlg_warn(struct md_mlg
*, const char *,
97 const char *, const char *, ...);
98 static void mlg_msg(struct md_mlg
*, enum roffmsg
,
99 const char *, const char *, char *);
100 static void mlg_vmsg(struct md_mlg
*, enum roffmsg
,
101 const char *, const char *,
102 const char *, va_list);
105 extern size_t strlcat(char *, const char *, size_t);
106 extern size_t strlcpy(char *, const char *, size_t);
111 mlg_At_literal(const char *p
)
114 return("AT&T UNIX");
115 if (0 == strcmp(p
, "v6"))
116 return("Version 6 AT&T UNIX");
117 else if (0 == strcmp(p
, "v7"))
118 return("Version 7 AT&T UNIX");
119 else if (0 == strcmp(p
, "32v"))
120 return("Version 32v AT&T UNIX");
121 else if (0 == strcmp(p
, "V.1"))
122 return("AT&T System V.1 UNIX");
123 else if (0 == strcmp(p
, "V.4"))
124 return("AT&T System V.4 UNIX");
136 return("is currently in beta test.");
138 return("currently under development.");
150 return("BSDI BSD/OS");
160 mlg_begintag(struct md_mlg
*p
, enum md_ns ns
, int tok
,
161 int *argc
, char **argv
)
165 assert(MD_NS_DEFAULT
!= ns
);
169 if ( ! (ML_OVERRIDE_ONE
& p
->flags
) &&
170 ! (ML_OVERRIDE_ALL
& p
->flags
) &&
171 p
->pos
+ 11 >= COLUMNS
)
172 if ( ! mlg_newline(p
))
174 if (0 != p
->pos
&& (MD_TEXT
== p
->last
||
175 MD_INLINE_OUT
== p
->last
)
176 && ! (ML_OVERRIDE_ONE
& p
->flags
)
177 && ! (ML_OVERRIDE_ALL
& p
->flags
))
178 if ( ! ml_nputs(p
->mbuf
, " ", 1, &p
->pos
))
180 if (0 == p
->pos
&& ! mlg_indent(p
))
182 mlg_mode(p
, MD_INLINE_IN
);
186 if ( ! mlg_newline(p
))
188 if ( ! mlg_indent(p
))
190 } else if ( ! mlg_indent(p
))
193 mlg_mode(p
, MD_BLK_IN
);
197 if ( ! ml_nputs(p
->mbuf
, "<", 1, &p
->pos
))
200 res
= (*p
->cbs
.ml_begintag
)(p
->mbuf
, p
->data
, p
->args
, ns
, tok
,
201 argc
, (const char **)argv
);
206 p
->pos
+= (size_t)res
;
208 if ( ! ml_nputs(p
->mbuf
, ">", 1, &p
->pos
))
215 if ( ! mlg_newline(p
))
225 mlg_endtag(struct md_mlg
*p
, enum md_ns ns
, int tok
)
229 assert(MD_NS_DEFAULT
!= ns
);
237 if ( ! mlg_newline(p
))
239 if ( ! mlg_indent(p
))
241 } else if ( ! mlg_indent(p
))
246 if ( ! ml_nputs(p
->mbuf
, "</", 2, &p
->pos
))
249 res
= (*p
->cbs
.ml_endtag
)(p
->mbuf
, p
->data
, p
->args
, ns
, tok
);
254 p
->pos
+= (size_t)res
;
256 if ( ! ml_nputs(p
->mbuf
, ">", 1, &p
->pos
))
261 mlg_mode(p
, MD_INLINE_OUT
);
264 mlg_mode(p
, MD_BLK_OUT
);
273 mlg_indent(struct md_mlg
*p
)
277 count
= p
->indent
> MAXINDENT
?
278 (size_t)MAXINDENT
: p
->indent
;
282 return(ml_putchars(p
->mbuf
, ' ', count
, &p
->pos
));
287 mlg_newline(struct md_mlg
*p
)
291 return(ml_nputs(p
->mbuf
, "\n", 1, NULL
));
296 mlg_mode(struct md_mlg
*p
, enum md_tok ns
)
299 p
->flags
&= ~ML_OVERRIDE_ONE
;
305 mlg_data(struct md_mlg
*p
, int space
, const char *start
, char *buf
)
311 assert(0 != p
->indent
);
313 if (ML_OVERRIDE_ONE
& p
->flags
||
314 ML_OVERRIDE_ALL
& p
->flags
)
320 if ( ! mlg_indent(p
))
323 c
= ml_nputstring(p
->mbuf
, buf
, sz
, &p
->pos
);
326 mlg_err(p
, start
, buf
, "bad char sequence");
329 mlg_warn(p
, start
, buf
, "bogus char sequence");
334 if (p
->indent
* INDENT
+ sz
>= COLUMNS
)
335 if ( ! mlg_newline(p
))
341 if (space
&& sz
+ p
->pos
>= COLUMNS
) {
342 if ( ! mlg_newline(p
))
344 if ( ! mlg_indent(p
))
347 if ( ! ml_nputs(p
->mbuf
, " ", 1, &p
->pos
))
351 c
= ml_nputstring(p
->mbuf
, buf
, sz
, &p
->pos
);
354 mlg_err(p
, start
, buf
, "bad char sequence");
357 mlg_warn(p
, start
, buf
, "bogus char sequence");
367 mlg_line(struct md_mlg
*p
, char *buf
)
370 return(roff_engine(p
->tree
, buf
));
375 mlg_exit(struct md_mlg
*p
, int flush
)
379 c
= roff_free(p
->tree
, flush
);
382 (*p
->cbs
.ml_free
)(p
->data
);
389 mlg_alloc(const struct md_args
*args
,
390 const struct md_rbuf
*rbuf
,
391 struct md_mbuf
*mbuf
,
392 const struct ml_cbs
*cbs
)
397 cb
.roffhead
= mlg_roffhead
;
398 cb
.rofftail
= mlg_rofftail
;
399 cb
.roffin
= mlg_roffin
;
400 cb
.roffout
= mlg_roffout
;
401 cb
.roffblkin
= mlg_roffblkin
;
402 cb
.roffblkheadin
= mlg_roffblkheadin
;
403 cb
.roffblkheadout
= mlg_roffblkheadout
;
404 cb
.roffblkbodyin
= mlg_roffblkbodyin
;
405 cb
.roffblkbodyout
= mlg_roffblkbodyout
;
406 cb
.roffblkout
= mlg_roffblkout
;
407 cb
.roffspecial
= mlg_roffspecial
;
408 cb
.roffmsg
= mlg_roffmsg
;
409 cb
.roffdata
= mlg_roffdata
;
411 if (NULL
== (p
= calloc(1, sizeof(struct md_mlg
))))
418 (void)memcpy(&p
->cbs
, cbs
, sizeof(struct ml_cbs
));
420 if (NULL
== (p
->tree
= roff_alloc(&cb
, p
)))
422 else if ( ! (*p
->cbs
.ml_alloc
)(&p
->data
))
432 mlg_roffhead(void *arg
, const struct tm
*tm
, const char *os
,
433 const char *title
, const char *sec
, const char *vol
)
438 p
= (struct md_mlg
*)arg
;
440 mlg_mode(p
, MD_BLK_IN
);
442 if ( ! (*p
->cbs
.ml_begin
)(p
->mbuf
, p
->args
, tm
, os
, title
, sec
, vol
))
446 return(mlg_newline(p
));
451 mlg_rofftail(void *arg
)
456 p
= (struct md_mlg
*)arg
;
459 if ( ! mlg_newline(p
))
462 if ( ! (*p
->cbs
.ml_end
)(p
->mbuf
, p
->args
))
465 mlg_mode(p
, MD_BLK_OUT
);
467 return(mlg_newline(p
));
472 mlg_roffspecial(void *arg
, int tok
, const char *start
, char **more
)
477 p
= (struct md_mlg
*)arg
;
480 * First handle macros without content.
485 p
->flags
|= ML_OVERRIDE_ONE
;
489 if (0 == strcmp(*more
, "on"))
490 p
->flags
|= ML_OVERRIDE_ALL
;
492 p
->flags
&= ~ML_OVERRIDE_ALL
;
498 if ( ! mlg_begintag(p
, MD_NS_INLINE
, tok
, NULL
, more
))
504 mlg_err(p
, start
, start
, "missing argument");
507 if ( ! ml_puts(p
->mbuf
, *more
++, &p
->pos
))
510 if ( ! ml_nputs(p
->mbuf
, "(", 1, &p
->pos
))
512 if ( ! ml_puts(p
->mbuf
, *more
++, &p
->pos
))
514 if ( ! ml_nputs(p
->mbuf
, ")", 1, &p
->pos
))
518 mlg_err(p
, start
, start
, "too many arguments");
526 if ( ! ml_puts(p
->mbuf
, *more
++, &p
->pos
))
528 assert(NULL
== *more
);
532 if ( ! ml_puts(p
->mbuf
, "The ", &p
->pos
))
534 if ( ! mlg_begintag(p
, MD_NS_INLINE
, ROFF_Xr
, NULL
, NULL
))
536 if ( ! ml_puts(p
->mbuf
, *more
++, &p
->pos
))
538 if ( ! mlg_endtag(p
, MD_NS_INLINE
, ROFF_Xr
))
540 if ( ! ml_puts(p
->mbuf
, " utility exits 0 on success, "
541 "and >0 if an error "
544 assert(NULL
== *more
);
547 if ( ! ml_puts(p
->mbuf
, mlg_At_literal(*more
), &p
->pos
))
559 if ( ! ml_puts(p
->mbuf
, mlg_literal(tok
), &p
->pos
))
562 if ( ! ml_nputs(p
->mbuf
, " ", 1, &p
->pos
))
564 if ( ! ml_putstring(p
->mbuf
, *more
++, &p
->pos
))
573 assert(NULL
== *more
);
574 if ( ! ml_puts(p
->mbuf
, mlg_literal(tok
), &p
->pos
))
578 mlg_err(p
, start
, start
, "`%s' not yet supported",
583 return(mlg_endtag(p
, MD_NS_INLINE
, tok
));
588 mlg_roffblkin(void *arg
, int tok
, int *argc
, char **argv
)
591 return(mlg_begintag((struct md_mlg
*)arg
,
592 MD_NS_BLOCK
, tok
, argc
, argv
));
597 mlg_roffblkout(void *arg
, int tok
)
600 return(mlg_endtag((struct md_mlg
*)arg
, MD_NS_BLOCK
, tok
));
605 mlg_roffblkbodyin(void *arg
, int tok
, int *argc
, char **argv
)
608 return(mlg_begintag((struct md_mlg
*)arg
,
609 MD_NS_BODY
, tok
, argc
, argv
));
614 mlg_roffblkbodyout(void *arg
, int tok
)
617 return(mlg_endtag((struct md_mlg
*)arg
, MD_NS_BODY
, tok
));
622 mlg_roffblkheadin(void *arg
, int tok
, int *argc
, char **argv
)
625 return(mlg_begintag((struct md_mlg
*)arg
,
626 MD_NS_HEAD
, tok
, argc
, argv
));
631 mlg_roffblkheadout(void *arg
, int tok
)
634 return(mlg_endtag((struct md_mlg
*)arg
, MD_NS_HEAD
, tok
));
639 mlg_roffin(void *arg
, int tok
, int *argc
, char **argv
)
642 return(mlg_begintag((struct md_mlg
*)arg
,
643 MD_NS_INLINE
, tok
, argc
, argv
));
648 mlg_roffout(void *arg
, int tok
)
651 return(mlg_endtag((struct md_mlg
*)arg
, MD_NS_INLINE
, tok
));
656 mlg_roffmsg(void *arg
, enum roffmsg lvl
,
657 const char *buf
, const char *pos
, char *msg
)
660 mlg_msg((struct md_mlg
*)arg
, lvl
, buf
, pos
, msg
);
665 mlg_roffdata(void *arg
, int space
, const char *start
, char *buf
)
670 p
= (struct md_mlg
*)arg
;
672 if ( ! mlg_data(p
, space
, start
, buf
))
675 mlg_mode(p
, MD_TEXT
);
682 mlg_vmsg(struct md_mlg
*p
, enum roffmsg lvl
, const char *start
,
683 const char *pos
, const char *fmt
, va_list ap
)
687 (void)vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
688 mlg_msg(p
, lvl
, start
, pos
, buf
);
693 mlg_warn(struct md_mlg
*p
, const char *start
,
694 const char *pos
, const char *fmt
, ...)
699 mlg_vmsg(p
, ROFF_WARN
, start
, pos
, fmt
, ap
);
705 mlg_err(struct md_mlg
*p
, const char *start
,
706 const char *pos
, const char *fmt
, ...)
711 mlg_vmsg(p
, ROFF_ERROR
, start
, pos
, fmt
, ap
);
717 mlg_msg(struct md_mlg
*p
, enum roffmsg lvl
,
718 const char *buf
, const char *pos
, char *msg
)
724 if ( ! (MD_WARN_ALL
& p
->args
->warnings
))
736 (void)fprintf(stderr
, "%s:%zu: %s: %s (column %zu)\n",
737 p
->rbuf
->name
, p
->rbuf
->line
, level
,
740 (void)fprintf(stderr
, "%s: %s: %s\n",
741 p
->rbuf
->name
, level
, msg
);