1 /* $Id: mdoc_html.c,v 1.182 2011/11/03 20:37:00 schwarze Exp $ */
2 /*
3 * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
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 above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include <sys/types.h>
22
23 #include <assert.h>
24 #include <ctype.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #include "mandoc.h"
31 #include "out.h"
32 #include "html.h"
33 #include "mdoc.h"
34 #include "main.h"
35
36 #define INDENT 5
37
38 #define MDOC_ARGS const struct mdoc_meta *m, \
39 const struct mdoc_node *n, \
40 struct html *h
41
42 #ifndef MIN
43 #define MIN(a,b) ((/*CONSTCOND*/(a)<(b))?(a):(b))
44 #endif
45
46 struct htmlmdoc {
47 int (*pre)(MDOC_ARGS);
48 void (*post)(MDOC_ARGS);
49 };
50
51 static void print_mdoc(MDOC_ARGS);
52 static void print_mdoc_head(MDOC_ARGS);
53 static void print_mdoc_node(MDOC_ARGS);
54 static void print_mdoc_nodelist(MDOC_ARGS);
55 static void synopsis_pre(struct html *,
56 const struct mdoc_node *);
57
58 static void a2width(const char *, struct roffsu *);
243 {mdoc__x_pre, mdoc__x_post}, /* %U */
244 {NULL, NULL}, /* Ta */
245 };
246
247 static const char * const lists[LIST_MAX] = {
248 NULL,
249 "list-bul",
250 "list-col",
251 "list-dash",
252 "list-diag",
253 "list-enum",
254 "list-hang",
255 "list-hyph",
256 "list-inset",
257 "list-item",
258 "list-ohang",
259 "list-tag"
260 };
261
262 void
263 html_mdoc(void *arg, const struct mdoc *m)
264 {
265
266 print_mdoc(mdoc_meta(m), mdoc_node(m), (struct html *)arg);
267 putchar('\n');
268 }
269
270
271 /*
272 * Calculate the scaling unit passed in a `-width' argument. This uses
273 * either a native scaling unit (e.g., 1i, 2m) or the string length of
274 * the value.
275 */
276 static void
277 a2width(const char *p, struct roffsu *su)
278 {
279
280 if ( ! a2roffsu(p, su, SCALE_MAX)) {
281 su->unit = SCALE_BU;
282 su->scale = html_strlen(p);
283 }
284 }
285
286
344 SCALE_HS_INIT(su, INDENT);
345 else if (0 == strcmp(p, "indent-two"))
346 SCALE_HS_INIT(su, INDENT * 2);
347 else if ( ! a2roffsu(p, su, SCALE_MAX))
348 SCALE_HS_INIT(su, html_strlen(p));
349 }
350
351
352 static void
353 print_mdoc(MDOC_ARGS)
354 {
355 struct tag *t, *tt;
356 struct htmlpair tag;
357
358 PAIR_CLASS_INIT(&tag, "mandoc");
359
360 if ( ! (HTML_FRAGMENT & h->oflags)) {
361 print_gen_decls(h);
362 t = print_otag(h, TAG_HTML, 0, NULL);
363 tt = print_otag(h, TAG_HEAD, 0, NULL);
364 print_mdoc_head(m, n, h);
365 print_tagq(h, tt);
366 print_otag(h, TAG_BODY, 0, NULL);
367 print_otag(h, TAG_DIV, 1, &tag);
368 } else
369 t = print_otag(h, TAG_DIV, 1, &tag);
370
371 print_mdoc_nodelist(m, n, h);
372 print_tagq(h, t);
373 }
374
375
376 /* ARGSUSED */
377 static void
378 print_mdoc_head(MDOC_ARGS)
379 {
380
381 print_gen_head(h);
382 bufinit(h);
383 bufcat_fmt(h, "%s(%s)", m->title, m->msec);
384
385 if (m->arch)
386 bufcat_fmt(h, " (%s)", m->arch);
387
388 print_otag(h, TAG_TITLE, 0, NULL);
389 print_text(h, h->buf);
390 }
391
392
393 static void
394 print_mdoc_nodelist(MDOC_ARGS)
395 {
396
397 print_mdoc_node(m, n, h);
398 if (n->next)
399 print_mdoc_nodelist(m, n->next, h);
400 }
401
402
403 static void
404 print_mdoc_node(MDOC_ARGS)
405 {
406 int child;
407 struct tag *t;
408
409 child = 1;
410 t = h->tags.head;
411
412 switch (n->type) {
413 case (MDOC_ROOT):
414 child = mdoc_root_pre(m, n, h);
415 break;
416 case (MDOC_TEXT):
417 /* No tables in this mode... */
418 assert(NULL == h->tblt);
419
420 /*
421 * Make sure that if we're in a literal mode already
422 * (i.e., within a <PRE>) don't print the newline.
423 */
424 if (' ' == *n->string && MDOC_LINE & n->flags)
425 if ( ! (HTML_LITERAL & h->flags))
426 print_otag(h, TAG_BR, 0, NULL);
427 if (MDOC_DELIMC & n->flags)
428 h->flags |= HTML_NOSPACE;
429 print_text(h, n->string);
430 if (MDOC_DELIMO & n->flags)
431 h->flags |= HTML_NOSPACE;
432 return;
433 case (MDOC_EQN):
434 print_eqn(h, n->eqn);
437 /*
438 * This will take care of initialising all of the table
439 * state data for the first table, then tearing it down
440 * for the last one.
441 */
442 print_tbl(h, n->span);
443 return;
444 default:
445 /*
446 * Close out the current table, if it's open, and unset
447 * the "meta" table state. This will be reopened on the
448 * next table element.
449 */
450 if (h->tblt) {
451 print_tblclose(h);
452 t = h->tags.head;
453 }
454
455 assert(NULL == h->tblt);
456 if (mdocs[n->tok].pre && ENDBODY_NOT == n->end)
457 child = (*mdocs[n->tok].pre)(m, n, h);
458 break;
459 }
460
461 if (HTML_KEEP & h->flags) {
462 if (n->prev && n->prev->line != n->line) {
463 h->flags &= ~HTML_KEEP;
464 h->flags |= HTML_PREKEEP;
465 } else if (NULL == n->prev) {
466 if (n->parent && n->parent->line != n->line) {
467 h->flags &= ~HTML_KEEP;
468 h->flags |= HTML_PREKEEP;
469 }
470 }
471 }
472
473 if (child && n->child)
474 print_mdoc_nodelist(m, n->child, h);
475
476 print_stagq(h, t);
477
478 switch (n->type) {
479 case (MDOC_ROOT):
480 mdoc_root_post(m, n, h);
481 break;
482 case (MDOC_EQN):
483 break;
484 default:
485 if (mdocs[n->tok].post && ENDBODY_NOT == n->end)
486 (*mdocs[n->tok].post)(m, n, h);
487 break;
488 }
489 }
490
491 /* ARGSUSED */
492 static void
493 mdoc_root_post(MDOC_ARGS)
494 {
495 struct htmlpair tag[3];
496 struct tag *t, *tt;
497
498 PAIR_SUMMARY_INIT(&tag[0], "Document Footer");
499 PAIR_CLASS_INIT(&tag[1], "foot");
500 PAIR_INIT(&tag[2], ATTR_WIDTH, "100%");
501 t = print_otag(h, TAG_TABLE, 3, tag);
502 PAIR_INIT(&tag[0], ATTR_WIDTH, "50%");
503 print_otag(h, TAG_COL, 1, tag);
504 print_otag(h, TAG_COL, 1, tag);
505
506 print_otag(h, TAG_TBODY, 0, NULL);
507
508 tt = print_otag(h, TAG_TR, 0, NULL);
509
510 PAIR_CLASS_INIT(&tag[0], "foot-date");
511 print_otag(h, TAG_TD, 1, tag);
512 print_text(h, m->date);
513 print_stagq(h, tt);
514
515 PAIR_CLASS_INIT(&tag[0], "foot-os");
516 PAIR_INIT(&tag[1], ATTR_ALIGN, "right");
517 print_otag(h, TAG_TD, 2, tag);
518 print_text(h, m->os);
519 print_tagq(h, t);
520 }
521
522
523 /* ARGSUSED */
524 static int
525 mdoc_root_pre(MDOC_ARGS)
526 {
527 struct htmlpair tag[3];
528 struct tag *t, *tt;
529 char b[BUFSIZ], title[BUFSIZ];
530
531 strlcpy(b, m->vol, BUFSIZ);
532
533 if (m->arch) {
534 strlcat(b, " (", BUFSIZ);
535 strlcat(b, m->arch, BUFSIZ);
536 strlcat(b, ")", BUFSIZ);
537 }
538
539 snprintf(title, BUFSIZ - 1, "%s(%s)", m->title, m->msec);
540
541 PAIR_SUMMARY_INIT(&tag[0], "Document Header");
542 PAIR_CLASS_INIT(&tag[1], "head");
543 PAIR_INIT(&tag[2], ATTR_WIDTH, "100%");
544 t = print_otag(h, TAG_TABLE, 3, tag);
545 PAIR_INIT(&tag[0], ATTR_WIDTH, "30%");
546 print_otag(h, TAG_COL, 1, tag);
547 print_otag(h, TAG_COL, 1, tag);
548 print_otag(h, TAG_COL, 1, tag);
549
550 print_otag(h, TAG_TBODY, 0, NULL);
551
552 tt = print_otag(h, TAG_TR, 0, NULL);
553
554 PAIR_CLASS_INIT(&tag[0], "head-ltitle");
555 print_otag(h, TAG_TD, 1, tag);
556 print_text(h, title);
557 print_stagq(h, tt);
558
559 PAIR_CLASS_INIT(&tag[0], "head-vol");
672
673 print_text(h, "\\(em");
674 PAIR_CLASS_INIT(&tag, "desc");
675 print_otag(h, TAG_SPAN, 1, &tag);
676 return(1);
677 }
678
679
680 static int
681 mdoc_nm_pre(MDOC_ARGS)
682 {
683 struct htmlpair tag;
684 struct roffsu su;
685 int len;
686
687 switch (n->type) {
688 case (MDOC_ELEM):
689 synopsis_pre(h, n);
690 PAIR_CLASS_INIT(&tag, "name");
691 print_otag(h, TAG_B, 1, &tag);
692 if (NULL == n->child && m->name)
693 print_text(h, m->name);
694 return(1);
695 case (MDOC_HEAD):
696 print_otag(h, TAG_TD, 0, NULL);
697 if (NULL == n->child && m->name)
698 print_text(h, m->name);
699 return(1);
700 case (MDOC_BODY):
701 print_otag(h, TAG_TD, 0, NULL);
702 return(1);
703 default:
704 break;
705 }
706
707 synopsis_pre(h, n);
708 PAIR_CLASS_INIT(&tag, "synopsis");
709 print_otag(h, TAG_TABLE, 1, &tag);
710
711 for (len = 0, n = n->child; n; n = n->next)
712 if (MDOC_TEXT == n->type)
713 len += html_strlen(n->string);
714
715 if (0 == len && m->name)
716 len = html_strlen(m->name);
717
718 SCALE_HS_INIT(&su, (double)len);
719 bufinit(h);
720 bufcat_su(h, "width", &su);
721 PAIR_STYLE_INIT(&tag, h);
722 print_otag(h, TAG_COL, 1, &tag);
723 print_otag(h, TAG_COL, 0, NULL);
724 print_otag(h, TAG_TBODY, 0, NULL);
725 print_otag(h, TAG_TR, 0, NULL);
726 return(1);
727 }
728
729
730 /* ARGSUSED */
731 static int
732 mdoc_xr_pre(MDOC_ARGS)
733 {
734 struct htmlpair tag[2];
735
736 if (NULL == n->child)
964 case (LIST_column):
965 print_otag(h, TAG_TR, 1, tag);
966 break;
967 default:
968 break;
969 }
970 }
971
972 return(1);
973 }
974
975 /* ARGSUSED */
976 static int
977 mdoc_bl_pre(MDOC_ARGS)
978 {
979 int i;
980 struct htmlpair tag[3];
981 struct roffsu su;
982 char buf[BUFSIZ];
983
984 bufinit(h);
985
986 if (MDOC_BODY == n->type) {
987 if (LIST_column == n->norm->Bl.type)
988 print_otag(h, TAG_TBODY, 0, NULL);
989 return(1);
990 }
991
992 if (MDOC_HEAD == n->type) {
993 if (LIST_column != n->norm->Bl.type)
994 return(0);
995
996 /*
997 * For each column, print out the <COL> tag with our
998 * suggested width. The last column gets min-width, as
999 * in terminal mode it auto-sizes to the width of the
1000 * screen and we want to preserve that behaviour.
1001 */
1002
1003 for (i = 0; i < (int)n->norm->Bl.ncols; i++) {
1004 a2width(n->norm->Bl.cols[i], &su);
1005 if (i < (int)n->norm->Bl.ncols - 1)
1006 bufcat_su(h, "width", &su);
1007 else
1008 bufcat_su(h, "min-width", &su);
1009 PAIR_STYLE_INIT(&tag[0], h);
1010 print_otag(h, TAG_COL, 1, tag);
1011 }
1012
1013 return(0);
1014 }
1015
1016 SCALE_VS_INIT(&su, 0);
1017 bufcat_su(h, "margin-top", &su);
1018 bufcat_su(h, "margin-bottom", &su);
1019 PAIR_STYLE_INIT(&tag[0], h);
1020
1021 assert(lists[n->norm->Bl.type]);
1022 strlcpy(buf, "list ", BUFSIZ);
1023 strlcat(buf, lists[n->norm->Bl.type], BUFSIZ);
1024 PAIR_INIT(&tag[1], ATTR_CLASS, buf);
1025
1026 /* Set the block's left-hand margin. */
1027
1028 if (n->norm->Bl.offs) {
1029 a2offs(n->norm->Bl.offs, &su);
1030 bufcat_su(h, "margin-left", &su);
1031 }
1032
1033 switch (n->norm->Bl.type) {
1034 case(LIST_bullet):
1035 /* FALLTHROUGH */
1036 case(LIST_dash):
1208 bufinit(h);
1209 bufcat_su(h, "margin-left", &su);
1210 PAIR_STYLE_INIT(&tag[0], h);
1211
1212 if (DISP_unfilled != n->norm->Bd.type &&
1213 DISP_literal != n->norm->Bd.type) {
1214 PAIR_CLASS_INIT(&tag[1], "display");
1215 print_otag(h, TAG_DIV, 2, tag);
1216 return(1);
1217 }
1218
1219 PAIR_CLASS_INIT(&tag[1], "lit display");
1220 print_otag(h, TAG_PRE, 2, tag);
1221
1222 /* This can be recursive: save & set our literal state. */
1223
1224 sv = h->flags & HTML_LITERAL;
1225 h->flags |= HTML_LITERAL;
1226
1227 for (nn = n->child; nn; nn = nn->next) {
1228 print_mdoc_node(m, nn, h);
1229 /*
1230 * If the printed node flushes its own line, then we
1231 * needn't do it here as well. This is hacky, but the
1232 * notion of selective eoln whitespace is pretty dumb
1233 * anyway, so don't sweat it.
1234 */
1235 switch (nn->tok) {
1236 case (MDOC_Sm):
1237 /* FALLTHROUGH */
1238 case (MDOC_br):
1239 /* FALLTHROUGH */
1240 case (MDOC_sp):
1241 /* FALLTHROUGH */
1242 case (MDOC_Bl):
1243 /* FALLTHROUGH */
1244 case (MDOC_D1):
1245 /* FALLTHROUGH */
1246 case (MDOC_Dl):
1247 /* FALLTHROUGH */
1248 case (MDOC_Lp):
2256 break;
2257 case (MDOC_Qo):
2258 /* FALLTHROUGH */
2259 case (MDOC_Qq):
2260 /* FALLTHROUGH */
2261 case (MDOC_Do):
2262 /* FALLTHROUGH */
2263 case (MDOC_Dq):
2264 print_text(h, "\\(rq");
2265 break;
2266 case (MDOC_Po):
2267 /* FALLTHROUGH */
2268 case (MDOC_Pq):
2269 print_text(h, ")");
2270 break;
2271 case (MDOC_Ql):
2272 /* FALLTHROUGH */
2273 case (MDOC_So):
2274 /* FALLTHROUGH */
2275 case (MDOC_Sq):
2276 print_text(h, "\\(aq");
2277 break;
2278 default:
2279 abort();
2280 /* NOTREACHED */
2281 }
2282 }
2283
2284
|
1 /* $Id: mdoc_html.c,v 1.186 2013/12/24 20:45:27 schwarze Exp $ */
2 /*
3 * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
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 above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include <sys/types.h>
22
23 #include <assert.h>
24 #include <ctype.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #include "mandoc.h"
31 #include "out.h"
32 #include "html.h"
33 #include "mdoc.h"
34 #include "main.h"
35
36 #define INDENT 5
37
38 #define MDOC_ARGS const struct mdoc_meta *meta, \
39 const struct mdoc_node *n, \
40 struct html *h
41
42 #ifndef MIN
43 #define MIN(a,b) ((/*CONSTCOND*/(a)<(b))?(a):(b))
44 #endif
45
46 struct htmlmdoc {
47 int (*pre)(MDOC_ARGS);
48 void (*post)(MDOC_ARGS);
49 };
50
51 static void print_mdoc(MDOC_ARGS);
52 static void print_mdoc_head(MDOC_ARGS);
53 static void print_mdoc_node(MDOC_ARGS);
54 static void print_mdoc_nodelist(MDOC_ARGS);
55 static void synopsis_pre(struct html *,
56 const struct mdoc_node *);
57
58 static void a2width(const char *, struct roffsu *);
243 {mdoc__x_pre, mdoc__x_post}, /* %U */
244 {NULL, NULL}, /* Ta */
245 };
246
247 static const char * const lists[LIST_MAX] = {
248 NULL,
249 "list-bul",
250 "list-col",
251 "list-dash",
252 "list-diag",
253 "list-enum",
254 "list-hang",
255 "list-hyph",
256 "list-inset",
257 "list-item",
258 "list-ohang",
259 "list-tag"
260 };
261
262 void
263 html_mdoc(void *arg, const struct mdoc *mdoc)
264 {
265
266 print_mdoc(mdoc_meta(mdoc), mdoc_node(mdoc),
267 (struct html *)arg);
268 putchar('\n');
269 }
270
271
272 /*
273 * Calculate the scaling unit passed in a `-width' argument. This uses
274 * either a native scaling unit (e.g., 1i, 2m) or the string length of
275 * the value.
276 */
277 static void
278 a2width(const char *p, struct roffsu *su)
279 {
280
281 if ( ! a2roffsu(p, su, SCALE_MAX)) {
282 su->unit = SCALE_BU;
283 su->scale = html_strlen(p);
284 }
285 }
286
287
345 SCALE_HS_INIT(su, INDENT);
346 else if (0 == strcmp(p, "indent-two"))
347 SCALE_HS_INIT(su, INDENT * 2);
348 else if ( ! a2roffsu(p, su, SCALE_MAX))
349 SCALE_HS_INIT(su, html_strlen(p));
350 }
351
352
353 static void
354 print_mdoc(MDOC_ARGS)
355 {
356 struct tag *t, *tt;
357 struct htmlpair tag;
358
359 PAIR_CLASS_INIT(&tag, "mandoc");
360
361 if ( ! (HTML_FRAGMENT & h->oflags)) {
362 print_gen_decls(h);
363 t = print_otag(h, TAG_HTML, 0, NULL);
364 tt = print_otag(h, TAG_HEAD, 0, NULL);
365 print_mdoc_head(meta, n, h);
366 print_tagq(h, tt);
367 print_otag(h, TAG_BODY, 0, NULL);
368 print_otag(h, TAG_DIV, 1, &tag);
369 } else
370 t = print_otag(h, TAG_DIV, 1, &tag);
371
372 print_mdoc_nodelist(meta, n, h);
373 print_tagq(h, t);
374 }
375
376
377 /* ARGSUSED */
378 static void
379 print_mdoc_head(MDOC_ARGS)
380 {
381
382 print_gen_head(h);
383 bufinit(h);
384 bufcat_fmt(h, "%s(%s)", meta->title, meta->msec);
385
386 if (meta->arch)
387 bufcat_fmt(h, " (%s)", meta->arch);
388
389 print_otag(h, TAG_TITLE, 0, NULL);
390 print_text(h, h->buf);
391 }
392
393
394 static void
395 print_mdoc_nodelist(MDOC_ARGS)
396 {
397
398 print_mdoc_node(meta, n, h);
399 if (n->next)
400 print_mdoc_nodelist(meta, n->next, h);
401 }
402
403
404 static void
405 print_mdoc_node(MDOC_ARGS)
406 {
407 int child;
408 struct tag *t;
409
410 child = 1;
411 t = h->tags.head;
412
413 switch (n->type) {
414 case (MDOC_ROOT):
415 child = mdoc_root_pre(meta, n, h);
416 break;
417 case (MDOC_TEXT):
418 /* No tables in this mode... */
419 assert(NULL == h->tblt);
420
421 /*
422 * Make sure that if we're in a literal mode already
423 * (i.e., within a <PRE>) don't print the newline.
424 */
425 if (' ' == *n->string && MDOC_LINE & n->flags)
426 if ( ! (HTML_LITERAL & h->flags))
427 print_otag(h, TAG_BR, 0, NULL);
428 if (MDOC_DELIMC & n->flags)
429 h->flags |= HTML_NOSPACE;
430 print_text(h, n->string);
431 if (MDOC_DELIMO & n->flags)
432 h->flags |= HTML_NOSPACE;
433 return;
434 case (MDOC_EQN):
435 print_eqn(h, n->eqn);
438 /*
439 * This will take care of initialising all of the table
440 * state data for the first table, then tearing it down
441 * for the last one.
442 */
443 print_tbl(h, n->span);
444 return;
445 default:
446 /*
447 * Close out the current table, if it's open, and unset
448 * the "meta" table state. This will be reopened on the
449 * next table element.
450 */
451 if (h->tblt) {
452 print_tblclose(h);
453 t = h->tags.head;
454 }
455
456 assert(NULL == h->tblt);
457 if (mdocs[n->tok].pre && ENDBODY_NOT == n->end)
458 child = (*mdocs[n->tok].pre)(meta, n, h);
459 break;
460 }
461
462 if (HTML_KEEP & h->flags) {
463 if (n->prev ? (n->prev->lastline != n->line) :
464 (n->parent && n->parent->line != n->line)) {
465 h->flags &= ~HTML_KEEP;
466 h->flags |= HTML_PREKEEP;
467 }
468 }
469
470 if (child && n->child)
471 print_mdoc_nodelist(meta, n->child, h);
472
473 print_stagq(h, t);
474
475 switch (n->type) {
476 case (MDOC_ROOT):
477 mdoc_root_post(meta, n, h);
478 break;
479 case (MDOC_EQN):
480 break;
481 default:
482 if (mdocs[n->tok].post && ENDBODY_NOT == n->end)
483 (*mdocs[n->tok].post)(meta, n, h);
484 break;
485 }
486 }
487
488 /* ARGSUSED */
489 static void
490 mdoc_root_post(MDOC_ARGS)
491 {
492 struct htmlpair tag[3];
493 struct tag *t, *tt;
494
495 PAIR_SUMMARY_INIT(&tag[0], "Document Footer");
496 PAIR_CLASS_INIT(&tag[1], "foot");
497 PAIR_INIT(&tag[2], ATTR_WIDTH, "100%");
498 t = print_otag(h, TAG_TABLE, 3, tag);
499 PAIR_INIT(&tag[0], ATTR_WIDTH, "50%");
500 print_otag(h, TAG_COL, 1, tag);
501 print_otag(h, TAG_COL, 1, tag);
502
503 print_otag(h, TAG_TBODY, 0, NULL);
504
505 tt = print_otag(h, TAG_TR, 0, NULL);
506
507 PAIR_CLASS_INIT(&tag[0], "foot-date");
508 print_otag(h, TAG_TD, 1, tag);
509 print_text(h, meta->date);
510 print_stagq(h, tt);
511
512 PAIR_CLASS_INIT(&tag[0], "foot-os");
513 PAIR_INIT(&tag[1], ATTR_ALIGN, "right");
514 print_otag(h, TAG_TD, 2, tag);
515 print_text(h, meta->os);
516 print_tagq(h, t);
517 }
518
519
520 /* ARGSUSED */
521 static int
522 mdoc_root_pre(MDOC_ARGS)
523 {
524 struct htmlpair tag[3];
525 struct tag *t, *tt;
526 char b[BUFSIZ], title[BUFSIZ];
527
528 strlcpy(b, meta->vol, BUFSIZ);
529
530 if (meta->arch) {
531 strlcat(b, " (", BUFSIZ);
532 strlcat(b, meta->arch, BUFSIZ);
533 strlcat(b, ")", BUFSIZ);
534 }
535
536 snprintf(title, BUFSIZ - 1, "%s(%s)", meta->title, meta->msec);
537
538 PAIR_SUMMARY_INIT(&tag[0], "Document Header");
539 PAIR_CLASS_INIT(&tag[1], "head");
540 PAIR_INIT(&tag[2], ATTR_WIDTH, "100%");
541 t = print_otag(h, TAG_TABLE, 3, tag);
542 PAIR_INIT(&tag[0], ATTR_WIDTH, "30%");
543 print_otag(h, TAG_COL, 1, tag);
544 print_otag(h, TAG_COL, 1, tag);
545 print_otag(h, TAG_COL, 1, tag);
546
547 print_otag(h, TAG_TBODY, 0, NULL);
548
549 tt = print_otag(h, TAG_TR, 0, NULL);
550
551 PAIR_CLASS_INIT(&tag[0], "head-ltitle");
552 print_otag(h, TAG_TD, 1, tag);
553 print_text(h, title);
554 print_stagq(h, tt);
555
556 PAIR_CLASS_INIT(&tag[0], "head-vol");
669
670 print_text(h, "\\(em");
671 PAIR_CLASS_INIT(&tag, "desc");
672 print_otag(h, TAG_SPAN, 1, &tag);
673 return(1);
674 }
675
676
677 static int
678 mdoc_nm_pre(MDOC_ARGS)
679 {
680 struct htmlpair tag;
681 struct roffsu su;
682 int len;
683
684 switch (n->type) {
685 case (MDOC_ELEM):
686 synopsis_pre(h, n);
687 PAIR_CLASS_INIT(&tag, "name");
688 print_otag(h, TAG_B, 1, &tag);
689 if (NULL == n->child && meta->name)
690 print_text(h, meta->name);
691 return(1);
692 case (MDOC_HEAD):
693 print_otag(h, TAG_TD, 0, NULL);
694 if (NULL == n->child && meta->name)
695 print_text(h, meta->name);
696 return(1);
697 case (MDOC_BODY):
698 print_otag(h, TAG_TD, 0, NULL);
699 return(1);
700 default:
701 break;
702 }
703
704 synopsis_pre(h, n);
705 PAIR_CLASS_INIT(&tag, "synopsis");
706 print_otag(h, TAG_TABLE, 1, &tag);
707
708 for (len = 0, n = n->child; n; n = n->next)
709 if (MDOC_TEXT == n->type)
710 len += html_strlen(n->string);
711
712 if (0 == len && meta->name)
713 len = html_strlen(meta->name);
714
715 SCALE_HS_INIT(&su, (double)len);
716 bufinit(h);
717 bufcat_su(h, "width", &su);
718 PAIR_STYLE_INIT(&tag, h);
719 print_otag(h, TAG_COL, 1, &tag);
720 print_otag(h, TAG_COL, 0, NULL);
721 print_otag(h, TAG_TBODY, 0, NULL);
722 print_otag(h, TAG_TR, 0, NULL);
723 return(1);
724 }
725
726
727 /* ARGSUSED */
728 static int
729 mdoc_xr_pre(MDOC_ARGS)
730 {
731 struct htmlpair tag[2];
732
733 if (NULL == n->child)
961 case (LIST_column):
962 print_otag(h, TAG_TR, 1, tag);
963 break;
964 default:
965 break;
966 }
967 }
968
969 return(1);
970 }
971
972 /* ARGSUSED */
973 static int
974 mdoc_bl_pre(MDOC_ARGS)
975 {
976 int i;
977 struct htmlpair tag[3];
978 struct roffsu su;
979 char buf[BUFSIZ];
980
981 if (MDOC_BODY == n->type) {
982 if (LIST_column == n->norm->Bl.type)
983 print_otag(h, TAG_TBODY, 0, NULL);
984 return(1);
985 }
986
987 if (MDOC_HEAD == n->type) {
988 if (LIST_column != n->norm->Bl.type)
989 return(0);
990
991 /*
992 * For each column, print out the <COL> tag with our
993 * suggested width. The last column gets min-width, as
994 * in terminal mode it auto-sizes to the width of the
995 * screen and we want to preserve that behaviour.
996 */
997
998 for (i = 0; i < (int)n->norm->Bl.ncols; i++) {
999 bufinit(h);
1000 a2width(n->norm->Bl.cols[i], &su);
1001 if (i < (int)n->norm->Bl.ncols - 1)
1002 bufcat_su(h, "width", &su);
1003 else
1004 bufcat_su(h, "min-width", &su);
1005 PAIR_STYLE_INIT(&tag[0], h);
1006 print_otag(h, TAG_COL, 1, tag);
1007 }
1008
1009 return(0);
1010 }
1011
1012 SCALE_VS_INIT(&su, 0);
1013 bufinit(h);
1014 bufcat_su(h, "margin-top", &su);
1015 bufcat_su(h, "margin-bottom", &su);
1016 PAIR_STYLE_INIT(&tag[0], h);
1017
1018 assert(lists[n->norm->Bl.type]);
1019 strlcpy(buf, "list ", BUFSIZ);
1020 strlcat(buf, lists[n->norm->Bl.type], BUFSIZ);
1021 PAIR_INIT(&tag[1], ATTR_CLASS, buf);
1022
1023 /* Set the block's left-hand margin. */
1024
1025 if (n->norm->Bl.offs) {
1026 a2offs(n->norm->Bl.offs, &su);
1027 bufcat_su(h, "margin-left", &su);
1028 }
1029
1030 switch (n->norm->Bl.type) {
1031 case(LIST_bullet):
1032 /* FALLTHROUGH */
1033 case(LIST_dash):
1205 bufinit(h);
1206 bufcat_su(h, "margin-left", &su);
1207 PAIR_STYLE_INIT(&tag[0], h);
1208
1209 if (DISP_unfilled != n->norm->Bd.type &&
1210 DISP_literal != n->norm->Bd.type) {
1211 PAIR_CLASS_INIT(&tag[1], "display");
1212 print_otag(h, TAG_DIV, 2, tag);
1213 return(1);
1214 }
1215
1216 PAIR_CLASS_INIT(&tag[1], "lit display");
1217 print_otag(h, TAG_PRE, 2, tag);
1218
1219 /* This can be recursive: save & set our literal state. */
1220
1221 sv = h->flags & HTML_LITERAL;
1222 h->flags |= HTML_LITERAL;
1223
1224 for (nn = n->child; nn; nn = nn->next) {
1225 print_mdoc_node(meta, nn, h);
1226 /*
1227 * If the printed node flushes its own line, then we
1228 * needn't do it here as well. This is hacky, but the
1229 * notion of selective eoln whitespace is pretty dumb
1230 * anyway, so don't sweat it.
1231 */
1232 switch (nn->tok) {
1233 case (MDOC_Sm):
1234 /* FALLTHROUGH */
1235 case (MDOC_br):
1236 /* FALLTHROUGH */
1237 case (MDOC_sp):
1238 /* FALLTHROUGH */
1239 case (MDOC_Bl):
1240 /* FALLTHROUGH */
1241 case (MDOC_D1):
1242 /* FALLTHROUGH */
1243 case (MDOC_Dl):
1244 /* FALLTHROUGH */
1245 case (MDOC_Lp):
2253 break;
2254 case (MDOC_Qo):
2255 /* FALLTHROUGH */
2256 case (MDOC_Qq):
2257 /* FALLTHROUGH */
2258 case (MDOC_Do):
2259 /* FALLTHROUGH */
2260 case (MDOC_Dq):
2261 print_text(h, "\\(rq");
2262 break;
2263 case (MDOC_Po):
2264 /* FALLTHROUGH */
2265 case (MDOC_Pq):
2266 print_text(h, ")");
2267 break;
2268 case (MDOC_Ql):
2269 /* FALLTHROUGH */
2270 case (MDOC_So):
2271 /* FALLTHROUGH */
2272 case (MDOC_Sq):
2273 print_text(h, "\\(cq");
2274 break;
2275 default:
2276 abort();
2277 /* NOTREACHED */
2278 }
2279 }
2280
2281
|