changeset 6482:91112dd5c9f5

* etags.c (cwd, outfiledir): vars added. (relative_filename, absolute_filename, absolute_dirname): functions added to compute filenames in tags files. (process_file): filenames in tags file are relative to the directory where the tags file is (useful with the -o option). (main): initialise the outfiledir var. (TYPEDST): added the `tignore' value. (C_entries): corrected various small bugs.
author Francesco Potortì <pot@gnu.org>
date Wed, 23 Mar 1994 18:27:19 +0000
parents 55236c5bca7c
children 373e377d79f7
files lib-src/etags.c
diffstat 1 files changed, 212 insertions(+), 45 deletions(-) [+]
line wrap: on
line diff
--- a/lib-src/etags.c	Wed Mar 23 18:23:32 1994 +0000
+++ b/lib-src/etags.c	Wed Mar 23 18:27:19 1994 +0000
@@ -25,9 +25,11 @@
  *	Gnu Emacs TAGS format and modifications by RMS?
  *	Sam Kendall added C++.
  *
- *	Francesco Potorti` (pot@cnuce.cnr.it) is the current maintainer. 10.7
+ *	Francesco Potorti` (pot@cnuce.cnr.it) is the current maintainer.
  */
 
+char etags_version[] = "@(#) pot revision number is 10.15";
+
 #ifdef MSDOS
 #include <fcntl.h>
 #endif /* MSDOS */
@@ -48,9 +50,8 @@
 #include "getopt.h"
 
 extern char *getenv ();
+extern char *getcwd ();
 
-char *etags_index (), *etags_rindex ();
-char *savenstr ();
 
 /* Define the symbol ETAGS to make the program "etags",
  which makes emacs-style tag tables by default.
@@ -151,19 +152,20 @@
   struct nd_st *left, *right;	/* left and right sons		*/
 };
 
-long ftell ();
 typedef struct nd_st NODE;
 
 logical header_file;		/* TRUE if .h file, FALSE o.w.  */
 /* boolean "functions" (see init)	*/
 logical _wht[0177], _etk[0177], _itk[0177], _btk[0177];
 
+char cwd [BUFSIZ];		/* current working directory */
+char *outfiledir;		/* directory of tagfile */
 
 char *concat ();
-char *savenstr ();
-char *savestr ();
-char *xmalloc ();
-char *xrealloc ();
+char *savenstr (), *savestr ();
+char *etags_index (), *etags_rindex ();
+char *relative_filename (), *absolute_filename (), *absolute_dirname ();
+char *xmalloc (), *xrealloc ();
 int L_isdef (), L_isquote ();
 int PF_funcs ();
 int total_size_of_entries ();
@@ -241,7 +243,7 @@
  *endtk = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?",	/* token ending chars	*/
 				/* token starting chars			*/
  *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~",
-				  /* valid in-token chars		*/
+				/* valid in-token chars			*/
  *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
 
 int append_to_tagfile;		/* -a: append to tags */
@@ -442,7 +444,7 @@
   extern char *gfnames ();
   extern char *massage_name ();
 #endif
-
+ 
 #ifdef MSDOS
   _fmode = O_BINARY;   /* all of files are treated as binary files */
 #endif /* MSDOS */
@@ -465,7 +467,7 @@
   for (;;)
     {
       int opt;
-      opt = getopt_long (argc, argv, "aACdDo:f:StTi:BFuvxwVH", longopts, 0);
+      opt = getopt_long (argc, argv, "aCdDo:f:StTi:BFuvxwVH", longopts, 0);
 
       if (opt == EOF)
 	break;
@@ -569,10 +571,20 @@
       exit (BAD);
     }
 
-  if (outfile == 0)
+  if (outfile == NULL)
     {
       outfile = emacs_tags_format ? "TAGS" : "tags";
     }
+  getcwd (cwd, BUFSIZ);		/* the current working directory */
+  strcat (cwd, "/");
+  if (streq (outfile, "-"))
+    {
+      outfiledir = cwd;
+    }
+  else
+    {
+      outfiledir = absolute_dirname (outfile, cwd);
+    }
 
   init ();			/* set up boolean "functions"		*/
 
@@ -619,18 +631,18 @@
       this_file = argv[optind];
 #endif
       /* Input file named "-" means read file names from stdin and use them. */
-	  if (streq (this_file, "-"))
+      if (streq (this_file, "-"))
+	{
+	  while (!feof (stdin))
 	    {
-	      while (!feof (stdin))
-		{
-		  (void) readline (&filename_lb, stdin);
-		  if (strlen (filename_lb.buffer) > 0)
-		    process_file (filename_lb.buffer);
-		}
+	      (void) readline (&filename_lb, stdin);
+	      if (strlen (filename_lb.buffer) > 0)
+		process_file (filename_lb.buffer);
 	    }
-	  else
-	    process_file (this_file);
 	}
+      else
+	process_file (this_file);
+    }
 
   if (emacs_tags_format)
     {
@@ -701,7 +713,20 @@
     }
   if (emacs_tags_format)
     {
-      fprintf (outf, "\f\n%s,%d\n", file, total_size_of_entries (head));
+      char *filename;
+
+      if (file[0] == '/')
+	{
+	  /* file is an absolute filename.  Canonicalise it. */
+	  filename = absolute_filename (file, cwd);
+	}
+      else
+	{
+	  /* file is a filename relative to cwd.  Make it relative
+	     to the directory of the tags file. */
+	  filename = relative_filename (file, outfiledir);
+	}
+      fprintf (outf, "\f\n%s,%d\n", filename, total_size_of_entries (head));
       put_entries (head);
       free_tree (head);
       head = NULL;
@@ -1318,7 +1343,8 @@
 FUNCST funcdef;
 
 
- /* typedefs are recognized using a simple finite automaton.
+ /*
+  * typedefs are recognized using a simple finite automaton.
   * typeddef is its state variable.
   */
 typedef enum
@@ -1326,16 +1352,16 @@
   tnone,			/* nothing seen */
   ttypedseen,			/* typedef keyword seen */
   tinbody,			/* inside typedef body */
-  tend				/* just before typedef tag */
+  tend,				/* just before typedef tag */
+  tignore			/* junk after typedef tag */
 } TYPEDST;
 TYPEDST typdef;
 
 
- /* struct tags for C++ are recognized using another simple
-  * finite automaton.  `structdef' is its state variable.
-  * This machinery is only invoked for C++; otherwise structdef
-  * should remain snone.  However, this machinery can easily be
-  * adapted to find structure tags in normal C code.
+ /* 
+  * struct-like structures (enum, struct and union) are recognized
+  * using another simple finite automaton.  `structdef' is its state
+  * variable.
   */
 typedef enum
 {
@@ -1346,6 +1372,7 @@
   sinbody			/* in struct body: recognize member func defs*/
 } STRUCTST;
 STRUCTST structdef;
