* Francesco Potorti` (F.Potorti@cnuce.cnr.it) is the current maintainer.
*/
-char pot_etags_version[] = "@(#) pot revision number is 11.66";
+char pot_etags_version[] = "@(#) pot revision number is 11.77";
#define TRUE 1
#define FALSE 0
# define MAXPATHLEN _MAX_PATH
#endif
+#if !defined (MSDOS) && !defined (WINDOWSNT) && defined (STDC_HEADERS)
+#include <stdlib.h>
+#include <string.h>
+#endif
+
#ifdef HAVE_CONFIG_H
# include <config.h>
/* On some systems, Emacs defines static as nothing for the sake
#define streq(s,t) ((DEBUG &&!(s)&&!(t)&&(abort(),1)) || !strcmp(s,t))
#define strneq(s,t,n) ((DEBUG &&!(s)&&!(t)&&(abort(),1)) || !strncmp(s,t,n))
-#define lowcase(c) tolower ((unsigned char)c)
+#define lowcase(c) tolower ((char)c)
#define iswhite(arg) (_wht[arg]) /* T if char is white */
#define begtoken(arg) (_btk[arg]) /* T if char can start token */
char *etags_strchr (), *etags_strrchr ();
char *etags_getcwd ();
char *relative_filename (), *absolute_filename (), *absolute_dirname ();
+void grow_linebuffer ();
long *xmalloc (), *xrealloc ();
typedef void Lang_function ();
* `readline' reads a line from a stream into a linebuffer and works
* regardless of the length of the line.
*/
-#define GROW_LINEBUFFER(buf,toksize) \
-while (buf.size < toksize) \
- buf.buffer = (char *) xrealloc (buf.buffer, buf.size *= 2)
struct linebuffer
{
long size;
/* 0 struct/enum/union decls, and C++ */
/* member functions. */
logical constantypedefs; /* -d: create tags for C #define and enum */
- /* constants. Enum consts not implemented. */
+ /* constants. */
/* -D: opposite of -d. Default under ctags. */
logical update; /* -u: update tags */
logical vgrind_style; /* -v: create vgrind style index output */
void
print_version ()
{
- printf ("%s for Emacs version %s\n", (CTAGS) ? "ctags" : "etags", VERSION);
+ printf ("%s (GNU Emacs %s)\n", (CTAGS) ? "ctags" : "etags", VERSION);
+ puts ("Copyright (C) 1996 Free Software Foundation, Inc. and Ken Arnold");
+ puts ("This program is distributed under the same terms as Emacs");
exit (GOOD);
}
if (CTAGS)
puts ("-d, --defines\n\
- Create tag entries for constant C #defines, too.");
+ Create tag entries for C #define constants and enum constants, too.");
else
puts ("-D, --no-defines\n\
- Don't create tag entries for constant C #defines. This makes\n\
- the tags file smaller.");
+ Don't create tag entries for C #define constants and enum constants.\n\
+ This makes the tags file smaller.");
if (!CTAGS)
{
print_language_names ();
+ puts ("");
+ puts ("Report bugs to bug-gnu-emacs@prep.ai.mit.edu");
+
exit (GOOD);
}
/*
* If etags, always find typedefs and structure tags. Why not?
- * Also default is to find macro constants.
+ * Also default is to find macro constants and enum constants.
*/
if (!CTAGS)
typedefs = typedefs_and_cplusplus = constantypedefs = TRUE;
because we want them ordered. Let's do it now. */
if (cxref_style)
{
- tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
- if (tagf == NULL)
- pfatal (tagfile);
put_entries (head);
exit (GOOD);
}
"mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
tagfile, argbuffer[i].what, tagfile);
if (system (cmd) != GOOD)
- fatal ("failed to execute shell command");
+ fatal ("failed to execute shell command", NULL);
}
append_to_tagfile = TRUE;
}
sprintf (cmd, "sort %s -o %s", tagfile, tagfile);
exit (system (cmd));
}
- exit (GOOD);
+ return GOOD;
}
{
/* Etags Mode */
if (last_node == NULL)
- fatal ("internal error in add_node", 0);
+ fatal ("internal error in add_node", NULL);
last_node->right = node;
last_node = node;
}
else
{
if (node->name == NULL)
- error ("internal error: NULL name in ctags mode.", 0);
+ error ("internal error: NULL name in ctags mode.", NULL);
if (cxref_style)
{
/*%>*/
enum sym_type
-C_symtype(str, len, c_ext)
+C_symtype (str, len, c_ext)
char *str;
int len;
int c_ext;
{
- register struct C_stab_entry *se = in_word_set(str, len);
+ register struct C_stab_entry *se = in_word_set (str, len);
if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
return st_none;
* consider_token ()
* checks to see if the current token is at the start of a
* function, or corresponds to a typedef, or is a struct/union/enum
- * tag.
+ * tag, or #define, or an enum constant.
*
- * *IS_FUNC gets TRUE iff the token is a function or macro with args.
- * C_EXT is which language we are looking at.
+ * *IS_FUNC gets TRUE iff the token is a function or #define macro
+ * with args. C_EXT is which language we are looking at.
*
* In the future we will need some way to adjust where the end of
* the token is; for instance, implementing the C++ keyword
case dignorerest:
return FALSE;
default:
- error ("internal error: definedef value.", 0);
+ error ("internal error: definedef value.", NULL);
}
/*
* This structdef business is NOT invoked when we are ctags and the
* file is plain C. This is because a struct tag may have the same
* name as another tag, and this loses with ctags.
- *
- * This if statement deals with the typdef state machine as
- * follows: if typdef==ttypedseen and token is struct/union/class/enum,
- * return FALSE. All the other code here is for the structdef
- * state machine.
*/
switch (toktype)
{
}
return FALSE;
}
+
if (structdef == skeyseen)
{
/* Save the tag for struct/union/class, for functions that may be
return FALSE;
}
- /* Detect GNU macros. */
+ /* Detect GNU macros.
+
+ DEFUN note for writers of emacs C code:
+ The DEFUN macro, used in emacs C source code, has a first arg
+ that is a string (the lisp function name), and a second arg that
+ is a C function name. Since etags skips strings, the second arg
+ is tagged. This is unfortunate, as it would be better to tag the
+ first arg. The simplest way to deal with this problem would be
+ to name the tag with a name built from the function name, by
+ removing the initial 'F' character and substituting '-' for '_'.
+ Anyway, this assumes that the conventions of naming lisp
+ functions will never change. Currently, this method is not
+ implemented, so writers of emacs code are recommended to put the
+ first two args of a DEFUN on the same line. */
if (definedef == dnone && toktype == st_C_gnumacro)
{
next_token_is_func = TRUE;
return TRUE;
}
- /*
- * Detecting Objective C constructs.
- */
+ /* Detect Objective C constructs. */
switch (objdef)
{
case onone:
{
objdef = omethodtag;
methodlen = len;
- GROW_LINEBUFFER (token_name, methodlen+1);
+ grow_linebuffer (&token_name, methodlen+1);
strncpy (token_name.buffer, str, len);
token_name.buffer[methodlen] = '\0';
return TRUE;
{
objdef = omethodtag;
methodlen += len;
- GROW_LINEBUFFER (token_name, methodlen+1);
+ grow_linebuffer (&token_name, methodlen+1);
strncat (token_name.buffer, str, len);
return TRUE;
}
return FALSE;
}
- /* A function? */
+ /* A function or enum constant? */
switch (toktype)
{
case st_C_typespec:
if (funcdef != finlist && funcdef != fignore)
funcdef = fnone; /* should be useless */
return FALSE;
- default:
+ case st_none:
+ if (constantypedefs && structdef == sinbody && structtype == st_C_enum)
+ return TRUE;
if (funcdef == fnone)
{
funcdef = ftagseen;
/*
* C_entries ()
- * This routine finds functions, typedefs, #define's and
- * struct/union/enum definitions in C syntax and adds them
- * to the list.
+ * This routine finds functions, typedefs, #define's, enum
+ * constants and struct/union/enum definitions in C syntax
+ * and adds them to the list.
*/
typedef struct
{
definedef = dnone; \
} while (0)
-/* Ideally this macro should never be called wihen tok.valid is FALSE,
- but this would mean that the state machines always guess right. */
-#define make_tag(isfun) do \
+/* This macro should never be called when tok.valid is FALSE, but
+ we must protect about both invalid input and internal errors. */
+#define make_C_tag(isfun) do \
if (tok.valid) { \
char *name = NULL; \
if (CTAGS || tok.named) \
name = savestr (token_name.buffer); \
pfnote (name, isfun, tok.buffer, tok.linelen, tok.lineno, tok.linepos); \
tok.valid = FALSE; \
-} while (0)
+} /* else if (DEBUG) abort (); */ while (0)
void
C_entries (c_ext, inf)
/* Consider token only if some complicated conditions are satisfied. */
if ((definedef != dnone
|| (cblev == 0 && structdef != scolonseen)
- || (cblev == 1 && cplpl && structdef == sinbody))
+ || (cblev == 1 && cplpl && structdef == sinbody)
+ || (structdef == sinbody && structtype == st_C_enum))
&& typdef != tignore
&& definedef != dignorerest
&& funcdef != finlist)
&& is_func)
/* function defined in C++ class body */
{
- GROW_LINEBUFFER (token_name,
+ grow_linebuffer (&token_name,
strlen(structtag)+2+toklen+1);
strcpy (token_name.buffer, structtag);
strcat (token_name.buffer, "::");
else if (objdef == ocatseen)
/* Objective C category */
{
- GROW_LINEBUFFER (token_name,
+ grow_linebuffer (&token_name,
strlen(objtag)+2+toklen+1);
strcpy (token_name.buffer, objtag);
strcat (token_name.buffer, "(");
}
else
{
- GROW_LINEBUFFER (token_name, toklen+1);
+ grow_linebuffer (&token_name, toklen+1);
strncpy (token_name.buffer,
newlb.buffer+tokoff, toklen);
token_name.buffer[toklen] = '\0';
switch_line_buffers ();
}
else
- make_tag (is_func);
+ make_C_tag (is_func);
}
midtoken = FALSE;
}
funcdef = finlist;
continue;
case flistseen:
- make_tag (TRUE);
+ make_C_tag (TRUE);
funcdef = fignore;
break;
case ftagseen:
{
case otagseen:
objdef = oignore;
- make_tag (TRUE);
+ make_C_tag (TRUE);
break;
case omethodtag:
case omethodparm:
objdef = omethodcolon;
methodlen += 1;
- GROW_LINEBUFFER (token_name, methodlen+1);
+ grow_linebuffer (&token_name, methodlen+1);
strcat (token_name.buffer, ":");
break;
}
case ftagseen:
if (yacc_rules)
{
- make_tag (FALSE);
+ make_C_tag (FALSE);
funcdef = fignore;
}
break;
switch (typdef)
{
case tend:
- make_tag (FALSE);
+ make_C_tag (FALSE);
/* FALLTHRU */
default:
typdef = tnone;
{
case omethodtag:
case omethodparm:
- make_tag (TRUE);
+ make_C_tag (TRUE);
objdef = oinbody;
break;
}
if (cblev == 0 && typdef == tend)
{
typdef = tignore;
- make_tag (FALSE);
+ make_C_tag (FALSE);
break;
}
if (funcdef != finlist && funcdef != fignore)
if (*lp != '*')
{
typdef = tignore;
- make_tag (FALSE);
+ make_C_tag (FALSE);
}
break;
} /* switch (typdef) */
break;
if (objdef == ocatseen && parlev == 1)
{
- make_tag (TRUE);
+ make_C_tag (TRUE);
objdef = oignore;
}
if (--parlev == 0)
if (cblev == 0 && typdef == tend)
{
typdef = tignore;
- make_tag (FALSE);
+ make_C_tag (FALSE);
}
}
else if (parlev < 0) /* can happen due to ill-conceived #if's. */
switch (structdef)
{
case skeyseen: /* unnamed struct */
- structtag = "_anonymous_";
structdef = sinbody;
+ structtag = "_anonymous_";
break;
case stagseen:
case scolonseen: /* named struct */
structdef = sinbody;
- make_tag (FALSE);
+ make_C_tag (FALSE);
break;
}
switch (funcdef)
{
case flistseen:
- make_tag (TRUE);
+ make_C_tag (TRUE);
/* FALLTHRU */
case fignore:
funcdef = fnone;
switch (objdef)
{
case otagseen:
- make_tag (TRUE);
+ make_C_tag (TRUE);
objdef = oignore;
break;
case omethodtag:
case omethodparm:
- make_tag (TRUE);
+ make_C_tag (TRUE);
objdef = oinbody;
break;
default:
- /* Neutralize `extern "C" {' grot and look inside structs. */
+ /* Neutralize `extern "C" {' grot. */
if (cblev == 0 && structdef == snone && typdef == tnone)
cblev = -1;
}
case '\0':
if (objdef == otagseen)
{
- make_tag (TRUE);
+ make_C_tag (TRUE);
objdef = oignore;
}
/* If a macro spans multiple lines don't reset its state. */
continue;
/* save all values for later tagging */
- GROW_LINEBUFFER (tline, strlen (lb.buffer) + 1);
+ grow_linebuffer (&tline, strlen (lb.buffer) + 1);
strcpy (tline.buffer, lb.buffer);
save_lineno = lineno;
save_lcno = linecharno;
else if (isspace (dbp[0])) /* Not a predicate */
continue;
else if (dbp[0] == '/' && dbp[1] == '*') /* comment. */
- prolog_skip_comment (&lb, inf, &lineno, &linecharno);
+ prolog_skip_comment (&lb, inf);
else if (len = prolog_pred (dbp, last))
{
/* Predicate. Store the function name so that we only
if (regexp_pattern[0] == '\0')
{
- error ("missing regexp", 0);
+ error ("missing regexp", NULL);
return;
}
if (regexp_pattern[strlen(regexp_pattern)-1] != regexp_pattern[0])
name = scan_separators (regexp_pattern);
if (regexp_pattern[0] == '\0')
{
- error ("null regexp", 0);
+ error ("null regexp", NULL);
return;
}
(void) scan_separators (name);
{
*--p = '\0';
#ifdef DOS_NT
- /* Assume CRLF->LF translation will be performed by Emacs
- when loading this file, so CRs won't appear in the buffer.
- It would be cleaner to compensate within Emacs;
- however, Emacs does not know how many CRs were deleted
- before any given point in the file. */
+ /* Assume CRLF->LF translation will be performed by Emacs
+ when loading this file, so CRs won't appear in the buffer.
+ It would be cleaner to compensate within Emacs;
+ however, Emacs does not know how many CRs were deleted
+ before any given point in the file. */
chars_deleted = 1;
#else
chars_deleted = 2;
char *
etags_getcwd ()
{
-#ifdef MSDOS
- char *p, path[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
-
- getwd (path);
- for (p = path; *p != '\0'; p++)
- if (*p == '\\')
- *p = '/';
- else
- *p = lowcase (*p);
-
- return strdup (path);
-#else /* not MSDOS */
-#if HAVE_GETCWD
+#ifdef HAVE_GETCWD
int bufsize = 200;
char *path = xnew (bufsize, char);
path = xnew (bufsize, char);
}
+#if WINDOWSNT
+ {
+ /* Convert backslashes to slashes. */
+ char *p;
+ for (p = path; *p != '\0'; p++)
+ if (*p == '\\')
+ *p = '/';
+ }
+#endif
+
return path;
-#else /* not MSDOS and not HAVE_GETCWD */
+
+#else /* not HAVE_GETCWD */
+#ifdef MSDOS
+ char *p, path[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
+
+ getwd (path);
+
+ for (p = path; *p != '\0'; p++)
+ if (*p == '\\')
+ *p = '/';
+ else
+ *p = lowcase (*p);
+
+ return strdup (path);
+#else /* not MSDOS */
struct linebuffer path;
FILE *pipe;
pclose (pipe);
return path.buffer;
-#endif /* not HAVE_GETCWD */
#endif /* not MSDOS */
+#endif /* not HAVE_GETCWD */
}
/* Return a newly allocated string containing the filename
{
char *fp, *dp, *abs, *res;
- /* Find the common root of file and dir. */
+ /* Find the common root of file and dir (with a trailing slash). */
abs = absolute_filename (file, cwd);
fp = abs;
dp = dir;
while (*fp++ == *dp++)
continue;
- do
- {
- fp--;
- dp--;
- }
+ fp--, dp--; /* back to the first differing char */
+ do /* look at the equal chars until / */
+ fp--, dp--;
while (*fp != '/');
/* Build a sequence of "../" strings for the resulting relative filename. */
return res;
}
+/* Increase the size of a linebuffer. */
+void
+grow_linebuffer (bufp, toksize)
+ struct linebuffer *bufp;
+ int toksize;
+{
+ while (bufp->size < toksize)
+ bufp->size *= 2;
+ bufp->buffer = (char *) xrealloc (bufp->buffer, bufp->size);
+}
+
/* Like malloc but get fatal error if memory is exhausted. */
long *
xmalloc (size)
{
long *result = (long *) malloc (size);
if (result == NULL)
- fatal ("virtual memory exhausted", 0);
+ fatal ("virtual memory exhausted", NULL);
return result;
}
{
long *result = (long *) realloc (ptr, size);
if (result == NULL)
- fatal ("virtual memory exhausted");
+ fatal ("virtual memory exhausted", NULL);
return result;
}