Added options to make Robodoc more customizable.
[robodoc.git] / Source / html_generator.c
1 /*
2 Copyright (C) 1994-2007  Frans Slothouber, Jacco van Weert, Petteri Kettunen,
3 Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner,
4 Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai.
5
6 This file is part of ROBODoc
7
8 ROBODoc is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
21 */
22
23
24 /****h* ROBODoc/HTML_Generator
25  * FUNCTION
26  *   The generator for HTML output.
27  *
28  *   The generator supports sections upto 7 levels deep.  It supports
29  *   a Table of Contents based on all headers.  A masterindex for
30  *   all headertypes and seperate masterindexes for each headertype.
31  *
32  * MODIFICATION HISTORY
33  *   2003-02-03   Frans Slothouber  Refactoring
34  *   ????-??-??   Frans Slothouber  V1.0
35  *******
36  * $Id: html_generator.c,v 1.91 2007/07/10 19:13:51 gumpu Exp $
37  */
38
39
40 #include <stdio.h>
41 #include <ctype.h>
42 #include <string.h>
43 #include <assert.h>
44 #include <stdlib.h>
45
46 #include "html_generator.h"
47 #include "util.h"
48 #include "globals.h"
49 #include "robodoc.h"
50 #include "links.h"
51 #include "headers.h"
52 #include "headertypes.h"
53 #include "generator.h"
54 #include "items.h"
55 #include "string.h"
56 #include "document.h"
57 #include "directory.h"
58 #include "path.h"
59 #include "part.h"
60 #include "roboconfig.h"
61
62 #ifdef DMALLOC
63 #include <dmalloc.h>
64 #endif
65
66 static char        *css_name = NULL;
67 static int          in_linecomment = 0; // are we in a line comment?
68
69 static void         RB_HTML_Generate_String(
70     FILE *dest_doc,
71     const char *a_string );
72
73
74
75 /* TODO Documentation */
76 static void HTML_Generate_Div(
77     FILE *dest_doc,
78     char *id )
79 {
80
81     fprintf( dest_doc, "<div id=\"%s\">\n", id );
82 }
83
84
85 /* TODO Documentation */
86 static void HTML_Generate_Div_End(
87     FILE *dest_doc,
88     char *id )
89 {
90     fprintf( dest_doc, "</div> <!-- %s -->\n", id );
91 }
92
93
94 /* TODO Documentation */
95
96 char               *HTML_TOC_Index_Filename(
97     struct RB_Document *document )
98 {
99     char               *toc_index_path = NULL;
100     char               *toc_index_name = "toc_index.html";
101
102     assert( document->docroot->name );
103
104     toc_index_path =
105         calloc( strlen( toc_index_name ) + 2 +
106                 strlen( document->docroot->name ), 1 );
107     strcpy( toc_index_path, document->docroot->name );
108     strcat( toc_index_path, toc_index_name );
109
110     return toc_index_path;
111 }
112
113
114
115 /* TODO  Documentation */
116 static void RB_HTML_Generate_Source_Tree_Entry(
117     FILE *dest_doc,
118     char *dest_name,
119     struct RB_Path *parent_path,
120     struct RB_Directory *srctree,
121     struct RB_Document *document )
122 {
123     struct RB_Path     *cur_path;
124     struct RB_Filename *cur_filename;
125
126     fprintf( dest_doc, "<ul>\n" );
127
128     for ( cur_filename = srctree->first;
129           cur_filename; cur_filename = cur_filename->next )
130     {
131         if ( cur_filename->path == parent_path )
132         {
133             char               *r = 0;
134
135             if ( cur_filename->link )
136             {
137                 if ( document->actions.do_one_file_per_header )
138                 {
139                     fprintf( dest_doc, "<li><tt>\n" );
140                     RB_HTML_Generate_String( dest_doc, cur_filename->name );
141                     fprintf( dest_doc, "</tt></li>\n" );
142                 }
143                 else
144                 {
145                     r = RB_HTML_RelativeAddress( dest_name,
146                                                  cur_filename->link->
147                                                  file_name );
148                     fprintf( dest_doc, "<li>\n" );
149                     fprintf( dest_doc, "<a href=\"%s#%s\"><tt>\n", r,
150                              cur_filename->link->label_name );
151                     RB_HTML_Generate_String( dest_doc, cur_filename->name );
152                     fprintf( dest_doc, "</tt></a></li>\n" );
153                 }
154             }
155         }
156     }
157     for ( cur_path = srctree->first_path;
158           cur_path; cur_path = cur_path->next )
159     {
160         if ( cur_path->parent == parent_path )
161         {
162             fprintf( dest_doc, "<li>\n" );
163             RB_HTML_Generate_String( dest_doc, cur_path->name );
164             RB_HTML_Generate_Source_Tree_Entry( dest_doc, dest_name, cur_path,
165                                                 srctree, document );
166             fprintf( dest_doc, "</li>\n" );
167         }
168     }
169     fprintf( dest_doc, "</ul>\n" );
170 }
171
172 /* TODO  Documentation */
173 void RB_HTML_Generate_Source_Tree(
174     FILE *dest_doc,
175     char *dest_name,
176     struct RB_Document *document )
177 {
178     struct RB_Directory *srctree;
179
180     srctree = document->srctree;
181     RB_HTML_Generate_Source_Tree_Entry( dest_doc, dest_name, NULL, srctree,
182                                         document );
183 }
184
185
186 /****if* HTML_Generator/RB_HTML_Generate_String
187  * FUNCTION
188  *   Write a string to the destination document, escaping
189  *   characters where necessary.
190  * SYNOPSIS
191  */
192 static void RB_HTML_Generate_String(
193     FILE *dest_doc,
194     const char *a_string )
195 /*
196  * INPUTS
197  *   o dest_doc -- the file the characters are written too
198  *   o a_string -- a nul terminated string.
199  * SEE ALSO
200  *   RB_HTML_Generate_Char()
201  * SOURCE
202  */
203 {
204     int                 i;
205     int                 l = strlen( a_string );
206     unsigned char       c;
207
208     for ( i = 0; i < l; ++i )
209     {
210         c = a_string[i];
211         RB_HTML_Generate_Char( dest_doc, c );
212     }
213 }
214
215 /*******/
216
217
218 /****if* HTML_Generator/RB_HTML_Generate_False_Link
219  * FUNCTION
220  *   Create a representation for a link that links an word in
221  *   a header to the header itself.
222  * SYNOPSIS
223  */
224 void RB_HTML_Generate_False_Link(
225     FILE *dest_doc,
226     char *name )
227 /*
228  * INPUTS
229  *   * dest_doc -- the file the representation is written to.
230  *   * name     -- the word.
231  * SOURCE
232  */
233 {
234     fprintf( dest_doc, "<strong>" );
235     RB_HTML_Generate_String( dest_doc, name );
236     fprintf( dest_doc, "</strong>" );
237
238 }
239
240 /*******/
241
242
243 /****f* HTML_Generator/RB_HTML_Color_String
244  * FUNCTION
245  *   Generates various colored strings
246  * SOURCE
247  */
248
249 static void RB_HTML_Color_String(
250     FILE *dest_doc,
251     int open,
252     const char *class,
253     const char *string )
254 {
255     switch ( open )
256     {
257         // string, closing
258     case 0:
259         RB_HTML_Generate_String( dest_doc, string );
260         fprintf( dest_doc, "</span>" );
261         break;
262
263         // opening, string
264     case 1:
265         fprintf( dest_doc, "<span class=\"%s\">", class );
266         RB_HTML_Generate_String( dest_doc, string );
267         break;
268
269         // opening, string, closing
270     case 2:
271         fprintf( dest_doc, "<span class=\"%s\">", class );
272         RB_HTML_Generate_String( dest_doc, string );
273         fprintf( dest_doc, "</span>" );
274         break;
275
276         // opening, char, closing
277     case 3:
278         fprintf( dest_doc, "<span class=\"%s\">", class );
279         RB_HTML_Generate_Char( dest_doc, *string );
280         fprintf( dest_doc, "</span>" );
281         break;
282
283         // Bug
284     default:
285         assert( 0 );
286     }
287 }
288
289 /*******/
290
291
292 /****f* HTML_Generator/RB_HTML_Generate_Line_Comment_End
293  * FUNCTION
294  *   Check if a line comment is active and generate ending sequence for it.
295  *   Should be called at the end of each SOURCE line.
296  * SYNOPSIS
297  */
298 void RB_HTML_Generate_Line_Comment_End(
299     FILE *dest_doc )
300 {
301     // Check if we are in a line comment
302     if ( in_linecomment )
303     {
304         // and end the line comment
305         in_linecomment = 0;
306         RB_HTML_Color_String( dest_doc, in_linecomment, COMMENT_CLASS, "" );
307     }
308 }
309
310 /*******/
311
312
313 /****f* HTML_Generator/RB_HTML_Generate_Extra
314  * FUNCTION
315  *   Do some additional processing to detect HTML extra's like
316  *   file references and other kind of links for the documentation
317  *   body of an item.
318  * SYNOPSIS
319  */
320 int RB_HTML_Generate_Extra(
321     FILE *dest_doc,
322     enum ItemType item_type,
323     char *cur_char,
324     char prev_char )
325 /*
326  * INPUTS
327  *   o dest_doc  -- the file to write to.
328  *   o item_type -- the kind of item the body belongs to.
329  *   o cur_char  -- pointer to a substring of the item's body
330  *   o prev_char -- the character just before cur char (zero if none)
331  * RESULTS
332  *   Number of characters produced.
333  * SOURCE
334  */
335 {
336     char                link[1024], *str;
337     int                 res = -1;
338     unsigned int        i;
339     static int          incomment = 0;  /* are we in comment? */
340     static int          quote = 0;      /* double quote */
341     static int          squote = 0;     /* single quote */
342
343     // Reset comment and quote state machine if not source item
344     if ( !Works_Like_SourceItem( item_type ) )
345     {
346         quote = 0;
347         squote = 0;
348         incomment = 0;
349         in_linecomment = 0;
350     }
351     // else check for quotations and string literals
352     else if ( !( incomment || in_linecomment ) )
353     {
354         switch ( *cur_char )
355         {
356             // Check for quoted string literals ("string")
357         case '\"':
358             if ( !squote && course_of_action.do_quotes )
359             {
360                 if ( prev_char != '\\' )
361                 {
362                     quote = !quote;
363                     RB_HTML_Color_String( dest_doc, quote,
364                                           QUOTE_CLASS, "\"" );
365                     return 0;
366                 }
367                 else if ( quote && *( ( char * ) ( cur_char - 2 ) ) == '\\' )
368                 {
369                     quote = !quote;     /* case "... \\" */
370                     RB_HTML_Color_String( dest_doc, quote,
371                                           QUOTE_CLASS, "\"" );
372                     return 0;
373                 }
374             }
375             break;
376
377             // Check for single quoted string literals ('string')
378         case '\'':
379             if ( !quote && course_of_action.do_squotes )
380             {
381                 if ( prev_char != '\\' )
382                 {
383                     squote = !squote;
384                     RB_HTML_Color_String( dest_doc, squote,
385                                           SQUOTE_CLASS, "\'" );
386                     return 0;
387                 }
388                 else if ( squote && *( ( char * ) ( cur_char - 2 ) ) == '\\' )
389                 {
390                     squote = !squote;   /* case '\\' */
391                     RB_HTML_Color_String( dest_doc, squote,
392                                           SQUOTE_CLASS, "\'" );
393                     return 0;
394                 }
395             }
396             break;
397
398         default:
399             break;
400         }
401     }
402
403     // Recognise line comments
404     if ( Works_Like_SourceItem( item_type ) && !incomment && !quote
405          && !squote && course_of_action.do_line_comments )
406     {
407         // check for line comment start
408         if ( !in_linecomment )
409         {
410             str =
411                 Find_Parameter_Partial( &
412                                         ( configuration.
413                                           source_line_comments ), cur_char );
414             if ( str )
415             {
416                 in_linecomment = 1;
417                 RB_HTML_Color_String( dest_doc, in_linecomment,
418                                       COMMENT_CLASS, str );
419                 //  We found it, so exit
420                 return strlen( str ) - 1;
421             }
422         }
423         // The end of line comments are generated in
424         // RB_HTML_Generate_Line_Comment_End()
425     }
426
427     // Recognise block comments
428     if ( Works_Like_SourceItem( item_type ) && !in_linecomment && !quote
429          && !squote && course_of_action.do_block_comments )
430     {
431         // Check for block comment start
432         if ( !incomment )
433         {
434             str =
435                 Find_Parameter_Partial( &
436                                         ( configuration.
437                                           remark_begin_markers ), cur_char );
438             if ( str )
439             {
440                 incomment = 1;
441                 RB_HTML_Color_String( dest_doc, incomment,
442                                       COMMENT_CLASS, str );
443                 //  We found it, so exit
444                 return strlen( str ) - 1;
445             }
446         }
447         // Check for block comment end
448         else
449         {
450             str =
451                 Find_Parameter_Partial( &( configuration.remark_end_markers ),
452                                         cur_char );
453             if ( str )
454             {
455                 incomment = 0;
456                 RB_HTML_Color_String( dest_doc, incomment,
457                                       COMMENT_CLASS, str );
458                 //  We found it, so exit
459                 return strlen( str ) - 1;
460             }
461         }
462     }
463
464     // Do further source formating
465     if ( Works_Like_SourceItem( item_type ) &&
466          !in_linecomment && !incomment && !quote && !squote )
467     {
468         // Check for keywords
469         if ( configuration.keywords.number && course_of_action.do_keywords )
470         {
471             char               *keyword;
472
473             // Check if we are at the beginning of a word
474             if ( !utf8_isalnum( prev_char ) && ( prev_char != '_' ) )
475             {
476                 // Count word length
477                 for ( i = 1;    // A word should have at least one character...
478                       utf8_isalnum( cur_char[i] ) || ( cur_char[i] == '_' );
479                       i++ );
480                 // Check if it is a keyword
481                 if ( ( keyword = Find_Keyword( cur_char, i ) ) )
482                 {
483                     RB_HTML_Color_String( dest_doc, 2, KEYWORD_CLASS,
484                                           keyword );
485                     // Exit function
486                     return i - 1;
487                 }
488             }
489         }
490
491         // Do some fancy coloration for non-alphanumeric chars
492         if ( !utf8_isalnum( *cur_char ) && *cur_char != '_'
493              && *cur_char != ' ' && course_of_action.do_non_alpha )
494         {
495             RB_HTML_Color_String( dest_doc, 3, SIGN_CLASS, cur_char );
496             return 0;
497         }
498     }
499
500     // Check for links, etc...
501     if ( incomment || in_linecomment || !Works_Like_SourceItem( item_type ) )
502     {
503         if ( strncmp( "http://", cur_char, 7 ) == 0 )
504         {
505             sscanf( cur_char, "%s", link );
506             RB_Say( "found link %s\n", SAY_DEBUG, link );
507             res = ( strlen( link ) - 1 );
508             /* [ 697247 ] http://body. does not skip the '.' */
509             if ( link[( strlen( link ) - 1 )] == '.' )
510             {
511                 link[( strlen( link ) - 1 )] = '\0';
512                 fprintf( dest_doc, "<a href=\"%s\">%s</a>.", link, link );
513             }
514             else
515             {
516                 fprintf( dest_doc, "<a href=\"%s\">%s</a>", link, link );
517             }
518         }
519         else if ( strncmp( "href:", cur_char, 5 ) == 0 )
520         {
521             /*
522              * handy in relative hyperlink paths, e.g.
523              * href:../../modulex/
524              */
525             sscanf( ( cur_char + 5 ), "%s", link );
526             RB_Say( "found link %s\n", SAY_DEBUG, link );
527             res = ( strlen( link ) + 4 );
528             fprintf( dest_doc, "<a href=\"%s\">%s</a>", link, link );
529         }
530         else if ( strncmp( "file:/", cur_char, strlen( "file:/" ) ) == 0 )
531         {
532             sscanf( cur_char, "%s", link );
533             RB_Say( "found link %s\n", SAY_DEBUG, link );
534             res = ( strlen( link ) - 1 );
535             fprintf( dest_doc, "<a href=\"%s\">%s</a>", link, link );
536         }
537         else if ( strncmp( "mailto:", cur_char, 7 ) == 0 )
538         {
539             sscanf( ( cur_char + 7 ), "%s", link );
540             RB_Say( "found mail to %s\n", SAY_DEBUG, link );
541             res = ( strlen( link ) + 6 );
542             fprintf( dest_doc, "<a href=\"mailto:%s\">%s</a>", link, link );
543         }
544         else if ( strncmp( "image:", cur_char, 6 ) == 0 )
545         {
546             sscanf( ( cur_char + 6 ), "%s", link );
547             RB_Say( "found image %s\n", SAY_DEBUG, link );
548             res = ( strlen( link ) + 5 );
549             fprintf( dest_doc, "<img src=\"%s\">", link );
550         }
551
552     }
553     return res;
554 }
555
556 /******/
557
558
559
560 void RB_HTML_Generate_Item_Name(
561     FILE *dest_doc,
562     char *name )
563 {
564     fprintf( dest_doc, "<p class=\"item_name\">" );
565     RB_HTML_Generate_String( dest_doc, name );
566     fprintf( dest_doc, "</p>\n" );
567 }
568
569 void RB_HTML_Generate_Item_Begin(
570     FILE *dest_doc,
571     char *name )
572 {
573     USE( dest_doc );
574     USE( name );
575     /* empty */
576 }
577
578 void RB_HTML_Generate_Item_End(
579     FILE *dest_doc,
580     char *name )
581 {
582     USE( dest_doc );
583     USE( name );
584     /* empty */
585 }
586
587
588 int                 sectiontoc_counters[MAX_SECTION_DEPTH];
589
590 /****f* HTML_Generator/RB_HTML_Generate_TOC_Section
591  * FUNCTION
592  *   Create a table of contents based on the hierarchy of
593  *   the headers starting for a particular point in this
594  *   hierarchy (the parent).
595  * SYNOPSIS
596  */
597 void RB_HTML_Generate_TOC_Section(
598     FILE *dest_doc,
599     char *dest_name,
600     struct RB_header *parent,
601     struct RB_header **headers,
602     int count,
603     int depth )
604 /*
605  * INPUTS
606  *   o dest_doc  -- the file to write to.
607  *   o dest_name -- the name of this file.
608  *   o parent    -- the parent of the headers for which the the
609  *                  current level(depth) of TOC is created.
610  *   o headers   -- an array of headers for which the TOC is created
611  *   o count     -- the number of headers in this array
612  *   o depth     -- the current depth of the TOC
613  * NOTES
614  *   This is a recursive function and tricky stuff.
615  * SOURCE
616  */
617 {
618     struct RB_header   *header;
619     int                 i, n, once = 0;
620
621     ++sectiontoc_counters[depth];
622
623     for ( i = depth + 1; i < MAX_SECTION_DEPTH; ++i )
624     {
625         sectiontoc_counters[i] = 0;
626     }
627
628     // List item start
629     fprintf( dest_doc, "<li>" );
630
631     // Do not generate section numbers if sectionnameonly
632     if ( !( course_of_action.do_sectionnameonly ) )
633     {
634         for ( i = 1; i <= depth; ++i )
635         {
636             fprintf( dest_doc, "%d.", sectiontoc_counters[i] );
637         }
638         fprintf( dest_doc, " " );
639     }
640
641
642     // Generate Link to first reference name
643     RB_HTML_Generate_Link( dest_doc, dest_name, parent->file_name,
644                            parent->unique_name,
645                            // only generate function name if sectionnameonly
646                            ( course_of_action.do_sectionnameonly ) ?
647                            parent->function_name : parent->name, 0 );
648
649     // Generate links to further reference names
650     for ( n = 1; n < parent->no_names; n++ )
651     {
652         RB_HTML_Generate_String( dest_doc, ", " );
653         RB_HTML_Generate_Link( dest_doc, dest_name, parent->file_name,
654                                parent->unique_name, parent->names[n], 0 );
655     }
656
657     // List item end
658     fprintf( dest_doc, "</li>\n" );
659
660     for ( i = 0; i < count; ++i )
661     {
662         header = headers[i];
663         if ( header->parent == parent )
664         {
665             // Generate better TOC level hiearchy (Thuffir)
666             // We only generate <ul> once for a level
667             if ( !once )
668             {
669                 once = 1;
670                 fprintf( dest_doc, "<ul>\n" );
671             }
672             RB_HTML_Generate_TOC_Section( dest_doc, dest_name, header,
673                                           headers, count, depth + 1 );
674         }
675         else
676         {
677             /* Empty */
678         }
679     }
680     // If we have generated an <ul> before, generate the closing one too.
681     if ( once )
682         fprintf( dest_doc, "</ul>\n" );
683 }
684
685 /*******/
686
687
688 void RB_HTML_Generate_TOC_Entries(
689     FILE *dest_doc,
690     struct RB_header **headers,
691     int count,
692     struct RB_Part *owner,
693     char *dest_name )
694 {
695   struct RB_header *header;
696   char *object_name, *label_name, *file_name;
697   int i, j;
698
699 //  fprintf( dest_doc, "<h3>Table of Contents</h3>\n" );
700   fprintf( dest_doc, "<p class=\"item_name\">TABLE OF CONTENTS</p>\n" );
701   fprintf( dest_doc, "<ul class=\"toc_entries\">\n" );
702
703   for ( i = count - 1; i >= 0; i-- )
704     {
705       header = headers[i];
706
707       if ( header->htype->typeCharacter != 'h' &&
708            !strcmp( owner->filename->name, header->owner->filename->name ) &&
709            Find_Link( header->function_name,
710                       &object_name, &label_name,
711                       &file_name ) )
712         {
713           for ( j = 0; j < header->no_names; j++ )
714             {
715               fprintf( dest_doc, "<li class=\"toc_entries\">" );
716               RB_HTML_Generate_Link( dest_doc,
717                                      dest_name,
718                                      file_name,
719                                      "",
720                                      object_name, 0);
721               fprintf( dest_doc, "</li>\n" );
722             }
723         }
724     }
725
726   fprintf( dest_doc, "</ul>\n" );
727 }
728
729
730 void RB_HTML_Generate_TOC_2(
731     FILE *dest_doc,
732     struct RB_header **headers,
733     int count,
734     struct RB_Part *owner,
735     char *dest_name )
736 {
737     struct RB_header   *header;
738     int                 i, j;
739     int                 depth = 1;
740
741     for ( i = 0; i < MAX_SECTION_DEPTH; ++i )
742     {
743         sectiontoc_counters[i] = 0;
744     }
745     fprintf( dest_doc, "<h3>TABLE OF CONTENTS</h3>\n" );
746     if ( course_of_action.do_sections )
747     {
748         /* --sections was specified, create a TOC based on the
749          * hierarchy of the headers.
750          */
751         fprintf( dest_doc, "<ul>\n" );
752         for ( i = 0; i < count; ++i )
753         {
754             header = headers[i];
755             if ( owner == NULL )
756             {
757                 if ( header->parent )
758                 {
759                     /* Will be done in the subfunction */
760                 }
761                 else
762                 {
763                     RB_HTML_Generate_TOC_Section( dest_doc, dest_name, header,
764                                                   headers, count, depth );
765                 }
766             }
767             else
768             {
769                 /* This is the TOC for a specific RB_Part (MultiDoc
770                  * documentation). We only include the headers that
771                  * are part of the subtree. That is, headers that are
772                  * parth the RB_Part, or that are childern of the
773                  * headers in the RB_Part.
774                  */
775                 if ( header->owner == owner )
776                 {
777                     /* BUG 721690 */
778                     /* Any of the parents of this header should not
779                      * have the same owner as this header, otherwise
780                      * this header will be part of the TOC multiple times.
781                      */
782                     int                 no_bad_parent = TRUE;
783                     struct RB_header   *parent = header->parent;
784
785                     for ( ; parent; parent = parent->parent )
786                     {
787                         if ( parent->owner == owner )
788                         {
789                             no_bad_parent = FALSE;
790                             break;
791                         }
792                     }
793                     if ( no_bad_parent )
794                     {
795                         RB_HTML_Generate_TOC_Section( dest_doc, dest_name,
796                                                       header, headers, count,
797                                                       depth );
798                     }
799                 }
800             }
801         }
802         fprintf( dest_doc, "</ul>\n" );
803     }
804     else
805     {
806         /* No --section option, generate a plain, one-level
807          * TOC
808          */
809         fprintf( dest_doc, "<ul>\n" );
810
811         for ( i = 0; i < count; ++i )
812         {
813             header = headers[i];
814             if ( header->name && header->function_name &&
815                  ( ( owner == NULL ) || ( header->owner == owner ) ) )
816             {
817                 for ( j = 0; j < header->no_names; j++ )
818                 {
819                     fprintf( dest_doc, "<li>" );
820
821                     RB_HTML_Generate_Link( dest_doc, dest_name,
822                                            header->file_name,
823                                            header->unique_name,
824                                            header->names[j], 0 );
825                     fprintf( dest_doc, "</li>\n" );
826                 }
827             }
828         }
829         fprintf( dest_doc, "</ul>\n" );
830     }
831 }
832
833
834
835 /****f* HTML_Generator/RB_HTML_Generate_Label
836  * FUNCTION
837  *   Generate a label (name) that can be refered too.
838  *   A label should consist of only alphanumeric characters so
839  *   all 'odd' characters are replaced with their ASCII code in
840  *   hex format.
841  * SYNOPSIS
842  */
843 void RB_HTML_Generate_Label(
844     FILE *dest_doc,
845     char *name )
846 /*
847  * INPUTS
848  *   o dest_doc -- the file to write it to.
849  *   o name     -- the name of the label.
850  * SOURCE
851  */
852 {
853     int                 i;
854     int                 l = strlen( name );
855     unsigned char       c;
856
857     fprintf( dest_doc, "<a name=\"" );
858     for ( i = 0; i < l; ++i )
859     {
860         c = name[i];
861         if ( utf8_isalnum( c ) )
862         {
863             RB_HTML_Generate_Char( dest_doc, c );
864         }
865         else
866         {
867             char                buf[4];
868
869             sprintf( buf, "%02x", c );
870             RB_HTML_Generate_Char( dest_doc, buf[0] );
871             RB_HTML_Generate_Char( dest_doc, buf[1] );
872         }
873     }
874     fprintf( dest_doc, "\">\n" );
875 }
876
877 /********/
878
879
880
881 static int          section_counters[MAX_SECTION_DEPTH];
882
883
884 /* TODO Documentation */
885
886 void RB_HTML_Generate_BeginSection(
887     FILE *dest_doc,
888     int depth,
889     char *name,
890     struct RB_header *header )
891 {
892     int                 i;
893
894     ++section_counters[depth];
895     for ( i = depth + 1; i < MAX_SECTION_DEPTH; ++i )
896     {
897         section_counters[i] = 0;
898     }
899     switch ( depth )
900     {
901     case 1:
902     case 2:
903     case 3:
904     case 4:
905     case 5:
906     case 6:
907     case 7:
908         fprintf( dest_doc, "<h%d>", depth );
909         // Only generate section numbers if no sectionnameonly
910         if ( !( course_of_action.do_sectionnameonly ) )
911         {
912             for ( i = 1; i <= depth; ++i )
913             {
914                 fprintf( dest_doc, "%d.", section_counters[i] );
915             }
916             fprintf( dest_doc, "  " );
917         }
918
919         // Print Header "first" name
920         RB_HTML_Generate_String( dest_doc, name );
921
922         // Print further names
923         for ( i = 1; i < header->no_names; i++ )
924         {
925             fprintf( dest_doc, ( i % header_breaks ) ? ", " : ",<br />" );
926             RB_HTML_Generate_String( dest_doc, header->names[i] );
927         }
928
929         // Include module name if not sectionnameonly
930         if ( !( course_of_action.do_sectionnameonly ) )
931         {
932             fprintf( dest_doc, " [ " );
933             RB_HTML_Generate_String( dest_doc, header->htype->indexName );
934             fprintf( dest_doc, " ]" );
935         }
936
937         fprintf( dest_doc, "  </h%d>\n", depth );
938         break;
939     default:
940         /* too deep, don't do anything. */
941         assert( 0 );
942     }
943 }
944
945 void RB_HTML_Generate_EndSection(
946     FILE *dest_doc,
947     int depth,
948     char *name )
949 {
950     USE( dest_doc );
951     USE( name );
952     USE( depth );
953     /* Empty */
954 }
955
956
957 char               *RB_HTML_Get_Default_Extension(
958     void )
959 {
960     return ( ".html" );
961 }
962
963 /****f* HTML_Generator/RB_HTML_Generate_Doc_Start
964  * NAME
965  *   RB_HTML_Generate_Doc_Start --
966  * FUNCTION
967  *   Generate the first part of a HTML document.
968  *   As far as ROBODoc is concerned a HTML document
969  *   consists of three parts:
970  *   * The start of a document
971  *   * The body of a document
972  *   * The end of a document
973  * SYNOPSIS
974  */
975 void RB_HTML_Generate_Doc_Start(
976     FILE *dest_doc,
977     char *src_name,
978     char *name,
979     char *dest_name,
980     char *charset )
981 /*
982  * INPUTS
983  *   o dest_doc  --  the output file.
984  *   o src_name  --  The file or directoryname from which
985  *                   this document is generated.
986  *   o name      --  The title for this document
987  *   o dest_name --  the name of the output file.
988  *   o charset   --  the charset to be used for the file.
989  * SOURCE
990  */
991 {
992
993     if ( course_of_action.do_headless )
994     {
995         /* The user wants a headless document, so we skip everything
996          * upto and until <BODY>
997          */
998     }
999     else
1000     {
1001         /* Append document type and title */
1002         fprintf( dest_doc, "<?xml version=\"1.0\" encoding=\"%s\"?>\n",
1003                  charset ? charset : DEFAULT_CHARSET );
1004         fprintf( dest_doc,
1005                  "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n" );
1006         fprintf( dest_doc,
1007                  "                      \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" );
1008
1009         fprintf( dest_doc,
1010                  "<html  xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n" );
1011         fprintf( dest_doc, "<head>\n" );
1012         fprintf( dest_doc,
1013                  "<meta http-equiv=\"Content-Style-Type\" content=\"text/css\" />\n" );
1014         /* TODO is charset still needed?? */
1015         fprintf( dest_doc,
1016                  "<meta http-equiv=\"Content-type\" content=\"text/html; charset=%s\" />\n",
1017                  charset ? charset : DEFAULT_CHARSET );
1018         RB_InsertCSS( dest_doc, dest_name );
1019         fprintf( dest_doc, "<title>%s</title>\n", name );
1020
1021         /* append SGML-comment with document- and copyright-info. This code
1022          * ensures that every line has an own comment to avoid problems with
1023          * buggy browsers */
1024         fprintf( dest_doc, "<!-- Source: %s -->\n", src_name );
1025         if ( course_of_action.do_nogenwith )
1026         {
1027
1028         }
1029         else
1030         {
1031             static const char   copyright_text[]
1032                 = COMMENT_ROBODOC /* COMMENT_COPYRIGHT */ ;
1033             size_t              i = 0;
1034             char                previous_char = '\n';
1035             char                current_char = copyright_text[i];
1036
1037             while ( current_char )
1038             {
1039                 if ( previous_char == '\n' )
1040                 {
1041                     fprintf( dest_doc, "<!-- " );
1042                 }
1043                 if ( current_char == '\n' )
1044                 {
1045                     fprintf( dest_doc, " -->" );
1046                 }
1047                 else if ( ( current_char == '-' )
1048                           && ( previous_char == '-' ) )
1049                 {
1050                     /* avoid "--" inside SGML-comment, and use "-_" instead; this
1051                      * looks a bit strange, but one should still be able to figure
1052                      * out what is meant when reading the output */
1053                     current_char = '_';
1054                 }
1055                 fputc( current_char, dest_doc );
1056                 i += 1;
1057                 previous_char = current_char;
1058                 current_char = copyright_text[i];
1059             }
1060         }
1061
1062         /* append heading and start list of links to functions */
1063         fprintf( dest_doc, "</head>\n" );
1064         fprintf( dest_doc, "<body>\n" );
1065     }
1066
1067 //    HTML_Generate_Div( dest_doc, "container" );
1068
1069     /* Use user specified header if present */
1070     if ( document_header )
1071     {
1072         fprintf ( dest_doc, document_header );
1073     }
1074     else
1075     {
1076         /* Generate document title if available (Thuffir) */
1077         HTML_Generate_Div( dest_doc, "logo" );
1078         fprintf( dest_doc, "<a name=\"robo_top_of_doc\">" );
1079         if ( document_title )
1080             RB_HTML_Generate_String( dest_doc, document_title );
1081         fprintf( dest_doc, "</a>\n" );
1082         HTML_Generate_Div_End( dest_doc, "logo" );
1083     }
1084 }
1085
1086 /******/
1087
1088
1089 /* TODO */
1090 /*x**if* HTML_Generator/RB_HTML_Generate_Doc_End
1091  * NAME
1092  *   RB_HTML_Generate_Doc_End --
1093  * FUNCTION
1094  *   Close of the document with the proper end tags.
1095  ******
1096  */
1097
1098 void RB_HTML_Generate_Doc_End(
1099     FILE *dest_doc,
1100     char *name,
1101     char *src_name )
1102 {
1103
1104     USE( name );
1105
1106     /* Use user specified footer if present */
1107     if ( document_footer )
1108     {
1109         fprintf ( dest_doc, document_footer );
1110     }
1111     else
1112     {
1113       HTML_Generate_Div( dest_doc, "footer" );
1114
1115         /* TODO This should be done with
1116          * RB_Generate_Label()
1117          */
1118         if ( course_of_action.do_nogenwith )
1119         {
1120             fprintf( dest_doc, "<p>Generated from %s on ", src_name );
1121             RB_TimeStamp( dest_doc );
1122             fprintf( dest_doc, "</p>\n" );
1123         }
1124         else
1125         {
1126             fprintf( dest_doc,
1127                      "<p>Generated from %s with <a href=\"http://www.xs4all.nl/~rfsber/Robo/robodoc.html\">ROBODoc</a> V%s on ",
1128                      src_name, VERSION );
1129             RB_TimeStamp( dest_doc );
1130             fprintf( dest_doc, "</p>\n" );
1131         }
1132
1133         HTML_Generate_Div_End( dest_doc, "footer" );
1134     }
1135
1136 //    HTML_Generate_Div_End( dest_doc, "container" );
1137
1138     if ( course_of_action.do_footless )
1139     {
1140         /* The user does not want the foot of the
1141          * document.
1142          */
1143     }
1144     else
1145     {
1146         fprintf( dest_doc, "</body>\n</html>\n" );
1147     }
1148 }
1149
1150
1151 void RB_HTML_Generate_Nav_Bar(
1152     struct RB_Document *document,
1153     FILE *current_doc,
1154     struct RB_header *current_header )
1155 {
1156     char               *current_filename = NULL;
1157     char               *target_filename = NULL;
1158     char               *label = NULL;
1159     char               *label_name = NULL;
1160
1161     current_filename = RB_Get_FullDocname( current_header->owner->filename );
1162     target_filename = RB_Get_FullDocname( current_header->owner->filename );
1163     label = Get_Fullname( current_header->owner->filename );
1164     /* The navigation bar */
1165     fprintf( current_doc, "<p>" );
1166
1167     // [ Top ]
1168     fprintf( current_doc, "[ " );
1169     RB_HTML_Generate_Link( current_doc, current_filename, NULL,
1170                            "robo_top_of_doc", "Top", 0 );
1171     fprintf( current_doc, " ] " );
1172
1173     // [ "Parentname" ]
1174     if ( current_header->parent )
1175     {
1176         fprintf( current_doc, "[ " );
1177         target_filename =
1178             RB_Get_FullDocname( current_header->parent->owner->filename );
1179         label = current_header->parent->unique_name;
1180         label_name = current_header->parent->function_name;
1181         RB_HTML_Generate_Link( current_doc, current_filename, target_filename,
1182                                label, label_name, 0 );
1183         fprintf( current_doc, " ] " );
1184     }
1185
1186     // [ "Modulename" ]
1187     fprintf( current_doc, "[ " );
1188     label_name = current_header->htype->indexName;
1189     if ( ( course_of_action.do_index ) && ( course_of_action.do_multidoc ) )
1190     {
1191         target_filename = RB_Get_SubIndex_FileName( document->docroot->name,
1192                                                     document->extension,
1193                                                     current_header->htype );
1194         RB_HTML_Generate_Link( current_doc, current_filename, target_filename,
1195                                "robo_top_of_doc", label_name, 0 );
1196         free( target_filename );
1197     }
1198     else
1199     {
1200         RB_HTML_Generate_String( current_doc, label_name );
1201     }
1202     fprintf( current_doc, " ]</p>\n" );
1203 }
1204
1205
1206
1207 /* TODO Documentation */
1208
1209 void RB_HTML_Generate_Nav_Bar_One_File_Per_Header(
1210     struct RB_Document *document,
1211     FILE *current_doc,
1212     struct RB_header *current_header )
1213 {
1214     char               *current_filename = NULL;
1215     char               *target_filename = NULL;
1216     char               *label = NULL;
1217     char               *label_name = NULL;
1218
1219     current_filename = RB_Get_FullDocname( current_header->owner->filename );
1220     target_filename = RB_Get_FullDocname( current_header->owner->filename );
1221     label = Get_Fullname( current_header->owner->filename );
1222     /* The navigation bar */
1223     if ( current_header->parent )
1224     {
1225         target_filename =
1226             RB_Get_FullDocname( current_header->parent->owner->filename );
1227         label = current_header->parent->unique_name;
1228         label_name = current_header->parent->function_name;
1229         RB_HTML_Generate_Link( current_doc, current_filename, target_filename,
1230                                label, label_name, "menuitem" );
1231     }
1232     /* FS TODO  one_file_per_header without   index is not logical */
1233     if ( ( course_of_action.do_index ) && ( course_of_action.do_multidoc ) )
1234     {
1235         target_filename = RB_Get_SubIndex_FileName( document->docroot->name,
1236                                                     document->extension,
1237                                                     current_header->htype );
1238         label_name = current_header->htype->indexName;
1239         RB_HTML_Generate_Link( current_doc, current_filename, target_filename,
1240                                "robo_top_of_doc", label_name, "menuitem" );
1241         free( target_filename );
1242     }
1243 }
1244
1245
1246
1247
1248
1249 /* TODO Documentation */
1250 /*x**if* HTML_Generator/RB_HTML_Generate_Header_Start
1251  * NAME
1252  *   RB_HTML_Generate_Header_Start --
1253  ******
1254  */
1255
1256 void RB_HTML_Generate_Header_Start(
1257     FILE *dest_doc,
1258     struct RB_header *cur_header )
1259 {
1260     struct RB_HeaderType *header_type;
1261     int                 i;
1262
1263     if ( cur_header->name && cur_header->function_name )
1264     {
1265 /*        fprintf( dest_doc, "<hr />\n" ); */
1266         RB_HTML_Generate_Label( dest_doc, cur_header->name );
1267         fprintf( dest_doc, "</a><a name=\"%s\"></a><h2>",
1268                  cur_header->unique_name );
1269
1270         header_type = RB_FindHeaderType( cur_header->htype->typeCharacter );
1271
1272         for ( i = 1; i <= cur_header->no_names; i++ )
1273         {
1274             // If Section names only, do not print module name
1275             if ( i == 1 && ( course_of_action.do_sectionnameonly ) )
1276                 RB_HTML_Generate_String( dest_doc,
1277                                          cur_header->function_name );
1278             else
1279                 RB_HTML_Generate_String( dest_doc, cur_header->names[i - 1] );
1280
1281             // Break lines after a predefined number of header names
1282             if ( i < cur_header->no_names )
1283                 fprintf( dest_doc, ( i % header_breaks ) ? ", " : ",<br />" );
1284         }
1285
1286         // Print header type (if available and not Section names only)
1287         if ( header_type && !( course_of_action.do_sectionnameonly ) )
1288         {
1289             fprintf( dest_doc, " [ " );
1290             RB_HTML_Generate_String( dest_doc, header_type->indexName );
1291             fprintf( dest_doc, " ]" );
1292         }
1293
1294         fprintf( dest_doc, "</h2>\n\n" );
1295     }
1296 }
1297
1298 /* TODO */
1299 /*x**f* HTML_Generator/RB_HTML_Generate_Header_End
1300  * NAME
1301  *   RB_HTML_Generate_Header_End --
1302  ******
1303  */
1304
1305 void RB_HTML_Generate_Header_End(
1306     FILE *dest_doc,
1307     struct RB_header *cur_header )
1308 {
1309     USE( cur_header );
1310     fprintf( dest_doc, "\n" );
1311 }
1312
1313
1314 /****f* HTML_Generator/RB_HTML_Generate_IndexMenu
1315  * FUNCTION
1316  *   Generates a menu to jump to the various master index files for
1317  *   the various header types.  The menu is generated for each of the
1318  *   master index files.  The current header type is highlighted.
1319  * SYNOPSIS
1320  */
1321 void RB_HTML_Generate_IndexMenu(
1322     FILE *dest_doc,
1323     char *filename,
1324     struct RB_Document *document,
1325     struct RB_HeaderType *cur_type )
1326     /* TODO  Use cur_type */
1327 /*
1328  * INPUTS
1329  *   * dest_doc       -- the output file.
1330  *   * filename       -- the name of the output file
1331  *   * document       -- the gathered documention.
1332  *   * cur_headertype -- the header type that is to be highlighted.
1333  ******
1334  */
1335 {
1336     unsigned char       type_char;
1337     char               *toc_index_path = NULL;
1338
1339     USE( cur_type );            /* TODO FS make use of this */
1340     assert( dest_doc );
1341     assert( filename );
1342     assert( document );
1343
1344     toc_index_path = HTML_TOC_Index_Filename( document );
1345     RB_HTML_Generate_Link( dest_doc,
1346                            filename,
1347                            toc_index_path,
1348                            "top", "Table of Contents", "menuitem" );
1349     free( toc_index_path );
1350     fprintf( dest_doc, "\n" );
1351
1352     for ( type_char = MIN_HEADER_TYPE;
1353           type_char < MAX_HEADER_TYPE; ++type_char )
1354     {
1355         struct RB_HeaderType *header_type;
1356         int                 n;
1357
1358         header_type = RB_FindHeaderType( type_char );
1359         if ( header_type )
1360         {
1361             n = RB_Number_Of_Links( header_type, NULL, FALSE ) +
1362                 RB_Number_Of_Links( header_type, NULL, TRUE );
1363
1364             if ( n )
1365             {
1366                 char               *targetfilename = 0;
1367
1368                 targetfilename =
1369                     RB_Get_SubIndex_FileName( document->docroot->name,
1370                                               document->extension,
1371                                               header_type );
1372                 assert( targetfilename );
1373
1374                 RB_HTML_Generate_Link( dest_doc,
1375                                        filename,
1376                                        targetfilename,
1377                                        "top",
1378                                        header_type->indexName, "menuitem" );
1379                 free( targetfilename );
1380                 fprintf( dest_doc, "\n" );
1381             }
1382         }
1383     }
1384 }
1385
1386 /****f* HTML_Generator/RB_HTML_Generate_Header_IndexMenu
1387  * FUNCTION
1388  *   Generates a menu to jump to the header's entries.  The menu is
1389  *   generated for each entry file.
1390  * SYNOPSIS
1391  */
1392 void RB_HTML_Generate_Header_IndexMenu(
1393     FILE *dest_doc,
1394     char *filename,
1395     struct RB_Document *document,
1396     struct RB_Part *owner,
1397     struct RB_HeaderType *cur_type )
1398     /* TODO  Use cur_type */
1399 /*
1400  * INPUTS
1401  *   * dest_doc       -- the output file.
1402  *   * filename       -- the name of the output file
1403  *   * document       -- the gathered documention.
1404  *   * cur_headertype -- the header type that is to be highlighted.
1405  ******
1406  */
1407 {
1408     struct RB_header *header;
1409     char *object_name, *label_name, *file_name;
1410     int i, j;
1411
1412     for ( i = document->no_headers - 1; i >= 0; i-- )
1413     {
1414         header = document->headers[i];
1415
1416         if ( !strcmp( owner->filename->name, header->owner->filename->name ) &&
1417              ( header->htype->typeCharacter == 'h' ||
1418                Find_Link( header->function_name,
1419                           &object_name, &label_name,
1420                           &file_name ) ) )
1421         {
1422             for ( j = 0; j < header->no_names; j++ )
1423             {
1424                 if ( header->htype->typeCharacter == 'h' )
1425                 {
1426                     RB_HTML_Generate_Link( dest_doc,
1427                                            filename,
1428                                            header->owner->filename->docname,
1429                                            NULL,
1430                                            header->function_name,
1431                                            "menuitem" );
1432                     fprintf( dest_doc, "\n" );
1433                 }
1434                 else
1435                 {
1436                     RB_HTML_Generate_Link( dest_doc,
1437                                            filename,
1438                                            file_name,
1439                                            "",
1440                                            object_name,
1441                                            "menuitem" );
1442                     fprintf( dest_doc, "\n" );
1443                 }
1444             }
1445         }
1446     }
1447 }
1448
1449 /****f* HTML_Generator/RB_HTML_Generate_Module_IndexMenu
1450  * FUNCTION
1451  *   Generates a menu to jump to the different modules.  The menu is
1452  *   generated for each header file.
1453  * SYNOPSIS
1454  */
1455 void RB_HTML_Generate_Module_IndexMenu(
1456     FILE *dest_doc,
1457     char *filename,
1458     struct RB_Document *document,
1459     struct RB_HeaderType *cur_type )
1460     /* TODO  Use cur_type */
1461 /*
1462  * INPUTS
1463  *   * dest_doc       -- the output file.
1464  *   * filename       -- the name of the output file
1465  *   * document       -- the gathered documention.
1466  *   * cur_headertype -- the header type that is to be highlighted.
1467  ******
1468  */
1469 {
1470     struct RB_Part *i_part;
1471
1472     for ( i_part = document->parts; i_part != NULL; i_part = i_part->next )
1473     {
1474       if ( !i_part->headers ||
1475            i_part->headers[0].htype->typeCharacter != 'h' ||
1476            !strcmp(i_part->headers[0].function_name,
1477                    "ROBODoc Cascading Style Sheet") )
1478             continue;
1479         RB_HTML_Generate_Link( dest_doc,
1480                                filename,
1481                                i_part->filename->docname,
1482                                NULL,
1483                                i_part->headers[0].function_name,
1484                                "menuitem" );
1485         fprintf( dest_doc, "\n" );
1486     }
1487 }
1488
1489
1490 /****f* HTML_Generator/RB_HTML_Generate_Index_Page
1491  * FUNCTION
1492  *   Generate a single file with a index table for headers
1493  *   of one specific type of headers
1494  * SYNOPSIS
1495  */
1496 void RB_HTML_Generate_Index_Page(
1497     struct RB_Document *document,
1498     struct RB_HeaderType *header_type )
1499 /*
1500  * INPUTS
1501  *   o document    -- the document
1502  *   o header_type -- the type for which the table is to
1503  *                    be generated.
1504  ******
1505  */
1506 {
1507     char               *filename = 0;
1508     FILE               *file;
1509
1510     assert( document );
1511     assert( header_type );
1512
1513     filename = RB_Get_SubIndex_FileName( document->docroot->name,
1514                                          document->extension, header_type );
1515     assert( filename );
1516
1517     file = fopen( filename, "w" );
1518     if ( !file )
1519     {
1520         RB_Panic( "can't open (%s)!\n", filename );
1521     }
1522     else
1523     {
1524         /* File opened, now we generate an index
1525          * for the specified header type
1526          */
1527         RB_HTML_Generate_Doc_Start( file,
1528                                     document->srcroot->name,
1529                                     header_type->indexName,
1530                                     filename, document->charset );
1531
1532         /* breadcrumbtrail */
1533         HTML_Generate_Begin_Extra( file );
1534         /* No content for extra section yet... */
1535         HTML_Generate_End_Extra( file );
1536
1537         /* Menu for navigation */
1538         HTML_Generate_Begin_Navigation( file );
1539         RB_HTML_Generate_IndexMenu( file, filename, document, header_type );
1540         HTML_Generate_End_Navigation( file );
1541
1542         /* Content */
1543         HTML_Generate_Begin_Content( file );
1544         if ( RB_CompareHeaderTypes
1545              ( header_type, RB_FindHeaderType( HT_SOURCEHEADERTYPE ) )
1546              && ( header_type->typeCharacter != HT_MASTERINDEXTYPE ) )
1547         {
1548             RB_HTML_Generate_Source_Tree( file, filename, document );
1549         }
1550         else
1551         {
1552             RB_HTML_Generate_Index_Table( file,
1553                                           filename,
1554                                           header_type,
1555                                           header_type->indexName );
1556         }
1557         HTML_Generate_End_Content( file );
1558         RB_HTML_Generate_Doc_End( file, filename, document->srcroot->name );
1559         fclose( file );
1560     }
1561
1562     free( filename );
1563 }
1564
1565
1566 /* Create an index page that contains only the table of content */
1567
1568 void HTML_Generate_TOC_Index_Page(
1569     struct RB_Document *document )
1570 {
1571     FILE               *file = NULL;
1572     char               *toc_index_path = HTML_TOC_Index_Filename( document );
1573
1574     file = fopen( toc_index_path, "w" );
1575     if ( !file )
1576     {
1577         RB_Panic( "can't open (%s)!\n", toc_index_path );
1578     }
1579     else
1580     {
1581         RB_HTML_Generate_Doc_Start( file, document->srcroot->name,
1582                                     "Table of Contents",
1583                                     toc_index_path, document->charset );
1584
1585         /* breadcrumbtrail */
1586         HTML_Generate_Begin_Extra( file );
1587         /* No content for extra section yet... */
1588         HTML_Generate_End_Extra( file );
1589
1590         /* Menu for navigation */
1591         HTML_Generate_Begin_Navigation( file );
1592         RB_HTML_Generate_IndexMenu( file, toc_index_path, document, NULL );
1593         HTML_Generate_End_Navigation( file );
1594
1595         /* Content */
1596         HTML_Generate_Begin_Content( file );
1597         RB_Generate_TOC_2( file, document->headers,
1598                            document->no_headers, NULL, toc_index_path );
1599         HTML_Generate_End_Content( file );
1600
1601         /* End part */
1602         RB_HTML_Generate_Doc_End( file, toc_index_path,
1603                                   document->srcroot->name );
1604         fclose( file );
1605     }
1606
1607     free( toc_index_path );
1608 }
1609
1610
1611
1612
1613
1614 /* TODO */
1615 /*x**if* HTML_Generator/RB_HTML_Generate_Index
1616  * NAME
1617  *   RB_HTML_Generate_Index --
1618  ******
1619  */
1620
1621
1622 /* Should be called indexes */
1623 void RB_HTML_Generate_Index(
1624     struct RB_Document *document )
1625 {
1626     unsigned char       type_char = 0;
1627
1628     assert( document );
1629
1630     for ( type_char = MIN_HEADER_TYPE;
1631           type_char < MAX_HEADER_TYPE; ++type_char )
1632     {
1633         struct RB_HeaderType *header_type;
1634         int                 n;
1635
1636         header_type = RB_FindHeaderType( type_char );
1637         if ( header_type )
1638         {
1639             n = RB_Number_Of_Links( header_type, NULL, FALSE ) +
1640                 RB_Number_Of_Links( header_type, NULL, TRUE );
1641             if ( n )
1642             {
1643                 /* There are headers of this type, so create an index page
1644                  * for them
1645                  */
1646                 RB_HTML_Generate_Index_Page( document, header_type );
1647             }
1648         }
1649     }
1650
1651     RB_HTML_Generate_Index_Page( document,
1652                                  RB_FindHeaderType( HT_MASTERINDEXTYPE ) );
1653
1654     HTML_Generate_TOC_Index_Page( document );
1655 }
1656
1657
1658
1659
1660
1661
1662 void RB_HTML_Generate_Table_Body(
1663     FILE *dest,
1664     char *dest_name,
1665     struct RB_HeaderType *type,
1666     int internal )
1667 {
1668     struct RB_link     *cur_link;
1669     unsigned int        i;
1670     char                first_char = ' ';
1671     int                 found = FALSE;
1672
1673     /* Compute the number of columns we need for
1674      * this type of header.
1675      */
1676     for ( i = 0; i < link_index_size; ++i )
1677     {
1678         cur_link = link_index[i];
1679         if ( cur_link->htype &&
1680              RB_CompareHeaderTypes( cur_link->htype, type ) &&
1681              ( ( cur_link->is_internal && internal ) ||
1682                ( !cur_link->is_internal && !internal ) ) )
1683         {
1684             char               *r = 0;
1685
1686             r = RB_HTML_RelativeAddress( dest_name, cur_link->file_name );
1687             if ( toupper( cur_link->object_name[0] ) != first_char )
1688             {
1689                 first_char = toupper( cur_link->object_name[0] );
1690                 if ( found )
1691                 {
1692 //                    fprintf( dest, "</div>\n" );
1693                 }
1694                 fprintf( dest, "<h2><a name=\"%c\"></a>", first_char );
1695                 RB_HTML_Generate_Char( dest, first_char );
1696                 fprintf( dest, "</h2>" );
1697 //              fprintf( dest, "<div class=\"indexitem\">\n" );
1698                 found = TRUE;
1699             }
1700             fprintf( dest, "<a href=\"%s#%s\" class=\"indexitem\" >", r,
1701                      cur_link->label_name );
1702             RB_HTML_Generate_String( dest, cur_link->object_name );
1703             fprintf( dest, "</a>\n" );
1704         }
1705     }
1706     if ( found )
1707     {
1708 //        fprintf( dest, "</div>\n" );
1709     }
1710 }
1711
1712
1713 /****if* HTML_Generator/RB_HTML_Generate_Index_Shortcuts
1714  * NAME
1715  *   RB_HTML_Generate_Index_Shortcuts
1716  * FUNCTION
1717  *   Generates alphabetic shortcuts to index entries.
1718  * SYNOPSIS
1719  */
1720 static void RB_HTML_Generate_Index_Shortcuts(
1721     FILE *dest )
1722 /*
1723  * INPUTS
1724  *   o dest        -- the file to write to
1725  * TODO
1726  *   - Only list used letters.
1727  *   - List all letters (accented, signs, etc), not just the common ones.
1728  *   - Should be better to implement it as a <div> ?
1729  * SOURCE
1730  */
1731 {
1732     unsigned char       c;
1733
1734     fprintf( dest, "<h2>" );
1735
1736     // Generate A - Z
1737     for ( c = 'A'; c <= 'Z'; c++ )
1738     {
1739         fprintf( dest, "<a href=\"#%c\">", c );
1740         RB_HTML_Generate_Char( dest, c );
1741         fprintf( dest, "</a> - " );
1742     }
1743
1744     // Generate 0 - 9
1745     for ( c = '0'; c <= '9'; c++ )
1746     {
1747         fprintf( dest, "<a href=\"#%c\">", c );
1748         RB_HTML_Generate_Char( dest, c );
1749         fprintf( dest, "</a>" );
1750
1751         // Do not generate separator for the last char
1752         if ( c != '9' )
1753         {
1754             fprintf( dest, " - " );
1755         }
1756     }
1757
1758     fprintf( dest, "</h2>\n" );
1759 }
1760
1761 /********/
1762
1763 /****if* HTML_Generator/RB_HTML_Generate_Index_Table
1764  * NAME
1765  *   RB_HTML_Generate_Index_Table --
1766  * FUNCTION
1767  *   Create a HTML TABLE containing links to headers of a particular
1768  *   type.  This creates two tables, a table for normal headers as
1769  *   well as one for internal headers.
1770  * SYNOPSIS
1771  */
1772 void RB_HTML_Generate_Index_Table(
1773     FILE *dest,
1774     char *dest_name,
1775     struct RB_HeaderType *type,
1776     char *title )
1777 /*
1778  * INPUTS
1779  *   o dest        -- the file in which to write the table
1780  *   o dest_name   -- the name of this file
1781  *   o type        -- the type of header for which to generate
1782  *                    the table
1783  *   o title       -- the title of the table.
1784  * SOURCE
1785  */
1786 {
1787     /* Compute the number of columns we need for
1788      * this type of header.
1789      */
1790
1791     // Generate Index Title
1792     fprintf( dest, "<h1>" );
1793     RB_HTML_Generate_String( dest, title );
1794     fprintf( dest, "</h1>\n" );
1795
1796     // Generate Shortcuts at the begining
1797     RB_HTML_Generate_Index_Shortcuts( dest );
1798
1799     if ( RB_Number_Of_Links( type, NULL, FALSE ) )
1800     {
1801         if ( RB_Number_Of_Links( type, NULL, TRUE ) )
1802         {
1803             /* only print a title if there are two tables. */
1804             fprintf( dest, "<h2>Normal</h2>" );
1805         }
1806         RB_HTML_Generate_Table_Body( dest, dest_name, type, FALSE );
1807     }
1808
1809     if ( RB_Number_Of_Links( type, NULL, TRUE ) )
1810     {
1811         /* Always print the  Internal title, since
1812          * these headers are special and the user should know
1813          * he is looking at something special.
1814          */
1815         fprintf( dest, "<h2>Internal</h2>" );
1816         RB_HTML_Generate_Table_Body( dest, dest_name, type, TRUE );
1817     }
1818
1819     // Generate Shortcuts at the end
1820     RB_HTML_Generate_Index_Shortcuts( dest );
1821 }
1822
1823 /********/
1824
1825
1826
1827 /* TODO */
1828 /*x**if* HTML_Generator/RB_HTML_Generate_Empty_Item
1829  * NAME
1830  *   RB_HTML_Generate_Empty_Item --
1831  ******
1832  */
1833
1834 void RB_HTML_Generate_Empty_Item(
1835     FILE *dest_doc )
1836 {
1837     fprintf( dest_doc, "<br>\n" );
1838 }
1839
1840
1841
1842
1843 /****f* HTML_Generator/RB_HTML_Generate_Link
1844  * NAME
1845  *   RB_HTML_Generate_Link --
1846  * SYNOPSIS
1847  */
1848 void RB_HTML_Generate_Link(
1849     FILE *cur_doc,
1850     char *cur_name,
1851     char *filename,
1852     char *labelname,
1853     char *linkname,
1854     char *classname )
1855 /*
1856  * INPUTS
1857  *   cur_doc  --  the file to which the text is written
1858  *   cur_name --  the name of the destination file
1859  *                (the file from which we link)
1860  *   filename --  the name of the file that contains the link
1861  *                (the file we link to)
1862  *   labelname--  the name of the unique label of the link.
1863  *   linkname --  the name of the link as shown to the user.
1864  * SOURCE
1865  */
1866 {
1867     if ( classname )
1868     {
1869         fprintf( cur_doc, "<a class=\"%s\" ", classname );
1870     }
1871     else
1872     {
1873         fprintf( cur_doc, "<a " );
1874     }
1875     if ( filename && strcmp( filename, cur_name ) && labelname)
1876     {
1877         char               *r = RB_HTML_RelativeAddress( cur_name, filename );
1878
1879         fprintf( cur_doc, "href=\"%s#%s\">", r, labelname );
1880         RB_HTML_Generate_String( cur_doc, linkname );
1881         fprintf( cur_doc, "</a>" );
1882     }
1883     else if (labelname)
1884     {
1885         fprintf( cur_doc, "href=\"#%s\">", labelname );
1886         RB_HTML_Generate_String( cur_doc, linkname );
1887         fprintf( cur_doc, "</a>" );
1888     }
1889     else
1890     {
1891         fprintf( cur_doc, "href=\"%s\">", filename);
1892         RB_HTML_Generate_String( cur_doc, linkname );
1893         fprintf( cur_doc, "</a>" );
1894     }
1895 }
1896
1897 /******/
1898
1899
1900 /****f* HTML_Generator/RB_HTML_RelativeAddress
1901  * FUNCTION
1902  *   Link to 'that' from 'this' computing the relative path.  Here
1903  *   'this' and 'that' are both paths.  This function is used to
1904  *   create links from one document to another document that might be
1905  *   in a completely different directory.
1906  * SYNOPSIS
1907  */
1908 char               *RB_HTML_RelativeAddress(
1909     char *thisname,
1910     char *thatname )
1911 /*
1912  * EXAMPLE
1913  *   The following two
1914  *     this /sub1/sub2/sub3/f.html
1915  *     that /sub1/sub2/g.html
1916  *   result in
1917  *     ../g.html
1918  *
1919  *     this /sub1/f.html
1920  *     that /sub1/sub2/g.html
1921  *     ==
1922  *     ./sub2/g.html
1923  *
1924  *     this /sub1/f.html
1925  *     that /sub1/g.html
1926  *     ==
1927  *     ./g.html
1928  *
1929  *     this /sub1/doc3/doc1/tt.html
1930  *     that /sub1/doc5/doc2/qq.html
1931  *     ==
1932  *     ../../doc5/doc2/qq.html
1933  *
1934  * NOTES
1935  *   Notice the execelent docmentation.
1936  * SOURCE
1937  */
1938 #define MAX_RELATIVE_SIZE 1024
1939 {
1940     static char         relative[MAX_RELATIVE_SIZE + 1];
1941     char               *i_this;
1942     char               *i_that;
1943     char               *i_this_slash = NULL;
1944     char               *i_that_slash = NULL;
1945
1946     relative[0] = '\0';
1947
1948     assert( thisname );
1949     assert( thatname );
1950
1951     for ( i_this = thisname, i_that = thatname;
1952           ( *i_this && *i_that ) && ( *i_this == *i_that );
1953           ++i_this, ++i_that )
1954     {
1955         if ( *i_this == '/' )
1956         {
1957             i_this_slash = i_this;
1958         }
1959         if ( *i_that == '/' )
1960         {
1961             i_that_slash = i_that;
1962         }
1963     }
1964
1965     if ( i_this_slash && i_that_slash )
1966     {
1967         int                 this_slashes_left = 0;
1968         int                 that_slashes_left = 0;
1969         char               *i_c;
1970
1971         for ( i_c = i_this_slash + 1; *i_c; ++i_c )
1972         {
1973             if ( *i_c == '/' )
1974             {
1975                 ++this_slashes_left;
1976             }
1977         }
1978
1979         for ( i_c = i_that_slash + 1; *i_c; ++i_c )
1980         {
1981             if ( *i_c == '/' )
1982             {
1983                 ++that_slashes_left;
1984             }
1985         }
1986
1987         if ( this_slashes_left )
1988         {
1989             int                 i;
1990
1991             for ( i = 0; i < this_slashes_left; ++i )
1992             {
1993                 strcat( relative, "../" );
1994             }
1995             strcat( relative, i_that_slash + 1 );
1996         }
1997         else if ( that_slashes_left )
1998         {
1999             /* !this_slashes_left && that_slashes_left */
2000             strcat( relative, "./" );
2001             strcat( relative, i_that_slash + 1 );
2002         }
2003         else
2004         {
2005             /* !this_slashes_left && !that_slashes_left */
2006             strcat( relative, "./" );
2007             strcat( relative, i_that_slash + 1 );
2008         }
2009     }
2010     return relative;
2011 }
2012
2013 /******/
2014
2015
2016
2017 /****f* HTML_Generator/RB_HTML_Generate_Char
2018  * NAME
2019  *   RB_HTML_Generate_Char -- generate a single character for an item.
2020  * SYNOPSIS
2021  */
2022 void RB_HTML_Generate_Char(
2023     FILE *dest_doc,
2024     int c )
2025 /*
2026  * FUNCTION
2027  *   This function is called for every character that goes
2028  *   into an item's body.  This escapes all the reserved
2029  *   HTML characters such as '&', '<', '>', '"'.
2030  * SOURCE
2031  */
2032 {
2033     switch ( c )
2034     {
2035     case '\n':
2036         assert( 0 );
2037         break;
2038     case '\t':
2039         assert( 0 );
2040         break;
2041     case '<':
2042         fprintf( dest_doc, "&lt;" );
2043         break;
2044     case '>':
2045         fprintf( dest_doc, "&gt;" );
2046         break;
2047     case '&':
2048         fprintf( dest_doc, "&amp;" );
2049         break;
2050     default:
2051         // All others are printed literally
2052         fputc( c, dest_doc );
2053     }
2054 }
2055
2056 /*******/
2057
2058
2059 void HTML_Generate_Begin_Content(
2060     FILE *dest_doc )
2061 {
2062     HTML_Generate_Div( dest_doc, "content" );
2063 }
2064
2065 void HTML_Generate_End_Content(
2066     FILE *dest_doc )
2067 {
2068     HTML_Generate_Div_End( dest_doc, "content" );
2069 }
2070
2071 void HTML_Generate_Begin_Navigation(
2072     FILE *dest_doc )
2073 {
2074     HTML_Generate_Div( dest_doc, "navigation" );
2075 }
2076
2077 void HTML_Generate_End_Navigation(
2078     FILE *dest_doc )
2079 {
2080
2081     HTML_Generate_Div_End( dest_doc, "navigation" );
2082 }
2083
2084 void HTML_Generate_Begin_Extra(
2085     FILE *dest_doc )
2086 {
2087     HTML_Generate_Div( dest_doc, "extra" );
2088 }
2089
2090 void HTML_Generate_End_Extra(
2091     FILE *dest_doc )
2092 {
2093     HTML_Generate_Div_End( dest_doc, "extra" );
2094 }
2095
2096
2097
2098
2099 /****f* HTML_Generator/RB_Create_CSS
2100  * FUNCTION
2101  *   Create the .css file.  Unless the user specified it's own css
2102  *   file robodoc creates a default one.
2103  *
2104  *   For multidoc mode the name of the .css file is
2105  *      robodoc.css
2106  *   For singledoc mode the name of the .css file is equal
2107  *   to the name of the documentation file.
2108  * SYNOPSIS
2109  */
2110 void RB_Create_CSS(
2111     struct RB_Document *document )
2112 /*
2113  * INPUTS
2114  *   o document -- the document for which to create the file.
2115  * SOURCE
2116  */
2117 {
2118     size_t              l = 0;
2119     FILE               *css_file;
2120
2121     /* compute the complete path to the css file */
2122     if ( ( document->actions.do_singledoc ) ||
2123          ( document->actions.do_singlefile ) )
2124     {
2125         char               *extension = ".css";
2126
2127         l += strlen( document->singledoc_name );
2128         l += strlen( extension );
2129         ++l;
2130         css_name = malloc( l );
2131         strcpy( css_name, document->singledoc_name );
2132         strcat( css_name, extension );
2133     }
2134     else
2135     {
2136         struct RB_Path     *docroot = document->docroot;
2137         char               *docrootname = docroot->name;
2138         char               *filename = "robodoc.css";
2139
2140         l = strlen( filename );
2141         l += strlen( docrootname );
2142         ++l;
2143         css_name = malloc( l );
2144         strcpy( css_name, docrootname );
2145         strcat( css_name, filename );
2146     }
2147
2148     RB_Say( "Creating CSS file %s\n", SAY_DEBUG, css_name );
2149     if ( document->css )
2150     {
2151         /* The user specified its own css file,
2152          * so we use the content of that.
2153          */
2154         RB_CopyFile( document->css, css_name );
2155     }
2156     else
2157     {
2158         css_file = fopen( css_name, "w" );
2159         if ( css_file )
2160         {
2161                     /** BEGIN BEGIN BEGIN Don't remove */
2162             fprintf( css_file,
2163                      "/****h* ROBODoc/ROBODoc Cascading Style Sheet\n"
2164                      " * FUNCTION\n"
2165                      " *   This is the default cascading style sheet for documentation\n"
2166                      " *   generated with ROBODoc.\n"
2167                      " *   You can edit this file to your own liking and then use\n"
2168                      " *   it with the option\n"
2169                      " *      --css <filename>\n"
2170                      " *\n"
2171                      " *   This style-sheet defines the following layout\n"
2172                      " *      +----------------------------------------+\n"
2173                      " *      |    logo                                |\n"
2174                      " *      +----------------------------------------+\n"
2175                      " *      |    extra                               |\n"
2176                      " *      +----------------------------------------+\n"
2177                      " *      |                              | navi-   |\n"
2178                      " *      |                              | gation  |\n"
2179                      " *      |      content                 |         |\n"
2180                      " *      |                              |         |\n"
2181                      " *      +----------------------------------------+\n"
2182                      " *      |    footer                              |\n"
2183                      " *      +----------------------------------------+\n"
2184                      " *\n"
2185                      " *   This style-sheet is based on a style-sheet that was automatically\n"
2186                      " *   generated with the Strange Banana stylesheet generator.\n"
2187                      " *   See http://www.strangebanana.com/generator.aspx\n"
2188                      " *\n"
2189                      " ******\n"
2190                      " * $Id: html_generator.c,v 1.91 2007/07/10 19:13:51 gumpu Exp $\n"
2191                      " */\n"
2192                      "\n"
2193                      "body\n"
2194                      "{\n"
2195                      "    background-color:    rgb(255,255,255);\n"
2196                      "    color:               rgb(98,84,55);\n"
2197                      "    font-family:         Arial, serif;\n"
2198                      "    border-color:        rgb(226,199,143);\n"
2199                      "}\n"
2200                      "\n"
2201                      "pre\n"
2202                      "{\n"
2203                      "    font-family:      monospace;\n"
2204                      "    margin:      15px;\n"
2205                      "    padding:     5px;\n"
2206                      "    white-space: pre;\n"
2207                      "    color:       #000;\n"
2208                      "}\n"
2209                      "\n"
2210                      "pre.source\n"
2211                      "{\n"
2212                      "    background-color: #ffe;\n"
2213                      "    border: dashed #aa9 1px;\n"
2214                      "}\n"
2215                      "\n"
2216                      "p\n"
2217                      "{\n"
2218                      "    margin:15px;\n"
2219                      "}\n"
2220                      "\n"
2221                      "p.item_name \n"
2222                      "{\n"
2223                      "    font-weight: bolder;\n"
2224                      "    margin:5px;\n"
2225                      "    font-size: 120%%;\n"
2226                      "}\n"
2227                      "\n"
2228                      "#content\n" "{\n" "    font-size:           100%%;\n" );
2229             fprintf( css_file,
2230                      "    color:               rgb(0,0,0);\n"
2231                      "    background-color:    rgb(255,255,255);\n"
2232                      "    border-left-width:   0px; \n"
2233                      "    border-right-width:  0px; \n"
2234                      "    border-top-width:    0px; \n"
2235                      "    border-bottom-width: 0px;\n"
2236                      "    border-left-style:   none; \n"
2237                      "    border-right-style:  none; \n"
2238                      "    border-top-style:    none; \n"
2239                      "    border-bottom-style: none;\n"
2240                      "    padding:             40px 31px 14px 17px;\n"
2241                      "    border-color:        rgb(0,0,0);\n"
2242                      "    text-align:          justify;\n"
2243                      "}\n"
2244                      "\n"
2245                      "#navigation\n"
2246                      "{\n"
2247                      "    background-color: rgb(98,84,55);\n"
2248                      "    color:            rgb(230,221,202);\n"
2249                      "    font-family:      \"Times New Roman\", serif;\n"
2250                      "    font-style:       normal;\n"
2251                      "    border-color:     rgb(0,0,0);\n"
2252                      "}\n"
2253                      "\n"
2254                      "a.menuitem\n"
2255                      "{\n"
2256                      "    font-size: 120%%;\n"
2257                      "    background-color:    rgb(0,0,0);\n"
2258                      "    color:               rgb(195,165,100);\n"
2259                      "    font-variant:        normal;\n"
2260                      "    text-transform:      none;\n"
2261                      "    font-weight:         normal;\n"
2262                      "    padding:             1px 8px 3px 1px;\n"
2263                      "    margin-left:         5px; \n"
2264                      "    margin-right:        5px; \n"
2265                      "    margin-top:          5px; \n"
2266                      "    margin-bottom:       5px;\n"
2267                      "    border-color:        rgb(159,126,57);\n"
2268                      "    text-align:          right;\n"
2269                      "}\n"
2270                      "\n"
2271                      "#logo, #logo a\n"
2272                      "{\n"
2273                      "    font-size: 130%%;\n"
2274                      "    background-color:   rgb(198,178,135);\n"
2275                      "    color:              rgb(98,84,55);\n"
2276                      "    font-family:        Georgia, serif;\n"
2277                      "    font-style:         normal;\n"
2278                      "    font-variant:       normal;\n"
2279                      "    text-transform:     none;\n"
2280                      "    font-weight:        bold;\n"
2281                      "    padding:            20px 18px 20px 18px;\n"
2282                      "    border-color:       rgb(255,255,255);\n"
2283                      "    text-align:         right;\n"
2284                      "}\n"
2285                      "\n"
2286                      "#extra, #extra a\n"
2287                      "{\n"
2288                      "    font-size: 128%%;\n"
2289                      "    background-color:    rgb(0,0,0);\n"
2290                      "    color:               rgb(230,221,202);\n"
2291                      "    font-style:          normal;\n"
2292                      "    font-variant:        normal;\n"
2293                      "    text-transform:      none;\n"
2294                      "    font-weight:         normal;\n" );
2295             fprintf( css_file,
2296                      "    border-left-width:   0px; \n"
2297                      "    border-right-width:  0px; \n"
2298                      "    border-top-width:    0px; \n"
2299                      "    border-bottom-width: 0px;\n"
2300                      "    border-left-style:   none; \n"
2301                      "    border-right-style:  none; \n"
2302                      "    border-top-style:    none; \n"
2303                      "    border-bottom-style: none;\n"
2304                      "    padding: 12px 12px 12px 12px;\n"
2305                      "    border-color:        rgb(195,165,100);\n"
2306                      "    text-align:          center;\n"
2307                      "}\n"
2308                      "\n"
2309                      "#content a\n"
2310                      "{\n"
2311                      "    color:              rgb(159,126,57);\n"
2312                      "    text-decoration:    none;\n"
2313                      "}\n"
2314                      "\n"
2315                      "#content a:hover, #content a:active\n"
2316                      "{\n"
2317                      "    color:              rgb(255,255,255);\n"
2318                      "    background-color:   rgb(159,126,57);\n"
2319                      "}\n"
2320                      "\n"
2321                      "a.indexitem\n"
2322                      "{\n"
2323                      "    display: block;\n"
2324                      "}\n"
2325                      "\n"
2326                      "h1, h2, h3, h4, h5, h6\n"
2327                      "{\n"
2328                      "    background-color: rgb(221,221,221);\n"
2329                      "    font-family:      Arial, serif;\n"
2330                      "    font-style:       normal;\n"
2331                      "    font-variant:     normal;\n"
2332                      "    text-transform:   none;\n"
2333                      "    font-weight:      normal;\n"
2334                      "}\n"
2335                      "\n"
2336                      "h1\n"
2337                      "{\n"
2338                      "    font-size: 151%%;\n"
2339                      "}\n"
2340                      "\n"
2341                      "h2\n"
2342                      "{\n"
2343                      "    font-size: 142%%;\n"
2344                      "}\n"
2345                      "\n"
2346                      "h3\n"
2347                      "{\n"
2348                      "    font-size: 133%%;\n"
2349                      "}\n"
2350                      "\n"
2351                      "h4\n"
2352                      "{\n"
2353                      "    font-size: 124%%;\n"
2354                      "}\n"
2355                      "\n"
2356                      "h5\n"
2357                      "{\n"
2358                      "    font-size: 115%%;\n"
2359                      "}\n"
2360                      "\n"
2361                      "h6\n"
2362                      "{\n"
2363                      "    font-size: 106%%;\n"
2364                      "}\n"
2365                      "\n"
2366                      "#navigation a\n"
2367                      "{\n"
2368                      "    text-decoration: none;\n"
2369                      "}\n"
2370                      "\n"
2371                      ".menuitem:hover\n"
2372                      "{\n"
2373                      "    background-color:   rgb(195,165,100);\n"
2374                      "    color:              rgb(0,0,0);\n"
2375                      "}\n"
2376                      "\n"
2377                      "#extra a\n"
2378                      "{\n"
2379                      "    text-decoration: none;\n"
2380                      "}\n"
2381                      "\n"
2382                      "#logo a\n"
2383                      "{\n"
2384                      "    text-decoration: none;\n"
2385                      "}\n"
2386                      "\n"
2387                      "#extra a:hover\n"
2388                      "{\n"
2389                      "}\n"
2390                      "\n"
2391                      "/* layout */\n"
2392                      "#navigation\n"
2393                      "{\n"
2394                      "    width:       22%%; \n"
2395                      "    position:    relative; \n"
2396                      "    top:         0; \n"
2397                      "    right:       0; \n"
2398                      "    float:       right; \n"
2399                      "    text-align:  center;\n"
2400                      "    margin-left: 10px;\n"
2401                      "}\n"
2402                      "\n"
2403                      ".menuitem       {width: auto;}\n"
2404                      "#content        {width: auto;}\n"
2405                      ".menuitem       {display: block;}\n" "\n" "\n" );
2406             fprintf( css_file,
2407                      "div#footer\n"
2408                      "{\n"
2409                      "    background-color: rgb(198,178,135);\n"
2410                      "    color:      rgb(98,84,55);\n"
2411                      "    clear:      left;\n"
2412                      "    width:      100%%;\n"
2413                      "    font-size:   71%%;\n"
2414                      "}\n"
2415                      "\n"
2416                      "div#footer a\n"
2417                      "{\n"
2418                      "    background-color: rgb(198,178,135);\n"
2419                      "    color:            rgb(98,84,55);\n"
2420                      "}\n"
2421                      "\n"
2422                      "div#footer p\n"
2423                      "{\n"
2424                      "    margin:0;\n"
2425                      "    padding:5px 10px\n"
2426                      "}\n"
2427                      "\n"
2428                      "span.keyword\n"
2429                      "{\n"
2430                      "    color: #00F;\n"
2431                      "}\n"
2432                      "\n"
2433                      "span.comment\n"
2434                      "{\n"
2435                      "    color: #080;\n"
2436                      "}\n"
2437                      "\n"
2438                      "span.quote\n"
2439                      "{\n"
2440                      "    color: #F00;\n"
2441                      "}\n"
2442                      "\n"
2443                      "span.squote\n"
2444                      "{\n"
2445                      "    color: #F0F;\n"
2446                      "}\n"
2447                      "\n"
2448                      "span.sign\n"
2449                      "{\n"
2450                      "    color: #008B8B;\n"
2451                      "}\n"
2452                      "\n"
2453                      "\n"
2454                      "@media print\n"
2455                      "{\n"
2456                      "    #navigation {display: none;}\n"
2457                      "    #content    {padding: 0px;}\n"
2458                      "    #content a  {text-decoration: underline;}\n"
2459                      "}\n" );
2460                     /** END END END Don't remove */
2461             fclose( css_file );
2462         }
2463         else
2464         {
2465             RB_Panic( "Can't open %s for writing\n", css_name );
2466         }
2467     }
2468 }
2469
2470 /*******/
2471
2472
2473 void RB_InsertCSS(
2474     FILE *dest_doc,
2475     char *filename )
2476 {
2477     if ( css_name )
2478     {
2479         char               *r = RB_HTML_RelativeAddress( filename, css_name );
2480
2481         assert( r );
2482         assert( strlen( r ) );
2483         fprintf( dest_doc,
2484                  "<link rel=\"stylesheet\" href=\"%s\" type=\"text/css\" />\n",
2485                  r );
2486     }
2487 }
2488
2489
2490
2491 void HTML_Generate_Begin_Paragraph(
2492     FILE *dest_doc )
2493 {
2494     fprintf( dest_doc, "<p>" );
2495 }
2496
2497 void HTML_Generate_End_Paragraph(
2498     FILE *dest_doc )
2499 {
2500     fprintf( dest_doc, "</p>\n" );
2501 }
2502
2503
2504 void HTML_Generate_Begin_Preformatted(
2505     FILE *dest_doc,
2506     int source )
2507 {
2508     // Check if we are preformatting a SOURCE item
2509     if ( source )
2510     {
2511         // SOURCE items have their own class in the CSS
2512         fprintf( dest_doc, "<pre class=\"%s\">", SOURCE_CLASS );
2513     }
2514     else
2515     {
2516         fprintf( dest_doc, "<pre>" );
2517     }
2518 }
2519
2520 void HTML_Generate_End_Preformatted(
2521     FILE *dest_doc )
2522 {
2523     fprintf( dest_doc, "</pre>\n" );
2524 }
2525
2526
2527 void HTML_Generate_Begin_List(
2528     FILE *dest_doc )
2529 {
2530     fprintf( dest_doc, "<ul>" );
2531 }
2532
2533 void HTML_Generate_End_List(
2534     FILE *dest_doc )
2535 {
2536     fprintf( dest_doc, "</ul>\n" );
2537 }
2538
2539 void HTML_Generate_Begin_List_Item(
2540     FILE *dest_doc )
2541 {
2542     fprintf( dest_doc, "<li>" );
2543 }
2544
2545 void HTML_Generate_End_List_Item(
2546     FILE *dest_doc )
2547 {
2548     fprintf( dest_doc, "</li>\n" );
2549 }