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