]> code.delx.au - gnu-emacs/blobdiff - lib-src/etags.c
*** empty log message ***
[gnu-emacs] / lib-src / etags.c
index 5fd45e21fab71894f9daf87f26859bccfc33ca3a..0ba1ccf861f767db70447f68c3daed51b577d50e 100644 (file)
@@ -33,7 +33,7 @@ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  *     Francesco Potortì <pot@gnu.org> has maintained it since 1993.
  */
 
-char pot_etags_version[] = "@(#) pot revision number is 15.10";
+char pot_etags_version[] = "@(#) pot revision number is 15.16";
 
 #define        TRUE    1
 #define        FALSE   0
@@ -346,7 +346,7 @@ int main __P((int, char **));
 static compressor *get_compressor_from_suffix __P((char *, char **));
 static language *get_language_from_langname __P((const char *));
 static language *get_language_from_interpreter __P((char *));
-static language *get_language_from_filename __P((char *));
+static language *get_language_from_filename __P((char *, bool));
 static long readline __P((linebuffer *, FILE *));
 static long readline_internal __P((linebuffer *, FILE *));
 static bool nocase_tail __P((char *));
@@ -368,9 +368,10 @@ static void initbuffer __P((linebuffer *));
 static void process_file __P((char *, language *));
 static void find_entries __P((FILE *));
 static void free_tree __P((node *));
+static void free_fdesc __P((fdesc *));
 static void pfnote __P((char *, bool, char *, int, int, long));
 static void new_pfnote __P((char *, int, bool, char *, int, int, long));
-static void invalidate_nodes __P((fdesc *, node *));
+static void invalidate_nodes __P((fdesc *, node **));
 static void put_entries __P((node *));
 
 static char *concat __P((char *, char *, char *));
@@ -380,6 +381,7 @@ static char *savenstr __P((char *, int));
 static char *savestr __P((char *));
 static char *etags_strchr __P((const char *, int));
 static char *etags_strrchr __P((const char *, int));
+static bool strcaseeq __P((const char *, const char *));
 static char *etags_getcwd __P((void));
 static char *relative_filename __P((char *, char *));
 static char *absolute_filename __P((char *, char *));
@@ -409,6 +411,7 @@ static char *dbp;           /* pointer to start of current tag */
 static const int invalidcharno = -1;
 
 static node *nodehead;         /* the head of the binary tree of tags */
+static node *last_node;                /* the last node created */
 
 static linebuffer lb;          /* the current line */
 
@@ -1351,8 +1354,9 @@ get_language_from_interpreter (interpreter)
  * Return a language given the file name.
  */
 static language *
-get_language_from_filename (file)
+get_language_from_filename (file, case_sensitive)
      char *file;
+     bool case_sensitive;
 {
   language *lang;
   char **name, **ext, *suffix;
@@ -1361,7 +1365,9 @@ get_language_from_filename (file)
   for (lang = lang_names; lang->name != NULL; lang++)
     if (lang->filenames != NULL)
       for (name = lang->filenames; *name != NULL; name++)
-       if (streq (*name, file))
+       if ((case_sensitive)
+           ? streq (*name, file)
+           : strcaseeq (*name, file))
          return lang;
 
   /* If not found, try suffix after last dot. */
@@ -1372,7 +1378,9 @@ get_language_from_filename (file)
   for (lang = lang_names; lang->name != NULL; lang++)
     if (lang->suffixes != NULL)
       for (ext = lang->suffixes; *ext != NULL; ext++)
-       if (streq (*ext, suffix))
+       if ((case_sensitive)
+           ? streq (*ext, suffix)
+           : strcaseeq (*ext, suffix))
          return lang;
   return NULL;
 }
@@ -1422,12 +1430,6 @@ process_file (file, lang)
        goto cleanup;
     }
 
