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