Added cross-reference support for document generator.
[silc.git] / util / robodoc / Source / generator.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include "robodoc.h"
6 #include "headers.h"
7 #include "items.h"
8 #include "folds.h"
9 #include "util.h"
10 #include "links.h"
11 #include "generator.h"
12 #include "analyser.h"
13 #include <errno.h>
14
15 /****f* ROBODoc/RB_Generate_Documentation [3.0h]
16  * NAME
17  *   RB_Generate_Documentation
18  * SYNOPSIS
19  *   RB_Generate_Documentation (dest_doc, name, name)
20  *
21  *   RB_Generate_Documentation (FILE *, char *, char *)
22  * FUNCTION
23  *   Generates the autodoc documentation from the list of
24  *   function headers that has been created by
25  *   RB_Analyse_Document.
26  * INPUTS
27  *   dest_doc   - Pointer to the file to which the output will be written.
28  *   src_name   - The name of the source file.
29  *   dest_name  - The name of this file.
30  * BUGS
31  *   There might be plenty.
32  * SEE ALSO
33  *   RB_Generate_Doc_Start,
34  *   RB_Generate_Doc_End,
35  *   RB_Generate_Header_Start,
36  *   RB_Generate_Header_End,
37  *   RB_Generate_Header_Name,
38  *   RB_Generate_Item_Name,
39  *   RB_Generate_Item_Doc,
40  *   RB_Generate_Item_Body .
41  * SOURCE
42  */
43
44 void
45 RB_Generate_Documentation (
46                             FILE * dest_doc, char *src_name, char *dest_name)
47 {
48   struct RB_header *cur_header;
49   char fname[256];
50   FILE *orig_doc = dest_doc;
51
52   RB_Make_Index_Tables ();
53
54   RB_Generate_Doc_Start (dest_doc, src_name, dest_name, 1);
55
56   for (cur_header = first_header;
57        cur_header;
58        cur_header = cur_header->next_header)
59     {
60       int item_type;
61       char *next_line, *item_line = NULL;
62
63       RB_Say ("generating documentation for \"%s\"\n", cur_header->name);
64
65       if (output_mode == HTML)
66         {
67           sprintf(fname, "%s-%s.html", doc_base, cur_header->function_name);
68           dest_doc = fopen(fname, "w");
69           if (!dest_doc)
70             {
71               fprintf(stderr, "%s\n", strerror(errno));
72               exit(1);
73             }
74         }
75
76       RB_Generate_Header_Start (dest_doc, cur_header, src_name);
77
78       next_line = cur_header->contents;
79       item_type = RB_Find_Item (&next_line, &item_line);
80
81       if (item_type != NO_ITEM)
82         {
83           int old_item_type;
84           char *old_next_line;
85
86           do
87             {
88               if (course_of_action & DO_TELL)
89                 printf ("[%s] ", item_names[item_type]);
90
91               if (!((item_type == SOURCE_ITEM) &&  
92                   (course_of_action & DO_NOSOURCE)))
93                 RB_Generate_Item_Name (dest_doc, item_type);
94               
95               old_next_line = next_line;
96               old_item_type = item_type;
97               
98               item_type = RB_Find_Item (&next_line, &item_line);
99
100               if (!((old_item_type == SOURCE_ITEM) &&  
101                   (course_of_action & DO_NOSOURCE)))
102                 RB_Generate_Item_Doc (dest_doc, dest_name,
103                                       old_next_line, item_line,
104                                       cur_header->function_name, 
105                                       old_item_type);
106             }
107           while (item_type != NO_ITEM);
108           if (course_of_action & DO_TELL)
109             putchar ('\n');
110         }
111       else
112         printf ("%s: WARNING, header \"%s\" has no items\n",
113                 whoami, cur_header->name);
114
115       RB_Generate_Header_End (dest_doc, cur_header);
116
117       if (output_mode == HTML)
118         fclose(dest_doc);
119     }
120
121   dest_doc = orig_doc;
122   RB_Generate_Doc_End (dest_doc, dest_name);
123 }
124
125 /***** RB_Generate_Documentation ***/
126
127
128
129
130
131 /****f* ROBODoc/RB_Generate_Doc_Start [3.0j]
132  * NAME
133  *   RB_Generate_Doc_Start -- Generate document header.
134  * SYNOPSIS
135  *   RB_Generate_Doc_Start (dest_doc, src_name, name, toc)
136  *
137  *   RB_Generate_Doc_Start (FILE *, char *, char *, char)
138  * FUNCTION
139  *   Generates for depending on the output_mode the text that
140  *   will be at the start of a document.
141  *   Including the table of contents.
142  * INPUTS
143  *   dest_doc - pointer to the file to which the output will
144  *              be written.
145  *   src_name - the name of the source file.
146  *   name     - the name of this file.
147  *   output_mode - global variable that indicates the output
148  *                 mode.
149  *   toc      - generate table of contens
150  * SEE ALSO
151  *   RB_Generate_Doc_End
152  * SOURCE
153  */
154
155 void
156 RB_Generate_Doc_Start (
157                       FILE * dest_doc, char *src_name, char *name, char toc)
158 {
159   struct RB_header *cur_header;
160   int cur_len, max_len, header_nr;
161
162   switch (output_mode)
163     {
164     case AMIGAGUIDE:
165       if (strstr (name + 1, ".guide") == NULL)
166         fprintf (dest_doc, "@database %s.guide\n", name);
167       else
168         fprintf (dest_doc, "@database %s\n", name);
169       fprintf (dest_doc, "@rem Source: %s\n", src_name);
170       fprintf (dest_doc, "@rem " COMMENT_ROBODOC);
171       fprintf (dest_doc, "@rem " COMMENT_COPYRIGHT);
172       fprintf (dest_doc, "@node Main %s\n", name);
173       fprintf (dest_doc, "@{jcenter}\n");
174       fprintf (dest_doc,
175                "@{fg highlight}@{b}TABLE OF CONTENTS@{ub}@{fg text}\n\n");
176
177       max_len = 0;
178       for (cur_header = first_header;
179            cur_header;
180            cur_header = cur_header->next_header)
181         {
182           if (cur_header->name)
183             {
184               cur_len = strlen (cur_header->name);
185               if (cur_len > max_len)
186                 max_len = cur_len;
187             }
188         }
189
190       for (cur_header = first_header;
191            cur_header;
192            cur_header = cur_header->next_header)
193         {
194           if (cur_header->name && cur_header->function_name)
195             {
196               fprintf (dest_doc, "@{\"%s", cur_header->name);
197
198               for (cur_len = strlen (cur_header->name);
199                    cur_len < max_len;
200                    ++cur_len)
201                 fputc (' ', dest_doc);
202               fprintf (dest_doc, "\" Link \"%s\"}\n", cur_header->function_name);
203             }
204         }
205
206       fprintf (dest_doc, "@{jleft}\n");
207       fprintf (dest_doc, "@endnode\n");
208       break;
209
210     case HTML:
211       /* Append document type and title */
212       fprintf (dest_doc,
213                "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n");
214       fprintf (dest_doc, "<HTML><HEAD>\n<TITLE>%s</TITLE>\n", name);
215
216       /* append SGML-comment with document- and copyright-info. This code
217        * ensures that every line has an own comment to avoid problems with 
218        * buggy browsers */
219       fprintf (dest_doc, "<!-- Source: %s -->\n", src_name);
220       {
221         static const char copyright_text[]
222         = COMMENT_ROBODOC COMMENT_COPYRIGHT;
223         size_t i = 0;
224         char previous_char = '\n';
225         char current_char = copyright_text[i];
226
227         while (current_char)
228           {
229             if (previous_char == '\n')
230               {
231                 fprintf (dest_doc, "<!-- ");
232               }
233             if (current_char == '\n')
234               {
235                 fprintf (dest_doc, " -->");
236               }
237             else if ((current_char == '-') && (previous_char == '-'))
238               {
239                 /* avoid "--" inside SGML-comment, and use "-_" instead; this
240                  * looks a bit strange, but one should still be able to figure 
241                  * out what is meant when reading the output */
242                 current_char = '_';
243               }
244             fputc (current_char, dest_doc);
245             i += 1;
246             previous_char = current_char;
247             current_char = copyright_text[i];
248           }
249       }
250
251       /* append heading and start list of links to functions */
252       fprintf (dest_doc, "</HEAD><BODY BGCOLOR=\"#FFFFFF\">\n");
253 #if 0
254       fprintf (dest_doc, "<A NAME=\"%s\">Generated from %s</A> with ROBODoc v"
255                VERSION
256                " on ",
257                src_name, src_name);
258       RB_TimeStamp (dest_doc);
259 #endif
260       fprintf (dest_doc, "<BR>\n");
261       if (toc)
262         {
263           char iname[256];
264           FILE *index;
265           int start = 0;
266
267           /* do toc if not in fold */
268 #if 0
269           fprintf (dest_doc,
270                    "<H3 ALIGN=\"center\">TABLE OF CONTENTS</H3>\n");
271           fprintf (dest_doc, "<OL>\n");
272 #endif
273
274           /* Generate quick index file, for fast referencing */
275           sprintf(iname, "%s-index.tmpl", doc_base);
276           index = fopen(iname, "w");
277           if (!index)
278             {
279               fprintf(stderr, "%s\n", strerror(errno));
280               exit(1);
281             }
282
283           for (cur_header = first_header;
284                cur_header;
285                cur_header = cur_header->next_header)
286             {
287               char fname[256];
288
289               sprintf(fname, "%s-%s.html", RB_FilePart(doc_base), 
290                       cur_header->function_name);
291
292               if (cur_header->name && cur_header->function_name)
293                 {
294                   if (start == 0) 
295                     {
296                       int item_type;
297                       char *next_line, *item_line = NULL;
298                     
299                       RB_Generate_Header_Start (dest_doc, cur_header, 
300                                                 src_name);
301
302                       next_line = cur_header->contents;
303                       item_type = RB_Find_Item (&next_line, &item_line);
304                       
305                       if (item_type != NO_ITEM)
306                         {
307                           int old_item_type;
308                           char *old_next_line;
309                           
310                           do
311                             {
312                               if (course_of_action & DO_TELL)
313                                 printf ("[%s] ", item_names[item_type]);
314                               
315                               if (!((item_type == SOURCE_ITEM) &&
316                                     (course_of_action & DO_NOSOURCE)))
317                                 RB_Generate_Item_Name (dest_doc, item_type);
318                               
319                               old_next_line = next_line;
320                               old_item_type = item_type;
321                               
322                               item_type = RB_Find_Item (&next_line, 
323                                                         &item_line);
324                               
325                               if (!((old_item_type == SOURCE_ITEM) &&
326                                     (course_of_action & DO_NOSOURCE)))
327                                 RB_Generate_Item_Doc(dest_doc, name,
328                                                      old_next_line, item_line,
329                                                      cur_header->function_name,
330                                                      old_item_type);
331                             }
332                           while (item_type != NO_ITEM);
333                           if (course_of_action & DO_TELL)
334                             putchar ('\n');
335                         }
336
337                       if (index)
338                         {
339                           fprintf (index, "<A HREF=\"%s\"><IMG SRC=\"index_pic.gif\" BORDER=\"0\" ALT=\"\">%s</A><BR>\n",
340                                    name, cur_header->function_name);
341                         }
342
343                       start = 1;
344                     }
345                   else
346                     {
347                       fprintf (dest_doc, "<LI><A HREF=\"%s\">%s</A>\n",
348                                fname, cur_header->function_name);
349                       if (index)
350                         fprintf (index, "<A HREF=\"%s\"><IMG SRC=\"index_pic.gif\" BORDER=\"0\" ALT=\"\">%s</A><BR>\n",
351                                  fname, cur_header->function_name);
352                     }
353                 }
354             }
355
356 #if 0
357           fprintf (dest_doc, "</OL>\n");
358 #endif
359
360           if (index)
361             fclose(index);
362         }
363       break;
364
365     case LATEX:
366       fprintf (dest_doc, "%% Document: %s\n", name);
367       fprintf (dest_doc, "%% Source: %s\n", src_name);
368       fprintf (dest_doc, "%% " COMMENT_ROBODOC);
369       fprintf (dest_doc, "%% " COMMENT_COPYRIGHT);
370       if (course_of_action & DO_SINGLEDOC) {
371         fprintf (dest_doc, "\\section{%s}\n", src_name);
372       } else {
373         fprintf (dest_doc, "\\documentclass{article}\n");
374         fprintf (dest_doc, "\\usepackage{makeidx}\n");
375         fprintf (dest_doc, "\\oddsidemargin  0.15 in\n");
376         fprintf (dest_doc, "\\evensidemargin 0.35 in\n");
377         fprintf (dest_doc, "\\marginparwidth 1 in   \n");
378         fprintf (dest_doc, "\\oddsidemargin 0.25 in \n");
379         fprintf (dest_doc, "\\evensidemargin 0.25 in\n");
380         fprintf (dest_doc, "\\marginparwidth 0.75 in\n");
381         fprintf (dest_doc, "\\textwidth 5.875 in\n");
382         
383         fprintf (dest_doc, "\\setlength{\\parindent}{0in}\n");
384         fprintf (dest_doc, "\\setlength{\\parskip}{.08in}\n\n");
385         
386         /* changed default header to use boldface (vs slant) */
387         fprintf (dest_doc, "\\pagestyle{headings}\n");
388
389         if (document_title) {
390           fprintf (dest_doc, "\\title{%s}\n", 
391                    document_title);
392         } else {
393           fprintf (dest_doc, "\\title{API Reference}\n");
394         }
395         fprintf (dest_doc, "\\author{%s}\n", COMMENT_ROBODOC);
396         fprintf (dest_doc, "\\makeindex\n");
397         fprintf (dest_doc, "\\begin{document}\n");
398         fprintf (dest_doc, "\\maketitle\n");
399         /* autogenerate table of contents! */
400         fprintf (dest_doc, "\\printindex\n");
401         fprintf (dest_doc, "\\tableofcontents\n");
402         fprintf (dest_doc, "\\newpage\n");
403         /* trick to disable the autogenerated \newpage */
404         fprintf (dest_doc, "\n");
405       }
406       break;
407
408     case RTF:
409       {
410         char *cook_link;
411
412         /* RTF header */
413         fprintf (dest_doc, "{\\rtf1\\ansi \\deff0"
414                  "{\\fonttbl;"
415                  "\\f0\\fswiss MS Sans Serif;"
416                  "\\f1\\fmodern Courier New;"
417                  "\\f2\\ftech Symbol;"
418                  "}"
419                  "{\\colortbl;"
420                  "\\red255\\green255\\blue255;"
421                  "\\red0\\green0\\blue0;"
422                  "\\red0\\green0\\blue255;"
423                  "}");
424
425         /* RTF document info */
426         fprintf (dest_doc, "{\\info"
427                  "{\\title %s}"
428                  "{\\comment\n"
429                  " Source: %s\n"
430                  " " COMMENT_ROBODOC
431                  " " COMMENT_COPYRIGHT
432                  "}"
433                  "}", name, src_name);
434
435         /* RTF document format */
436         fprintf (dest_doc, "{\\margl1440\\margr1440}\n");
437
438         /* RTF document section */
439         fprintf (dest_doc, "\\f0\\cb1\\cf3\\fs28\\b1\\qc"
440                  "{\\super #{\\footnote{\\super #}%s_TOC}}"
441                  "{\\super ${\\footnote{\\super $}Contents}}"
442                  "{TABLE OF CONTENTS}\\ql\\b0\\fs20\\cf2\\par\n", src_name);
443         for (cur_header = first_header;
444              cur_header;
445              cur_header = cur_header->next_header)
446           {
447             if (cur_header->name && cur_header->function_name)
448               {
449                 cook_link = RB_CookStr (cur_header->function_name);
450                 fprintf (dest_doc, "{\\uldb %s}{\\v %s}\\line\n",
451                          cur_header->name, cook_link);
452                 free (cook_link);
453               }
454           }
455         fprintf (dest_doc, "\\par\n");
456       }
457       break;
458     case ASCII:
459       if (course_of_action & DO_TOC)
460         {
461           fprintf (dest_doc, "TABLE OF CONTENTS\n");
462           for (cur_header = first_header, header_nr = 1;
463                cur_header;
464                cur_header = cur_header->next_header, header_nr++)
465             {
466               if (cur_header->name && cur_header->function_name)
467                 {
468                   fprintf (dest_doc, "%4.4d %s\n",
469                            header_nr, cur_header->name);
470                 }
471             }
472           fputc ('\f', dest_doc);
473         }
474     default:
475       break;
476     }
477 }
478
479 /***************/
480
481
482 /****f* ROBODoc/RB_Generate_Doc_End [3.0h]
483  * NAME
484  *   RB_Generate_Doc_End -- generate document trailer.
485  * SYNOPSIS
486  *   RB_Generate_Doc_End (dest_doc, name)
487  *
488  *   RB_Generate_Doc_End (FILE *, char *)
489  * FUNCTION
490  *   Generates for depending on the output_mode the text that
491  *   will be at the end of a document.
492  * INPUTS
493  *   dest_doc - pointer to the file to which the output will
494  *              be written.
495  *   name     - the name of this file.
496  *   output_mode - global variable that indicates the output
497  *                 mode.
498  * NOTES
499  *   Doesn't do anything with its arguments, but that might
500  *   change in the future.
501  * BUGS
502  * SOURCE
503  */
504
505 void
506 RB_Generate_Doc_End (FILE * dest_doc, char *name)
507 {
508   switch (output_mode)
509     {
510     case AMIGAGUIDE:
511       fputc ('\n', dest_doc);
512       break;
513     case HTML:
514       fprintf (dest_doc, "</BODY></HTML>\n");
515       break;
516     case LATEX:
517       if (!(course_of_action & DO_SINGLEDOC)) { 
518         fprintf (dest_doc, "\\end{document}\n");
519       }
520       break;
521     case RTF:
522       fputc ('}', dest_doc);
523       break;
524     case ASCII:
525       break;
526     }
527 }
528
529 /************/
530
531
532 /****f* ROBODoc/RB_Generate_Header_Start [3.0h]
533  * NAME
534  *   RB_Generate_Header_Start -- generate header start text.
535  * SYNOPSIS
536  *  void RB_Generate_Header_Start (dest_doc, cur_header)
537  *
538  *  void RB_Generate_Header_Start (FILE *, struct RB_header *)
539  * FUNCTION
540  *   Generates depending on the output_mode the text that
541  *   will be at the end of each header.
542  * INPUTS
543  *   dest_doc - pointer to the file to which the output will
544  *              be written.
545  *   cur_header - pointer to a RB_header structure.
546  * SEE ALSO
547  *   RB_Generate_Header_End
548  * SOURCE
549  */
550
551 void
552 RB_Generate_Header_Start (FILE * dest_doc, struct RB_header *cur_header,
553                           const char *src_name)
554 {
555   char *cook_link;
556
557   switch (output_mode)
558     {                           /* switch by *koessi */
559     case AMIGAGUIDE:
560       if (cur_header->name && cur_header->function_name)
561         {
562           fprintf (dest_doc, "@Node \"%s\" \"%s\"\n",
563                    cur_header->function_name,
564                    cur_header->name);
565           fprintf (dest_doc, "%s", att_start_command[MAKE_SHINE][output_mode]);
566           fprintf (dest_doc, "%s", cur_header->name);
567           fprintf (dest_doc, "%s", att_stop_command[MAKE_SHINE][output_mode]);
568           fprintf (dest_doc, "\n\n");
569         }
570       break;
571     case HTML:
572       if (cur_header->name && cur_header->function_name)
573         {
574 #if 0
575           fprintf (dest_doc, "<HR>\n");
576 #endif
577           if (cur_header->type == FUNCTION_HEADER)
578             fprintf (dest_doc, 
579                      "\n<FONT SIZE=\"+2\" COLOR=\"#000055\"><B>"
580                      "Function <A NAME=\"%s\">%s</A>"
581                      "</FONT></B><BR><BR>\n\n",
582                      cur_header->function_name,
583                      cur_header->function_name);
584           else if (cur_header->type == STRUCT_HEADER)
585             fprintf (dest_doc, 
586                      "\n<FONT SIZE=\"+2\" COLOR=\"#000055\"><B>"
587                      "Structure <A NAME=\"%s\">%s</A>"
588                      "</FONT></B><BR><BR>\n\n",
589                      cur_header->function_name,
590                      cur_header->function_name);
591           else if (cur_header->type == VARIABLE_HEADER)
592             fprintf (dest_doc, 
593                      "\n<FONT SIZE=\"+2\" COLOR=\"#000055\"><B>"
594                      "Variable <A NAME=\"%s\">%s</A>"
595                      "</FONT></B><BR><BR>\n\n",
596                      cur_header->function_name,
597                      cur_header->function_name);
598           else if (cur_header->type == MAIN_HEADER)
599             fprintf (dest_doc, 
600                      "\n<FONT SIZE=\"+2\" COLOR=\"#000055\"><B>"
601                      "<A NAME=\"%s\">%s</A>"
602                      "</FONT></B><BR><SMALL>Header: %s</SMALL><BR><BR>\n\n",
603                      cur_header->function_name,
604                      cur_header->function_name, src_name);
605           else
606             fprintf (dest_doc, 
607                      "\n<FONT SIZE=\"+2\" COLOR=\"#000055\"><B>"
608                      "<A NAME=\"%s\">%s</A>"
609                      "</FONT></B><BR><BR>\n\n",
610                      cur_header->function_name,
611                      cur_header->function_name);
612         }
613       break;
614     case LATEX:
615       cook_link = RB_CookStr (cur_header->name);
616       if (!(course_of_action & DO_SINGLEDOC)) {
617         fprintf (dest_doc, "\\newpage\n");
618       }
619       fprintf (dest_doc, "\\subsection{%s}\n", cook_link);
620       free (cook_link);
621       if (cur_header->function_name) {
622         cook_link = RB_CookStr (cur_header->function_name);
623         fprintf (dest_doc, "\\index{unsorted!%s}\\index{%s!%s}\n", cook_link, 
624                  RB_header_type_names[cur_header->type], cook_link);
625         free (cook_link);
626       }
627       break;
628     case RTF:
629       if (cur_header->name && cur_header->function_name)
630         {
631           cook_link = RB_CookStr (cur_header->function_name);
632           fprintf (dest_doc, "\\page"
633                    "{\\super #{\\footnote{\\super #}%s}}"
634                    "{\\super ${\\footnote{\\super $}%s}}"
635                    "\\cf3 %s\\cf2\\line\n",
636                    cur_header->function_name,
637                    cur_header->name,
638                    cur_header->name);
639           free (cook_link);
640         }
641       break;
642     case ASCII:
643       {
644         fprintf (dest_doc, "%s", att_start_command[MAKE_SHINE][output_mode]);
645         fprintf (dest_doc, "%s", cur_header->name);
646         fprintf (dest_doc, "%s", att_stop_command[MAKE_SHINE][output_mode]);
647         fprintf (dest_doc, "\n\n");
648       }
649       break;
650     }
651 }
652
653 /******/
654
655
656 /****f* ROBODoc/RB_Generate_Header_End [3.0h]
657  * NAME
658  *   RB_Generate_Header_End
659  * SYNOPSIS
660  *   void RB_Generate_Header_End (dest_doc, cur_header)
661  *
662  *   void RB_Generate_Header_End (FILE *, struct RB_header *)
663  * FUNCTION
664  *   Generates for depending on the output_mode the text that
665  *   will be at the end of a header.
666  * INPUTS
667  *   dest_doc - pointer to the file to which the output will
668  *              be written.
669  *   cur_header - pointer to a RB_header structure.
670  * SEE ALSO
671  *   RB_Generate_Header_Start
672  * SOURCE
673  */
674
675 void
676 RB_Generate_Header_End (FILE * dest_doc, struct RB_header *cur_header)
677 {
678   switch (output_mode)
679     {                           /* switch by *koessi */
680     case AMIGAGUIDE:
681       if (cur_header->name && cur_header->function_name)
682         fprintf (dest_doc, "@endnode\n");
683       break;
684     case HTML:
685     case LATEX:
686       fputc ('\n', dest_doc);
687       break;
688     case RTF:
689       fprintf (dest_doc, "\\par\n");
690       break;
691     case ASCII:
692       fputc ('\f', dest_doc);
693     default:
694       break;
695     }
696 }
697
698 /*****/
699
700
701 /****f* ROBODoc/RB_Generate_Header_Name [3.0c]
702  * NAME
703  *   RB_Generate_Header_Name
704  * SYNOPSIS
705  *   RB_Generate_Header_Name (dest_doc, name)
706  *
707  *   RB_Generate_Header_Name (FILE *, char *)
708  * INPUTS
709  *  dest_doc - pointer to the file to which the output will
710  *             be written.
711  *  name - pointer to the header name.
712  * SOURCE
713  */
714
715 void
716 RB_Generate_Header_Name (FILE * dest_doc, char *name)
717 {
718   char format_str[] = "%s";
719
720   fprintf (dest_doc, format_str, att_start_command[MAKE_SHINE][output_mode]);
721   fprintf (dest_doc, format_str, name);
722   fprintf (dest_doc, format_str, att_stop_command[MAKE_SHINE][output_mode]);
723   fprintf (dest_doc, "\n\n");
724 }
725
726 /*** RB_Generate_Header_Name ***/
727
728
729 /****** ROBODoc/RB_Generate_Item_Name [2.01]
730  * NAME
731  *   RB_Generate_Item_Name -- fast&easy
732  * SYNOPSIS
733  *   void RB_Generate_Item_Name( FILE * dest_doc, int item_type )
734  * FUNCTION
735  *   write the items name to the doc
736  * INPUTS
737  *   FILE * dest_doc         -- document in progress
738  *   int item_type           -- this leads to the name and makes colors
739  * AUTHOR
740  *   Koessi
741  * NOTES
742  *   uses globals: output_mode, item_names[]
743  * SOURCE
744  */
745
746 void
747 RB_Generate_Item_Name (FILE * dest_doc, int item_type)
748 {
749   char format_str[] = "%s";
750
751   if (item_attributes[item_type] & ITEM_NAME_LARGE_FONT)
752     {
753       fprintf (dest_doc, format_str,
754                att_start_command[MAKE_LARGE][output_mode]);
755       fprintf (dest_doc, format_str,
756                att_start_command[MAKE_BOLD][output_mode]);
757       if (output_mode == HTML)
758         fprintf (dest_doc, "\n<FONT COLOR=\"#000055\">");
759       fprintf (dest_doc, format_str, item_names[item_type]);
760       if (output_mode == HTML)
761         fprintf (dest_doc, "\n</FONT>");
762       fprintf (dest_doc, format_str,
763                att_stop_command[MAKE_BOLD][output_mode]);
764       fprintf (dest_doc, format_str,
765                att_stop_command[MAKE_LARGE][output_mode]);
766     }
767   else
768     fprintf (dest_doc, format_str, item_names[item_type]);
769
770   fputc ('\n', dest_doc);
771 }
772
773 /*****/
774
775
776
777 /****f* ROBODoc/RB_Generate_Item_Doc [3.0j]
778  * NAME
779  *   RB_Generate_Item_Doc
780  * SYNOPSIS
781  *   void RB_Generate_Item_Doc(FILE * dest_doc, char *dest_name,
782  *                             char *begin_of_item,
783  *                             char *end_of_item,
784  *                             char *function_name,
785  *                             int item_type)
786  * FUNCTION
787  *   Generates the body text of an item, applying predefined attributes
788  *   to the text.
789  * NOTES
790  *   Body text is always non-proportional for several reasons:
791  *   1) text is rarely written with prop spacing and text wrapping
792  *      in mind -- e.g., see SYNOPSIS above
793  *   2) source code looks better
794  *   3) it simplifies LaTeX handling
795  * SOURCE
796  */
797
798 void
799 RB_Generate_Item_Doc (FILE * dest_doc, char *dest_name,
800                       char *begin_of_item,
801                       char *end_of_item,
802                       char *function_name,
803                       int item_type)
804 {
805   char format_str[] = "%s";
806
807   if (begin_of_item == end_of_item)
808     {
809       switch (output_mode)
810         {
811         case HTML:
812           fprintf (dest_doc, "<BR>\n");
813           break;
814         case LATEX:
815           fprintf (dest_doc, "\\\\\n");
816           break;
817         case RTF:
818           fprintf (dest_doc, "\n");
819           break;
820         default:
821           break;
822         }
823       return;
824     }
825   /* For text body in HTML, change to non-prop _before_ changing font
826    * style. * To conform to DTD, this avoids <B><PRE> and instead uses
827    * <PRE><B> */
828   if (output_mode == HTML)
829     {
830       fprintf (dest_doc, "<PRE>");
831     }
832   /* change font style */
833   if (item_attributes[item_type] & TEXT_BODY_LARGE_FONT)
834     fprintf (dest_doc, format_str,
835              att_start_command[MAKE_LARGE][output_mode]);
836   if (item_attributes[item_type] & TEXT_BODY_ITALICS)
837     fprintf (dest_doc, format_str,
838              att_start_command[MAKE_ITALICS][output_mode]);
839   if (item_attributes[item_type] & TEXT_BODY_NON_PROP)
840     fprintf (dest_doc, format_str,
841              att_start_command[MAKE_NON_PROP][output_mode]);
842   if (item_attributes[item_type] & TEXT_BODY_SMALL_FONT)
843     fprintf (dest_doc, format_str,
844              att_start_command[MAKE_SMALL][output_mode]);
845   if (item_attributes[item_type] & TEXT_BODY_BOLD)
846     fprintf (dest_doc, format_str,
847              att_start_command[MAKE_BOLD][output_mode]);
848   if (item_attributes[item_type] & TEXT_BODY_UNDERLINE)
849     fprintf (dest_doc, format_str,
850              att_start_command[MAKE_UNDERLINE][output_mode]);
851   if (item_attributes[item_type] & TEXT_BODY_SHINE)
852     fprintf (dest_doc, format_str,
853              att_start_command[MAKE_SHINE][output_mode]);
854   if (item_attributes[item_type] & TEXT_BODY_DEFAULT)
855     fprintf (dest_doc, format_str,
856              att_start_command[MAKE_DEFAULT][output_mode]);
857
858   /* 
859    * For some modes, the text body is always non-prop
860    */
861   switch (output_mode)
862     {
863     case LATEX:
864       fprintf (dest_doc, "\\begin{verbatim}\n");
865       break;
866     case RTF:
867       fprintf (dest_doc, "{\\f1{}");
868       break;
869     default:
870       break;
871     }
872
873   RB_Generate_Item_Body (dest_doc, dest_name, begin_of_item, end_of_item,
874                          function_name, item_type, 0);
875
876   switch (output_mode)
877     {
878     case LATEX:
879       /* split the text so LaTeX doesn't get confused ;) */
880       fprintf (dest_doc, "\\" "end{verbatim}\n");
881       break;
882     case RTF:
883       fputc ('}', dest_doc);
884     default:
885       break;
886     }
887
888   /* restore font style */
889   if (item_attributes[item_type] & TEXT_BODY_SHINE)
890     fprintf (dest_doc, format_str,
891              att_stop_command[MAKE_SHINE][output_mode]);
892   if (item_attributes[item_type] & TEXT_BODY_UNDERLINE)
893     fprintf (dest_doc, format_str,
894              att_stop_command[MAKE_UNDERLINE][output_mode]);
895   if (item_attributes[item_type] & TEXT_BODY_BOLD)
896     fprintf (dest_doc, format_str,
897              att_stop_command[MAKE_BOLD][output_mode]);
898   if (item_attributes[item_type] & TEXT_BODY_SMALL_FONT)
899     fprintf (dest_doc, format_str,
900              att_stop_command[MAKE_SMALL][output_mode]);
901   if (item_attributes[item_type] & TEXT_BODY_NON_PROP)
902     fprintf (dest_doc, format_str,
903              att_stop_command[MAKE_NON_PROP][output_mode]);
904   if (item_attributes[item_type] & TEXT_BODY_ITALICS)
905     fprintf (dest_doc, format_str,
906              att_stop_command[MAKE_ITALICS][output_mode]);
907   if (item_attributes[item_type] & TEXT_BODY_LARGE_FONT)
908     fprintf (dest_doc, format_str,
909              att_stop_command[MAKE_LARGE][output_mode]);
910   if (item_attributes[item_type] & TEXT_BODY_DEFAULT)
911     fprintf (dest_doc, format_str,
912              att_stop_command[MAKE_DEFAULT][output_mode]);
913
914   if (output_mode != HTML)
915     {
916       fputc ('\n', dest_doc);
917     }
918   /* for HTML, switch back to prop-font after restoring font style */
919   if (output_mode == HTML)
920     {
921       fprintf (dest_doc, "</PRE>");
922     }
923 }
924
925 /******/
926
927
928
929 /****f* ROBODoc/RB_Generate_Item_Body [3.0h]
930  * NAME
931  *  RB_Generate_Item_Body
932  * SYNOPSIS
933  *  char * RB_Generate_Item_Body(FILE * dest_doc, char *dest_name,
934  *                             char *begin_of_item, char *end_of_item,
935  *                             char *function_name,
936  *                             int   item_type, int tabs_to_skip)
937  *
938  * FUNCTION
939  *   Generates body of an item in output-specific form
940  * INPUTS
941  *   dest_doc      - pointer to the file to which
942  *                   the output will be written.
943  *   dest_name     - the name of this file.
944  *   begin_of_item -
945  *   end_of_item   -
946  *   function_name -
947  *   item_type     -
948  *   tabs_to_skip  - how many tabs to skip in this fold.
949  * BUGS
950  *   o Unbalanced fold marks lead to crash.
951  * NOTES
952  *   o Almost completely rewritten by koessi
953  *   o Almost completely Re-Rewritten by Slothouber :)
954  *   o Folding mode by PetteriK.
955  *   o Linking fixed inside folds / PetteriK 08.04.2000 
956  * SOURCE
957  */
958
959 char *
960 RB_Generate_Item_Body (FILE * dest_doc, char *dest_name,
961                        char *begin_of_item, char *end_of_item,
962                        char *function_name,
963                        int item_type, int tabs_to_skip)
964 {
965   char *cur_char, old_char, c;
966   int html_incr;
967   char fname[128], foldname[128];
968   static int in_fold = 0;       /* PetteriK 08.04.2000 */
969
970   cur_char = begin_of_item;
971
972   if (item_type == SOURCE_ITEM)
973     {
974       /* skip end_comment_marker */
975       for (; *cur_char && *cur_char != '\n'; cur_char++);
976
977       /* skip blank lines leading up to source code */
978       while (*cur_char == '\n')
979         cur_char++;
980
981       /* trim blanks following source code */
982       do
983         {
984           end_of_item--;
985         }
986       while (end_of_item > cur_char && isspace (*end_of_item));
987       end_of_item++;            /* advance 1 for placement of the NUL */
988     }
989   old_char = *end_of_item;
990   *end_of_item = '\0';
991
992   for (; *cur_char; cur_char++)
993     {
994       int tb = tab_size;
995       int do_search = TRUE;
996       int was_link = FALSE;
997       int tabs = 0;
998
999       if (item_type != SOURCE_ITEM)
1000         {
1001           /* Skip empty lines */
1002           while (*cur_char == '\n') {
1003                 cur_char++;
1004           }
1005           cur_char = RB_Skip_Remark_Marker (cur_char);
1006         }
1007       else
1008         {
1009           /* indent source */
1010           switch (output_mode)
1011             {
1012             case RTF:
1013               fprintf (dest_doc, "\\tab ");
1014               break;
1015
1016             case AMIGAGUIDE:
1017             case HTML:
1018             case LATEX:
1019             default:
1020               fprintf (dest_doc, "    ");
1021             }
1022         }
1023
1024       while (((c = *cur_char) != '\0') && (c != '\n'))
1025         {
1026           char *label_name, *file_name;
1027           char found = 0;
1028           int tmp;
1029
1030           if (!do_search)
1031             {
1032               if (!isalnum (c) && (c != '_'))
1033                 {
1034                   do_search = TRUE;
1035                 }
1036             }
1037           else
1038             {
1039               if (isalpha (c) || (c == '_'))
1040                 {
1041                   if (((was_link = RB_Find_Link (cur_char, &label_name,
1042                                                  &file_name)) == FALSE))
1043                     {
1044                       do_search = FALSE;
1045                     }
1046                 }
1047               else
1048                 was_link = FALSE;
1049             }
1050
1051           if (!was_link)
1052             {
1053               switch (output_mode)
1054                 {
1055                 case AMIGAGUIDE:
1056                   switch (c)
1057                     {
1058                     case '\n':
1059                       --cur_char;
1060                       break;
1061                     case '\t':
1062                       for (tb %= tab_size; tb < tab_size; ++tb)
1063                         fputc (' ', dest_doc);
1064                       break;
1065                     case '@':
1066                       fprintf (dest_doc, "\\@");
1067                       tb++;
1068                       break;
1069                     case '\\':
1070                       fprintf (dest_doc, "\\\\");
1071                       tb++;
1072                       break;
1073                     default:
1074                       fputc (c, dest_doc);
1075                       tb++;
1076                     }
1077                   break;
1078
1079                 case HTML:
1080                   /* PetteriK 26.07.1999 */
1081                   if (extra_flags & FOLD)
1082                     {
1083                       cur_char = RB_Check_Fold_Start (cur_char,
1084                                                       foldname, &found);
1085                     }
1086                   if ((extra_flags & FOLD) && found)
1087                     {
1088                       FILE *fp;
1089
1090                       RB_Say ("fold name %s\n", foldname);
1091                       RB_Say ("fold begin %d\n", ++fold);
1092                       RB_Say ("tabs %d\n", tabs);
1093                       sprintf (fname, "%s_fold_%d.html", doc_base, fold);
1094                       RB_Say ("opening file %s\n", fname);
1095                       fp = fopen (fname, "w");
1096                       RB_Generate_Doc_Start (fp, foldname, foldname, 0);
1097                       fprintf (fp, "<PRE>\n");
1098                       fprintf (dest_doc, "<A HREF=\"%s\">... %s</A>",
1099                                fname, foldname);
1100                       in_fold++;        /* PetteriK 08.04.2000 */
1101                       cur_char = RB_Generate_Item_Body (fp, dest_name,
1102                                                       cur_char, end_of_item,
1103                                                         function_name,
1104                                                         item_type, tabs);
1105                       in_fold--;        /* PetteriK 08.04.2000 */
1106                       /* skip chars until newline */
1107                       while (*cur_char != '\n')
1108                         {
1109                           cur_char++;
1110                         }
1111                       cur_char--;
1112                       fprintf (fp, "\n</PRE>\n");
1113                       RB_Generate_Doc_End (fp, foldname);
1114                       fclose (fp);
1115                     }
1116                   else if ((extra_flags & FOLD) && RB_Check_Fold_End (cur_char))
1117                     {
1118                       RB_Say ("fold end found\n");
1119                       return cur_char;
1120                     }
1121                   else if ((html_incr = RB_HTML_Extra (dest_doc,
1122                                                        item_type, cur_char)))
1123                     {
1124                       cur_char += html_incr;
1125                     }
1126                   else
1127                     {
1128                       switch (c)
1129                         {
1130                         case '\n':
1131                           --cur_char;
1132                           break;
1133                         case '\t':
1134                           if (extra_flags & FOLD)
1135                             {
1136                               if (tabs >= tabs_to_skip)
1137                                 {
1138                                   for (tb %= tab_size; tb < tab_size; ++tb)
1139                                     {
1140                                       fputc (' ', dest_doc);
1141                                     }
1142                                 }
1143                               tabs++;
1144                             }
1145                           else
1146                             {
1147                               for (tb %= tab_size; tb < tab_size; ++tb)
1148                                 {
1149                                   fputc (' ', dest_doc);
1150                                 }
1151                             }
1152                           break;
1153                         case '<':
1154                           fprintf (dest_doc, "&lt;");
1155                           tb++;
1156                           break;
1157                         case '>':
1158                           fprintf (dest_doc, "&gt;");
1159                           tb++;
1160                           break;
1161                         case '&':
1162                           fprintf (dest_doc, "&amp;");
1163                           tb++;
1164                           break;
1165                         default:
1166                           fputc (c, dest_doc);
1167                           tb++;
1168                         }
1169                     }
1170                   break;        /* end case HTML */
1171
1172                 case LATEX:
1173                   switch (c)
1174                     {
1175                     case '\n':
1176                       --cur_char;
1177                       break;
1178                     case '\t':
1179                       for (tb %= tab_size; tb < tab_size; ++tb)
1180                         fputc (' ', dest_doc);
1181                       break;
1182 #if 0
1183                       /* not used in LaTeX's verbatim environment */
1184                     case '$':
1185                     case '&':
1186                     case '%':
1187                     case '#':
1188                     case '_':
1189                     case '{':
1190                     case '}':
1191                       fputc ('\\', dest_doc);
1192                       fputc (c, dest_doc);
1193                       tb++;
1194                       break;
1195                     case '\\':
1196                       fprintf (dest_doc, "$\\backslash$");
1197                       tb++;
1198                       break;
1199                     case '~':
1200                       fprintf (dest_doc, "$\\tilde$");
1201                       tb++;
1202                       break;
1203                     case '^':
1204                       fprintf (dest_doc, "$\\,\\!^{\\sim}$");
1205                       tb++;
1206                       break;
1207 #endif
1208                     default:
1209                       fputc (c, dest_doc);
1210                       tb++;
1211                     }
1212                   break;
1213
1214                 case RTF:
1215                   switch (c)
1216                     {
1217                     case '\n':
1218                       --cur_char;
1219                       break;
1220                     case '\t':
1221                       for (tb %= tab_size; tb < tab_size; ++tb)
1222                         fputc (' ', dest_doc);
1223                       break;
1224                     case '\\':
1225                     case '{':
1226                     case '}':
1227                       fputc ('\\', dest_doc);
1228                       fputc (c, dest_doc);
1229                       tb++;
1230                       break;
1231                     default:
1232                       fputc (c, dest_doc);
1233                       tb++;
1234                     }
1235                   break;
1236
1237                 default:
1238                   fputc (c, dest_doc);
1239                   tb++;
1240                 }
1241               cur_char++;
1242             }
1243           else
1244             {
1245               switch (output_mode)
1246                 {
1247                 case AMIGAGUIDE:
1248                   if (file_name && strcmp (file_name, dest_name))
1249                     fprintf (dest_doc, "@{\"%s\" Link \"%s/%s\"}",
1250                              label_name, file_name, label_name);
1251                   else
1252                     {
1253                       if (strcmp (label_name, function_name))
1254                         fprintf (dest_doc, "@{\"%s\" Link \"%s\"}",
1255                                  label_name, label_name);
1256                       else
1257                         {
1258                           fprintf (dest_doc, "%s",
1259                                  att_start_command[MAKE_BOLD][output_mode]);
1260                           fprintf (dest_doc, "%s", label_name);
1261                           fprintf (dest_doc, "%s",
1262                                    att_stop_command[MAKE_BOLD][output_mode]);
1263                         }
1264                     }
1265                   break;
1266
1267                 case HTML:
1268                   /* Include the file name in the link if we are in fold
1269                    * PetteriK 08.04.2000 
1270                    */
1271                   if (in_fold)
1272                     {
1273                       /* We are in fold, always use the file name in the link, 
1274                        * in file_name == NULL (i.e. the label is in the current file 
1275                        * that we are processing), refer to value in dest_name. 
1276                        * This also makes sure that we link correctly if function_name
1277                        * is the same as label_name.
1278                        */
1279                       fprintf (dest_doc, "<A HREF=\"%s#%s\">%s</A>",
1280                                (file_name ? file_name : dest_name),
1281                                label_name, label_name);
1282                     }
1283                   else if (file_name && strcmp (file_name, dest_name))
1284                     {
1285 #if 0
1286                       fprintf (dest_doc, "<A HREF=\"%s#%s\">%s</A>",
1287                                file_name, label_name, label_name);
1288 #endif
1289                       fprintf (dest_doc, "<A HREF=\"%s-%s.html\">%s</A>",
1290                                RB_FilePartStart(file_name), label_name, 
1291                                label_name);
1292                     }
1293                   else
1294                     {
1295                       if (strcmp (label_name, function_name))
1296                         {
1297 #if 0
1298                           fprintf (dest_doc, "<A HREF=\"#%s\">%s</A>",
1299                                    label_name, label_name);
1300 #endif
1301                           fprintf (dest_doc, "<A HREF=\"%s-%s.html\">%s</A>",
1302                                    RB_FilePart(doc_base), label_name, 
1303                                                label_name);
1304                         }
1305                       else
1306                         {
1307                           fprintf (dest_doc, "%s",
1308                                  att_start_command[MAKE_BOLD][output_mode]);
1309                           fprintf (dest_doc, "%s", label_name);
1310                           fprintf (dest_doc, "%s",
1311                                    att_stop_command[MAKE_BOLD][output_mode]);
1312                         }
1313                     }
1314                   break;
1315
1316                 case RTF:
1317                   if (strcmp (label_name, function_name))
1318                     {
1319                       char *cook_link;
1320
1321                       cook_link = RB_CookStr (label_name);
1322                       fprintf (dest_doc, "{\\uldb %s}{\\v %s}",
1323                                label_name, cook_link);
1324                       free (cook_link);
1325                     }
1326                   else
1327                     {
1328                       fprintf (dest_doc, "%s",
1329                                att_start_command[MAKE_BOLD][output_mode]);
1330                       fprintf (dest_doc, "%s", label_name);
1331                       fprintf (dest_doc, "%s",
1332                                att_stop_command[MAKE_BOLD][output_mode]);
1333                     }
1334                   break;
1335                 default:
1336                   fprintf (dest_doc, "%s", label_name);
1337                 }
1338               tmp = strlen (label_name);
1339               cur_char += tmp;
1340               tb += tmp;
1341             }                   /* end if */
1342         }
1343
1344       if (*cur_char)
1345         {
1346           if (output_mode == RTF)
1347             fprintf (dest_doc, "\\line");
1348           fputc ('\n', dest_doc);
1349           tabs = 0;
1350         }
1351     }
1352   *end_of_item = old_char;
1353   return (char *) 0;
1354 }
1355
1356
1357 /***************/
1358
1359
1360 /****f* ROBODoc/RB_HTML_Extra
1361 * NAME
1362 *   RB_HTML_Extra
1363 * AUTHOR
1364 *   PetteriK
1365 * HISTORY
1366 *   05/15/2000 Added mailto: support (Guillaume Etorre)
1367 * FUNCTION
1368 *   Check and process embedded hyperlinks.
1369 * RETURN VAL* FUNCTION
1370 *   Check and process embedded hyperlinks.
1371 * RETURN VALUE
1372 *   Number of chars processed from *cur_char
1373 * TODO
1374 *   Flag for C and other grammars.
1375 * BUGS
1376 *   As the documentation generated for this functions shows, if
1377 *   the C source code contains a string with " / * " in it, this
1378 *   function fails :)
1379 * SOURCE
1380 */
1381
1382 int
1383 RB_HTML_Extra (FILE * dest_doc, int item_type, char *cur_char)
1384 {
1385   int res = 0;
1386   char link[1024];
1387
1388   if (strncmp ("http://", cur_char, strlen ("http://")) == 0)
1389     {
1390       sscanf (cur_char, "%s", link);
1391       RB_Say ("found link %s\n", link);
1392       res = (strlen (link) - 1);
1393       fprintf (dest_doc, "<A HREF=\"%s\">%s</A>", link, link);
1394     }
1395   else if (strncmp ("href:", cur_char, strlen ("href:")) == 0)
1396     {
1397       /* handy in relative hyperlink paths, e.g. href:../../modulex/ */
1398       sscanf ((cur_char + strlen ("href:")), "%s", link);
1399       RB_Say ("found link %s\n", link);
1400       res = (strlen (link) + strlen ("href:") - 1);
1401       fprintf (dest_doc, "<A HREF=\"%s\">%s</A>", link, link);
1402     }
1403   else if (strncmp ("mailto:", cur_char, strlen ("mailto:")) == 0)
1404     {
1405       sscanf ((cur_char + strlen ("mailto:")), "%s", link);
1406       RB_Say ("found mail to %s\n", link);
1407       res = (strlen (link) + strlen ("mailto:") - 1);
1408       fprintf (dest_doc, "<A HREF=\"mailto:%s\">%s</A>", link, link);
1409     }
1410   else if ((extra_flags & C_MODE) && (item_type == SOURCE_ITEM) &&
1411            (strncmp ("/*", cur_char, 2) == 0))
1412     {
1413       /* start of C comment */
1414       fprintf (dest_doc, "<FONT COLOR = \"#FF0000\">/*");
1415       res = 1;
1416     }
1417   else if ((extra_flags & C_MODE) && (item_type == SOURCE_ITEM) &&
1418            (strncmp ("*/", cur_char, 2) == 0))
1419     {
1420       /* end of C comment */
1421       fprintf (dest_doc, "*/</FONT>");
1422       res = 1;
1423     }
1424   return res;
1425 }
1426
1427 /**********/
1428
1429
1430 /****f* ROBODoc/RB_Generate_Index
1431  * NAME
1432  *   RB_Generate_Index -- generate index file based on xref files.
1433  * SYNOPSIS
1434  *   void RB_Generate_Index(FILE *dest, char *name) 
1435  * FUNCTION
1436  *   Create a master index file. It contains pointers to the
1437  *   documentation generated for each source file, as well as all
1438  *   "objects" found in the source files.
1439  ********
1440  */
1441
1442 void
1443 RB_Generate_Index (FILE * dest, char *source)
1444 {
1445   RB_Slow_Sort_Links ();
1446
1447   switch (output_mode)
1448     {
1449     case HTML:
1450       {
1451         if (document_title) {
1452           RB_Generate_Doc_Start (dest, source, document_title, 0);
1453           fprintf (dest, "<H1>%s</H1>\n", document_title);
1454         } else {
1455           RB_Generate_Doc_Start (dest, source, "Master Index File", 0);
1456           fprintf (dest, "<H1>Master Index File</H1>\n");
1457         }
1458         if (RB_Number_Of_Links (MAIN_HEADER, NULL))
1459           RB_Generate_Index_Table (dest, MAIN_HEADER, "Project Modules");
1460         RB_Generate_Index_Table (dest, NO_HEADER, "Source Files");
1461         if (RB_Number_Of_Links (CLASS_HEADER, NULL))
1462           RB_Generate_Index_Table (dest, CLASS_HEADER, "Classes");
1463         if (RB_Number_Of_Links (METHOD_HEADER, NULL))
1464           RB_Generate_Index_Table (dest, METHOD_HEADER, "Methods");
1465         if (RB_Number_Of_Links (STRUCT_HEADER, NULL))
1466           RB_Generate_Index_Table (dest, STRUCT_HEADER, "Structures");
1467         if (RB_Number_Of_Links (FUNCTION_HEADER, NULL))
1468           RB_Generate_Index_Table (dest, FUNCTION_HEADER, "Functions");
1469         if (RB_Number_Of_Links (VARIABLE_HEADER, NULL))
1470           RB_Generate_Index_Table (dest, VARIABLE_HEADER, "Variables");
1471         if (RB_Number_Of_Links (CONSTANT_HEADER, NULL))
1472           RB_Generate_Index_Table (dest, CONSTANT_HEADER, "Constants");
1473         if (RB_Number_Of_Links (GENERIC_HEADER, NULL))
1474           RB_Generate_Index_Table (dest, GENERIC_HEADER, "Generic");
1475         if (RB_Number_Of_Links (INTERNAL_HEADER, NULL))
1476           RB_Generate_Index_Table (dest, INTERNAL_HEADER, "Internal");
1477         RB_Generate_Doc_End (dest, source);
1478       } break;
1479     case LATEX:
1480       {
1481         RB_Generate_Doc_Start (dest, source, "Master File", 0);
1482         RB_Generate_LaTeX_Includes (dest);
1483         RB_Generate_Doc_End (dest, source);
1484       }
1485     }
1486 }
1487
1488
1489 /****f* ROBODoc/Generate_LaTeX_Includes
1490  * NAME
1491  *   Generate_LaTeX_Includes -- generate include commands
1492  * SYNOPSIS
1493  *   void RB_Generate_LaTeX_Includes (FILE *dest)
1494  * FUNCTION
1495  *   Generates a series of \include commands to include the
1496  *   documentation generated for each source file into one
1497  *   big file.
1498  ****
1499  */
1500
1501 void
1502 RB_Generate_LaTeX_Includes (FILE *dest)
1503 {
1504   struct RB_link *cur_link;
1505   for (cur_link = first_link;
1506        cur_link;
1507        cur_link = cur_link->next_link) {
1508     {
1509       if (cur_link->type == NO_HEADER)
1510         fprintf (dest, "\\include{%s}\n", cur_link->label_name);
1511     }
1512   }
1513 }
1514
1515 /****f* ROBODoc/RB_Generate_Index_Table
1516  * NAME
1517  *   RB_Generate_Index --
1518  * SYNOPSIS
1519  *   void RB_Generate_Index_Table(FILE *, int type, char *title)
1520  *        RB_Generate_Index_Table(dest, type, title)
1521  * FUNCTION
1522  *   Creates a table with index items of a particular type.
1523  *   If the type is NO_HEADER, then the table is a table of
1524  *   source files. In this case no link is added if the
1525  *   source file did not contain any documentation.  
1526  * INPUTS
1527  *   dest  -- output file
1528  *   type  -- kind of header index. 
1529  *   title -- title for the table
1530  * SOURCE
1531  */
1532
1533 void
1534 RB_Generate_Index_Table (FILE * dest, int type, char *title)
1535 {
1536   struct RB_link *cur_link;
1537   int number_of_columns;
1538   int cur_column;
1539
1540   number_of_columns = 60 / RB_Max_Name_Length (type, NULL);
1541
1542   fprintf (dest, "<H2>%s</H2>\n", title);
1543   fprintf (dest, "<TABLE>\n");
1544   cur_column = 0;
1545   for (cur_link = first_link;
1546        cur_link;
1547        cur_link = cur_link->next_link)
1548     {
1549       if (cur_link->type == type)
1550         {
1551           if (cur_column == 0)
1552             {
1553               fprintf (dest, "<TR>\n");
1554             }
1555           if (type == NO_HEADER)
1556             {
1557               if (RB_Number_Of_Links (NO_HEADER, cur_link->file_name) > 1)
1558                 {
1559                   fprintf (dest,
1560                            "<TD><A HREF=\"%s#%s\"><TT>%s</TT></A></TD>\n",
1561                            cur_link->file_name, cur_link->label_name,
1562                            cur_link->label_name);
1563                 }
1564               else
1565                 {
1566                   fprintf (dest, "<TD>%s</TD>\n", cur_link->label_name);
1567                 }
1568             }
1569           else
1570             {
1571               fprintf (dest, "<TD><A HREF=\"%s#%s\"><TT>%s</TT></A></TD>\n",
1572                        cur_link->file_name, cur_link->label_name,
1573                        cur_link->label_name);
1574             };
1575           cur_column++;
1576           if (cur_column > number_of_columns)
1577             {
1578               fprintf (dest, "</TR>\n");
1579               cur_column = 0;
1580             }
1581         }
1582     }
1583   for (; cur_column <= number_of_columns;)
1584     {
1585       if (cur_column == 0)
1586         {
1587           fprintf (dest, "<TR>\n");
1588         }
1589       fprintf (dest, "<TD></TD>\n");
1590       cur_column++;
1591     }
1592   fprintf (dest, "</TR>\n");
1593   fprintf (dest, "</TABLE>\n");
1594 }
1595
1596 /******* END RB_Generate_Index_Table  *****/
1597
1598
1599 /****f* ROBODoc/RB_Number_Of_Links
1600  * NAME
1601  *   RB_Number_Of_Links -- Count the number of links.
1602  * FUNCTION
1603  *   Counts the number of links that are of a particular type
1604  *   and that can be found in a particular file.
1605  * INPUTS
1606  *   type      -- the header type of the header the link is pointing to.
1607  *                If NO_HEADER, all header types are counted.
1608  *   file_name -- name of the file the link comes from, can be NULL, in
1609  *                which case only the type is checked.
1610  * RESULT
1611  *   number of links.
1612  ******
1613  */
1614
1615 int
1616 RB_Number_Of_Links (int type, char *file_name)
1617 {
1618   struct RB_link *cur_link;
1619   int n = 0;
1620
1621   for (cur_link = first_link;
1622        cur_link;
1623        cur_link = cur_link->next_link)
1624     {
1625       if (cur_link->type == type || (type == NO_HEADER))
1626         {
1627           if (file_name)
1628             {
1629               if (strcmp (file_name, cur_link->file_name) == 0)
1630                 {
1631                   n++;
1632                 }
1633             }
1634           else
1635             {
1636               n++;
1637             }
1638         }
1639     }
1640
1641   return n;
1642 }
1643
1644
1645 /****f* ROBODoc/RB_Max_Name_Length
1646  * NAME
1647  *   RB_Max_Name_Length -- find longest label name.
1648  * FUNCTION
1649  *   Find the length of the longest label name in a sub list
1650  *   of the list with links.  This is used to determine how
1651  *   many columns can be displayed in a table.
1652  *   The sublist is specified by the type of header the link
1653  *   should point to, as well as by the name of the documentation 
1654  *   file.
1655  * EXAMPLE
1656  *     RB_Max_Name_Length(CLASS_HEADER, "muppets.c.html")
1657  *   longest label name in the list of links to class headers 
1658  *   in muppets.c.html.
1659  *     RB_Max_Name_Length(CLASS_HEADER, NULL)
1660  *   longest label name in the list of links to class headers.
1661  * INPUTS
1662  *   type      -- type of header
1663  *   file_name -- file the header come from, can be NULL.
1664  *                In which links from all files are used.
1665  * SOURCE
1666  */
1667
1668 int
1669 RB_Max_Name_Length (int type, char *file_name)
1670 {
1671   struct RB_link *cur_link;
1672   int n = 1;
1673
1674   for (cur_link = first_link;
1675        cur_link;
1676        cur_link = cur_link->next_link)
1677     {
1678       if (cur_link->type == type)
1679         {
1680           if (file_name)
1681             {
1682               if (strcmp (file_name, cur_link->file_name) == 0)
1683                 {
1684                   if (strlen (cur_link->label_name) > n)
1685                     {
1686                       n = strlen (cur_link->label_name);
1687                     }
1688                 }
1689             }
1690           else
1691             {
1692               if (strlen (cur_link->label_name) > n)
1693                 {
1694                   n = strlen (cur_link->label_name);
1695                 }
1696             }
1697         }
1698     }
1699   return n;
1700 }
1701
1702 /*********/