Initial revision
[silc.git] / util / robodoc / Source / analyser.c
diff --git a/util/robodoc/Source/analyser.c b/util/robodoc/Source/analyser.c
new file mode 100644 (file)
index 0000000..50af048
--- /dev/null
@@ -0,0 +1,670 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "robodoc.h"
+#include "headers.h"
+#include "items.h"
+#include "util.h"
+#include "folds.h"
+#include "links.h"
+#include "analyser.h"
+
+
+/****** ROBODoc/RB_Analyse_Document [3.0i]
+ * NAME
+ *   RB_Analyse_Document -- scan document for headers and store them
+ * SYNOPSIS
+ *   RB_Analyse_Document (document)
+ *   RB_Analyse_Document (FILE *)
+ * FUNCTION
+ *   Searches the document for headers. Stores information about
+ *   any headers that are found in a linked list. Information
+ *   that is stored includes, the name of the header, its version
+ *   number, and its contents.
+ * INPUTS
+ *   document - a pointer to a file with the document to be
+ *              analysed
+ *   the gobal buffer line_buffer.
+ * RESULT
+ *   1)   A linked list pointed to by the global variable
+ *        first_header that contains information about each
+ *        header.
+ * NOTES
+ *   Using fseek and ftell because gcc doesn't know fgetpos and fsetpos,
+ *   on the sun unix system that I use.
+ * SEE ALSO
+ *   RB_Find_Marker
+ * SOURCE
+ */
+
+void
+RB_Analyse_Document (FILE * document)
+{
+  int header_type;
+  int real_size;
+  char *name;
+
+  for (;
+       (header_type = RB_Find_Marker (document)) != NO_HEADER;
+       )
+    {
+      struct RB_header *new_header;
+      
+      if (!
+         (
+          ((header_type == INTERNAL_HEADER) &&
+           !(course_of_action & (DO_INCLUDE_INTERNAL | DO_INTERNAL_ONLY)))
+          ||
+          ((header_type != INTERNAL_HEADER) &&
+           (course_of_action & DO_INTERNAL_ONLY))
+          ||
+          (header_type == BLANK_HEADER)
+          )
+         )
+       {
+         long cur_file_pos;
+         
+         new_header = RB_Alloc_Header ();
+         RB_Insert_In_List (&first_header, new_header);
+         new_header->type = header_type;
+         if ((new_header->name = RB_Find_Header_Name ()) != NULL)
+           {
+             RB_Say ("found header [line %5d]: \"%s\"\n",
+                     line_number, new_header->name);
+             if ((new_header->function_name
+                  = RB_Function_Name (new_header->name)) == NULL)
+               {
+                 RB_Panic ("Can't determine the \"function\" name.\n");
+               }
+             cur_file_pos = (long) ftell (document);
+             if ((real_size = RB_Find_End_Marker (document,
+                                                  &new_header->size))
+                 != 0)
+               {
+                 char *contents;
+                 
+                 fseek (document, cur_file_pos, 0);
+                 if ((contents = malloc ((new_header->size +
+                                          2) * sizeof (char)))
+                     != NULL)
+                   {
+                     fread (contents, new_header->size, sizeof (char), document);
+                     
+                     contents[real_size] = '\0';
+                     new_header->contents = contents;
+                     new_header->size = real_size;
+                   }
+                 else
+                   RB_Panic ("out of memory! [Alloc Header Contents]\n");
+               }
+             else
+               {
+                 RB_Panic ("found header with no end marker \"%s\"\n",
+                           new_header->name);
+               }
+           }
+         else
+           {
+             RB_Panic ("found header marker but no name [line %d]\n",
+                       line_number);
+           }
+       }
+      else
+       {
+         if (header_type != BLANK_HEADER)
+           {
+             if ((name = RB_Find_Header_Name ()) != NULL)
+               {
+                 new_header = RB_Alloc_Header ();
+                 if ((real_size =
+                      RB_Find_End_Marker (document, &new_header->size))
+                     == 0)
+                   {
+                     RB_Free_Header (new_header);
+                     RB_Panic ("found header with no end marker \"%s\"\n", name);
+                   }
+                 else
+                   {
+                     RB_Free_Header (new_header);
+                   }
+               }
+             else
+               {
+                 RB_Panic ("found header marker but no name [line %d]\n",
+                           line_number);
+               }
+           }
+       }
+    }
+}
+
+/****** END RB_Analyse_Document *******/
+
+
+
+
+/****f* ROBODoc/RB_Function_Name [2.0x]
+ * NAME
+ *   RB_Function_Name -- get pointer to the function name.
+ * SYNOPSIS
+ *   char *RB_NamePart(char *header_name)
+ * FUNCTION
+ *   A header name is consists of two parts. The module name and
+ *   the function name. This returns a pointer to the function name.
+ *   The name "function name" is a bit obsolete. It is really the name
+ *   of any of objects that can be documented; classes, methods,
+ *   variables, functions, projects, etc.
+ * SOURCE
+ */
+
+char *
+RB_Function_Name (char *header_name)
+{
+  char *cur_char;
+  char c;
+  char *name;
+
+  name = NULL;
+  if ((cur_char = header_name) != NULL)
+    {
+      for (; (c = *cur_char) != '\0'; ++cur_char)
+       {
+         if ('/' == *cur_char)
+           {
+             ++cur_char;
+             if (*cur_char)
+               name = cur_char;
+           }
+       }
+    }
+  if (name) {
+     char *temp;
+     temp = malloc((strlen(name) + 1) * sizeof(char));
+     strcpy(temp, name);
+     return temp; 
+  } else {
+     return (name);
+  }
+}
+
+/*** RB_Name_Part ***/
+
+
+
+/****** ROBODoc/RB_Find_Marker [3.0h]
+ * NAME
+ *   RB_Find_Marker -- Search for header marker in document.
+ * SYNOPSIS
+ *   header_type = RB_Find_Marker (document)
+ *             int RB_Find_Marker (FILE *)
+ * FUNCTION
+ *   Read document file line by line, and search each line for the
+ *   any of the headers defined in the array  header_markers
+ * INPUTS
+ *   document - pointer to the file to be searched.
+ *   the gobal buffer line_buffer.
+ * RESULT
+ *   header type
+ *   can be:
+ *    (1) NO_HEADER - no header found, end of file reached
+ *    (2) MAIN_HEADER
+ *    (3) GENERIC_HEADER
+ *    (4) INTERNAL_HEADER
+ * BUGS
+ *   Bad use of feof(), fgets().
+ * SEE ALSO
+ *   RB_Find_End_Marker
+ * SOURCE
+ */
+
+int
+RB_Find_Marker (FILE * document)
+{
+  int found;
+  int marker, marker_type;
+  char *cur_char, *cur_mchar;
+
+  marker_type = NO_HEADER;
+  cur_char = NULL;
+  found = FALSE;
+  while (!feof (document) && !found)
+    {
+      *line_buffer = '\0';
+      fgets (line_buffer, MAX_LINE_LEN, document);
+      if (!feof (document))
+       {
+         line_number++;
+         for (marker = 0;
+              ((cur_mchar = header_markers[marker]) != NULL) && !found;
+              marker++)
+           {
+             for (found = TRUE, cur_char = line_buffer;
+                  *cur_mchar && *cur_char && found;
+                  cur_mchar++, cur_char++)
+               {
+                 if (tolower(*cur_mchar) != tolower(*cur_char))
+                   found = FALSE;
+               }
+           }
+         if (found)
+           {
+             switch (*cur_char)
+               {
+               case 'h':
+                 marker_type = MAIN_HEADER;
+                 break;
+               case '*':
+                 marker_type = GENERIC_HEADER;
+                 break;
+               case 'i':
+                 marker_type = INTERNAL_HEADER;
+                 break;
+               case 'f':
+                 marker_type = FUNCTION_HEADER;
+                 break;
+               case 's':
+                 marker_type = STRUCT_HEADER;
+                 break;
+               case 'c':
+                 marker_type = CLASS_HEADER;
+                 break;
+               case 'm':
+                 marker_type = METHOD_HEADER;
+                 break;
+               case 'd':
+                 marker_type = CONSTANT_HEADER;
+                 break;
+               case 'v':
+                 marker_type = VARIABLE_HEADER;
+                 break;
+               default:
+                 RB_Say ("%s: WARNING, [line %d] undefined headertype,"
+                         " using GENERIC\n", whoami, line_number);
+                 marker_type = GENERIC_HEADER;
+               }
+           }
+       }
+    }
+  if (!found || feof (document))
+    {
+      marker_type = NO_HEADER;
+    }
+  else if (marker_type == GENERIC_HEADER)
+    {
+      skip_while (*cur_char == '*');
+      if (*cur_char == '/')
+       {
+         marker_type = BLANK_HEADER;
+       }
+    }
+  return marker_type;
+}
+
+/******** END RB_Find_Marker ******/
+
+
+/****** ROBODoc/RB_Find_End_Marker [3.0h]
+ * NAME
+ *   RB_Find_End_Marker -- Search for end marker in document.
+ * SYNOPSIS
+ *   result = RB_Find_End_Marker (document)
+ *        int RB_Find_End_Marker (FILE *)
+ * FUNCTION
+ *   Searches line by line till any of the markers in the
+ *   array: end_markers is found.
+ * INPUTS
+ *   document   - pointer to the file to be searched.
+ *   int *total_size - external size
+ *   the gobal buffer line_buffer.
+ * RESULT
+ *                real_size if end marker was found
+ *   0          - no end marker was found
+ * SEE ALSO
+ *   RB_Find_Marker
+ * SOURCE
+ */
+
+int
+RB_Find_End_Marker (FILE * document, int *total_size)
+{
+  int real_size = 0;
+  int found = FALSE;
+  int marker;
+  int line_len = 0;
+  char *cur_char, *cur_mchar;
+
+  while (!feof (document) && !found)
+    {
+      cur_char = line_buffer;
+      *cur_char = '\0';
+      fgets (cur_char, MAX_LINE_LEN, document);
+      ++line_number;           /* global linecounter *koessi */
+
+      line_len = strlen (cur_char);
+      real_size += line_len;
+
+      if (!feof (document))
+       {
+         for (marker = 0;
+              ((cur_mchar = end_markers[marker]) != NULL) && !found;
+              marker++)
+           {
+             for (found = TRUE, cur_char = line_buffer;
+                  *cur_mchar && *cur_char && found;
+                  cur_mchar++, cur_char++)
+               {
+                 if (tolower(*cur_mchar) != tolower(*cur_char))
+                   found = FALSE;
+               }
+           }
+       }
+    }
+  if (total_size)
+    *total_size = real_size;
+  if (found)
+    return real_size - line_len;
+  else
+    return 0;
+}
+
+/*****  RB_Find_End_Marker   *****/
+
+
+/****** ROBODoc/RB_Find_Header_Name   [3.0b]
+ * NAME
+ *   RB_Find_Header_Name -- search for header name
+ * SYNOPSIS
+ *   result = RB_Find_Header_Name ()
+ *      char *RB_Find_Header_Name ()
+ * FUNCTION
+ *   Searches the line buffer for the header name.
+ *   It assumes that the header name follows after the
+ *   header marker, seperated by one or more spaces, and terminated
+ *   by one or more spaces or a '\n'.
+ *   It allocates an array of chars and copies the name to this array.
+ * INPUTS
+ *   the gobal buffer line_buffer.
+ * RESULT
+ *   pointer to the allocated array of chars that contains the name,
+ *   terminated with a '\0'.
+ *   NULL if no header name was found.
+ * MODIFICATION HISTORY
+ *   8. August 1995      --  optimized by koessi
+ * SEE ALSO
+ *   RB_Find_Function_Name(), RB_WordLen(), RB_StrDup()
+ * SOURCE
+ */
+
+char *
+RB_Find_Header_Name (void)
+{
+  char *cur_char;
+
+  cur_char = line_buffer;
+  skip_while (*cur_char != '*');
+  skip_while (!isspace (*cur_char));
+  skip_while (isspace (*cur_char));
+  if (*cur_char)
+    {
+      char *end_char, old_char;
+
+      end_char = cur_char + RB_WordLen (cur_char);
+      old_char = *end_char;
+      *end_char = '\0';
+      cur_char = RB_StrDup (cur_char);
+      *end_char = old_char;
+      return (cur_char);
+    }
+  return (NULL);
+}
+
+/*****  RB_Find_Header_Name  *****/
+
+
+/****** ROBODoc/RB_Find_Item [3.0b]
+ * NAME
+ *   RB_Find_Item -- find item in header contents.
+ * SYNOPSIS
+ *   item_type = RB_Find_Item (next_line,item_line)
+ *
+ *           int RB_Find_Item (char **,  char **)
+ * FUNCTION
+ *   Searches the header contents line by line, looking
+ *   for an item Indicator.
+ * INPUTS
+ *   next_line  - pointer to a pointer that points to line
+ *                at which the search will start.
+ * SIDE-EFFECTS
+ *   next_line  - pointer to a pointer that points to begin of the line
+ *                after the line the item was found on.
+ *   item_line  - pointer to a pointer that points to the line the item
+ *                was found on.
+ * RESULT
+ *   item_type  - one of possible items indicators.
+ * SOURCE
+ */
+
+int
+RB_Find_Item (char **next_line, char **item_line)
+{
+  char *cur_char = *next_line;
+  int item_type;
+
+  for (item_type = NO_ITEM;
+       *cur_char && (item_type == NO_ITEM);
+    )
+    {
+      *item_line = cur_char;
+      cur_char = RB_Skip_Remark_Marker (cur_char);
+
+      skip_while (isspace (*cur_char) && *cur_char != '\n');
+      if (isupper (*cur_char))
+       {
+         char *item_begin = cur_char;
+         char *item_end;
+
+         skip_while (isupper (*cur_char));
+         item_end = cur_char;
+         if (isspace (*cur_char) && *cur_char)
+           {
+             skip_while (isspace (*cur_char) && *cur_char != '\n');
+
+             /* Item consists of two words ? */
+             if (isupper (*cur_char) && *cur_char)
+               {
+                 skip_while (isupper (*cur_char));
+                 item_end = cur_char;
+                 skip_while (isspace (*cur_char) && *cur_char != '\n');
+               }
+             if (*cur_char == '\n')
+               {
+                 char old_char = *item_end;
+
+                 *item_end = '\0';
+                 item_type = RB_Get_Item_Type (item_begin);
+                 *item_end = old_char;
+                 cur_char++;
+               }
+           }
+       }
+      if (item_type == NO_ITEM)
+       {
+         find_eol;
+         if (*cur_char)
+           cur_char++;
+       }
+    }
+
+  /* advance item_line to end of comment block when we have no more items */
+  if (item_type == NO_ITEM)
+    {
+      *item_line = cur_char;
+    }
+  *next_line = cur_char;
+  return item_type;
+}
+
+/*****  RB_Find_Item    *****/
+
+
+/****** ROBODoc/RRB_Number_Duplicate_Headers 
+ * NAME
+ *    RB_Number_Duplicate_Headers -- number duplicate headers
+ * SYNOPSIS
+ *    RB_Number_Duplicate_Headers (void)
+ * FUNCTION
+ *    Extends the function name with an additional number if there 
+ *    are several components with the same name.
+ *    Otherwise there will be labels with the same name in HTML
+ *    which confuses the browser.
+ * SOURCE
+ */
+
+void 
+RB_Number_Duplicate_Headers (void)
+{
+  struct RB_header *cur_header;
+  struct RB_header *dup_header;
+  for (cur_header = first_header; 
+       cur_header;
+       cur_header = cur_header->next_header)
+  {  
+    char number[20];
+    int  nr = 0;
+    for (dup_header = cur_header->next_header; 
+         dup_header;
+         dup_header = dup_header->next_header)
+    {
+       if (strcmp(cur_header->function_name,
+                  dup_header->function_name) == 0) {
+          char *new_name;
+          nr++;
+          sprintf(number, "(%d)", nr);
+          new_name = malloc ((strlen(number) + 1 + 
+              strlen(dup_header->function_name) + 1 ) * sizeof(char));
+          if (new_name == NULL) 
+             RB_Panic ("out of memory! [Number Duplicates]\n");
+          sprintf(new_name, "%s%s", dup_header->function_name,
+                  number);
+          free(dup_header->function_name);
+          dup_header->function_name = new_name;
+       }
+    }
+  }
+}
+
+/******/
+
+
+/****** ROBODoc/RB_Make_Index_Tables [3.0b]
+ * NAME
+ *    RB_Make_Index_Tables
+ * SYNOPSIS
+ *    void RB_Make_Index_Tables (void)
+ * FUNCTION
+ *    Creates sorted index tables of headers and links to speed up
+ *    matching links later on.
+ * INPUTS
+ *    none
+ * SIDE EFFECTS
+ *    Modifies header_index & link_index
+ * RESULT
+ *    none
+ * SOURCE
+ */
+
+void
+RB_Make_Index_Tables ()
+{
+  int nr_of_headers, header;
+  int nr_of_links, link;
+  struct RB_link *cur_link;
+  struct RB_header *cur_header;
+
+  for (cur_header = first_header, nr_of_headers = 0;
+       cur_header;
+       cur_header = cur_header->next_header)
+    nr_of_headers++;
+
+  for (cur_link = first_link, nr_of_links = 0;
+       cur_link;
+       cur_link = cur_link->next_link)
+    nr_of_links++;
+
+  if (nr_of_headers)
+    {
+      int sort1, sort2;
+
+      RB_Say ("Allocating Header Index Table\n");
+      header_index = malloc (nr_of_headers * sizeof (struct RB_header **));
+
+      header_index_size = nr_of_headers;
+      if (!header_index)
+       RB_Panic ("out of memory! [Make Index Tables]\n");
+
+      /* Fill Index Table */
+      for (cur_header = first_header, header = 0;
+          cur_header;
+          cur_header = cur_header->next_header, header++)
+       header_index[header] = cur_header;
+
+      /* Sort Index Table */
+      RB_Say ("Sorting Header Index Table\n");
+      for (sort1 = 0; sort1 < nr_of_headers; sort1++)
+       {
+         struct RB_header *temp;
+
+         for (sort2 = sort1; sort2 < nr_of_headers; sort2++)
+           {
+             if (strcmp (header_index[sort1]->function_name,
+                         header_index[sort2]->function_name) > 0)
+               {
+                 temp = header_index[sort1];
+                 header_index[sort1] = header_index[sort2];
+                 header_index[sort2] = temp;
+               }
+           }
+       }
+    }
+  if (nr_of_links)
+    {
+      int sort1, sort2;
+
+      RB_Say ("Allocating Link Index Table\n");
+      link_index = malloc (nr_of_links * sizeof (struct RB_link **));
+
+      link_index_size = nr_of_links;
+      if (!link_index)
+       RB_Panic ("out of memory! [Make Index Tables]\n");
+
+      /* Fill Index Table */
+      for (cur_link = first_link, link = 0;
+          cur_link;
+          cur_link = cur_link->next_link, link++)
+       {
+         link_index[link] = cur_link;
+       }
+
+      /* Sort Index Table */
+      RB_Say ("Sorting Link Index Table\n");
+      for (sort1 = 0; sort1 < nr_of_links; sort1++)
+       {
+         struct RB_link *temp;
+
+         for (sort2 = sort1; sort2 < nr_of_links; sort2++)
+           {
+             if (strcmp (link_index[sort1]->label_name,
+                         link_index[sort2]->label_name) > 0)
+               {
+                 temp = link_index[sort1];
+                 link_index[sort1] = link_index[sort2];
+                 link_index[sort2] = temp;
+               }
+           }
+       }
+    }
+}
+
+/****** RB_Make_Index_Tables  *****/