Annotation of mandoc/html.c, Revision 1.138
1.138 ! kristaps 1: /* $Id: html.c,v 1.137 2011/04/30 22:24:31 kristaps Exp $ */
1.1 kristaps 2: /*
1.126 schwarze 3: * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4: * Copyright (c) 2011 Ingo Schwarze <schwarze@openbsd.org>
1.1 kristaps 5: *
6: * Permission to use, copy, modify, and distribute this software for any
1.29 kristaps 7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 9: *
1.29 kristaps 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 kristaps 17: */
1.92 kristaps 18: #ifdef HAVE_CONFIG_H
19: #include "config.h"
20: #endif
21:
1.41 kristaps 22: #include <sys/types.h>
1.30 kristaps 23:
1.1 kristaps 24: #include <assert.h>
1.68 kristaps 25: #include <ctype.h>
1.76 kristaps 26: #include <stdarg.h>
1.29 kristaps 27: #include <stdio.h>
1.63 kristaps 28: #include <stdint.h>
1.1 kristaps 29: #include <stdlib.h>
1.33 kristaps 30: #include <string.h>
1.45 kristaps 31: #include <unistd.h>
1.1 kristaps 32:
1.100 kristaps 33: #include "mandoc.h"
1.138 ! kristaps 34: #include "libmandoc.h"
1.58 kristaps 35: #include "out.h"
1.51 kristaps 36: #include "html.h"
1.64 kristaps 37: #include "main.h"
1.63 kristaps 38:
1.29 kristaps 39: struct htmldata {
1.63 kristaps 40: const char *name;
1.29 kristaps 41: int flags;
1.30 kristaps 42: #define HTML_CLRLINE (1 << 0)
43: #define HTML_NOSTACK (1 << 1)
1.93 kristaps 44: #define HTML_AUTOCLOSE (1 << 2) /* Tag has auto-closure. */
1.29 kristaps 45: };
1.7 kristaps 46:
1.29 kristaps 47: static const struct htmldata htmltags[TAG_MAX] = {
1.30 kristaps 48: {"html", HTML_CLRLINE}, /* TAG_HTML */
49: {"head", HTML_CLRLINE}, /* TAG_HEAD */
50: {"body", HTML_CLRLINE}, /* TAG_BODY */
1.93 kristaps 51: {"meta", HTML_CLRLINE | HTML_NOSTACK | HTML_AUTOCLOSE}, /* TAG_META */
1.33 kristaps 52: {"title", HTML_CLRLINE}, /* TAG_TITLE */
1.30 kristaps 53: {"div", HTML_CLRLINE}, /* TAG_DIV */
1.29 kristaps 54: {"h1", 0}, /* TAG_H1 */
55: {"h2", 0}, /* TAG_H2 */
56: {"span", 0}, /* TAG_SPAN */
1.99 kristaps 57: {"link", HTML_CLRLINE | HTML_NOSTACK | HTML_AUTOCLOSE}, /* TAG_LINK */
1.93 kristaps 58: {"br", HTML_CLRLINE | HTML_NOSTACK | HTML_AUTOCLOSE}, /* TAG_BR */
1.30 kristaps 59: {"a", 0}, /* TAG_A */
1.33 kristaps 60: {"table", HTML_CLRLINE}, /* TAG_TABLE */
1.114 kristaps 61: {"tbody", HTML_CLRLINE}, /* TAG_TBODY */
1.93 kristaps 62: {"col", HTML_CLRLINE | HTML_NOSTACK | HTML_AUTOCLOSE}, /* TAG_COL */
1.33 kristaps 63: {"tr", HTML_CLRLINE}, /* TAG_TR */
64: {"td", HTML_CLRLINE}, /* TAG_TD */
1.34 kristaps 65: {"li", HTML_CLRLINE}, /* TAG_LI */
66: {"ul", HTML_CLRLINE}, /* TAG_UL */
67: {"ol", HTML_CLRLINE}, /* TAG_OL */
1.114 kristaps 68: {"dl", HTML_CLRLINE}, /* TAG_DL */
69: {"dt", HTML_CLRLINE}, /* TAG_DT */
70: {"dd", HTML_CLRLINE}, /* TAG_DD */
1.115 kristaps 71: {"blockquote", HTML_CLRLINE}, /* TAG_BLOCKQUOTE */
1.116 kristaps 72: {"p", HTML_CLRLINE | HTML_NOSTACK | HTML_AUTOCLOSE}, /* TAG_P */
1.118 kristaps 73: {"pre", HTML_CLRLINE }, /* TAG_PRE */
1.119 kristaps 74: {"b", 0 }, /* TAG_B */
1.120 kristaps 75: {"i", 0 }, /* TAG_I */
1.121 kristaps 76: {"code", 0 }, /* TAG_CODE */
1.122 kristaps 77: {"small", 0 }, /* TAG_SMALL */
1.90 kristaps 78: };
79:
1.82 kristaps 80: static const char *const htmlattrs[ATTR_MAX] = {
1.119 kristaps 81: "http-equiv", /* ATTR_HTTPEQUIV */
82: "content", /* ATTR_CONTENT */
83: "name", /* ATTR_NAME */
84: "rel", /* ATTR_REL */
85: "href", /* ATTR_HREF */
86: "type", /* ATTR_TYPE */
87: "media", /* ATTR_MEDIA */
88: "class", /* ATTR_CLASS */
89: "style", /* ATTR_STYLE */
90: "width", /* ATTR_WIDTH */
91: "id", /* ATTR_ID */
92: "summary", /* ATTR_SUMMARY */
93: "align", /* ATTR_ALIGN */
1.125 kristaps 94: "colspan", /* ATTR_COLSPAN */
1.29 kristaps 95: };
1.10 kristaps 96:
1.126 schwarze 97: static void print_num(struct html *, const char *, size_t);
1.132 kristaps 98: static void print_spec(struct html *, const char *, size_t);
1.83 kristaps 99: static void print_res(struct html *, const char *, size_t);
1.82 kristaps 100: static void print_ctag(struct html *, enum htmltag);
1.93 kristaps 101: static void print_doctype(struct html *);
102: static void print_xmltype(struct html *);
1.88 kristaps 103: static int print_encode(struct html *, const char *, int);
1.132 kristaps 104: static void print_metaf(struct html *, enum mandoc_esc);
1.94 kristaps 105: static void print_attr(struct html *,
106: const char *, const char *);
1.93 kristaps 107: static void *ml_alloc(char *, enum htmltype);
1.82 kristaps 108:
109:
1.93 kristaps 110: static void *
111: ml_alloc(char *outopts, enum htmltype type)
1.10 kristaps 112: {
1.30 kristaps 113: struct html *h;
1.63 kristaps 114: const char *toks[4];
115: char *v;
1.43 kristaps 116:
117: toks[0] = "style";
1.53 kristaps 118: toks[1] = "man";
1.54 kristaps 119: toks[2] = "includes";
120: toks[3] = NULL;
1.30 kristaps 121:
1.128 kristaps 122: h = mandoc_calloc(1, sizeof(struct html));
1.10 kristaps 123:
1.93 kristaps 124: h->type = type;
1.66 kristaps 125: h->tags.head = NULL;
1.136 kristaps 126: h->symtab = mchars_alloc();
1.41 kristaps 127:
1.47 kristaps 128: while (outopts && *outopts)
1.63 kristaps 129: switch (getsubopt(&outopts, UNCONST(toks), &v)) {
1.43 kristaps 130: case (0):
131: h->style = v;
132: break;
133: case (1):
1.53 kristaps 134: h->base_man = v;
1.43 kristaps 135: break;
1.54 kristaps 136: case (2):
137: h->base_includes = v;
138: break;
1.43 kristaps 139: default:
140: break;
141: }
142:
1.30 kristaps 143: return(h);
1.29 kristaps 144: }
1.10 kristaps 145:
1.93 kristaps 146: void *
147: html_alloc(char *outopts)
148: {
149:
150: return(ml_alloc(outopts, HTML_HTML_4_01_STRICT));
151: }
152:
153:
154: void *
155: xhtml_alloc(char *outopts)
156: {
157:
158: return(ml_alloc(outopts, HTML_XHTML_1_0_STRICT));
159: }
160:
1.33 kristaps 161:
1.29 kristaps 162: void
163: html_free(void *p)
164: {
1.30 kristaps 165: struct tag *tag;
166: struct html *h;
167:
168: h = (struct html *)p;
1.37 kristaps 169:
1.66 kristaps 170: while ((tag = h->tags.head) != NULL) {
171: h->tags.head = tag->next;
1.30 kristaps 172: free(tag);
173: }
1.36 kristaps 174:
175: if (h->symtab)
1.133 kristaps 176: mchars_free(h->symtab);
1.53 kristaps 177:
1.30 kristaps 178: free(h);
1.10 kristaps 179: }
1.2 kristaps 180:
1.33 kristaps 181:
1.51 kristaps 182: void
1.29 kristaps 183: print_gen_head(struct html *h)
184: {
1.41 kristaps 185: struct htmlpair tag[4];
186:
187: tag[0].key = ATTR_HTTPEQUIV;
188: tag[0].val = "Content-Type";
189: tag[1].key = ATTR_CONTENT;
190: tag[1].val = "text/html; charset=utf-8";
191: print_otag(h, TAG_META, 2, tag);
192:
193: tag[0].key = ATTR_NAME;
194: tag[0].val = "resource-type";
195: tag[1].key = ATTR_CONTENT;
196: tag[1].val = "document";
197: print_otag(h, TAG_META, 2, tag);
198:
199: if (h->style) {
200: tag[0].key = ATTR_REL;
201: tag[0].val = "stylesheet";
202: tag[1].key = ATTR_HREF;
203: tag[1].val = h->style;
204: tag[2].key = ATTR_TYPE;
205: tag[2].val = "text/css";
206: tag[3].key = ATTR_MEDIA;
207: tag[3].val = "all";
208: print_otag(h, TAG_LINK, 4, tag);
209: }
1.4 kristaps 210: }
211:
1.127 kristaps 212: /* ARGSUSED */
1.29 kristaps 213: static void
1.126 schwarze 214: print_num(struct html *h, const char *p, size_t len)
215: {
1.137 kristaps 216: char c;
1.126 schwarze 217:
1.137 kristaps 218: if ('\0' != (c = mchars_num2char(p, len)))
219: putchar((int)c);
1.126 schwarze 220: }
221:
222: static void
1.132 kristaps 223: print_spec(struct html *h, const char *p, size_t len)
1.32 kristaps 224: {
1.107 kristaps 225: int cp;
1.32 kristaps 226: const char *rhs;
227: size_t sz;
228:
1.133 kristaps 229: if ((cp = mchars_spec2cp(h->symtab, p, len)) > 0) {
1.107 kristaps 230: printf("&#%d;", cp);
231: return;
1.132 kristaps 232: } else if (-1 == cp && 1 == len) {
1.108 kristaps 233: fwrite(p, 1, len, stdout);
234: return;
1.107 kristaps 235: } else if (-1 == cp)
236: return;
1.32 kristaps 237:
1.133 kristaps 238: if (NULL != (rhs = mchars_spec2str(h->symtab, p, len, &sz)))
1.107 kristaps 239: fwrite(rhs, 1, sz, stdout);
1.32 kristaps 240: }
241:
1.33 kristaps 242:
1.32 kristaps 243: static void
1.83 kristaps 244: print_res(struct html *h, const char *p, size_t len)
1.32 kristaps 245: {
1.107 kristaps 246: int cp;
1.32 kristaps 247: const char *rhs;
248: size_t sz;
249:
1.133 kristaps 250: if ((cp = mchars_res2cp(h->symtab, p, len)) > 0) {
1.107 kristaps 251: printf("&#%d;", cp);
252: return;
253: } else if (-1 == cp)
254: return;
1.32 kristaps 255:
1.133 kristaps 256: if (NULL != (rhs = mchars_res2str(h->symtab, p, len, &sz)))
1.107 kristaps 257: fwrite(rhs, 1, sz, stdout);
1.32 kristaps 258: }
259:
1.33 kristaps 260:
1.88 kristaps 261: static void
1.132 kristaps 262: print_metaf(struct html *h, enum mandoc_esc deco)
1.88 kristaps 263: {
1.90 kristaps 264: enum htmlfont font;
1.88 kristaps 265:
266: switch (deco) {
1.132 kristaps 267: case (ESCAPE_FONTPREV):
1.90 kristaps 268: font = h->metal;
1.88 kristaps 269: break;
1.132 kristaps 270: case (ESCAPE_FONTITALIC):
1.90 kristaps 271: font = HTMLFONT_ITALIC;
272: break;
1.132 kristaps 273: case (ESCAPE_FONTBOLD):
1.90 kristaps 274: font = HTMLFONT_BOLD;
1.88 kristaps 275: break;
1.132 kristaps 276: case (ESCAPE_FONTROMAN):
1.90 kristaps 277: font = HTMLFONT_NONE;
1.88 kristaps 278: break;
279: default:
280: abort();
281: /* NOTREACHED */
282: }
283:
1.122 kristaps 284: if (h->metaf) {
285: print_tagq(h, h->metaf);
286: h->metaf = NULL;
287: }
288:
289: h->metal = h->metac;
290: h->metac = font;
291:
292: if (HTMLFONT_NONE != font)
293: h->metaf = HTMLFONT_BOLD == font ?
294: print_otag(h, TAG_B, 0, NULL) :
295: print_otag(h, TAG_I, 0, NULL);
1.88 kristaps 296: }
297:
1.138 ! kristaps 298: int
! 299: html_strlen(const char *cp)
! 300: {
! 301: int ssz, sz;
! 302: const char *seq, *p;
! 303:
! 304: /*
! 305: * Account for escaped sequences within string length
! 306: * calculations. This follows the logic in term_strlen() as we
! 307: * must calculate the width of produced strings.
! 308: * Assume that characters are always width of "1". This is
! 309: * hacky, but it gets the job done for approximation of widths.
! 310: */
! 311:
! 312: sz = 0;
! 313: while (NULL != (p = strchr(cp, '\\'))) {
! 314: sz += (int)(p - cp);
! 315: ++cp;
! 316: switch (mandoc_escape(&cp, &seq, &ssz)) {
! 317: case (ESCAPE_ERROR):
! 318: return(sz);
! 319: case (ESCAPE_PREDEF):
! 320: sz++;
! 321: break;
! 322: case (ESCAPE_SPECIAL):
! 323: sz++;
! 324: break;
! 325: default:
! 326: break;
! 327: }
! 328: }
! 329:
! 330: assert(sz >= 0);
! 331: return(sz + strlen(cp));
! 332: }
1.88 kristaps 333:
1.85 kristaps 334: static int
1.88 kristaps 335: print_encode(struct html *h, const char *p, int norecurse)
1.29 kristaps 336: {
1.77 kristaps 337: size_t sz;
1.85 kristaps 338: int len, nospace;
1.82 kristaps 339: const char *seq;
1.132 kristaps 340: enum mandoc_esc esc;
1.100 kristaps 341: static const char rejs[6] = { '\\', '<', '>', '&', ASCII_HYPH, '\0' };
1.14 kristaps 342:
1.85 kristaps 343: nospace = 0;
344:
1.132 kristaps 345: while ('\0' != *p) {
1.100 kristaps 346: sz = strcspn(p, rejs);
1.77 kristaps 347:
348: fwrite(p, 1, sz, stdout);
1.132 kristaps 349: p += (int)sz;
1.77 kristaps 350:
1.132 kristaps 351: if ('\0' == *p)
352: break;
353:
354: switch (*p++) {
355: case ('<'):
1.82 kristaps 356: printf("<");
357: continue;
1.132 kristaps 358: case ('>'):
1.82 kristaps 359: printf(">");
360: continue;
1.132 kristaps 361: case ('&'):
1.82 kristaps 362: printf("&");
1.34 kristaps 363: continue;
1.132 kristaps 364: case (ASCII_HYPH):
1.100 kristaps 365: putchar('-');
366: continue;
1.132 kristaps 367: default:
1.77 kristaps 368: break;
1.132 kristaps 369: }
1.77 kristaps 370:
1.132 kristaps 371: esc = mandoc_escape(&p, &seq, &len);
372: if (ESCAPE_ERROR == esc)
373: break;
1.82 kristaps 374:
1.132 kristaps 375: switch (esc) {
376: case (ESCAPE_NUMBERED):
377: print_num(h, seq, len);
1.126 schwarze 378: break;
1.132 kristaps 379: case (ESCAPE_PREDEF):
380: print_res(h, seq, len);
1.82 kristaps 381: break;
1.132 kristaps 382: case (ESCAPE_SPECIAL):
383: print_spec(h, seq, len);
1.82 kristaps 384: break;
1.132 kristaps 385: case (ESCAPE_FONTPREV):
1.90 kristaps 386: /* FALLTHROUGH */
1.132 kristaps 387: case (ESCAPE_FONTBOLD):
1.88 kristaps 388: /* FALLTHROUGH */
1.132 kristaps 389: case (ESCAPE_FONTITALIC):
1.88 kristaps 390: /* FALLTHROUGH */
1.132 kristaps 391: case (ESCAPE_FONTROMAN):
1.88 kristaps 392: if (norecurse)
393: break;
1.132 kristaps 394: print_metaf(h, esc);
395: break;
396: case (ESCAPE_NOSPACE):
397: if ('\0' == *p)
398: nospace = 1;
1.88 kristaps 399: break;
1.82 kristaps 400: default:
401: break;
402: }
1.32 kristaps 403: }
1.85 kristaps 404:
405: return(nospace);
1.14 kristaps 406: }
407:
408:
1.94 kristaps 409: static void
410: print_attr(struct html *h, const char *key, const char *val)
411: {
412: printf(" %s=\"", key);
413: (void)print_encode(h, val, 1);
414: putchar('\"');
415: }
416:
417:
1.51 kristaps 418: struct tag *
1.29 kristaps 419: print_otag(struct html *h, enum htmltag tag,
420: int sz, const struct htmlpair *p)
1.14 kristaps 421: {
1.29 kristaps 422: int i;
1.30 kristaps 423: struct tag *t;
424:
1.94 kristaps 425: /* Push this tags onto the stack of open scopes. */
426:
1.30 kristaps 427: if ( ! (HTML_NOSTACK & htmltags[tag].flags)) {
1.128 kristaps 428: t = mandoc_malloc(sizeof(struct tag));
1.30 kristaps 429: t->tag = tag;
1.66 kristaps 430: t->next = h->tags.head;
431: h->tags.head = t;
1.30 kristaps 432: } else
433: t = NULL;
1.29 kristaps 434:
435: if ( ! (HTML_NOSPACE & h->flags))
1.105 kristaps 436: if ( ! (HTML_CLRLINE & htmltags[tag].flags)) {
437: /* Manage keeps! */
438: if ( ! (HTML_KEEP & h->flags)) {
439: if (HTML_PREKEEP & h->flags)
440: h->flags |= HTML_KEEP;
441: putchar(' ');
442: } else
443: printf(" ");
444: }
1.29 kristaps 445:
1.109 kristaps 446: if ( ! (h->flags & HTML_NONOSPACE))
447: h->flags &= ~HTML_NOSPACE;
1.110 kristaps 448: else
449: h->flags |= HTML_NOSPACE;
1.109 kristaps 450:
1.94 kristaps 451: /* Print out the tag name and attributes. */
452:
1.29 kristaps 453: printf("<%s", htmltags[tag].name);
1.94 kristaps 454: for (i = 0; i < sz; i++)
455: print_attr(h, htmlattrs[p[i].key], p[i].val);
456:
457: /* Add non-overridable attributes. */
458:
459: if (TAG_HTML == tag && HTML_XHTML_1_0_STRICT == h->type) {
460: print_attr(h, "xmlns", "http://www.w3.org/1999/xhtml");
461: print_attr(h, "xml:lang", "en");
462: print_attr(h, "lang", "en");
1.29 kristaps 463: }
1.93 kristaps 464:
1.134 kristaps 465: /* Accommodate for XML "well-formed" singleton escaping. */
1.94 kristaps 466:
1.93 kristaps 467: if (HTML_AUTOCLOSE & htmltags[tag].flags)
468: switch (h->type) {
469: case (HTML_XHTML_1_0_STRICT):
470: putchar('/');
471: break;
472: default:
473: break;
474: }
475:
1.78 kristaps 476: putchar('>');
1.14 kristaps 477:
1.29 kristaps 478: h->flags |= HTML_NOSPACE;
1.117 kristaps 479:
480: if ((HTML_AUTOCLOSE | HTML_CLRLINE) & htmltags[tag].flags)
481: putchar('\n');
482:
1.30 kristaps 483: return(t);
1.14 kristaps 484: }
485:
486:
1.29 kristaps 487: static void
488: print_ctag(struct html *h, enum htmltag tag)
1.14 kristaps 489: {
490:
1.29 kristaps 491: printf("</%s>", htmltags[tag].name);
1.71 kristaps 492: if (HTML_CLRLINE & htmltags[tag].flags) {
1.29 kristaps 493: h->flags |= HTML_NOSPACE;
1.78 kristaps 494: putchar('\n');
1.87 kristaps 495: }
1.14 kristaps 496: }
497:
498:
1.51 kristaps 499: void
1.93 kristaps 500: print_gen_decls(struct html *h)
1.1 kristaps 501: {
1.93 kristaps 502:
503: print_xmltype(h);
504: print_doctype(h);
505: }
506:
507:
508: static void
509: print_xmltype(struct html *h)
510: {
511:
1.100 kristaps 512: if (HTML_XHTML_1_0_STRICT == h->type)
1.121 kristaps 513: puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
1.93 kristaps 514: }
515:
516:
517: static void
518: print_doctype(struct html *h)
519: {
520: const char *doctype;
521: const char *dtd;
1.96 kristaps 522: const char *name;
1.93 kristaps 523:
524: switch (h->type) {
525: case (HTML_HTML_4_01_STRICT):
1.96 kristaps 526: name = "HTML";
1.93 kristaps 527: doctype = "-//W3C//DTD HTML 4.01//EN";
528: dtd = "http://www.w3.org/TR/html4/strict.dtd";
529: break;
530: default:
1.96 kristaps 531: name = "html";
1.93 kristaps 532: doctype = "-//W3C//DTD XHTML 1.0 Strict//EN";
533: dtd = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";
534: break;
535: }
536:
1.96 kristaps 537: printf("<!DOCTYPE %s PUBLIC \"%s\" \"%s\">\n",
538: name, doctype, dtd);
1.1 kristaps 539: }
540:
1.51 kristaps 541: void
1.104 kristaps 542: print_text(struct html *h, const char *word)
1.1 kristaps 543: {
544:
1.105 kristaps 545: if ( ! (HTML_NOSPACE & h->flags)) {
546: /* Manage keeps! */
547: if ( ! (HTML_KEEP & h->flags)) {
548: if (HTML_PREKEEP & h->flags)
549: h->flags |= HTML_KEEP;
550: putchar(' ');
551: } else
552: printf(" ");
553: }
1.30 kristaps 554:
1.122 kristaps 555: assert(NULL == h->metaf);
556: if (HTMLFONT_NONE != h->metac)
557: h->metaf = HTMLFONT_BOLD == h->metac ?
558: print_otag(h, TAG_B, 0, NULL) :
559: print_otag(h, TAG_I, 0, NULL);
560:
1.104 kristaps 561: assert(word);
562: if ( ! print_encode(h, word, 0))
1.109 kristaps 563: if ( ! (h->flags & HTML_NONOSPACE))
564: h->flags &= ~HTML_NOSPACE;
1.122 kristaps 565:
566: if (h->metaf) {
567: print_tagq(h, h->metaf);
568: h->metaf = NULL;
569: }
1.113 schwarze 570:
571: h->flags &= ~HTML_IGNDELIM;
1.1 kristaps 572: }
1.30 kristaps 573:
574:
1.51 kristaps 575: void
1.30 kristaps 576: print_tagq(struct html *h, const struct tag *until)
577: {
578: struct tag *tag;
579:
1.66 kristaps 580: while ((tag = h->tags.head) != NULL) {
1.125 kristaps 581: /*
582: * Remember to close out and nullify the current
583: * meta-font and table, if applicable.
584: */
1.89 kristaps 585: if (tag == h->metaf)
586: h->metaf = NULL;
1.125 kristaps 587: if (tag == h->tblt)
588: h->tblt = NULL;
1.30 kristaps 589: print_ctag(h, tag->tag);
1.66 kristaps 590: h->tags.head = tag->next;
1.30 kristaps 591: free(tag);
592: if (until && tag == until)
593: return;
594: }
595: }
596:
597:
1.51 kristaps 598: void
1.30 kristaps 599: print_stagq(struct html *h, const struct tag *suntil)
600: {
601: struct tag *tag;
602:
1.66 kristaps 603: while ((tag = h->tags.head) != NULL) {
1.30 kristaps 604: if (suntil && tag == suntil)
605: return;
1.125 kristaps 606: /*
607: * Remember to close out and nullify the current
608: * meta-font and table, if applicable.
609: */
1.89 kristaps 610: if (tag == h->metaf)
611: h->metaf = NULL;
1.125 kristaps 612: if (tag == h->tblt)
613: h->tblt = NULL;
1.30 kristaps 614: print_ctag(h, tag->tag);
1.66 kristaps 615: h->tags.head = tag->next;
1.30 kristaps 616: free(tag);
617: }
618: }
1.55 kristaps 619:
620:
621: void
622: bufinit(struct html *h)
623: {
624:
625: h->buf[0] = '\0';
626: h->buflen = 0;
627: }
628:
629:
630: void
1.58 kristaps 631: bufcat_style(struct html *h, const char *key, const char *val)
632: {
633:
634: bufcat(h, key);
635: bufncat(h, ":", 1);
636: bufcat(h, val);
637: bufncat(h, ";", 1);
638: }
639:
640:
641: void
1.55 kristaps 642: bufcat(struct html *h, const char *p)
643: {
644:
645: bufncat(h, p, strlen(p));
646: }
647:
648:
649: void
650: buffmt(struct html *h, const char *fmt, ...)
651: {
652: va_list ap;
653:
654: va_start(ap, fmt);
1.56 kristaps 655: (void)vsnprintf(h->buf + (int)h->buflen,
1.55 kristaps 656: BUFSIZ - h->buflen - 1, fmt, ap);
657: va_end(ap);
658: h->buflen = strlen(h->buf);
659: }
660:
661:
662: void
663: bufncat(struct html *h, const char *p, size_t sz)
664: {
665:
666: if (h->buflen + sz > BUFSIZ - 1)
667: sz = BUFSIZ - 1 - h->buflen;
668:
669: (void)strncat(h->buf, p, sz);
670: h->buflen += sz;
671: }
672:
673:
674: void
675: buffmt_includes(struct html *h, const char *name)
676: {
677: const char *p, *pp;
678:
679: pp = h->base_includes;
1.61 kristaps 680:
681: while (NULL != (p = strchr(pp, '%'))) {
1.56 kristaps 682: bufncat(h, pp, (size_t)(p - pp));
1.55 kristaps 683: switch (*(p + 1)) {
684: case('I'):
685: bufcat(h, name);
686: break;
687: default:
688: bufncat(h, p, 2);
689: break;
690: }
691: pp = p + 2;
692: }
693: if (pp)
694: bufcat(h, pp);
695: }
696:
697:
698: void
699: buffmt_man(struct html *h,
700: const char *name, const char *sec)
701: {
702: const char *p, *pp;
703:
704: pp = h->base_man;
1.61 kristaps 705:
706: /* LINTED */
707: while (NULL != (p = strchr(pp, '%'))) {
1.56 kristaps 708: bufncat(h, pp, (size_t)(p - pp));
1.55 kristaps 709: switch (*(p + 1)) {
710: case('S'):
1.58 kristaps 711: bufcat(h, sec ? sec : "1");
1.55 kristaps 712: break;
713: case('N'):
1.58 kristaps 714: buffmt(h, name);
1.55 kristaps 715: break;
716: default:
717: bufncat(h, p, 2);
718: break;
719: }
720: pp = p + 2;
721: }
722: if (pp)
723: bufcat(h, pp);
724: }
1.58 kristaps 725:
726:
727: void
728: bufcat_su(struct html *h, const char *p, const struct roffsu *su)
729: {
1.62 kristaps 730: double v;
1.63 kristaps 731: const char *u;
1.58 kristaps 732:
733: v = su->scale;
734:
735: switch (su->unit) {
736: case (SCALE_CM):
737: u = "cm";
738: break;
739: case (SCALE_IN):
740: u = "in";
741: break;
742: case (SCALE_PC):
743: u = "pc";
744: break;
745: case (SCALE_PT):
746: u = "pt";
747: break;
1.59 kristaps 748: case (SCALE_EM):
749: u = "em";
750: break;
1.58 kristaps 751: case (SCALE_MM):
752: if (0 == (v /= 100))
753: v = 1;
754: u = "em";
755: break;
1.59 kristaps 756: case (SCALE_EN):
757: u = "ex";
758: break;
759: case (SCALE_BU):
760: u = "ex";
761: break;
1.58 kristaps 762: case (SCALE_VS):
763: u = "em";
764: break;
765: default:
766: u = "ex";
767: break;
768: }
769:
1.103 kristaps 770: /*
771: * XXX: the CSS spec isn't clear as to which types accept
772: * integer or real numbers, so we just make them all decimals.
773: */
774: buffmt(h, "%s: %.2f%s;", p, v, u);
1.58 kristaps 775: }
1.65 kristaps 776:
1.68 kristaps 777:
778: void
1.70 kristaps 779: html_idcat(char *dst, const char *src, int sz)
1.68 kristaps 780: {
1.70 kristaps 781: int ssz;
1.68 kristaps 782:
1.124 schwarze 783: assert(sz > 2);
1.68 kristaps 784:
785: /* Cf. <http://www.w3.org/TR/html4/types.html#h-6.2>. */
786:
1.124 schwarze 787: /* We can't start with a number (bah). */
788:
789: if ('#' == *dst) {
790: dst++;
791: sz--;
792: }
793: if ('\0' == *dst) {
794: *dst++ = 'x';
795: *dst = '\0';
796: sz--;
797: }
798:
1.70 kristaps 799: for ( ; *dst != '\0' && sz; dst++, sz--)
1.68 kristaps 800: /* Jump to end. */ ;
1.70 kristaps 801:
802: for ( ; *src != '\0' && sz > 1; src++) {
1.73 kristaps 803: ssz = snprintf(dst, (size_t)sz, "%.2x", *src);
1.70 kristaps 804: sz -= ssz;
805: dst += ssz;
806: }
1.68 kristaps 807: }
CVSweb