145d5e6d2a0178a33de20a10e9300d33adfa471f
[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_2(
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     int                 i, j;
697     int                 depth = 1;
698
699     for ( i = 0; i < MAX_SECTION_DEPTH; ++i )
700     {
701         sectiontoc_counters[i] = 0;
702     }
703     fprintf( dest_doc, "<h3>TABLE OF CONTENTS</h3>\n" );
704     if ( course_of_action.do_sections )
705     {
706         /* --sections was specified, create a TOC based on the
707          * hierarchy of the headers.
708          */
709         fprintf( dest_doc, "<ul>\n" );
710         for ( i = 0; i < count; ++i )
711         {
712             header = headers[i];
713             if ( owner == NULL )
714             {
715                 if ( header->parent )
716                 {
717                     /* Will be done in the subfunction */
718                 }
719                 else
720                 {
721                     RB_HTML_Generate_TOC_Section( dest_doc, dest_name, header,
722                                                   headers, count, depth );
723                 }
724             }
725             else
726             {
727                 /* This is the TOC for a specific RB_Part (MultiDoc
728                  * documentation). We only include the headers that
729                  * are part of the subtree. That is, headers that are
730                  * parth the RB_Part, or that are childern of the
731                  * headers in the RB_Part.
732                  */
733                 if ( header->owner == owner )
734                 {
735                     /* BUG 721690 */
736                     /* Any of the parents of this header should not
737                      * have the same owner as this header, otherwise
738                      * this header will be part of the TOC multiple times.
739                      */
740                     int                 no_bad_parent = TRUE;
741                     struct RB_header   *parent = header->parent;
742
743                     for ( ; parent; parent = parent->parent )
744                     {
745                         if ( parent->owner == owner )
746                         {
747                             no_bad_parent = FALSE;
748                             break;
749                         }
750                     }
751                     if ( no_bad_parent )
752                     {
753                         RB_HTML_Generate_TOC_Section( dest_doc, dest_name,
754                                                       header, headers, count,
755                                                       depth );
756                     }
757                 }
758             }
759         }
760         fprintf( dest_doc, "</ul>\n" );
761     }
762     else
763     {
764         /* No --section option, generate a plain, one-level
765          * TOC
766          */
767         fprintf( dest_doc, "<ul>\n" );
768
769         for ( i = 0; i < count; ++i )
770         {
771             header = headers[i];
772             if ( header->name && header->function_name &&
773                  ( ( owner == NULL ) || ( header->owner == owner ) ) )
774             {
775                 for ( j = 0; j < header->no_names; j++ )
776                 {
777                     fprintf( dest_doc, "<li>" );
778
779                     RB_HTML_Generate_Link( dest_doc, dest_name,
780                                            header->file_name,
781                                            header->unique_name,
782                                            header->names[j], 0 );
783                     fprintf( dest_doc, "</li>\n" );
784                 }
785             }
786         }
787         fprintf( dest_doc, "</ul>\n" );
788     }
789 }
790
791
792
793 /****f* HTML_Generator/RB_HTML_Generate_Label
794  * FUNCTION
795  *   Generate a label (name) that can be refered too.
796  *   A label should consist of only alphanumeric characters so
797  *   all 'odd' characters are replaced with their ASCII code in
798  *   hex format.
799  * SYNOPSIS
800  */
801 void RB_HTML_Generate_Label(
802     FILE *dest_doc,
803     char *name )
804 /*
805  * INPUTS
806  *   o dest_doc -- the file to write it to.
807  *   o name     -- the name of the label.
808  * SOURCE
809  */
810 {
811     int                 i;
812     int                 l = strlen( name );
813     unsigned char       c;
814
815     fprintf( dest_doc, "<a name=\"" );
816     for ( i = 0; i < l; ++i )
817     {
818         c = name[i];
819         if ( utf8_isalnum( c ) )
820         {
821             RB_HTML_Generate_Char( dest_doc, c );
822         }
823         else
824         {
825             char                buf[4];
826
827             sprintf( buf, "%02x", c );
828             RB_HTML_Generate_Char( dest_doc, buf[0] );
829             RB_HTML_Generate_Char( dest_doc, buf[1] );
830         }
831     }
832     fprintf( dest_doc, "\">\n" );
833 }
834
835 /********/
836
837
838
839 static int          section_counters[MAX_SECTION_DEPTH];
840
841
842 /* TODO Documentation */
843
844 void RB_HTML_Generate_BeginSection(
845     FILE *dest_doc,
846     int depth,
847     char *name,
848     struct RB_header *header )
849 {
850     int                 i;
851
852     ++section_counters[depth];
853     for ( i = depth + 1; i < MAX_SECTION_DEPTH; ++i )
854     {
855         section_counters[i] = 0;
856     }
857     switch ( depth )
858     {
859     case 1:
860     case 2:
861     case 3:
862     case 4:
863     case 5:
864     case 6:
865     case 7:
866         fprintf( dest_doc, "<h%d>", depth );
867         // Only generate section numbers if no sectionnameonly
868         if ( !( course_of_action.do_sectionnameonly ) )
869         {
870             for ( i = 1; i <= depth; ++i )
871             {
872                 fprintf( dest_doc, "%d.", section_counters[i] );
873             }
874             fprintf( dest_doc, "  " );
875         }
876
877         // Print Header "first" name
878         RB_HTML_Generate_String( dest_doc, name );
879
880         // Print further names
881         for ( i = 1; i < header->no_names; i++ )
882         {
883             fprintf( dest_doc, ( i % header_breaks ) ? ", " : ",<br />" );
884             RB_HTML_Generate_String( dest_doc, header->names[i] );
885         }
886
887         // Include module name if not sectionnameonly
888         if ( !( course_of_action.do_sectionnameonly ) )
889         {
890             fprintf( dest_doc, " [ " );
891             RB_HTML_Generate_String( dest_doc, header->htype->indexName );
892             fprintf( dest_doc, " ]" );
893         }
894
895         fprintf( dest_doc, "  </h%d>\n", depth );
896         break;
897     default:
898         /* too deep, don't do anything. */
899         assert( 0 );
900     }
901 }
902
903 void RB_HTML_Generate_EndSection(
904     FILE *dest_doc,
905     int depth,
906     char *name )
907 {
908     USE( dest_doc );
909     USE( name );
910     USE( depth );
911     /* Empty */
912 }
913
914
915 char               *RB_HTML_Get_Default_Extension(
916     void )
917 {
918     return ( ".html" );
919 }
920
921 /****f* HTML_Generator/RB_HTML_Generate_Doc_Start
922  * NAME
923  *   RB_HTML_Generate_Doc_Start --
924  * FUNCTION
925  *   Generate the first part of a HTML document.
926  *   As far as ROBODoc is concerned a HTML document
927  *   consists of three parts:
928  *   * The start of a document
929  *   * The body of a document
930  *   * The end of a document
931  * SYNOPSIS
932  */
933 void RB_HTML_Generate_Doc_Start(
934     FILE *dest_doc,
935     char *src_name,
936     char *name,
937     char *dest_name,
938     char *charset )
939 /*
940  * INPUTS
941  *   o dest_doc  --  the output file.
942  *   o src_name  --  The file or directoryname from which 
943  *                   this document is generated.
944  *   o name      --  The title for this document
945  *   o dest_name --  the name of the output file.
946  *   o charset   --  the charset to be used for the file.
947  * SOURCE
948  */
949 {
950
951     if ( course_of_action.do_headless )
952     {
953         /* The user wants a headless document, so we skip everything
954          * upto and until <BODY>
955          */
956     }
957     else
958     {
959         /* Append document type and title */
960         fprintf( dest_doc, "<?xml version=\"1.0\" encoding=\"%s\"?>\n",
961                  charset ? charset : DEFAULT_CHARSET );
962         fprintf( dest_doc,
963                  "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n" );
964         fprintf( dest_doc,
965                  "                      \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" );
966
967         fprintf( dest_doc,
968                  "<html  xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n" );
969         fprintf( dest_doc, "<head>\n" );
970         fprintf( dest_doc,
971                  "<meta http-equiv=\"Content-Style-Type\" content=\"text/css\" />\n" );
972         /* TODO is charset still needed?? */
973         fprintf( dest_doc,
974                  "<meta http-equiv=\"Content-type\" content=\"text/html; charset=%s\" />\n",
975                  charset ? charset : DEFAULT_CHARSET );
976         RB_InsertCSS( dest_doc, dest_name );
977         fprintf( dest_doc, "<title>%s</title>\n", name );
978
979         /* append SGML-comment with document- and copyright-info. This code
980          * ensures that every line has an own comment to avoid problems with
981          * buggy browsers */
982         fprintf( dest_doc, "<!-- Source: %s -->\n", src_name );
983         if ( course_of_action.do_nogenwith )
984         {
985
986         }
987         else
988         {
989             static const char   copyright_text[]
990                 = COMMENT_ROBODOC /* COMMENT_COPYRIGHT */ ;
991             size_t              i = 0;
992             char                previous_char = '\n';
993             char                current_char = copyright_text[i];
994
995             while ( current_char )
996             {
997                 if ( previous_char == '\n' )
998                 {
999                     fprintf( dest_doc, "<!-- " );
1000                 }
1001                 if ( current_char == '\n' )
1002                 {
1003                     fprintf( dest_doc, " -->" );
1004                 }
1005                 else if ( ( current_char == '-' )
1006                           && ( previous_char == '-' ) )
1007                 {
1008                     /* avoid "--" inside SGML-comment, and use "-_" instead; this
1009                      * looks a bit strange, but one should still be able to figure
1010                      * out what is meant when reading the output */
1011                     current_char = '_';
1012                 }
1013                 fputc( current_char, dest_doc );
1014                 i += 1;
1015                 previous_char = current_char;
1016                 current_char = copyright_text[i];
1017             }
1018         }
1019
1020         /* append heading and start list of links to functions */
1021         fprintf( dest_doc, "</head>\n" );
1022         fprintf( dest_doc, "<body>\n" );
1023     }
1024
1025 //    HTML_Generate_Div( dest_doc, "container" );
1026
1027     /* Generate document title if available (Thuffir) */
1028     HTML_Generate_Div( dest_doc, "logo" );
1029     fprintf( dest_doc, "<a name=\"robo_top_of_doc\">" );
1030     if ( document_title )
1031         RB_HTML_Generate_String( dest_doc, document_title );
1032     fprintf( dest_doc, "</a>\n" );
1033     HTML_Generate_Div_End( dest_doc, "logo" );
1034
1035
1036
1037 }
1038
1039 /******/
1040
1041
1042 /* TODO */
1043 /*x**if* HTML_Generator/RB_HTML_Generate_Doc_End
1044  * NAME
1045  *   RB_HTML_Generate_Doc_End --
1046  * FUNCTION
1047  *   Close of the document with the proper end tags.
1048  ******
1049  */
1050
1051 void RB_HTML_Generate_Doc_End(
1052     FILE *dest_doc,
1053     char *name,
1054     char *src_name )
1055 {
1056
1057     USE( name );
1058
1059
1060     HTML_Generate_Div( dest_doc, "footer" );
1061     /* TODO This should be done with
1062      * RB_Generate_Label() 
1063      */
1064     if ( course_of_action.do_nogenwith )
1065     {
1066         fprintf( dest_doc, "<p>Generated from %s on ", src_name );
1067         RB_TimeStamp( dest_doc );
1068         fprintf( dest_doc, "</p>\n" );
1069     }
1070     else
1071     {
1072         fprintf( dest_doc,
1073                  "<p>Generated from %s with <a href=\"http://www.xs4all.nl/~rfsber/Robo/robodoc.html\">ROBODoc</a> V%s on ",
1074                  src_name, VERSION );
1075         RB_TimeStamp( dest_doc );
1076         fprintf( dest_doc, "</p>\n" );
1077     }
1078     HTML_Generate_Div_End( dest_doc, "footer" );
1079
1080 //    HTML_Generate_Div_End( dest_doc, "container" );
1081
1082     if ( course_of_action.do_footless )
1083     {
1084         /* The user does not want the foot of the
1085          * document.
1086          */
1087     }
1088     else
1089     {
1090         fprintf( dest_doc, "</body>\n</html>\n" );
1091     }
1092 }
1093
1094
1095 void RB_HTML_Generate_Nav_Bar(
1096     struct RB_Document *document,
1097     FILE *current_doc,
1098     struct RB_header *current_header )
1099 {
1100     char               *current_filename = NULL;
1101     char               *target_filename = NULL;
1102     char               *label = NULL;
1103     char               *label_name = NULL;
1104
1105     current_filename = RB_Get_FullDocname( current_header->owner->filename );
1106     target_filename = RB_Get_FullDocname( current_header->owner->filename );
1107     label = Get_Fullname( current_header->owner->filename );
1108     /* The navigation bar */
1109     fprintf( current_doc, "<p>" );
1110
1111     // [ Top ]
1112     fprintf( current_doc, "[ " );
1113     RB_HTML_Generate_Link( current_doc, current_filename, NULL,
1114                            "robo_top_of_doc", "Top", 0 );
1115     fprintf( current_doc, " ] " );
1116
1117     // [ "Parentname" ]
1118     if ( current_header->parent )
1119     {
1120         fprintf( current_doc, "[ " );
1121         target_filename =
1122             RB_Get_FullDocname( current_header->parent->owner->filename );
1123         label = current_header->parent->unique_name;
1124         label_name = current_header->parent->function_name;
1125         RB_HTML_Generate_Link( current_doc, current_filename, target_filename,
1126                                label, label_name, 0 );
1127         fprintf( current_doc, " ] " );
1128     }
1129
1130     // [ "Modulename" ]
1131     fprintf( current_doc, "[ " );
1132     label_name = current_header->htype->indexName;
1133     if ( ( course_of_action.do_index ) && ( course_of_action.do_multidoc ) )
1134     {
1135         target_filename = RB_Get_SubIndex_FileName( document->docroot->name,
1136                                                     document->extension,
1137                                                     current_header->htype );
1138         RB_HTML_Generate_Link( current_doc, current_filename, target_filename,
1139                                "robo_top_of_doc", label_name, 0 );
1140         free( target_filename );
1141     }
1142     else
1143     {
1144         RB_HTML_Generate_String( current_doc, label_name );
1145     }
1146     fprintf( current_doc, " ]</p>\n" );
1147 }
1148
1149
1150
1151 /* TODO Documentation */
1152
1153 void RB_HTML_Generate_Nav_Bar_One_File_Per_Header(
1154     struct RB_Document *document,
1155     FILE *current_doc,
1156     struct RB_header *current_header )
1157 {
1158     char               *current_filename = NULL;
1159     char               *target_filename = NULL;
1160     char               *label = NULL;
1161     char               *label_name = NULL;
1162
1163     current_filename = RB_Get_FullDocname( current_header->owner->filename );
1164     target_filename = RB_Get_FullDocname( current_header->owner->filename );
1165     label = Get_Fullname( current_header->owner->filename );
1166     /* The navigation bar */
1167     if ( current_header->parent )
1168     {
1169         target_filename =
1170             RB_Get_FullDocname( current_header->parent->owner->filename );
1171         label = current_header->parent->unique_name;
1172         label_name = current_header->parent->function_name;
1173         RB_HTML_Generate_Link( current_doc, current_filename, target_filename,
1174                                label, label_name, "menuitem" );
1175     }
1176     /* FS TODO  one_file_per_header without   index is not logical */
1177     if ( ( course_of_action.do_index ) && ( course_of_action.do_multidoc ) )
1178     {
1179         target_filename = RB_Get_SubIndex_FileName( document->docroot->name,
1180                                                     document->extension,
1181                                                     current_header->htype );
1182         label_name = current_header->htype->indexName;
1183         RB_HTML_Generate_Link( current_doc, current_filename, target_filename,
1184                                "robo_top_of_doc", label_name, "menuitem" );
1185         free( target_filename );
1186     }
1187 }
1188
1189
1190
1191
1192
1193 /* TODO Documentation */
1194 /*x**if* HTML_Generator/RB_HTML_Generate_Header_Start
1195  * NAME
1196  *   RB_HTML_Generate_Header_Start --
1197  ******
1198  */
1199
1200 void RB_HTML_Generate_Header_Start(
1201     FILE *dest_doc,
1202     struct RB_header *cur_header )
1203 {
1204     struct RB_HeaderType *header_type;
1205     int                 i;
1206
1207     if ( cur_header->name && cur_header->function_name )
1208     {
1209         fprintf( dest_doc, "<hr />\n" );
1210         RB_HTML_Generate_Label( dest_doc, cur_header->name );
1211         fprintf( dest_doc, "</a><a name=\"%s\"></a><h2>",
1212                  cur_header->unique_name );
1213
1214         header_type = RB_FindHeaderType( cur_header->htype->typeCharacter );
1215
1216         for ( i = 1; i <= cur_header->no_names; i++ )
1217         {
1218             // If Section names only, do not print module name
1219             if ( i == 1 && ( course_of_action.do_sectionnameonly ) )
1220                 RB_HTML_Generate_String( dest_doc,
1221                                          cur_header->function_name );
1222             else
1223                 RB_HTML_Generate_String( dest_doc, cur_header->names[i - 1] );
1224
1225             // Break lines after a predefined number of header names
1226             if ( i < cur_header->no_names )
1227                 fprintf( dest_doc, ( i % header_breaks ) ? ", " : ",<br />" );
1228         }
1229
1230         // Print header type (if available and not Section names only)
1231         if ( header_type && !( course_of_action.do_sectionnameonly ) )
1232         {
1233             fprintf( dest_doc, " [ " );
1234             RB_HTML_Generate_String( dest_doc, header_type->indexName );
1235             fprintf( dest_doc, " ]" );
1236         }
1237
1238         fprintf( dest_doc, "</h2>\n\n" );
1239     }
1240 }
1241
1242 /* TODO */
1243 /*x**f* HTML_Generator/RB_HTML_Generate_Header_End
1244  * NAME
1245  *   RB_HTML_Generate_Header_End --
1246  ******
1247  */
1248
1249 void RB_HTML_Generate_Header_End(
1250     FILE *dest_doc,
1251     struct RB_header *cur_header )
1252 {
1253     USE( cur_header );
1254     fprintf( dest_doc, "\n" );
1255 }
1256
1257
1258 /****f* HTML_Generator/RB_HTML_Generate_IndexMenu
1259  * FUNCTION
1260  *   Generates a menu to jump to the various master index files for
1261  *   the various header types.  The menu is generated for each of the
1262  *   master index files.  The current header type is highlighted.
1263  * SYNOPSIS
1264  */
1265 void RB_HTML_Generate_IndexMenu(
1266     FILE *dest_doc,
1267     char *filename,
1268     struct RB_Document *document,
1269     struct RB_HeaderType *cur_type )
1270     /* TODO  Use cur_type */
1271 /*
1272  * INPUTS
1273  *   * dest_doc       -- the output file.
1274  *   * filename       -- the name of the output file
1275  *   * document       -- the gathered documention.
1276  *   * cur_headertype -- the header type that is to be highlighted.
1277  ******
1278  */
1279 {
1280     unsigned char       type_char;
1281     char               *toc_index_path = NULL;
1282
1283     USE( cur_type );            /* TODO FS make use of this */
1284     assert( dest_doc );
1285     assert( filename );
1286     assert( document );
1287
1288     toc_index_path = HTML_TOC_Index_Filename( document );
1289     RB_HTML_Generate_Link( dest_doc,
1290                            filename,
1291                            toc_index_path,
1292                            "top", "Table of Contents", "menuitem" );
1293     free( toc_index_path );
1294     fprintf( dest_doc, "\n" );
1295
1296     for ( type_char = MIN_HEADER_TYPE;
1297           type_char < MAX_HEADER_TYPE; ++type_char )
1298     {
1299         struct RB_HeaderType *header_type;
1300         int                 n;
1301
1302         header_type = RB_FindHeaderType( type_char );
1303         if ( header_type )
1304         {
1305             n = RB_Number_Of_Links( header_type, NULL, FALSE ) +
1306                 RB_Number_Of_Links( header_type, NULL, TRUE );
1307
1308             if ( n )
1309             {
1310                 char               *targetfilename = 0;
1311
1312                 targetfilename =
1313                     RB_Get_SubIndex_FileName( document->docroot->name,
1314                                               document->extension,
1315                                               header_type );
1316                 assert( targetfilename );
1317
1318                 RB_HTML_Generate_Link( dest_doc,
1319                                        filename,
1320                                        targetfilename,
1321                                        "top",
1322                                        header_type->indexName, "menuitem" );
1323                 free( targetfilename );
1324                 fprintf( dest_doc, "\n" );
1325             }
1326         }
1327     }
1328 }
1329
1330 /****f* HTML_Generator/RB_HTML_Generate_Index_Page
1331  * FUNCTION
1332  *   Generate a single file with a index table for headers
1333  *   of one specific type of headers
1334  * SYNOPSIS
1335  */
1336 void RB_HTML_Generate_Index_Page(
1337     struct RB_Document *document,
1338     struct RB_HeaderType *header_type )
1339 /*
1340  * INPUTS
1341  *   o document    -- the document
1342  *   o header_type -- the type for which the table is to
1343  *                    be generated.
1344  ******
1345  */
1346 {
1347     char               *filename = 0;
1348     FILE               *file;
1349
1350     assert( document );
1351     assert( header_type );
1352
1353     filename = RB_Get_SubIndex_FileName( document->docroot->name,
1354                                          document->extension, header_type );
1355     assert( filename );
1356
1357     file = fopen( filename, "w" );
1358     if ( !file )
1359     {
1360         RB_Panic( "can't open (%s)!\n", filename );
1361     }
1362     else
1363     {
1364         /* File opened, now we generate an index
1365          * for the specified header type 
1366          */
1367         RB_HTML_Generate_Doc_Start( file,
1368                                     document->srcroot->name,
1369                                     header_type->indexName,
1370                                     filename, document->charset );
1371
1372         /* breadcrumbtrail */
1373         HTML_Generate_Begin_Extra( file );
1374         /* No content for extra section yet... */
1375         HTML_Generate_End_Extra( file );
1376
1377         /* Menu for navigation */
1378         HTML_Generate_Begin_Navigation( file );
1379         RB_HTML_Generate_IndexMenu( file, filename, document, header_type );
1380         HTML_Generate_End_Navigation( file );
1381
1382         /* Content */
1383         HTML_Generate_Begin_Content( file );
1384         if ( RB_CompareHeaderTypes
1385              ( header_type, RB_FindHeaderType( HT_SOURCEHEADERTYPE ) )
1386              && ( header_type->typeCharacter != HT_MASTERINDEXTYPE ) )
1387         {
1388             RB_HTML_Generate_Source_Tree( file, filename, document );
1389         }
1390         else
1391         {
1392             RB_HTML_Generate_Index_Table( file,
1393                                           filename,
1394                                           header_type,
1395                                           header_type->indexName );
1396         }
1397         HTML_Generate_End_Content( file );
1398         RB_HTML_Generate_Doc_End( file, filename, document->srcroot->name );
1399         fclose( file );
1400     }
1401
1402     free( filename );
1403 }
1404
1405
1406 /* Create an index page that contains only the table of content */
1407
1408 void HTML_Generate_TOC_Index_Page(
1409     struct RB_Document *document )
1410 {
1411     FILE               *file = NULL;
1412     char               *toc_index_path = HTML_TOC_Index_Filename( document );
1413
1414     file = fopen( toc_index_path, "w" );
1415     if ( !file )
1416     {
1417         RB_Panic( "can't open (%s)!\n", toc_index_path );
1418     }
1419     else
1420     {
1421         RB_HTML_Generate_Doc_Start( file, document->srcroot->name,
1422                                     "Table of Contents",
1423                                     toc_index_path, document->charset );
1424
1425         /* breadcrumbtrail */
1426         HTML_Generate_Begin_Extra( file );
1427         /* No content for extra section yet... */
1428         HTML_Generate_End_Extra( file );
1429
1430         /* Menu for navigation */
1431         HTML_Generate_Begin_Navigation( file );
1432         RB_HTML_Generate_IndexMenu( file, toc_index_path, document, NULL );
1433         HTML_Generate_End_Navigation( file );
1434
1435         /* Content */
1436         HTML_Generate_Begin_Content( file );
1437         RB_Generate_TOC_2( file, document->headers,
1438                            document->no_headers, NULL, toc_index_path );
1439         HTML_Generate_End_Content( file );
1440
1441         /* End part */
1442         RB_HTML_Generate_Doc_End( file, toc_index_path,
1443                                   document->srcroot->name );
1444         fclose( file );
1445     }
1446
1447     free( toc_index_path );
1448 }
1449
1450
1451
1452
1453
1454 /* TODO */
1455 /*x**if* HTML_Generator/RB_HTML_Generate_Index
1456  * NAME
1457  *   RB_HTML_Generate_Index --
1458  ******
1459  */
1460
1461
1462 /* Should be called indexes */
1463 void RB_HTML_Generate_Index(
1464     struct RB_Document *document )
1465 {
1466     unsigned char       type_char = 0;
1467
1468     assert( document );
1469
1470     for ( type_char = MIN_HEADER_TYPE;
1471           type_char < MAX_HEADER_TYPE; ++type_char )
1472     {
1473         struct RB_HeaderType *header_type;
1474         int                 n;
1475
1476         header_type = RB_FindHeaderType( type_char );
1477         if ( header_type )
1478         {
1479             n = RB_Number_Of_Links( header_type, NULL, FALSE ) +
1480                 RB_Number_Of_Links( header_type, NULL, TRUE );
1481             if ( n )
1482             {
1483                 /* There are headers of this type, so create an index page
1484                  * for them
1485                  */
1486                 RB_HTML_Generate_Index_Page( document, header_type );
1487             }
1488         }
1489     }
1490
1491     RB_HTML_Generate_Index_Page( document,
1492                                  RB_FindHeaderType( HT_MASTERINDEXTYPE ) );
1493
1494     HTML_Generate_TOC_Index_Page( document );
1495 }
1496
1497
1498
1499
1500
1501
1502 void RB_HTML_Generate_Table_Body(
1503     FILE *dest,
1504     char *dest_name,
1505     struct RB_HeaderType *type,
1506     int internal )
1507 {
1508     struct RB_link     *cur_link;
1509     unsigned int        i;
1510     char                first_char = ' ';
1511     int                 found = FALSE;
1512
1513     /* Compute the number of columns we need for
1514      * this type of header.
1515      */
1516     for ( i = 0; i < link_index_size; ++i )
1517     {
1518         cur_link = link_index[i];
1519         if ( cur_link->htype &&
1520              RB_CompareHeaderTypes( cur_link->htype, type ) &&
1521              ( ( cur_link->is_internal && internal ) ||
1522                ( !cur_link->is_internal && !internal ) ) )
1523         {
1524             char               *r = 0;
1525
1526             r = RB_HTML_RelativeAddress( dest_name, cur_link->file_name );
1527             if ( toupper( cur_link->object_name[0] ) != first_char )
1528             {
1529                 first_char = toupper( cur_link->object_name[0] );
1530                 if ( found )
1531                 {
1532 //                    fprintf( dest, "</div>\n" );
1533                 }
1534                 fprintf( dest, "<h2><a name=\"%c\"></a>", first_char );
1535                 RB_HTML_Generate_Char( dest, first_char );
1536                 fprintf( dest, "</h2>" );
1537 //              fprintf( dest, "<div class=\"indexitem\">\n" );
1538                 found = TRUE;
1539             }
1540             fprintf( dest, "<a href=\"%s#%s\" class=\"indexitem\" >", r,
1541                      cur_link->label_name );
1542             RB_HTML_Generate_String( dest, cur_link->object_name );
1543             fprintf( dest, "</a>\n" );
1544         }
1545     }
1546     if ( found )
1547     {
1548 //        fprintf( dest, "</div>\n" );
1549     }
1550 }
1551
1552
1553 /****if* HTML_Generator/RB_HTML_Generate_Index_Shortcuts
1554  * NAME
1555  *   RB_HTML_Generate_Index_Shortcuts
1556  * FUNCTION
1557  *   Generates alphabetic shortcuts to index entries.
1558  * SYNOPSIS
1559  */
1560 static void RB_HTML_Generate_Index_Shortcuts(
1561     FILE *dest )
1562 /*
1563  * INPUTS
1564  *   o dest        -- the file to write to
1565  * TODO
1566  *   - Only list used letters.
1567  *   - List all letters (accented, signs, etc), not just the common ones.
1568  *   - Should be better to implement it as a <div> ?
1569  * SOURCE
1570  */
1571 {
1572     unsigned char       c;
1573
1574     fprintf( dest, "<h2>" );
1575
1576     // Generate A - Z
1577     for ( c = 'A'; c <= 'Z'; c++ )
1578     {
1579         fprintf( dest, "<a href=\"#%c\">", c );
1580         RB_HTML_Generate_Char( dest, c );
1581         fprintf( dest, "</a> - " );
1582     }
1583
1584     // Generate 0 - 9
1585     for ( c = '0'; c <= '9'; c++ )
1586     {
1587         fprintf( dest, "<a href=\"#%c\">", c );
1588         RB_HTML_Generate_Char( dest, c );
1589         fprintf( dest, "</a>" );
1590
1591         // Do not generate separator for the last char
1592         if ( c != '9' )
1593         {
1594             fprintf( dest, " - " );
1595         }
1596     }
1597
1598     fprintf( dest, "</h2>\n" );
1599 }
1600
1601 /********/
1602
1603 /****if* HTML_Generator/RB_HTML_Generate_Index_Table
1604  * NAME
1605  *   RB_HTML_Generate_Index_Table --
1606  * FUNCTION
1607  *   Create a HTML TABLE containing links to headers of a particular
1608  *   type.  This creates two tables, a table for normal headers as
1609  *   well as one for internal headers.
1610  * SYNOPSIS
1611  */
1612 void RB_HTML_Generate_Index_Table(
1613     FILE *dest,
1614     char *dest_name,
1615     struct RB_HeaderType *type,
1616     char *title )
1617 /*
1618  * INPUTS
1619  *   o dest        -- the file in which to write the table
1620  *   o dest_name   -- the name of this file
1621  *   o type        -- the type of header for which to generate
1622  *                    the table
1623  *   o title       -- the title of the table.
1624  * SOURCE
1625  */
1626 {
1627     /* Compute the number of columns we need for
1628      * this type of header.
1629      */
1630
1631     // Generate Index Title
1632     fprintf( dest, "<h1>" );
1633     RB_HTML_Generate_String( dest, title );
1634     fprintf( dest, "</h1>\n" );
1635
1636     // Generate Shortcuts at the begining
1637     RB_HTML_Generate_Index_Shortcuts( dest );
1638
1639     if ( RB_Number_Of_Links( type, NULL, FALSE ) )
1640     {
1641         if ( RB_Number_Of_Links( type, NULL, TRUE ) )
1642         {
1643             /* only print a title if there are two tables. */
1644             fprintf( dest, "<h2>Normal</h2>" );
1645         }
1646         RB_HTML_Generate_Table_Body( dest, dest_name, type, FALSE );
1647     }
1648
1649     if ( RB_Number_Of_Links( type, NULL, TRUE ) )
1650     {
1651         /* Always print the  Internal title, since
1652          * these headers are special and the user should know
1653          * he is looking at something special.
1654          */
1655         fprintf( dest, "<h2>Internal</h2>" );
1656         RB_HTML_Generate_Table_Body( dest, dest_name, type, TRUE );
1657     }
1658
1659     // Generate Shortcuts at the end
1660     RB_HTML_Generate_Index_Shortcuts( dest );
1661 }
1662
1663 /********/
1664
1665
1666
1667 /* TODO */
1668 /*x**if* HTML_Generator/RB_HTML_Generate_Empty_Item
1669  * NAME
1670  *   RB_HTML_Generate_Empty_Item --
1671  ******
1672  */
1673
1674 void RB_HTML_Generate_Empty_Item(
1675     FILE *dest_doc )
1676 {
1677     fprintf( dest_doc, "<br>\n" );
1678 }
1679
1680
1681
1682
1683 /****f* HTML_Generator/RB_HTML_Generate_Link
1684  * NAME
1685  *   RB_HTML_Generate_Link --
1686  * SYNOPSIS
1687  */
1688 void RB_HTML_Generate_Link(
1689     FILE *cur_doc,
1690     char *cur_name,
1691     char *filename,
1692     char *labelname,
1693     char *linkname,
1694     char *classname )
1695 /*
1696  * INPUTS
1697  *   cur_doc  --  the file to which the text is written
1698  *   cur_name --  the name of the destination file
1699  *                (the file from which we link)
1700  *   filename --  the name of the file that contains the link
1701  *                (the file we link to)
1702  *   labelname--  the name of the unique label of the link.
1703  *   linkname --  the name of the link as shown to the user.
1704  * SOURCE
1705  */
1706 {
1707     if ( classname )
1708     {
1709         fprintf( cur_doc, "<a class=\"%s\" ", classname );
1710     }
1711     else
1712     {
1713         fprintf( cur_doc, "<a " );
1714     }
1715     if ( filename && strcmp( filename, cur_name ) )
1716     {
1717         char               *r = RB_HTML_RelativeAddress( cur_name, filename );
1718
1719         fprintf( cur_doc, "href=\"%s#%s\">", r, labelname );
1720         RB_HTML_Generate_String( cur_doc, linkname );
1721         fprintf( cur_doc, "</a>" );
1722
1723     }
1724     else
1725     {
1726         fprintf( cur_doc, "href=\"#%s\">", labelname );
1727         RB_HTML_Generate_String( cur_doc, linkname );
1728         fprintf( cur_doc, "</a>" );
1729     }
1730 }
1731
1732 /******/
1733
1734
1735 /****f* HTML_Generator/RB_HTML_RelativeAddress
1736  * FUNCTION
1737  *   Link to 'that' from 'this' computing the relative path.  Here
1738  *   'this' and 'that' are both paths.  This function is used to
1739  *   create links from one document to another document that might be
1740  *   in a completely different directory.
1741  * SYNOPSIS
1742  */
1743 char               *RB_HTML_RelativeAddress(
1744     char *thisname,
1745     char *thatname )
1746 /*
1747  * EXAMPLE
1748  *   The following two
1749  *     this /sub1/sub2/sub3/f.html
1750  *     that /sub1/sub2/g.html
1751  *   result in 
1752  *     ../g.html
1753  *
1754  *     this /sub1/f.html
1755  *     that /sub1/sub2/g.html
1756  *     ==
1757  *     ./sub2/g.html
1758  *
1759  *     this /sub1/f.html
1760  *     that /sub1/g.html
1761  *     ==
1762  *     ./g.html
1763  *
1764  *     this /sub1/doc3/doc1/tt.html
1765  *     that /sub1/doc5/doc2/qq.html
1766  *     ==
1767  *     ../../doc5/doc2/qq.html
1768  *
1769  * NOTES
1770  *   Notice the execelent docmentation.
1771  * SOURCE
1772  */
1773 #define MAX_RELATIVE_SIZE 1024
1774 {
1775     static char         relative[MAX_RELATIVE_SIZE + 1];
1776     char               *i_this;
1777     char               *i_that;
1778     char               *i_this_slash = NULL;
1779     char               *i_that_slash = NULL;
1780
1781     relative[0] = '\0';
1782
1783     assert( thisname );
1784     assert( thatname );
1785
1786     for ( i_this = thisname, i_that = thatname;
1787           ( *i_this && *i_that ) && ( *i_this == *i_that );
1788           ++i_this, ++i_that )
1789     {
1790         if ( *i_this == '/' )
1791         {
1792             i_this_slash = i_this;
1793         }
1794         if ( *i_that == '/' )
1795         {
1796             i_that_slash = i_that;
1797         }
1798     }
1799
1800     if ( i_this_slash && i_that_slash )
1801     {
1802         int                 this_slashes_left = 0;
1803         int                 that_slashes_left = 0;
1804         char               *i_c;
1805
1806         for ( i_c = i_this_slash + 1; *i_c; ++i_c )
1807         {
1808             if ( *i_c == '/' )
1809             {
1810                 ++this_slashes_left;
1811             }
1812         }
1813
1814         for ( i_c = i_that_slash + 1; *i_c; ++i_c )
1815         {
1816             if ( *i_c == '/' )
1817             {
1818                 ++that_slashes_left;
1819             }
1820         }
1821
1822         if ( this_slashes_left )
1823         {
1824             int                 i;
1825
1826             for ( i = 0; i < this_slashes_left; ++i )
1827             {
1828                 strcat( relative, "../" );
1829             }
1830             strcat( relative, i_that_slash + 1 );
1831         }
1832         else if ( that_slashes_left )
1833         {
1834             /* !this_slashes_left && that_slashes_left */
1835             strcat( relative, "./" );
1836             strcat( relative, i_that_slash + 1 );
1837         }
1838         else
1839         {
1840             /* !this_slashes_left && !that_slashes_left */
1841             strcat( relative, "./" );
1842             strcat( relative, i_that_slash + 1 );
1843         }
1844     }
1845     return relative;
1846 }
1847
1848 /******/
1849
1850
1851
1852 /****f* HTML_Generator/RB_HTML_Generate_Char
1853  * NAME
1854  *   RB_HTML_Generate_Char -- generate a single character for an item.
1855  * SYNOPSIS
1856  */
1857 void RB_HTML_Generate_Char(
1858     FILE *dest_doc,
1859     int c )
1860 /*
1861  * FUNCTION
1862  *   This function is called for every character that goes
1863  *   into an item's body.  This escapes all the reserved
1864  *   HTML characters such as '&', '<', '>', '"'.
1865  * SOURCE
1866  */
1867 {
1868     switch ( c )
1869     {
1870     case '\n':
1871         assert( 0 );
1872         break;
1873     case '\t':
1874         assert( 0 );
1875         break;
1876     case '<':
1877         fprintf( dest_doc, "&lt;" );
1878         break;
1879     case '>':
1880         fprintf( dest_doc, "&gt;" );
1881         break;
1882     case '&':
1883         fprintf( dest_doc, "&amp;" );
1884         break;
1885     default:
1886         // All others are printed literally
1887         fputc( c, dest_doc );
1888     }
1889 }
1890
1891 /*******/
1892
1893
1894 void HTML_Generate_Begin_Content(
1895     FILE *dest_doc )
1896 {
1897     HTML_Generate_Div( dest_doc, "content" );
1898 }
1899
1900 void HTML_Generate_End_Content(
1901     FILE *dest_doc )
1902 {
1903     HTML_Generate_Div_End( dest_doc, "content" );
1904 }
1905
1906 void HTML_Generate_Begin_Navigation(
1907     FILE *dest_doc )
1908 {
1909     HTML_Generate_Div( dest_doc, "navigation" );
1910 }
1911
1912 void HTML_Generate_End_Navigation(
1913     FILE *dest_doc )
1914 {
1915
1916     HTML_Generate_Div_End( dest_doc, "navigation" );
1917 }
1918
1919 void HTML_Generate_Begin_Extra(
1920     FILE *dest_doc )
1921 {
1922     HTML_Generate_Div( dest_doc, "extra" );
1923 }
1924
1925 void HTML_Generate_End_Extra(
1926     FILE *dest_doc )
1927 {
1928     HTML_Generate_Div_End( dest_doc, "extra" );
1929 }
1930
1931
1932
1933
1934 /****f* HTML_Generator/RB_Create_CSS
1935  * FUNCTION
1936  *   Create the .css file.  Unless the user specified it's own css
1937  *   file robodoc creates a default one.
1938  *
1939  *   For multidoc mode the name of the .css file is
1940  *      robodoc.css
1941  *   For singledoc mode the name of the .css file is equal
1942  *   to the name of the documentation file.
1943  * SYNOPSIS
1944  */
1945 void RB_Create_CSS(
1946     struct RB_Document *document )
1947 /*
1948  * INPUTS
1949  *   o document -- the document for which to create the file.
1950  * SOURCE
1951  */
1952 {
1953     size_t              l = 0;
1954     FILE               *css_file;
1955
1956     /* compute the complete path to the css file */
1957     if ( ( document->actions.do_singledoc ) ||
1958          ( document->actions.do_singlefile ) )
1959     {
1960         char               *extension = ".css";
1961
1962         l += strlen( document->singledoc_name );
1963         l += strlen( extension );
1964         ++l;
1965         css_name = malloc( l );
1966         strcpy( css_name, document->singledoc_name );
1967         strcat( css_name, extension );
1968     }
1969     else
1970     {
1971         struct RB_Path     *docroot = document->docroot;
1972         char               *docrootname = docroot->name;
1973         char               *filename = "robodoc.css";
1974
1975         l = strlen( filename );
1976         l += strlen( docrootname );
1977         ++l;
1978         css_name = malloc( l );
1979         strcpy( css_name, docrootname );
1980         strcat( css_name, filename );
1981     }
1982
1983     RB_Say( "Creating CSS file %s\n", SAY_DEBUG, css_name );
1984     if ( document->css )
1985     {
1986         /* The user specified its own css file,
1987          * so we use the content of that.
1988          */
1989         RB_CopyFile( document->css, css_name );
1990     }
1991     else
1992     {
1993         css_file = fopen( css_name, "w" );
1994         if ( css_file )
1995         {
1996                     /** BEGIN BEGIN BEGIN Don't remove */
1997             fprintf( css_file,
1998                      "/****h* ROBODoc/ROBODoc Cascading Style Sheet\n"
1999                      " * FUNCTION\n"
2000                      " *   This is the default cascading style sheet for documentation\n"
2001                      " *   generated with ROBODoc.\n"
2002                      " *   You can edit this file to your own liking and then use\n"
2003                      " *   it with the option\n"
2004                      " *      --css <filename>\n"
2005                      " *\n"
2006                      " *   This style-sheet defines the following layout\n"
2007                      " *      +----------------------------------------+\n"
2008                      " *      |    logo                                |\n"
2009                      " *      +----------------------------------------+\n"
2010                      " *      |    extra                               |\n"
2011                      " *      +----------------------------------------+\n"
2012                      " *      |                              | navi-   |\n"
2013                      " *      |                              | gation  |\n"
2014                      " *      |      content                 |         |\n"
2015                      " *      |                              |         |\n"
2016                      " *      +----------------------------------------+\n"
2017                      " *      |    footer                              |\n"
2018                      " *      +----------------------------------------+\n"
2019                      " *\n"
2020                      " *   This style-sheet is based on a style-sheet that was automatically\n"
2021                      " *   generated with the Strange Banana stylesheet generator.\n"
2022                      " *   See http://www.strangebanana.com/generator.aspx\n"
2023                      " *\n"
2024                      " ******\n"
2025                      " * $Id: html_generator.c,v 1.91 2007/07/10 19:13:51 gumpu Exp $\n"
2026                      " */\n"
2027                      "\n"
2028                      "body\n"
2029                      "{\n"
2030                      "    background-color:    rgb(255,255,255);\n"
2031                      "    color:               rgb(98,84,55);\n"
2032                      "    font-family:         Arial, serif;\n"
2033                      "    border-color:        rgb(226,199,143);\n"
2034                      "}\n"
2035                      "\n"
2036                      "pre\n"
2037                      "{\n"
2038                      "    font-family:      monospace;\n"
2039                      "    margin:      15px;\n"
2040                      "    padding:     5px;\n"
2041                      "    white-space: pre;\n"
2042                      "    color:       #000;\n"
2043                      "}\n"
2044                      "\n"
2045                      "pre.source\n"
2046                      "{\n"
2047                      "    background-color: #ffe;\n"
2048                      "    border: dashed #aa9 1px;\n"
2049                      "}\n"
2050                      "\n"
2051                      "p\n"
2052                      "{\n"
2053                      "    margin:15px;\n"
2054                      "}\n"
2055                      "\n"
2056                      "p.item_name \n"
2057                      "{\n"
2058                      "    font-weight: bolder;\n"
2059                      "    margin:5px;\n"
2060                      "    font-size: 120%%;\n"
2061                      "}\n"
2062                      "\n"
2063                      "#content\n" "{\n" "    font-size:           100%%;\n" );
2064             fprintf( css_file,
2065                      "    color:               rgb(0,0,0);\n"
2066                      "    background-color:    rgb(255,255,255);\n"
2067                      "    border-left-width:   0px; \n"
2068                      "    border-right-width:  0px; \n"
2069                      "    border-top-width:    0px; \n"
2070                      "    border-bottom-width: 0px;\n"
2071                      "    border-left-style:   none; \n"
2072                      "    border-right-style:  none; \n"
2073                      "    border-top-style:    none; \n"
2074                      "    border-bottom-style: none;\n"
2075                      "    padding:             40px 31px 14px 17px;\n"
2076                      "    border-color:        rgb(0,0,0);\n"
2077                      "    text-align:          justify;\n"
2078                      "}\n"
2079                      "\n"
2080                      "#navigation\n"
2081                      "{\n"
2082                      "    background-color: rgb(98,84,55);\n"
2083                      "    color:            rgb(230,221,202);\n"
2084                      "    font-family:      \"Times New Roman\", serif;\n"
2085                      "    font-style:       normal;\n"
2086                      "    border-color:     rgb(0,0,0);\n"
2087                      "}\n"
2088                      "\n"
2089                      "a.menuitem\n"
2090                      "{\n"
2091                      "    font-size: 120%%;\n"
2092                      "    background-color:    rgb(0,0,0);\n"
2093                      "    color:               rgb(195,165,100);\n"
2094                      "    font-variant:        normal;\n"
2095                      "    text-transform:      none;\n"
2096                      "    font-weight:         normal;\n"
2097                      "    padding:             1px 8px 3px 1px;\n"
2098                      "    margin-left:         5px; \n"
2099                      "    margin-right:        5px; \n"
2100                      "    margin-top:          5px; \n"
2101                      "    margin-bottom:       5px;\n"
2102                      "    border-color:        rgb(159,126,57);\n"
2103                      "    text-align:          right;\n"
2104                      "}\n"
2105                      "\n"
2106                      "#logo, #logo a\n"
2107                      "{\n"
2108                      "    font-size: 130%%;\n"
2109                      "    background-color:   rgb(198,178,135);\n"
2110                      "    color:              rgb(98,84,55);\n"
2111                      "    font-family:        Georgia, serif;\n"
2112                      "    font-style:         normal;\n"
2113                      "    font-variant:       normal;\n"
2114                      "    text-transform:     none;\n"
2115                      "    font-weight:        bold;\n"
2116                      "    padding:            20px 18px 20px 18px;\n"
2117                      "    border-color:       rgb(255,255,255);\n"
2118                      "    text-align:         right;\n"
2119                      "}\n"
2120                      "\n"
2121                      "#extra, #extra a\n"
2122                      "{\n"
2123                      "    font-size: 128%%;\n"
2124                      "    background-color:    rgb(0,0,0);\n"
2125                      "    color:               rgb(230,221,202);\n"
2126                      "    font-style:          normal;\n"
2127                      "    font-variant:        normal;\n"
2128                      "    text-transform:      none;\n"
2129                      "    font-weight:         normal;\n" );
2130             fprintf( css_file,
2131                      "    border-left-width:   0px; \n"
2132                      "    border-right-width:  0px; \n"
2133                      "    border-top-width:    0px; \n"
2134                      "    border-bottom-width: 0px;\n"
2135                      "    border-left-style:   none; \n"
2136                      "    border-right-style:  none; \n"
2137                      "    border-top-style:    none; \n"
2138                      "    border-bottom-style: none;\n"
2139                      "    padding: 12px 12px 12px 12px;\n"
2140                      "    border-color:        rgb(195,165,100);\n"
2141                      "    text-align:          center;\n"
2142                      "}\n"
2143                      "\n"
2144                      "#content a\n"
2145                      "{\n"
2146                      "    color:              rgb(159,126,57);\n"
2147                      "    text-decoration:    none;\n"
2148                      "}\n"
2149                      "\n"
2150                      "#content a:hover, #content a:active\n"
2151                      "{\n"
2152                      "    color:              rgb(255,255,255);\n"
2153                      "    background-color:   rgb(159,126,57);\n"
2154                      "}\n"
2155                      "\n"
2156                      "a.indexitem\n"
2157                      "{\n"
2158                      "    display: block;\n"
2159                      "}\n"
2160                      "\n"
2161                      "h1, h2, h3, h4, h5, h6\n"
2162                      "{\n"
2163                      "    background-color: rgb(221,221,221);\n"
2164                      "    font-family:      Arial, serif;\n"
2165                      "    font-style:       normal;\n"
2166                      "    font-variant:     normal;\n"
2167                      "    text-transform:   none;\n"
2168                      "    font-weight:      normal;\n"
2169                      "}\n"
2170                      "\n"
2171                      "h1\n"
2172                      "{\n"
2173                      "    font-size: 151%%;\n"
2174                      "}\n"
2175                      "\n"
2176                      "h2\n"
2177                      "{\n"
2178                      "    font-size: 142%%;\n"
2179                      "}\n"
2180                      "\n"
2181                      "h3\n"
2182                      "{\n"
2183                      "    font-size: 133%%;\n"
2184                      "}\n"
2185                      "\n"
2186                      "h4\n"
2187                      "{\n"
2188                      "    font-size: 124%%;\n"
2189                      "}\n"
2190                      "\n"
2191                      "h5\n"
2192                      "{\n"
2193                      "    font-size: 115%%;\n"
2194                      "}\n"
2195                      "\n"
2196                      "h6\n"
2197                      "{\n"
2198                      "    font-size: 106%%;\n"
2199                      "}\n"
2200                      "\n"
2201                      "#navigation a\n"
2202                      "{\n"
2203                      "    text-decoration: none;\n"
2204                      "}\n"
2205                      "\n"
2206                      ".menuitem:hover\n"
2207                      "{\n"
2208                      "    background-color:   rgb(195,165,100);\n"
2209                      "    color:              rgb(0,0,0);\n"
2210                      "}\n"
2211                      "\n"
2212                      "#extra a\n"
2213                      "{\n"
2214                      "    text-decoration: none;\n"
2215                      "}\n"
2216                      "\n"
2217                      "#logo a\n"
2218                      "{\n"
2219                      "    text-decoration: none;\n"
2220                      "}\n"
2221                      "\n"
2222                      "#extra a:hover\n"
2223                      "{\n"
2224                      "}\n"
2225                      "\n"
2226                      "/* layout */\n"
2227                      "#navigation\n"
2228                      "{\n"
2229                      "    width:       22%%; \n"
2230                      "    position:    relative; \n"
2231                      "    top:         0; \n"
2232                      "    right:       0; \n"
2233                      "    float:       right; \n"
2234                      "    text-align:  center;\n"
2235                      "    margin-left: 10px;\n"
2236                      "}\n"
2237                      "\n"
2238                      ".menuitem       {width: auto;}\n"
2239                      "#content        {width: auto;}\n"
2240                      ".menuitem       {display: block;}\n" "\n" "\n" );
2241             fprintf( css_file,
2242                      "div#footer\n"
2243                      "{\n"
2244                      "    background-color: rgb(198,178,135);\n"
2245                      "    color:      rgb(98,84,55);\n"
2246                      "    clear:      left;\n"
2247                      "    width:      100%%;\n"
2248                      "    font-size:   71%%;\n"
2249                      "}\n"
2250                      "\n"
2251                      "div#footer a\n"
2252                      "{\n"
2253                      "    background-color: rgb(198,178,135);\n"
2254                      "    color:            rgb(98,84,55);\n"
2255                      "}\n"
2256                      "\n"
2257                      "div#footer p\n"
2258                      "{\n"
2259                      "    margin:0;\n"
2260                      "    padding:5px 10px\n"
2261                      "}\n"
2262                      "\n"
2263                      "span.keyword\n"
2264                      "{\n"
2265                      "    color: #00F;\n"
2266                      "}\n"
2267                      "\n"
2268                      "span.comment\n"
2269                      "{\n"
2270                      "    color: #080;\n"
2271                      "}\n"
2272                      "\n"
2273                      "span.quote\n"
2274                      "{\n"
2275                      "    color: #F00;\n"
2276                      "}\n"
2277                      "\n"
2278                      "span.squote\n"
2279                      "{\n"
2280                      "    color: #F0F;\n"
2281                      "}\n"
2282                      "\n"
2283                      "span.sign\n"
2284                      "{\n"
2285                      "    color: #008B8B;\n"
2286                      "}\n"
2287                      "\n"
2288                      "\n"
2289                      "@media print\n"
2290                      "{\n"
2291                      "    #navigation {display: none;}\n"
2292                      "    #content    {padding: 0px;}\n"
2293                      "    #content a  {text-decoration: underline;}\n"
2294                      "}\n" );
2295                     /** END END END Don't remove */
2296             fclose( css_file );
2297         }
2298         else
2299         {
2300             RB_Panic( "Can't open %s for writing\n", css_name );
2301         }
2302     }
2303 }
2304
2305 /*******/
2306
2307
2308 void RB_InsertCSS(
2309     FILE *dest_doc,
2310     char *filename )
2311 {
2312     if ( css_name )
2313     {
2314         char               *r = RB_HTML_RelativeAddress( filename, css_name );
2315
2316         assert( r );
2317         assert( strlen( r ) );
2318         fprintf( dest_doc,
2319                  "<link rel=\"stylesheet\" href=\"%s\" type=\"text/css\" />\n",
2320                  r );
2321     }
2322 }
2323
2324
2325
2326 void HTML_Generate_Begin_Paragraph(
2327     FILE *dest_doc )
2328 {
2329     fprintf( dest_doc, "<p>" );
2330 }
2331
2332 void HTML_Generate_End_Paragraph(
2333     FILE *dest_doc )
2334 {
2335     fprintf( dest_doc, "</p>\n" );
2336 }
2337
2338
2339 void HTML_Generate_Begin_Preformatted(
2340     FILE *dest_doc,
2341     int source )
2342 {
2343     // Check if we are preformatting a SOURCE item
2344     if ( source )
2345     {
2346         // SOURCE items have their own class in the CSS
2347         fprintf( dest_doc, "<pre class=\"%s\">", SOURCE_CLASS );
2348     }
2349     else
2350     {
2351         fprintf( dest_doc, "<pre>" );
2352     }
2353 }
2354
2355 void HTML_Generate_End_Preformatted(
2356     FILE *dest_doc )
2357 {
2358     fprintf( dest_doc, "</pre>\n" );
2359 }
2360
2361
2362 void HTML_Generate_Begin_List(
2363     FILE *dest_doc )
2364 {
2365     fprintf( dest_doc, "<ul>" );
2366 }
2367
2368 void HTML_Generate_End_List(
2369     FILE *dest_doc )
2370 {
2371     fprintf( dest_doc, "</ul>\n" );
2372 }
2373
2374 void HTML_Generate_Begin_List_Item(
2375     FILE *dest_doc )
2376 {
2377     fprintf( dest_doc, "<li>" );
2378 }
2379
2380 void HTML_Generate_End_List_Item(
2381     FILE *dest_doc )
2382 {
2383     fprintf( dest_doc, "</li>\n" );
2384 }