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