Annotation of mandoc/html.c, Revision 1.29
1.29 ! kristaps 1: /* $Id: tree.c,v 1.14 2009/08/13 11:45:29 kristaps Exp $ */
1.1 kristaps 2: /*
1.29 ! kristaps 3: * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
1.1 kristaps 4: *
5: * Permission to use, copy, modify, and distribute this software for any
1.29 ! kristaps 6: * purpose with or without fee is hereby granted, provided that the above
! 7: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 8: *
1.29 ! kristaps 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.
1.1 kristaps 16: */
17: #include <assert.h>
1.4 kristaps 18: #include <err.h>
1.29 ! kristaps 19: #include <stdio.h>
1.1 kristaps 20: #include <stdlib.h>
21:
1.29 ! kristaps 22: #include "mdoc.h"
! 23: #include "man.h"
1.2 kristaps 24:
1.29 ! kristaps 25: #define DOCTYPE "-//W3C//DTD HTML 4.01//EN"
! 26: #define DTD "http://www.w3.org/TR/html4/strict.dtd"
1.8 kristaps 27:
1.29 ! kristaps 28: enum htmltag {
! 29: TAG_HTML,
! 30: TAG_HEAD,
! 31: TAG_BODY,
! 32: TAG_META,
! 33: TAG_TITLE,
! 34: TAG_DIV,
! 35: TAG_H1,
! 36: TAG_H2,
! 37: TAG_P,
! 38: TAG_SPAN,
! 39: TAG_LINK,
! 40: TAG_MAX
1.7 kristaps 41: };
42:
1.29 ! kristaps 43: enum htmlattr {
! 44: ATTR_HTTPEQUIV,
! 45: ATTR_CONTENT,
! 46: ATTR_NAME,
! 47: ATTR_REL,
! 48: ATTR_HREF,
! 49: ATTR_TYPE,
! 50: ATTR_MEDIA,
! 51: ATTR_CLASS,
! 52: ATTR_MAX
1.7 kristaps 53: };
54:
1.29 ! kristaps 55: struct htmldata {
! 56: char *name;
! 57: int flags;
! 58: #define HTML_BLOCK (1 << 0)
! 59: };
1.7 kristaps 60:
1.29 ! kristaps 61: static const struct htmldata htmltags[TAG_MAX] = {
! 62: {"html", HTML_BLOCK}, /* TAG_HTML */
! 63: {"head", HTML_BLOCK}, /* TAG_HEAD */
! 64: {"body", HTML_BLOCK}, /* TAG_BODY */
! 65: {"meta", HTML_BLOCK}, /* TAG_META */
! 66: {"title", HTML_BLOCK}, /* TAG_TITLE */
! 67: {"div", HTML_BLOCK}, /* TAG_DIV */
! 68: {"h1", 0}, /* TAG_H1 */
! 69: {"h2", 0}, /* TAG_H2 */
! 70: {"p", HTML_BLOCK}, /* TAG_P */
! 71: {"span", 0}, /* TAG_SPAN */
! 72: {"link", HTML_BLOCK}, /* TAG_LINK */
! 73: };
1.10 kristaps 74:
1.29 ! kristaps 75: static const char *const htmlattrs[ATTR_MAX] = {
! 76: "http-equiv",
! 77: "content",
! 78: "name",
! 79: "rel",
! 80: "href",
! 81: "type",
! 82: "media",
! 83: "class"
! 84: };
1.10 kristaps 85:
1.29 ! kristaps 86: struct htmlpair {
! 87: enum htmlattr key;
! 88: char *val;
! 89: };
1.10 kristaps 90:
1.29 ! kristaps 91: struct html {
! 92: int flags;
! 93: #define HTML_NOSPACE (1 << 0)
! 94: };
1.10 kristaps 95:
1.29 ! kristaps 96: #define MDOC_ARGS const struct mdoc_meta *m, \
! 97: const struct mdoc_node *n, \
! 98: struct html *h
! 99: #define MAN_ARGS const struct man_meta *m, \
! 100: const struct man_node *n, \
! 101: struct html *h
! 102: struct htmlmdoc {
! 103: int (*pre)(MDOC_ARGS);
! 104: void (*post)(MDOC_ARGS);
! 105: };
1.13 kristaps 106:
1.29 ! kristaps 107: static void print_gen_doctype(struct html *);
! 108: static void print_gen_head(struct html *);
! 109: static void print_mdoc(MDOC_ARGS);
! 110: static void print_mdoc_head(MDOC_ARGS);
! 111: static void print_mdoc_node(MDOC_ARGS);
! 112: static void print_man(MAN_ARGS);
! 113: static void print_man_head(MAN_ARGS);
! 114: static void print_man_body(MAN_ARGS);
! 115: static void print_otag(struct html *, enum htmltag,
! 116: int, const struct htmlpair *);
! 117: static void print_ctag(struct html *, enum htmltag);
! 118: static void print_encode(const char *);
! 119: static void print_text(struct html *, const char *);
! 120: static int mdoc_root_pre(MDOC_ARGS);
! 121: static void mdoc_root_post(MDOC_ARGS);
! 122:
! 123: static int mdoc_nd_pre(MDOC_ARGS);
! 124: static int mdoc_nm_pre(MDOC_ARGS);
! 125: static void mdoc_nm_post(MDOC_ARGS);
! 126: static int mdoc_pp_pre(MDOC_ARGS);
! 127: static int mdoc_sh_pre(MDOC_ARGS);
! 128: static void mdoc_sh_post(MDOC_ARGS);
! 129: static int mdoc_ss_pre(MDOC_ARGS);
! 130: static void mdoc_ss_post(MDOC_ARGS);
! 131:
! 132: static const struct htmlmdoc mdocs[MDOC_MAX] = {
! 133: {NULL, NULL}, /* Ap */
! 134: {NULL, NULL}, /* Dd */
! 135: {NULL, NULL}, /* Dt */
! 136: {NULL, NULL}, /* Os */
! 137: {mdoc_sh_pre, mdoc_sh_post }, /* Sh */
! 138: {mdoc_ss_pre, mdoc_ss_post }, /* Ss */
! 139: {mdoc_pp_pre, NULL}, /* Pp */
! 140: {NULL, NULL}, /* D1 */
! 141: {NULL, NULL}, /* Dl */
! 142: {NULL, NULL}, /* Bd */
! 143: {NULL, NULL}, /* Ed */
! 144: {NULL, NULL}, /* Bl */
! 145: {NULL, NULL}, /* El */
! 146: {NULL, NULL}, /* It */
! 147: {NULL, NULL}, /* Ad */
! 148: {NULL, NULL}, /* An */
! 149: {NULL, NULL}, /* Ar */
! 150: {NULL, NULL}, /* Cd */
! 151: {NULL, NULL}, /* Cm */
! 152: {NULL, NULL}, /* Dv */
! 153: {NULL, NULL}, /* Er */
! 154: {NULL, NULL}, /* Ev */
! 155: {NULL, NULL}, /* Ex */
! 156: {NULL, NULL}, /* Fa */
! 157: {NULL, NULL}, /* Fd */
! 158: {NULL, NULL}, /* Fl */
! 159: {NULL, NULL}, /* Fn */
! 160: {NULL, NULL}, /* Ft */
! 161: {NULL, NULL}, /* Ic */
! 162: {NULL, NULL}, /* In */
! 163: {NULL, NULL}, /* Li */
! 164: {mdoc_nd_pre, NULL}, /* Nd */
! 165: {mdoc_nm_pre, mdoc_nm_post}, /* Nm */
! 166: {NULL, NULL}, /* Op */
! 167: {NULL, NULL}, /* Ot */
! 168: {NULL, NULL}, /* Pa */
! 169: {NULL, NULL}, /* Rv */
! 170: {NULL, NULL}, /* St */
! 171: {NULL, NULL}, /* Va */
! 172: {NULL, NULL}, /* Vt */
! 173: {NULL, NULL}, /* Xr */
! 174: {NULL, NULL}, /* %A */
! 175: {NULL, NULL}, /* %B */
! 176: {NULL, NULL}, /* %D */
! 177: {NULL, NULL}, /* %I */
! 178: {NULL, NULL}, /* %J */
! 179: {NULL, NULL}, /* %N */
! 180: {NULL, NULL}, /* %O */
! 181: {NULL, NULL}, /* %P */
! 182: {NULL, NULL}, /* %R */
! 183: {NULL, NULL}, /* %T */
! 184: {NULL, NULL}, /* %V */
! 185: {NULL, NULL}, /* Ac */
! 186: {NULL, NULL}, /* Ao */
! 187: {NULL, NULL}, /* Aq */
! 188: {NULL, NULL}, /* At */
! 189: {NULL, NULL}, /* Bc */
! 190: {NULL, NULL}, /* Bf */
! 191: {NULL, NULL}, /* Bo */
! 192: {NULL, NULL}, /* Bq */
! 193: {NULL, NULL}, /* Bsx */
! 194: {NULL, NULL}, /* Bx */
! 195: {NULL, NULL}, /* Db */
! 196: {NULL, NULL}, /* Dc */
! 197: {NULL, NULL}, /* Do */
! 198: {NULL, NULL}, /* Dq */
! 199: {NULL, NULL}, /* Ec */
! 200: {NULL, NULL}, /* Ef */
! 201: {NULL, NULL}, /* Em */
! 202: {NULL, NULL}, /* Eo */
! 203: {NULL, NULL}, /* Fx */
! 204: {NULL, NULL}, /* Ms */
! 205: {NULL, NULL}, /* No */
! 206: {NULL, NULL}, /* Ns */
! 207: {NULL, NULL}, /* Nx */
! 208: {NULL, NULL}, /* Ox */
! 209: {NULL, NULL}, /* Pc */
! 210: {NULL, NULL}, /* Pf */
! 211: {NULL, NULL}, /* Po */
! 212: {NULL, NULL}, /* Pq */
! 213: {NULL, NULL}, /* Qc */
! 214: {NULL, NULL}, /* Ql */
! 215: {NULL, NULL}, /* Qo */
! 216: {NULL, NULL}, /* Qq */
! 217: {NULL, NULL}, /* Re */
! 218: {NULL, NULL}, /* Rs */
! 219: {NULL, NULL}, /* Sc */
! 220: {NULL, NULL}, /* So */
! 221: {NULL, NULL}, /* Sq */
! 222: {NULL, NULL}, /* Sm */
! 223: {NULL, NULL}, /* Sx */
! 224: {NULL, NULL}, /* Sy */
! 225: {NULL, NULL}, /* Tn */
! 226: {NULL, NULL}, /* Ux */
! 227: {NULL, NULL}, /* Xc */
! 228: {NULL, NULL}, /* Xo */
! 229: {NULL, NULL}, /* Fo */
! 230: {NULL, NULL}, /* Fc */
! 231: {NULL, NULL}, /* Oo */
! 232: {NULL, NULL}, /* Oc */
! 233: {NULL, NULL}, /* Bk */
! 234: {NULL, NULL}, /* Ek */
! 235: {NULL, NULL}, /* Bt */
! 236: {NULL, NULL}, /* Hf */
! 237: {NULL, NULL}, /* Fr */
! 238: {NULL, NULL}, /* Ud */
! 239: {NULL, NULL}, /* Lb */
! 240: {NULL, NULL}, /* Lp */
! 241: {NULL, NULL}, /* Lk */
! 242: {NULL, NULL}, /* Mt */
! 243: {NULL, NULL}, /* Brq */
! 244: {NULL, NULL}, /* Bro */
! 245: {NULL, NULL}, /* Brc */
! 246: {NULL, NULL}, /* %C */
! 247: {NULL, NULL}, /* Es */
! 248: {NULL, NULL}, /* En */
! 249: {NULL, NULL}, /* Dx */
! 250: {NULL, NULL}, /* %Q */
! 251: {NULL, NULL}, /* br */
! 252: {NULL, NULL}, /* sp */
! 253: };
1.10 kristaps 254:
255:
1.29 ! kristaps 256: int
! 257: html_mdoc(void *arg, const struct mdoc *m)
1.10 kristaps 258: {
1.29 ! kristaps 259: struct html *h;
1.10 kristaps 260:
1.29 ! kristaps 261: h = (struct html *)arg;
1.10 kristaps 262:
1.29 ! kristaps 263: print_gen_doctype(h);
! 264: print_otag(h, TAG_HTML, 0, NULL);
! 265: print_mdoc(mdoc_meta(m), mdoc_node(m), h);
! 266: print_ctag(h, TAG_HTML);
! 267: printf("\n");
! 268: return(1);
1.10 kristaps 269: }
270:
271:
1.29 ! kristaps 272: int
! 273: html_man(void *arg, const struct man *m)
1.10 kristaps 274: {
1.29 ! kristaps 275: struct html *h;
1.10 kristaps 276:
1.29 ! kristaps 277: h = (struct html *)arg;
1.10 kristaps 278:
1.29 ! kristaps 279: print_gen_doctype(h);
! 280: print_otag(h, TAG_HTML, 0, NULL);
! 281: print_man(man_meta(m), man_node(m), h);
! 282: print_ctag(h, TAG_HTML);
! 283: printf("\n");
! 284: return(1);
1.10 kristaps 285: }
286:
287:
1.29 ! kristaps 288: void *
! 289: html_alloc(void)
1.10 kristaps 290: {
291:
1.29 ! kristaps 292: return(calloc(1, sizeof(struct html)));
! 293: }
1.10 kristaps 294:
1.13 kristaps 295:
1.29 ! kristaps 296: void
! 297: html_free(void *p)
! 298: {
1.10 kristaps 299:
1.29 ! kristaps 300: free(p);
1.10 kristaps 301: }
1.2 kristaps 302:
303:
1.29 ! kristaps 304: static void
! 305: print_mdoc(MDOC_ARGS)
1.4 kristaps 306: {
307:
1.29 ! kristaps 308: print_otag(h, TAG_HEAD, 0, NULL);
! 309: print_mdoc_head(m, n, h);
! 310: print_ctag(h, TAG_HEAD);
! 311: print_otag(h, TAG_BODY, 0, NULL);
! 312: print_mdoc_node(m, n, h);
! 313: print_ctag(h, TAG_BODY);
! 314: }
1.4 kristaps 315:
316:
1.29 ! kristaps 317: static void
! 318: print_gen_head(struct html *h)
! 319: {
! 320: struct htmlpair meta0[2];
! 321: struct htmlpair meta1[2];
! 322: struct htmlpair link[4];
! 323:
! 324: meta0[0].key = ATTR_HTTPEQUIV;
! 325: meta0[0].val = "Content-Type";
! 326: meta0[1].key = ATTR_CONTENT;
! 327: meta0[1].val = "text/html; charest-utf-8";
! 328:
! 329: meta1[0].key = ATTR_NAME;
! 330: meta1[0].val = "resource-type";
! 331: meta1[1].key = ATTR_CONTENT;
! 332: meta1[1].val = "document";
! 333:
! 334: link[0].key = ATTR_REL;
! 335: link[0].val = "stylesheet";
! 336: link[1].key = ATTR_HREF;
! 337: link[1].val = "style.css";
! 338: link[2].key = ATTR_TYPE;
! 339: link[2].val = "text/css";
! 340: link[3].key = ATTR_MEDIA;
! 341: link[3].val = "all";
! 342:
! 343: print_otag(h, TAG_META, 2, meta0);
! 344: print_otag(h, TAG_META, 2, meta1);
! 345: print_otag(h, TAG_LINK, 4, link);
1.4 kristaps 346: }
347:
348:
1.29 ! kristaps 349: static void
! 350: print_mdoc_head(MDOC_ARGS)
1.18 kristaps 351: {
352:
1.29 ! kristaps 353: print_gen_head(h);
! 354: print_otag(h, TAG_TITLE, 0, NULL);
! 355: print_encode(m->title);
! 356: print_ctag(h, TAG_TITLE);
1.18 kristaps 357: }
358:
359:
360: static int
1.29 ! kristaps 361: mdoc_root_pre(MDOC_ARGS)
1.18 kristaps 362: {
1.29 ! kristaps 363: struct htmlpair div;
1.18 kristaps 364:
1.29 ! kristaps 365: div.key = ATTR_CLASS;
! 366: div.val = "body";
1.18 kristaps 367:
1.29 ! kristaps 368: print_otag(h, TAG_DIV, 1, &div);
! 369: return(1);
1.2 kristaps 370: }
371:
372:
1.29 ! kristaps 373: static void
! 374: mdoc_root_post(MDOC_ARGS)
1.2 kristaps 375: {
1.22 kristaps 376:
1.29 ! kristaps 377: print_ctag(h, TAG_DIV);
1.2 kristaps 378: }
379:
380:
1.7 kristaps 381: static int
1.29 ! kristaps 382: mdoc_ss_pre(MDOC_ARGS)
1.2 kristaps 383: {
1.3 kristaps 384:
1.29 ! kristaps 385: if (MDOC_BODY == n->type)
! 386: print_otag(h, TAG_P, 0, NULL);
! 387: if (MDOC_HEAD == n->type)
! 388: print_otag(h, TAG_H2, 0, NULL);
! 389: return(1);
1.3 kristaps 390: }
391:
392:
1.29 ! kristaps 393: static void
! 394: mdoc_ss_post(MDOC_ARGS)
! 395: {
1.10 kristaps 396:
1.29 ! kristaps 397: if (MDOC_BODY == n->type)
! 398: print_ctag(h, TAG_P);
! 399: if (MDOC_HEAD == n->type)
! 400: print_ctag(h, TAG_H2);
1.3 kristaps 401: }
402:
403:
1.7 kristaps 404: static int
1.29 ! kristaps 405: mdoc_pp_pre(MDOC_ARGS)
1.3 kristaps 406: {
407:
1.29 ! kristaps 408: print_otag(h, TAG_P, 0, NULL);
! 409: return(0);
1.3 kristaps 410: }
411:
412:
1.7 kristaps 413: static int
1.29 ! kristaps 414: mdoc_nd_pre(MDOC_ARGS)
1.3 kristaps 415: {
416:
1.29 ! kristaps 417: if (MDOC_BODY == n->type)
! 418: print_text(h, "--");
! 419: return(1);
1.3 kristaps 420: }
421:
422:
1.7 kristaps 423: static int
1.29 ! kristaps 424: mdoc_nm_pre(MDOC_ARGS)
1.3 kristaps 425: {
1.29 ! kristaps 426: struct htmlpair class;
1.3 kristaps 427:
1.29 ! kristaps 428: class.key = ATTR_CLASS;
! 429: class.val = "name";
1.3 kristaps 430:
1.29 ! kristaps 431: print_otag(h, TAG_SPAN, 1, &class);
! 432: if (NULL == n->child)
! 433: print_text(h, m->name);
1.3 kristaps 434:
1.29 ! kristaps 435: return(1);
1.2 kristaps 436: }
437:
438:
1.29 ! kristaps 439: static void
! 440: mdoc_nm_post(MDOC_ARGS)
1.2 kristaps 441: {
1.3 kristaps 442:
1.29 ! kristaps 443: print_ctag(h, TAG_SPAN);
1.2 kristaps 444: }
1.1 kristaps 445:
446:
1.7 kristaps 447: static int
1.29 ! kristaps 448: mdoc_sh_pre(MDOC_ARGS)
! 449: {
1.19 kristaps 450:
1.29 ! kristaps 451: if (MDOC_BODY == n->type)
! 452: print_otag(h, TAG_P, 0, NULL);
! 453: if (MDOC_HEAD == n->type)
! 454: print_otag(h, TAG_H1, 0, NULL);
1.12 kristaps 455: return(1);
1.2 kristaps 456: }
457:
458:
1.29 ! kristaps 459: static void
! 460: mdoc_sh_post(MDOC_ARGS)
1.2 kristaps 461: {
462:
1.29 ! kristaps 463: if (MDOC_BODY == n->type)
! 464: print_ctag(h, TAG_P);
! 465: if (MDOC_HEAD == n->type)
! 466: print_ctag(h, TAG_H1);
1.2 kristaps 467: }
468:
469:
1.29 ! kristaps 470: static void
! 471: print_mdoc_node(MDOC_ARGS)
1.2 kristaps 472: {
1.29 ! kristaps 473: int child;
1.8 kristaps 474:
1.29 ! kristaps 475: child = 1;
1.8 kristaps 476:
1.29 ! kristaps 477: switch (n->type) {
! 478: case (MDOC_ROOT):
! 479: child = mdoc_root_pre(m, n, h);
1.7 kristaps 480: break;
1.29 ! kristaps 481: case (MDOC_TEXT):
! 482: print_text(h, n->string);
1.7 kristaps 483: break;
1.3 kristaps 484: default:
1.29 ! kristaps 485: if (mdocs[n->tok].pre)
! 486: child = (*mdocs[n->tok].pre)(m, n, h);
1.3 kristaps 487: break;
1.2 kristaps 488: }
489:
1.29 ! kristaps 490: if (child && n->child)
! 491: print_mdoc_node(m, n->child, h);
1.8 kristaps 492:
1.29 ! kristaps 493: switch (n->type) {
! 494: case (MDOC_ROOT):
! 495: mdoc_root_post(m, n, h);
1.7 kristaps 496: break;
1.29 ! kristaps 497: case (MDOC_TEXT):
1.7 kristaps 498: break;
1.3 kristaps 499: default:
1.29 ! kristaps 500: if (mdocs[n->tok].post)
! 501: (*mdocs[n->tok].post)(m, n, h);
1.3 kristaps 502: break;
503: }
1.2 kristaps 504:
1.29 ! kristaps 505: if (n->next)
! 506: print_mdoc_node(m, n->next, h);
1.2 kristaps 507: }
508:
509:
1.29 ! kristaps 510: static void
! 511: print_man(MAN_ARGS)
1.9 kristaps 512: {
513:
1.29 ! kristaps 514: print_otag(h, TAG_HEAD, 0, NULL);
! 515: print_man_head(m, n, h);
! 516: print_ctag(h, TAG_HEAD);
! 517: print_otag(h, TAG_BODY, 0, NULL);
! 518: print_man_body(m, n, h);
! 519: print_ctag(h, TAG_BODY);
1.9 kristaps 520: }
521:
522:
523: static void
1.29 ! kristaps 524: print_man_head(MAN_ARGS)
1.9 kristaps 525: {
526:
1.29 ! kristaps 527: print_gen_head(h);
! 528: print_otag(h, TAG_TITLE, 0, NULL);
! 529: print_encode(m->title);
! 530: print_ctag(h, TAG_TITLE);
! 531: }
1.9 kristaps 532:
533:
1.29 ! kristaps 534: static void
! 535: print_man_body(MAN_ARGS)
! 536: {
1.9 kristaps 537: }
538:
539:
1.29 ! kristaps 540: static void
! 541: print_encode(const char *p)
! 542: {
1.14 kristaps 543:
1.29 ! kristaps 544: printf("%s", p); /* XXX */
1.14 kristaps 545: }
546:
547:
1.29 ! kristaps 548: static void
! 549: print_otag(struct html *h, enum htmltag tag,
! 550: int sz, const struct htmlpair *p)
1.14 kristaps 551: {
1.29 ! kristaps 552: int i;
! 553:
! 554: if ( ! (HTML_NOSPACE & h->flags))
! 555: if ( ! (HTML_BLOCK & htmltags[tag].flags))
! 556: printf(" ");
! 557:
! 558: printf("<%s", htmltags[tag].name);
! 559: for (i = 0; i < sz; i++) {
! 560: printf(" %s=\"", htmlattrs[p[i].key]);
! 561: assert(p->val);
! 562: print_encode(p[i].val);
! 563: printf("\"");
! 564: }
! 565: printf(">");
1.14 kristaps 566:
1.29 ! kristaps 567: h->flags |= HTML_NOSPACE;
1.14 kristaps 568:
569: }
570:
571:
572: /* ARGSUSED */
1.29 ! kristaps 573: static void
! 574: print_ctag(struct html *h, enum htmltag tag)
1.14 kristaps 575: {
576:
1.29 ! kristaps 577: printf("</%s>", htmltags[tag].name);
! 578: if (HTML_BLOCK & htmltags[tag].flags)
! 579: h->flags |= HTML_NOSPACE;
1.14 kristaps 580: }
581:
582:
1.29 ! kristaps 583: /* ARGSUSED */
! 584: static void
! 585: print_gen_doctype(struct html *h)
1.1 kristaps 586: {
1.29 ! kristaps 587:
! 588: printf("<!DOCTYPE HTML PUBLIC \"%s\" \"%s\">\n", DOCTYPE, DTD);
1.1 kristaps 589: }
590:
591:
1.29 ! kristaps 592: static void
! 593: print_text(struct html *h, const char *p)
1.1 kristaps 594: {
595:
1.29 ! kristaps 596: if (*p && 0 == *(p + 1))
! 597: switch (*p) {
! 598: case('.'):
! 599: /* FALLTHROUGH */
! 600: case(','):
! 601: /* FALLTHROUGH */
! 602: case(';'):
! 603: /* FALLTHROUGH */
! 604: case(':'):
! 605: /* FALLTHROUGH */
! 606: case('?'):
! 607: /* FALLTHROUGH */
! 608: case('!'):
! 609: /* FALLTHROUGH */
! 610: case(')'):
! 611: /* FALLTHROUGH */
! 612: case(']'):
! 613: /* FALLTHROUGH */
! 614: case('}'):
! 615: h->flags |= HTML_NOSPACE;
! 616: default:
! 617: break;
! 618: }
1.1 kristaps 619:
1.29 ! kristaps 620: if ( ! (h->flags & HTML_NOSPACE))
! 621: printf(" ");
! 622: h->flags &= ~HTML_NOSPACE;
1.1 kristaps 623:
1.29 ! kristaps 624: if (p)
! 625: print_encode(p);
1.8 kristaps 626:
1.29 ! kristaps 627: if (*p && 0 == *(p + 1))
! 628: switch (*p) {
! 629: case('('):
! 630: /* FALLTHROUGH */
! 631: case('['):
! 632: /* FALLTHROUGH */
! 633: case('{'):
! 634: h->flags |= HTML_NOSPACE;
! 635: default:
! 636: break;
! 637: }
1.1 kristaps 638: }
CVSweb