-  /* Create a new input file description entry. */
-  fdp = fdhead;
-  fdhead = xnew (1, fdesc);
-  *fdhead = emptyfdesc;
-  fdhead->next = fdp;
-
   if (stat (real_name, &stat_buf) != 0)
     {
       /* Reset real_name and try with a different name. */
@@ -1496,24 +1498,29 @@ process_file (file, lang)
       goto cleanup;
     }
 
-  fdhead->infname = savestr (uncompressed_name);
-  fdhead->lang = lang;
-  fdhead->infabsname = absolute_filename (uncompressed_name, cwd);
-  fdhead->infabsdir = absolute_dirname (uncompressed_name, cwd);
+  /* Create a new input file description entry. */
+  fdp = xnew (1, fdesc);
+  *fdp = emptyfdesc;
+  fdp->next = fdhead;
+  fdp->infname = savestr (uncompressed_name);
+  fdp->lang = lang;
+  fdp->infabsname = absolute_filename (uncompressed_name, cwd);
+  fdp->infabsdir = absolute_dirname (uncompressed_name, cwd);
   if (filename_is_absolute (uncompressed_name))
     {
       /* file is an absolute file name.  Canonicalize it. */
-      fdhead->taggedfname = absolute_filename (uncompressed_name, NULL);
+      fdp->taggedfname = absolute_filename (uncompressed_name, NULL);
     }
   else
     {
       /* file is a file name relative to cwd.  Make it relative
         to the directory of the tags file. */
-      fdhead->taggedfname = relative_filename (uncompressed_name, tagfiledir);
+      fdp->taggedfname = relative_filename (uncompressed_name, tagfiledir);
     }
-  fdhead->usecharno = TRUE;    /* use char position when making tags */
-  fdhead->prop = NULL;
+  fdp->usecharno = TRUE;       /* use char position when making tags */
+  fdp->prop = NULL;
 
+  fdhead = fdp;
   curfdp = fdhead;             /* the current file description */
 
   find_entries (inf);
@@ -1525,10 +1532,45 @@ process_file (file, lang)
   if (retval < 0)
     pfatal (file);
 
+  /* If not Ctags, and if this is not metasource and if it contained no #line
+     directives, we can write the tags and free all nodes pointing to
+     curfdp. */
+  if (!CTAGS
+      && curfdp->usecharno     /* no #line directives in this file */
+      && !curfdp->lang->metasource)
+    {
+      node *np, *prev;
+
+      /* Look for the head of the sublist relative to this file.  See add_node
+        for the structure of the node tree. */
+      prev = NULL;
+      for (np = nodehead; np != NULL; prev = np, np = np->left)
+       if (np->fdp == curfdp)
+         break;
+
+      /* If we generated tags for this file, write and delete them. */
+      if (np != NULL)
+       {
+         /* This is the head of the last sublist, if any.  The following
+            instructions depend on this being true. */
+         assert (np->left == NULL);
+
+         assert (fdhead == curfdp);
+         assert (last_node->fdp == curfdp);
+         put_entries (np);     /* write tags for file curfdp->taggedfname */
+         free_tree (np);       /* remove the written nodes */
+         if (prev == NULL)
+           nodehead = NULL;    /* no nodes left */
+         else
+           prev->left = NULL;  /* delete the pointer to the sublist */
+       }
+    }
+
  cleanup:
-  /* XXX if no more useful, delete head of file description list */
   if (compressed_name) free (compressed_name);
   if (uncompressed_name) free (uncompressed_name);
+  last_node = NULL;
+  curfdp = NULL;
   return;
 }
 
@@ -1563,8 +1605,6 @@ init ()
  * This routine opens the specified file and calls the function
  * which finds the function and type definitions.
  */
-static node *last_node = NULL;
-
 static void
 find_entries (inf)
      FILE *inf;
