* 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
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 *));
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 *));
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 *));
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 */
* 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;
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. */
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;
}
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. */
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);
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;
}
* 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;
/* 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;
}
}
+ /* 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. */
{
{
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 */
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");
}
}
+/*
+ * 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
}
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;
}
/* 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 */
/* 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
return (char *)r;
}
-
/*
* Return the ptr in sp at which the character c first
* appears; NULL if not found
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)
* 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:
*/