+
 /*
  * When structdef is stagseen, scolonseen, or sinbody, structtag is the
  * struct tag, and structtype is the type of the preceding struct-like  
@@ -1448,7 +1475,7 @@
   lp = curlb.buffer;
   *lp = 0;
 
-  definedef = dnone; funcdef = fnone; typdef= tnone; structdef= snone;
+  definedef = dnone; funcdef = fnone; typdef = tnone; structdef = snone;
   next_token_is_func = yacc_rules = FALSE;
   midtoken = inquote = inchar = incomm = quotednl = FALSE;
   cblev = 0;
@@ -1515,7 +1542,7 @@
 	      CNL;
 	      /* FALLTHRU */
 	    case '\'':
-	    inchar = FALSE;
+	      inchar = FALSE;
 	      break;
 	    }
 	  continue;
@@ -1553,7 +1580,7 @@
 		/* entering or exiting rules section in yacc file */
 		lp++;
 		definedef = dnone; funcdef = fnone;
-		typdef= tnone; structdef= snone;
+		typdef = tnone; structdef = snone;
 		next_token_is_func = FALSE;
 		midtoken = inquote = inchar = incomm = quotednl = FALSE;
 		cblev = 0;
@@ -1572,9 +1599,10 @@
       /* Consider token only if some complicated conditions are satisfied. */
       if (((cblev == 0 && structdef != scolonseen)
 	   || (cblev == 1 && cplpl && structdef == sinbody))
+	  && typdef != tignore
 	  && definedef != dignorerest
 	  && (funcdef != finlist
-	      || (definedef != dnone && definedef != dignorerest)))
+	      || definedef != dnone))
 	{
 	  if (midtoken)
 	    {
@@ -1714,19 +1742,37 @@
 	case ';':
 	  if (definedef != dnone)
 	    break;
-	  if (cblev == 0 && typdef == tend)
-	    {
-	      typdef = tnone;
-	      MAKE_TAG_FROM_OTH_LB (FALSE);
-	    }
+	  if (cblev == 0)
+	    switch (typdef)
+	      {
+	      case tend:
+		MAKE_TAG_FROM_OTH_LB (FALSE);
+		/* FALLTHRU */
+	      default:
+		typdef = tnone;
+	      }
 	  if (funcdef != fignore)
 	    funcdef = fnone;
-	  /* FALLTHRU */
+	  if (structdef == stagseen)
+	    structdef = snone;
+	  break;
 	case ',':
-	  /* FALLTHRU */
+	  if (definedef != dnone)
+	    break;
+	  if (funcdef != finlist && funcdef != fignore)
+	    funcdef = fnone;
+	  if (structdef == stagseen)
+	    structdef = snone;
+	  break;
 	case '[':
 	  if (definedef != dnone)
 	    break;
+	  if (cblev == 0 && typdef == tend)
+	    {
+	      typdef = tignore;
+	      MAKE_TAG_FROM_OTH_LB (FALSE);
+	      break;
+	    }
 	  if (funcdef != finlist && funcdef != fignore)
 	    funcdef = fnone;
 	  if (structdef == stagseen)
@@ -1758,6 +1804,11 @@
 		  funcdef = flistseen;
 		  break;
 		}
+	      if (cblev == 0 && typdef == tend)
+		{
+		  typdef = tignore;
+		  MAKE_TAG_FROM_OTH_LB (FALSE);
+		}
 	    }
 	  else if (parlev < 0)	/* can happen due to ill-conceived #if's. */
 	    parlev = 0;
@@ -1786,6 +1837,11 @@
 	      /* FALLTHRU */
 	    case fignore:
 	      funcdef = fnone;
+	      break;
+	    case fnone:
+	      /* Neutralize `extern "C" {' grot.
+	      if (cblev == 0 && structdef == snone && typdef == tnone)
+		cblev--; */;
 	    }
 	  cblev++;
 	  break;
@@ -1910,6 +1966,7 @@
 	{
 	  if (typedefs)
 	    typdef = ttypedseen;
+	  funcdef = fnone;
 	  return (FALSE);
 	}
       break;
@@ -2015,7 +2072,8 @@
   switch (toktype)
     {
     case st_C_typespec:
-      funcdef = fnone;		/* should be useless */
+      if (funcdef != finlist && funcdef != fignore)
+        funcdef = fnone;		/* should be useless */
       return (FALSE);
     default:
       if (funcdef == fnone)
@@ -2176,7 +2234,7 @@
 	dbp++;
     }
   if (!isalpha (*dbp)
-	  && *dbp != '_'
+      && *dbp != '_'
       && *dbp != '$')
     return;
   for (cp = dbp + 1;
@@ -2364,7 +2422,7 @@
 		  verify_tag = FALSE;
 		}
 	    }
-	  if ((found_tag) && (verify_tag))	/* not external proc, so make tag */
+	  if ((found_tag) && (verify_tag)) /* not external proc, so make tag */
 	    {
 	      found_tag = FALSE;
 	      verify_tag = FALSE;
@@ -3073,7 +3131,8 @@
   fprintf (stderr, "\n");
 }
 