@@ -1583,7 +1623,7 @@ find_entries (inf)
   /* Else try to guess the language given the file name. */
   if (parser == NULL)
     {
-      lang = get_language_from_filename (curfdp->infname);
+      lang = get_language_from_filename (curfdp->infname, TRUE);
       if (lang != NULL && lang->function != NULL)
        {
          curfdp->lang = lang;
@@ -1622,11 +1662,28 @@ find_entries (inf)
        }
     }
 
+  /* We rewind here, even if inf may be a pipe.  We fail if the
+     length of the first line is longer than the pipe block size,
+     which is unlikely. */
+  if (parser == NULL)
+    rewind (inf);
+
+  /* Else try to guess the language given the case insensitive file name. */
+  if (parser == NULL)
+    {
+      lang = get_language_from_filename (curfdp->infname, FALSE);
+      if (lang != NULL && lang->function != NULL)
+       {
+         curfdp->lang = lang;
+         parser = lang->function;
+       }
+    }
+
   if (!no_line_directive
       && curfdp->lang != NULL && curfdp->lang->metasource)
-    /* It may be that this is an xxx.y file, and we already parsed an xxx.c
+    /* It may be that this is a bingo.y file, and we already parsed a bingo.c
        file, or anyway we parsed a file that is automatically generated from
-       this one.  If this is the case, the xxx.c file contained #line
+       this one.  If this is the case, the bingo.c file contained #line
        directives that generated tags pointing to this file.  Let's delete
        them all before parsing this file, which is the real source. */
     {
@@ -1639,21 +1696,16 @@ find_entries (inf)
          {
            fdesc *badfdp = *fdpp;
 
-           *fdpp = badfdp->next; /* remove the bad description from the list */
-           fdpp = &badfdp->next; /* advance the list pointer */
+           if (DEBUG)
+             fprintf (stderr,
+                      "Removing references to \"%s\" obtained from \"%s\"\n",
+                      badfdp->taggedfname, badfdp->infname);
 
-           fprintf (stderr, "Removing references to \"%s\" obtained from \"%s\"\n",
-                    badfdp->taggedfname, badfdp->infname);
            /* Delete the tags referring to badfdp. */
-           invalidate_nodes (badfdp, nodehead);
-
-           /* Delete badfdp. */
-           if (badfdp->infname != NULL) free (badfdp->infname);
-           if (badfdp->infabsname != NULL) free (badfdp->infabsname);
-           if (badfdp->infabsdir != NULL) free (badfdp->infabsdir);
-           if (badfdp->taggedfname != NULL) free (badfdp->taggedfname);
-           if (badfdp->prop != NULL) free (badfdp->prop);
-           free (badfdp);
+           invalidate_nodes (badfdp, &nodehead);
+
+           *fdpp = badfdp->next; /* remove the bad description from the list */
+           free_fdesc (badfdp);
          }
        else
          fdpp = &(*fdpp)->next; /* advance the list pointer */
@@ -1665,11 +1717,6 @@ find_entries (inf)
       return;
     }
 
-  /* We rewind here, even if inf may be a pipe.  We fail if the
-     length of the first line is longer than the pipe block size,
-     which is unlikely. */
-  rewind (inf);
-
   /* Else try Fortran. */
   old_last_node = last_node;
   curfdp->lang = get_language_from_langname ("fortran");
@@ -1820,6 +1867,22 @@ free_tree (np)
     }
 }
 
