]>
git.cameronkatri.com Git - mandoc.git/blob - html4_strict.c
d198ebad6f86ca26989b926c1990d2ae5dd68d3a
1 /* $Id: html4_strict.c,v 1.3 2008/11/23 22:30:53 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 const struct md_args *arg, \
43 struct md_mbuf *out, \
44 const struct md_rbuf *in, \
45 const char *buf, size_t sz, \
46 size_t pos, enum roffd type, \
54 int (*cb
)(ROFFCALL_ARGS
);
57 #define ROFF_NESTED (1 << 0) /* FIXME: test. */
58 #define ROFF_PARSED (1 << 1) /* FIXME: test. */
59 #define ROFF_CALLABLE (1 << 2) /* FIXME: test. */
64 struct roffnode
*parent
;
69 struct roffnode
*last
;
75 #define ROFF_PRELUDE (1 << 1)
76 #define ROFF_PRELUDE_Os (1 << 2)
77 #define ROFF_PRELUDE_Dt (1 << 3)
78 #define ROFF_PRELUDE_Dd (1 << 4)
79 #define ROFF_BODY (1 << 5)
91 static int roff_Dd(ROFFCALL_ARGS
);
92 static int roff_Dt(ROFFCALL_ARGS
);
93 static int roff_Os(ROFFCALL_ARGS
);
94 static int roff_Sh(ROFFCALL_ARGS
);
95 static int roff_An(ROFFCALL_ARGS
);
96 static int roff_Li(ROFFCALL_ARGS
);
98 static struct roffnode
*roffnode_new(int, size_t,
100 static void roffnode_free(int, struct rofftree
*);
102 static int rofffind(const char *);
103 static int roffparse(const struct md_args
*,
105 const struct md_rbuf
*,
106 const char *, size_t,
108 static int textparse(struct md_mbuf
*,
109 const struct md_rbuf
*,
110 const char *, size_t,
111 const struct rofftree
*);
113 static void dbg_enter(const struct md_args
*, int);
114 static void dbg_leave(const struct md_args
*, int);
117 static const struct rofftok tokens
[ROFF_Max
] =
119 { ROFF___
, "\\\"", NULL
, ROFF_COMMENT
, 0 },
120 { ROFF_Dd
, "Dd", roff_Dd
, ROFF_TITLE
, 0 },
121 { ROFF_Dt
, "Dt", roff_Dt
, ROFF_TITLE
, 0 },
122 { ROFF_Os
, "Os", roff_Os
, ROFF_TITLE
, 0 },
123 { ROFF_Sh
, "Sh", roff_Sh
, ROFF_LAYOUT
, 0 },
124 { ROFF_An
, "An", roff_An
, ROFF_TEXT
, ROFF_PARSED
},
125 { ROFF_Li
, "Li", roff_Li
, ROFF_TEXT
, ROFF_PARSED
| ROFF_CALLABLE
},
130 md_exit_html4_strict(const struct md_args
*args
, struct md_mbuf
*out
,
131 const struct md_rbuf
*in
, int error
, void *data
)
133 struct rofftree
*tree
;
137 tree
= (struct rofftree
*)data
;
144 if ( ! (*tokens
[tree
->last
->tok
].cb
)(args
, out
, in
,
145 NULL
, 0, 0, ROFF_EXIT
, tree
))
148 if (out
&& (ROFF_PRELUDE
& tree
->state
)) {
149 warnx("%s: prelude never finished", in
->name
);
155 return(error
? 0 : 1);
160 md_init_html4_strict(const struct md_args
*args
, struct md_mbuf
*out
,
161 const struct md_rbuf
*in
, void **data
)
163 struct rofftree
*tree
;
170 /* TODO: write HTML-DTD header. */
172 if (NULL
== (tree
= calloc(1, sizeof(struct rofftree
)))) {
177 tree
->state
= ROFF_PRELUDE
;
185 md_line_html4_strict(const struct md_args
*args
, struct md_mbuf
*out
,
186 const struct md_rbuf
*in
, const char *buf
,
187 size_t sz
, void *data
)
189 struct rofftree
*tree
;
195 tree
= (struct rofftree
*)data
;
198 warnx("%s: blank line (line %zu)", in
->name
, in
->line
);
200 } else if ('.' != *buf
)
201 return(textparse(out
, in
, buf
, sz
, tree
));
203 return(roffparse(args
, out
, in
, buf
, sz
, tree
));
208 textparse(struct md_mbuf
*out
, const struct md_rbuf
*in
,
209 const char *buf
, size_t sz
,
210 const struct rofftree
*tree
)
219 if (NULL
== tree
->last
) {
220 warnx("%s: unexpected text (line %zu)",
223 } else if (NULL
== tree
->last
->parent
) {
224 warnx("%s: disallowed text (line %zu)",
229 if ( ! md_buf_puts(out
, buf
, sz
))
231 return(md_buf_putstring(out
, " "));
236 roffparse(const struct md_args
*args
, struct md_mbuf
*out
,
237 const struct md_rbuf
*in
, const char *buf
,
238 size_t sz
, struct rofftree
*tree
)
242 struct roffnode
*node
;
252 * Extract the token identifier from the buffer. If there's no
253 * callback for the token (comment, etc.) then exit immediately.
254 * We don't do any error handling (yet), so if the token doesn't
259 warnx("%s: malformed line (line %zu)",
262 } else if (ROFF_Max
== (tokid
= rofffind(buf
+ 1))) {
263 warnx("%s: unknown line token `%c%c' (line %zu)",
264 in
->name
, *(buf
+ 1),
265 *(buf
+ 2), in
->line
);
269 /* Domain cross-contamination (and sanity) checks. */
271 switch (tokens
[tokid
].type
) {
273 if (ROFF_PRELUDE
& tree
->state
) {
274 assert( ! (ROFF_BODY
& tree
->state
));
277 assert(ROFF_BODY
& tree
->state
);
278 warnx("%s: prelude token `%s' in body (line %zu)",
279 in
->name
, tokens
[tokid
].name
, in
->line
);
284 if (ROFF_BODY
& tree
->state
) {
285 assert( ! (ROFF_PRELUDE
& tree
->state
));
288 assert(ROFF_PRELUDE
& tree
->state
);
289 warnx("%s: text token `%s' in prelude (line %zu)",
290 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; /* FIXME: de-globalise. */
418 dbg_enter(const struct md_args
*args
, int tokid
)
423 if ( ! (args
->dbg
& MD_DBG_TREE
))
426 assert(tokid
>= 0 && tokid
<= ROFF_Max
);
429 for (i
= 0; i
< dbg_lvl
; i
++)
432 (void)printf("%s\n", tokens
[tokid
].name
);
434 if (ROFF_LAYOUT
== tokens
[tokid
].type
)
440 dbg_leave(const struct md_args
*args
, int tokid
)
445 if ( ! (args
->dbg
& MD_DBG_TREE
))
447 if (ROFF_LAYOUT
!= tokens
[tokid
].type
)
450 assert(tokid
>= 0 && tokid
<= ROFF_Max
);
456 for (i
= 0; i
< dbg_lvl
; i
++)
459 (void)printf("%s\n", tokens
[tokid
].name
);
464 roff_Dd(ROFFCALL_ARGS
)
467 assert(ROFF_PRELUDE
& tree
->state
);
468 if (ROFF_PRELUDE_Dt
& tree
->state
||
469 ROFF_PRELUDE_Dd
& tree
->state
) {
470 warnx("%s: bad prelude ordering (line %zu)",
475 assert(NULL
== tree
->last
);
476 tree
->state
|= ROFF_PRELUDE_Dd
;
478 dbg_enter(arg
, ROFF_Dd
);
484 roff_Dt(ROFFCALL_ARGS
)
487 assert(ROFF_PRELUDE
& tree
->state
);
488 if ( ! (ROFF_PRELUDE_Dd
& tree
->state
) ||
489 (ROFF_PRELUDE_Dt
& tree
->state
)) {
490 warnx("%s: bad prelude ordering (line %zu)",
495 assert(NULL
== tree
->last
);
496 tree
->state
|= ROFF_PRELUDE_Dt
;
498 dbg_enter(arg
, ROFF_Dt
);
504 roff_Os(ROFFCALL_ARGS
)
507 if (ROFF_EXIT
== type
) {
508 roffnode_free(ROFF_Os
, tree
);
509 dbg_leave(arg
, ROFF_Os
);
513 assert(ROFF_PRELUDE
& tree
->state
);
514 if ( ! (ROFF_PRELUDE_Dt
& tree
->state
) ||
515 ! (ROFF_PRELUDE_Dd
& tree
->state
)) {
516 warnx("%s: bad prelude ordering (line %zu)",
521 assert(NULL
== tree
->last
);
522 if (NULL
== roffnode_new(ROFF_Os
, in
->line
, tree
))
525 tree
->state
|= ROFF_PRELUDE_Os
;
526 tree
->state
&= ~ROFF_PRELUDE
;
527 tree
->state
|= ROFF_BODY
;
529 dbg_enter(arg
, ROFF_Os
);
535 roff_Sh(ROFFCALL_ARGS
)
538 if (ROFF_EXIT
== type
) {
539 roffnode_free(ROFF_Sh
, tree
);
540 dbg_leave(arg
, ROFF_Sh
);
544 if (NULL
== roffnode_new(ROFF_Sh
, in
->line
, tree
))
547 dbg_enter(arg
, ROFF_Sh
);
553 roff_Li(ROFFCALL_ARGS
)
561 roff_An(ROFFCALL_ARGS
)