changeset 14859:efa1bc6b7b17

* etags.c (just_read_file): Reset lineno and charno on entry. * etags.c: Prolog language totaly rewritten. (Prolog_functions): Rewritten from scratch. (skip_comment, prolog_getit): Removed. (prolog_skip_comment): New function, like old skip_comment. (prolog_pred, prolog_atom, prolog_white): New functions. (erlang_func, erlang_attributes): Forward declarations added. (erlang_atom): Check if backslash ends line inside quoted atom. * etags.c (absolutefn): DOS_NT version corrected. (main): Append "/" to the dir name only if not already there. (print_help): Explain the absolute/relative file name issue. * etags.c: New Languange Erlang added. (Erlang_functions, erlang_func, erlang_attribute, erlang_atom, erlang_white): New functions. (Erlang_suffixes): New suffix list. (lang_names): Erlang entry added. (prolog_getit): Accepts headers spanning several lines. Always name tags. (Prolog_functions): Removed incorrect compensation for newline characters. (readline_internal): Zero-terminate last line.
author Francesco Potortì <pot@gnu.org>
date Fri, 22 Mar 1996 19:13:22 +0000
parents 0a88c1cc98ec
children 65dba0cd5306
files lib-src/etags.c
diffstat 1 files changed, 414 insertions(+), 98 deletions(-) [+]
line wrap: on
line diff
--- a/lib-src/etags.c	Fri Mar 22 14:18:20 1996 +0000
+++ b/lib-src/etags.c	Fri Mar 22 19:13:22 1996 +0000
@@ -28,10 +28,10 @@
  *	Francesco Potorti` reorganised C and C++ based on work by Joe Wells.
  *	Regexp tags by Tom Tromey.
  *
- *	Francesco Potorti` (pot@cnuce.cnr.it) is the current maintainer.
+ *	Francesco Potorti` (F.Potorti@cnuce.cnr.it) is the current maintainer.
  */
 
-char pot_etags_version[] = "@(#) pot revision number is 11.53";
+char pot_etags_version[] = "@(#) pot revision number is 11.59";
 
 #define	TRUE	1
 #define	FALSE	0
@@ -41,22 +41,22 @@
 #endif
 
 #ifdef MSDOS
-#include <fcntl.h>
-#include <sys/param.h>
+# include <fcntl.h>
+# include <sys/param.h>
 #endif /* MSDOS */
 
 #ifdef WINDOWSNT
-#include <stdlib.h>
-#include <fcntl.h>
-#include <string.h>
-#define MAXPATHLEN _MAX_PATH
+# include <stdlib.h>
+# include <fcntl.h>
+# include <string.h>
+# define MAXPATHLEN _MAX_PATH
 #endif
 
 #ifdef HAVE_CONFIG_H
-#include <config.h>
-/* On some systems, Emacs defines static as nothing for the sake
-   of unexec.  We don't want that here since we don't use unexec. */
-#undef static
+# include <config.h>
+  /* On some systems, Emacs defines static as nothing for the sake
+     of unexec.  We don't want that here since we don't use unexec. */
+# undef static
 #endif
 
 #include <stdio.h>
@@ -75,7 +75,7 @@
 #include <getopt.h>
 
 #ifdef ETAGS_REGEXPS
-#include <regex.h>
+# include <regex.h>
 #endif /* ETAGS_REGEXPS */
 
 /* Define CTAGS to make the program "ctags" compatible with the usual one.
@@ -90,11 +90,11 @@
 
 /* Exit codes for success and failure.  */
 #ifdef VMS
-#define	GOOD	1
-#define BAD	0
+# define	GOOD	1
+# define	BAD	0
 #else
-#define	GOOD	0
-#define	BAD	1
+# define	GOOD	0
+# define	BAD	1
 #endif
 
 /* C extensions. */
@@ -113,7 +113,8 @@
 #define	endtoken(arg)	(_etk[arg])	/* T if char ends tokens	*/
 
 #ifdef DOS_NT
-# define absolutefn(fn) (fn[0] == '/' || (isalpha (fn[0]) && fn[1] == ':'))
+# define absolutefn(fn) (fn[0] == '/' \
+			 || (isalpha (fn[0]) && fn[1] == ':' && fn[2] == '/'))
 #else
 # define absolutefn(fn) (fn[0] == '/')
 #endif
@@ -156,6 +157,7 @@
 Lang_function C_entries;
 Lang_function Cplusplus_entries;
 Lang_function Cstar_entries;
+Lang_function Erlang_functions;
 Lang_function Fortran_functions;
 Lang_function Yacc_entries;
 Lang_function Lisp_functions;
@@ -172,6 +174,7 @@
 void plain_C_entries ();
 void Cplusplus_entries ();
 void Cstar_entries ();
+void Erlang_functions ();
 void Fortran_functions ();
 void Yacc_entries ();
 void Lisp_functions ();
@@ -347,6 +350,9 @@
 char *Cstar_suffixes [] =
   { "cs", "hs", NULL };
 
+char *Erlang_suffixes [] =
+  { "erl", "hrl", NULL };
+
 char *Fortran_suffixes [] =
   { "F", "f", "f90", "for", NULL };
 
@@ -398,6 +404,7 @@
   { "c",       default_C_entries,   default_C_suffixes,	  NULL              },
   { "c++",     Cplusplus_entries,   Cplusplus_suffixes,	  NULL              },
   { "c*",      Cstar_entries,	    Cstar_suffixes,	  NULL              },
+  { "erlang",  Erlang_functions,    Erlang_suffixes,	  NULL              },
   { "fortran", Fortran_functions,   Fortran_suffixes,	  NULL              },
   { "lisp",    Lisp_functions,	    Lisp_suffixes,	  NULL              },
   { "pascal",  Pascal_functions,    Pascal_suffixes,	  NULL              },
@@ -453,7 +460,11 @@
 {
   printf ("These are the options accepted by %s.  You may use unambiguous\n\
 abbreviations for the long option names.  A - as file name means read\n\
-names from stdin.\n\n", progname);
+names from stdin.", progname);
+  if (!CTAGS)
+    printf ("  Absolute names are stored in the output file as they\n\
+are.  Relative ones are stored relative to the output file's directory.");
+  puts ("\n");
 
   puts ("-a, --append\n\
         Append tag entries to existing tags file.");
@@ -843,19 +854,14 @@
     }
 
   if (tagfile == NULL)
-    {
-      tagfile = CTAGS ? "tags" : "TAGS";
-    }
+    tagfile = CTAGS ? "tags" : "TAGS";
   cwd = etags_getcwd ();	/* the current working directory */
-  strcat (cwd, "/");
+  if (cwd[strlen(cwd)-1] != '/')
+    strcat (cwd, "/");
   if (streq (tagfile, "-"))
-    {
-      tagfiledir = cwd;
-    }
+    tagfiledir = cwd;
   else
-    {
-      tagfiledir = absolute_dirname (tagfile, cwd);
-    }
+    tagfiledir = absolute_dirname (tagfile, cwd);
 
   init ();			/* set up boolean "functions" */
 
@@ -3451,91 +3457,63 @@
   return -1;
 }
 
-/* Support for Prolog.  */
-
-/* Whole head (not only functor, but also arguments)
-   is gotten in compound term. */
-void
-prolog_getit (s)
-     char *s;
-{
-  char *save_s;
-  int insquote, npar;
-
-  save_s = s;
-  insquote = FALSE;
-  npar = 0;
-  while (1)
-    {
-      if (s[0] == '\0')		/* syntax error. */
-	return;
-      else if (insquote && s[0] == '\'' && s[1] == '\'')
-	s += 2;
-      else if (s[0] == '\'')
-	{
-	  insquote = !insquote;
-	  s++;
-	}
-      else if (!insquote && s[0] == '(')
-	{
-	  npar++;
-	  s++;
-	}
-      else if (!insquote && s[0] == ')')
-	{
-	  npar--;
-	  s++;
-	  if (npar == 0)
-	    break;
-	  else if (npar < 0)	/* syntax error. */
-	    return;
-	}
-      else if (!insquote && s[0] == '.'
-	       && (isspace (s[1]) || s[1] == '\0'))
-	{			/* fullstop. */
-	  if (npar != 0)	/* syntax error. */
-	    return;
-	  s++;
-	  break;
-	}
-      else
-	s++;
-    }
-  pfnote ((CTAGS) ? savenstr (save_s, s-save_s) : NULL, TRUE,
-	  save_s, s-save_s, lineno, linecharno);
-}
-
-/* It is assumed that prolog predicate starts from column 0. */
+/*
+ * Prolog support (rewritten) by Anders Lindgren, Mar. 96
+ *
+ * Assumes that the predicate starts at column 0.
+ * Only the first clause of a predicate is added. 
+ */
 void
 Prolog_functions (inf)
      FILE *inf;
 {
-  void skip_comment (), prolog_getit ();
-
-  lineno = linecharno = charno = 0;
+  int prolog_pred ();
+  void prolog_skip_comment ();
+
+  char * last;
+  int len;
+  int allocated;
+
+  allocated = 0;
+  len = 0;
+  last = NULL;
+
+  lineno = 0;
+  linecharno = 0;
+  charno = 0;
+
   while (!feof (inf))
     {
       lineno++;
       linecharno += charno;
-      charno = readline (&lb, inf) + 1;	/* 1 for newline. */
+      charno = readline (&lb, inf);
       dbp = lb.buffer;
-      if (isspace (dbp[0]))	/* not predicate header. */
+      if (dbp[0] == '\0')	/* Empty line */
 	continue;
-      else if (dbp[0] == '%')	/* comment. */
+      else if (isspace (dbp[0])) /* Not a predicate */
 	continue;
       else if (dbp[0] == '/' && dbp[1] == '*')	/* comment. */
-	skip_comment (&lb, inf, &lineno, &linecharno);
-      else			/* found. */
-	prolog_getit (dbp);
+	prolog_skip_comment (&lb, inf, &lineno, &linecharno);
+      else if (len = prolog_pred (dbp, last)) 
+	{
+	  /* Predicate.  Store the function name so that we only
+	   * generates a tag for the first clause.  */
+	  if (last == NULL)
+	    last = xnew(len + 1, char);
+	  else if (len + 1 > allocated)
+	    last = (char *) xrealloc(last, len + 1);
+	  allocated = len + 1;
+	  strncpy (last, dbp, len);
+	  last[len] = '\0';
+	}
     }
 }
 
+
 void
-skip_comment (plb, inf, plineno, plinecharno)
+prolog_skip_comment (plb, inf)
      struct linebuffer *plb;
      FILE *inf;
-     int *plineno;		/* result */
-     long *plinecharno;		/* result */
 {
   char *cp;
 
@@ -3544,11 +3522,345 @@
       for (cp = plb->buffer; *cp != '\0'; cp++)
 	if (cp[0] == '*' && cp[1] == '/')
 	  return;
-      (*plineno)++;
-      *plinecharno += readline (plb, inf) + 1; /* 1 for newline. */
+      lineno++;
+      linecharno += readline (plb, inf);
     }
   while (!feof(inf));
 }
+
+/*
+ * A predicate definition is added if it matches:
+ *     <beginning of line><Prolog Atom><whitespace>(
+ *
+ * It is added to the tags database if it doesn't match the
+ * name of the previous clause header.
+ *
+ * Return the size of the name of the predicate, or 0 if no header
+ * was found.
+ */
+int
+prolog_pred (s, last)
+     char *s;
+     char *last;		/* Name of last clause. */
+{
+  int prolog_atom();
+  int prolog_white();
+
+  int pos;
+  int len;
+
+  pos = prolog_atom(s, 0);
+  if (pos < 1)
+    return 0;
+
+  len = pos;
+  pos += prolog_white(s, pos);
+
+  if ((s[pos] == '(') || (s[pos] == '.'))
+    {
+      if (s[pos] == '(')
+	pos++;
+
+      /* Save only the first clause. */
+      if ((last == NULL) ||
+	  (len != strlen(last)) ||
+	  (strncmp(s, last, len) != 0))
+	{
+	  pfnote ((CTAGS) ? savenstr (s, len) : NULL, TRUE,
+		  s, pos, lineno, linecharno);
+	  return len;
+	}
+    }
+  return 0;
+}
+
+/*
+ * Consume a Prolog atom.
+ * Return the number of bytes consumed, or -1 if there was an error.
+ *
+ * A prolog atom, in this context, could be one of:
+ * - An alphanumeric sequence, starting with a lower case letter.
+ * - A quoted arbitrary string. Single quotes can escape themselves.
+ *   Backslash quotes everything.
+ */
+int
+prolog_atom (s, pos)
+     char *s;
+     int pos;
+{
+  int origpos;
+
+  origpos = pos;
+
+  if (islower(s[pos]) || (s[pos] == '_'))
+    {
+      /* The atom is unquoted. */
+      pos++;
+      while (isalnum(s[pos]) || (s[pos] == '_'))
+	{
+	  pos++;
+	}
+      return pos - origpos;
+    }
+  else if (s[pos] == '\'')
+    {
+      pos++;
+
+      while (1) 
+	{
+	  if (s[pos] == '\'')
+	    {
+	      pos++;
+	      if (s[pos] != '\'')
+		break;
+	      pos++;		/* A double quote */
+	    }
+	  else if (s[pos] == '\0')
+	    /* Multiline quoted atoms are ignored. */
+	    return -1;
+	  else if (s[pos] == '\\')
+	    {
+	      if (s[pos+1] == '\0')
+		return -1;
+	      pos += 2;
+	    }
+	  else
+	    pos++;
+	}
+      return pos - origpos;
+    }
+  else
+    return -1;
+}
+
+/* Consume whitespace.  Return the number of bytes eaten. */
+int
+prolog_white (s, pos)
+     char *s;
+     int pos;
+{
+  int origpos;
+
+  origpos = pos;
+
+  while (isspace(s[pos]))
+    pos++;
+
+  return pos - origpos;
+}
+
+/* 
+ * Support for Erlang  --  Anders Lindgren, Feb 1996.
+ *
+ * Generates tags for functions, defines, and records.
+ *
+ * Assumes that Erlang functions start at column 0.
+ */
+void
+Erlang_functions (inf)
+     FILE *inf;
+{
+  int erlang_func ();
+  void erlang_attribute ();
+
+  char * last;
+  int len;
+  int allocated;
+
+  allocated = 0;
+  len = 0;
+  last = NULL;
+
+  lineno = 0;
+  linecharno = 0;
+  charno = 0;
+
+  while (!feof (inf))
+    {
+      lineno++;
+      linecharno += charno;
+      charno = readline (&lb, inf);
+      dbp = lb.buffer;
+      if (dbp[0] == '\0')	/* Empty line */
+	continue;
+      else if (isspace (dbp[0])) /* Not function nor attribute */
+	continue;
+      else if (dbp[0] == '%')	/* comment */
+	continue;
+      else if (dbp[0] == '"')	/* Sometimes, strings start in column one */
+	continue;
+      else if (dbp[0] == '-') 	/* attribute, e.g. "-define" */
+	{
+	  erlang_attribute(dbp);
+	  last = NULL;
+	}
+      else if (len = erlang_func (dbp, last)) 
+	{
+	  /* 
+	   * Function.  Store the function name so that we only
+	   * generates a tag for the first clause.
+	   */
+	  if (last == NULL)
+	    last = xnew(len + 1, char);
+	  else if (len + 1 > allocated)
+	    last = (char *) xrealloc(last, len + 1);
+	  allocated = len + 1;
+	  strncpy (last, dbp, len);
+	  last[len] = '\0';
+	}
+    }
+}
+
+
+/*
+ * A function definition is added if it matches:
+ *     <beginning of line><Erlang Atom><whitespace>(
+ *
+ * It is added to the tags database if it doesn't match the
+ * name of the previous clause header.
+ *
+ * Return the size of the name of the function, or 0 if no function
+ * was found.
+ */
+int
+erlang_func (s, last)
+     char *s;
+     char *last;		/* Name of last clause. */
+{
+  int erlang_atom ();
+  int erlang_white ();
+
+  int pos;
+  int len;
+
+  pos = erlang_atom(s, 0);
+  if (pos < 1)
+    return 0;
+
+  len = pos;
+  pos += erlang_white(s, pos);
+
+  if (s[pos++] == '(')
+    {
+      /* Save only the first clause. */
+      if ((last == NULL) ||
+	  (len != strlen(last)) ||
+	  (strncmp(s, last, len) != 0))
+	{
+	  pfnote ((CTAGS) ? savenstr (s, len) : NULL, TRUE,
+		  s, pos, lineno, linecharno);
+	  return len;
+	}
+    }
+  return 0;
+}
+
+
+/*
+ * Handle attributes.  Currently, tags are generated for defines 
+ * and records.
+ *
+ * They are on the form:
+ * -define(foo, bar).
+ * -define(Foo(M, N), M+N).
+ * -record(graph, {vtab = notable, cyclic = true}).
+ */
+void
+erlang_attribute (s)
+     char *s;
+{
+  int erlang_atom ();
+  int erlang_white ();
+
+  int pos;
+  int len;
+
+  if ((strncmp(s, "-define", 7) == 0) ||
+      (strncmp(s, "-record", 7) == 0))
+    {
+      pos = 7;
+      pos += erlang_white(s, pos);
+
+      if (s[pos++] == '(') 
+	{
+	  pos += erlang_white(s, pos);
+	
+	  if (len = erlang_atom(s, pos))
+	    {
+	      pfnote ((CTAGS) ? savenstr (& s[pos], len) : NULL, TRUE,
+		      s, pos + len, lineno, linecharno);
+	    }
+	}
+    }
+  return;
+}
+
+
+/*
+ * Consume an Erlang atom (or variable).
+ * Return the number of bytes consumed, or -1 if there was an error.
+ */
+int
+erlang_atom (s, pos)
+     char *s;
+     int pos;
+{
+  int origpos;
+
+  origpos = pos;
+
+  if (isalpha (s[pos]) || s[pos] == '_')
+    {
+      /* The atom is unquoted. */
+      pos++;
+      while (isalnum (s[pos]) || s[pos] == '_')
+	pos++;
+      return pos - origpos;
+    }
+  else if (s[pos] == '\'')
+    {
+      pos++;
+
+      while (1) 
+	{
+	  if (s[pos] == '\'')
+	    {
+	      pos++;
+	      break;
+	    }
+	  else if (s[pos] == '\0')
+	    /* Multiline quoted atoms are ignored. */
+	    return -1;
+	  else if (s[pos] == '\\')
+	    {
+	      if (s[pos+1] == '\0')
+		return -1;
+	      pos += 2;
+	    }
+	  else
+	    pos++;
+	}
+      return pos - origpos;
+    }
+  else
+    return -1;
+}
+
+/* Consume whitespace.  Return the number of bytes eaten */
+int
+erlang_white (s, pos)
+     char *s;
+     int pos;
+{
+  int origpos;
+
+  origpos = pos;
+
+  while (isspace (s[pos]))
+    pos++;
+
+  return pos - origpos;
+}
 
 #ifdef ETAGS_REGEXPS
 /* Take a string like "/blah/" and turn it into "blah", making sure
@@ -3754,6 +4066,7 @@
 	}
       if (c == EOF)
 	{
+	  *p = '\0';
 	  chars_deleted = 0;
 	  break;
 	}
@@ -3843,6 +4156,9 @@
 just_read_file (inf)
      FILE *inf;
 {
+  lineno = 0;
+  charno = 0;
+
   while (!feof (inf))
     {
       ++lineno;