+/*
+ * free_fdesc ()
+ *     delete a file description
+ */
+static void
+free_fdesc (fdp)
+     register fdesc *fdp;
+{
+  if (fdp->infname != NULL) free (fdp->infname);
+  if (fdp->infabsname != NULL) free (fdp->infabsname);
+  if (fdp->infabsdir != NULL) free (fdp->infabsdir);
+  if (fdp->taggedfname != NULL) free (fdp->taggedfname);
+  if (fdp->prop != NULL) free (fdp->prop);
+  free (fdp);
+}
+
 /*
  * add_node ()
  *     Adds a node to the tree of nodes.  In etags mode, sort by file
@@ -1844,16 +1907,16 @@ add_node (np, cur_node_p)
     }
 
   if (!CTAGS)
+    /* Etags Mode */
     {
-      /* Etags Mode */
-      assert (last_node != NULL);
       /* For each file name, tags are in a linked sublist on the right
         pointer.  The first tags of different files are a linked list
         on the left pointer.  last_node points to the end of the last
         used sublist. */
-      if (last_node->fdp == np->fdp)
+      if (last_node != NULL && last_node->fdp == np->fdp)
        {
          /* Let's use the same sublist as the last added node. */
+         assert (last_node->right == NULL);
          last_node->right = np;
          last_node = np;
        }
@@ -1867,7 +1930,8 @@ add_node (np, cur_node_p)
        /* The head of this sublist is not good for us.  Let's try the
           next one. */
        add_node (np, &cur_node->left);
-    }
+    } /* if ETAGS mode */
+
   else
     {
       /* Ctags Mode */
@@ -1901,25 +1965,44 @@ add_node (np, cur_node_p)
 
       /* Actually add the node */
       add_node (np, dif < 0 ? &cur_node->left : &cur_node->right);
-    }
+    } /* if CTAGS mode */
 }
 
 /*
  * invalidate_nodes ()
  *     Scan the node tree and invalidate all nodes pointing to the
- *     given file description.
+ *     given file description (CTAGS case) or free them (ETAGS case).
  */
 static void
-invalidate_nodes (badfdp, np)
+invalidate_nodes (badfdp, npp)
      fdesc *badfdp;
-     node *np;
+     node **npp;
 {
-  if (np->left != NULL)
-    invalidate_nodes (badfdp, np->left);
-  if (np->fdp == badfdp)
-    np-> valid = FALSE;
-  if (np->right != NULL)
-    invalidate_nodes (badfdp, np->right);
+  node *np = *npp;
+
+  if (np == NULL)
+    return;
+
+  if (CTAGS)
+    {
+      if (np->left != NULL)
+       invalidate_nodes (badfdp, &np->left);
+      if (np->fdp == badfdp)
+       np-> valid = FALSE;
+      if (np->right != NULL)
+       invalidate_nodes (badfdp, &np->right);
+    }
+  else
+    {
+      node **next = &np->left;
+      if (np->fdp == badfdp)
+       {
+         *npp = *next;         /* detach the sublist from the list */
+         np->left = NULL;      /* isolate it */
+         free_tree (np);       /* free it */
+       }
+      invalidate_nodes (badfdp, next);
+    }
 }
 
 \f
@@ -5741,7 +5824,6 @@ etags_strrchr (sp, c)
   return (char *)r;
 }
 
-
 /*
  * Return the ptr in sp at which the character c first
  * appears; NULL if not found
@@ -5761,6 +5843,26 @@ etags_strchr (sp, c)
   return NULL;
 }
 
+/*
+ * Return TRUE if the two strings are equal, ignoring case for alphabetic
+ * characters.
+ *
+ * Analogous to BSD's strcasecmp, included for portability.
+ */
+static bool
+strcaseeq (s1, s2)
+     register const char *s1;
+     register const char *s2;
+{
+  while (*s1 != '\0'
+        && (ISALPHA (*s1) && ISALPHA (*s2)
+            ? lowcase (*s1) == lowcase (*s2)
+            : *s1 == *s2))
+    s1++, s2++;
+
+  return (*s1 == *s2);
+}
+
 /* Skip spaces, return new pointer. */
 static char *
 skip_spaces (cp)
@@ -6087,6 +6189,6 @@ xrealloc (ptr, size)
  * indent-tabs-mode: t
  * tab-width: 8
  * fill-column: 79
- * c-font-lock-extra-types: ("FILE" "bool" "language" "linebuffer" "fdesc")
+ * c-font-lock-extra-types: ("FILE" "bool" "language" "linebuffer" "fdesc" "node")
  * End:
  */