Update Cygwin's fnmatch to latest from FreeBSD.

* collate.h (__collate_load_error): Convert to extern declaration.
        * globals.cc (__collate_load_error): Define and initialize here.
        * libc/fnmatch.c: Update to latest from FreeBSD.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2015-11-18 20:51:12 +01:00
parent 8cdd7bad21
commit 7da497499f
3 changed files with 87 additions and 55 deletions

View File

@ -1,6 +1,6 @@
/* collate.h: Internal BSD libc header, used in glob and regcomp, for instance. /* collate.h: Internal BSD libc header, used in glob and regcomp, for instance.
Copyright 2012 Red Hat, Inc. Copyright 2012, 2015 Red Hat, Inc.
This file is part of Cygwin. This file is part of Cygwin.
@ -13,10 +13,9 @@ details. */
extern "C" { extern "C" {
#endif #endif
/* We never have a collate load error. */ extern const int __collate_load_error;
const int __collate_load_error = 0;
int __collate_range_cmp (int c1, int c2); extern int __collate_range_cmp (int c1, int c2);
#ifdef __cplusplus #ifdef __cplusplus
}; };

View File

@ -103,6 +103,9 @@ char NO_COPY almost_null[1];
extern "C" { extern "C" {
/* We never have a collate load error. */
const int __collate_load_error = 0;
/* Heavily-used const UNICODE_STRINGs are defined here once. The idea is a /* Heavily-used const UNICODE_STRINGs are defined here once. The idea is a
speed improvement by not having to initialize a UNICODE_STRING every time speed improvement by not having to initialize a UNICODE_STRING every time
we make a string comparison. The _RDATA trick allows defining the strings we make a string comparison. The _RDATA trick allows defining the strings

View File

@ -5,6 +5,11 @@
* This code is derived from software contributed to Berkeley by * This code is derived from software contributed to Berkeley by
* Guido van Rossum. * Guido van Rossum.
* *
* Copyright (c) 2011 The FreeBSD Foundation
* All rights reserved.
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
* are met: * are met:
@ -34,9 +39,7 @@
static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94"; static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94";
#endif /* LIBC_SCCS and not lint */ #endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h> #include <sys/cdefs.h>
#if 0 __FBSDID("$FreeBSD: head/lib/libc/gen/fnmatch.c 288309 2015-09-27 12:52:18Z jilles $");
__FBSDID("$FreeBSD: src/lib/libc/gen/fnmatch.c,v 1.18 2007/01/09 00:27:53 imp Exp $");
#endif
/* /*
* Function fnmatch() as specified in POSIX 1003.2-1992, section B.6. * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
@ -60,7 +63,11 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/fnmatch.c,v 1.18 2007/01/09 00:27:53 imp Ex
#include <wchar.h> #include <wchar.h>
#include <wctype.h> #include <wctype.h>
#include "../posix/collate.h" #ifdef __CYGWIN__
#include "../collate.h"
#else
#include "collate.h"
#endif
#define EOS '\0' #define EOS '\0'
@ -69,31 +76,30 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/fnmatch.c,v 1.18 2007/01/09 00:27:53 imp Ex
#define RANGE_ERROR (-1) #define RANGE_ERROR (-1)
static int rangematch(const char *, wchar_t, int, char **, mbstate_t *); static int rangematch(const char *, wchar_t, int, char **, mbstate_t *);
static int fnmatch1(const char *, const char *, int, mbstate_t, mbstate_t); static int fnmatch1(const char *, const char *, const char *, int, mbstate_t,
mbstate_t);
int int
fnmatch(pattern, string, flags) fnmatch(const char *pattern, const char *string, int flags)
const char *pattern, *string;
int flags;
{ {
static const mbstate_t initial; static const mbstate_t initial;
return (fnmatch1(pattern, string, flags, initial, initial)); return (fnmatch1(pattern, string, string, flags, initial, initial));
} }
static int static int
fnmatch1(pattern, string, flags, patmbs, strmbs) fnmatch1(const char *pattern, const char *string, const char *stringstart,
const char *pattern, *string; int flags, mbstate_t patmbs, mbstate_t strmbs)
int flags;
mbstate_t patmbs, strmbs;
{ {
const char *stringstart; const char *bt_pattern, *bt_string;
mbstate_t bt_patmbs, bt_strmbs;
char *newp; char *newp;
char c; char c;
wchar_t pc, sc; wchar_t pc, sc;
size_t pclen, sclen; size_t pclen, sclen;
for (stringstart = string;;) { bt_pattern = bt_string = NULL;
for (;;) {
pclen = mbrtowc(&pc, pattern, MB_LEN_MAX, &patmbs); pclen = mbrtowc(&pc, pattern, MB_LEN_MAX, &patmbs);
if (pclen == (size_t)-1 || pclen == (size_t)-2) if (pclen == (size_t)-1 || pclen == (size_t)-2)
return (FNM_NOMATCH); return (FNM_NOMATCH);
@ -108,16 +114,18 @@ fnmatch1(pattern, string, flags, patmbs, strmbs)
case EOS: case EOS:
if ((flags & FNM_LEADING_DIR) && sc == '/') if ((flags & FNM_LEADING_DIR) && sc == '/')
return (0); return (0);
return (sc == EOS ? 0 : FNM_NOMATCH); if (sc == EOS)
return (0);
goto backtrack;
case '?': case '?':
if (sc == EOS) if (sc == EOS)
return (FNM_NOMATCH); return (FNM_NOMATCH);
if (sc == '/' && (flags & FNM_PATHNAME)) if (sc == '/' && (flags & FNM_PATHNAME))
return (FNM_NOMATCH); goto backtrack;
if (sc == '.' && (flags & FNM_PERIOD) && if (sc == '.' && (flags & FNM_PERIOD) &&
(string == stringstart || (string == stringstart ||
((flags & FNM_PATHNAME) && *(string - 1) == '/'))) ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
return (FNM_NOMATCH); goto backtrack;
string += sclen; string += sclen;
break; break;
case '*': case '*':
@ -129,7 +137,7 @@ fnmatch1(pattern, string, flags, patmbs, strmbs)
if (sc == '.' && (flags & FNM_PERIOD) && if (sc == '.' && (flags & FNM_PERIOD) &&
(string == stringstart || (string == stringstart ||
((flags & FNM_PATHNAME) && *(string - 1) == '/'))) ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
return (FNM_NOMATCH); goto backtrack;
/* Optimize for pattern with * at end or before /. */ /* Optimize for pattern with * at end or before /. */
if (c == EOS) if (c == EOS)
@ -145,33 +153,24 @@ fnmatch1(pattern, string, flags, patmbs, strmbs)
break; break;
} }
/* General case, use recursion. */ /*
while (sc != EOS) { * First try the shortest match for the '*' that
if (!fnmatch1(pattern, string, * could work. We can forget any earlier '*' since
flags & ~FNM_PERIOD, patmbs, strmbs)) * there is no way having it match more characters
return (0); * can help us, given that we are already here.
sclen = mbrtowc(&sc, string, MB_LEN_MAX, */
&strmbs); bt_pattern = pattern, bt_patmbs = patmbs;
if (sclen == (size_t)-1 || bt_string = string, bt_strmbs = strmbs;
sclen == (size_t)-2) {
sc = (unsigned char)*string;
sclen = 1;
memset(&strmbs, 0, sizeof(strmbs));
}
if (sc == '/' && flags & FNM_PATHNAME)
break; break;
string += sclen;
}
return (FNM_NOMATCH);
case '[': case '[':
if (sc == EOS) if (sc == EOS)
return (FNM_NOMATCH); return (FNM_NOMATCH);
if (sc == '/' && (flags & FNM_PATHNAME)) if (sc == '/' && (flags & FNM_PATHNAME))
return (FNM_NOMATCH); goto backtrack;
if (sc == '.' && (flags & FNM_PERIOD) && if (sc == '.' && (flags & FNM_PERIOD) &&
(string == stringstart || (string == stringstart ||
((flags & FNM_PATHNAME) && *(string - 1) == '/'))) ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
return (FNM_NOMATCH); goto backtrack;
switch (rangematch(pattern, sc, flags, &newp, switch (rangematch(pattern, sc, flags, &newp,
&patmbs)) { &patmbs)) {
@ -181,7 +180,7 @@ fnmatch1(pattern, string, flags, patmbs, strmbs)
pattern = newp; pattern = newp;
break; break;
case RANGE_NOMATCH: case RANGE_NOMATCH:
return (FNM_NOMATCH); goto backtrack;
} }
string += sclen; string += sclen;
break; break;
@ -191,21 +190,44 @@ fnmatch1(pattern, string, flags, patmbs, strmbs)
&patmbs); &patmbs);
if (pclen == (size_t)-1 || pclen == (size_t)-2) if (pclen == (size_t)-1 || pclen == (size_t)-2)
return (FNM_NOMATCH); return (FNM_NOMATCH);
if (pclen == 0)
pc = '\\';
pattern += pclen; pattern += pclen;
} }
/* FALLTHROUGH */ /* FALLTHROUGH */
default: default:
norm: norm:
string += sclen;
if (pc == sc) if (pc == sc)
; ;
else if ((flags & FNM_CASEFOLD) && else if ((flags & FNM_CASEFOLD) &&
(towlower(pc) == towlower(sc))) (towlower(pc) == towlower(sc)))
; ;
else else {
backtrack:
/*
* If we have a mismatch (other than hitting
* the end of the string), go back to the last
* '*' seen and have it match one additional
* character.
*/
if (bt_pattern == NULL)
return (FNM_NOMATCH); return (FNM_NOMATCH);
string += sclen; sclen = mbrtowc(&sc, bt_string, MB_LEN_MAX,
&bt_strmbs);
if (sclen == (size_t)-1 ||
sclen == (size_t)-2) {
sc = (unsigned char)*bt_string;
sclen = 1;
memset(&bt_strmbs, 0,
sizeof(bt_strmbs));
}
if (sc == EOS)
return (FNM_NOMATCH);
if (sc == '/' && flags & FNM_PATHNAME)
return (FNM_NOMATCH);
bt_string += sclen;
pattern = bt_pattern, patmbs = bt_patmbs;
string = bt_string, strmbs = bt_strmbs;
}
break; break;
} }
} }
@ -213,17 +235,17 @@ fnmatch1(pattern, string, flags, patmbs, strmbs)
} }
static int static int
rangematch(pattern, test, flags, newp, patmbs) rangematch(const char *pattern, wchar_t test, int flags, char **newp,
const char *pattern; mbstate_t *patmbs)
wchar_t test;
int flags;
char **newp;
mbstate_t *patmbs;
{ {
int negate, ok; int negate, ok;
wchar_t c, c2; wchar_t c, c2;
size_t pclen; size_t pclen;
const char *origpat; const char *origpat;
#ifndef __CYGWIN__
struct xlocale_collate *table =
(struct xlocale_collate*)__get_locale()->components[XLC_COLLATE];
#endif
/* /*
* A bracket expression starting with an unquoted circumflex * A bracket expression starting with an unquoted circumflex
@ -278,11 +300,19 @@ rangematch(pattern, test, flags, newp, patmbs)
if (flags & FNM_CASEFOLD) if (flags & FNM_CASEFOLD)
c2 = towlower(c2); c2 = towlower(c2);
#ifdef __CYGWIN__
if (__collate_load_error ? if (__collate_load_error ?
c <= test && test <= c2 : c <= test && test <= c2 :
__collate_range_cmp(c, test) <= 0 __collate_range_cmp(c, test) <= 0
&& __collate_range_cmp(test, c2) <= 0 && __collate_range_cmp(test, c2) <= 0
) )
#else
if (table->__collate_load_error ?
c <= test && test <= c2 :
__collate_range_cmp(table, c, test) <= 0
&& __collate_range_cmp(table, test, c2) <= 0
)
#endif
ok = 1; ok = 1;
} else if (c == test) } else if (c == test)
ok = 1; ok = 1;