Print this page
9718 update mandoc to 1.14.4
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/mandoc/html.c
+++ new/usr/src/cmd/mandoc/html.c
1 -/* $Id: html.c,v 1.219 2017/07/15 17:57:51 schwarze Exp $ */
1 +/* $Id: html.c,v 1.238 2018/06/25 16:54:59 schwarze Exp $ */
2 2 /*
3 3 * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
4 - * Copyright (c) 2011-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
4 + * Copyright (c) 2011-2015, 2017, 2018 Ingo Schwarze <schwarze@openbsd.org>
5 5 *
6 6 * Permission to use, copy, modify, and distribute this software for any
7 7 * purpose with or without fee is hereby granted, provided that the above
8 8 * copyright notice and this permission notice appear in all copies.
9 9 *
10 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
11 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
13 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 17 */
18 18 #include "config.h"
19 19
20 20 #include <sys/types.h>
21 21
22 22 #include <assert.h>
23 23 #include <ctype.h>
24 24 #include <stdarg.h>
25 +#include <stddef.h>
25 26 #include <stdio.h>
26 27 #include <stdint.h>
27 28 #include <stdlib.h>
28 29 #include <string.h>
29 30 #include <unistd.h>
30 31
31 32 #include "mandoc_aux.h"
33 +#include "mandoc_ohash.h"
32 34 #include "mandoc.h"
33 35 #include "roff.h"
34 36 #include "out.h"
35 37 #include "html.h"
36 38 #include "manconf.h"
37 39 #include "main.h"
38 40
39 41 struct htmldata {
40 42 const char *name;
41 43 int flags;
42 44 #define HTML_NOSTACK (1 << 0)
43 45 #define HTML_AUTOCLOSE (1 << 1)
44 46 #define HTML_NLBEFORE (1 << 2)
45 47 #define HTML_NLBEGIN (1 << 3)
46 48 #define HTML_NLEND (1 << 4)
47 49 #define HTML_NLAFTER (1 << 5)
48 50 #define HTML_NLAROUND (HTML_NLBEFORE | HTML_NLAFTER)
49 51 #define HTML_NLINSIDE (HTML_NLBEGIN | HTML_NLEND)
50 52 #define HTML_NLALL (HTML_NLAROUND | HTML_NLINSIDE)
51 53 #define HTML_INDENT (1 << 6)
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
52 54 #define HTML_NOINDENT (1 << 7)
53 55 };
54 56
55 57 static const struct htmldata htmltags[TAG_MAX] = {
56 58 {"html", HTML_NLALL},
57 59 {"head", HTML_NLALL | HTML_INDENT},
58 60 {"body", HTML_NLALL},
59 61 {"meta", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL},
60 62 {"title", HTML_NLAROUND},
61 63 {"div", HTML_NLAROUND},
64 + {"div", 0},
62 65 {"h1", HTML_NLAROUND},
63 66 {"h2", HTML_NLAROUND},
64 67 {"span", 0},
65 68 {"link", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL},
66 69 {"br", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL},
67 70 {"a", 0},
68 71 {"table", HTML_NLALL | HTML_INDENT},
69 - {"colgroup", HTML_NLALL | HTML_INDENT},
70 - {"col", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL},
71 72 {"tr", HTML_NLALL | HTML_INDENT},
72 73 {"td", HTML_NLAROUND},
73 74 {"li", HTML_NLAROUND | HTML_INDENT},
74 75 {"ul", HTML_NLALL | HTML_INDENT},
75 76 {"ol", HTML_NLALL | HTML_INDENT},
76 77 {"dl", HTML_NLALL | HTML_INDENT},
77 78 {"dt", HTML_NLAROUND},
78 79 {"dd", HTML_NLAROUND | HTML_INDENT},
79 80 {"pre", HTML_NLALL | HTML_NOINDENT},
80 81 {"var", 0},
81 82 {"cite", 0},
82 83 {"b", 0},
83 84 {"i", 0},
84 85 {"code", 0},
85 86 {"small", 0},
86 87 {"style", HTML_NLALL | HTML_INDENT},
87 88 {"math", HTML_NLALL | HTML_INDENT},
88 89 {"mrow", 0},
89 90 {"mi", 0},
90 91 {"mn", 0},
91 92 {"mo", 0},
92 93 {"msup", 0},
93 94 {"msub", 0},
94 95 {"msubsup", 0},
95 96 {"mfrac", 0},
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
96 97 {"msqrt", 0},
97 98 {"mfenced", 0},
98 99 {"mtable", 0},
99 100 {"mtr", 0},
100 101 {"mtd", 0},
101 102 {"munderover", 0},
102 103 {"munder", 0},
103 104 {"mover", 0},
104 105 };
105 106
106 -static const char *const roffscales[SCALE_MAX] = {
107 - "cm", /* SCALE_CM */
108 - "in", /* SCALE_IN */
109 - "pc", /* SCALE_PC */
110 - "pt", /* SCALE_PT */
111 - "em", /* SCALE_EM */
112 - "em", /* SCALE_MM */
113 - "ex", /* SCALE_EN */
114 - "ex", /* SCALE_BU */
115 - "em", /* SCALE_VS */
116 - "ex", /* SCALE_FS */
117 -};
107 +/* Avoid duplicate HTML id= attributes. */
108 +static struct ohash id_unique;
118 109
119 -static void a2width(const char *, struct roffsu *);
120 110 static void print_byte(struct html *, char);
121 111 static void print_endword(struct html *);
122 112 static void print_indent(struct html *);
123 113 static void print_word(struct html *, const char *);
124 114
125 115 static void print_ctag(struct html *, struct tag *);
126 116 static int print_escape(struct html *, char);
127 117 static int print_encode(struct html *, const char *, const char *, int);
128 118 static void print_href(struct html *, const char *, const char *, int);
129 119 static void print_metaf(struct html *, enum mandoc_esc);
130 120
131 121
132 122 void *
133 123 html_alloc(const struct manoutput *outopts)
134 124 {
135 125 struct html *h;
↓ open down ↓ |
6 lines elided |
↑ open up ↑ |
136 126
137 127 h = mandoc_calloc(1, sizeof(struct html));
138 128
139 129 h->tag = NULL;
140 130 h->style = outopts->style;
141 131 h->base_man = outopts->man;
142 132 h->base_includes = outopts->includes;
143 133 if (outopts->fragment)
144 134 h->oflags |= HTML_FRAGMENT;
145 135
136 + mandoc_ohash_init(&id_unique, 4, 0);
137 +
146 138 return h;
147 139 }
148 140
149 141 void
150 142 html_free(void *p)
151 143 {
152 144 struct tag *tag;
153 145 struct html *h;
146 + char *cp;
147 + unsigned int slot;
154 148
155 149 h = (struct html *)p;
156 -
157 150 while ((tag = h->tag) != NULL) {
158 151 h->tag = tag->next;
159 152 free(tag);
160 153 }
161 -
162 154 free(h);
155 +
156 + cp = ohash_first(&id_unique, &slot);
157 + while (cp != NULL) {
158 + free(cp);
159 + cp = ohash_next(&id_unique, &slot);
160 + }
161 + ohash_delete(&id_unique);
163 162 }
164 163
165 164 void
166 165 print_gen_head(struct html *h)
167 166 {
168 167 struct tag *t;
169 168
170 169 print_otag(h, TAG_META, "?", "charset", "utf-8");
170 + if (h->style != NULL) {
171 + print_otag(h, TAG_LINK, "?h??", "rel", "stylesheet",
172 + h->style, "type", "text/css", "media", "all");
173 + return;
174 + }
171 175
172 176 /*
173 - * Print a default style-sheet.
177 + * Print a minimal embedded style sheet.
174 178 */
175 179
176 180 t = print_otag(h, TAG_STYLE, "");
177 181 print_text(h, "table.head, table.foot { width: 100%; }");
178 182 print_endline(h);
179 183 print_text(h, "td.head-rtitle, td.foot-os { text-align: right; }");
180 184 print_endline(h);
181 185 print_text(h, "td.head-vol { text-align: center; }");
182 186 print_endline(h);
183 187 print_text(h, "div.Pp { margin: 1ex 0ex; }");
188 + print_endline(h);
189 + print_text(h, "div.Nd, div.Bf, div.Op { display: inline; }");
190 + print_endline(h);
191 + print_text(h, "span.Pa, span.Ad { font-style: italic; }");
192 + print_endline(h);
193 + print_text(h, "span.Ms { font-weight: bold; }");
194 + print_endline(h);
195 + print_text(h, "dl.Bl-diag ");
196 + print_byte(h, '>');
197 + print_text(h, " dt { font-weight: bold; }");
198 + print_endline(h);
199 + print_text(h, "code.Nm, code.Fl, code.Cm, code.Ic, "
200 + "code.In, code.Fd, code.Fn,");
201 + print_endline(h);
202 + print_text(h, "code.Cd { font-weight: bold; "
203 + "font-family: inherit; }");
184 204 print_tagq(h, t);
185 -
186 - if (h->style)
187 - print_otag(h, TAG_LINK, "?h??", "rel", "stylesheet",
188 - h->style, "type", "text/css", "media", "all");
189 205 }
190 206
191 207 static void
192 208 print_metaf(struct html *h, enum mandoc_esc deco)
193 209 {
194 210 enum htmlfont font;
195 211
196 212 switch (deco) {
197 213 case ESCAPE_FONTPREV:
198 214 font = h->metal;
199 215 break;
200 216 case ESCAPE_FONTITALIC:
201 217 font = HTMLFONT_ITALIC;
202 218 break;
203 219 case ESCAPE_FONTBOLD:
204 220 font = HTMLFONT_BOLD;
205 221 break;
206 222 case ESCAPE_FONTBI:
207 223 font = HTMLFONT_BI;
208 224 break;
209 225 case ESCAPE_FONT:
210 226 case ESCAPE_FONTROMAN:
211 227 font = HTMLFONT_NONE;
212 228 break;
213 229 default:
214 230 abort();
215 231 }
216 232
217 233 if (h->metaf) {
218 234 print_tagq(h, h->metaf);
219 235 h->metaf = NULL;
220 236 }
221 237
222 238 h->metal = h->metac;
223 239 h->metac = font;
224 240
225 241 switch (font) {
226 242 case HTMLFONT_ITALIC:
227 243 h->metaf = print_otag(h, TAG_I, "");
228 244 break;
229 245 case HTMLFONT_BOLD:
230 246 h->metaf = print_otag(h, TAG_B, "");
231 247 break;
↓ open down ↓ |
33 lines elided |
↑ open up ↑ |
232 248 case HTMLFONT_BI:
233 249 h->metaf = print_otag(h, TAG_B, "");
234 250 print_otag(h, TAG_I, "");
235 251 break;
236 252 default:
237 253 break;
238 254 }
239 255 }
240 256
241 257 char *
242 -html_make_id(const struct roff_node *n)
258 +html_make_id(const struct roff_node *n, int unique)
243 259 {
244 260 const struct roff_node *nch;
245 - char *buf, *cp;
261 + char *buf, *bufs, *cp;
262 + unsigned int slot;
263 + int suffix;
246 264
247 265 for (nch = n->child; nch != NULL; nch = nch->next)
248 266 if (nch->type != ROFFT_TEXT)
249 267 return NULL;
250 268
251 269 buf = NULL;
252 270 deroff(&buf, n);
271 + if (buf == NULL)
272 + return NULL;
253 273
254 - /* http://www.w3.org/TR/html5/dom.html#the-id-attribute */
274 + /*
275 + * In ID attributes, only use ASCII characters that are
276 + * permitted in URL-fragment strings according to the
277 + * explicit list at:
278 + * https://url.spec.whatwg.org/#url-fragment-string
279 + */
255 280
256 281 for (cp = buf; *cp != '\0'; cp++)
257 - if (*cp == ' ')
282 + if (isalnum((unsigned char)*cp) == 0 &&
283 + strchr("!$&'()*+,-./:;=?@_~", *cp) == NULL)
258 284 *cp = '_';
259 285
260 - return buf;
261 -}
286 + if (unique == 0)
287 + return buf;
262 288
263 -int
264 -html_strlen(const char *cp)
265 -{
266 - size_t rsz;
267 - int skip, sz;
289 + /* Avoid duplicate HTML id= attributes. */
268 290
269 - /*
270 - * Account for escaped sequences within string length
271 - * calculations. This follows the logic in term_strlen() as we
272 - * must calculate the width of produced strings.
273 - * Assume that characters are always width of "1". This is
274 - * hacky, but it gets the job done for approximation of widths.
275 - */
276 -
277 - sz = 0;
278 - skip = 0;
279 - while (1) {
280 - rsz = strcspn(cp, "\\");
281 - if (rsz) {
282 - cp += rsz;
283 - if (skip) {
284 - skip = 0;
285 - rsz--;
291 + bufs = NULL;
292 + suffix = 1;
293 + slot = ohash_qlookup(&id_unique, buf);
294 + cp = ohash_find(&id_unique, slot);
295 + if (cp != NULL) {
296 + while (cp != NULL) {
297 + free(bufs);
298 + if (++suffix > 127) {
299 + free(buf);
300 + return NULL;
286 301 }
287 - sz += rsz;
302 + mandoc_asprintf(&bufs, "%s_%d", buf, suffix);
303 + slot = ohash_qlookup(&id_unique, bufs);
304 + cp = ohash_find(&id_unique, slot);
288 305 }
289 - if ('\0' == *cp)
290 - break;
291 - cp++;
292 - switch (mandoc_escape(&cp, NULL, NULL)) {
293 - case ESCAPE_ERROR:
294 - return sz;
295 - case ESCAPE_UNICODE:
296 - case ESCAPE_NUMBERED:
297 - case ESCAPE_SPECIAL:
298 - case ESCAPE_OVERSTRIKE:
299 - if (skip)
300 - skip = 0;
301 - else
302 - sz++;
303 - break;
304 - case ESCAPE_SKIPCHAR:
305 - skip = 1;
306 - break;
307 - default:
308 - break;
309 - }
306 + free(buf);
307 + buf = bufs;
310 308 }
311 - return sz;
309 + ohash_insert(&id_unique, slot, buf);
310 + return buf;
312 311 }
313 312
314 313 static int
315 314 print_escape(struct html *h, char c)
316 315 {
317 316
318 317 switch (c) {
319 318 case '<':
320 319 print_word(h, "<");
321 320 break;
322 321 case '>':
323 322 print_word(h, ">");
324 323 break;
325 324 case '&':
326 325 print_word(h, "&");
327 326 break;
328 327 case '"':
329 328 print_word(h, """);
330 329 break;
331 330 case ASCII_NBRSP:
332 331 print_word(h, " ");
333 332 break;
334 333 case ASCII_HYPH:
335 334 print_byte(h, '-');
336 335 break;
337 336 case ASCII_BREAK:
338 337 break;
339 338 default:
340 339 return 0;
341 340 }
342 341 return 1;
343 342 }
344 343
345 344 static int
346 345 print_encode(struct html *h, const char *p, const char *pend, int norecurse)
347 346 {
348 347 char numbuf[16];
349 348 struct tag *t;
350 349 const char *seq;
351 350 size_t sz;
352 351 int c, len, breakline, nospace;
353 352 enum mandoc_esc esc;
354 353 static const char rejs[10] = { ' ', '\\', '<', '>', '&', '"',
355 354 ASCII_NBRSP, ASCII_HYPH, ASCII_BREAK, '\0' };
356 355
357 356 if (pend == NULL)
358 357 pend = strchr(p, '\0');
359 358
360 359 breakline = 0;
361 360 nospace = 0;
362 361
363 362 while (p < pend) {
364 363 if (HTML_SKIPCHAR & h->flags && '\\' != *p) {
365 364 h->flags &= ~HTML_SKIPCHAR;
366 365 p++;
367 366 continue;
368 367 }
369 368
370 369 for (sz = strcspn(p, rejs); sz-- && p < pend; p++)
371 370 print_byte(h, *p);
372 371
373 372 if (breakline &&
374 373 (p >= pend || *p == ' ' || *p == ASCII_NBRSP)) {
375 374 t = print_otag(h, TAG_DIV, "");
376 375 print_text(h, "\\~");
377 376 print_tagq(h, t);
378 377 breakline = 0;
379 378 while (p < pend && (*p == ' ' || *p == ASCII_NBRSP))
380 379 p++;
381 380 continue;
382 381 }
383 382
384 383 if (p >= pend)
385 384 break;
386 385
387 386 if (*p == ' ') {
388 387 print_endword(h);
389 388 p++;
390 389 continue;
391 390 }
392 391
393 392 if (print_escape(h, *p++))
394 393 continue;
395 394
396 395 esc = mandoc_escape(&p, &seq, &len);
397 396 if (ESCAPE_ERROR == esc)
398 397 break;
399 398
400 399 switch (esc) {
401 400 case ESCAPE_FONT:
402 401 case ESCAPE_FONTPREV:
403 402 case ESCAPE_FONTBOLD:
404 403 case ESCAPE_FONTITALIC:
405 404 case ESCAPE_FONTBI:
406 405 case ESCAPE_FONTROMAN:
407 406 if (0 == norecurse)
408 407 print_metaf(h, esc);
409 408 continue;
410 409 case ESCAPE_SKIPCHAR:
411 410 h->flags |= HTML_SKIPCHAR;
412 411 continue;
413 412 default:
414 413 break;
415 414 }
416 415
417 416 if (h->flags & HTML_SKIPCHAR) {
418 417 h->flags &= ~HTML_SKIPCHAR;
419 418 continue;
420 419 }
421 420
422 421 switch (esc) {
423 422 case ESCAPE_UNICODE:
424 423 /* Skip past "u" header. */
425 424 c = mchars_num2uc(seq + 1, len - 1);
426 425 break;
427 426 case ESCAPE_NUMBERED:
428 427 c = mchars_num2char(seq, len);
429 428 if (c < 0)
430 429 continue;
431 430 break;
432 431 case ESCAPE_SPECIAL:
433 432 c = mchars_spec2cp(seq, len);
434 433 if (c <= 0)
435 434 continue;
436 435 break;
437 436 case ESCAPE_BREAK:
438 437 breakline = 1;
439 438 continue;
440 439 case ESCAPE_NOSPACE:
441 440 if ('\0' == *p)
442 441 nospace = 1;
443 442 continue;
444 443 case ESCAPE_OVERSTRIKE:
445 444 if (len == 0)
446 445 continue;
447 446 c = seq[len - 1];
448 447 break;
449 448 default:
450 449 continue;
451 450 }
452 451 if ((c < 0x20 && c != 0x09) ||
453 452 (c > 0x7E && c < 0xA0))
454 453 c = 0xFFFD;
455 454 if (c > 0x7E) {
456 455 (void)snprintf(numbuf, sizeof(numbuf), "&#x%.4X;", c);
457 456 print_word(h, numbuf);
458 457 } else if (print_escape(h, c) == 0)
459 458 print_byte(h, c);
460 459 }
461 460
462 461 return nospace;
463 462 }
464 463
465 464 static void
466 465 print_href(struct html *h, const char *name, const char *sec, int man)
467 466 {
468 467 const char *p, *pp;
469 468
470 469 pp = man ? h->base_man : h->base_includes;
471 470 while ((p = strchr(pp, '%')) != NULL) {
472 471 print_encode(h, pp, p, 1);
473 472 if (man && p[1] == 'S') {
474 473 if (sec == NULL)
475 474 print_byte(h, '1');
476 475 else
477 476 print_encode(h, sec, NULL, 1);
478 477 } else if ((man && p[1] == 'N') ||
479 478 (man == 0 && p[1] == 'I'))
480 479 print_encode(h, name, NULL, 1);
481 480 else
482 481 print_encode(h, p, p + 2, 1);
↓ open down ↓ |
161 lines elided |
↑ open up ↑ |
483 482 pp = p + 2;
484 483 }
485 484 if (*pp != '\0')
486 485 print_encode(h, pp, NULL, 1);
487 486 }
488 487
489 488 struct tag *
490 489 print_otag(struct html *h, enum htmltag tag, const char *fmt, ...)
491 490 {
492 491 va_list ap;
493 - struct roffsu mysu, *su;
494 - char numbuf[16];
495 492 struct tag *t;
496 493 const char *attr;
497 494 char *arg1, *arg2;
498 - double v;
499 - int i, have_style, tflags;
495 + int tflags;
500 496
501 497 tflags = htmltags[tag].flags;
502 498
503 499 /* Push this tag onto the stack of open scopes. */
504 500
505 501 if ((tflags & HTML_NOSTACK) == 0) {
506 502 t = mandoc_malloc(sizeof(struct tag));
507 503 t->tag = tag;
508 504 t->next = h->tag;
509 505 h->tag = t;
510 506 } else
511 507 t = NULL;
512 508
513 509 if (tflags & HTML_NLBEFORE)
514 510 print_endline(h);
515 511 if (h->col == 0)
516 512 print_indent(h);
517 513 else if ((h->flags & HTML_NOSPACE) == 0) {
518 514 if (h->flags & HTML_KEEP)
519 515 print_word(h, " ");
520 516 else {
521 517 if (h->flags & HTML_PREKEEP)
522 518 h->flags |= HTML_KEEP;
523 519 print_endword(h);
524 520 }
525 521 }
526 522
527 523 if ( ! (h->flags & HTML_NONOSPACE))
528 524 h->flags &= ~HTML_NOSPACE;
↓ open down ↓ |
19 lines elided |
↑ open up ↑ |
529 525 else
530 526 h->flags |= HTML_NOSPACE;
531 527
532 528 /* Print out the tag name and attributes. */
533 529
534 530 print_byte(h, '<');
535 531 print_word(h, htmltags[tag].name);
536 532
537 533 va_start(ap, fmt);
538 534
539 - have_style = 0;
540 535 while (*fmt != '\0') {
541 - if (*fmt == 's') {
542 - have_style = 1;
543 - fmt++;
544 - break;
545 - }
546 536
547 - /* Parse a non-style attribute and its arguments. */
537 + /* Parse attributes and arguments. */
548 538
549 539 arg1 = va_arg(ap, char *);
540 + arg2 = NULL;
550 541 switch (*fmt++) {
551 542 case 'c':
552 543 attr = "class";
553 544 break;
554 545 case 'h':
555 546 attr = "href";
556 547 break;
557 548 case 'i':
558 549 attr = "id";
559 550 break;
551 + case 's':
552 + attr = "style";
553 + arg2 = va_arg(ap, char *);
554 + break;
560 555 case '?':
561 556 attr = arg1;
562 557 arg1 = va_arg(ap, char *);
563 558 break;
564 559 default:
565 560 abort();
566 561 }
567 - arg2 = NULL;
568 562 if (*fmt == 'M')
569 563 arg2 = va_arg(ap, char *);
570 564 if (arg1 == NULL)
571 565 continue;
572 566
573 - /* Print the non-style attributes. */
567 + /* Print the attributes. */
574 568
575 569 print_byte(h, ' ');
576 570 print_word(h, attr);
577 571 print_byte(h, '=');
578 572 print_byte(h, '"');
579 573 switch (*fmt) {
580 574 case 'I':
581 575 print_href(h, arg1, NULL, 0);
582 576 fmt++;
583 577 break;
584 578 case 'M':
585 579 print_href(h, arg1, arg2, 1);
586 580 fmt++;
587 581 break;
588 582 case 'R':
589 583 print_byte(h, '#');
↓ open down ↓ |
6 lines elided |
↑ open up ↑ |
590 584 print_encode(h, arg1, NULL, 1);
591 585 fmt++;
592 586 break;
593 587 case 'T':
594 588 print_encode(h, arg1, NULL, 1);
595 589 print_word(h, "\" title=\"");
596 590 print_encode(h, arg1, NULL, 1);
597 591 fmt++;
598 592 break;
599 593 default:
600 - print_encode(h, arg1, NULL, 1);
601 - break;
602 - }
603 - print_byte(h, '"');
604 - }
605 -
606 - /* Print out styles. */
607 -
608 - while (*fmt != '\0') {
609 - arg1 = NULL;
610 - su = NULL;
611 -
612 - /* First letter: input argument type. */
613 -
614 - switch (*fmt++) {
615 - case 'h':
616 - i = va_arg(ap, int);
617 - su = &mysu;
618 - SCALE_HS_INIT(su, i);
619 - break;
620 - case 's':
621 - arg1 = va_arg(ap, char *);
622 - break;
623 - case 'u':
624 - su = va_arg(ap, struct roffsu *);
625 - break;
626 - case 'w':
627 - if ((arg2 = va_arg(ap, char *)) != NULL) {
628 - su = &mysu;
629 - a2width(arg2, su);
594 + if (arg2 == NULL)
595 + print_encode(h, arg1, NULL, 1);
596 + else {
597 + print_word(h, arg1);
598 + print_byte(h, ':');
599 + print_byte(h, ' ');
600 + print_word(h, arg2);
601 + print_byte(h, ';');
630 602 }
631 - if (*fmt == '*') {
632 - if (su != NULL && su->unit == SCALE_EN &&
633 - su->scale > 5.9 && su->scale < 6.1)
634 - su = NULL;
635 - fmt++;
636 - }
637 - if (*fmt == '+') {
638 - if (su != NULL) {
639 - /* Make even bold text fit. */
640 - su->scale *= 1.2;
641 - /* Add padding. */
642 - su->scale += 3.0;
643 - }
644 - fmt++;
645 - }
646 - if (*fmt == '-') {
647 - if (su != NULL)
648 - su->scale *= -1.0;
649 - fmt++;
650 - }
651 603 break;
652 - default:
653 - abort();
654 604 }
655 -
656 - /* Second letter: style name. */
657 -
658 - switch (*fmt++) {
659 - case 'h':
660 - attr = "height";
661 - break;
662 - case 'i':
663 - attr = "text-indent";
664 - break;
665 - case 'l':
666 - attr = "margin-left";
667 - break;
668 - case 'w':
669 - attr = "width";
670 - break;
671 - case 'W':
672 - attr = "min-width";
673 - break;
674 - case '?':
675 - attr = arg1;
676 - arg1 = va_arg(ap, char *);
677 - break;
678 - default:
679 - abort();
680 - }
681 - if (su == NULL && arg1 == NULL)
682 - continue;
683 -
684 - if (have_style == 1)
685 - print_word(h, " style=\"");
686 - else
687 - print_byte(h, ' ');
688 - print_word(h, attr);
689 - print_byte(h, ':');
690 - print_byte(h, ' ');
691 - if (su != NULL) {
692 - v = su->scale;
693 - if (su->unit == SCALE_MM && (v /= 100.0) == 0.0)
694 - v = 1.0;
695 - else if (su->unit == SCALE_BU)
696 - v /= 24.0;
697 - (void)snprintf(numbuf, sizeof(numbuf), "%.2f", v);
698 - print_word(h, numbuf);
699 - print_word(h, roffscales[su->unit]);
700 - } else
701 - print_word(h, arg1);
702 - print_byte(h, ';');
703 - have_style = 2;
704 - }
705 - if (have_style == 2)
706 605 print_byte(h, '"');
707 -
606 + }
708 607 va_end(ap);
709 608
710 609 /* Accommodate for "well-formed" singleton escaping. */
711 610
712 611 if (HTML_AUTOCLOSE & htmltags[tag].flags)
713 612 print_byte(h, '/');
714 613
715 614 print_byte(h, '>');
716 615
717 616 if (tflags & HTML_NLBEGIN)
718 617 print_endline(h);
719 618 else
720 619 h->flags |= HTML_NOSPACE;
721 620
722 621 if (tflags & HTML_INDENT)
723 622 h->indent++;
724 623 if (tflags & HTML_NOINDENT)
725 624 h->noindent++;
726 625
727 626 return t;
728 627 }
729 628
730 629 static void
731 630 print_ctag(struct html *h, struct tag *tag)
732 631 {
733 632 int tflags;
734 633
735 634 /*
736 635 * Remember to close out and nullify the current
737 636 * meta-font and table, if applicable.
738 637 */
739 638 if (tag == h->metaf)
740 639 h->metaf = NULL;
741 640 if (tag == h->tblt)
742 641 h->tblt = NULL;
743 642
744 643 tflags = htmltags[tag->tag].flags;
745 644
746 645 if (tflags & HTML_INDENT)
747 646 h->indent--;
748 647 if (tflags & HTML_NOINDENT)
749 648 h->noindent--;
750 649 if (tflags & HTML_NLEND)
751 650 print_endline(h);
752 651 print_indent(h);
753 652 print_byte(h, '<');
754 653 print_byte(h, '/');
755 654 print_word(h, htmltags[tag->tag].name);
756 655 print_byte(h, '>');
757 656 if (tflags & HTML_NLAFTER)
758 657 print_endline(h);
759 658
760 659 h->tag = tag->next;
761 660 free(tag);
↓ open down ↓ |
44 lines elided |
↑ open up ↑ |
762 661 }
763 662
764 663 void
765 664 print_gen_decls(struct html *h)
766 665 {
767 666 print_word(h, "<!DOCTYPE html>");
768 667 print_endline(h);
769 668 }
770 669
771 670 void
671 +print_gen_comment(struct html *h, struct roff_node *n)
672 +{
673 + int wantblank;
674 +
675 + print_word(h, "<!-- This is an automatically generated file."
676 + " Do not edit.");
677 + h->indent = 1;
678 + wantblank = 0;
679 + while (n != NULL && n->type == ROFFT_COMMENT) {
680 + if (strstr(n->string, "-->") == NULL &&
681 + (wantblank || *n->string != '\0')) {
682 + print_endline(h);
683 + print_indent(h);
684 + print_word(h, n->string);
685 + wantblank = *n->string != '\0';
686 + }
687 + n = n->next;
688 + }
689 + if (wantblank)
690 + print_endline(h);
691 + print_word(h, " -->");
692 + print_endline(h);
693 + h->indent = 0;
694 +}
695 +
696 +void
772 697 print_text(struct html *h, const char *word)
773 698 {
774 699 if (h->col && (h->flags & HTML_NOSPACE) == 0) {
775 700 if ( ! (HTML_KEEP & h->flags)) {
776 701 if (HTML_PREKEEP & h->flags)
777 702 h->flags |= HTML_KEEP;
778 703 print_endword(h);
779 704 } else
780 705 print_word(h, " ");
781 706 }
782 707
783 708 assert(NULL == h->metaf);
784 709 switch (h->metac) {
785 710 case HTMLFONT_ITALIC:
786 711 h->metaf = print_otag(h, TAG_I, "");
787 712 break;
788 713 case HTMLFONT_BOLD:
789 714 h->metaf = print_otag(h, TAG_B, "");
790 715 break;
791 716 case HTMLFONT_BI:
792 717 h->metaf = print_otag(h, TAG_B, "");
793 718 print_otag(h, TAG_I, "");
794 719 break;
795 720 default:
796 721 print_indent(h);
797 722 break;
798 723 }
799 724
800 725 assert(word);
801 726 if ( ! print_encode(h, word, NULL, 0)) {
802 727 if ( ! (h->flags & HTML_NONOSPACE))
803 728 h->flags &= ~HTML_NOSPACE;
804 729 h->flags &= ~HTML_NONEWLINE;
805 730 } else
806 731 h->flags |= HTML_NOSPACE | HTML_NONEWLINE;
807 732
808 733 if (h->metaf) {
809 734 print_tagq(h, h->metaf);
810 735 h->metaf = NULL;
811 736 }
812 737
813 738 h->flags &= ~HTML_IGNDELIM;
814 739 }
815 740
816 741 void
817 742 print_tagq(struct html *h, const struct tag *until)
818 743 {
819 744 struct tag *tag;
820 745
821 746 while ((tag = h->tag) != NULL) {
822 747 print_ctag(h, tag);
823 748 if (until && tag == until)
824 749 return;
825 750 }
826 751 }
827 752
828 753 void
829 754 print_stagq(struct html *h, const struct tag *suntil)
830 755 {
831 756 struct tag *tag;
832 757
833 758 while ((tag = h->tag) != NULL) {
834 759 if (suntil && tag == suntil)
835 760 return;
836 761 print_ctag(h, tag);
837 762 }
838 763 }
839 764
840 765 void
841 766 print_paragraph(struct html *h)
842 767 {
843 768 struct tag *t;
844 769
845 770 t = print_otag(h, TAG_DIV, "c", "Pp");
846 771 print_tagq(h, t);
847 772 }
848 773
849 774
850 775 /***********************************************************************
851 776 * Low level output functions.
852 777 * They implement line breaking using a short static buffer.
853 778 ***********************************************************************/
854 779
855 780 /*
856 781 * Buffer one HTML output byte.
857 782 * If the buffer is full, flush and deactivate it and start a new line.
858 783 * If the buffer is inactive, print directly.
859 784 */
860 785 static void
861 786 print_byte(struct html *h, char c)
862 787 {
863 788 if ((h->flags & HTML_BUFFER) == 0) {
864 789 putchar(c);
865 790 h->col++;
866 791 return;
867 792 }
868 793
869 794 if (h->col + h->bufcol < sizeof(h->buf)) {
870 795 h->buf[h->bufcol++] = c;
871 796 return;
872 797 }
873 798
874 799 putchar('\n');
875 800 h->col = 0;
876 801 print_indent(h);
877 802 putchar(' ');
878 803 putchar(' ');
879 804 fwrite(h->buf, h->bufcol, 1, stdout);
880 805 putchar(c);
881 806 h->col = (h->indent + 1) * 2 + h->bufcol + 1;
882 807 h->bufcol = 0;
883 808 h->flags &= ~HTML_BUFFER;
884 809 }
885 810
886 811 /*
887 812 * If something was printed on the current output line, end it.
888 813 * Not to be called right after print_indent().
889 814 */
890 815 void
891 816 print_endline(struct html *h)
892 817 {
893 818 if (h->col == 0)
894 819 return;
895 820
896 821 if (h->bufcol) {
897 822 putchar(' ');
898 823 fwrite(h->buf, h->bufcol, 1, stdout);
899 824 h->bufcol = 0;
900 825 }
901 826 putchar('\n');
902 827 h->col = 0;
903 828 h->flags |= HTML_NOSPACE;
904 829 h->flags &= ~HTML_BUFFER;
905 830 }
906 831
907 832 /*
908 833 * Flush the HTML output buffer.
909 834 * If it is inactive, activate it.
910 835 */
911 836 static void
912 837 print_endword(struct html *h)
913 838 {
914 839 if (h->noindent) {
915 840 print_byte(h, ' ');
916 841 return;
917 842 }
918 843
919 844 if ((h->flags & HTML_BUFFER) == 0) {
920 845 h->col++;
921 846 h->flags |= HTML_BUFFER;
922 847 } else if (h->bufcol) {
923 848 putchar(' ');
924 849 fwrite(h->buf, h->bufcol, 1, stdout);
925 850 h->col += h->bufcol + 1;
926 851 }
927 852 h->bufcol = 0;
928 853 }
929 854
930 855 /*
931 856 * If at the beginning of a new output line,
932 857 * perform indentation and mark the line as containing output.
933 858 * Make sure to really produce some output right afterwards,
934 859 * but do not use print_otag() for producing it.
935 860 */
936 861 static void
937 862 print_indent(struct html *h)
938 863 {
939 864 size_t i;
940 865
941 866 if (h->col)
942 867 return;
943 868
944 869 if (h->noindent == 0) {
945 870 h->col = h->indent * 2;
946 871 for (i = 0; i < h->col; i++)
947 872 putchar(' ');
948 873 }
949 874 h->flags &= ~HTML_NOSPACE;
950 875 }
↓ open down ↓ |
169 lines elided |
↑ open up ↑ |
951 876
952 877 /*
953 878 * Print or buffer some characters
954 879 * depending on the current HTML output buffer state.
955 880 */
956 881 static void
957 882 print_word(struct html *h, const char *cp)
958 883 {
959 884 while (*cp != '\0')
960 885 print_byte(h, *cp++);
961 -}
962 -
963 -/*
964 - * Calculate the scaling unit passed in a `-width' argument. This uses
965 - * either a native scaling unit (e.g., 1i, 2m) or the string length of
966 - * the value.
967 - */
968 -static void
969 -a2width(const char *p, struct roffsu *su)
970 -{
971 - const char *end;
972 -
973 - end = a2roffsu(p, su, SCALE_MAX);
974 - if (end == NULL || *end != '\0') {
975 - su->unit = SCALE_EN;
976 - su->scale = html_strlen(p);
977 - } else if (su->scale < 0.0)
978 - su->scale = 0.0;
979 886 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX