/* Tags file maker to go with GNU Emacs
Copyright (C) 1984, 87, 88, 89, 93, 94, 95
Free Software Foundation, Inc. and Ken Arnold
+
This file is not considered part of GNU Emacs.
This program is free software; you can redistribute it and/or modify
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+along with this program; if not, write to the Free Software Foundation,
+Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/*
* Authors:
* 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 $Revision: 11.84 $";
#define TRUE 1
#define FALSE 0
#endif
#ifdef MSDOS
-#include <fcntl.h>
-#include <sys/param.h>
+# include <string.h>
+# include <fcntl.h>
+# include <sys/param.h>
#endif /* MSDOS */
#ifdef WINDOWSNT
+# include <stdlib.h>
+# include <fcntl.h>
+# include <string.h>
+# include <io.h>
+# define MAXPATHLEN _MAX_PATH
+#endif
+
+#if !defined (MSDOS) && !defined (WINDOWSNT) && defined (STDC_HEADERS)
#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>
#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.
- Let it undefined to make the program "etags", which makes emacs-style
+ Leave it undefined to make the program "etags", which makes emacs-style
tag tables and tags typedefs, #defines and struct/union/enum by default. */
#ifdef CTAGS
# undef CTAGS
/* 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. */
#define C_STAR 0x00003 /* C* */
#define YACC 0x10000 /* yacc file */
-#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 streq(s,t) ((DEBUG && (s) == NULL && (t) == NULL \
+ && (abort (), 1)) || !strcmp (s, t))
+#define strneq(s,t,n) ((DEBUG && (s) == NULL && (t) == NULL \
+ && (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 */
#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] == '/' \
+ || (fn[1] == ':' && fn[2] == '/'))
#else
# define absolutefn(fn) (fn[0] == '/')
#endif
*
* SYNOPSIS: Type *xnew (int n, Type);
*/
-#define xnew(n,Type) ((Type *) xmalloc ((n) * sizeof (Type)))
+#ifdef chkmalloc
+# include "chkmalloc.h"
+# define xnew(n,Type) ((Type *) trace_xmalloc (__FILE__, __LINE__, \
+ (n) * sizeof (Type)))
+#else
+# define xnew(n,Type) ((Type *) xmalloc ((n) * sizeof (Type)))
+#endif
typedef int logical;
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 ();
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;
void plain_C_entries ();
void Cplusplus_entries ();
void Cstar_entries ();
+void Erlang_functions ();
void Fortran_functions ();
void Yacc_entries ();
void Lisp_functions ();
int lineno; /* line number of current line */
long charno; /* current character number */
-
-long linecharno; /* charno of start of line; not used by C,
- but by every other language. */
+long linecharno; /* charno of start of line */
char *curfile; /* current input file name */
char *tagfile; /* output file */
* `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 */
char *Cstar_suffixes [] =
{ "cs", "hs", NULL };
+char *Erlang_suffixes [] =
+ { "erl", "hrl", NULL };
+
char *Fortran_suffixes [] =
{ "F", "f", "f90", "for", NULL };
{ "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 },
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);
}
{
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.");
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);
}
at_filename
};
-/* This structure helps us allow mixing of --lang and filenames. */
+/* This structure helps us allow mixing of --lang and file names. */
typedef struct
{
enum argument_type arg_type;
/*
v1.05 nmm 26-Jun-86 fn_exp - expand specification of list of file names
- returning in each successive call the next filename matching the input
+ returning in each successive call the next file name matching the input
spec. The function expects that each in_spec passed
to it will be processed to completion; in particular, up to and
including the call following that in which the last matching name
If an error occurs, on return out_spec contains the value
of in_spec when the error occurred.
- With each successive filename returned in out_spec, the
+ With each successive file name returned in out_spec, the
function's return value is one. When there are no more matching
names the function returns zero. If on the first call no file
matches in_spec, or there is any other error, -1 is returned.
system (cmd)
char *cmd;
{
- fprintf (stderr, "system() function not implemented under VMS\n");
+ error ("%s", "system() function not implemented under VMS");
}
#endif
#endif /* VMS */
\f
-void
+int
main (argc, argv)
int argc;
char *argv[];
{
int i;
- unsigned int nincluded_files = 0;
- char **included_files = xnew (argc, char *);
+ unsigned int nincluded_files;
+ char **included_files;
char *this_file;
argument *argbuffer;
- int current_arg = 0, file_count = 0;
+ int current_arg, file_count;
struct linebuffer filename_lb;
#ifdef VMS
logical got_err;
#endif /* DOS_NT */
progname = argv[0];
+ nincluded_files = 0;
+ included_files = xnew (argc, char *);
+ current_arg = 0;
+ file_count = 0;
/* Allocate enough no matter what happens. Overkill, but each one
is small. */
/*
* 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;
break;
case 1:
- /* This means that a filename has been seen. Record it. */
+ /* This means that a file name has been seen. Record it. */
argbuffer[current_arg].arg_type = at_filename;
argbuffer[current_arg].what = optarg;
++current_arg;
case 'o':
if (tagfile)
{
- fprintf (stderr, "%s: -%c option may only be given once.\n",
- progname, opt);
+ error ("-%c option may only be given once.", opt);
suggest_asking_for_help ();
}
tagfile = optarg;
if (nincluded_files == 0 && file_count == 0)
{
- fprintf (stderr, "%s: No input files specified.\n", progname);
+ error ("%s", "No input files specified.");
suggest_asking_for_help ();
}
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] != '/')
+ cwd = concat (cwd, "/", "");
if (streq (tagfile, "-"))
- {
- tagfiledir = cwd;
- }
+ tagfiledir = cwd;
else
- {
- tagfiledir = absolute_dirname (tagfile, cwd);
- }
+ tagfiledir = absolute_dirname (tagfile, cwd);
init (); /* set up boolean "functions" */
if (!CTAGS)
{
if (streq (tagfile, "-"))
- tagf = stdout;
+ {
+ tagf = stdout;
+#ifdef DOS_NT
+ /* Switch redirected `stdout' to binary mode (setting `_fmode'
+ doesn't take effect until after `stdout' is already open). */
+ if (!isatty (fileno (stdout)))
+ setmode (fileno (stdout), O_BINARY);
+#endif /* DOS_NT */
+ }
else
tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
if (tagf == NULL)
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", (char *)NULL);
}
append_to_tagfile = TRUE;
}
sprintf (cmd, "sort %s -o %s", tagfile, tagfile);
exit (system (cmd));
}
- exit (GOOD);
+ return GOOD;
}
return lang->function;
}
- fprintf (stderr, "%s: language \"%s\" not recognized.\n",
- progname, optarg);
+ error ("language \"%s\" not recognized.", optarg);
suggest_asking_for_help ();
/* This point should never be reached. The function should either
{
struct stat stat_buf;
FILE *inf;
+#ifdef DOS_NT
+ char *p;
+
+ for (p = file; *p != '\0'; p++)
+ if (*p == '\\')
+ *p = '/';
+#endif
if (stat (file, &stat_buf) == 0 && !S_ISREG (stat_buf.st_mode))
{
- fprintf (stderr, "Skipping %s: it is not a regular file.\n", file);
+ error ("Skipping %s: it is not a regular file.", file);
return;
}
if (streq (file, tagfile) && !streq (tagfile, "-"))
{
- fprintf (stderr, "Skipping inclusion of %s in self.\n", file);
+ error ("Skipping inclusion of %s in self.", file);
return;
}
inf = fopen (file, "r");
if (absolutefn (file))
{
- /* file is an absolute filename. Canonicalise it. */
+ /* file is an absolute file name. Canonicalise it. */
filename = absolute_filename (file, cwd);
}
else
{
- /* file is a filename relative to cwd. Make it relative
+ /* file is a file name relative to cwd. Make it relative
to the directory of the tags file. */
filename = relative_filename (file, tagfiledir);
}
{
/* Etags Mode */
if (last_node == NULL)
- fatal ("internal error in add_node", 0);
+ fatal ("internal error in add_node", (char *)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.", (char *)NULL);
if (cxref_style)
{
enum sym_type
{
st_none, st_C_objprot, st_C_objimpl, st_C_objend, st_C_gnumacro,
- st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec,
+ st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec
};
/* Feed stuff between (but not including) %[ and %] lines to:
- gperf -c -k1,3 -o -p -r -t
+ gperf -c -k 1,3 -o -p -r -t
%[
struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
%%
@implementation,0, st_C_objimpl
@end, 0, st_C_objend
class, C_PLPL, st_C_struct
+namespace, C_PLPL, st_C_struct
domain, C_STAR, st_C_struct
union, 0, st_C_struct
struct, 0, st_C_struct
enum, 0, st_C_enum
typedef, 0, st_C_typedef
define, 0, st_C_define
+bool, C_PLPL, st_C_typespec
long, 0, st_C_typespec
short, 0, st_C_typespec
int, 0, st_C_typespec
static, 0, st_C_typespec
const, 0, st_C_typespec
volatile, 0, st_C_typespec
+explicit, C_PLPL, st_C_typespec
+mutable, C_PLPL, st_C_typespec
+typename, C_PLPL, st_C_typespec
# DEFUN used in emacs, the next three used in glibc (SYSCALL only for mach).
DEFUN, 0, st_C_gnumacro
SYSCALL, 0, st_C_gnumacro
%]
and replace lines between %< and %> with its output. */
/*%<*/
-/* C code produced by gperf version 1.8.1 (K&R C version) */
-/* Command-line: gperf -c -k1,3 -o -p -r -t */
+/* C code produced by gperf version 2.1 (K&R C version) */
+/* Command-line: gperf -c -k 1,3 -o -p -r -t */
struct C_stab_entry { char *name; int c_ext; enum sym_type type; };
#define MIN_WORD_LENGTH 3
#define MAX_WORD_LENGTH 15
-#define MIN_HASH_VALUE 7
-#define MAX_HASH_VALUE 63
+#define MIN_HASH_VALUE 34
+#define MAX_HASH_VALUE 121
/*
- 29 keywords
- 57 is the maximum key range
+ 34 keywords
+ 88 is the maximum key range
*/
static int
hash (str, len)
- register char *str;
- register int len;
+ register char *str;
+ register unsigned int len;
{
static unsigned char hash_table[] =
{
- 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 17, 63, 63, 63, 4, 14,
- 4, 63, 63, 63, 63, 63, 63, 63, 63, 63,
- 8, 63, 63, 0, 23, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 28, 63, 28,
- 10, 31, 27, 18, 63, 6, 63, 63, 26, 1,
- 11, 2, 29, 63, 29, 16, 26, 13, 15, 63,
- 63, 63, 63, 63, 63, 63, 63, 63,
+ 121, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+ 121, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+ 121, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+ 121, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+ 121, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+ 121, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+ 121, 121, 121, 121, 45, 121, 121, 121, 16, 19,
+ 61, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+ 10, 121, 121, 20, 53, 121, 121, 121, 121, 121,
+ 121, 121, 121, 121, 121, 121, 121, 41, 45, 22,
+ 60, 47, 37, 28, 121, 55, 121, 121, 20, 14,
+ 29, 30, 5, 121, 50, 59, 30, 54, 6, 121,
+ 121, 121, 121, 121, 121, 121, 121, 121,
};
return len + hash_table[str[2]] + hash_table[str[0]];
}
struct C_stab_entry *
-in_word_set (str, len)
+in_word_set (str, len)
register char *str;
- register int len;
+ register unsigned int len;
{
static struct C_stab_entry wordlist[] =
{
- {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"volatile", 0, st_C_typespec},
+ {"PSEUDO", 0, st_C_gnumacro},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"typedef", 0, st_C_typedef},
+ {"typename", C_PLPL, st_C_typespec},
+ {"",}, {"",}, {"",},
{"SYSCALL", 0, st_C_gnumacro},
- {"",}, {"",}, {"",}, {"",}, {"",},
- {"DEFUN", 0, st_C_gnumacro},
- {"",}, {"",}, {"",},
- {"domain", C_STAR, st_C_struct},
- {"",}, {"",}, {"",}, {"",}, {"",},
- {"short", 0, st_C_typespec},
- {"union", 0, st_C_struct},
+ {"",}, {"",}, {"",},
+ {"mutable", C_PLPL, st_C_typespec},
+ {"namespace", C_PLPL, st_C_struct},
+ {"long", 0, st_C_typespec},
+ {"",}, {"",},
+ {"const", 0, st_C_typespec},
+ {"",}, {"",}, {"",},
+ {"explicit", C_PLPL, st_C_typespec},
+ {"",}, {"",}, {"",}, {"",},
{"void", 0, st_C_typespec},
- {"",}, {"",},
- {"PSEUDO", 0, st_C_gnumacro},
- {"double", 0, st_C_typespec},
- {"",}, {"",},
- {"@end", 0, st_C_objend},
- {"@implementation", 0, st_C_objimpl},
+ {"",},
+ {"char", 0, st_C_typespec},
+ {"class", C_PLPL, st_C_struct},
+ {"",}, {"",}, {"",},
{"float", 0, st_C_typespec},
- {"int", 0, st_C_typespec},
- {"",},
- {"unsigned", 0, st_C_typespec},
+ {"",},
+ {"@implementation", 0, st_C_objimpl},
+ {"auto", 0, st_C_typespec},
+ {"",},
+ {"ENTRY", 0, st_C_gnumacro},
+ {"@end", 0, st_C_objend},
+ {"bool", C_PLPL, st_C_typespec},
+ {"domain", C_STAR, st_C_struct},
+ {"",},
+ {"DEFUN", 0, st_C_gnumacro},
+ {"extern", 0, st_C_typespec},
{"@interface", 0, st_C_objprot},
- {"",},
+ {"",}, {"",}, {"",},
+ {"int", 0, st_C_typespec},
+ {"",}, {"",}, {"",}, {"",},
{"signed", 0, st_C_typespec},
- {"long", 0, st_C_typespec},
- {"ENTRY", 0, st_C_gnumacro},
+ {"short", 0, st_C_typespec},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
{"define", 0, st_C_define},
- {"const", 0, st_C_typespec},
- {"",}, {"",}, {"",},
+ {"@protocol", 0, st_C_objprot},
{"enum", 0, st_C_enum},
- {"volatile", 0, st_C_typespec},
{"static", 0, st_C_typespec},
+ {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+ {"union", 0, st_C_struct},
{"struct", 0, st_C_struct},
- {"",}, {"",}, {"",},
- {"@protocol", 0, st_C_objprot},
- {"",}, {"",},
- {"auto", 0, st_C_typespec},
- {"",},
- {"char", 0, st_C_typespec},
- {"class", C_PLPL, st_C_struct},
- {"typedef", 0, st_C_typedef},
- {"extern", 0, st_C_typespec},
+ {"",}, {"",}, {"",}, {"",},
+ {"double", 0, st_C_typespec},
+ {"unsigned", 0, st_C_typespec},
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
/*%>*/
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;
omethodtag, /* after method name */
omethodcolon, /* after method colon */
omethodparm, /* after method parameter */
- oignore, /* wait for @end */
+ oignore /* wait for @end */
} objdef;
/*
* 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.", (char *)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
{
do { \
curlinepos = charno; \
lineno++; \
+ linecharno = charno; \
charno += readline (&curlb, inf); \
lp = curlb.buffer; \
quotednl = FALSE; \
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 \
-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)
+
+void
+make_C_tag (isfun, tokp)
+ logical isfun;
+ TOKEN *tokp;
+{
+ char *name = NULL;
+
+ /* This function should never be called when tok.valid is FALSE, but
+ we must protect against invalid input or internal errors. */
+ if (tokp->valid)
+ {
+ if (CTAGS || tokp->named)
+ name = savestr (token_name.buffer);
+ pfnote (name, isfun,
+ tokp->buffer, tokp->linelen, tokp->lineno, tokp->linepos);
+ tokp->valid = FALSE;
+ }
+ else if (DEBUG)
+ abort ();
+}
+
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, &tok);
}
midtoken = FALSE;
}
funcdef = finlist;
continue;
case flistseen:
- make_tag (TRUE);
+ make_C_tag (TRUE, &tok);
funcdef = fignore;
break;
case ftagseen:
{
case otagseen:
objdef = oignore;
- make_tag (TRUE);
+ make_C_tag (TRUE, &tok);
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, &tok);
funcdef = fignore;
}
break;
switch (typdef)
{
case tend:
- make_tag (FALSE);
+ make_C_tag (FALSE, &tok);
/* FALLTHRU */
default:
typdef = tnone;
{
case omethodtag:
case omethodparm:
- make_tag (TRUE);
+ make_C_tag (TRUE, &tok);
objdef = oinbody;
break;
}
if (cblev == 0 && typdef == tend)
{
typdef = tignore;
- make_tag (FALSE);
+ make_C_tag (FALSE, &tok);
break;
}
if (funcdef != finlist && funcdef != fignore)
/* Make sure that the next char is not a '*'.
This handles constructs like:
typedef void OperatorFun (int fun); */
- if (*lp != '*')
+ if (tok.valid && *lp != '*')
{
typdef = tignore;
- make_tag (FALSE);
+ make_C_tag (FALSE, &tok);
}
break;
} /* switch (typdef) */
break;
if (objdef == ocatseen && parlev == 1)
{
- make_tag (TRUE);
+ make_C_tag (TRUE, &tok);
objdef = oignore;
}
if (--parlev == 0)
if (cblev == 0 && typdef == tend)
{
typdef = tignore;
- make_tag (FALSE);
+ make_C_tag (FALSE, &tok);
}
}
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, &tok);
break;
}
switch (funcdef)
{
case flistseen:
- make_tag (TRUE);
+ make_C_tag (TRUE, &tok);
/* FALLTHRU */
case fignore:
funcdef = fnone;
switch (objdef)
{
case otagseen:
- make_tag (TRUE);
+ make_C_tag (TRUE, &tok);
objdef = oignore;
break;
case omethodtag:
case omethodparm:
- make_tag (TRUE);
+ make_C_tag (TRUE, &tok);
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, &tok);
objdef = oignore;
}
/* If a macro spans multiple lines don't reset its state. */
/* Added by Mosur Mohan, 4/22/88 */
/* Pascal parsing */
-#define GET_NEW_LINE \
-{ \
- linecharno = charno; lineno++; \
- charno += 1 + readline (&lb, inf); \
- dbp = lb.buffer; \
-}
-
/*
* Locates tags for procedures & functions. Doesn't do any type- or
* var-definitions. It does look for the keyword "extern" or
c = *dbp++;
if (c == '\0') /* if end of line */
{
- GET_NEW_LINE;
+ lineno++;
+ linecharno = charno;
+ charno += readline (&lb, inf);
+ dbp = lb.buffer;
if (*dbp == '\0')
continue;
if (!((found_tag && verify_tag) ||
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;
i = TEX_Token (lasthit);
if (0 <= i)
{
- pfnote (NULL, TRUE,
+ pfnote ((char *)NULL, TRUE,
lb.buffer, strlen (lb.buffer), lineno, linecharno);
#if TeX_named_tokens
TEX_getit (lasthit, TEX_toktab[i].len);
return -1;
}
\f
-/* Support for Prolog. */
+/*
+ * 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;
+{
+ 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);
+ dbp = lb.buffer;
+ if (dbp[0] == '\0') /* Empty line */
+ continue;
+ else if (isspace (dbp[0])) /* Not a predicate */
+ continue;
+ else if (dbp[0] == '/' && dbp[1] == '*') /* comment. */
+ prolog_skip_comment (&lb, inf);
+ else if (len = prolog_pred (dbp, last))
+ {
+ /* Predicate. Store the function name so that we only
+ generate 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';
+ }
+ }
+}
+
-/* Whole head (not only functor, but also arguments)
- is gotten in compound term. */
void
-prolog_getit (s)
+prolog_skip_comment (plb, inf)
+ struct linebuffer *plb;
+ FILE *inf;
+{
+ char *cp;
+
+ do
+ {
+ for (cp = plb->buffer; *cp != '\0'; cp++)
+ if (cp[0] == '*' && cp[1] == '/')
+ return;
+ 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. */
{
- char *save_s;
- int insquote, npar;
+ int prolog_atom();
+ int prolog_white();
- save_s = s;
- insquote = FALSE;
- npar = 0;
- while (1)
+ 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[0] == '\0') /* syntax error. */
- return;
- else if (insquote && s[0] == '\'' && s[1] == '\'')
- s += 2;
- else if (s[0] == '\'')
+ if (s[pos] == '(')
+ pos++;
+
+ /* Save only the first clause. */
+ if ((last == NULL) ||
+ (len != strlen(last)) ||
+ (strncmp(s, last, len) != 0))
{
- insquote = !insquote;
- s++;
+ pfnote ((CTAGS) ? savenstr (s, len) : NULL, TRUE,
+ s, pos, lineno, linecharno);
+ return len;
}
- else if (!insquote && s[0] == '(')
+ }
+ 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] == '_'))
{
- npar++;
- s++;
+ pos++;
}
- else if (!insquote && s[0] == ')')
+ return pos - origpos;
+ }
+ else if (s[pos] == '\'')
+ {
+ pos++;
+
+ while (1)
{
- 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;
+ 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++;
}
- else
- s++;
+ return pos - origpos;
}
- pfnote ((CTAGS) ? savenstr (save_s, s-save_s) : NULL, TRUE,
- save_s, s-save_s, lineno, linecharno);
+ else
+ return -1;
}
-/* It is assumed that prolog predicate starts from column 0. */
+/* 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;
+}
+\f
+/*
+ * Support for Erlang -- Anders Lindgren, Feb 1996.
+ *
+ * Generates tags for functions, defines, and records.
+ *
+ * Assumes that Erlang functions start at column 0.
+ */
void
-Prolog_functions (inf)
+Erlang_functions (inf)
FILE *inf;
{
- void skip_comment (), prolog_getit ();
+ int erlang_func ();
+ void erlang_attribute ();
+
+ char * last;
+ int len;
+ int allocated;
+
+ allocated = 0;
+ len = 0;
+ last = NULL;
+
+ lineno = 0;
+ linecharno = 0;
+ charno = 0;
- lineno = linecharno = 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 function nor attribute */
continue;
- else if (dbp[0] == '/' && dbp[1] == '*') /* comment. */
- skip_comment (&lb, inf, &lineno, &linecharno);
- else /* found. */
- prolog_getit (dbp);
+ 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
-skip_comment (plb, inf, plineno, plinecharno)
- struct linebuffer *plb;
- FILE *inf;
- int *plineno; /* result */
- long *plinecharno; /* result */
+erlang_attribute (s)
+ char *s;
{
- char *cp;
+ int erlang_atom ();
+ int erlang_white ();
- do
+ int pos;
+ int len;
+
+ if ((strncmp(s, "-define", 7) == 0) ||
+ (strncmp(s, "-record", 7) == 0))
{
- for (cp = plb->buffer; *cp != '\0'; cp++)
- if (cp[0] == '*' && cp[1] == '/')
- return;
- (*plineno)++;
- *plinecharno += readline (plb, inf) + 1; /* 1 for newline. */
+ 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);
+ }
+ }
}
- while (!feof(inf));
+ 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;
}
\f
#ifdef ETAGS_REGEXPS
if (regexp_pattern[0] == '\0')
{
- error ("missing regexp", 0);
+ error ("missing regexp", (char *)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", (char *)NULL);
return;
}
(void) scan_separators (name);
char *in, *out;
struct re_registers *regs;
{
- char *result = NULL, *t;
- int size = 0;
+ char *result, *t;
+ int size, i;
+
+ result = NULL;
+ size = strlen (out);
/* Pass 1: figure out how much size to allocate. */
- for (t = out; *t; ++t)
- {
- if (*t == '\\')
- {
- ++t;
- if (!*t)
- {
- fprintf (stderr, "%s: pattern substitution ends prematurely\n",
- progname);
- return NULL;
- }
- if (isdigit (*t))
- {
- int dig = *t - '0';
- size += regs->end[dig] - regs->start[dig];
- }
- }
- }
+ if (out[strlen (out) - 1] == '\\')
+ fatal ("pattern error in %s", out);
+ for (t = out; *t != '\0'; ++t)
+ if (*t == '\\' && isdigit (*++t))
+ {
+ int dig = *t - '0';
+ size += regs->end[dig] - regs->start[dig] - 2;
+ }
/* Allocate space and do the substitutions. */
result = xnew (size + 1, char);
- size = 0;
- for (; *out; ++out)
+ for (i = 0; *out != '\0'; ++out)
{
- if (*out == '\\')
+ if (*out == '\\' && isdigit (*++out))
{
- ++out;
- if (isdigit (*out))
- {
- /* Using "dig2" satisfies my debugger. Bleah. */
- int dig2 = *out - '0';
- strncpy (result + size, in + regs->start[dig2],
- regs->end[dig2] - regs->start[dig2]);
- size += regs->end[dig2] - regs->start[dig2];
- }
- else
- result[size++] = *out;
+ /* Using "dig2" satisfies my debugger. Bleah. */
+ int dig2 = *out - '0';
+ int diglen = regs->end[dig2] - regs->start[dig2];
+ strncpy (result + i, in + regs->start[dig2], diglen);
+ i += diglen;
}
else
- result[size++] = *out;
+ result[i++] = *out;
}
- result[size] = '\0';
+ result[i] = '\0';
+ if (DEBUG && i > size)
+ abort ();
return result;
}
}
if (c == EOF)
{
+ *p = '\0';
chars_deleted = 0;
break;
}
if (p > buffer && p[-1] == '\r')
{
*--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. */
+ chars_deleted = 1;
+#else
chars_deleted = 2;
+#endif
}
else
{
else
{
/* Make an unnamed tag. */
- pfnote (NULL, TRUE,
+ pfnote ((char *)NULL, TRUE,
linebuffer->buffer, match, lineno, linecharno);
}
break;
just_read_file (inf)
FILE *inf;
{
+ lineno = 0;
+ charno = 0;
+
while (!feof (inf))
{
++lineno;
char *
etags_getcwd ()
{
-#ifdef DOS_NT
- char *p, path[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS. */
-
- getwd (path);
- p = path;
- while (*p)
- if (*p == '\\')
- *p++ = '/';
- else
- *p++ = lowcase (*p);
-
- return strdup (path);
-#else /* not DOS_NT */
-#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 DOS_NT 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 MSDOS */
#endif /* not HAVE_GETCWD */
-#endif /* not DOS_NT */
}
-/* Return a newly allocated string containing the filename
+/* Return a newly allocated string containing the file name
of FILE relative to the absolute directory DIR (which
should end with a slash). */
char *
char *file, *dir;
{
char *fp, *dp, *abs, *res;
+ int i;
- /* 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. */
- for (dp = etags_strchr (dp + 1, '/'), res = "";
- dp != NULL;
- dp = etags_strchr (dp + 1, '/'))
- {
- res = concat (res, "../", "");
- }
-
- /* Add the filename relative to the common root of file and dir. */
- res = concat (res, fp + 1, "");
+ /* Build a sequence of "../" strings for the resulting relative file name. */
+ i = 0;
+ while ((dp = etags_strchr (dp + 1, '/')) != NULL)
+ i += 1;
+ res = xnew (3*i + strlen (fp + 1) + 1, char);
+ res[0] = '\0';
+ while (i-- > 0)
+ strcat (res, "../");
+
+ /* Add the file name relative to the common root of file and dir. */
+ strcat (res, fp + 1);
free (abs);
return res;
}
/* Return a newly allocated string containing the
- absolute filename of FILE given CWD (which should
+ absolute file name of FILE given CWD (which should
end with a slash). */
char *
absolute_filename (file, cwd)
char *slashp, *cp, *res;
if (absolutefn (file))
- res = concat (file, "", "");
+ res = savestr (file);
+#ifdef DOS_NT
+ /* We don't support non-absolute file names with a drive
+ letter, like `d:NAME' (it's too much hassle). */
+ else if (file[1] == ':')
+ fatal ("%s: relative file names with drive letters not supported", file);
+#endif
else
res = concat (cwd, file, "");
cp = slashp;
do
cp--;
- while (cp >= res && *cp != '/');
- if (*cp == '/')
- {
- strcpy (cp, slashp + 3);
- }
- else /* else (cp == res) */
- {
- if (slashp[3] != '\0')
- strcpy (cp, slashp + 4);
- else
- return ".";
- }
+ while (cp >= res && !absolutefn (cp));
+ if (cp < res)
+ cp = slashp; /* the absolute name begins with "/.." */
+#ifdef DOS_NT
+ /* Under MSDOS and NT we get `d:/NAME' as absolute
+ file name, so the luser could say `d:/../NAME'.
+ We silently treat this as `d:/NAME'. */
+ else if (cp[0] != '/')
+ cp = slashp;
+#endif
+ strcpy (cp, slashp + 3);
slashp = cp;
continue;
}
slashp = etags_strchr (slashp + 1, '/');
}
-
- return res;
+
+ if (res[0] == '\0')
+ return savestr ("/");
+ else
+ return res;
}
/* Return a newly allocated string containing the absolute
- filename of dir where FILE resides given CWD (which should
+ file name of dir where FILE resides given CWD (which should
end with a slash). */
char *
absolute_dirname (file, cwd)
{
char *slashp, *res;
char save;
+#ifdef DOS_NT
+ char *p;
+
+ for (p = file; *p != '\0'; p++)
+ if (*p == '\\')
+ *p = '/';
+#endif
slashp = etags_strrchr (file, '/');
if (slashp == NULL)
- return cwd;
+ return savestr (cwd);
save = slashp[1];
slashp[1] = '\0';
res = absolute_filename (file, cwd);
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", (char *)NULL);
return result;
}
{
long *result = (long *) realloc (ptr, size);
if (result == NULL)
- fatal ("virtual memory exhausted");
+ fatal ("virtual memory exhausted", (char *)NULL);
return result;
}