addition of silc.css
[silc.git] / util / robodoc / Source / analyser.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <ctype.h>
4 #include <string.h>
5
6 #include "robodoc.h"
7 #include "headers.h"
8 #include "items.h"
9 #include "util.h"
10 #include "folds.h"
11 #include "links.h"
12 #include "analyser.h"
13
14
15 /****** ROBODoc/RB_Analyse_Document [3.0i]
16  * NAME
17  *   RB_Analyse_Document -- scan document for headers and store them
18  * SYNOPSIS
19  *   RB_Analyse_Document (document)
20  *   RB_Analyse_Document (FILE *)
21  * FUNCTION
22  *   Searches the document for headers. Stores information about
23  *   any headers that are found in a linked list. Information
24  *   that is stored includes, the name of the header, its version
25  *   number, and its contents.
26  * INPUTS
27  *   document - a pointer to a file with the document to be
28  *              analysed
29  *   the gobal buffer line_buffer.
30  * RESULT
31  *   1)   A linked list pointed to by the global variable
32  *        first_header that contains information about each
33  *        header.
34  * NOTES
35  *   Using fseek and ftell because gcc doesn't know fgetpos and fsetpos,
36  *   on the sun unix system that I use.
37  * SEE ALSO
38  *   RB_Find_Marker
39  * SOURCE
40  */
41
42 void
43 RB_Analyse_Document (FILE * document)
44 {
45   int header_type;
46   int real_size;
47   char *name;
48
49   for (;
50        (header_type = RB_Find_Marker (document)) != NO_HEADER;
51        )
52     {
53       struct RB_header *new_header;
54       
55       if (!
56           (
57            ((header_type == INTERNAL_HEADER) &&
58             !(course_of_action & (DO_INCLUDE_INTERNAL | DO_INTERNAL_ONLY)))
59            ||
60            ((header_type != INTERNAL_HEADER) &&
61             (course_of_action & DO_INTERNAL_ONLY))
62            ||
63            (header_type == BLANK_HEADER)
64            )
65           )
66         {
67           long cur_file_pos;
68           
69           new_header = RB_Alloc_Header ();
70           RB_Insert_In_List (&first_header, new_header);
71           new_header->type = header_type;
72           if ((new_header->name = RB_Find_Header_Name ()) != NULL)
73             {
74               RB_Say ("found header [line %5d]: \"%s\"\n",
75                       line_number, new_header->name);
76               if ((new_header->function_name
77                    = RB_Function_Name (new_header->name)) == NULL)
78                 {
79                   RB_Panic ("Can't determine the \"function\" name.\n");
80                 }
81               cur_file_pos = (long) ftell (document);
82               if ((real_size = RB_Find_End_Marker (document,
83                                                    &new_header->size))
84                   != 0)
85                 {
86                   char *contents;
87                   
88                   fseek (document, cur_file_pos, 0);
89                   if ((contents = malloc ((new_header->size +
90                                            2) * sizeof (char)))
91                       != NULL)
92                     {
93                       fread (contents, new_header->size, sizeof (char), document);
94                       
95                       contents[real_size] = '\0';
96                       new_header->contents = contents;
97                       new_header->size = real_size;
98                     }
99                   else
100                     RB_Panic ("out of memory! [Alloc Header Contents]\n");
101                 }
102               else
103                 {
104                   RB_Panic ("found header with no end marker \"%s\"\n",
105                             new_header->name);
106                 }
107             }
108           else
109             {
110               RB_Panic ("found header marker but no name [line %d]\n",
111                         line_number);
112             }
113         }
114       else
115         {
116           if (header_type != BLANK_HEADER)
117             {
118               if ((name = RB_Find_Header_Name ()) != NULL)
119                 {
120                   new_header = RB_Alloc_Header ();
121                   if ((real_size =
122                        RB_Find_End_Marker (document, &new_header->size))
123                       == 0)
124                     {
125                       RB_Free_Header (new_header);
126                       RB_Panic ("found header with no end marker \"%s\"\n", name);
127                     }
128                   else
129                     {
130                       RB_Free_Header (new_header);
131                     }
132                 }
133               else
134                 {
135                   RB_Panic ("found header marker but no name [line %d]\n",
136                             line_number);
137                 }
138             }
139         }
140     }
141 }
142
143 /****** END RB_Analyse_Document *******/
144
145
146
147
148 /****f* ROBODoc/RB_Function_Name [2.0x]
149  * NAME
150  *   RB_Function_Name -- get pointer to the function name.
151  * SYNOPSIS
152  *   char *RB_NamePart(char *header_name)
153  * FUNCTION
154  *   A header name is consists of two parts. The module name and
155  *   the function name. This returns a pointer to the function name.
156  *   The name "function name" is a bit obsolete. It is really the name
157  *   of any of objects that can be documented; classes, methods,
158  *   variables, functions, projects, etc.
159  * SOURCE
160  */
161
162 char *
163 RB_Function_Name (char *header_name)
164 {
165   char *cur_char;
166   char c;
167   char *name;
168
169   name = NULL;
170   if ((cur_char = header_name) != NULL)
171     {
172       for (; (c = *cur_char) != '\0'; ++cur_char)
173         {
174           if ('/' == *cur_char)
175             {
176               ++cur_char;
177               if (*cur_char)
178                 name = cur_char;
179             }
180         }
181     }
182   if (name) {
183      char *temp;
184      temp = malloc((strlen(name) + 1) * sizeof(char));
185      strcpy(temp, name);
186      return temp; 
187   } else {
188      return (name);
189   }
190 }
191
192 /*** RB_Name_Part ***/
193
194
195
196 /****** ROBODoc/RB_Find_Marker [3.0h]
197  * NAME
198  *   RB_Find_Marker -- Search for header marker in document.
199  * SYNOPSIS
200  *   header_type = RB_Find_Marker (document)
201  *             int RB_Find_Marker (FILE *)
202  * FUNCTION
203  *   Read document file line by line, and search each line for the
204  *   any of the headers defined in the array  header_markers
205  * INPUTS
206  *   document - pointer to the file to be searched.
207  *   the gobal buffer line_buffer.
208  * RESULT
209  *   header type
210  *   can be:
211  *    (1) NO_HEADER - no header found, end of file reached
212  *    (2) MAIN_HEADER
213  *    (3) GENERIC_HEADER
214  *    (4) INTERNAL_HEADER
215  * BUGS
216  *   Bad use of feof(), fgets().
217  * SEE ALSO
218  *   RB_Find_End_Marker
219  * SOURCE
220  */
221
222 int
223 RB_Find_Marker (FILE * document)
224 {
225   int found;
226   int marker, marker_type;
227   char *cur_char, *cur_mchar;
228
229   marker_type = NO_HEADER;
230   cur_char = NULL;
231   found = FALSE;
232   while (!feof (document) && !found)
233     {
234       *line_buffer = '\0';
235       fgets (line_buffer, MAX_LINE_LEN, document);
236       if (!feof (document))
237         {
238           line_number++;
239           for (marker = 0;
240                ((cur_mchar = header_markers[marker]) != NULL) && !found;
241                marker++)
242             {
243               for (found = TRUE, cur_char = line_buffer;
244                    *cur_mchar && *cur_char && found;
245                    cur_mchar++, cur_char++)
246                 {
247                   if (tolower(*cur_mchar) != tolower(*cur_char))
248                     found = FALSE;
249                 }
250             }
251           if (found)
252             {
253               switch (*cur_char)
254                 {
255                 case 'h':
256                   marker_type = MAIN_HEADER;
257                   break;
258                 case '*':
259                   marker_type = GENERIC_HEADER;
260                   break;
261                 case 'i':
262                   marker_type = INTERNAL_HEADER;
263                   break;
264                 case 'f':
265                   marker_type = FUNCTION_HEADER;
266                   break;
267                 case 's':
268                   marker_type = STRUCT_HEADER;
269                   break;
270                 case 'c':
271                   marker_type = CLASS_HEADER;
272                   break;
273                 case 'm':
274                   marker_type = METHOD_HEADER;
275                   break;
276                 case 'd':
277                   marker_type = CONSTANT_HEADER;
278                   break;
279                 case 'v':
280                   marker_type = VARIABLE_HEADER;
281                   break;
282                 default:
283                   RB_Say ("%s: WARNING, [line %d] undefined headertype,"
284                           " using GENERIC\n", whoami, line_number);
285                   marker_type = GENERIC_HEADER;
286                 }
287             }
288         }
289     }
290   if (!found || feof (document))
291     {
292       marker_type = NO_HEADER;
293     }
294   else if (marker_type == GENERIC_HEADER)
295     {
296       skip_while (*cur_char == '*');
297       if (*cur_char == '/')
298         {
299           marker_type = BLANK_HEADER;
300         }
301     }
302   return marker_type;
303 }
304
305 /******** END RB_Find_Marker ******/
306
307
308 /****** ROBODoc/RB_Find_End_Marker [3.0h]
309  * NAME
310  *   RB_Find_End_Marker -- Search for end marker in document.
311  * SYNOPSIS
312  *   result = RB_Find_End_Marker (document)
313  *        int RB_Find_End_Marker (FILE *)
314  * FUNCTION
315  *   Searches line by line till any of the markers in the
316  *   array: end_markers is found.
317  * INPUTS
318  *   document   - pointer to the file to be searched.
319  *   int *total_size - external size
320  *   the gobal buffer line_buffer.
321  * RESULT
322  *                real_size if end marker was found
323  *   0          - no end marker was found
324  * SEE ALSO
325  *   RB_Find_Marker
326  * SOURCE
327  */
328
329 int
330 RB_Find_End_Marker (FILE * document, int *total_size)
331 {
332   int real_size = 0;
333   int found = FALSE;
334   int marker;
335   int line_len = 0;
336   char *cur_char, *cur_mchar;
337
338   while (!feof (document) && !found)
339     {
340       cur_char = line_buffer;
341       *cur_char = '\0';
342       fgets (cur_char, MAX_LINE_LEN, document);
343       ++line_number;            /* global linecounter *koessi */
344
345       line_len = strlen (cur_char);
346       real_size += line_len;
347
348       if (!feof (document))
349         {
350           for (marker = 0;
351                ((cur_mchar = end_markers[marker]) != NULL) && !found;
352                marker++)
353             {
354               for (found = TRUE, cur_char = line_buffer;
355                    *cur_mchar && *cur_char && found;
356                    cur_mchar++, cur_char++)
357                 {
358                   if (tolower(*cur_mchar) != tolower(*cur_char))
359                     found = FALSE;
360                 }
361             }
362         }
363     }
364   if (total_size)
365     *total_size = real_size;
366   if (found)
367     return real_size - line_len;
368   else
369     return 0;
370 }
371
372 /*****  RB_Find_End_Marker   *****/
373
374
375 /****** ROBODoc/RB_Find_Header_Name   [3.0b]
376  * NAME
377  *   RB_Find_Header_Name -- search for header name
378  * SYNOPSIS
379  *   result = RB_Find_Header_Name ()
380  *      char *RB_Find_Header_Name ()
381  * FUNCTION
382  *   Searches the line buffer for the header name.
383  *   It assumes that the header name follows after the
384  *   header marker, seperated by one or more spaces, and terminated
385  *   by one or more spaces or a '\n'.
386  *   It allocates an array of chars and copies the name to this array.
387  * INPUTS
388  *   the gobal buffer line_buffer.
389  * RESULT
390  *   pointer to the allocated array of chars that contains the name,
391  *   terminated with a '\0'.
392  *   NULL if no header name was found.
393  * MODIFICATION HISTORY
394  *   8. August 1995      --  optimized by koessi
395  * SEE ALSO
396  *   RB_Find_Function_Name(), RB_WordLen(), RB_StrDup()
397  * SOURCE
398  */
399
400 char *
401 RB_Find_Header_Name (void)
402 {
403   char *cur_char;
404
405   cur_char = line_buffer;
406   skip_while (*cur_char != '*');
407   skip_while (!isspace (*cur_char));
408   skip_while (isspace (*cur_char));
409   if (*cur_char)
410     {
411       char *end_char, old_char;
412
413       end_char = cur_char + RB_WordLen (cur_char);
414       old_char = *end_char;
415       *end_char = '\0';
416       cur_char = RB_StrDup (cur_char);
417       *end_char = old_char;
418       return (cur_char);
419     }
420   return (NULL);
421 }
422
423 /*****  RB_Find_Header_Name  *****/
424
425
426 /****** ROBODoc/RB_Find_Item [3.0b]
427  * NAME
428  *   RB_Find_Item -- find item in header contents.
429  * SYNOPSIS
430  *   item_type = RB_Find_Item (next_line,item_line)
431  *
432  *           int RB_Find_Item (char **,  char **)
433  * FUNCTION
434  *   Searches the header contents line by line, looking
435  *   for an item Indicator.
436  * INPUTS
437  *   next_line  - pointer to a pointer that points to line
438  *                at which the search will start.
439  * SIDE-EFFECTS
440  *   next_line  - pointer to a pointer that points to begin of the line
441  *                after the line the item was found on.
442  *   item_line  - pointer to a pointer that points to the line the item
443  *                was found on.
444  * RESULT
445  *   item_type  - one of possible items indicators.
446  * SOURCE
447  */
448
449 int
450 RB_Find_Item (char **next_line, char **item_line)
451 {
452   char *cur_char = *next_line;
453   int item_type;
454
455   for (item_type = NO_ITEM;
456        *cur_char && (item_type == NO_ITEM);
457     )
458     {
459       *item_line = cur_char;
460       cur_char = RB_Skip_Remark_Marker (cur_char);
461
462       skip_while (isspace (*cur_char) && *cur_char != '\n');
463       if (isupper (*cur_char))
464         {
465           char *item_begin = cur_char;
466           char *item_end;
467
468           skip_while (isupper (*cur_char));
469           item_end = cur_char;
470           if (isspace (*cur_char) && *cur_char)
471             {
472               skip_while (isspace (*cur_char) && *cur_char != '\n');
473
474               /* Item consists of two words ? */
475               if (isupper (*cur_char) && *cur_char)
476                 {
477                   skip_while (isupper (*cur_char));
478                   item_end = cur_char;
479                   skip_while (isspace (*cur_char) && *cur_char != '\n');
480                 }
481               if (*cur_char == '\n')
482                 {
483                   char old_char = *item_end;
484
485                   *item_end = '\0';
486                   item_type = RB_Get_Item_Type (item_begin);
487                   *item_end = old_char;
488                   cur_char++;
489                 }
490             }
491         }
492       if (item_type == NO_ITEM)
493         {
494           find_eol;
495           if (*cur_char)
496             cur_char++;
497         }
498     }
499
500   /* advance item_line to end of comment block when we have no more items */
501   if (item_type == NO_ITEM)
502     {
503       *item_line = cur_char;
504     }
505   *next_line = cur_char;
506   return item_type;
507 }
508
509 /*****  RB_Find_Item    *****/
510
511
512 /****** ROBODoc/RRB_Number_Duplicate_Headers 
513  * NAME
514  *    RB_Number_Duplicate_Headers -- number duplicate headers
515  * SYNOPSIS
516  *    RB_Number_Duplicate_Headers (void)
517  * FUNCTION
518  *    Extends the function name with an additional number if there 
519  *    are several components with the same name.
520  *    Otherwise there will be labels with the same name in HTML
521  *    which confuses the browser.
522  * SOURCE
523  */
524
525 void 
526 RB_Number_Duplicate_Headers (void)
527 {
528   struct RB_header *cur_header;
529   struct RB_header *dup_header;
530   for (cur_header = first_header; 
531        cur_header;
532        cur_header = cur_header->next_header)
533   {  
534     char number[20];
535     int  nr = 0;
536     for (dup_header = cur_header->next_header; 
537          dup_header;
538          dup_header = dup_header->next_header)
539     {
540        if (strcmp(cur_header->function_name,
541                   dup_header->function_name) == 0) {
542           char *new_name;
543           nr++;
544           sprintf(number, "(%d)", nr);
545           new_name = malloc ((strlen(number) + 1 + 
546               strlen(dup_header->function_name) + 1 ) * sizeof(char));
547           if (new_name == NULL) 
548              RB_Panic ("out of memory! [Number Duplicates]\n");
549           sprintf(new_name, "%s%s", dup_header->function_name,
550                   number);
551           free(dup_header->function_name);
552           dup_header->function_name = new_name;
553        }
554     }
555   }
556 }
557
558 /******/
559
560
561 /****** ROBODoc/RB_Make_Index_Tables [3.0b]
562  * NAME
563  *    RB_Make_Index_Tables
564  * SYNOPSIS
565  *    void RB_Make_Index_Tables (void)
566  * FUNCTION
567  *    Creates sorted index tables of headers and links to speed up
568  *    matching links later on.
569  * INPUTS
570  *    none
571  * SIDE EFFECTS
572  *    Modifies header_index & link_index
573  * RESULT
574  *    none
575  * SOURCE
576  */
577
578 void
579 RB_Make_Index_Tables ()
580 {
581   int nr_of_headers, header;
582   int nr_of_links, link;
583   struct RB_link *cur_link;
584   struct RB_header *cur_header;
585
586   for (cur_header = first_header, nr_of_headers = 0;
587        cur_header;
588        cur_header = cur_header->next_header)
589     nr_of_headers++;
590
591   for (cur_link = first_link, nr_of_links = 0;
592        cur_link;
593        cur_link = cur_link->next_link)
594     nr_of_links++;
595
596   if (nr_of_headers)
597     {
598       int sort1, sort2;
599
600       RB_Say ("Allocating Header Index Table\n");
601       header_index = malloc (nr_of_headers * sizeof (struct RB_header **));
602
603       header_index_size = nr_of_headers;
604       if (!header_index)
605         RB_Panic ("out of memory! [Make Index Tables]\n");
606
607       /* Fill Index Table */
608       for (cur_header = first_header, header = 0;
609            cur_header;
610            cur_header = cur_header->next_header, header++)
611         header_index[header] = cur_header;
612
613       /* Sort Index Table */
614       RB_Say ("Sorting Header Index Table\n");
615       for (sort1 = 0; sort1 < nr_of_headers; sort1++)
616         {
617           struct RB_header *temp;
618
619           for (sort2 = sort1; sort2 < nr_of_headers; sort2++)
620             {
621               if (strcmp (header_index[sort1]->function_name,
622                           header_index[sort2]->function_name) > 0)
623                 {
624                   temp = header_index[sort1];
625                   header_index[sort1] = header_index[sort2];
626                   header_index[sort2] = temp;
627                 }
628             }
629         }
630     }
631   if (nr_of_links)
632     {
633       int sort1, sort2;
634
635       RB_Say ("Allocating Link Index Table\n");
636       link_index = malloc (nr_of_links * sizeof (struct RB_link **));
637
638       link_index_size = nr_of_links;
639       if (!link_index)
640         RB_Panic ("out of memory! [Make Index Tables]\n");
641
642       /* Fill Index Table */
643       for (cur_link = first_link, link = 0;
644            cur_link;
645            cur_link = cur_link->next_link, link++)
646         {
647           link_index[link] = cur_link;
648         }
649
650       /* Sort Index Table */
651       RB_Say ("Sorting Link Index Table\n");
652       for (sort1 = 0; sort1 < nr_of_links; sort1++)
653         {
654           struct RB_link *temp;
655
656           for (sort2 = sort1; sort2 < nr_of_links; sort2++)
657             {
658               if (strcmp (link_index[sort1]->label_name,
659                           link_index[sort2]->label_name) > 0)
660                 {
661                   temp = link_index[sort1];
662                   link_index[sort1] = link_index[sort2];
663                   link_index[sort2] = temp;
664                 }
665             }
666         }
667     }
668 }
669
670 /****** RB_Make_Index_Tables  *****/