]>
git.cameronkatri.com Git - mandoc.git/blob - html4_strict.c
1 /* $Id: html4_strict.c,v 1.4 2008/11/23 23:12:47 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"
42 #define ROFFCALL_ARGS \
43 const struct md_args *arg, struct md_mbuf *out, \
44 const struct md_rbuf *in, const char *buf, size_t sz, \
45 size_t pos, enum roffd type, struct rofftree *tree
52 int (*cb
)(ROFFCALL_ARGS
);
55 #define ROFF_NESTED (1 << 0)
56 #define ROFF_PARSED (1 << 1)
57 #define ROFF_CALLABLE (1 << 2)
62 struct roffnode
*parent
;
67 struct roffnode
*last
;
73 #define ROFF_PRELUDE (1 << 1)
74 #define ROFF_PRELUDE_Os (1 << 2)
75 #define ROFF_PRELUDE_Dt (1 << 3)
76 #define ROFF_PRELUDE_Dd (1 << 4)
77 #define ROFF_BODY (1 << 5)
89 static int roff_Dd(ROFFCALL_ARGS
);
90 static int roff_Dt(ROFFCALL_ARGS
);
91 static int roff_Os(ROFFCALL_ARGS
);
92 static int roff_Sh(ROFFCALL_ARGS
);
93 static int roff_An(ROFFCALL_ARGS
);
94 static int roff_Li(ROFFCALL_ARGS
);
96 static struct roffnode
*roffnode_new(int, size_t,
98 static void roffnode_free(int, struct rofftree
*);
100 static int rofffind(const char *);
101 static int roffparse(const struct md_args
*,
103 const struct md_rbuf
*,
104 const char *, size_t,
106 static int textparse(struct md_mbuf
*,
107 const struct md_rbuf
*,
108 const char *, size_t,
109 const struct rofftree
*);
111 static void dbg_enter(const struct md_args
*, int);
112 static void dbg_leave(const struct md_args
*, int);
115 static const struct rofftok tokens
[ROFF_Max
] =
117 { ROFF___
, "\\\"", NULL
, ROFF_COMMENT
, 0 },
118 { ROFF_Dd
, "Dd", roff_Dd
, ROFF_TITLE
, 0 },
119 { ROFF_Dt
, "Dt", roff_Dt
, ROFF_TITLE
, 0 },
120 { ROFF_Os
, "Os", roff_Os
, ROFF_TITLE
, 0 },
121 { ROFF_Sh
, "Sh", roff_Sh
, ROFF_LAYOUT
, 0 },
122 { ROFF_An
, "An", roff_An
, ROFF_TEXT
, ROFF_PARSED
},
123 { ROFF_Li
, "Li", roff_Li
, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
},
128 md_exit_html4_strict(const struct md_args
*args
, struct md_mbuf
*out
,
129 const struct md_rbuf
*in
, int error
, void *data
)
131 struct rofftree
*tree
;
135 tree
= (struct rofftree
*)data
;
142 if ( ! (*tokens
[tree
->last
->tok
].cb
)(args
, out
, in
,
143 NULL
, 0, 0, ROFF_EXIT
, tree
))
146 if (out
&& (ROFF_PRELUDE
& tree
->state
)) {
147 warnx("%s: prelude never finished", in
->name
);
153 return(error
? 0 : 1);
158 md_init_html4_strict(const struct md_args
*args
, struct md_mbuf
*out
,
159 const struct md_rbuf
*in
, void **data
)
161 struct rofftree
*tree
;
168 /* TODO: write HTML-DTD header. */
170 if (NULL
== (tree
= calloc(1, sizeof(struct rofftree
)))) {
175 tree
->state
= ROFF_PRELUDE
;
183 md_line_html4_strict(const struct md_args
*args
, struct md_mbuf
*out
,
184 const struct md_rbuf
*in
, const char *buf
,
185 size_t sz
, void *data
)
187 struct rofftree
*tree
;
193 tree
= (struct rofftree
*)data
;
196 warnx("%s: blank line (line %zu)", in
->name
, in
->line
);
198 } else if ('.' != *buf
)
199 return(textparse(out
, in
, buf
, sz
, tree
));
201 return(roffparse(args
, out
, in
, buf
, sz
, tree
));
206 textparse(struct md_mbuf
*out
, const struct md_rbuf
*in
,
207 const char *buf
, size_t sz
,
208 const struct rofftree
*tree
)
217 if (NULL
== tree
->last
) {
218 warnx("%s: unexpected text (line %zu)",
221 } else if (NULL
== tree
->last
->parent
) {
222 warnx("%s: disallowed text (line %zu)",
227 if ( ! md_buf_puts(out
, buf
, sz
))
229 return(md_buf_putstring(out
, " "));
234 roffparse(const struct md_args
*args
, struct md_mbuf
*out
,
235 const struct md_rbuf
*in
, const char *buf
,
236 size_t sz
, struct rofftree
*tree
)
240 struct roffnode
*node
;
250 * Extract the token identifier from the buffer. If there's no
251 * callback for the token (comment, etc.) then exit immediately.
252 * We don't do any error handling (yet), so if the token doesn't
257 warnx("%s: malformed line (line %zu)",
260 } else if (ROFF_Max
== (tokid
= rofffind(buf
+ 1))) {
261 warnx("%s: unknown line token `%c%c' (line %zu)",
262 in
->name
, *(buf
+ 1),
263 *(buf
+ 2), in
->line
);
267 /* Domain cross-contamination (and sanity) checks. */
269 switch (tokens
[tokid
].type
) {
271 if (ROFF_PRELUDE
& tree
->state
) {
272 assert( ! (ROFF_BODY
& tree
->state
));
275 assert(ROFF_BODY
& tree
->state
);
276 warnx("%s: prelude token `%s' in body (line %zu)",
277 in
->name
, tokens
[tokid
].name
, in
->line
);
282 if (ROFF_BODY
& tree
->state
) {
283 assert( ! (ROFF_PRELUDE
& tree
->state
));
286 assert(ROFF_PRELUDE
& tree
->state
);
287 warnx("%s: body token `%s' in prelude (line %zu)",
288 in
->name
, tokens
[tokid
].name
, in
->line
);
297 * Text-domain checks.
300 if (ROFF_TEXT
== tokens
[tokid
].type
&&
301 ! (ROFF_PARSED
& tokens
[tokid
].flags
)) {
302 warnx("%s: text token `%s' not callable (line %zu)",
303 in
->name
, tokens
[tokid
].name
, in
->line
);
308 * If this is a non-nestable layout token and we're below a
309 * token of the same type, then recurse upward to the token,
310 * closing out the interim scopes.
312 * If there's a nested token on the chain, then raise an error
313 * as nested tokens have corresponding "ending" tokens and we're
314 * breaking their scope.
320 if (ROFF_LAYOUT
== tokens
[tokid
].type
&&
321 ! (ROFF_NESTED
& tokens
[tokid
].flags
)) {
322 for (node
= tree
->last
; node
; node
= node
->parent
) {
323 if (node
->tok
== tokid
)
326 /* Don't break nested scope. */
328 if ( ! (ROFF_NESTED
& tokens
[node
->tok
].flags
))
330 warnx("%s: scope of %s (line %zu) broken by "
331 "%s (line %zu)", in
->name
,
334 tokens
[node
->tok
].name
,
341 assert(ROFF_LAYOUT
== tokens
[tokid
].type
);
342 assert( ! (ROFF_NESTED
& tokens
[tokid
].flags
));
343 assert(node
->tok
== tokid
);
345 /* Clear up to last scoped token. */
350 if ( ! (*tokens
[tree
->last
->tok
].cb
)
351 (args
, out
, in
, NULL
,
352 0, 0, ROFF_EXIT
, tree
))
354 } while (t
!= tokid
);
357 /* Proceed with actual token processing. */
359 return((*tokens
[tokid
].cb
)(args
, out
, in
, buf
, sz
,
360 pos
, ROFF_ENTER
, tree
));
365 rofffind(const char *name
)
370 /* FIXME: use a table, this is slow but ok for now. */
373 for (i
= 0; i
< ROFF_Max
; i
++)
375 if (0 == strncmp(name
, tokens
[i
].name
, 2))
382 static struct roffnode
*
383 roffnode_new(int tokid
, size_t line
, struct rofftree
*tree
)
387 if (NULL
== (p
= malloc(sizeof(struct roffnode
)))) {
394 p
->parent
= tree
->last
;
401 roffnode_free(int tokid
, struct rofftree
*tree
)
406 assert(tree
->last
->tok
== tokid
);
409 tree
->last
= tree
->last
->parent
;
414 static int dbg_lvl
= 0;
418 dbg_enter(const struct md_args
*args
, int tokid
)
424 if ( ! (args
->dbg
& MD_DBG_TREE
))
426 assert(tokid
>= 0 && tokid
<= ROFF_Max
);
430 switch (tokens
[tokid
].type
) {
434 (void)strlcat(buf
, "body: ", sizeof(buf
));
437 (void)strlcat(buf
, "prelude: ", sizeof(buf
));
444 for (i
= 0; i
< dbg_lvl
; i
++)
445 (void)strlcat(buf
, " ", sizeof(buf
));
447 (void)strlcat(buf
, tokens
[tokid
].name
, sizeof(buf
));
449 (void)printf("%s\n", buf
);
451 if (ROFF_LAYOUT
== tokens
[tokid
].type
)
457 dbg_leave(const struct md_args
*args
, int tokid
)
460 if ( ! (args
->dbg
& MD_DBG_TREE
))
462 if (ROFF_LAYOUT
!= tokens
[tokid
].type
)
465 assert(tokid
>= 0 && tokid
<= ROFF_Max
);
472 roff_Dd(ROFFCALL_ARGS
)
475 assert(ROFF_PRELUDE
& tree
->state
);
476 if (ROFF_PRELUDE_Dt
& tree
->state
||
477 ROFF_PRELUDE_Dd
& tree
->state
) {
478 warnx("%s: prelude `Dd' out-of-order (line %zu)",
483 assert(NULL
== tree
->last
);
484 tree
->state
|= ROFF_PRELUDE_Dd
;
486 dbg_enter(arg
, ROFF_Dd
);
492 roff_Dt(ROFFCALL_ARGS
)
495 assert(ROFF_PRELUDE
& tree
->state
);
496 if ( ! (ROFF_PRELUDE_Dd
& tree
->state
) ||
497 (ROFF_PRELUDE_Dt
& tree
->state
)) {
498 warnx("%s: prelude `Dt' out-of-order (line %zu)",
503 assert(NULL
== tree
->last
);
504 tree
->state
|= ROFF_PRELUDE_Dt
;
506 dbg_enter(arg
, ROFF_Dt
);
512 roff_Os(ROFFCALL_ARGS
)
515 if (ROFF_EXIT
== type
) {
516 roffnode_free(ROFF_Os
, tree
);
517 dbg_leave(arg
, ROFF_Os
);
521 assert(ROFF_PRELUDE
& tree
->state
);
522 if ( ! (ROFF_PRELUDE_Dt
& tree
->state
) ||
523 ! (ROFF_PRELUDE_Dd
& tree
->state
)) {
524 warnx("%s: prelude `Os' out-of-order (line %zu)",
529 assert(NULL
== tree
->last
);
530 if (NULL
== roffnode_new(ROFF_Os
, in
->line
, tree
))
533 tree
->state
|= ROFF_PRELUDE_Os
;
534 tree
->state
&= ~ROFF_PRELUDE
;
535 tree
->state
|= ROFF_BODY
;
537 dbg_enter(arg
, ROFF_Os
);
543 roff_Sh(ROFFCALL_ARGS
)
546 if (ROFF_EXIT
== type
) {
547 roffnode_free(ROFF_Sh
, tree
);
548 dbg_leave(arg
, ROFF_Sh
);
552 if (NULL
== roffnode_new(ROFF_Sh
, in
->line
, tree
))
555 dbg_enter(arg
, ROFF_Sh
);
561 roff_Li(ROFFCALL_ARGS
)
569 roff_An(ROFFCALL_ARGS
)