Skip to content

Commit

Permalink
Add bundled fnmatch from upstream ctags
Browse files Browse the repository at this point in the history
If we don't have `fnmatch()` (e.g. on Windows), use the bundled version
from upstream ctags.
  • Loading branch information
b4n committed Nov 22, 2020
1 parent 33fc269 commit b1c9096
Show file tree
Hide file tree
Showing 4 changed files with 246 additions and 1 deletion.
2 changes: 2 additions & 0 deletions configure.ac
Expand Up @@ -52,6 +52,8 @@ AC_CHECK_FUNC([regcomp],
AC_CHECK_FUNCS([memcpy isblank wcrtomb mbrtowc wcscoll])
AC_FUNC_ALLOCA])
AM_CONDITIONAL([USE_BUNDLED_REGEX], [test "xno" = "x$have_regcomp"])
AC_CHECK_FUNC([fnmatch], [have_fnmatch=yes], [have_fnmatch=no])
AM_CONDITIONAL([USE_BUNDLED_FNMATCH], [test "xno" = "x$have_fnmatch"])

# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_OFF_T
Expand Down
15 changes: 14 additions & 1 deletion ctags/Makefile.am
Expand Up @@ -177,6 +177,8 @@ libctags_la_SOURCES = \
main/xtag_p.h \
$(parsers)

libctags_la_LIBADD =

# build bundled GNU regex if needed
if USE_BUNDLED_REGEX
noinst_LTLIBRARIES += libgnu_regex.la
Expand All @@ -195,6 +197,17 @@ libgnu_regex_la_CPPFLAGS = -D__USE_GNU
EXTRA_DIST = \
gnu_regex/README.txt

libctags_la_LIBADD = libgnu_regex.la
libctags_la_LIBADD += libgnu_regex.la
AM_CPPFLAGS += -I$(srcdir)/gnu_regex
endif

# build bundled fnmatch if needed
if USE_BUNDLED_FNMATCH
noinst_LTLIBRARIES += libfnmatch.la
libfnmatch_la_SOURCES = \
fnmatch/fnmatch.c \
fnmatch/fnmatch.h

libctags_la_LIBADD += libfnmatch.la
AM_CPPFLAGS += -I$(srcdir)/fnmatch
endif
190 changes: 190 additions & 0 deletions ctags/fnmatch/fnmatch.c
@@ -0,0 +1,190 @@
/* Copyright (C) 1992 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details. */

/* Modified slightly by Brian Berliner <berliner@sun.com> and
Jim Blandy <jimb@cyclic.com> for CVS use */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

/* Some file systems are case-insensitive. If FOLD_FN_CHAR is
#defined, it maps the character C onto its "canonical" form. In a
case-insensitive system, it would map all alphanumeric characters
to lower case. Under Windows NT, / and \ are both path component
separators, so FOLD_FN_CHAR would map them both to /. */
#ifndef FOLD_FN_CHAR
#define FOLD_FN_CHAR(c) (c)
#endif

/* IGNORE(@ */
/* #include <ansidecl.h> */
/* @) */
#include <errno.h>
#include <fnmatch.h>

#if !defined(__GNU_LIBRARY__) \
&& !defined(STDC_HEADERS) \
&& !defined(_CRT_ERRNO_DEFINED)
extern int errno;
#endif

