1 /* $Vendor-Id: man_html.c,v 1.45 2010/07/23 12:27:28 kristaps Exp $ */ 2 /* 3 * Copyright (c) 2008, 2009, 2010 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 29 #include "mandoc.h" 30 #include "out.h" 31 #include "html.h" 32 #include "man.h" 33 #include "main.h" 34 35 /* TODO: preserve ident widths. */ 36 /* FIXME: have PD set the default vspace width. */ 37 38 #define INDENT 5 39 #define HALFINDENT 3 40 41 #define MAN_ARGS const struct man_meta *m, \ 42 const struct man_node *n, \ 43 struct mhtml *mh, \ 44 struct html *h 45 46 struct mhtml { 47 int fl; 48 #define MANH_LITERAL (1 << 0) /* literal context */ 49 }; 50 51 struct htmlman { 52 int (*pre)(MAN_ARGS); 53 int (*post)(MAN_ARGS); 54 }; 55 56 static void print_man(MAN_ARGS); 57 static void print_man_head(MAN_ARGS); 58 static void print_man_nodelist(MAN_ARGS); 59 static void print_man_node(MAN_ARGS); 60 61 static int a2width(const struct man_node *, 62 struct roffsu *); 63 64 static int man_alt_pre(MAN_ARGS); 65 static int man_br_pre(MAN_ARGS); 66 static int man_ign_pre(MAN_ARGS); 67 static int man_in_pre(MAN_ARGS); 68 static int man_literal_pre(MAN_ARGS); 69 static void man_root_post(MAN_ARGS); 70 static int man_root_pre(MAN_ARGS); 71 static int man_B_pre(MAN_ARGS); 72 static int man_HP_pre(MAN_ARGS); 73 static int man_I_pre(MAN_ARGS); 74 static int man_IP_pre(MAN_ARGS); 75 static int man_PP_pre(MAN_ARGS); 76 static int man_RS_pre(MAN_ARGS); 77 static int man_SB_pre(MAN_ARGS); 78 static int man_SH_pre(MAN_ARGS); 79 static int man_SM_pre(MAN_ARGS); 80 static int man_SS_pre(MAN_ARGS); 81 82 static const struct htmlman mans[MAN_MAX] = { 83 { man_br_pre, NULL }, /* br */ 84 { NULL, NULL }, /* TH */ 85 { man_SH_pre, NULL }, /* SH */ 86 { man_SS_pre, NULL }, /* SS */ 87 { man_IP_pre, NULL }, /* TP */ 88 { man_PP_pre, NULL }, /* LP */ 89 { man_PP_pre, NULL }, /* PP */ 90 { man_PP_pre, NULL }, /* P */ 91 { man_IP_pre, NULL }, /* IP */ 92 { man_HP_pre, NULL }, /* HP */ 93 { man_SM_pre, NULL }, /* SM */ 94 { man_SB_pre, NULL }, /* SB */ 95 { man_alt_pre, NULL }, /* BI */ 96 { man_alt_pre, NULL }, /* IB */ 97 { man_alt_pre, NULL }, /* BR */ 98 { man_alt_pre, NULL }, /* RB */ 99 { NULL, NULL }, /* R */ 100 { man_B_pre, NULL }, /* B */ 101 { man_I_pre, NULL }, /* I */ 102 { man_alt_pre, NULL }, /* IR */ 103 { man_alt_pre, NULL }, /* RI */ 104 { NULL, NULL }, /* na */ 105 { NULL, NULL }, /* i */ 106 { man_br_pre, NULL }, /* sp */ 107 { man_literal_pre, NULL }, /* nf */ 108 { man_literal_pre, NULL }, /* fi */ 109 { NULL, NULL }, /* r */ 110 { NULL, NULL }, /* RE */ 111 { man_RS_pre, NULL }, /* RS */ 112 { man_ign_pre, NULL }, /* DT */ 113 { man_ign_pre, NULL }, /* UC */ 114 { man_ign_pre, NULL }, /* PD */ 115 { man_br_pre, NULL }, /* Sp */ 116 { man_literal_pre, NULL }, /* Vb */ 117 { man_literal_pre, NULL }, /* Ve */ 118 { man_ign_pre, NULL }, /* AT */ 119 { man_in_pre, NULL }, /* in */ 120 }; 121 122 123 void 124 html_man(void *arg, const struct man *m) 125 { 126 struct html *h; 127 struct tag *t; 128 struct mhtml mh; 129 130 h = (struct html *)arg; 131 132 print_gen_decls(h); 133 134 memset(&mh, 0, sizeof(struct mhtml)); 135 136 t = print_otag(h, TAG_HTML, 0, NULL); 137 print_man(man_meta(m), man_node(m), &mh, h); 138 print_tagq(h, t); 139 140 printf("\n"); 141 } 142 143 144 static void 145 print_man(MAN_ARGS) 146 { 147 struct tag *t; 148 struct htmlpair tag; 149 150 t = print_otag(h, TAG_HEAD, 0, NULL); 151 152 print_man_head(m, n, mh, h); 153 print_tagq(h, t); 154 t = print_otag(h, TAG_BODY, 0, NULL); 155 156 tag.key = ATTR_CLASS; 157 tag.val = "body"; 158 print_otag(h, TAG_DIV, 1, &tag); 159 160 print_man_nodelist(m, n, mh, h); 161 162 print_tagq(h, t); 163 } 164 165 166 /* ARGSUSED */ 167 static void 168 print_man_head(MAN_ARGS) 169 { 170 171 print_gen_head(h); 172 bufinit(h); 173 buffmt(h, "%s(%s)", m->title, m->msec); 174 175 print_otag(h, TAG_TITLE, 0, NULL); 176 print_text(h, h->buf); 177 } 178 179 180 static void 181 print_man_nodelist(MAN_ARGS) 182 { 183 184 print_man_node(m, n, mh, h); 185 if (n->next) 186 print_man_nodelist(m, n->next, mh, h); 187 } 188 189 190 static void 191 print_man_node(MAN_ARGS) 192 { 193 int child; 194 struct tag *t; 195 196 child = 1; 197 t = h->tags.head; 198 199 bufinit(h); 200 201 /* 202 * FIXME: embedded elements within next-line scopes (e.g., `br' 203 * within an empty `B') will cause formatting to be forgotten 204 * due to scope closing out. 205 */ 206 207 switch (n->type) { 208 case (MAN_ROOT): 209 child = man_root_pre(m, n, mh, h); 210 break; 211 case (MAN_TEXT): 212 print_text(h, n->string); 213 214 if (MANH_LITERAL & mh->fl) 215 print_otag(h, TAG_BR, 0, NULL); 216 217 return; 218 default: 219 /* 220 * Close out scope of font prior to opening a macro 221 * scope. Assert that the metafont is on the top of the 222 * stack (it's never nested). 223 */ 224 if (h->metaf) { 225 assert(h->metaf == t); 226 print_tagq(h, h->metaf); 227 assert(NULL == h->metaf); 228 t = h->tags.head; 229 } 230 if (mans[n->tok].pre) 231 child = (*mans[n->tok].pre)(m, n, mh, h); 232 break; 233 } 234 235 if (child && n->child) 236 print_man_nodelist(m, n->child, mh, h); 237 238 /* This will automatically close out any font scope. */ 239 print_stagq(h, t); 240 241 bufinit(h); 242 243 switch (n->type) { 244 case (MAN_ROOT): 245 man_root_post(m, n, mh, h); 246 break; 247 case (MAN_TEXT): 248 break; 249 default: 250 if (mans[n->tok].post) 251 (*mans[n->tok].post)(m, n, mh, h); 252 break; 253 } 254 } 255 256 257 static int 258 a2width(const struct man_node *n, struct roffsu *su) 259 { 260 261 if (MAN_TEXT != n->type) 262 return(0); 263 if (a2roffsu(n->string, su, SCALE_BU)) 264 return(1); 265 266 return(0); 267 } 268 269 270 /* ARGSUSED */ 271 static int 272 man_root_pre(MAN_ARGS) 273 { 274 struct htmlpair tag[3]; 275 struct tag *t, *tt; 276 char b[BUFSIZ], title[BUFSIZ]; 277 278 b[0] = 0; 279 if (m->vol) 280 (void)strlcat(b, m->vol, BUFSIZ); 281 282 snprintf(title, BUFSIZ - 1, "%s(%s)", m->title, m->msec); 283 284 PAIR_CLASS_INIT(&tag[0], "header"); 285 bufcat_style(h, "width", "100%"); 286 PAIR_STYLE_INIT(&tag[1], h); 287 PAIR_SUMMARY_INIT(&tag[2], "header"); 288 289 t = print_otag(h, TAG_TABLE, 3, tag); 290 tt = print_otag(h, TAG_TR, 0, NULL); 291 292 bufinit(h); 293 bufcat_style(h, "width", "10%"); 294 PAIR_STYLE_INIT(&tag[0], h); 295 print_otag(h, TAG_TD, 1, tag); 296 print_text(h, title); 297 print_stagq(h, tt); 298 299 bufinit(h); 300 bufcat_style(h, "width", "80%"); 301 bufcat_style(h, "white-space", "nowrap"); 302 bufcat_style(h, "text-align", "center"); 303 PAIR_STYLE_INIT(&tag[0], h); 304 print_otag(h, TAG_TD, 1, tag); 305 print_text(h, b); 306 print_stagq(h, tt); 307 308 bufinit(h); 309 bufcat_style(h, "width", "10%"); 310 bufcat_style(h, "text-align", "right"); 311 PAIR_STYLE_INIT(&tag[0], h); 312 print_otag(h, TAG_TD, 1, tag); 313 print_text(h, title); 314 print_tagq(h, t); 315 return(1); 316 } 317 318 319 /* ARGSUSED */ 320 static void 321 man_root_post(MAN_ARGS) 322 { 323 struct htmlpair tag[3]; 324 struct tag *t, *tt; 325 char b[DATESIZ]; 326 327 if (m->rawdate) 328 strlcpy(b, m->rawdate, DATESIZ); 329 else 330 time2a(m->date, b, DATESIZ); 331 332 PAIR_CLASS_INIT(&tag[0], "footer"); 333 bufcat_style(h, "width", "100%"); 334 PAIR_STYLE_INIT(&tag[1], h); 335 PAIR_SUMMARY_INIT(&tag[2], "footer"); 336 337 t = print_otag(h, TAG_TABLE, 3, tag); 338 tt = print_otag(h, TAG_TR, 0, NULL); 339 340 bufinit(h); 341 bufcat_style(h, "width", "50%"); 342 PAIR_STYLE_INIT(&tag[0], h); 343 print_otag(h, TAG_TD, 1, tag); 344 print_text(h, b); 345 print_stagq(h, tt); 346 347 bufinit(h); 348 bufcat_style(h, "width", "50%"); 349 bufcat_style(h, "text-align", "right"); 350 PAIR_STYLE_INIT(&tag[0], h); 351 print_otag(h, TAG_TD, 1, tag); 352 if (m->source) 353 print_text(h, m->source); 354 print_tagq(h, t); 355 } 356 357 358 359 /* ARGSUSED */ 360 static int 361 man_br_pre(MAN_ARGS) 362 { 363 struct roffsu su; 364 struct htmlpair tag; 365 366 SCALE_VS_INIT(&su, 1); 367 368 switch (n->tok) { 369 case (MAN_Sp): 370 SCALE_VS_INIT(&su, 0.5); 371 break; 372 case (MAN_sp): 373 if (n->child) 374 a2roffsu(n->child->string, &su, SCALE_VS); 375 break; 376 default: 377 su.scale = 0; 378 break; 379 } 380 381 bufcat_su(h, "height", &su); 382 PAIR_STYLE_INIT(&tag, h); 383 print_otag(h, TAG_DIV, 1, &tag); 384 385 /* So the div isn't empty: */ 386 print_text(h, "\\~"); 387 388 return(0); 389 } 390 391 392 /* ARGSUSED */ 393 static int 394 man_SH_pre(MAN_ARGS) 395 { 396 struct htmlpair tag[2]; 397 struct roffsu su; 398 399 if (MAN_BODY == n->type) { 400 SCALE_HS_INIT(&su, INDENT); 401 bufcat_su(h, "margin-left", &su); 402 PAIR_CLASS_INIT(&tag[0], "sec-body"); 403 PAIR_STYLE_INIT(&tag[1], h); 404 print_otag(h, TAG_DIV, 2, tag); 405 return(1); 406 } else if (MAN_BLOCK == n->type) { 407 PAIR_CLASS_INIT(&tag[0], "sec-block"); 408 if (n->prev && MAN_SH == n->prev->tok) 409 if (NULL == n->prev->body->child) { 410 print_otag(h, TAG_DIV, 1, tag); 411 return(1); 412 } 413 414 SCALE_VS_INIT(&su, 1); 415 bufcat_su(h, "margin-top", &su); 416 if (NULL == n->next) 417 bufcat_su(h, "margin-bottom", &su); 418 PAIR_STYLE_INIT(&tag[1], h); 419 print_otag(h, TAG_DIV, 2, tag); 420 return(1); 421 } 422 423 PAIR_CLASS_INIT(&tag[0], "sec-head"); 424 print_otag(h, TAG_DIV, 1, tag); 425 return(1); 426 } 427 428 429 /* ARGSUSED */ 430 static int 431 man_alt_pre(MAN_ARGS) 432 { 433 const struct man_node *nn; 434 struct tag *t; 435 int i; 436 enum htmlfont fp; 437 438 for (i = 0, nn = n->child; nn; nn = nn->next, i++) { 439 switch (n->tok) { 440 case (MAN_BI): 441 fp = i % 2 ? HTMLFONT_ITALIC : HTMLFONT_BOLD; 442 break; 443 case (MAN_IB): 444 fp = i % 2 ? HTMLFONT_BOLD : HTMLFONT_ITALIC; 445 break; 446 case (MAN_RI): 447 fp = i % 2 ? HTMLFONT_ITALIC : HTMLFONT_NONE; 448 break; 449 case (MAN_IR): 450 fp = i % 2 ? HTMLFONT_NONE : HTMLFONT_ITALIC; 451 break; 452 case (MAN_BR): 453 fp = i % 2 ? HTMLFONT_NONE : HTMLFONT_BOLD; 454 break; 455 case (MAN_RB): 456 fp = i % 2 ? HTMLFONT_BOLD : HTMLFONT_NONE; 457 break; 458 default: 459 abort(); 460 /* NOTREACHED */ 461 } 462 463 if (i) 464 h->flags |= HTML_NOSPACE; 465 466 /* 467 * Open and close the scope with each argument, so that 468 * internal \f escapes, which are common, are also 469 * closed out with the scope. 470 */ 471 t = print_ofont(h, fp); 472 print_man_node(m, nn, mh, h); 473 print_tagq(h, t); 474 } 475 476 return(0); 477 } 478 479 480 /* ARGSUSED */ 481 static int 482 man_SB_pre(MAN_ARGS) 483 { 484 struct htmlpair tag; 485 486 /* FIXME: print_ofont(). */ 487 PAIR_CLASS_INIT(&tag, "small bold"); 488 print_otag(h, TAG_SPAN, 1, &tag); 489 return(1); 490 } 491 492 493 /* ARGSUSED */ 494 static int 495 man_SM_pre(MAN_ARGS) 496 { 497 struct htmlpair tag; 498 499 PAIR_CLASS_INIT(&tag, "small"); 500 print_otag(h, TAG_SPAN, 1, &tag); 501 return(1); 502 } 503 504 505 /* ARGSUSED */ 506 static int 507 man_SS_pre(MAN_ARGS) 508 { 509 struct htmlpair tag[3]; 510 struct roffsu su; 511 512 SCALE_VS_INIT(&su, 1); 513 514 if (MAN_BODY == n->type) { 515 PAIR_CLASS_INIT(&tag[0], "ssec-body"); 516 if (n->parent->next && n->child) { 517 bufcat_su(h, "margin-bottom", &su); 518 PAIR_STYLE_INIT(&tag[1], h); 519 print_otag(h, TAG_DIV, 2, tag); 520 return(1); 521 } 522 523 print_otag(h, TAG_DIV, 1, tag); 524 return(1); 525 } else if (MAN_BLOCK == n->type) { 526 PAIR_CLASS_INIT(&tag[0], "ssec-block"); 527 if (n->prev && MAN_SS == n->prev->tok) 528 if (n->prev->body->child) { 529 bufcat_su(h, "margin-top", &su); 530 PAIR_STYLE_INIT(&tag[1], h); 531 print_otag(h, TAG_DIV, 2, tag); 532 return(1); 533 } 534 535 print_otag(h, TAG_DIV, 1, tag); 536 return(1); 537 } 538 539 SCALE_HS_INIT(&su, INDENT - HALFINDENT); 540 bufcat_su(h, "margin-left", &su); 541 PAIR_CLASS_INIT(&tag[0], "ssec-head"); 542 PAIR_STYLE_INIT(&tag[1], h); 543 print_otag(h, TAG_DIV, 2, tag); 544 return(1); 545 } 546 547 548 /* ARGSUSED */ 549 static int 550 man_PP_pre(MAN_ARGS) 551 { 552 struct htmlpair tag; 553 struct roffsu su; 554 int i; 555 556 if (MAN_BLOCK != n->type) 557 return(1); 558 559 i = 0; 560 561 if (MAN_ROOT == n->parent->type) { 562 SCALE_HS_INIT(&su, INDENT); 563 bufcat_su(h, "margin-left", &su); 564 i = 1; 565 } 566 if (n->prev) { 567 SCALE_VS_INIT(&su, 1); 568 bufcat_su(h, "margin-top", &su); 569 i = 1; 570 } 571 572 PAIR_STYLE_INIT(&tag, h); 573 print_otag(h, TAG_DIV, i, &tag); 574 return(1); 575 } 576 577 578 /* ARGSUSED */ 579 static int 580 man_IP_pre(MAN_ARGS) 581 { 582 struct roffsu su; 583 struct htmlpair tag; 584 const struct man_node *nn; 585 int width; 586 587 /* 588 * This scattering of 1-BU margins and pads is to make sure that 589 * when text overruns its box, the subsequent text isn't flush 590 * up against it. However, the rest of the right-hand box must 591 * also be adjusted in consideration of this 1-BU space. 592 */ 593 594 if (MAN_BODY == n->type) { 595 SCALE_HS_INIT(&su, INDENT); 596 bufcat_su(h, "margin-left", &su); 597 PAIR_STYLE_INIT(&tag, h); 598 print_otag(h, TAG_DIV, 1, &tag); 599 return(1); 600 } 601 602 nn = MAN_BLOCK == n->type ? 603 n->head->child : n->parent->head->child; 604 605 SCALE_HS_INIT(&su, INDENT); 606 width = 0; 607 608 /* Width is the last token. */ 609 610 if (MAN_IP == n->tok && NULL != nn) 611 if (NULL != (nn = nn->next)) { 612 for ( ; nn->next; nn = nn->next) 613 /* Do nothing. */ ; 614 width = a2width(nn, &su); 615 } 616 617 /* Width is the first token. */ 618 619 if (MAN_TP == n->tok && NULL != nn) { 620 /* Skip past non-text children. */ 621 while (nn && MAN_TEXT != nn->type) 622 nn = nn->next; 623 if (nn) 624 width = a2width(nn, &su); 625 } 626 627 if (MAN_BLOCK == n->type) { 628 bufcat_su(h, "margin-left", &su); 629 SCALE_VS_INIT(&su, 1); 630 bufcat_su(h, "margin-top", &su); 631 bufcat_style(h, "clear", "both"); 632 PAIR_STYLE_INIT(&tag, h); 633 print_otag(h, TAG_DIV, 1, &tag); 634 return(1); 635 } 636 637 bufcat_su(h, "min-width", &su); 638 SCALE_INVERT(&su); 639 bufcat_su(h, "margin-left", &su); 640 SCALE_HS_INIT(&su, 1); 641 bufcat_su(h, "margin-right", &su); 642 bufcat_style(h, "clear", "left"); 643 644 if (n->next && n->next->child) 645 bufcat_style(h, "float", "left"); 646 647 PAIR_STYLE_INIT(&tag, h); 648 print_otag(h, TAG_DIV, 1, &tag); 649 650 /* 651 * Without a length string, we can print all of our children. 652 */ 653 654 if ( ! width) 655 return(1); 656 657 /* 658 * When a length has been specified, we need to carefully print 659 * our child context: IP gets all children printed but the last 660 * (the width), while TP gets all children printed but the first 661 * (the width). 662 */ 663 664 if (MAN_IP == n->tok) 665 for (nn = n->child; nn->next; nn = nn->next) 666 print_man_node(m, nn, mh, h); 667 if (MAN_TP == n->tok) 668 for (nn = n->child->next; nn; nn = nn->next) 669 print_man_node(m, nn, mh, h); 670 671 return(0); 672 } 673 674 675 /* ARGSUSED */ 676 static int 677 man_HP_pre(MAN_ARGS) 678 { 679 const struct man_node *nn; 680 struct htmlpair tag; 681 struct roffsu su; 682 683 if (MAN_HEAD == n->type) 684 return(0); 685 686 nn = MAN_BLOCK == n->type ? 687 n->head->child : n->parent->head->child; 688 689 SCALE_HS_INIT(&su, INDENT); 690 691 if (NULL != nn) 692 (void)a2width(nn, &su); 693 694 if (MAN_BLOCK == n->type) { 695 bufcat_su(h, "margin-left", &su); 696 SCALE_VS_INIT(&su, 1); 697 bufcat_su(h, "margin-top", &su); 698 bufcat_style(h, "clear", "both"); 699 PAIR_STYLE_INIT(&tag, h); 700 print_otag(h, TAG_DIV, 1, &tag); 701 return(1); 702 } 703 704 bufcat_su(h, "margin-left", &su); 705 SCALE_INVERT(&su); 706 bufcat_su(h, "text-indent", &su); 707 708 PAIR_STYLE_INIT(&tag, h); 709 print_otag(h, TAG_DIV, 1, &tag); 710 return(1); 711 } 712 713 714 /* ARGSUSED */ 715 static int 716 man_B_pre(MAN_ARGS) 717 { 718 719 print_ofont(h, HTMLFONT_BOLD); 720 return(1); 721 } 722 723 724 /* ARGSUSED */ 725 static int 726 man_I_pre(MAN_ARGS) 727 { 728 729 print_ofont(h, HTMLFONT_ITALIC); 730 return(1); 731 } 732 733 734 /* ARGSUSED */ 735 static int 736 man_literal_pre(MAN_ARGS) 737 { 738 739 switch (n->tok) { 740 case (MAN_nf): 741 /* FALLTHROUGH */ 742 case (MAN_Vb): 743 print_otag(h, TAG_BR, 0, NULL); 744 mh->fl |= MANH_LITERAL; 745 return(MAN_Vb != n->tok); 746 default: 747 mh->fl &= ~MANH_LITERAL; 748 break; 749 } 750 751 return(1); 752 } 753 754 755 /* ARGSUSED */ 756 static int 757 man_in_pre(MAN_ARGS) 758 { 759 760 print_otag(h, TAG_BR, 0, NULL); 761 return(0); 762 } 763 764 765 /* ARGSUSED */ 766 static int 767 man_ign_pre(MAN_ARGS) 768 { 769 770 return(0); 771 } 772 773 774 /* ARGSUSED */ 775 static int 776 man_RS_pre(MAN_ARGS) 777 { 778 struct htmlpair tag; 779 struct roffsu su; 780 781 if (MAN_HEAD == n->type) 782 return(0); 783 else if (MAN_BODY == n->type) 784 return(1); 785 786 SCALE_HS_INIT(&su, INDENT); 787 bufcat_su(h, "margin-left", &su); 788 789 if (n->head->child) { 790 SCALE_VS_INIT(&su, 1); 791 a2width(n->head->child, &su); 792 bufcat_su(h, "margin-top", &su); 793 } 794 795 PAIR_STYLE_INIT(&tag, h); 796 print_otag(h, TAG_DIV, 1, &tag); 797 return(1); 798 } 799