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