IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-Copyright (C) 1984, 1987-1989, 1993-1995, 1998-2011
+Copyright (C) 1984, 1987-1989, 1993-1995, 1998-2012
Free Software Foundation, Inc.
This file is not considered part of GNU Emacs.
# define NDEBUG /* disable assert */
#endif
-#ifdef HAVE_CONFIG_H
-# include <config.h>
- /* This is probably not necessary any more. On some systems, config.h
- used to define static as nothing for the sake of unexec. We don't
- want that here since we don't use unexec. None of these systems
- are supported any more, but the idea is still mentioned in
- etc/PROBLEMS. */
-# undef static
-# ifndef PTR /* for XEmacs */
-# define PTR void *
-# endif
-#else /* no config.h */
-# if defined (__STDC__) && (__STDC__ || defined (__SUNPRO_C))
-# define PTR void * /* for generic pointers */
-# else /* not standard C */
-# define const /* remove const for old compilers' sake */
-# define PTR long * /* don't use void* */
-# endif
-#endif /* !HAVE_CONFIG_H */
+#include <config.h>
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1 /* enables some compiler checks on GNU */
# include <fcntl.h>
# include <sys/param.h>
# include <io.h>
-# ifndef HAVE_CONFIG_H
-# define DOS_NT
-# include <sys/config.h>
-# endif
#else
# define MSDOS FALSE
#endif /* MSDOS */
# endif
#endif /* HAVE_UNISTD_H */
+#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <c-strcase.h>
#include <assert.h>
#ifdef NDEBUG
# include <getopt.h>
#endif /* NO_LONG_OPTIONS */
-#ifndef HAVE_CONFIG_H /* this is a standalone compilation */
-# ifdef __CYGWIN__ /* compiling on Cygwin */
- !!! NOTICE !!!
- the regex.h distributed with Cygwin is not compatible with etags, alas!
-If you want regular expression support, you should delete this notice and
- arrange to use the GNU regex.h and regex.c.
-# endif
-#endif
#include <regex.h>
/* Define CTAGS to make the program "ctags" compatible with the usual one.
#endif
#define streq(s,t) (assert ((s)!=NULL || (t)!=NULL), !strcmp (s, t))
-#define strcaseeq(s,t) (assert ((s)!=NULL && (t)!=NULL), !etags_strcasecmp (s, t))
+#define strcaseeq(s,t) (assert ((s)!=NULL && (t)!=NULL), !c_strcasecmp (s, t))
#define strneq(s,t,n) (assert ((s)!=NULL || (t)!=NULL), !strncmp (s, t, n))
-#define strncaseeq(s,t,n) (assert ((s)!=NULL && (t)!=NULL), !etags_strncasecmp (s, t, n))
+#define strncaseeq(s,t,n) (assert ((s)!=NULL && (t)!=NULL), !c_strncasecmp (s, t, n))
#define CHARS 256 /* 2^sizeof(char) */
#define CHAR(x) ((unsigned int)(x) & (CHARS - 1))
struct re_pattern_buffer *pat; /* the compiled pattern */
struct re_registers regs; /* re registers */
bool error_signaled; /* already signaled for this regexp */
- bool force_explicit_name; /* do not allow implict tag name */
+ bool force_explicit_name; /* do not allow implicit tag name */
bool ignore_case; /* ignore case when matching */
bool multi_line; /* do a multi-line match on the whole file */
} regexp;
static void analyse_regex (char *);
static void free_regexps (void);
static void regex_tag_multiline (void);
-static void error (const char *, const char *);
-static void suggest_asking_for_help (void) NO_RETURN;
-void fatal (const char *, const char *) NO_RETURN;
-static void pfatal (const char *) NO_RETURN;
+static void error (const char *, ...) ATTRIBUTE_FORMAT_PRINTF (1, 2);
+static _Noreturn void suggest_asking_for_help (void);
+_Noreturn void fatal (const char *, const char *);
+static _Noreturn void pfatal (const char *);
static void add_node (node *, node **);
static void init (void);
static char *savestr (const char *);
static char *etags_strchr (const char *, int);
static char *etags_strrchr (const char *, int);
-static int etags_strcasecmp (const char *, const char *);
-static int etags_strncasecmp (const char *, const char *, int);
static char *etags_getcwd (void);
static char *relative_filename (char *, char *);
static char *absolute_filename (char *, char *);
static void canonicalize_filename (char *);
static void linebuffer_init (linebuffer *);
static void linebuffer_setlen (linebuffer *, int);
-static PTR xmalloc (size_t);
-static PTR xrealloc (char *, size_t);
+static void *xmalloc (size_t);
+static void *xrealloc (char *, size_t);
\f
static char searchar = '/'; /* use /.../ searches */
static const char *Cplusplus_suffixes [] =
{ "C", "c++", "cc", "cpp", "cxx", "H", "h++", "hh", "hpp", "hxx",
"M", /* Objective C++ */
- "pdb", /* Postscript with C syntax */
+ "pdb", /* PostScript with C syntax */
NULL };
static const char Cplusplus_help [] =
"In C++ code, all the tag constructs of C code are tagged. (Use\n\
static void
print_version (void)
{
- /* Makes it easier to update automatically. */
- char emacs_copyright[] = "Copyright (C) 2011 Free Software Foundation, Inc.";
+ char emacs_copyright[] = COPYRIGHT;
printf ("%s (%s %s)\n", (CTAGS) ? "ctags" : "etags", EMACS_NAME, VERSION);
puts (emacs_copyright);
case 'o':
if (tagfile)
{
- error ("-o option may only be given once.", (char *)NULL);
+ error ("-o option may only be given once.");
suggest_asking_for_help ();
/* NOTREACHED */
}
if (nincluded_files == 0 && file_count == 0)
{
- error ("no input files specified.", (char *)NULL);
+ error ("no input files specified.");
suggest_asking_for_help ();
/* NOTREACHED */
}
language *lang;
if (name == NULL)
- error ("empty language name", (char *)NULL);
+ error ("empty language name");
else
{
for (lang = lang_names; lang->name != NULL; lang++)
assert (parser != NULL);
- /* Generic initialisations before reading from file. */
+ /* Generic initializations before reading from file. */
linebuffer_setlen (&filebuf, 0); /* reset the file buffer */
- /* Generic initialisations before parsing file with readline. */
+ /* Generic initializations before parsing file with readline. */
lineno = 0; /* reset global line number */
charno = 0; /* reset global char number */
linecharno = 0; /* reset global char number of line start */
* 4. the character, if any, immediately after NAME in LINESTART must
* also be a character in NONAM.
*
- * The implementation uses the notinname() macro, which recognises the
+ * The implementation uses the notinname() macro, which recognizes the
* characters stored in the string `nonam'.
* etags.el needs to use the same characters that are in NONAM.
*/
\f
static int total_size_of_entries (node *);
-static int number_len (long);
+static int number_len (long) ATTRIBUTE_CONST;
/* Length of a non-negative number's decimal representation. */
static int
{
/* Ctags mode */
if (np->name == NULL)
- error ("internal error: NULL name in ctags mode.", (char *)NULL);
+ error ("internal error: NULL name in ctags mode.");
if (cxref_style)
{
}
for (i = 1; i < cstack.nl; i++)
{
- char *s;
- int slen;
-
- s = cstack.cname[i];
+ char *s = cstack.cname[i];
if (s == NULL)
continue;
- slen = strlen (s);
- len += slen + qlen;
- linebuffer_setlen (cn, len);
- strncat (cn->buffer, qualifier, qlen);
- strncat (cn->buffer, s, slen);
+ linebuffer_setlen (cn, len + qlen + strlen (s));
+ len += sprintf (cn->buffer + len, "%s%s", qualifier, s);
}
}
case dignorerest:
return FALSE;
default:
- error ("internal error: definedef value.", (char *)NULL);
+ error ("internal error: definedef value.");
}
/*
fvdef = fvnone;
objdef = omethodtag;
linebuffer_setlen (&token_name, len);
- strncpy (token_name.buffer, str, len);
+ memcpy (token_name.buffer, str, len);
token_name.buffer[len] = '\0';
return TRUE;
}
case omethodparm:
if (parlev == 0)
{
+ int oldlen = token_name.len;
fvdef = fvnone;
objdef = omethodtag;
- linebuffer_setlen (&token_name, token_name.len + len);
- strncat (token_name.buffer, str, len);
+ linebuffer_setlen (&token_name, oldlen + len);
+ memcpy (token_name.buffer + oldlen, str, len);
+ token_name.buffer[oldlen + len] = '\0';
return TRUE;
}
return FALSE;
make_tag (token_name.buffer, token_name.len, isfun, token.line,
token.offset+token.length+1, token.lineno, token.linepos);
else if (DEBUG)
- { /* this branch is optimised away if !DEBUG */
+ { /* this branch is optimized away if !DEBUG */
make_tag (concat ("INVALID TOKEN:-->", token_name.buffer, ""),
token_name.len + 17, isfun, token.line,
token.offset+token.length+1, token.lineno, token.linepos);
- error ("INVALID TOKEN", NULL);
+ error ("INVALID TOKEN");
}
token.valid = FALSE;
}
continue;
}
- else if (bracketlev > 0)
- {
- switch (c)
- {
- case ']':
- if (--bracketlev > 0)
- continue;
- break;
- case '\0':
- CNL_SAVE_DEFINEDEF ();
- break;
- }
- continue;
- }
else switch (c)
{
case '"':
inquote = TRUE;
+ if (bracketlev > 0)
+ continue;
if (inattribute)
break;
switch (fvdef)
continue;
case '\'':
inchar = TRUE;
+ if (bracketlev > 0)
+ continue;
if (inattribute)
break;
- if (fvdef != finlist && fvdef != fignore && fvdef !=vignore)
+ if (fvdef != finlist && fvdef != fignore && fvdef != vignore)
{
fvextern = FALSE;
fvdef = fvnone;
incomm = TRUE;
lp++;
c = ' ';
+ if (bracketlev > 0)
+ continue;
}
else if (/* cplpl && */ *lp == '/')
{
for (cp = newlb.buffer; cp < lp-1; cp++)
if (!iswhite (*cp))
{
- if (*cp == '*' && *(cp+1) == '/')
+ if (*cp == '*' && cp[1] == '/')
{
cp++;
cpptoken = TRUE;
continue;
case '[':
bracketlev++;
- continue;
+ continue;
+ default:
+ if (bracketlev > 0)
+ {
+ if (c == ']')
+ --bracketlev;
+ else if (c == '\0')
+ CNL_SAVE_DEFINEDEF ();
+ continue;
+ }
+ break;
} /* switch (c) */
if (c == ':' && *lp == ':' && begtoken (lp[1]))
/* This handles :: in the middle,
but not at the beginning of an identifier.
- Also, space-separated :: is not recognised. */
+ Also, space-separated :: is not recognized. */
{
if (c_ext & C_AUTO) /* automatic detection of C++ */
c_ext = (c_ext | C_PLPL) & ~C_AUTO;
&& nestlev > 0 && definedef == dnone)
/* in struct body */
{
+ int len;
write_classname (&token_name, qualifier);
- linebuffer_setlen (&token_name,
- token_name.len+qlen+toklen);
- strcat (token_name.buffer, qualifier);
- strncat (token_name.buffer,
- newlb.buffer + tokoff, toklen);
+ len = token_name.len;
+ linebuffer_setlen (&token_name, len+qlen+toklen);
+ sprintf (token_name.buffer + len, "%s%.*s",
+ qualifier, toklen, newlb.buffer + tokoff);
token.named = TRUE;
}
else if (objdef == ocatseen)
{
int len = strlen (objtag) + 2 + toklen;
linebuffer_setlen (&token_name, len);
- strcpy (token_name.buffer, objtag);
- strcat (token_name.buffer, "(");
- strncat (token_name.buffer,
- newlb.buffer + tokoff, toklen);
- strcat (token_name.buffer, ")");
+ sprintf (token_name.buffer, "%s(%.*s)",
+ objtag, toklen, newlb.buffer + tokoff);
token.named = TRUE;
}
else if (objdef == omethodtag
len -= 1;
}
linebuffer_setlen (&token_name, len);
- strncpy (token_name.buffer,
- newlb.buffer + off, len);
+ memcpy (token_name.buffer,
+ newlb.buffer + off, len);
token_name.buffer[len] = '\0';
if (defun)
while (--len >= 0)
else
{
linebuffer_setlen (&token_name, toklen);
- strncpy (token_name.buffer,
- newlb.buffer + tokoff, toklen);
+ memcpy (token_name.buffer,
+ newlb.buffer + tokoff, toklen);
token_name.buffer[toklen] = '\0';
/* Name macros and members. */
token.named = (structdef == stagseen
/* Check if this is an "extern" declaration. */
if (*dbp == '\0')
continue;
- if (lowcase (*dbp == 'e'))
+ if (lowcase (*dbp) == 'e')
{
if (nocase_tail ("extern")) /* superfluous, really! */
{
\f
/*
- * Postscript tags
+ * PostScript tags
* Just look for lines where the first character is '/'
* Also look at "defineps" for PSWrap
* Ideas by:
for (end = dbp; *end != '\0' && intoken (*end); end++)
continue;
linebuffer_setlen (&token_name, end - dbp);
- strncpy (token_name.buffer, dbp, end - dbp);
+ memcpy (token_name.buffer, dbp, end - dbp);
token_name.buffer[end - dbp] = '\0';
dbp = end;
else if (len + 1 > allocated)
xrnew (last, len + 1, char);
allocated = len + 1;
- strncpy (last, cp, len);
+ memcpy (last, cp, len);
last[len] = '\0';
}
}
else if (len + 1 > allocated)
xrnew (last, len + 1, char);
allocated = len + 1;
- strncpy (last, cp, len);
+ memcpy (last, cp, len);
last[len] = '\0';
}
}
{
static struct re_pattern_buffer zeropattern;
char sep, *pat, *name, *modifiers;
- char empty[] = "";
+ char empty = '\0';
const char *err;
struct re_pattern_buffer *patbuf;
regexp *rp;
if (strlen (regexp_pattern) < 3)
{
- error ("null regexp", (char *)NULL);
+ error ("null regexp");
return;
}
sep = regexp_pattern[0];
if (modifiers == NULL) /* no terminating separator --> no name */
{
modifiers = name;
- name = empty;
+ name = ∅
}
else
modifiers += 1; /* skip separator */
{
case 'N':
if (modifiers == name)
- error ("forcing explicit tag name but no name, ignoring", NULL);
+ error ("forcing explicit tag name but no name, ignoring");
force_explicit_name = TRUE;
break;
case 'i':
need_filebuf = TRUE;
break;
default:
- {
- char wrongmod [2];
- wrongmod[0] = modifiers[0];
- wrongmod[1] = '\0';
- error ("invalid regexp modifier `%s', ignoring", wrongmod);
- }
+ error ("invalid regexp modifier `%c', ignoring", modifiers[0]);
break;
}
{
dig = *out - '0';
diglen = regs->end[dig] - regs->start[dig];
- strncpy (t, in + regs->start[dig], diglen);
+ memcpy (t, in + regs->start[dig], diglen);
t += diglen;
}
else
if (!rp->multi_line)
continue; /* skip normal regexps */
- /* Generic initialisations before parsing file from memory. */
+ /* Generic initializations before parsing file from memory. */
lineno = 1; /* reset global line number */
charno = 0; /* reset global char number */
linecharno = 0; /* reset global char number of line start */
filebuf.size *= 2;
xrnew (filebuf.buffer, filebuf.size, char);
}
- strncpy (filebuf.buffer + filebuf.len, lbp->buffer, lbp->len);
+ memcpy (filebuf.buffer + filebuf.len, lbp->buffer, lbp->len);
filebuf.len += lbp->len;
filebuf.buffer[filebuf.len++] = '\n';
filebuf.buffer[filebuf.len] = '\0';
lineno += 1; /* increment global line number */
charno += result; /* increment global char number */
- /* Honour #line directives. */
+ /* Honor #line directives. */
if (!no_line_directive)
{
static bool discard_until_line_directive;
register char *dp;
dp = xnew (len + 1, char);
- strncpy (dp, cp, len);
+ memcpy (dp, cp, len);
dp[len] = '\0';
return dp;
}
return NULL;
}
-/*
- * Compare two strings, ignoring case for alphabetic characters.
- *
- * Same as BSD's strcasecmp, included for portability.
- */
-static int
-etags_strcasecmp (register const char *s1, register const char *s2)
-{
- while (*s1 != '\0'
- && (ISALPHA (*s1) && ISALPHA (*s2)
- ? lowcase (*s1) == lowcase (*s2)
- : *s1 == *s2))
- s1++, s2++;
-
- return (ISALPHA (*s1) && ISALPHA (*s2)
- ? lowcase (*s1) - lowcase (*s2)
- : *s1 - *s2);
-}
-
-/*
- * Compare two strings, ignoring case for alphabetic characters.
- * Stop after a given number of characters
- *
- * Same as BSD's strncasecmp, included for portability.
- */
-static int
-etags_strncasecmp (register const char *s1, register const char *s2, register int n)
-{
- while (*s1 != '\0' && n-- > 0
- && (ISALPHA (*s1) && ISALPHA (*s2)
- ? lowcase (*s1) == lowcase (*s2)
- : *s1 == *s2))
- s1++, s2++;
-
- if (n < 0)
- return 0;
- else
- return (ISALPHA (*s1) && ISALPHA (*s2)
- ? lowcase (*s1) - lowcase (*s2)
- : *s1 - *s2);
-}
-
/* Skip spaces (end of string is not space), return new pointer. */
static char *
skip_spaces (char *cp)
exit (EXIT_FAILURE);
}
-/* Print error message. `s1' is printf control string, `s2' is arg for it. */
+/* Output a diagnostic with printf-style FORMAT and args. */
static void
-error (const char *s1, const char *s2)
+error (const char *format, ...)
{
+ va_list ap;
+ va_start (ap, format);
fprintf (stderr, "%s: ", progname);
- fprintf (stderr, s1, s2);
+ vfprintf (stderr, format, ap);
fprintf (stderr, "\n");
+ va_end (ap);
}
/* Return a newly-allocated string whose contents
}
/* Like malloc but get fatal error if memory is exhausted. */
-static PTR
+static void *
xmalloc (size_t size)
{
- PTR result = (PTR) malloc (size);
+ void *result = malloc (size);
if (result == NULL)
fatal ("virtual memory exhausted", (char *)NULL);
return result;
}
-static PTR
+static void *
xrealloc (char *ptr, size_t size)
{
- PTR result = (PTR) realloc (ptr, size);
+ void *result = realloc (ptr, size);
if (result == NULL)
fatal ("virtual memory exhausted", (char *)NULL);
return result;