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