source: trunk/emx/src/emxdoc/html.c@ 3669

Last change on this file since 3669 was 18, checked in by bird, 22 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 17.6 KB
Line 
1/* html.c -- HTML output
2 Copyright (c) 1999 Eberhard Mattes
3
4This file is part of emxdoc.
5
6emxdoc is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11emxdoc is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with emxdoc; see the file COPYING. If not, write to
18the Free Software Foundation, 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <ctype.h>
26#include <assert.h>
27#include "emxdoc.h"
28#include "html.h"
29#include "xref.h"
30
31static int index_count;
32static struct word **index_v;
33static int index_n;
34static struct word *index_wp1;
35static const uchar *index_map;
36
37static void html_write_index (void);
38
39void html_output (const uchar *p, int may_break)
40{
41 const uchar *q;
42
43 if (*p == ' ' && output_x >= 60 && may_break)
44 {
45 write_nl ();
46 ++p;
47 }
48 while ((q = strpbrk (p, "<>& ")) != NULL)
49 {
50 write_nstring (p, q - p);
51 p = q;
52 if (p[0] == ' ' && p[1] == ' ')
53 while (*p == ' ')
54 {
55 write_string ("&nbsp;");
56 ++p;
57 }
58 else
59 switch (*p++)
60 {
61 case '<':
62 write_string ("&lt;");
63 break;
64 case '>':
65 write_string ("&gt;");
66 break;
67 case '&':
68 write_string ("&amp;");
69 break;
70 case ' ':
71 write_string (" ");
72 break;
73 default:
74 abort ();
75 }
76 }
77 write_string (p);
78}
79
80static void html_para (void)
81{
82 write_break ();
83 write_string ("<P>");
84}
85
86static void html_begin_link (const uchar *database, int ref)
87{
88 write_fmt ("<A HREF=\"%s%s#%d\">",
89 database != NULL ? (const char *)database : "",
90 database != NULL ? ".html" : "", ref);
91}
92
93
94static void html_end_link (void)
95{
96 write_string ("</A>");
97}
98
99
100void html_elements (enum style style)
101{
102 const struct element *ep;
103 enum style style_stack[STYLE_STACK_SIZE];
104 int style_sp, ignore_spaces;
105 uchar *p;
106
107 style_sp = 0;
108 style_stack[style_sp] = style;
109 ignore_spaces = FALSE;
110 for (ep = elements; ep->el != EL_END; ++ep)
111 switch (ep->el)
112 {
113 case EL_WORD:
114 case EL_PUNCT:
115 if (ep->n != 0)
116 {
117 if (ep->wp->database == NULL)
118 html_begin_link (NULL, ep->wp->ref);
119 else
120 html_begin_link (ep->wp->database->str, ep->wp->ref);
121 }
122 p = ep->wp->str;
123 if (ep->wp->special != NULL && ep->wp->special->html != NULL)
124 write_string (ep->wp->special->html);
125 else if (style_sp == 0 || style_stack[style_sp] == STYLE_NORMAL)
126 format_string (p, (ep->wp->style != STYLE_NORMAL
127 ? ep->wp->style : style), FALSE);
128 else
129 format_string (p, style_stack[style_sp], FALSE);
130 if (ep->n != 0)
131 html_end_link ();
132 break;
133 case EL_SPACE:
134 if (ignore_spaces)
135 ignore_spaces = FALSE;
136 else
137 format_spaces (ep->n, style_stack[style_sp], TRUE);
138 break;
139 case EL_BREAK:
140 write_line ("<BR>");
141 break;
142 case EL_STYLE:
143 if (style_sp + 1 >= STYLE_STACK_SIZE)
144 fatal ("%s:%d: Style stack overflow", input_fname, line_no);
145 style_stack[++style_sp] = ep->n;
146 break;
147 case EL_ENDSTYLE:
148 if (style_sp == 0)
149 fatal ("%s:%d: Style stack underflow", input_fname, line_no);
150 --style_sp;
151 break;
152 default:
153 abort ();
154 }
155}
156
157void html_start_hilite (void)
158{
159 if (hl_stack[hl_sp] & HL_TT)
160 write_string ("<TT>");
161 else if (hl_stack[hl_sp] & HL_BF)
162 write_string ("<B>");
163 else if (hl_stack[hl_sp] & (HL_SL | HL_EM))
164 write_string ("<I>");
165}
166
167
168void html_end_hilite (void)
169{
170 if (hl_stack[hl_sp] & HL_TT)
171 write_string ("</TT>");
172 else if (hl_stack[hl_sp] & HL_BF)
173 write_string ("</B>");
174 else if (hl_stack[hl_sp] & (HL_SL | HL_EM))
175 write_string ("</I>");
176}
177
178
179void html_end_env (void)
180{
181 switch (env_stack[env_sp].env)
182 {
183 case ENV_DESCRIPTION:
184 case ENV_LIST:
185 write_break ();
186 write_line ("</DL>");
187 break;
188 case ENV_ENUMERATE:
189 write_break ();
190 write_line ("</OL>");
191 break;
192 case ENV_ITEMIZE:
193 write_break ();
194 write_line ("</UL>");
195 break;
196 case ENV_TYPEWRITER:
197 write_break ();
198 write_line ("</PRE></BLOCKQUOTE>");
199 break;
200 case ENV_INDENT:
201 write_break ();
202 write_line ("</BLOCKQUOTE>");
203 break;
204 default:
205 abort ();
206 }
207}
208
209
210void html_toc_start (void)
211{
212}
213
214
215void html_toc_line (const uchar *s, const struct toc *tp)
216{
217 format_string (s, STYLE_NORMAL, FALSE);
218 html_begin_link (NULL, tp->ref);
219 html_output (tp->title, FALSE);
220 html_end_link ();
221 write_line ("<BR>");
222}
223
224
225void html_toc_end (void)
226{
227 write_line ("<HR>");
228}
229
230void html_heading1 (int ref)
231{
232 write_break ();
233 write_fmt ("<A NAME=\"%d\"></A>", ref);
234 write_nl ();
235}
236
237
238void html_heading2 (const uchar *s)
239{
240 if (para_flag)
241 html_para ();
242 switch (tg_level)
243 {
244 case 0:
245 write_string (s);
246 write_line ("<BR>");
247 break;
248 case 1: case 2: case 3: case 4: case 5: case 6:
249 write_fmt ("<H%d>", tg_level);
250 html_output (s, FALSE);
251 write_fmt ("</H%d>", tg_level);
252 write_nl ();
253 break;
254 default:
255 fatal ("Sorry, HTML supports only 6 levels of headings");
256 }
257 write_nl ();
258}
259
260
261void html_description (void)
262{
263 write_break ();
264 write_line ("<DL COMPACT>");
265 write_nl ();
266}
267
268
269void html_enumerate (void)
270{
271 write_break ();
272 write_line ("<OL>");
273 write_nl ();
274}
275
276
277void html_itemize (void)
278{
279 write_break ();
280 write_line ("<UL>");
281 write_nl ();
282}
283
284
285void html_indent (void)
286{
287 write_break ();
288 write_line ("<BLOCKQUOTE>");
289}
290
291
292void html_list (void)
293{
294 write_break ();
295 write_line ("<DL COMPACT>");
296}
297
298
299void html_verbatim_start (enum tag tag_end)
300{
301 write_break ();
302 switch (tag_end)
303 {
304 case TAG_ENDHEADERS:
305 html_para ();
306 format_string ("Headers:", STYLE_BOLD, FALSE);
307 break;
308 case TAG_ENDSAMPLECODE:
309 html_para ();
310 format_string ("Example:", STYLE_BOLD, FALSE);
311 write_line ("<BLOCKQUOTE>");
312 break;
313 case TAG_ENDEXAMPLE:
314 html_para ();
315 write_line ("<BLOCKQUOTE>");
316 break;
317 default:
318 break;
319 }
320 write_break ();
321 write_line ("<PRE>");
322}
323
324void html_verbatim_line (void)
325{
326 html_output (input, FALSE);
327 write_nl ();
328}
329
330void html_verbatim_end (enum tag tag_end)
331{
332 write_line ("</PRE>");
333 switch (tag_end)
334 {
335 case TAG_ENDEXAMPLE:
336 case TAG_ENDSAMPLECODE:
337 write_line ("</BLOCKQUOTE>");
338 break;
339 default:
340 break;
341 }
342}
343
344
345void html_description_item (const uchar *s)
346{
347 write_break ();
348 write_string ("<DT>");
349 make_elements (s);
350 html_elements (STYLE_NORMAL);
351 write_string ("<DD>");
352}
353
354
355void html_enumerate_item (void)
356{
357 write_break ();
358 write_line ("<LI>");
359}
360
361
362void html_itemize_item (void)
363{
364 write_break ();
365 write_line ("<LI>");
366}
367
368
369void html_list_item (const uchar *s)
370{
371 write_break ();
372 write_string ("<DT>");
373 make_elements (s);
374 html_elements (STYLE_NORMAL);
375 write_string ("<DD>");
376}
377
378
379void html_copy (void)
380{
381 if (para_flag)
382 html_para ();
383 switch (env_stack[env_sp].env)
384 {
385 case ENV_TYPEWRITER:
386 html_elements (STYLE_TTY);
387 break;
388 default:
389 html_elements (STYLE_NORMAL);
390 break;
391 }
392}
393
394
395void html_start (void)
396{
397 write_line ("<HTML><HEAD>");
398 if (title != NULL)
399 {
400 write_string ("<TITLE>");
401 format_string (title, STYLE_NORMAL, FALSE);
402 write_line ("</TITLE>");
403 }
404 write_line ("</HEAD><BODY>");
405}
406
407
408void html_end (void)
409{
410 if (index_count != 0)
411 start_index ();
412 if (out)
413 {
414 write_nl ();
415 html_write_index ();
416 write_line ("</BODY></HTML>");
417 }
418}
419
420void html_prototype_start (void)
421{
422 if (para_flag)
423 html_para ();
424 format_string (function_count == 1 ? "Prototype:" : "Prototypes:",
425 STYLE_BOLD, FALSE);
426 write_break ();
427 html_para ();
428}
429
430void html_prototype_end (uchar *compat)
431{
432 html_elements (STYLE_TTY);
433 html_para ();
434 if (compat[0] != 0)
435 {
436 format_string ("Compatibility:", STYLE_BOLD, FALSE);
437 html_para ();
438 format_string (compat, STYLE_NORMAL, FALSE);
439 html_para ();
440 compat[0] = 0;
441 }
442 format_string ("Description:", STYLE_BOLD, FALSE);
443}
444
445void html_see_also_start (void)
446{
447 if (para_flag)
448 html_para ();
449 format_string ("See also: ", STYLE_BOLD, FALSE);
450}
451
452void html_see_also_word (const uchar *word, const uchar *s)
453{
454 struct word *wp;
455
456 wp = use_reference (word);
457 if (wp != NULL)
458 {
459 if (wp->database == NULL)
460 html_begin_link (NULL, wp->ref);
461 else
462 html_begin_link (wp->database->str, wp->ref);
463 html_output (word, FALSE);
464 html_end_link ();
465 }
466 if (*s != 0)
467 {
468 write_string (",");
469 if (output_x >= 60)
470 write_nl ();
471 else
472 write_string (" ");
473 }
474}
475
476void html_sample_file (const uchar *s)
477{
478 html_libref_section ("Example");
479 format_string (" See ", STYLE_NORMAL, FALSE);
480 format_string (s, STYLE_TTY, FALSE);
481 para_flag = TRUE;
482}
483
484void html_libref_section (const uchar *s)
485{
486 if (para_flag)
487 html_para ();
488 format_string (s, STYLE_BOLD, FALSE);
489 write_string (":");
490 para_flag = TRUE;
491}
492
493void html_function_start (const struct toc *tp)
494{
495 write_line ("<HR>");
496 html_heading1 (tp->ref);
497 write_string ("<H2>");
498 html_output (tp->title, FALSE);
499 write_line ("</H2>");
500}
501
502void html_function_function (const struct toc *tp, const uchar *s)
503{
504 if (index_wp1 != NULL)
505 html_index (tp, s, 2);
506}
507
508void html_minitoc (const struct toc *tp)
509{
510 int level;
511
512 if (tp == NULL)
513 fatal ("%s:%d: Cannot build minitoc before the first heading",
514 input_fname, line_no);
515 if (para_flag)
516 html_para ();
517 level = tp->level;
518 tp = tp->next;
519 while (tp != NULL && tp->level >= level + 1)
520 {
521 if (tp->level == level + 1)
522 {
523 html_begin_link (NULL, tp->ref);
524 format_output (tp->title, FALSE);
525 html_end_link ();
526 write_line ("<BR>");
527 }
528 tp = tp->next;
529 }
530}
531
532
533void html_index (const struct toc *tp, const uchar *s, int level)
534{
535 struct word *wp;
536
537 switch (level)
538 {
539 case 0:
540 wp = word_add (s);
541 assert (tp != NULL);
542 if (wp->idx == 0)
543 {
544 wp->idx = tp->ref;
545 if (wp->subidx == NULL)
546 ++index_count;
547 }
548 else if (wp->idx != tp->ref)
549 warning (1, "%s:%d: Index entry multiply defined",
550 input_fname, line_no);
551 break;
552 case 1:
553 if (*s == 0)
554 index_wp1 = NULL;
555 else
556 {
557 wp = word_add (s);
558 index_wp1 = wp;
559 }
560 break;
561 case 2:
562 if (index_wp1 == NULL)
563 fatal ("%s:%d: %ci2 without %ci1", input_fname, line_no,
564 escape, escape);
565 if (index_wp1->subidx == NULL)
566 {
567 index_wp1->subidx = wt_new (37);
568 if (index_wp1->idx == 0)
569 ++index_count;
570 }
571 wp = wt_add (index_wp1->subidx, s);
572 assert (tp != NULL);
573 if (wp->idx == 0)
574 wp->idx = tp->ref;
575 else if (wp->idx != tp->ref)
576 warning (1, "%s:%d: Index entry multiply defined",
577 input_fname, line_no);
578 break;
579 default:
580 abort ();
581 }
582}
583
584
585static int index_add (struct word *wp)
586{
587 if (wp->idx != 0 || wp->subidx != NULL)
588 {
589 assert (index_n < index_count);
590 index_v[index_n++] = wp;
591 }
592 return 0;
593}
594
595static const uchar map_ascii[256] =
596 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
597 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
598 "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
599 "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
600 "\x40\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
601 "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x5a\x5b\x5c\x5d\x5e\x5f"
602 "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
603 "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\xff"
604 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
605 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
606 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
607 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
608 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
609 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
610 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
611 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
612
613static const uchar map_cp850[256] =
614 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
615 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
616 "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
617 "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
618 "\x40\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
619 "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x5a\x5b\x5c\x5d\x5e\x5f"
620 "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
621 "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\xff"
622 "\x63\x75\x65\x61\x61\x61\x61\x63\x65\x65\x65\x69\x69\x69\x61\x61"
623 "\x65\x61\x61\x6f\x6f\x6f\x75\x75\x79\x6f\x75\x6f\xff\x6f\xff\xff"
624 "\x61\x69\x6f\x75\x6e\x6e\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
625 "\xff\xff\xff\xff\xff\x61\x61\x61\xff\xff\xff\xff\xff\xff\xff\xff"
626 "\xff\xff\xff\xff\xff\xff\x61\x61\xff\xff\xff\xff\xff\xff\xff\xff"
627 "\xff\xff\x65\x65\x65\xff\x69\x69\x69\xff\xff\xff\xff\xff\x69\xff"
628 "\x6f\x80\x6f\x6f\x6f\x6f\xff\xff\xff\x75\x75\x75\x79\x79\xff\xff"
629 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
630
631static const uchar map_iso8859_1[256] =
632 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
633 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
634 "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
635 "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
636 "\x40\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
637 "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x5a\x5b\x5c\x5d\x5e\x5f"
638 "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
639 "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\xff"
640 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
641 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
642 "\x20\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
643 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
644 "\x61\x61\x61\x61\x61\x61\x61\x63\x65\x65\x65\x65\x69\x69\x69\x69"
645 "\xff\x6e\x6f\x6f\x6f\x6f\x6f\xff\x6f\x75\x75\x75\x75\x79\xff\x80"
646 "\x61\x61\x61\x61\x61\x61\x61\x63\x65\x65\x65\x65\x69\x69\x69\x69"
647 "\xff\x6e\x6f\x6f\x6f\x6f\x6f\xff\x6f\x75\x75\x75\x75\x79\xff\x79";
648
649static int compare1 (const uchar *s1, size_t n1,
650 const uchar *s2, size_t n2,
651 const uchar *map)
652{
653 uchar c1, c2;
654 int cmp;
655
656 while (n1 != 0 && n2 != 0)
657 {
658 c1 = map[*s1];
659 c2 = map[*s2];
660 if (c1 != c2)
661 {
662 /* Special cases for \ss */
663 if (c1 == 0x80)
664 {
665 cmp = compare1 ("ss", 2, s2, n2 < 2 ? n2 : 2, map_ascii);
666 if (cmp != 0)
667 return cmp;
668 ++s2; --n2;
669 }
670 else if (c2 == 0x80)
671 {
672 cmp = compare1 (s1, n1 < 2 ? n1 : 2, "ss", 2, map_ascii);
673 if (cmp != 0)
674 return cmp;
675 ++s1; --n1;
676 }
677 else if (c1 < c2)
678 return -1;
679 else
680 return 1;
681 }
682 ++s1; ++s2; --n1; --n2;
683 }
684 if (n1 != 0)
685 return 1;
686 if (n2 != 0)
687 return -1;
688 return 0;
689}
690
691static int index_compare (const void *p1, const void *p2)
692{
693 const struct word *wp1 = *(const struct word **)p1;
694 const struct word *wp2 = *(const struct word **)p2;
695 int cmp = compare1 (wp1->str, strlen (wp1->str),
696 wp2->str, strlen (wp2->str), index_map);
697 if (cmp != 0)
698 return cmp;
699 return strcmp (wp1->str, wp2->str);
700}
701
702static void index_recurse (struct word_table *wt, int level)
703{
704 int i, j, n;
705 struct word **v;
706
707 if (level != 0)
708 index_count = wt_count (wt);
709 n = index_count;
710 index_v = xmalloc (n * sizeof (*index_v));
711 index_n = 0;
712 wt_walk (wt, index_add);
713 assert (index_n == n);
714 v = index_v;
715 index_count = 0; index_v = NULL;
716
717 qsort (v, n, sizeof (*v), index_compare);
718 for (i = 0; i < n; ++i)
719 {
720 struct word *wp = v[i];
721 assert (wp->idx != 0 || wp->subidx != NULL);
722 for (j = 0; j < level; ++j)
723 write_string ("&nbsp;&nbsp;");
724 if (wp->idx != 0)
725 html_begin_link (NULL, wp->idx);
726 html_output ((const char *)wp->str, FALSE);
727 if (wp->idx != 0)
728 html_end_link ();
729 write_line ("<BR>");
730 if (wp->subidx != NULL)
731 index_recurse (wp->subidx, level + 1);
732 }
733 free (v);
734}
735
736static void html_write_index (void)
737{
738 if (index_count != 0)
739 {
740 int n = index_count;
741 if (output_encoding == ENC_ISO8859_1)
742 index_map = map_iso8859_1;
743 else
744 index_map = map_cp850;
745 index_recurse (word_top, 0);
746 index_count = n;
747 }
748}
749
750void html_fragment (const uchar *s)
751{
752 write_break ();
753 write_fmt ("<A NAME=\"%s\"></A>", (const char *)s);
754 write_nl ();
755}
Note: See TracBrowser for help on using the repository browser.