-/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3.  */
+/* Return a newly-allocated string whose contents
+   concatenate those of s1, s2, s3.  */
 
 char *
 concat (s1, s2, s3)
@@ -3085,11 +3144,119 @@
   strcpy (result, s1);
   strcpy (result + len1, s2);
   strcpy (result + len1 + len2, s3);
-  *(result + len1 + len2 + len3) = 0;
+  result[len1 + len2 + len3] = '\0';
 
   return result;
 }
 
+/* Return a newly allocated string containing the filename of FILE relative
+   to the absolute directory DIR (which should end with a slash). */
+
+char *
+relative_filename (file, dir)
+     char *file, *dir;
+{
+  char *fp, *dp, *res;
+
+  /* Find the common root of file and dir. */
+  fp = absolute_filename (file, cwd);
+  dp = dir;
+  while (*fp++ == *dp++)
+    continue;
+  do
+    {
+      fp--;
+      dp--;
+    }
+  while (*fp != '/');
+
+  /* Build a sequence of "../" strings for the resulting relative filename. */
+  for (dp = etags_index (dp + 1, '/'), res = "";
+       dp != NULL;
+       dp = etags_index (dp + 1, '/'))
+    {
+      res = concat (res, "../", "");
+    }
+
+  /* Add the filename relative to the common root of file and dir. */
+  res = concat (res, fp + 1, "");
+
+  return res;			/* temporary stub */
+}
+
+/* Return a newly allocated string containing the
+   absolute filename of FILE given CWD (which should end with a slash). */
+char *
+absolute_filename (file, cwd)
+     char *file, *cwd;
+{
+  char *slashp, *cp, *res;
+
+  if (file[0] == '/')
+    res = concat (file, "", "");
+  else
+    res = concat (cwd, file, "");
+
+  /* Delete the "/dirname/.." and "/." substrings. */
+  slashp = etags_index (res, '/');
+  while (slashp != NULL && slashp[0] != '\0')
+    {
+      if (slashp[1] == '.')
+	{
+	  if (slashp[2] == '.'
+	      && (slashp[3] == '/' || slashp[3] == '\0'))
+	    {
+	      cp = slashp;
+	      do
+		cp--;
+	      while (cp >= res && *cp != '/');
+	      if (*cp == '/')
+		{
+		  strcpy (cp, slashp + 3);
+		}
+	      else		/* else (cp == res) */
+		{
+		  if (slashp[3] != NULL)
+		    strcpy (cp, slashp + 4);
+		  else
+		    return ".";
+		}
+	      slashp = cp;
+	    }
+	  else if (slashp[2] == '/' || slashp[2] == '\0')
+	    {
+	      strcpy (slashp, slashp + 2);
+	    }
+	}
+      else
+	{
+	  slashp = etags_index (slashp + 1, '/');
+	}
+    }
+
+  return res;
+}
+
+/* Return a newly allocated string containing the absolute filename
+   of dir where FILE resides given CWD (which should end with a slash). */
+char *
+absolute_dirname (file, cwd)
+     char *file, *cwd;
+{
+  char *slashp, *res;
+  char save;
+
+  slashp = etags_rindex (file, '/');
+  if (slashp == NULL)
+    return cwd;
+  save = slashp[1];
+  slashp[1] = '\0';
+  res = absolute_filename (file, cwd);
+  slashp[1] = save;
+
+  return res;
+}
+
 /* Like malloc but get fatal error if memory is exhausted.  */
 
 char *