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