]> git.cameronkatri.com Git - mandoc.git/blob - html.c
*** empty log message ***
[mandoc.git] / html.c
1 /* $Id: html.c,v 1.19 2008/12/10 00:52:46 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
4 *
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
8 * copies.
9 *
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.
18 */
19 #include <sys/param.h>
20 #include <sys/stat.h>
21
22 #include <assert.h>
23 #include <err.h>
24 #include <fcntl.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #include "html.h"
31 #include "ml.h"
32
33 /* TODO: allow head/tail-less invocations (just "div" start). */
34
35 struct htmlnode {
36 int tok;
37 enum md_ns ns;
38 int argc[ROFF_MAXLINEARG];
39 char *argv[ROFF_MAXLINEARG];
40 struct htmlnode *parent;
41 };
42
43 struct htmlq {
44 struct htmlnode *last;
45 };
46
47
48 static int html_loadcss(struct md_mbuf *,
49 const char *);
50 static int html_alloc(void **);
51 static void html_free(void *);
52 static ssize_t html_endtag(struct md_mbuf *, void *,
53 const struct md_args *,
54 enum md_ns, int);
55 static ssize_t html_beginstring(struct md_mbuf *,
56 const struct md_args *,
57 const char *, size_t);
58 static ssize_t html_beginhttp(struct md_mbuf *,
59 const struct md_args *,
60 const char *, size_t);
61 static ssize_t html_endstring(struct md_mbuf *,
62 const struct md_args *,
63 const char *, size_t);
64 static ssize_t html_endhttp(struct md_mbuf *,
65 const struct md_args *,
66 const char *, size_t);
67 static ssize_t html_begintag(struct md_mbuf *, void *,
68 const struct md_args *,
69 enum md_ns, int,
70 const int *, const char **);
71 static int html_begin(struct md_mbuf *,
72 const struct md_args *,
73 const struct tm *,
74 const char *, const char *,
75 enum roffmsec, const char *);
76 static int html_printargs(struct md_mbuf *, int,
77 const char *, const int *,
78 const char **, size_t *);
79 static int html_end(struct md_mbuf *,
80 const struct md_args *);
81 static int html_blocktagname(struct md_mbuf *,
82 const struct md_args *, int,
83 struct htmlq *, const int *,
84 const char **, size_t *);
85 static int html_blocktagargs(struct md_mbuf *,
86 const struct md_args *, int,
87 const int *, const char **, size_t *);
88 static int html_headtagname(struct md_mbuf *,
89 const struct md_args *, int,
90 struct htmlq *, const int *,
91 const char **, size_t *);
92 static int html_headtagargs(struct md_mbuf *,
93 const struct md_args *, int,
94 const int *, const char **, size_t *);
95 static int html_bodytagname(struct md_mbuf *,
96 const struct md_args *,
97 int, struct htmlq *, const int *,
98 const char **, size_t *);
99 static int html_bodytagargs(struct md_mbuf *,
100 const struct md_args *, int,
101 const int *, const char **, size_t *);
102 static int html_inlinetagname(struct md_mbuf *,
103 const struct md_args *, int, size_t *);
104 static int html_inlinetagargs(struct md_mbuf *,
105 const struct md_args *, int,
106 const int *, const char **, size_t *);
107 static int html_Bl_bodytagname(struct md_mbuf *,
108 struct htmlq *, const int *,
109 const char **, size_t *);
110 static int html_It_blocktagname(struct md_mbuf *,
111 struct htmlq *, const int *,
112 const char **, size_t *);
113 static int html_It_headtagname(struct md_mbuf *,
114 struct htmlq *, const int *,
115 const char **, size_t *);
116 static int html_It_bodytagname(struct md_mbuf *,
117 struct htmlq *, const int *,
118 const char **, size_t *);
119 static int html_tputln(struct md_mbuf *,
120 enum ml_scope, int, enum html_tag);
121 static int html_aputln(struct md_mbuf *, enum ml_scope,
122 int, enum html_tag,
123 int, const struct html_pair *);
124
125
126 /* ARGSUSED */
127 static int
128 html_It_headtagname(struct md_mbuf *mbuf, struct htmlq *q,
129 const int *argc, const char **argv, size_t *res)
130 {
131 struct htmlnode *n;
132 int i;
133
134 for (n = q->last; n; n = n->parent)
135 if (n->tok == ROFF_Bl)
136 break;
137
138 assert(n);
139
140 /* LINTED */
141 for (i = 0; ROFF_ARGMAX != n->argc[i] &&
142 i < ROFF_MAXLINEARG; i++) {
143 switch (n->argc[i]) {
144 case (ROFF_Ohang):
145 return(html_stput(mbuf, HTML_TAG_DIV, res));
146 case (ROFF_Tag):
147 /* FALLTHROUGH */
148 case (ROFF_Column):
149 return(html_stput(mbuf, HTML_TAG_TD, res));
150 default:
151 break;
152 }
153 }
154
155 return(0);
156 }
157
158
159 /* ARGSUSED */
160 static int
161 html_It_bodytagname(struct md_mbuf *mbuf, struct htmlq *q,
162 const int *argc, const char **argv, size_t *res)
163 {
164 struct htmlnode *n;
165 int i;
166
167 for (n = q->last; n; n = n->parent)
168 if (n->tok == ROFF_Bl)
169 break;
170
171 assert(n);
172
173 /* LINTED */
174 for (i = 0; ROFF_ARGMAX != n->argc[i] &&
175 i < ROFF_MAXLINEARG; i++) {
176 switch (n->argc[i]) {
177 case (ROFF_Enum):
178 /* FALLTHROUGH */
179 case (ROFF_Bullet):
180 /* FALLTHROUGH */
181 case (ROFF_Dash):
182 /* FALLTHROUGH */
183 case (ROFF_Hyphen):
184 /* FALLTHROUGH */
185 case (ROFF_Item):
186 /* FALLTHROUGH */
187 case (ROFF_Diag):
188 /* FALLTHROUGH */
189 case (ROFF_Hang):
190 /* FALLTHROUGH */
191 case (ROFF_Ohang):
192 /* FALLTHROUGH */
193 case (ROFF_Inset):
194 return(html_stput(mbuf, HTML_TAG_DIV, res));
195 case (ROFF_Tag):
196 /* FALLTHROUGH */
197 case (ROFF_Column):
198 return(html_stput(mbuf, HTML_TAG_TD, res));
199 default:
200 break;
201 }
202 }
203
204 assert(i != ROFF_MAXLINEARG);
205 return(0);
206 }
207
208
209 /* ARGSUSED */
210 static int
211 html_Bl_bodytagname(struct md_mbuf *mbuf, struct htmlq *q,
212 const int *argc, const char **argv, size_t *res)
213 {
214 int i;
215
216 for (i = 0; ROFF_ARGMAX != argc[i]
217 && i < ROFF_MAXLINEARG; i++) {
218 switch (argc[i]) {
219 case (ROFF_Enum):
220 return(html_stput(mbuf, HTML_TAG_OL, res));
221 case (ROFF_Bullet):
222 /* FALLTHROUGH */
223 case (ROFF_Dash):
224 /* FALLTHROUGH */
225 case (ROFF_Hyphen):
226 /* FALLTHROUGH */
227 case (ROFF_Item):
228 /* FALLTHROUGH */
229 case (ROFF_Diag):
230 /* FALLTHROUGH */
231 case (ROFF_Hang):
232 /* FALLTHROUGH */
233 case (ROFF_Ohang):
234 /* FALLTHROUGH */
235 case (ROFF_Inset):
236 return(html_stput(mbuf, HTML_TAG_UL, res));
237 case (ROFF_Tag):
238 /* FALLTHROUGH */
239 case (ROFF_Column):
240 return(html_stput(mbuf, HTML_TAG_TABLE, res));
241 default:
242 break;
243 }
244 }
245
246 assert(i != ROFF_MAXLINEARG);
247 return(0);
248 }
249
250
251 /* ARGSUSED */
252 static int
253 html_It_blocktagname(struct md_mbuf *mbuf, struct htmlq *q,
254 const int *argc, const char **argv, size_t *res)
255 {
256 struct htmlnode *n;
257 int i;
258
259 for (n = q->last; n; n = n->parent)
260 if (n->tok == ROFF_Bl)
261 break;
262
263 assert(n);
264
265 /* LINTED */
266 for (i = 0; ROFF_ARGMAX != n->argc[i] &&
267 i < ROFF_MAXLINEARG; i++) {
268 switch (n->argc[i]) {
269 case (ROFF_Enum):
270 /* FALLTHROUGH */
271 case (ROFF_Bullet):
272 /* FALLTHROUGH */
273 case (ROFF_Dash):
274 /* FALLTHROUGH */
275 case (ROFF_Hyphen):
276 /* FALLTHROUGH */
277 case (ROFF_Item):
278 /* FALLTHROUGH */
279 case (ROFF_Diag):
280 /* FALLTHROUGH */
281 case (ROFF_Hang):
282 /* FALLTHROUGH */
283 case (ROFF_Ohang):
284 /* FALLTHROUGH */
285 case (ROFF_Inset):
286 return(html_stput(mbuf, HTML_TAG_LI, res));
287 case (ROFF_Tag):
288 /* FALLTHROUGH */
289 case (ROFF_Column):
290 return(html_stput(mbuf, HTML_TAG_TR, res));
291 default:
292 break;
293 }
294 }
295
296 assert(i != ROFF_MAXLINEARG);
297 return(0);
298 }
299
300
301 static int
302 html_loadcss(struct md_mbuf *mbuf, const char *css)
303 {
304 size_t res, bufsz;
305 char *buf;
306 struct stat st;
307 int fd, c;
308 ssize_t ssz;
309
310 c = 0;
311 res = 0;
312 buf = NULL;
313
314 if (-1 == (fd = open(css, O_RDONLY, 0))) {
315 warn("%s", css);
316 return(0);
317 }
318
319 if (-1 == fstat(fd, &st)) {
320 warn("%s", css);
321 goto out;
322 }
323
324 bufsz = MAX(st.st_blksize, BUFSIZ);
325 if (NULL == (buf = malloc(bufsz))) {
326 warn("malloc");
327 goto out;
328 }
329
330 for (;;) {
331 if (-1 == (ssz = read(fd, buf, bufsz))) {
332 warn("%s", css);
333 goto out;
334 } else if (0 == ssz)
335 break;
336 if ( ! ml_nputs(mbuf, buf, (size_t)ssz, &res))
337 goto out;
338 }
339
340 c = 1;
341
342 out:
343 if (-1 == close(fd)) {
344 warn("%s", css);
345 c = 0;
346 }
347
348 if (buf)
349 free(buf);
350
351 return(c);
352 }
353
354
355 static int
356 html_tputln(struct md_mbuf *mbuf, enum ml_scope scope,
357 int i, enum html_tag tag)
358 {
359
360 if ( ! ml_putchars(mbuf, ' ', INDENT(i) * INDENT_SZ, NULL))
361 return(0);
362 if ( ! html_tput(mbuf, scope, tag, NULL))
363 return(0);
364 return(ml_nputs(mbuf, "\n", 1, NULL));
365 }
366
367
368 static int
369 html_aputln(struct md_mbuf *mbuf, enum ml_scope scope, int i,
370 enum html_tag tag, int sz, const struct html_pair *p)
371 {
372
373 if ( ! ml_putchars(mbuf, ' ', INDENT(i) * INDENT_SZ, NULL))
374 return(0);
375 if ( ! html_aput(mbuf, scope, tag, NULL, sz, p))
376 return(0);
377 return(ml_nputs(mbuf, "\n", 1, NULL));
378 }
379
380
381 /* ARGSUSED */
382 static int
383 html_begin(struct md_mbuf *mbuf, const struct md_args *args,
384 const struct tm *tm, const char *os,
385 const char *name, enum roffmsec msec, const char *vol)
386 {
387 struct html_pair attr[4];
388 char ts[32];
389 int i;
390
391 (void)snprintf(ts, sizeof(ts), "%s(%s)",
392 name, roff_msecname(msec));
393
394 i = 0;
395
396 if ( ! html_typeput(mbuf, HTML_TYPE_4_01_STRICT, NULL))
397 return(0);
398 if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_HTML))
399 return(0);
400 if ( ! html_tputln(mbuf, ML_OPEN, i++, HTML_TAG_HEAD))
401 return(0);
402
403 attr[0].attr = HTML_ATTR_HTTP_EQUIV;
404 attr[0].val = "content-type";
405 attr[1].attr = HTML_ATTR_CONTENT;
406 attr[1].val = "text/html;charset=utf-8";
407
408 if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_META, 2, attr))
409 return(0);
410
411 attr[0].attr = HTML_ATTR_NAME;
412 attr[0].val = "resource-type";
413 attr[1].attr = HTML_ATTR_CONTENT;
414 attr[1].val = "document";
415
416 if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_META, 2, attr))
417 return(0);
418
419 if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_TITLE))
420 return(0);
421 if ( ! ml_putstring(mbuf, ts, NULL))
422 return(0);
423 if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TITLE))
424 return(0);
425
426 if (HTML_CSS_EMBED & args->params.html.flags) {
427 attr[0].attr = HTML_ATTR_TYPE;
428 attr[0].val = "text/css";
429
430 if ( ! html_aputln(mbuf, ML_OPEN, i,
431 HTML_TAG_STYLE, 1, attr))
432 return(0);
433 if ( ! html_commentput(mbuf, ML_OPEN, NULL))
434 return(NULL);
435
436 if ( ! html_loadcss(mbuf, args->params.html.css))
437 return(0);
438
439 if ( ! html_commentput(mbuf, ML_CLOSE, NULL))
440 return(NULL);
441 if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_STYLE))
442 return(0);
443 } else {
444 attr[0].attr = HTML_ATTR_REL;
445 attr[0].val = "stylesheet";
446 attr[1].attr = HTML_ATTR_TYPE;
447 attr[1].val = "text/css";
448 attr[2].attr = HTML_ATTR_HREF;
449 attr[2].val = args->params.html.css;
450
451 if ( ! html_aputln(mbuf, ML_OPEN, i,
452 HTML_TAG_LINK, 3, attr))
453 return(0);
454 }
455
456 if ( ! html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_HEAD))
457 return(0);
458 if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_BODY))
459 return(0);
460
461 attr[0].attr = HTML_ATTR_CLASS;
462 attr[0].val = "mdoc";
463
464 if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_DIV, 1, attr))
465 return(0);
466
467 attr[0].attr = HTML_ATTR_WIDTH;
468 attr[0].val = "100%";
469
470 if ( ! html_aputln(mbuf, ML_OPEN, i++, HTML_TAG_TABLE, 1, attr))
471 return(0);
472 if ( ! html_tputln(mbuf, ML_OPEN, i++, HTML_TAG_TR))
473 return(0);
474
475 if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_TD))
476 return(0);
477 if ( ! ml_putstring(mbuf, ts, NULL))
478 return(0);
479 if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD))
480 return(0);
481
482 if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_TD))
483 return(0);
484 /* TODO: middle. */
485 if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD))
486 return(0);
487
488 if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_TD))
489 return(0);
490 if ( ! ml_putstring(mbuf, ts, NULL))
491 return(0);
492 if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD))
493 return(0);
494
495 if ( ! html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_TR))
496 return(0);
497 return(html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_TABLE));
498 }
499
500
501 /* ARGSUSED */
502 static int
503 html_end(struct md_mbuf *mbuf, const struct md_args *args)
504 {
505
506 if ( ! html_tputln(mbuf, ML_CLOSE, 0, HTML_TAG_DIV))
507 return(0);
508 if ( ! html_tputln(mbuf, ML_CLOSE, 0, HTML_TAG_BODY))
509 return(0);
510 return(html_tputln(mbuf, ML_CLOSE, 0, HTML_TAG_HTML));
511 }
512
513
514 /* ARGSUSED */
515 static int
516 html_bodytagname(struct md_mbuf *mbuf,
517 const struct md_args *args, int tok, struct htmlq *q,
518 const int *argc, const char **argv, size_t *res)
519 {
520
521 switch (tok) {
522 case (ROFF_Bl):
523 return(html_Bl_bodytagname(mbuf, q, argc, argv, res));
524 case (ROFF_Fo):
525 return(html_stput(mbuf, HTML_TAG_SPAN, res));
526 case (ROFF_It):
527 return(html_It_bodytagname(mbuf, q, argc, argv, res));
528 case (ROFF_Oo):
529 return(html_stput(mbuf, HTML_TAG_SPAN, res));
530 default:
531 break;
532 }
533
534 return(html_stput(mbuf, HTML_TAG_DIV, res));
535 }
536
537
538 /* ARGSUSED */
539 static int
540 html_headtagname(struct md_mbuf *mbuf,
541 const struct md_args *args, int tok, struct htmlq *q,
542 const int *argc, const char **argv, size_t *res)
543 {
544
545 switch (tok) {
546 case (ROFF_It):
547 return(html_It_headtagname(mbuf, q, argc, argv, res));
548 case (ROFF_Fo):
549 /* FALLTHROUGH */
550 case (ROFF_Oo):
551 return(html_stput(mbuf, HTML_TAG_SPAN, res));
552 case (ROFF_Sh):
553 return(html_stput(mbuf, HTML_TAG_H1, res));
554 case (ROFF_Ss):
555 return(html_stput(mbuf, HTML_TAG_H2, res));
556 default:
557 break;
558 }
559
560 return(html_stput(mbuf, HTML_TAG_DIV, res));
561 }
562
563
564 /* ARGSUSED */
565 static int
566 html_blocktagname(struct md_mbuf *mbuf, const struct md_args *args,
567 int tok, struct htmlq *q, const int *argc,
568 const char **argv, size_t *res)
569 {
570
571 switch (tok) {
572 case (ROFF_Fo):
573 /* FALLTHROUGH */
574 case (ROFF_Oo):
575 return(html_stput(mbuf, HTML_TAG_SPAN, res));
576 case (ROFF_It):
577 return(html_It_blocktagname(mbuf, q, argc, argv, res));
578 default:
579 break;
580 }
581
582 return(html_stput(mbuf, HTML_TAG_DIV, res));
583 }
584
585
586 /* ARGSUSED */
587 static int
588 html_printargs(struct md_mbuf *mbuf, int tok, const char *ns,
589 const int *argc, const char **argv, size_t *res)
590 {
591
592 /* FIXME: use API in ml.h. */
593
594 if ( ! ml_puts(mbuf, " class=\"", res))
595 return(0);
596 if ( ! ml_puts(mbuf, ns, res))
597 return(0);
598 if ( ! ml_puts(mbuf, "-", res))
599 return(0);
600 if ( ! ml_puts(mbuf, toknames[tok], res))
601 return(0);
602 return(ml_puts(mbuf, "\"", res));
603 }
604
605
606 /* ARGSUSED */
607 static int
608 html_headtagargs(struct md_mbuf *mbuf,
609 const struct md_args *args, int tok,
610 const int *argc, const char **argv, size_t *res)
611 {
612
613 return(html_printargs(mbuf, tok, "head", argc, argv, res));
614 }
615
616
617 /* ARGSUSED */
618 static int
619 html_bodytagargs(struct md_mbuf *mbuf,
620 const struct md_args *args, int tok,
621 const int *argc, const char **argv, size_t *res)
622 {
623
624 return(html_printargs(mbuf, tok, "body", argc, argv, res));
625 }
626
627
628 /* ARGSUSED */
629 static int
630 html_blocktagargs(struct md_mbuf *mbuf,
631 const struct md_args *args, int tok,
632 const int *argc, const char **argv, size_t *res)
633 {
634
635 return(html_printargs(mbuf, tok, "block", argc, argv, res));
636 }
637
638
639 /* ARGSUSED */
640 static int
641 html_inlinetagargs(struct md_mbuf *mbuf,
642 const struct md_args *args, int tok,
643 const int *argc, const char **argv, size_t *res)
644 {
645
646 if ( ! html_printargs(mbuf, tok, "inline", argc, argv, res))
647 return(0);
648
649 switch (tok) {
650 case (ROFF_Sx):
651
652 /* FIXME: use API in ml.h. */
653
654 assert(*argv);
655 if ( ! ml_nputs(mbuf, " href=\"#", 8, res))
656 return(0);
657 if ( ! ml_putstring(mbuf, *argv, res))
658 return(0);
659 if ( ! ml_nputs(mbuf, "\"", 1, res))
660 return(0);
661 break;
662 default:
663 break;
664 }
665
666 return(1);
667 }
668
669
670 /* ARGSUSED */
671 static int
672 html_inlinetagname(struct md_mbuf *mbuf,
673 const struct md_args *args, int tok, size_t *res)
674 {
675
676 switch (tok) {
677 case (ROFF_Pp):
678 return(html_stput(mbuf, HTML_TAG_DIV, res));
679 case (ROFF_Sx):
680 return(html_stput(mbuf, HTML_TAG_A, res));
681 default:
682 break;
683 }
684
685 return(html_stput(mbuf, HTML_TAG_SPAN, res));
686 }
687
688
689 static ssize_t
690 html_begintag(struct md_mbuf *mbuf, void *data,
691 const struct md_args *args, enum md_ns ns,
692 int tok, const int *argc, const char **argv)
693 {
694 size_t res;
695 struct htmlq *q;
696 struct htmlnode *node;
697 int i;
698
699 assert(ns != MD_NS_DEFAULT);
700 res = 0;
701
702 assert(data);
703 q = (struct htmlq *)data;
704
705 if (NULL == (node = calloc(1, sizeof(struct htmlnode)))) {
706 warn("calloc");
707 return(-1);
708 }
709
710 node->parent = q->last;
711 node->tok = tok;
712 node->ns = ns;
713
714 if (argc) {
715 /* TODO: argv. */
716
717 assert(argv);
718 /* LINTED */
719 for (i = 0; ROFF_ARGMAX != argc[i]
720 && i < ROFF_MAXLINEARG; i++)
721 node->argc[i] = argc[i];
722 assert(i != ROFF_MAXLINEARG);
723 }
724
725
726 q->last = node;
727
728 switch (ns) {
729 case (MD_NS_BLOCK):
730 if ( ! html_blocktagname(mbuf, args, tok,
731 q, argc, argv, &res))
732 return(-1);
733 if ( ! html_blocktagargs(mbuf, args, tok,
734 argc, argv, &res))
735 return(-1);
736 break;
737 case (MD_NS_BODY):
738 if ( ! html_bodytagname(mbuf, args, tok,
739 q, argc, argv, &res))
740 return(-1);
741 if ( ! html_bodytagargs(mbuf, args, tok,
742 argc, argv, &res))
743 return(-1);
744 break;
745 case (MD_NS_HEAD):
746 if ( ! html_headtagname(mbuf, args, tok, q,
747 argc, argv, &res))
748 return(-1);
749 if ( ! html_headtagargs(mbuf, args, tok,
750 argc, argv, &res))
751 return(-1);
752 break;
753 default:
754 if ( ! html_inlinetagname(mbuf, args, tok, &res))
755 return(-1);
756 if ( ! html_inlinetagargs(mbuf, args, tok,
757 argc, argv, &res))
758 return(-1);
759 break;
760 }
761
762 return((ssize_t)res);
763 }
764
765
766 static ssize_t
767 html_endtag(struct md_mbuf *mbuf, void *data,
768 const struct md_args *args, enum md_ns ns, int tok)
769 {
770 size_t res;
771 struct htmlq *q;
772 struct htmlnode *node;
773
774 assert(ns != MD_NS_DEFAULT);
775 res = 0;
776
777 assert(data);
778 q = (struct htmlq *)data;
779 node = q->last;
780
781 switch (ns) {
782 case (MD_NS_BLOCK):
783 if ( ! html_blocktagname(mbuf, args, tok,
784 q, node->argc,
785 (const char **)node->argv, &res))
786 return(-1);
787 break;
788 case (MD_NS_BODY):
789 if ( ! html_bodytagname(mbuf, args, tok,
790 q, node->argc,
791 (const char **)node->argv, &res))
792 return(-1);
793 break;
794 case (MD_NS_HEAD):
795 if ( ! html_headtagname(mbuf, args, tok,
796 q, node->argc,
797 (const char **)node->argv, &res))
798 return(-1);
799 break;
800 default:
801 if ( ! html_inlinetagname(mbuf, args, tok, &res))
802 return(-1);
803 break;
804 }
805
806 q->last = node->parent;
807
808 free(node);
809
810 return((ssize_t)res);
811 }
812
813
814 static int
815 html_alloc(void **p)
816 {
817
818 if (NULL == (*p = calloc(1, sizeof(struct htmlq)))) {
819 warn("calloc");
820 return(0);
821 }
822 return(1);
823 }
824
825
826 static void
827 html_free(void *p)
828 {
829 struct htmlq *q;
830 struct htmlnode *n;
831
832 assert(p);
833 q = (struct htmlq *)p;
834
835 /* LINTED */
836 while ((n = q->last)) {
837 q->last = n->parent;
838 free(n);
839 }
840
841 free(q);
842 }
843
844
845 static ssize_t
846 html_beginhttp(struct md_mbuf *mbuf,
847 const struct md_args *args,
848 const char *buf, size_t sz)
849 {
850 size_t res;
851 struct html_pair pair;
852
853 res = 0;
854 pair.attr = HTML_ATTR_HREF;
855 pair.val = (char *)buf;
856
857 if ( ! html_aput(mbuf, ML_OPEN, HTML_TAG_A, &res, 1, &pair))
858 return(-1);
859 return((ssize_t)res);
860 }
861
862
863 static ssize_t
864 html_endhttp(struct md_mbuf *mbuf,
865 const struct md_args *args,
866 const char *buf, size_t sz)
867 {
868 size_t res;
869
870 res = 0;
871 if ( ! html_tput(mbuf, ML_CLOSE, HTML_TAG_A, &res))
872 return(-1);
873 return((ssize_t)res);
874 }
875
876
877 /* ARGSUSED */
878 static ssize_t
879 html_beginstring(struct md_mbuf *mbuf,
880 const struct md_args *args,
881 const char *buf, size_t sz)
882 {
883
884 if (0 == strncmp(buf, "http://", 7))
885 return(html_beginhttp(mbuf, args, buf, sz));
886
887 return(0);
888 }
889
890
891 /* ARGSUSED */
892 static ssize_t
893 html_endstring(struct md_mbuf *mbuf,
894 const struct md_args *args,
895 const char *buf, size_t sz)
896 {
897
898 if (0 == strncmp(buf, "http://", 7))
899 return(html_endhttp(mbuf, args, buf, sz));
900
901 return(0);
902 }
903
904
905 int
906 md_line_html(void *data, char *buf)
907 {
908
909 return(mlg_line((struct md_mlg *)data, buf));
910 }
911
912
913 int
914 md_exit_html(void *data, int flush)
915 {
916
917 return(mlg_exit((struct md_mlg *)data, flush));
918 }
919
920
921 void *
922 md_init_html(const struct md_args *args,
923 struct md_mbuf *mbuf, const struct md_rbuf *rbuf)
924 {
925 struct ml_cbs cbs;
926
927 cbs.ml_alloc = html_alloc;
928 cbs.ml_free = html_free;
929 cbs.ml_begintag = html_begintag;
930 cbs.ml_endtag = html_endtag;
931 cbs.ml_begin = html_begin;
932 cbs.ml_end = html_end;
933 cbs.ml_beginstring = html_beginstring;
934 cbs.ml_endstring = html_endstring;
935
936 return(mlg_alloc(args, rbuf, mbuf, &cbs));
937 }