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