char pot_etags_version[] = "@(#) pot revision number is 12.11";
#define TRUE 1
#define FALSE 0
#ifndef DEBUG
# define DEBUG FALSE
#endif
#ifdef MSDOS
# include <string.h>
# include <fcntl.h>
# include <sys/param.h>
#endif
#ifdef WINDOWSNT
# include <stdlib.h>
# include <fcntl.h>
# include <string.h>
# include <io.h>
# define MAXPATHLEN _MAX_PATH
#endif
#ifdef HAVE_CONFIG_H
# include <config.h>
# undef static
# define ETAGS_REGEXPS
# define LONG_OPTIONS
#endif
#if !defined (MSDOS) && !defined (WINDOWSNT) && defined (STDC_HEADERS)
#include <stdlib.h>
#include <string.h>
#endif
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#ifndef errno
extern int errno;
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#if !defined (S_ISREG) && defined (S_IFREG)
# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#endif
#ifdef LONG_OPTIONS
# include <getopt.h>
#else
# define getopt_long(argc,argv,optstr,lopts,lind) getopt (argc, argv, optstr)
extern char *optarg;
extern int optind, opterr;
#endif
#ifdef ETAGS_REGEXPS
# include <regex.h>
#endif
#ifdef CTAGS
# undef CTAGS
# define CTAGS TRUE
#else
# define CTAGS FALSE
#endif
#ifdef VMS
# define GOOD 1
# define BAD 0
#else
# define GOOD 0
# define BAD 1
#endif
#define C_PLPL 0x00001
#define C_STAR 0x00003
#define C_JAVA 0x00005
#define YACC 0x10000
#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 ((char)c)
#define CHARS 256
#define CHAR(x) ((int)x & (CHARS - 1))
#define iswhite(c) (_wht[CHAR(c)])
#define notinname(c) (_nin[CHAR(c)])
#define begtoken(c) (_btk[CHAR(c)])
#define intoken(c) (_itk[CHAR(c)])
#define endtoken(c) (_etk[CHAR(c)])
#ifdef DOS_NT
# define absolutefn(fn) (fn[0] == '/' \
|| (fn[1] == ':' && fn[2] == '/'))
#else
# define absolutefn(fn) (fn[0] == '/')
#endif
#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 bool;
typedef struct nd_st
{
char *name;
char *file;
bool is_func;
bool been_warned;
int lno;
long cno;
char *pat;
struct nd_st *left, *right;
} NODE;
extern char *getenv ();
char *concat ();
char *savenstr (), *savestr ();
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 ();
void Asm_labels ();
void C_entries ();
void default_C_entries ();
void plain_C_entries ();
void Cjava_entries ();
void Cobol_paragraphs ();
void Cplusplus_entries ();
void Cstar_entries ();
void Erlang_functions ();
void Fortran_functions ();
void Yacc_entries ();
void Lisp_functions ();
void Pascal_functions ();
void Perl_functions ();
void Postscript_functions ();
void Prolog_functions ();
void Scheme_functions ();
void TeX_functions ();
void just_read_file ();
Lang_function *get_language_from_name ();
Lang_function *get_language_from_interpreter ();
Lang_function *get_language_from_suffix ();
int total_size_of_entries ();
long readline ();
long readline_internal ();
#ifdef ETAGS_REGEXPS
void analyse_regex ();
void add_regex ();
#endif
void add_node ();
void error ();
void suggest_asking_for_help ();
void fatal (), pfatal ();
void find_entries ();
void free_tree ();
void getit ();
void init ();
void initbuffer ();
void pfnote (), new_pfnote ();
void process_file ();
void put_entries ();
void takeprec ();
char searchar = '/';
int lineno;
long charno;
long linecharno;
char *curfile;
char *tagfile;
char *progname;
char *cwd;
char *tagfiledir;
FILE *tagf;
NODE *head;
struct linebuffer
{
long size;
int len;
char *buffer;
};
struct linebuffer lb;
struct linebuffer token_name;
struct
{
long linepos;
struct linebuffer lb;
} lbs[2];
bool _wht[CHARS], _nin[CHARS], _itk[CHARS], _btk[CHARS], _etk[CHARS];
char
*white = " \f\t\n\013",
*nonam =" \f\t\n\013(=,[;",
*endtk = " \t\n\013\"'#()[]{}=-+%*/&|^~!<>;,.:?",
*begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~@",
*midtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
bool append_to_tagfile;
bool typedefs;
bool typedefs_and_cplusplus;
bool constantypedefs;
bool globals;
bool members;
bool update;
bool vgrind_style;
bool no_warnings;
bool cxref_style;
bool cplusplus;
bool noindentypedefs;
#ifdef LONG_OPTIONS
struct option longopts[] =
{
{ "append", no_argument, NULL, 'a' },
{ "backward-search", no_argument, NULL, 'B' },
{ "c++", no_argument, NULL, 'C' },
{ "cxref", no_argument, NULL, 'x' },
{ "defines", no_argument, NULL, 'd' },
{ "no-defines", no_argument, NULL, 'D' },
{ "globals", no_argument, &globals, TRUE },
{ "no-globals", no_argument, &globals, FALSE },
{ "help", no_argument, NULL, 'h' },
{ "help", no_argument, NULL, 'H' },
{ "ignore-indentation", no_argument, NULL, 'I' },
{ "include", required_argument, NULL, 'i' },
{ "language", required_argument, NULL, 'l' },
{ "members", no_argument, &members, TRUE },
{ "no-members", no_argument, &members, FALSE },
{ "no-warn", no_argument, NULL, 'w' },
{ "output", required_argument, NULL, 'o' },
#ifdef ETAGS_REGEXPS
{ "regex", required_argument, NULL, 'r' },
{ "no-regex", no_argument, NULL, 'R' },
#endif
{ "typedefs", no_argument, NULL, 't' },
{ "typedefs-and-c++", no_argument, NULL, 'T' },
{ "update", no_argument, NULL, 'u' },
{ "version", no_argument, NULL, 'V' },
{ "vgrind", no_argument, NULL, 'v' },
{ 0 }
};
#endif
#ifdef ETAGS_REGEXPS
struct pattern
{
struct re_pattern_buffer *pattern;
struct re_registers regs;
char *name_pattern;
bool error_signaled;
};
int num_patterns = 0;
struct pattern *patterns = NULL;
#endif
Lang_function *lang_func = NULL;
char *Asm_suffixes [] = { "a",
"asm",
"def",
"inc",
"ins",
"s", "sa",
"S",
"src",
NULL
};
char *default_C_suffixes [] =
{ "c", "h", NULL };
char *Cplusplus_suffixes [] =
{ "C", "H", "c++", "cc", "cpp", "cxx", "h++", "hh", "hpp", "hxx",
"M",
"pdb",
NULL };
char *Cjava_suffixes [] =
{ "java", NULL };
char *Cobol_suffixes [] =
{ "COB", "cob", NULL };
char *Cstar_suffixes [] =
{ "cs", "hs", NULL };
char *Erlang_suffixes [] =
{ "erl", "hrl", NULL };
char *Fortran_suffixes [] =
{ "F", "f", "f90", "for", NULL };
char *Lisp_suffixes [] =
{ "cl", "clisp", "el", "l", "lisp", "lsp", "ml", NULL };
char *Pascal_suffixes [] =
{ "p", "pas", NULL };
char *Perl_suffixes [] =
{ "pl", "pm", NULL };
char *Perl_interpreters [] =
{ "perl", "@PERL@", NULL };
char *plain_C_suffixes [] =
{ "pc",
"m",
"lm",
NULL };
char *Postscript_suffixes [] =
{ "ps", NULL };
char *Prolog_suffixes [] =
{ "prolog", NULL };
char *Scheme_suffixes [] =
{ "SCM", "SM", "oak", "sch", "scheme", "scm", "sm", "t", NULL };
char *TeX_suffixes [] =
{ "TeX", "bib", "clo", "cls", "ltx", "sty", "tex", NULL };
char *Yacc_suffixes [] =
{ "y", "ym", "yy", "yxx", "y++", NULL };
struct lang_entry
{
char *name;
Lang_function *function;
char **suffixes;
char **interpreters;
};
struct lang_entry lang_names [] =
{
{ "asm", Asm_labels, Asm_suffixes, NULL },
{ "c", default_C_entries, default_C_suffixes, NULL },
{ "c++", Cplusplus_entries, Cplusplus_suffixes, NULL },
{ "c*", Cstar_entries, Cstar_suffixes, NULL },
{ "cobol", Cobol_paragraphs, Cobol_suffixes, NULL },
{ "erlang", Erlang_functions, Erlang_suffixes, NULL },
{ "fortran", Fortran_functions, Fortran_suffixes, NULL },
{ "java", Cjava_entries, Cjava_suffixes, NULL },
{ "lisp", Lisp_functions, Lisp_suffixes, NULL },
{ "pascal", Pascal_functions, Pascal_suffixes, NULL },
{ "perl", Perl_functions, Perl_suffixes, Perl_interpreters },
{ "postscript", Postscript_functions, Postscript_suffixes, NULL },
{ "proc", plain_C_entries, plain_C_suffixes, NULL },
{ "prolog", Prolog_functions, Prolog_suffixes, NULL },
{ "scheme", Scheme_functions, Scheme_suffixes, NULL },
{ "tex", TeX_functions, TeX_suffixes, NULL },
{ "yacc", Yacc_entries, Yacc_suffixes, NULL },
{ "auto", NULL },
{ "none", just_read_file },
{ NULL, NULL }
};
void
print_language_names ()
{
struct lang_entry *lang;
char **ext;
puts ("\nThese are the currently supported languages, along with the\n\
default file name suffixes:");
for (lang = lang_names; lang->name != NULL; lang++)
{
printf ("\t%s\t", lang->name);
if (lang->suffixes != NULL)
for (ext = lang->suffixes; *ext != NULL; ext++)
printf (" .%s", *ext);
puts ("");
}
puts ("Where `auto' means use default language for files based on file\n\
name suffix, and `none' means only do regexp processing on files.\n\
If no language is specified and no matching suffix is found,\n\
the first line of the file is read for a sharp-bang (#!) sequence\n\
followed by the name of an interpreter. If no such sequence is found,\n\
Fortran is tried first; if no tags are found, C is tried next.");
}
#ifndef VERSION
# define VERSION "19"
#endif
void
print_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);
}
void
print_help ()
{
printf ("Usage: %s [options] [[regex-option ...] file-name] ...\n\
\n\
These are the options accepted by %s.\n", progname, progname);
#ifdef LONG_OPTIONS
puts ("You may use unambiguous abbreviations for the long option names.");
#else
puts ("Long option names do not work with this executable, as it is not\n\
linked with GNU getopt.");
#endif
puts ("A - as file name means read names from stdin.");
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 ("-B, --backward-search\n\
Write the search commands for the tag entries using '?', the\n\
backward-search command instead of '/', the forward-search command.");
puts ("-C, --c++\n\
Treat files whose name suffix defaults to C language as C++ files.");
if (CTAGS)
puts ("-d, --defines\n\
Create tag entries for C #define constants and enum constants, too.");
else
puts ("-D, --no-defines\n\
Don't create tag entries for C #define constants and enum constants.\n\
This makes the tags file smaller.");
if (!CTAGS)
{
puts ("-i FILE, --include=FILE\n\
Include a note in tag file indicating that, when searching for\n\
a tag, one should also consult the tags file FILE after\n\
checking the current file.");
puts ("-l LANG, --language=LANG\n\
Force the following files to be considered as written in the\n\
named language up to the next --language=LANG option.");
}
if (CTAGS)
puts ("--globals\n\
Create tag entries for global variables in C and derived languages.");
else
puts ("--no-globals\n\
Do not create tag entries for global variables in C and\n\
derived languages. This makes the tags file smaller.");
puts ("--members\n\
Create tag entries for member variables in C and derived languages.");
#ifdef ETAGS_REGEXPS
puts ("-r /REGEXP/, --regex=/REGEXP/ or --regex=@regexfile\n\
Make a tag for each line matching pattern REGEXP in the\n\
following files. regexfile is a file containing one REGEXP\n\
per line. REGEXP is anchored (as if preceded by ^).\n\
The form /REGEXP/NAME/ creates a named tag. For example Tcl\n\
named tags can be created with:\n\
--regex=/proc[ \\t]+\\([^ \\t]+\\)/\\1/.");
puts ("-R, --no-regex\n\
Don't create tags from regexps for the following files.");
#endif
puts ("-o FILE, --output=FILE\n\
Write the tags to FILE.");
puts ("-I, --ignore-indentation\n\
Don't rely on indentation quite as much as normal. Currently,\n\
this means not to assume that a closing brace in the first\n\
column is the final brace of a function or structure\n\
definition in C and C++.");
if (CTAGS)
{
puts ("-t, --typedefs\n\
Generate tag entries for C typedefs.");
puts ("-T, --typedefs-and-c++\n\
Generate tag entries for C typedefs, C struct/enum/union tags,\n\
and C++ member functions.");
puts ("-u, --update\n\
Update the tag entries for the given files, leaving tag\n\
entries for other files in place. Currently, this is\n\
implemented by deleting the existing entries for the given\n\
files and then rewriting the new entries at the end of the\n\
tags file. It is often faster to simply rebuild the entire\n\
tag file than to use this.");
puts ("-v, --vgrind\n\
Generates an index of items intended for human consumption,\n\
similar to the output of vgrind. The index is sorted, and\n\
gives the page number of each item.");
puts ("-w, --no-warn\n\
Suppress warning messages about entries defined in multiple\n\
files.");
puts ("-x, --cxref\n\
Like --vgrind, but in the style of cxref, rather than vgrind.\n\
The output uses line numbers instead of page numbers, but\n\
beyond that the differences are cosmetic; try both to see\n\
which you like.");
}
puts ("-V, --version\n\
Print the version of the program.\n\
-h, --help\n\
Print this help message.");
print_language_names ();
puts ("");
puts ("Report bugs to bug-gnu-emacs@gnu.org");
exit (GOOD);
}
enum argument_type
{
at_language,
at_regexp,
at_filename
};
typedef struct
{
enum argument_type arg_type;
char *what;
Lang_function *function;
} argument;
#ifdef VMS
#define EOS '\0'
#define MAX_FILE_SPEC_LEN 255
typedef struct {
short curlen;
char body[MAX_FILE_SPEC_LEN + 1];
} vspec;
#include <rmsdef.h>
#include <descrip.h>
#define OUTSIZE MAX_FILE_SPEC_LEN
short
fn_exp (out, in)
vspec *out;
char *in;
{
static long context = 0;
static struct dsc$descriptor_s o;
static struct dsc$descriptor_s i;
static bool pass1 = TRUE;
long status;
short retval;
if (pass1)
{
pass1 = FALSE;
o.dsc$a_pointer = (char *) out;
o.dsc$w_length = (short)OUTSIZE;
i.dsc$a_pointer = in;
i.dsc$w_length = (short)strlen(in);
i.dsc$b_dtype = DSC$K_DTYPE_T;
i.dsc$b_class = DSC$K_CLASS_S;
o.dsc$b_dtype = DSC$K_DTYPE_VT;
o.dsc$b_class = DSC$K_CLASS_VS;
}
if ((status = lib$find_file(&i, &o, &context, 0, 0)) == RMS$_NORMAL)
{
out->body[out->curlen] = EOS;
return 1;
}
else if (status == RMS$_NMF)
retval = 0;
else
{
strcpy(out->body, in);
retval = -1;
}
lib$find_file_end(&context);
pass1 = TRUE;
return retval;
}
char *
gfnames (arg, p_error)
char *arg;
bool *p_error;
{
static vspec filename = {MAX_FILE_SPEC_LEN, "\0"};
switch (fn_exp (&filename, arg))
{
case 1:
*p_error = FALSE;
return filename.body;
case 0:
*p_error = FALSE;
return NULL;
default:
*p_error = TRUE;
return filename.body;
}
}
#ifndef OLD
system (cmd)
char *cmd;
{
error ("%s", "system() function not implemented under VMS");
}
#endif
#define VERSION_DELIM ';'
char *massage_name (s)
char *s;
{
char *start = s;
for ( ; *s; s++)
if (*s == VERSION_DELIM)
{
*s = EOS;
break;
}
else
*s = lowcase (*s);
return start;
}
#endif
int
main (argc, argv)
int argc;
char *argv[];
{
int i;
unsigned int nincluded_files;
char **included_files;
char *this_file;
argument *argbuffer;
int current_arg, file_count;
struct linebuffer filename_lb;
#ifdef VMS
bool got_err;
#endif
#ifdef DOS_NT
_fmode = O_BINARY;
#endif
progname = argv[0];
nincluded_files = 0;
included_files = xnew (argc, char *);
current_arg = 0;
file_count = 0;
argbuffer = xnew (argc, argument);
#ifdef ETAGS_REGEXPS
re_set_syntax (RE_SYNTAX_EMACS);
#endif
if (!CTAGS)
{
typedefs = typedefs_and_cplusplus = constantypedefs = TRUE;
globals = TRUE;
members = FALSE;
}
while (1)
{
int opt;
char *optstring;
#ifdef ETAGS_REGEXPS
optstring = "-aCdDf:Il:o:r:RStTi:BuvxwVhH";
#else
optstring = "-aCdDf:Il:o:StTi:BuvxwVhH";
#endif
#ifndef LONG_OPTIONS
optstring = optstring + 1;
#endif
opt = getopt_long (argc, argv, optstring, longopts, 0);
if (opt == EOF)
break;
switch (opt)
{
case 0:
break;
case 1:
argbuffer[current_arg].arg_type = at_filename;
argbuffer[current_arg].what = optarg;
++current_arg;
++file_count;
break;
case 'a': append_to_tagfile = TRUE; break;
case 'C': cplusplus = TRUE; break;
case 'd': constantypedefs = TRUE; break;
case 'D': constantypedefs = FALSE; break;
case 'f':
case 'o':
if (tagfile)
{
error ("-%c option may only be given once.", opt);
suggest_asking_for_help ();
}
tagfile = optarg;
break;
case 'I':
case 'S':
noindentypedefs = TRUE;
break;
case 'l':
argbuffer[current_arg].function = get_language_from_name (optarg);
argbuffer[current_arg].arg_type = at_language;
++current_arg;
break;
#ifdef ETAGS_REGEXPS
case 'r':
argbuffer[current_arg].arg_type = at_regexp;
argbuffer[current_arg].what = optarg;
++current_arg;
break;
case 'R':
argbuffer[current_arg].arg_type = at_regexp;
argbuffer[current_arg].what = NULL;
++current_arg;
break;
#endif
case 'V':
print_version ();
break;
case 'h':
case 'H':
print_help ();
break;
case 't':
typedefs = TRUE;
break;
case 'T':
typedefs = typedefs_and_cplusplus = TRUE;
break;
#if (!CTAGS)
case 'i':
included_files[nincluded_files++] = optarg;
break;
#else
case 'B': searchar = '?'; break;
case 'u': update = TRUE; break;
case 'v': vgrind_style = TRUE;
case 'x': cxref_style = TRUE; break;
case 'w': no_warnings = TRUE; break;
#endif
default:
suggest_asking_for_help ();
}
}
for (; optind < argc; ++optind)
{
argbuffer[current_arg].arg_type = at_filename;
argbuffer[current_arg].what = argv[optind];
++current_arg;
++file_count;
}
if (nincluded_files == 0 && file_count == 0)
{
error ("no input files specified.", 0);
suggest_asking_for_help ();
}
if (tagfile == NULL)
tagfile = CTAGS ? "tags" : "TAGS";
cwd = etags_getcwd ();
if (cwd[strlen (cwd) - 1] != '/')
{
char *oldcwd = cwd;
cwd = concat (oldcwd, "/", "");
free (oldcwd);
}
if (streq (tagfile, "-"))
tagfiledir = cwd;
else
tagfiledir = absolute_dirname (tagfile, cwd);
init ();
initbuffer (&lb);
initbuffer (&token_name);
initbuffer (&lbs[0].lb);
initbuffer (&lbs[1].lb);
initbuffer (&filename_lb);
if (!CTAGS)
{
if (streq (tagfile, "-"))
{
tagf = stdout;
#ifdef DOS_NT
if (!isatty (fileno (stdout)))
setmode (fileno (stdout), O_BINARY);
#endif
}
else
tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
if (tagf == NULL)
pfatal (tagfile);
}
for (i = 0; i < current_arg; ++i)
{
switch (argbuffer[i].arg_type)
{
case at_language:
lang_func = argbuffer[i].function;
break;
#ifdef ETAGS_REGEXPS
case at_regexp:
analyse_regex (argbuffer[i].what);
break;
#endif
case at_filename:
#ifdef VMS
while ((this_file = gfnames (argbuffer[i].what, &got_err)) != NULL)
{
if (got_err)
{
error ("can't find file %s\n", this_file);
argc--, argv++;
}
else
{
this_file = massage_name (this_file);
}
#else
this_file = argbuffer[i].what;
#endif
if (streq (this_file, "-"))
while (readline_internal (&filename_lb, stdin) > 0)
process_file (filename_lb.buffer);
else
process_file (this_file);
#ifdef VMS
}
#endif
break;
}
}
if (!CTAGS)
{
while (nincluded_files-- > 0)
fprintf (tagf, "\f\n%s,include\n", *included_files++);
fclose (tagf);
exit (GOOD);
}
if (cxref_style)
{
put_entries (head);
exit (GOOD);
}
if (update)
{
char cmd[BUFSIZ];
for (i = 0; i < current_arg; ++i)
{
if (argbuffer[i].arg_type != at_filename)
continue;
sprintf (cmd,
"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", (char *)NULL);
}
append_to_tagfile = TRUE;
}
tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
if (tagf == NULL)
pfatal (tagfile);
put_entries (head);
fclose (tagf);
if (update)
{
char cmd[BUFSIZ];
sprintf (cmd, "sort %s -o %s", tagfile, tagfile);
exit (system (cmd));
}
return GOOD;
}
Lang_function *
get_language_from_name (name)
char *name;
{
struct lang_entry *lang;
if (name != NULL)
for (lang = lang_names; lang->name != NULL; lang++)
{
if (streq (name, lang->name))
return lang->function;
}
error ("language \"%s\" not recognized.", optarg);
suggest_asking_for_help ();
return NULL;
}
Lang_function *
get_language_from_interpreter (interpreter)
char *interpreter;
{
struct lang_entry *lang;
char **iname;
if (interpreter == NULL)
return NULL;
for (lang = lang_names; lang->name != NULL; lang++)
if (lang->interpreters != NULL)
for (iname = lang->interpreters; *iname != NULL; iname++)
if (streq (*iname, interpreter))
return lang->function;
return NULL;
}
Lang_function *
get_language_from_suffix (suffix)
char *suffix;
{
struct lang_entry *lang;
char **ext;
if (suffix == NULL)
return NULL;
for (lang = lang_names; lang->name != NULL; lang++)
if (lang->suffixes != NULL)
for (ext = lang->suffixes; *ext != NULL; ext++)
if (streq (*ext, suffix))
return lang->function;
return NULL;
}
void
process_file (file)
char *file;
{
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))
{
error ("skipping %s: it is not a regular file.", file);
return;
}
if (streq (file, tagfile) && !streq (tagfile, "-"))
{
error ("skipping inclusion of %s in self.", file);
return;
}
inf = fopen (file, "r");
if (inf == NULL)
{
perror (file);
return;
}
find_entries (file, inf);
if (!CTAGS)
{
char *filename;
if (absolutefn (file))
{
filename = absolute_filename (file, cwd);
}
else
{
filename = relative_filename (file, tagfiledir);
}
fprintf (tagf, "\f\n%s,%d\n", filename, total_size_of_entries (head));
free (filename);
put_entries (head);
free_tree (head);
head = NULL;
}
}
void
init ()
{
register char *sp;
register int i;
for (i = 0; i < CHARS; i++)
_wht[i] = _nin[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
for (sp = white; *sp; sp++) _wht[*sp] = TRUE; _wht[0] = _wht['\n'];
for (sp = nonam; *sp; sp++) _nin[*sp] = TRUE; _nin[0] = _nin['\n'];
for (sp = endtk; *sp; sp++) _etk[*sp] = TRUE; _etk[0] = _etk['\n'];
for (sp = midtk; *sp; sp++) _itk[*sp] = TRUE; _btk[0] = _btk['\n'];
for (sp = begtk; *sp; sp++) _btk[*sp] = TRUE; _itk[0] = _itk['\n'];
}
void
find_entries (file, inf)
char *file;
FILE *inf;
{
char *cp;
Lang_function *function;
NODE *old_last_node;
extern NODE *last_node;
curfile = savestr (file);
function = lang_func;
if (function != NULL)
{
function (inf);
fclose (inf);
return;
}
cp = etags_strrchr (file, '.');
if (cp != NULL)
{
cp += 1;
function = get_language_from_suffix (cp);
if (function != NULL)
{
function (inf);
fclose (inf);
return;
}
}
if (readline_internal (&lb, inf)
&& lb.len >= 2
&& lb.buffer[0] == '#'
&& lb.buffer[1] == '!')
{
char *lp;
lp = etags_strrchr (lb.buffer+2, '/');
if (lp != NULL)
lp += 1;
else
for (lp = lb.buffer+2; *lp != '\0' && isspace (*lp); lp++)
continue;
for (cp = lp; *cp != '\0' && !isspace (*cp); cp++)
continue;
*cp = '\0';
if (strlen (lp) > 0)
{
function = get_language_from_interpreter (lp);
if (function != NULL)
{
function (inf);
fclose (inf);
return;
}
}
}
rewind (inf);
old_last_node = last_node;
Fortran_functions (inf);
if (old_last_node == last_node)
{
rewind (inf);
default_C_entries (inf);
}
fclose (inf);
return;
}
void
pfnote (name, is_func, linestart, linelen, lno, cno)
char *name;
bool is_func;
char *linestart;
int linelen;
int lno;
long cno;
{
register NODE *np;
if (CTAGS && name == NULL)
return;
np = xnew (1, NODE);
if (CTAGS && !cxref_style && streq (name, "main"))
{
register char *fp = etags_strrchr (curfile, '/');
np->name = concat ("M", fp == 0 ? curfile : fp + 1, "");
fp = etags_strrchr (np->name, '.');
if (fp && fp[1] != '\0' && fp[2] == '\0')
fp[0] = 0;
}
else
np->name = name;
np->been_warned = FALSE;
np->file = curfile;
np->is_func = is_func;
np->lno = lno;
np->cno = cno ;
np->left = np->right = NULL;
if (CTAGS && !cxref_style)
{
if (strlen (linestart) < 50)
np->pat = concat (linestart, "$", "");
else
np->pat = savenstr (linestart, 50);
}
else
np->pat = savenstr (linestart, linelen);
add_node (np, &head);
}
#define traditional_tag_style TRUE
void
new_pfnote (name, namelen, is_func, linestart, linelen, lno, cno)
char *name;
int namelen;
bool is_func;
char *linestart;
int linelen;
int lno;
long cno;
{
register char *cp;
bool named;
named = TRUE;
if (!CTAGS)
{
for (cp = name; !notinname (*cp); cp++)
continue;
if (*cp == '\0')
{
cp = linestart + linelen - namelen;
if (notinname (linestart[linelen-1]))
cp -= 1;
if (cp >= linestart
&& (cp == linestart
|| notinname (cp[-1]))
&& strneq (name, cp, namelen))
named = FALSE;
}
}
if (named)
name = savenstr (name, namelen);
else
name = NULL;
pfnote (name, is_func, linestart, linelen, lno, cno);
}
void
free_tree (node)
register NODE *node;
{
while (node)
{
register NODE *node_right = node->right;
free_tree (node->left);
if (node->name != NULL)
free (node->name);
free (node->pat);
free ((char *) node);
node = node_right;
}
}
NODE *last_node = NULL;
void
add_node (node, cur_node_p)
NODE *node, **cur_node_p;
{
register int dif;
register NODE *cur_node = *cur_node_p;
if (cur_node == NULL)
{
*cur_node_p = node;
last_node = node;
return;
}
if (!CTAGS)
{
if (last_node == NULL)
fatal ("internal error in add_node", (char *)NULL);
last_node->right = node;
last_node = node;
}
else
{
dif = strcmp (node->name, cur_node->name);
if (!dif)
{
if (streq (node->file, cur_node->file))
{
if (!no_warnings)
{
fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
node->file, lineno, node->name);
fprintf (stderr, "Second entry ignored\n");
}
}
else if (!cur_node->been_warned && !no_warnings)
{
fprintf
(stderr,
"Duplicate entry in files %s and %s: %s (Warning only)\n",
node->file, cur_node->file, node->name);
cur_node->been_warned = TRUE;
}
return;
}
add_node (node, dif < 0 ? &cur_node->left : &cur_node->right);
}
}
void
put_entries (node)
register NODE *node;
{
register char *sp;
if (node == NULL)
return;
put_entries (node->left);
if (!CTAGS)
{
if (node->name != NULL)
fprintf (tagf, "%s\177%s\001%d,%ld\n",
node->pat, node->name, node->lno, node->cno);
else
fprintf (tagf, "%s\177%d,%ld\n",
node->pat, node->lno, node->cno);
}
else
{
if (node->name == NULL)
error ("internal error: NULL name in ctags mode.", (char *)NULL);
if (cxref_style)
{
if (vgrind_style)
fprintf (stdout, "%s %s %d\n",
node->name, node->file, (node->lno + 63) / 64);
else
fprintf (stdout, "%-16s %3d %-16s %s\n",
node->name, node->lno, node->file, node->pat);
}
else
{
fprintf (tagf, "%s\t%s\t", node->name, node->file);
if (node->is_func)
{
putc (searchar, tagf);
putc ('^', tagf);
for (sp = node->pat; *sp; sp++)
{
if (*sp == '\\' || *sp == searchar)
putc ('\\', tagf);
putc (*sp, tagf);
}
putc (searchar, tagf);
}
else
{
fprintf (tagf, "%d", node->lno);
}
putc ('\n', tagf);
}
}
put_entries (node->right);
}
int
number_len (num)
long num;
{
int len = 0;
if (!num)
return 1;
for (; num; num /= 10)
++len;
return len;
}
int
total_size_of_entries (node)
register NODE *node;
{
register int total;
if (node == NULL)
return 0;
total = 0;
for (; node; node = node->right)
{
total += total_size_of_entries (node->left);
total += strlen (node->pat) + 1;
total += number_len ((long) node->lno) + 1 + number_len (node->cno) + 1;
if (node->name != NULL)
total += 1 + strlen (node->name);
}
return total;
}
enum sym_type
{
st_none,
st_C_objprot, st_C_objimpl, st_C_objend,
st_C_gnumacro,
st_C_ignore,
st_C_javastruct,
st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec
};
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 15
#define MAX_HASH_VALUE 128
static int
hash (str, len)
register char *str;
register unsigned int len;
{
static unsigned char hash_table[] =
{
128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 39, 128, 128, 128, 54, 48,
46, 128, 128, 128, 128, 128, 128, 128, 128, 128,
28, 128, 128, 40, 32, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 24, 30, 47,
62, 7, 60, 27, 128, 60, 128, 128, 59, 16,
31, 23, 45, 128, 4, 14, 2, 55, 5, 128,
128, 128, 128, 128, 128, 128, 128, 128,
};
return len + hash_table[str[2]] + hash_table[str[0]];
}
struct C_stab_entry *
in_word_set (str, len)
register char *str;
register unsigned int len;
{
static struct C_stab_entry wordlist[] =
{
{"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
{"",}, {"",}, {"",}, {"",}, {"",}, {"",},
{"extern", 0, st_C_typespec},
{"extends", C_JAVA, st_C_javastruct},
{"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
{"struct", 0, st_C_struct},
{"mutable", C_PLPL, st_C_typespec},
{"",}, {"",}, {"",}, {"",},
{"auto", 0, st_C_typespec},
{"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
{"",}, {"",},
{"short", 0, st_C_typespec},
{"",},
{"static", 0, st_C_typespec},
{"",}, {"",},
{"signed", 0, st_C_typespec},
{"",}, {"",}, {"",}, {"",},
{"@protocol", 0, st_C_objprot},
{"",},
{"typedef", 0, st_C_typedef},
{"typename", C_PLPL, st_C_typespec},
{"namespace", C_PLPL, st_C_struct},
{"bool", C_PLPL, st_C_typespec},
{"",}, {"",},
{"explicit", C_PLPL, st_C_typespec},
{"",}, {"",}, {"",}, {"",},
{"int", 0, st_C_typespec},
{"enum", 0, st_C_enum},
{"",}, {"",},
{"void", 0, st_C_typespec},
{"@implementation", 0, st_C_objimpl},
{"",},
{"volatile", 0, st_C_typespec},
{"",},
{"@end", 0, st_C_objend},
{"char", 0, st_C_typespec},
{"class", C_PLPL, st_C_struct},
{"unsigned", 0, st_C_typespec},
{"",}, {"",},
{"@interface", 0, st_C_objprot},
{"",},
{"PSEUDO", 0, st_C_gnumacro},
{"const", 0, st_C_typespec},
{"domain", C_STAR, st_C_struct},
{"ENTRY", 0, st_C_gnumacro},
{"",},
{"SYSCALL", 0, st_C_gnumacro},
{"float", 0, st_C_typespec},
{"",}, {"",}, {"",}, {"",}, {"",},
{"long", 0, st_C_typespec},
{"",}, {"",}, {"",}, {"",},
{"package", C_JAVA, st_C_ignore},
{"",}, {"",}, {"",}, {"",}, {"",},
{"DEFUN", 0, st_C_gnumacro},
{"",}, {"",}, {"",}, {"",}, {"",},
{"import", C_JAVA, st_C_ignore},
{"",}, {"",}, {"",},
{"implements", C_JAVA, st_C_javastruct},
{"",}, {"",}, {"",}, {"",},
{"union", 0, st_C_struct},
{"",}, {"",},
{"double", 0, st_C_typespec},
{"",}, {"",},
{"friend", C_PLPL, st_C_ignore},
{"",},
{"define", 0, st_C_define},
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
{
register int key = hash (str, len);
if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)
{
register char *s = wordlist[key].name;
if (*s == *str && !strncmp (str + 1, s + 1, len - 1))
return &wordlist[key];
}
}
return 0;
}
enum sym_type
C_symtype (str, len, c_ext)
char *str;
int len;
int c_ext;
{
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;
return se->type;
}
enum
{
fvnone,
fvnameseen,
fstartlist,
finlist,
flistseen,
fignore,
vignore
} fvdef;
enum
{
tnone,
ttypedseen,
tinbody,
tend,
tignore
} typdef;
enum
{
snone,
skeyseen,
stagseen,
scolonseen,
sinbody
} structdef;
char *structtag = "<uninited>";
enum sym_type structtype;
char *objtag = "<uninited>";
enum
{
dnone,
dsharpseen,
ddefineseen,
dignorerest
} definedef;
enum
{
onone,
oprotocol,
oimplementation,
otagseen,
oparenseen,
ocatseen,
oinbody,
omethodsign,
omethodtag,
omethodcolon,
omethodparm,
oignore
} objdef;
typedef struct
{
bool valid;
char *str;
bool named;
int linelen;
int lineno;
long linepos;
char *buffer;
} TOKEN;
TOKEN tok;
bool next_token_is_func;
bool yacc_rules;
int methodlen;
bool
consider_token (str, len, c, c_ext, cblev, parlev, is_func_or_var)
register char *str;
register int len;
register char c;
int c_ext;
int cblev;
int parlev;
bool *is_func_or_var;
{
enum sym_type toktype = C_symtype (str, len, c_ext);
switch (definedef)
{
case dnone:
break;
case dsharpseen:
if (toktype == st_C_define)
{
definedef = ddefineseen;
}
else
{
definedef = dignorerest;
}
return FALSE;
case ddefineseen:
definedef = dignorerest;
*is_func_or_var = (c == '(');
if (!*is_func_or_var && !constantypedefs)
return FALSE;
else
return TRUE;
case dignorerest:
return FALSE;
default:
error ("internal error: definedef value.", (char *)NULL);
}
switch (typdef)
{
case tnone:
if (toktype == st_C_typedef)
{
if (typedefs)
typdef = ttypedseen;
fvdef = fvnone;
return FALSE;
}
break;
case ttypedseen:
switch (toktype)
{
case st_none:
case st_C_typespec:
typdef = tend;
break;
case st_C_struct:
case st_C_enum:
break;
}
break;
case tend:
switch (toktype)
{
case st_C_typespec:
case st_C_struct:
case st_C_enum:
return FALSE;
}
return TRUE;
}
switch (toktype)
{
case st_C_javastruct:
if (structdef == stagseen)
structdef = scolonseen;
return FALSE;
break;
case st_C_struct:
case st_C_enum:
if (typdef == ttypedseen
|| (typedefs_and_cplusplus && cblev == 0 && structdef == snone))
{
structdef = skeyseen;
structtype = toktype;
}
return FALSE;
}
if (structdef == skeyseen)
{
if (structtype == st_C_struct)
structtag = savenstr (str, len);
else
structtag = "<enum>";
structdef = stagseen;
return TRUE;
}
if (typdef != tnone)
{
definedef = dnone;
return FALSE;
}
if (definedef == dnone && toktype == st_C_gnumacro)
{
next_token_is_func = TRUE;
return FALSE;
}
if (next_token_is_func)
{
next_token_is_func = FALSE;
fvdef = fignore;
*is_func_or_var = TRUE;
return TRUE;
}
switch (objdef)
{
case onone:
switch (toktype)
{
case st_C_objprot:
objdef = oprotocol;
return FALSE;
case st_C_objimpl:
objdef = oimplementation;
return FALSE;
}
break;
case oimplementation:
objtag = savenstr (str, len);
objdef = oinbody;
return FALSE;
case oprotocol:
objtag = savenstr (str, len);
objdef = otagseen;
*is_func_or_var = TRUE;
return TRUE;
case oparenseen:
objdef = ocatseen;
*is_func_or_var = TRUE;
return TRUE;
case oinbody:
break;
case omethodsign:
if (parlev == 0)
{
objdef = omethodtag;
methodlen = len;
grow_linebuffer (&token_name, methodlen + 1);
strncpy (token_name.buffer, str, len);
token_name.buffer[methodlen] = '\0';
token_name.len = methodlen;
return TRUE;
}
return FALSE;
case omethodcolon:
if (parlev == 0)
objdef = omethodparm;
return FALSE;
case omethodparm:
if (parlev == 0)
{
objdef = omethodtag;
methodlen += len;
grow_linebuffer (&token_name, methodlen + 1);
strncat (token_name.buffer, str, len);
token_name.len = methodlen;
return TRUE;
}
return FALSE;
case oignore:
if (toktype == st_C_objend)
{
objdef = onone;
}
return FALSE;
}
switch (toktype)
{
case st_C_typespec:
if (fvdef != finlist && fvdef != fignore && fvdef != vignore)
fvdef = fvnone;
return FALSE;
case st_C_ignore:
fvdef = vignore;
return FALSE;
case st_none:
if (constantypedefs && structdef == sinbody && structtype == st_C_enum)
return TRUE;
if (fvdef == fvnone)
{
fvdef = fvnameseen;
*is_func_or_var = TRUE;
return TRUE;
}
}
return FALSE;
}
#define current_lb_is_new (newndx == curndx)
#define switch_line_buffers() (curndx = 1 - curndx)
#define curlb (lbs[curndx].lb)
#define othlb (lbs[1-curndx].lb)
#define newlb (lbs[newndx].lb)
#define curlinepos (lbs[curndx].linepos)
#define othlinepos (lbs[1-curndx].linepos)
#define newlinepos (lbs[newndx].linepos)
#define CNL_SAVE_DEFINEDEF \
do { \
curlinepos = charno; \
lineno++; \
linecharno = charno; \
charno += readline (&curlb, inf); \
lp = curlb.buffer; \
quotednl = FALSE; \
newndx = curndx; \
} while (0)
#define CNL \
do { \
CNL_SAVE_DEFINEDEF; \
if (savetok.valid) \
{ \
tok = savetok; \
savetok.valid = FALSE; \
} \
definedef = dnone; \
} while (0)
void
make_C_tag (isfun)
bool isfun;
{
if (tok.valid)
{
if (traditional_tag_style)
{
char *name = NULL;
if (CTAGS || tok.named)
name = savestr (token_name.buffer);
pfnote (name, isfun,
tok.buffer, tok.linelen, tok.lineno, tok.linepos);
}
else
new_pfnote (token_name.buffer, token_name.len, isfun,
tok.buffer, tok.linelen, tok.lineno, tok.linepos);
tok.valid = FALSE;
}
else if (DEBUG)
abort ();
}
void
C_entries (c_ext, inf)
int c_ext;
FILE *inf;
{
register char c;
register char *lp;
int curndx, newndx;
register int tokoff;
register int toklen;
char *qualifier;
int qlen;
int cblev;
int parlev;
bool incomm, inquote, inchar, quotednl, midtoken;
bool cplpl, cjava;
TOKEN savetok;
curndx = newndx = 0;
lineno = 0;
charno = 0;
lp = curlb.buffer;
*lp = 0;
fvdef = fvnone; typdef = tnone; structdef = snone;
definedef = dnone; objdef = onone;
next_token_is_func = yacc_rules = FALSE;
midtoken = inquote = inchar = incomm = quotednl = FALSE;
tok.valid = savetok.valid = FALSE;
cblev = 0;
parlev = 0;
cplpl = (c_ext & C_PLPL) == C_PLPL;
cjava = (c_ext & C_JAVA) == C_JAVA;
if (cjava)
{ qualifier = "."; qlen = 1; }
else
{ qualifier = "::"; qlen = 2; }
while (!feof (inf))
{
c = *lp++;
if (c == '\\')
{
if (*lp == '\0')
{
quotednl = TRUE;
continue;
}
lp++;
c = ' ';
}
else if (incomm)
{
switch (c)
{
case '*':
if (*lp == '/')
{
c = *lp++;
incomm = FALSE;
}
break;
case '\0':
CNL_SAVE_DEFINEDEF;
break;
}
continue;
}
else if (inquote)
{
switch (c)
{
case '"':
inquote = FALSE;
break;
case '\0':
CNL_SAVE_DEFINEDEF;
break;
}
continue;
}
else if (inchar)
{
switch (c)
{
case '\0':
CNL;
case '\'':
inchar = FALSE;
break;
}
continue;
}
else
switch (c)
{
case '"':
inquote = TRUE;
if (fvdef != finlist && fvdef != fignore && fvdef !=vignore)
fvdef = fvnone;
continue;
case '\'':
inchar = TRUE;
if (fvdef != finlist && fvdef != fignore && fvdef !=vignore)
fvdef = fvnone;
continue;
case '/':
if (*lp == '*')
{
lp++;
incomm = TRUE;
continue;
}
else if ( *lp == '/')
{
c = '\0';
break;
}
else
break;
case '%':
if ((c_ext & YACC) && *lp == '%')
{
lp++;
definedef = dnone; fvdef = fvnone;
typdef = tnone; structdef = snone;
next_token_is_func = FALSE;
midtoken = inquote = inchar = incomm = quotednl = FALSE;
cblev = 0;
yacc_rules = !yacc_rules;
continue;
}
else
break;
case '#':
if (definedef == dnone)
{
char *cp;
bool cpptoken = TRUE;
for (cp = newlb.buffer; cp < lp-1; cp++)
if (!iswhite (*cp))
{
if (*cp == '*' && *(cp+1) == '/')
{
cp++;
cpptoken = TRUE;
}
else
cpptoken = FALSE;
}
if (cpptoken)
definedef = dsharpseen;
}
continue;
}
if ((definedef != dnone
|| (cblev == 0 && structdef != scolonseen)
|| (cblev == 1 && cplpl && structdef == sinbody)
|| (structdef == sinbody && structtype == st_C_enum))
&& typdef != tignore
&& definedef != dignorerest
&& fvdef != finlist)
{
if (midtoken)
{
if (endtoken (c))
{
if (c == ':' && cplpl && *lp == ':' && begtoken(*(lp + 1)))
{
lp += 2;
toklen += 3;
}
else
{
bool funorvar = FALSE;
if (yacc_rules
|| consider_token (newlb.buffer + tokoff, toklen, c,
c_ext, cblev, parlev, &funorvar))
{
tok.named = FALSE;
if (structdef == sinbody
&& definedef == dnone
&& funorvar)
{
int len = strlen (structtag) + qlen + toklen;
grow_linebuffer (&token_name, len + 1);
strcpy (token_name.buffer, structtag);
strcat (token_name.buffer, qualifier);
strncat (token_name.buffer,
newlb.buffer + tokoff, toklen);
token_name.len = len;
tok.named = TRUE;
}
else if (objdef == ocatseen)
{
int len = strlen (objtag) + 2 + toklen;
grow_linebuffer (&token_name, len + 1);
strcpy (token_name.buffer, objtag);
strcat (token_name.buffer, "(");
strncat (token_name.buffer,
newlb.buffer + tokoff, toklen);
strcat (token_name.buffer, ")");
token_name.len = len;
tok.named = TRUE;
}
else if (objdef == omethodtag
|| objdef == omethodparm)
{
tok.named = TRUE;
}
else
{
grow_linebuffer (&token_name, toklen + 1);
strncpy (token_name.buffer,
newlb.buffer + tokoff, toklen);
token_name.buffer[toklen] = '\0';
token_name.len = toklen;
tok.named = (structdef == stagseen
|| typdef == tend
|| (funorvar
&& definedef == dignorerest));
}
tok.lineno = lineno;
tok.linelen = tokoff + toklen + 1;
tok.buffer = newlb.buffer;
tok.linepos = newlinepos;
tok.valid = TRUE;
if (definedef == dnone
&& (fvdef == fvnameseen
|| structdef == stagseen
|| typdef == tend
|| objdef != onone))
{
if (current_lb_is_new)
switch_line_buffers ();
}
else
make_C_tag (funorvar);
}
midtoken = FALSE;
}
}
else if (intoken (c))
{
toklen++;
continue;
}
}
else if (begtoken (c))
{
switch (definedef)
{
case dnone:
switch (fvdef)
{
case fstartlist:
fvdef = finlist;
continue;
case flistseen:
make_C_tag (TRUE);
fvdef = fignore;
break;
case fvnameseen:
fvdef = fvnone;
break;
}
if (structdef == stagseen && !cjava)
structdef = snone;
break;
case dsharpseen:
savetok = tok;
}
if (!yacc_rules || lp == newlb.buffer + 1)
{
tokoff = lp - 1 - newlb.buffer;
toklen = 1;
midtoken = TRUE;
}
continue;
}
}
switch (c)
{
case ':':
if (definedef != dnone)
break;
switch (objdef)
{
case otagseen:
objdef = oignore;
make_C_tag (TRUE);
break;
case omethodtag:
case omethodparm:
objdef = omethodcolon;
methodlen += 1;
grow_linebuffer (&token_name, methodlen + 1);
strcat (token_name.buffer, ":");
token_name.len = methodlen;
break;
}
if (structdef == stagseen)
structdef = scolonseen;
else
switch (fvdef)
{
case fvnameseen:
if (yacc_rules)
{
make_C_tag (FALSE);
fvdef = fignore;
}
break;
case fstartlist:
fvdef = fvnone;
break;
}
break;
case ';':
if (definedef != dnone)
break;
if (cblev == 0)
switch (typdef)
{
case tend:
make_C_tag (FALSE);
default:
typdef = tnone;
}
switch (fvdef)
{
case fignore:
break;
case fvnameseen:
if ((globals && cblev == 0) || (members && cblev == 1))
make_C_tag (FALSE);
default:
fvdef = fvnone;
tok.valid = FALSE;
}
if (structdef == stagseen)
structdef = snone;
break;
case ',':
if (definedef != dnone)
break;
switch (objdef)
{
case omethodtag:
case omethodparm:
make_C_tag (TRUE);
objdef = oinbody;
break;
}
switch (fvdef)
{
case finlist:
case fignore:
case vignore:
break;
case fvnameseen:
if ((globals && cblev == 0) || (members && cblev == 1))
make_C_tag (FALSE);
break;
default:
fvdef = fvnone;
}
if (structdef == stagseen)
structdef = snone;
break;
case '[':
if (definedef != dnone)
break;
if (cblev == 0 && typdef == tend)
{
typdef = tignore;
make_C_tag (FALSE);
break;
}
switch (fvdef)
{
case finlist:
case fignore:
case vignore:
break;
case fvnameseen:
if ((globals && cblev == 0) || (members && cblev == 1))
make_C_tag (FALSE);
default:
fvdef = fvnone;
}
if (structdef == stagseen)
structdef = snone;
break;
case '(':
if (definedef != dnone)
break;
if (objdef == otagseen && parlev == 0)
objdef = oparenseen;
switch (fvdef)
{
case fvnone:
switch (typdef)
{
case ttypedseen:
case tend:
if (tok.valid && *lp != '*')
{
make_C_tag (FALSE);
typdef = tignore;
}
break;
}
break;
case fvnameseen:
fvdef = fstartlist;
break;
case flistseen:
fvdef = finlist;
break;
}
parlev++;
break;
case ')':
if (definedef != dnone)
break;
if (objdef == ocatseen && parlev == 1)
{
make_C_tag (TRUE);
objdef = oignore;
}
if (--parlev == 0)
{
switch (fvdef)
{
case fstartlist:
case finlist:
fvdef = flistseen;
break;
}
if (cblev == 0 && typdef == tend)
{
typdef = tignore;
make_C_tag (FALSE);
}
}
else if (parlev < 0)
parlev = 0;
break;
case '{':
if (definedef != dnone)
break;
if (typdef == ttypedseen)
typdef = tinbody;
switch (structdef)
{
case skeyseen:
structdef = sinbody;
structtag = "_anonymous_";
break;
case stagseen:
case scolonseen:
structdef = sinbody;
make_C_tag (FALSE);
break;
}
switch (fvdef)
{
case flistseen:
make_C_tag (TRUE);
case fignore:
fvdef = fvnone;
break;
case fvnone:
switch (objdef)
{
case otagseen:
make_C_tag (TRUE);
objdef = oignore;
break;
case omethodtag:
case omethodparm:
make_C_tag (TRUE);
objdef = oinbody;
break;
default:
if (cblev == 0 && structdef == snone && typdef == tnone)
cblev = -1;
}
}
cblev++;
break;
case '*':
if (definedef != dnone)
break;
if (fvdef == fstartlist)
fvdef = fvnone;
break;
case '}':
if (definedef != dnone)
break;
if (!noindentypedefs && lp == newlb.buffer + 1)
{
cblev = 0;
parlev = 0;
}
else if (cblev > 0)
cblev--;
if (cblev == 0)
{
if (typdef == tinbody)
typdef = tend;
structdef = snone;
structtag = "<error>";
}
break;
case '=':
if (definedef != dnone)
break;
switch (fvdef)
{
case finlist:
case fignore:
case vignore:
break;
case fvnameseen:
if ((globals && cblev == 0) || (members && cblev == 1))
make_C_tag (FALSE);
default:
fvdef = vignore;
}
break;
case '+':
case '-':
if (objdef == oinbody && cblev == 0)
{
objdef = omethodsign;
break;
}
case '#': case '~': case '&': case '%': case '/': case '|':
case '^': case '!': case '<': case '>': case '.': case '?': case ']':
if (definedef != dnone)
break;
if (fvdef != finlist && fvdef != fignore && fvdef != vignore)
fvdef = fvnone;
break;
case '\0':
if (objdef == otagseen)
{
make_C_tag (TRUE);
objdef = oignore;
}
if (quotednl)
CNL_SAVE_DEFINEDEF;
else
CNL;
break;
}
}
}
void
default_C_entries (inf)
FILE *inf;
{
C_entries (cplusplus ? C_PLPL : 0, inf);
}
void
plain_C_entries (inf)
FILE *inf;
{
C_entries (0, inf);
}
void
Cplusplus_entries (inf)
FILE *inf;
{
C_entries (C_PLPL, inf);
}
void
Cjava_entries (inf)
FILE *inf;
{
C_entries (C_JAVA, inf);
}
void
Cstar_entries (inf)
FILE *inf;
{
C_entries (C_STAR, inf);
}
void
Yacc_entries (inf)
FILE *inf;
{
C_entries (YACC, inf);
}
char *dbp;
bool
tail (cp)
char *cp;
{
register int len = 0;
while (*cp && lowcase(*cp) == lowcase(dbp[len]))
cp++, len++;
if (*cp == '\0' && !intoken(dbp[len]))
{
dbp += len;
return TRUE;
}
return FALSE;
}
void
takeprec ()
{
while (isspace (*dbp))
dbp++;
if (*dbp != '*')
return;
dbp++;
while (isspace (*dbp))
dbp++;
if (strneq (dbp, "(*)", 3))
{
dbp += 3;
return;
}
if (!isdigit (*dbp))
{
--dbp;
return;
}
do
dbp++;
while (isdigit (*dbp));
}
void
getit (inf)
FILE *inf;
{
register char *cp;
while (isspace (*dbp))
dbp++;
if (*dbp == '\0')
{
lineno++;
linecharno = charno;
charno += readline (&lb, inf);
dbp = lb.buffer;
if (dbp[5] != '&')
return;
dbp += 6;
while (isspace (*dbp))
dbp++;
}
if (!isalpha (*dbp)
&& *dbp != '_'
&& *dbp != '$')
return;
for (cp = dbp + 1;
(*cp
&& (isalpha (*cp) || isdigit (*cp) || (*cp == '_') || (*cp == '$')));
cp++)
continue;
pfnote (savenstr (dbp, cp-dbp), TRUE,
lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
}
void
Fortran_functions (inf)
FILE *inf;
{
lineno = 0;
charno = 0;
while (!feof (inf))
{
lineno++;
linecharno = charno;
charno += readline (&lb, inf);
dbp = lb.buffer;
if (*dbp == '%')
dbp++;
while (isspace (*dbp))
dbp++;
if (*dbp == '\0')
continue;
switch (lowcase (*dbp))
{
case 'i':
if (tail ("integer"))
takeprec ();
break;
case 'r':
if (tail ("real"))
takeprec ();
break;
case 'l':
if (tail ("logical"))
takeprec ();
break;
case 'c':
if (tail ("complex") || tail ("character"))
takeprec ();
break;
case 'd':
if (tail ("double"))
{
while (isspace (*dbp))
dbp++;
if (*dbp == '\0')
continue;
if (tail ("precision"))
break;
continue;
}
break;
}
while (isspace (*dbp))
dbp++;
if (*dbp == '\0')
continue;
switch (lowcase (*dbp))
{
case 'f':
if (tail ("function"))
getit (inf);
continue;
case 's':
if (tail ("subroutine"))
getit (inf);
continue;
case 'e':
if (tail ("entry"))
getit (inf);
continue;
case 'p':
if (tail ("program"))
{
getit (inf);
continue;
}
if (tail ("procedure"))
getit (inf);
continue;
case 'b':
if (tail ("blockdata") || tail ("block data"))
{
while (isspace (*dbp))
dbp++;
if (*dbp == '\0')
pfnote (savestr ("blockdata"), TRUE, lb.buffer,
dbp - lb.buffer, lineno, linecharno);
else
getit (inf);
}
continue;
}
}
}
void
Asm_labels (inf)
FILE *inf;
{
register char *cp;
lineno = 0;
charno = 0;
while (!feof (inf))
{
lineno++;
linecharno = charno;
charno += readline (&lb, inf);
cp = lb.buffer;
if (isalpha (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
{
cp++;
while (isalnum (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
cp++;
if (*cp == ':' || isspace (*cp))
{
pfnote (savenstr(lb.buffer, cp-lb.buffer), TRUE,
lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
}
}
}
}
void
Perl_functions (inf)
FILE *inf;
{
register char *cp;
lineno = 0;
charno = 0;
while (!feof (inf))
{
lineno++;
linecharno = charno;
charno += readline (&lb, inf);
cp = lb.buffer;
if (*cp++ == 's' && *cp++ == 'u' && *cp++ == 'b' && isspace (*cp++))
{
while (*cp && isspace (*cp))
cp++;
while (*cp && ! isspace (*cp) && *cp != '{')
cp++;
pfnote (savenstr (lb.buffer, cp-lb.buffer), TRUE,
lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
}
}
}
void
Cobol_paragraphs (inf)
FILE *inf;
{
register char *cp;
lineno = 0;
charno = 0;
while (!feof (inf))
{
lineno++;
linecharno = charno;
charno += readline (&lb, inf);
if (lb.len < 9)
continue;
dbp = lb.buffer + 8;
if (dbp[-1] != ' ' || !isalnum (dbp[0]))
continue;
for (cp = dbp; isalnum (*cp) || *cp == '-'; cp++)
continue;
if (*cp++ == '.')
pfnote (savenstr (dbp, cp-dbp), TRUE,
lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
}
}
void
Pascal_functions (inf)
FILE *inf;
{
struct linebuffer tline;
long save_lcno;
int save_lineno, save_len;
char c, *cp, *namebuf;
bool
incomment,
inquote,
get_tagname,
found_tag,
inparms,
verify_tag;
lineno = 0;
charno = 0;
dbp = lb.buffer;
*dbp = '\0';
save_len = 0;
initbuffer (&tline);
incomment = inquote = FALSE;
found_tag = FALSE;
get_tagname = FALSE;
inparms = FALSE;
verify_tag = FALSE;
while (!feof (inf))
{
c = *dbp++;
if (c == '\0')
{
lineno++;
linecharno = charno;
charno += readline (&lb, inf);
dbp = lb.buffer;
if (*dbp == '\0')
continue;
if (!((found_tag && verify_tag) ||
get_tagname))
c = *dbp++;
}
if (incomment)
{
if (c == '}')
incomment = FALSE;
else if (c == '*' && *dbp == ')')
{
dbp++;
incomment = FALSE;
}
continue;
}
else if (inquote)
{
if (c == '\'')
inquote = FALSE;
continue;
}
else
switch (c)
{
case '\'':
inquote = TRUE;
continue;
case '{':
incomment = TRUE;
continue;
case '(':
if (*dbp == '*')
{
incomment = TRUE;
dbp++;
}
else if (found_tag)
inparms = TRUE;
continue;
case ')':
if (inparms)
inparms = FALSE;
continue;
case ';':
if (found_tag && !inparms)
{
verify_tag = TRUE;
break;
}
continue;
}
if (found_tag && verify_tag && (*dbp != ' '))
{
if (*dbp == '\0')
continue;
if (lowcase (*dbp == 'e'))
{
if (tail ("extern"))
{
found_tag = FALSE;
verify_tag = FALSE;
}
}
else if (lowcase (*dbp) == 'f')
{
if (tail ("forward"))
{
found_tag = FALSE;
verify_tag = FALSE;
}
}
if (found_tag && verify_tag)
{
found_tag = FALSE;
verify_tag = FALSE;
pfnote (namebuf, TRUE,
tline.buffer, save_len, save_lineno, save_lcno);
continue;
}
}
if (get_tagname)
{
if (*dbp == '\0')
continue;
grow_linebuffer (&tline, lb.len + 1);
strcpy (tline.buffer, lb.buffer);
save_lineno = lineno;
save_lcno = linecharno;
for (cp = dbp + 1; *cp != '\0' && !endtoken (*cp); cp++)
continue;
namebuf = savenstr (dbp, cp-dbp);
dbp = cp;
save_len = dbp - lb.buffer + 1;
get_tagname = FALSE;
found_tag = TRUE;
continue;
}
else if (!incomment && !inquote && !found_tag)
{
switch (lowcase (c))
{
case 'p':
if (tail ("rocedure"))
get_tagname = TRUE;
continue;
case 'f':
if (tail ("unction"))
get_tagname = TRUE;
continue;
}
}
}
free (tline.buffer);
}
int
L_isdef (strp)
register char *strp;
{
return ((strp[1] == 'd' || strp[1] == 'D')
&& (strp[2] == 'e' || strp[2] == 'E')
&& (strp[3] == 'f' || strp[3] == 'F'));
}
int
L_isquote (strp)
register char *strp;
{
return ((*(++strp) == 'q' || *strp == 'Q')
&& (*(++strp) == 'u' || *strp == 'U')
&& (*(++strp) == 'o' || *strp == 'O')
&& (*(++strp) == 't' || *strp == 'T')
&& (*(++strp) == 'e' || *strp == 'E')
&& isspace (*(++strp)));
}
void
L_getit ()
{
register char *cp;
if (*dbp == '\'')
dbp++;
else if (*dbp == '(' && L_isquote (dbp))
{
dbp += 7;
while (isspace (*dbp))
dbp++;
}
for (cp = dbp ;
*cp != '\0' && *cp != '(' && *cp != ' ' && *cp != ')';
cp++)
continue;
if (cp == dbp)
return;
pfnote (savenstr (dbp, cp-dbp), TRUE,
lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
}
void
Lisp_functions (inf)
FILE *inf;
{
lineno = 0;
charno = 0;
while (!feof (inf))
{
lineno++;
linecharno = charno;
charno += readline (&lb, inf);
dbp = lb.buffer;
if (dbp[0] == '(')
{
if (L_isdef (dbp))
{
while (!isspace (*dbp))
dbp++;
while (isspace (*dbp))
dbp++;
L_getit ();
}
else
{
do
dbp++;
while (*dbp && !isspace (*dbp)
&& *dbp != ':' && *dbp != '(' && *dbp != ')');
if (*dbp == ':')
{
do
dbp++;
while (*dbp == ':');
if (L_isdef (dbp - 1))
{
while (!isspace (*dbp))
dbp++;
while (isspace (*dbp))
dbp++;
L_getit ();
}
}
}
}
}
}
void
Postscript_functions (inf)
FILE *inf;
{
lineno = 0;
charno = 0;
while (!feof (inf))
{
lineno++;
linecharno = charno;
charno += readline (&lb, inf);
dbp = lb.buffer;
if (dbp[0] == '/')
{
register char *cp;
for (cp = dbp+1;
*cp != '\0' && *cp != ' ' && *cp != '{';
cp++)
continue;
pfnote (savenstr (dbp, cp-dbp), TRUE,
lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
}
}
}
void get_scheme ();
void
Scheme_functions (inf)
FILE *inf;
{
lineno = 0;
charno = 0;
while (!feof (inf))
{
lineno++;
linecharno = charno;
charno += readline (&lb, inf);
dbp = lb.buffer;
if (dbp[0] == '(' &&
(dbp[1] == 'D' || dbp[1] == 'd') &&
(dbp[2] == 'E' || dbp[2] == 'e') &&
(dbp[3] == 'F' || dbp[3] == 'f'))
{
while (!isspace (*dbp))
dbp++;
while (*dbp && (isspace (*dbp) || *dbp == '('))
dbp++;
get_scheme ();
}
if (dbp[0] == '(' &&
(dbp[1] == 'S' || dbp[1] == 's') &&
(dbp[2] == 'E' || dbp[2] == 'e') &&
(dbp[3] == 'T' || dbp[3] == 't') &&
(dbp[4] == '!' || dbp[4] == '!') &&
(isspace (dbp[5])))
{
while (!isspace (*dbp))
dbp++;
while (isspace (*dbp))
dbp++;
get_scheme ();
}
}
}
void
get_scheme ()
{
register char *cp;
if (*dbp == '\0')
return;
for (cp = dbp + 1;
*cp && *cp != '(' && *cp != ')' && !isspace (*cp);
cp++)
continue;
pfnote (savenstr (dbp, cp-dbp), TRUE,
lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
}
struct TEX_tabent
{
char *name;
int len;
};
struct TEX_tabent *TEX_toktab = NULL;
char *TEX_defenv = "\
:chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem\
:part:appendix:entry:index";
void TEX_mode ();
struct TEX_tabent *TEX_decode_env ();
int TEX_Token ();
char TEX_esc = '\\';
char TEX_opgrp = '{';
char TEX_clgrp = '}';
void
TeX_functions (inf)
FILE *inf;
{
char *lasthit;
register int i;
lineno = 0;
charno = 0;
TEX_mode (inf);
if (!TEX_toktab)
TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
while (!feof (inf))
{
lineno++;
linecharno = charno;
charno += readline (&lb, inf);
dbp = lb.buffer;
lasthit = dbp;
while (dbp = etags_strchr (dbp, TEX_esc))
{
if (!*(++dbp))
break;
linecharno += dbp - lasthit;
lasthit = dbp;
i = TEX_Token (lasthit);
if (i >= 0)
{
pfnote ( (char *)NULL, TRUE,
lb.buffer, lb.len, lineno, linecharno);
break;
}
}
}
}
#define TEX_LESC '\\'
#define TEX_SESC '!'
#define TEX_cmt '%'
void
TEX_mode (inf)
FILE *inf;
{
int c;
while ((c = getc (inf)) != EOF)
{
if (c == TEX_cmt)
while (c != '\n')
c = getc (inf);
else if (c == TEX_LESC || c == TEX_SESC )
break;
}
if (c == TEX_LESC)
{
TEX_esc = TEX_LESC;
TEX_opgrp = '{';
TEX_clgrp = '}';
}
else
{
TEX_esc = TEX_SESC;
TEX_opgrp = '<';
TEX_clgrp = '>';
}
rewind (inf);
}
struct TEX_tabent *
TEX_decode_env (evarname, defenv)
char *evarname;
char *defenv;
{
register char *env, *p;
struct TEX_tabent *tab;
int size, i;
env = getenv (evarname);
if (!env)
env = defenv;
else
{
char *oldenv = env;
env = concat (oldenv, defenv, "");
}
for (size = 1, p = env; p;)
if ((p = etags_strchr (p, ':')) && *(++p))
size++;
tab = xnew (size + 1, struct TEX_tabent);
for (i = 0; *env;)
{
p = etags_strchr (env, ':');
if (!p)
p = env + strlen (env);
if (p - env > 0)
{
tab[i].name = savenstr (env, p - env);
tab[i].len = strlen (tab[i].name);
i++;
}
if (*p)
env = p + 1;
else
{
tab[i].name = NULL;
tab[i].len = 0;
break;
}
}
return tab;
}
int
TEX_Token (cp)
char *cp;
{
int i;
for (i = 0; TEX_toktab[i].len > 0; i++)
if (strneq (TEX_toktab[i].name, cp, TEX_toktab[i].len))
return i;
return -1;
}
int prolog_pred ();
void prolog_skip_comment ();
int prolog_atom ();
int eat_white ();
void
Prolog_functions (inf)
FILE *inf;
{
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')
continue;
else if (isspace (dbp[0]))
continue;
else if (dbp[0] == '/' && dbp[1] == '*')
prolog_skip_comment (&lb, inf);
else if (len = prolog_pred (dbp, last))
{
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
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));
}
int
prolog_pred (s, last)
char *s;
char *last;
{
int pos;
int len;
pos = prolog_atom (s, 0);
if (pos < 1)
return 0;
len = pos;
pos += eat_white (s, pos);
if ((s[pos] == '(') || (s[pos] == '.'))
{
if (s[pos] == '(')
pos++;
if (last == NULL
|| len != strlen (last)
|| !strneq (s, last, len))
{
pfnote (savenstr (s, len), TRUE,
s, pos, lineno, linecharno);
return len;
}
}
return 0;
}
int
prolog_atom (s, pos)
char *s;
int pos;
{
int origpos;
origpos = pos;
if (islower(s[pos]) || (s[pos] == '_'))
{
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++;
}
else if (s[pos] == '\0')
return -1;
else if (s[pos] == '\\')
{
if (s[pos+1] == '\0')
return -1;
pos += 2;
}
else
pos++;
}
return pos - origpos;
}
else
return -1;
}
int
eat_white (s, pos)
char *s;
int pos;
{
int origpos = pos;
origpos = pos;
while (isspace (s[pos]))
pos++;
return pos - origpos;
}
int erlang_func ();
void erlang_attribute ();
int erlang_atom ();
void
Erlang_functions (inf)
FILE *inf;
{
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')
continue;
else if (isspace (dbp[0]))
continue;
else if (dbp[0] == '%')
continue;
else if (dbp[0] == '"')
continue;
else if (dbp[0] == '-')
{
erlang_attribute (dbp);
last = NULL;
}
else if (len = erlang_func (dbp, last))
{
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';
}
}
}
int
erlang_func (s, last)
char *s;
char *last;
{
int pos;
int len;
pos = erlang_atom (s, 0);
if (pos < 1)
return 0;
len = pos;
pos += eat_white (s, pos);
if (s[pos++] == '('
&& (last == NULL
|| len != strlen (last)
|| !strneq (s, last, len)))
{
pfnote (savenstr (s, len), TRUE,
s, pos, lineno, linecharno);
return len;
}
return 0;
}
void
erlang_attribute (s)
char *s;
{
int pos;
int len;
if (strneq (s, "-define", 7) || strneq (s, "-record", 7))
{
pos = 7 + eat_white (s, 7);
if (s[pos++] == '(')
{
pos += eat_white (s, pos);
if (len = erlang_atom (s, pos))
pfnote (savenstr (& s[pos], len), TRUE,
s, pos + len, lineno, linecharno);
}
}
return;
}
int
erlang_atom (s, pos)
char *s;
int pos;
{
int origpos;
origpos = pos;
if (isalpha (s[pos]) || s[pos] == '_')
{
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')
return -1;
else if (s[pos] == '\\')
{
if (s[pos+1] == '\0')
return -1;
pos += 2;
}
else
pos++;
}
return pos - origpos;
}
else
return -1;
}
#ifdef ETAGS_REGEXPS
char *
scan_separators (name)
char *name;
{
char sep = name[0];
char *copyto = name;
bool quoted = FALSE;
for (++name; *name != '\0'; ++name)
{
if (quoted)
{
if (*name == 't')
*copyto++ = '\t';
else if (*name == sep)
*copyto++ = sep;
else
{
*copyto++ = '\\';
*copyto++ = *name;
}
quoted = FALSE;
}
else if (*name == '\\')
quoted = TRUE;
else if (*name == sep)
break;
else
*copyto++ = *name;
}
*copyto = '\0';
return name;
}
void
analyse_regex (regex_arg)
char *regex_arg;
{
struct stat stat_buf;
if (regex_arg == NULL)
{
num_patterns = 0;
patterns = NULL;
return;
}
if (regex_arg[0] == '\0')
{
error ("missing regexp", (char *)NULL);
return;
}
if (regex_arg[0] == '@'
&& stat (regex_arg + 1, &stat_buf) == 0)
{
FILE *regexfp;
struct linebuffer regexbuf;
char *regexfile = regex_arg + 1;
regexfp = fopen (regexfile, "r");
if (regexfp == NULL)
{
perror (regexfile);
return;
}
initbuffer (®exbuf);
while (readline_internal (®exbuf, regexfp))
add_regex (regexbuf.buffer);
free (regexbuf.buffer);
fclose (regexfp);
}
else
{
add_regex (regex_arg);
}
}
void
add_regex (regexp_pattern)
char *regexp_pattern;
{
char *name;
const char *err;
struct re_pattern_buffer *patbuf;
if (regexp_pattern[strlen(regexp_pattern)-1] != regexp_pattern[0])
{
error ("%s: unterminated regexp", regexp_pattern);
return;
}
name = scan_separators (regexp_pattern);
if (regexp_pattern[0] == '\0')
{
error ("null regexp", (char *)NULL);
return;
}
(void) scan_separators (name);
patbuf = xnew (1, struct re_pattern_buffer);
patbuf->translate = NULL;
patbuf->fastmap = NULL;
patbuf->buffer = NULL;
patbuf->allocated = 0;
re_syntax_options = RE_INTERVALS;
err = re_compile_pattern (regexp_pattern, strlen (regexp_pattern), patbuf);
if (err != NULL)
{
error ("%s while compiling pattern", err);
return;
}
num_patterns += 1;
if (num_patterns == 1)
patterns = xnew (1, struct pattern);
else
patterns = ((struct pattern *)
xrealloc (patterns,
(num_patterns * sizeof (struct pattern))));
patterns[num_patterns - 1].pattern = patbuf;
patterns[num_patterns - 1].name_pattern = savestr (name);
patterns[num_patterns - 1].error_signaled = FALSE;
}
char *
substitute (in, out, regs)
char *in, *out;
struct re_registers *regs;
{
char *result, *t;
int size, dig, diglen;
result = NULL;
size = strlen (out);
if (out[size - 1] == '\\')
fatal ("pattern error in \"%s\"", out);
for (t = etags_strchr (out, '\\');
t != NULL;
t = etags_strchr (t + 2, '\\'))
if (isdigit (t[1]))
{
dig = t[1] - '0';
diglen = regs->end[dig] - regs->start[dig];
size += diglen - 2;
}
else
size -= 1;
result = xnew (size + 1, char);
for (t = result; *out != '\0'; out++)
if (*out == '\\' && isdigit (*++out))
{
dig = *out - '0';
diglen = regs->end[dig] - regs->start[dig];
strncpy (t, in + regs->start[dig], diglen);
t += diglen;
}
else
*t++ = *out;
*t = '\0';
if (DEBUG && (t > result + size || t - result != strlen (result)))
abort ();
return result;
}
#endif
void
initbuffer (linebuffer)
struct linebuffer *linebuffer;
{
linebuffer->size = 200;
linebuffer->buffer = xnew (200, char);
}
long
readline_internal (linebuffer, stream)
struct linebuffer *linebuffer;
register FILE *stream;
{
char *buffer = linebuffer->buffer;
register char *p = linebuffer->buffer;
register char *pend;
int chars_deleted;
pend = p + linebuffer->size;
while (1)
{
register int c = getc (stream);
if (p == pend)
{
linebuffer->size *= 2;
buffer = (char *) xrealloc (buffer, linebuffer->size);
p += buffer - linebuffer->buffer;
pend = buffer + linebuffer->size;
linebuffer->buffer = buffer;
}
if (c == EOF)
{
*p = '\0';
chars_deleted = 0;
break;
}
if (c == '\n')
{
if (p > buffer && p[-1] == '\r')
{
p -= 1;
#ifdef DOS_NT
chars_deleted = 1;
#else
chars_deleted = 2;
#endif
}
else
{
chars_deleted = 1;
}
*p = '\0';
break;
}
*p++ = c;
}
linebuffer->len = p - buffer;
return linebuffer->len + chars_deleted;
}
long
readline (linebuffer, stream)
struct linebuffer *linebuffer;
FILE *stream;
{
long result = readline_internal (linebuffer, stream);
#ifdef ETAGS_REGEXPS
int i;
if (linebuffer->len > 0)
for (i = 0; i < num_patterns; ++i)
{
int match = re_match (patterns[i].pattern, linebuffer->buffer,
linebuffer->len, 0, &patterns[i].regs);
switch (match)
{
case -2:
if (!patterns[i].error_signaled)
{
error ("error while matching pattern %d", i);
patterns[i].error_signaled = TRUE;
}
break;
case -1:
break;
default:
if (patterns[i].name_pattern[0] != '\0')
{
char *name = substitute (linebuffer->buffer,
patterns[i].name_pattern,
&patterns[i].regs);
if (name != NULL)
pfnote (name, TRUE,
linebuffer->buffer, match, lineno, linecharno);
}
else
{
pfnote ((char *)NULL, TRUE,
linebuffer->buffer, match, lineno, linecharno);
}
break;
}
}
#endif
return result;
}
void
just_read_file (inf)
FILE *inf;
{
lineno = 0;
charno = 0;
while (!feof (inf))
{
++lineno;
linecharno = charno;
charno += readline (&lb, inf);
}
}
char *
savestr (cp)
char *cp;
{
return savenstr (cp, strlen (cp));
}
char *
savenstr (cp, len)
char *cp;
int len;
{
register char *dp;
dp = xnew (len + 1, char);
strncpy (dp, cp, len);
dp[len] = '\0';
return dp;
}
char *
etags_strrchr (sp, c)
register char *sp, c;
{
register char *r;
r = NULL;
do
{
if (*sp == c)
r = sp;
} while (*sp++);
return r;
}
char *
etags_strchr (sp, c)
register char *sp, c;
{
do
{
if (*sp == c)
return sp;
} while (*sp++);
return NULL;
}
void
fatal (s1, s2)
char *s1, *s2;
{
error (s1, s2);
exit (BAD);
}
void
pfatal (s1)
char *s1;
{
perror (s1);
exit (BAD);
}
void
suggest_asking_for_help ()
{
fprintf (stderr, "\tTry `%s --help' for a complete list of options.\n",
progname);
exit (BAD);
}
void
error (s1, s2)
char *s1, *s2;
{
fprintf (stderr, "%s: ", progname);
fprintf (stderr, s1, s2);
fprintf (stderr, "\n");
}
char *
concat (s1, s2, s3)
char *s1, *s2, *s3;
{
int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
char *result = xnew (len1 + len2 + len3 + 1, char);
strcpy (result, s1);
strcpy (result + len1, s2);
strcpy (result + len1 + len2, s3);
result[len1 + len2 + len3] = '\0';
return result;
}
char *
etags_getcwd ()
{
#if defined (HAVE_GETCWD) || defined (WINDOWSNT)
int bufsize = 200;
char *path = xnew (bufsize, char);
while (getcwd (path, bufsize) == NULL)
{
if (errno != ERANGE)
pfatal ("getcwd");
bufsize *= 2;
free (path);
path = xnew (bufsize, char);
}
#if WINDOWSNT
{
char *p;
for (p = path; *p != '\0'; p++)
if (*p == '\\')
*p = '/';
if (islower (path[0]))
path[0] = toupper (path[0]);
}
#endif
return path;
#else
#ifdef MSDOS
char *p, path[MAXPATHLEN + 1];
getwd (path);
for (p = path; *p != '\0'; p++)
if (*p == '\\')
*p = '/';
else
*p = lowcase (*p);
return strdup (path);
#else
struct linebuffer path;
FILE *pipe;
initbuffer (&path);
pipe = (FILE *) popen ("pwd 2>/dev/null", "r");
if (pipe == NULL || readline_internal (&path, pipe) == 0)
pfatal ("pwd");
pclose (pipe);
return path.buffer;
#endif
#endif
}
char *
relative_filename (file, dir)
char *file, *dir;
{
char *fp, *dp, *abs, *res;
int i;
abs = absolute_filename (file, cwd);
fp = abs;
dp = dir;
while (*fp++ == *dp++)
continue;
fp--, dp--;
do {
if (fp == abs) return abs;
fp--, dp--;
} while (*fp != '/');
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, "../");
strcat (res, fp + 1);
free (abs);
return res;
}
char *
absolute_filename (file, cwd)
char *file, *cwd;
{
char *slashp, *cp, *res;
if (absolutefn (file))
res = savestr (file);
#ifdef DOS_NT
else if (file[1] == ':')
fatal ("%s: relative file names with drive letters not supported", file);
#endif
else
res = concat (cwd, file, "");
slashp = etags_strchr (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 && !absolutefn (cp));
if (cp < res)
cp = slashp;
#ifdef DOS_NT
else if (cp[0] != '/')
cp = slashp;
#endif
strcpy (cp, slashp + 3);
slashp = cp;
continue;
}
else if (slashp[2] == '/' || slashp[2] == '\0')
{
strcpy (slashp, slashp + 2);
continue;
}
}
slashp = etags_strchr (slashp + 1, '/');
}
#ifdef DOS_NT
if (res[0] && islower (res[0]))
res[0] = toupper (res[0]);
#endif
if (res[0] == '\0')
return savestr ("/");
else
return res;
}
char *
absolute_dirname (file, cwd)
char *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 savestr (cwd);
save = slashp[1];
slashp[1] = '\0';
res = absolute_filename (file, cwd);
slashp[1] = save;
return res;
}
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);
}
long *
xmalloc (size)
unsigned int size;
{
long *result = (long *) malloc (size);
if (result == NULL)
fatal ("virtual memory exhausted", (char *)NULL);
return result;
}
long *
xrealloc (ptr, size)
char *ptr;
unsigned int size;
{
long *result = (long *) realloc (ptr, size);
if (result == NULL)
fatal ("virtual memory exhausted", (char *)NULL);
return result;
}