updates
[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   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         }
70
71       RB_Generate_Header_Start (dest_doc, cur_header);
72
73       next_line = cur_header->contents;
74       item_type = RB_Find_Item (&next_line, &item_line);
75
76       if (item_type != NO_ITEM)
77         {
78           int old_item_type;
79           char *old_next_line;
80
81           do
82             {
83               if (course_of_action & DO_TELL)
84                 printf ("[%s] ", item_names[item_type]);
85
86               if (!((item_type == SOURCE_ITEM) &&  
87                   (course_of_action & DO_NOSOURCE)))
88                 RB_Generate_Item_Name (dest_doc, item_type);
89               
90               old_next_line = next_line;
91               old_item_type = item_type;
92               
93               item_type = RB_Find_Item (&next_line, &item_line);
94
95               if (!((old_item_type == SOURCE_ITEM) &&  
96                   (course_of_action & DO_NOSOURCE)))
97                 RB_Generate_Item_Doc (dest_doc, dest_name,
98                                       old_next_line, item_line,
99                                       cur_header->function_name, 
100                                       old_item_type);
101             }
102           while (item_type != NO_ITEM);
103           if (course_of_action & DO_TELL)
104             putchar ('\n');
105         }
106       else
107         printf ("%s: WARNING, header \"%s\" has no items\n",
108                 whoami, cur_header->name);
109
110       RB_Generate_Header_End (dest_doc, cur_header);
111     }
112
113   dest_doc = orig_doc;
114   RB_Generate_Doc_End (dest_doc, dest_name);
115 }
116
117 /***** RB_Generate_Documentation ***/
118
119
120
121
122
123 /****f* ROBODoc/RB_Generate_Doc_Start [3.0j]
124  * NAME
125  *   RB_Generate_Doc_Start -- Generate document header.
126  * SYNOPSIS
127  *   RB_Generate_Doc_Start (dest_doc, src_name, name, toc)
128  *
129  *   RB_Generate_Doc_Start (FILE *, char *, char *, char)
130  * FUNCTION
131  *   Generates for depending on the output_mode the text that
132  *   will be at the start of a document.
133  *   Including the table of contents.
134  * INPUTS
135  *   dest_doc - pointer to the file to which the output will
136  *              be written.
137  *   src_name - the name of the source file.
138  *   name     - the name of this file.
139  *   output_mode - global variable that indicates the output
140  *                 mode.
141  *   toc      - generate table of contens
142  * SEE ALSO
143  *   RB_Generate_Doc_End
144  * SOURCE
145  */
146
147 void
148 RB_Generate_Doc_Start (
149                       FILE * dest_doc, char *src_name, char *name, char toc)
150 {
151   struct RB_header *cur_header;
152   int cur_len, max_len, header_nr;
153
154   switch (output_mode)
155     {
156     case AMIGAGUIDE:
157       if (strstr (name + 1, ".guide") == NULL)
158         fprintf (dest_doc, "@database %s.guide\n", name);
159       else
160         fprintf (dest_doc, "@database %s\n", name);
161       fprintf (dest_doc, "@rem Source: %s\n", src_name);
162       fprintf (dest_doc, "@rem " COMMENT_ROBODOC);
163       fprintf (dest_doc, "@rem " COMMENT_COPYRIGHT);
164       fprintf (dest_doc, "@node Main %s\n", name);
165       fprintf (dest_doc, "@{jcenter}\n");
166       fprintf (dest_doc,
167                "@{fg highlight}@{b}TABLE OF CONTENTS@{ub}@{fg text}\n\n");
168
169       max_len = 0;
170       for (cur_header = first_header;
171            cur_header;
172            cur_header = cur_header->next_header)
173         {
174           if (cur_header->name)
175             {
176               cur_len = strlen (cur_header->name);
177               if (cur_len > max_len)
178                 max_len = cur_len;
179             }
180         }
181
182       for (cur_header = first_header;
183            cur_header;
184            cur_header = cur_header->next_header)
185         {
186           if (cur_header->name && cur_header->function_name)
187             {
188               fprintf (dest_doc, "@{\"%s", cur_header->name);
189
190               for (cur_len = strlen (cur_header->name);
191                    cur_len < max_len;
192                    ++cur_len)
193                 fputc (' ', dest_doc);
194               fprintf (dest_doc, "\" Link \"%s\"}\n", cur_header->function_name);
195             }
196         }
197
198       fprintf (dest_doc, "@{jleft}\n");
199       fprintf (dest_doc, "@endnode\n");
200       break;
201
202     case HTML:
203       /* Append document type and title */
204       fprintf (dest_doc,
205                "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n");
206       fprintf (dest_doc, "<HTML><HEAD>\n<TITLE>%s</TITLE>\n", name);
207
208       /* append SGML-comment with document- and copyright-info. This code
209        * ensures that every line has an own comment to avoid problems with 
210        * buggy browsers */
211       fprintf (dest_doc, "<!-- Source: %s -->\n", src_name);
212       {
213         static const char copyright_text[]
214         = COMMENT_ROBODOC COMMENT_COPYRIGHT;
215         size_t i = 0;
216         char previous_char = '\n';
217         char current_char = copyright_text[i];
218
219         while (current_char)
220           {
221             if (previous_char == '\n')
222               {
223                 fprintf (dest_doc, "<!-- ");
224               }
225             if (current_char == '\n')
226               {
227                 fprintf (dest_doc, " -->");
228               }
229             else if ((current_char == '-') && (previous_char == '-'))
230               {
231                 /* avoid "--" inside SGML-comment, and use "-_" instead; this
232                  * looks a bit strange, but one should still be able to figure 
233                  * out what is meant when reading the output */
234                 current_char = '_';
235               }
236             fputc (current_char, dest_doc);
237             i += 1;
238             previous_char = current_char;
239             current_char = copyright_text[i];
240           }
241       }
242
243       /* append heading and start list of links to functions */
244       fprintf (dest_doc, "</HEAD><BODY BGCOLOR=\"#FFFFFF\">\n");
245 #if 0
246       fprintf (dest_doc, "<A NAME=\"%s\">Generated from %s</A> with ROBODoc v"
247                VERSION
248                " on ",
249                src_name, src_name);
250       RB_TimeStamp (dest_doc);
251 #endif
252       fprintf (dest_doc, "<BR>\n");
253       if (toc)
254         {
255           char iname[256];
256           FILE *index;
257           int start = 0;
258
259           /* do toc if not in fold */
260 #if 0
261           fprintf (dest_doc,
262                    "<H3 ALIGN=\"center\">TABLE OF CONTENTS</H3>\n");
263 #endif
264           fprintf (dest_doc, "<OL>\n");
265
266           /* Generate quick index file, for fast referencing */
267           sprintf(iname, "%s_index.html", doc_base);
268           index = fopen(iname, "w");
269
270           for (cur_header = first_header;
271                cur_header;
272                cur_header = cur_header->next_header)
273             {
274               char fname[256];
275
276               sprintf(fname, "%s_%s.html", doc_base, 
277                       cur_header->function_name);
278
279               if (cur_header->name && cur_header->function_name)
280                 {
281                   if (start == 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                       start = 1;
330                     }
331                   else
332                     {
333                       fprintf (dest_doc, "<LI><A HREF=\"%s\">%s</A>\n",
334                                fname, cur_header->name);
335                       if (index)
336                         fprintf (index, " >> <A HREF=\"%s\">%s</A><BR>\n",
337                                  fname, cur_header->function_name);
338                     }
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 #if 0
1263                           fprintf (dest_doc, "<A HREF=\"#%s\">%s</A>",
1264                                    label_name, label_name);
1265 #endif
1266                           fprintf (dest_doc, "<A HREF=\"%s_%s.html\">%s</A>",
1267                                    doc_base, label_name, label_name);
1268                         }
1269                       else
1270                         {
1271                           fprintf (dest_doc, "%s",
1272                                  att_start_command[MAKE_BOLD][output_mode]);
1273                           fprintf (dest_doc, "%s", label_name);
1274                           fprintf (dest_doc, "%s",
1275                                    att_stop_command[MAKE_BOLD][output_mode]);
1276                         }
1277                     }
1278                   break;
1279
1280                 case RTF:
1281                   if (strcmp (label_name, function_name))
1282                     {
1283                       char *cook_link;
1284
1285                       cook_link = RB_CookStr (label_name);
1286                       fprintf (dest_doc, "{\\uldb %s}{\\v %s}",
1287                                label_name, cook_link);
1288                       free (cook_link);
1289                     }
1290                   else
1291                     {
1292                       fprintf (dest_doc, "%s",
1293                                att_start_command[MAKE_BOLD][output_mode]);
1294                       fprintf (dest_doc, "%s", label_name);
1295                       fprintf (dest_doc, "%s",
1296                                att_stop_command[MAKE_BOLD][output_mode]);
1297                     }
1298                   break;
1299                 default:
1300                   fprintf (dest_doc, "%s", label_name);
1301                 }
1302               tmp = strlen (label_name);
1303               cur_char += tmp;
1304               tb += tmp;
1305             }                   /* end if */
1306         }
1307
1308       if (*cur_char)
1309         {
1310           if (output_mode == RTF)
1311             fprintf (dest_doc, "\\line");
1312           fputc ('\n', dest_doc);
1313           tabs = 0;
1314         }
1315     }
1316   *end_of_item = old_char;
1317   return (char *) 0;
1318 }
1319
1320
1321 /***************/
1322
1323
1324 /****f* ROBODoc/RB_HTML_Extra
1325 * NAME
1326 *   RB_HTML_Extra
1327 * AUTHOR
1328 *   PetteriK
1329 * HISTORY
1330 *   05/15/2000 Added mailto: support (Guillaume Etorre)
1331 * FUNCTION
1332 *   Check and process embedded hyperlinks.
1333 * RETURN VAL* FUNCTION
1334 *   Check and process embedded hyperlinks.
1335 * RETURN VALUE
1336 *   Number of chars processed from *cur_char
1337 * TODO
1338 *   Flag for C and other grammars.
1339 * BUGS
1340 *   As the documentation generated for this functions shows, if
1341 *   the C source code contains a string with " / * " in it, this
1342 *   function fails :)
1343 * SOURCE
1344 */
1345
1346 int
1347 RB_HTML_Extra (FILE * dest_doc, int item_type, char *cur_char)
1348 {
1349   int res = 0;
1350   char link[1024];
1351
1352   if (strncmp ("http://", cur_char, strlen ("http://")) == 0)
1353     {
1354       sscanf (cur_char, "%s", link);
1355       RB_Say ("found link %s\n", link);
1356       res = (strlen (link) - 1);
1357       fprintf (dest_doc, "<A HREF=\"%s\">%s</A>", link, link);
1358     }
1359   else if (strncmp ("href:", cur_char, strlen ("href:")) == 0)
1360     {
1361       /* handy in relative hyperlink paths, e.g. href:../../modulex/ */
1362       sscanf ((cur_char + strlen ("href:")), "%s", link);
1363       RB_Say ("found link %s\n", link);
1364       res = (strlen (link) + strlen ("href:") - 1);
1365       fprintf (dest_doc, "<A HREF=\"%s\">%s</A>", link, link);
1366     }
1367   else if (strncmp ("mailto:", cur_char, strlen ("mailto:")) == 0)
1368     {
1369       sscanf ((cur_char + strlen ("mailto:")), "%s", link);
1370       RB_Say ("found mail to %s\n", link);
1371       res = (strlen (link) + strlen ("mailto:") - 1);
1372       fprintf (dest_doc, "<A HREF=\"mailto:%s\">%s</A>", link, link);
1373     }
1374   else if ((extra_flags & C_MODE) && (item_type == SOURCE_ITEM) &&
1375            (strncmp ("/*", cur_char, 2) == 0))
1376     {
1377       /* start of C comment */
1378       fprintf (dest_doc, "<FONT COLOR = \"#FF0000\">/*");
1379       res = 1;
1380     }
1381   else if ((extra_flags & C_MODE) && (item_type == SOURCE_ITEM) &&
1382            (strncmp ("*/", cur_char, 2) == 0))
1383     {
1384       /* end of C comment */
1385       fprintf (dest_doc, "*/</FONT>");
1386       res = 1;
1387     }
1388   return res;
1389 }
1390
1391 /**********/
1392
1393
1394 /****f* ROBODoc/RB_Generate_Index
1395  * NAME
1396  *   RB_Generate_Index -- generate index file based on xref files.
1397  * SYNOPSIS
1398  *   void RB_Generate_Index(FILE *dest, char *name) 
1399  * FUNCTION
1400  *   Create a master index file. It contains pointers to the
1401  *   documentation generated for each source file, as well as all
1402  *   "objects" found in the source files.
1403  ********
1404  */
1405
1406 void
1407 RB_Generate_Index (FILE * dest, char *source)
1408 {
1409   RB_Slow_Sort_Links ();
1410
1411   switch (output_mode)
1412     {
1413     case HTML:
1414       {
1415         if (document_title) {
1416           RB_Generate_Doc_Start (dest, source, document_title, 0);
1417           fprintf (dest, "<H1>%s</H1>\n", document_title);
1418         } else {
1419           RB_Generate_Doc_Start (dest, source, "Master Index File", 0);
1420           fprintf (dest, "<H1>Master Index File</H1>\n");
1421         }
1422         if (RB_Number_Of_Links (MAIN_HEADER, NULL))
1423           RB_Generate_Index_Table (dest, MAIN_HEADER, "Project Modules");
1424         RB_Generate_Index_Table (dest, NO_HEADER, "Source Files");
1425         if (RB_Number_Of_Links (CLASS_HEADER, NULL))
1426           RB_Generate_Index_Table (dest, CLASS_HEADER, "Classes");
1427         if (RB_Number_Of_Links (METHOD_HEADER, NULL))
1428           RB_Generate_Index_Table (dest, METHOD_HEADER, "Methods");
1429         if (RB_Number_Of_Links (STRUCT_HEADER, NULL))
1430           RB_Generate_Index_Table (dest, STRUCT_HEADER, "Structures");
1431         if (RB_Number_Of_Links (FUNCTION_HEADER, NULL))
1432           RB_Generate_Index_Table (dest, FUNCTION_HEADER, "Functions");
1433         if (RB_Number_Of_Links (VARIABLE_HEADER, NULL))
1434           RB_Generate_Index_Table (dest, VARIABLE_HEADER, "Variables");
1435         if (RB_Number_Of_Links (CONSTANT_HEADER, NULL))
1436           RB_Generate_Index_Table (dest, CONSTANT_HEADER, "Constants");
1437         if (RB_Number_Of_Links (GENERIC_HEADER, NULL))
1438           RB_Generate_Index_Table (dest, GENERIC_HEADER, "Generic");
1439         if (RB_Number_Of_Links (INTERNAL_HEADER, NULL))
1440           RB_Generate_Index_Table (dest, INTERNAL_HEADER, "Internal");
1441         RB_Generate_Doc_End (dest, source);
1442       } break;
1443     case LATEX:
1444       {
1445         RB_Generate_Doc_Start (dest, source, "Master File", 0);
1446         RB_Generate_LaTeX_Includes (dest);
1447         RB_Generate_Doc_End (dest, source);
1448       }
1449     }
1450 }
1451
1452
1453 /****f* ROBODoc/Generate_LaTeX_Includes
1454  * NAME
1455  *   Generate_LaTeX_Includes -- generate include commands
1456  * SYNOPSIS
1457  *   void RB_Generate_LaTeX_Includes (FILE *dest)
1458  * FUNCTION
1459  *   Generates a series of \include commands to include the
1460  *   documentation generated for each source file into one
1461  *   big file.
1462  ****
1463  */
1464
1465 void
1466 RB_Generate_LaTeX_Includes (FILE *dest)
1467 {
1468   struct RB_link *cur_link;
1469   for (cur_link = first_link;
1470        cur_link;
1471        cur_link = cur_link->next_link) {
1472     {
1473       if (cur_link->type == NO_HEADER)
1474         fprintf (dest, "\\include{%s}\n", cur_link->label_name);
1475     }
1476   }
1477 }
1478
1479 /****f* ROBODoc/RB_Generate_Index_Table
1480  * NAME
1481  *   RB_Generate_Index --
1482  * SYNOPSIS
1483  *   void RB_Generate_Index_Table(FILE *, int type, char *title)
1484  *        RB_Generate_Index_Table(dest, type, title)
1485  * FUNCTION
1486  *   Creates a table with index items of a particular type.
1487  *   If the type is NO_HEADER, then the table is a table of
1488  *   source files. In this case no link is added if the
1489  *   source file did not contain any documentation.  
1490  * INPUTS
1491  *   dest  -- output file
1492  *   type  -- kind of header index. 
1493  *   title -- title for the table
1494  * SOURCE
1495  */
1496
1497 void
1498 RB_Generate_Index_Table (FILE * dest, int type, char *title)
1499 {
1500   struct RB_link *cur_link;
1501   int number_of_columns;
1502   int cur_column;
1503
1504   number_of_columns = 60 / RB_Max_Name_Length (type, NULL);
1505
1506   fprintf (dest, "<H2>%s</H2>\n", title);
1507   fprintf (dest, "<TABLE>\n");
1508   cur_column = 0;
1509   for (cur_link = first_link;
1510        cur_link;
1511        cur_link = cur_link->next_link)
1512     {
1513       if (cur_link->type == type)
1514         {
1515           if (cur_column == 0)
1516             {
1517               fprintf (dest, "<TR>\n");
1518             }
1519           if (type == NO_HEADER)
1520             {
1521               if (RB_Number_Of_Links (NO_HEADER, cur_link->file_name) > 1)
1522                 {
1523                   fprintf (dest,
1524                            "<TD><A HREF=\"%s#%s\"><TT>%s</TT></A></TD>\n",
1525                            cur_link->file_name, cur_link->label_name,
1526                            cur_link->label_name);
1527                 }
1528               else
1529                 {
1530                   fprintf (dest, "<TD>%s</TD>\n", cur_link->label_name);
1531                 }
1532             }
1533           else
1534             {
1535               fprintf (dest, "<TD><A HREF=\"%s#%s\"><TT>%s</TT></A></TD>\n",
1536                        cur_link->file_name, cur_link->label_name,
1537                        cur_link->label_name);
1538             };
1539           cur_column++;
1540           if (cur_column > number_of_columns)
1541             {
1542               fprintf (dest, "</TR>\n");
1543               cur_column = 0;
1544             }
1545         }
1546     }
1547   for (; cur_column <= number_of_columns;)
1548     {
1549       if (cur_column == 0)
1550         {
1551           fprintf (dest, "<TR>\n");
1552         }
1553       fprintf (dest, "<TD></TD>\n");
1554       cur_column++;
1555     }
1556   fprintf (dest, "</TR>\n");
1557   fprintf (dest, "</TABLE>\n");
1558 }
1559
1560 /******* END RB_Generate_Index_Table  *****/
1561
1562
1563 /****f* ROBODoc/RB_Number_Of_Links
1564  * NAME
1565  *   RB_Number_Of_Links -- Count the number of links.
1566  * FUNCTION
1567  *   Counts the number of links that are of a particular type
1568  *   and that can be found in a particular file.
1569  * INPUTS
1570  *   type      -- the header type of the header the link is pointing to.
1571  *                If NO_HEADER, all header types are counted.
1572  *   file_name -- name of the file the link comes from, can be NULL, in
1573  *                which case only the type is checked.
1574  * RESULT
1575  *   number of links.
1576  ******
1577  */
1578
1579 int
1580 RB_Number_Of_Links (int type, char *file_name)
1581 {
1582   struct RB_link *cur_link;
1583   int n = 0;
1584
1585   for (cur_link = first_link;
1586        cur_link;
1587        cur_link = cur_link->next_link)
1588     {
1589       if (cur_link->type == type || (type == NO_HEADER))
1590         {
1591           if (file_name)
1592             {
1593               if (strcmp (file_name, cur_link->file_name) == 0)
1594                 {
1595                   n++;
1596                 }
1597             }
1598           else
1599             {
1600               n++;
1601             }
1602         }
1603     }
1604
1605   return n;
1606 }
1607
1608
1609 /****f* ROBODoc/RB_Max_Name_Length
1610  * NAME
1611  *   RB_Max_Name_Length -- find longest label name.
1612  * FUNCTION
1613  *   Find the length of the longest label name in a sub list
1614  *   of the list with links.  This is used to determine how
1615  *   many columns can be displayed in a table.
1616  *   The sublist is specified by the type of header the link
1617  *   should point to, as well as by the name of the documentation 
1618  *   file.
1619  * EXAMPLE
1620  *     RB_Max_Name_Length(CLASS_HEADER, "muppets.c.html")
1621  *   longest label name in the list of links to class headers 
1622  *   in muppets.c.html.
1623  *     RB_Max_Name_Length(CLASS_HEADER, NULL)
1624  *   longest label name in the list of links to class headers.
1625  * INPUTS
1626  *   type      -- type of header
1627  *   file_name -- file the header come from, can be NULL.
1628  *                In which links from all files are used.
1629  * SOURCE
1630  */
1631
1632 int
1633 RB_Max_Name_Length (int type, char *file_name)
1634 {
1635   struct RB_link *cur_link;
1636   int n = 1;
1637
1638   for (cur_link = first_link;
1639        cur_link;
1640        cur_link = cur_link->next_link)
1641     {
1642       if (cur_link->type == type)
1643         {
1644           if (file_name)
1645             {
1646               if (strcmp (file_name, cur_link->file_name) == 0)
1647                 {
1648                   if (strlen (cur_link->label_name) > n)
1649                     {
1650                       n = strlen (cur_link->label_name);
1651                     }
1652                 }
1653             }
1654           else
1655             {
1656               if (strlen (cur_link->label_name) > n)
1657                 {
1658                   n = strlen (cur_link->label_name);
1659                 }
1660             }
1661         }
1662     }
1663   return n;
1664 }
1665
1666 /*********/