/* Match STRING against the filename pattern PATTERN, returning zero if
it matches, nonzero if not. */
int
#if __STDC__
fnmatch (const char *pattern, const char *string, int flags)
#else
fnmatch (pattern, string, flags)
char *pattern;
char *string;
int flags;
#endif
{
register const char *p = pattern, *n = string;
register char c;

if ((flags & ~__FNM_FLAGS) != 0)
{
errno = EINVAL;
return -1;
}

while ((c = *p++) != '\0')
{
switch (c)
{
case '?':
if (*n == '\0')
return FNM_NOMATCH;
else if ((flags & FNM_PATHNAME) && *n == '/')
return FNM_NOMATCH;
else if ((flags & FNM_PERIOD) && *n == '.' &&
(n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
return FNM_NOMATCH;
break;

case '\\':
if (!(flags & FNM_NOESCAPE))
c = *p++;
if (*n != c)
return FNM_NOMATCH;
break;

case '*':
if ((flags & FNM_PERIOD) && *n == '.' &&
(n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
return FNM_NOMATCH;

for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
if (((flags & FNM_PATHNAME) && *n == '/') ||
(c == '?' && *n == '\0'))
return FNM_NOMATCH;

if (c == '\0')
return 0;

{
char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
for (--p; *n != '\0'; ++n)
if ((c == '[' || *n == c1) &&
fnmatch(p, n, flags & ~FNM_PERIOD) == 0)
return 0;
return FNM_NOMATCH;
}

case '[':
{
/* Nonzero if the sense of the character class is inverted. */
register int not;

if (*n == '\0')
return FNM_NOMATCH;

if ((flags & FNM_PERIOD) && *n == '.' &&
(n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
return FNM_NOMATCH;

not = (*p == '!' || *p == '^');
if (not)
++p;

c = *p++;
for (;;)
{
register char cstart = c, cend = c;

if (!(flags & FNM_NOESCAPE) && c == '\\')
cstart = cend = *p++;

if (c == '\0')
/* [ (unterminated) loses. */
return FNM_NOMATCH;

c = *p++;

if ((flags & FNM_PATHNAME) && c == '/')
/* [/] can never match. */
return FNM_NOMATCH;

if (c == '-' && *p != ']')
{
cend = *p++;
if (!(flags & FNM_NOESCAPE) && cend == '\\')
cend = *p++;
if (cend == '\0')
return FNM_NOMATCH;
c = *p++;
}

if (*n >= cstart && *n <= cend)
goto matched;

if (c == ']')
break;
}
if (!not)
return FNM_NOMATCH;
break;

matched:;
/* Skip the rest of the [...] that already matched. */
while (c != ']')
{
if (c == '\0')
/* [... (unterminated) loses. */
return FNM_NOMATCH;

c = *p++;
if (!(flags & FNM_NOESCAPE) && c == '\\')
/* 1003.2d11 is unclear if this is right. %%% */
++p;
}
if (not)
return FNM_NOMATCH;
}
break;

default:
if (FOLD_FN_CHAR (c) != FOLD_FN_CHAR (*n))
return FNM_NOMATCH;
}

++n;
}

if (*n == '\0')
return 0;

return FNM_NOMATCH;
}
40 changes: 40 additions & 0 deletions ctags/fnmatch/fnmatch.h
@@ -0,0 +1,40 @@
/* Copyright (C) 1992 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details. */

#ifndef _FNMATCH_H

#define _FNMATCH_H 1

/* Bits set in the FLAGS argument to `fnmatch'. */
#undef FNM_PATHNAME
#define FNM_PATHNAME (1 << 0)/* No wildcard can ever match `/'. */
#undef FNM_NOESCAPE
#define FNM_NOESCAPE (1 << 1)/* Backslashes don't quote special chars. */
#undef FNM_PERIOD
#define FNM_PERIOD (1 << 2)/* Leading `.' is matched only explicitly. */
#undef __FNM_FLAGS
#define __FNM_FLAGS (FNM_PATHNAME|FNM_NOESCAPE|FNM_PERIOD)

/* Value returned by `fnmatch' if STRING does not match PATTERN. */
#undef FNM_NOMATCH
#define FNM_NOMATCH 1

/* Match STRING against the filename pattern PATTERN,
returning zero if it matches, FNM_NOMATCH if not. */
#if __STDC__
extern int fnmatch (const char *pattern, const char *string, int flags);
#else
extern int fnmatch ();
#endif

#endif /* fnmatch.h */

0 comments on commit b1c9096

Please sign in to comment.