From patchwork Wed Dec 30 20:15:03 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 41602 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 4FE28385042E; Wed, 30 Dec 2020 20:15:15 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4FE28385042E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1609359315; bh=H+k3pqoJjWu2cTUOL2uSXLK8Rd19WA79DWUyMAxZIGg=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:Cc:From; b=xRi4/m8JqpvS7L0dQ+w5vwaK29uyOAAMGlfrlaxpAyQcziZp/rTeNx8dLCo8v3Aeg o8CpmVKVyip7B4Euui/j+l6g2/LJtndCh4OUPKZrdrLzIz0G5W/GzFY2VyQjPRU9Al 5AI2AfXdPf4AevhyshVC36IDW79s8RvL9/ofAHNw= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qt1-x835.google.com (mail-qt1-x835.google.com [IPv6:2607:f8b0:4864:20::835]) by sourceware.org (Postfix) with ESMTPS id D56183858038 for ; Wed, 30 Dec 2020 20:15:12 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org D56183858038 Received: by mail-qt1-x835.google.com with SMTP id a6so11684320qtw.6 for ; Wed, 30 Dec 2020 12:15:12 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=H+k3pqoJjWu2cTUOL2uSXLK8Rd19WA79DWUyMAxZIGg=; b=FtTV57qD12QKeS769KmIblljz8SKhLZyVLFQLZUeXcr8sQ8gWZ6YEryZwvLNQmWFp4 +45D0ny4LPYAqo8U32tIO766H4LxviqXQBc+LuOFVD2tW08PGq0ti2dx2+8W8q3S3llI olMnjo1yr4bFEO6rmUV8BSVxZ5wb0KU3MYCQ1ZWWQ3hHH5YOhcBXtqYUSnbVQtjUs2OG wGVIsW5N4UPBYSnFycM3iebrEKyz5BhT/VK46VIXrsMAtRgG2z1ow8gZkylOhzpk7uZ5 3fjI6obpsOxg3ckKHYwt1Ig9V3tFzxyJZZW9pZVRmYzmLDW4Sto02xLhwbfGJvOgDIrJ FOfw== X-Gm-Message-State: AOAM531XzupWi2I1AtFSmJ1XZ2HxlI/q25SkwI1qsyUnjGXH7iXZbAkq cnoP+96xeI4MXHaIaLoBLskh886kUEOprA== X-Google-Smtp-Source: ABdhPJygwetgULcV3frqeEFOM9eAIa6ABiNFml4VwzfhfWpJj7Ts6UR0utjlnxf3ocErww64IIDi9A== X-Received: by 2002:ac8:6b59:: with SMTP id x25mr54565220qts.301.1609359312123; Wed, 30 Dec 2020 12:15:12 -0800 (PST) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id v145sm5949057qka.27.2020.12.30.12.15.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Dec 2020 12:15:11 -0800 (PST) To: libc-alpha@sourceware.org, Paul Eggert Subject: [PATCH 1/5] posix: Sync regex code with gnulib Date: Wed, 30 Dec 2020 17:15:03 -0300 Message-Id: <20201230201507.2755086-1-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 X-Spam-Status: No, score=-13.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Reply-To: Adhemerval Zanella Cc: bug-gnulib@gnu.org Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" It sync with gnulib commit 43ee1a6bf. The main change is 9682f18e9. (which does not have a meaniful description). Checked on x86_64-linux-gnu. --- posix/regcomp.c | 2 +- posix/regex.h | 17 ++++++++++++----- posix/regex_internal.c | 19 ++++++++++--------- posix/regex_internal.h | 16 ++++++++++++---- 4 files changed, 35 insertions(+), 19 deletions(-) diff --git a/posix/regcomp.c b/posix/regcomp.c index 93bb0a0538..692928b0db 100644 --- a/posix/regcomp.c +++ b/posix/regcomp.c @@ -558,7 +558,7 @@ weak_alias (__regerror, regerror) static const bitset_t utf8_sb_map = { /* Set the first 128 bits. */ -# if defined __GNUC__ && !defined __STRICT_ANSI__ +# if (defined __GNUC__ || __clang_major__ >= 4) && !defined __STRICT_ANSI__ [0 ... 0x80 / BITSET_WORD_BITS - 1] = BITSET_WORD_MAX # else # if 4 * BITSET_WORD_BITS < ASCII_CHARS diff --git a/posix/regex.h b/posix/regex.h index 5fe41c8685..7418e6c76f 100644 --- a/posix/regex.h +++ b/posix/regex.h @@ -612,7 +612,9 @@ extern int re_exec (const char *); 'configure' might #define 'restrict' to those words, so pick a different name. */ #ifndef _Restrict_ -# if defined __restrict || 2 < __GNUC__ + (95 <= __GNUC_MINOR__) +# if defined __restrict \ + || 2 < __GNUC__ + (95 <= __GNUC_MINOR__) \ + || __clang_major__ >= 3 # define _Restrict_ __restrict # elif 199901L <= __STDC_VERSION__ || defined restrict # define _Restrict_ restrict @@ -620,13 +622,18 @@ extern int re_exec (const char *); # define _Restrict_ # endif #endif -/* For [restrict], use glibc's __restrict_arr if available. - Otherwise, GCC 3.1 (not in C++ mode) and C99 support [restrict]. */ +/* For the ISO C99 syntax + array_name[restrict] + use glibc's __restrict_arr if available. + Otherwise, GCC 3.1 and clang support this syntax (but not in C++ mode). + Other ISO C99 compilers support it as well. */ #ifndef _Restrict_arr_ # ifdef __restrict_arr # define _Restrict_arr_ __restrict_arr -# elif ((199901L <= __STDC_VERSION__ || 3 < __GNUC__ + (1 <= __GNUC_MINOR__)) \ - && !defined __GNUG__) +# elif ((199901L <= __STDC_VERSION__ \ + || 3 < __GNUC__ + (1 <= __GNUC_MINOR__) \ + || __clang_major__ >= 3) \ + && !defined __cplusplus) # define _Restrict_arr_ _Restrict_ # else # define _Restrict_arr_ diff --git a/posix/regex_internal.c b/posix/regex_internal.c index e1b6b4d5af..ed0a13461b 100644 --- a/posix/regex_internal.c +++ b/posix/regex_internal.c @@ -300,18 +300,20 @@ build_wcs_upper_buffer (re_string_t *pstr) while (byte_idx < end_idx) { wchar_t wc; + unsigned char ch = pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]; - if (isascii (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]) - && mbsinit (&pstr->cur_state)) + if (isascii (ch) && mbsinit (&pstr->cur_state)) { - /* In case of a singlebyte character. */ - pstr->mbs[byte_idx] - = toupper (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]); /* The next step uses the assumption that wchar_t is encoded ASCII-safe: all ASCII values can be converted like this. */ - pstr->wcs[byte_idx] = (wchar_t) pstr->mbs[byte_idx]; - ++byte_idx; - continue; + wchar_t wcu = __towupper (ch); + if (isascii (wcu)) + { + pstr->mbs[byte_idx] = wcu; + pstr->wcs[byte_idx] = wcu; + byte_idx++; + continue; + } } remain_len = end_idx - byte_idx; @@ -348,7 +350,6 @@ build_wcs_upper_buffer (re_string_t *pstr) { /* It is an invalid character, an incomplete character at the end of the string, or '\0'. Just use the byte. */ - int ch = pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]; pstr->mbs[byte_idx] = ch; /* And also cast it to wide char. */ pstr->wcs[byte_idx++] = (wchar_t) ch; diff --git a/posix/regex_internal.h b/posix/regex_internal.h index 8c42586c42..4a3cf779bf 100644 --- a/posix/regex_internal.h +++ b/posix/regex_internal.h @@ -77,6 +77,14 @@ # define isblank(ch) ((ch) == ' ' || (ch) == '\t') #endif +/* regex code assumes isascii has its usual numeric meaning, + even if the portable character set uses EBCDIC encoding, + and even if wint_t is wider than int. */ +#ifndef _LIBC +# undef isascii +# define isascii(c) (((c) & ~0x7f) == 0) +#endif + #ifdef _LIBC # ifndef _RE_DEFINE_LOCALE_FUNCTIONS # define _RE_DEFINE_LOCALE_FUNCTIONS 1 @@ -335,7 +343,7 @@ typedef struct Idx idx; /* for BACK_REF */ re_context_type ctx_type; /* for ANCHOR */ } opr; -#if __GNUC__ >= 2 && !defined __STRICT_ANSI__ +#if (__GNUC__ >= 2 || defined __clang__) && !defined __STRICT_ANSI__ re_token_type_t type : 8; #else re_token_type_t type; @@ -841,10 +849,10 @@ re_string_elem_size_at (const re_string_t *pstr, Idx idx) #endif /* RE_ENABLE_I18N */ #ifndef FALLTHROUGH -# if __GNUC__ < 7 -# define FALLTHROUGH ((void) 0) -# else +# if (__GNUC__ >= 7) || (__clang_major__ >= 10) # define FALLTHROUGH __attribute__ ((__fallthrough__)) +# else +# define FALLTHROUGH ((void) 0) # endif #endif From patchwork Wed Dec 30 20:15:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 41605 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 8EAC0388C031; Wed, 30 Dec 2020 20:15:22 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8EAC0388C031 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1609359322; bh=v/Y9eW8pNHEYQlbm/tUgVvO4QO1LHcrZFpPLsPXxgm8=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=eUr94yIcOr4p3M7VbXcV2W6L7/Q2WhSXjMmyAFfQd6yXL9m8bznvrZy20zLvIhx0r n2ryKenz57U8fi2Lj4ZFpGIVcZ9P/9jnctiXAHM644jRCI/74+AIn2oqfTiOgdNmFb dWLuKjS/b3Ni7iQV8nbPl2/6hK8HohkZyn0mo68k= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qt1-x82e.google.com (mail-qt1-x82e.google.com [IPv6:2607:f8b0:4864:20::82e]) by sourceware.org (Postfix) with ESMTPS id 44C66386103C for ; Wed, 30 Dec 2020 20:15:16 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 44C66386103C Received: by mail-qt1-x82e.google.com with SMTP id b9so11696646qtr.2 for ; Wed, 30 Dec 2020 12:15:16 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=v/Y9eW8pNHEYQlbm/tUgVvO4QO1LHcrZFpPLsPXxgm8=; b=qTGe+7qk14Dqke0D+fQE5J+ZyoWbJJnd6fLHcudzBCaOijC9fKPMuQFiN3Atdw/zYr nOFFQsfugi7GeYMrXkgudg9igiDdJg4ULna5wdKJFXJBNfFYP25BGctcGRz3x6MFqEev ZdmjCXsOVlQapE4SuxLbQeuRnqr7rfvn+Wln98cxO36cMq7nugOO13q6UcAfbceaXjRt vxsFmZtwUIAFXEcsA2Cy5lBKp0ZPfPjPOvOXYzNK5MvxWQAQyUi8Lyf59fyzmT4+XwOI rXHa+hIQCHwp//C9/8juwdvdkMWTeRwIptaIMIGlg/o8u6l6jnhqg4E/tDjKqw4lvbMU AAkg== X-Gm-Message-State: AOAM533aN1HhaSnhTYG0oAQk1KKWK1EluhgXE7FMPKFKBLajXIvwPhd+ XLdby30lV86/zcnbv3NO6v1sa894E4PLcg== X-Google-Smtp-Source: ABdhPJxNfbH0T8eRX1JUe3eIjjnPaBBuLLlHi82654EKs0k5yizJExTCK2eBal4X0T9QlpO/kdH4YA== X-Received: by 2002:ac8:57c4:: with SMTP id w4mr54218512qta.163.1609359314159; Wed, 30 Dec 2020 12:15:14 -0800 (PST) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id v145sm5949057qka.27.2020.12.30.12.15.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Dec 2020 12:15:13 -0800 (PST) To: libc-alpha@sourceware.org, Paul Eggert Subject: [PATCH 2/5] posix: Sync glob code with gnulib Date: Wed, 30 Dec 2020 17:15:04 -0300 Message-Id: <20201230201507.2755086-2-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201230201507.2755086-1-adhemerval.zanella@linaro.org> References: <20201230201507.2755086-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-13.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Reply-To: Adhemerval Zanella Cc: bug-gnulib@gnu.org Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" It sync with gnulib commit 43ee1a6bf and fixes and use-after-free bug (gnulib commit 717766da8926e36). The main change over gnulib is: --- posix/glob.c +++ lib/glob.c @@ -59,6 +59,12 @@ # define readdir(str) __readdir64 (str) # define getpwnam_r(name, bufp, buf, len, res) \ __getpwnam_r (name, bufp, buf, len, res) +# ifndef __lstat64 +# define __lstat64(fname, buf) __lxstat64 (_STAT_VER, fname, buf) +# endif +# ifndef __stat64 +# define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf) +# endif # define struct_stat64 struct stat64 # define FLEXIBLE_ARRAY_MEMBER # include Which is required since xstat symbols are not used internally anymore. Checked on x86_64-linux-gnu. --- posix/glob.c | 1748 ++++++++++++++++++++-------------------- posix/glob_pattern_p.c | 2 +- posix/globfree.c | 2 +- 3 files changed, 886 insertions(+), 866 deletions(-) diff --git a/posix/glob.c b/posix/glob.c index b4b34945e2..20239f780f 100644 --- a/posix/glob.c +++ b/posix/glob.c @@ -15,6 +15,16 @@ License along with the GNU C Library; if not, see . */ +#ifndef _LIBC + +/* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc + optimizes away the pattern == NULL test below. */ +# define _GL_ARG_NONNULL(params) + +# include + +#endif + #include #include @@ -26,7 +36,7 @@ #include #include -#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +#if defined _WIN32 && ! defined __CYGWIN__ # define WINDOWS32 #endif @@ -49,14 +59,19 @@ # define readdir(str) __readdir64 (str) # define getpwnam_r(name, bufp, buf, len, res) \ __getpwnam_r (name, bufp, buf, len, res) -# define struct_stat64 struct stat64 +# define struct_stat64 struct stat64 # define FLEXIBLE_ARRAY_MEMBER # include #else /* !_LIBC */ # define __glob glob # define __getlogin_r(buf, len) getlogin_r (buf, len) # define __lstat64(fname, buf) lstat (fname, buf) +# if defined _WIN32 && !defined __CYGWIN__ + /* Avoid GCC or clang warning. The original __stat64 macro is unused. */ +# undef __stat64 +# endif # define __stat64(fname, buf) stat (fname, buf) +# define __fxstatat64(_, d, f, st, flag) fstatat (d, f, st, flag) # define struct_stat64 struct stat # ifndef __MVS__ # define __alloca alloca @@ -73,7 +88,9 @@ static const char *next_brace_sub (const char *begin, int flags) __THROWNL; -typedef uint_fast8_t dirent_type; +/* The type of ((struct dirent *) 0)->d_type is 'unsigned char' on most + platforms, but 'unsigned int' in the mingw from mingw.org. */ +typedef uint_fast32_t dirent_type; #if !defined _LIBC && !defined HAVE_STRUCT_DIRENT_D_TYPE /* Any distinct values will do here. @@ -112,9 +129,9 @@ readdir_result_type (struct readdir_result d) /* Construct an initializer for a struct readdir_result object from a struct dirent *. No copy of the name is made. */ #define READDIR_RESULT_INITIALIZER(source) \ - { \ - source->d_name, \ - D_TYPE_TO_RESULT (source) \ + { \ + source->d_name, \ + D_TYPE_TO_RESULT (source) \ } /* Call gl_readdir on STREAM. This macro can be overridden to reduce @@ -204,7 +221,7 @@ glob_lstat (glob_t *pglob, int flags, const char *fullname) static bool size_add_wrapv (size_t a, size_t b, size_t *r) { -#if 5 <= __GNUC__ && !defined __ICC +#if 7 <= __GNUC__ && !defined __ICC return __builtin_add_overflow (a, b, r); #else *r = a + b; @@ -221,8 +238,8 @@ glob_use_alloca (size_t alloca_used, size_t len) } static int glob_in_dir (const char *pattern, const char *directory, - int flags, int (*errfunc) (const char *, int), - glob_t *pglob, size_t alloca_used); + int flags, int (*errfunc) (const char *, int), + glob_t *pglob, size_t alloca_used); static int prefix_array (const char *prefix, char **array, size_t n) __THROWNL; static int collated_compare (const void *, const void *) __THROWNL; @@ -247,17 +264,17 @@ next_brace_sub (const char *cp, int flags) while (*cp != '\0') if ((flags & GLOB_NOESCAPE) == 0 && *cp == '\\') { - if (*++cp == '\0') - break; - ++cp; + if (*++cp == '\0') + break; + ++cp; } else { - if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0)) - break; + if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0)) + break; - if (*cp++ == '{') - depth++; + if (*cp++ == '{') + depth++; } return *cp != '\0' ? cp : NULL; @@ -278,7 +295,7 @@ next_brace_sub (const char *cp, int flags) int GLOB_ATTRIBUTE __glob (const char *pattern, int flags, int (*errfunc) (const char *, int), - glob_t *pglob) + glob_t *pglob) { const char *filename; char *dirname = NULL; @@ -312,22 +329,22 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int), { pglob->gl_pathc = 0; if (!(flags & GLOB_DOOFFS)) - pglob->gl_pathv = NULL; + pglob->gl_pathv = NULL; else - { - size_t i; + { + size_t i; - if (pglob->gl_offs >= ~((size_t) 0) / sizeof (char *)) - return GLOB_NOSPACE; + if (pglob->gl_offs >= ~((size_t) 0) / sizeof (char *)) + return GLOB_NOSPACE; - pglob->gl_pathv = (char **) malloc ((pglob->gl_offs + 1) - * sizeof (char *)); - if (pglob->gl_pathv == NULL) - return GLOB_NOSPACE; + pglob->gl_pathv = (char **) malloc ((pglob->gl_offs + 1) + * sizeof (char *)); + if (pglob->gl_pathv == NULL) + return GLOB_NOSPACE; - for (i = 0; i <= pglob->gl_offs; ++i) - pglob->gl_pathv[i] = NULL; - } + for (i = 0; i <= pglob->gl_offs; ++i) + pglob->gl_pathv[i] = NULL; + } } if (flags & GLOB_BRACE) @@ -335,129 +352,129 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int), const char *begin; if (flags & GLOB_NOESCAPE) - begin = strchr (pattern, '{'); + begin = strchr (pattern, '{'); else - { - begin = pattern; - while (1) - { - if (*begin == '\0') - { - begin = NULL; - break; - } - - if (*begin == '\\' && begin[1] != '\0') - ++begin; - else if (*begin == '{') - break; - - ++begin; - } - } + { + begin = pattern; + while (1) + { + if (*begin == '\0') + { + begin = NULL; + break; + } + + if (*begin == '\\' && begin[1] != '\0') + ++begin; + else if (*begin == '{') + break; + + ++begin; + } + } if (begin != NULL) - { - /* Allocate working buffer large enough for our work. Note that - we have at least an opening and closing brace. */ - size_t firstc; - char *alt_start; - const char *p; - const char *next; - const char *rest; - size_t rest_len; - char *onealt; - size_t pattern_len = strlen (pattern) - 1; - int alloca_onealt = glob_use_alloca (alloca_used, pattern_len); - if (alloca_onealt) - onealt = alloca_account (pattern_len, alloca_used); - else - { - onealt = malloc (pattern_len); - if (onealt == NULL) - return GLOB_NOSPACE; - } - - /* We know the prefix for all sub-patterns. */ - alt_start = mempcpy (onealt, pattern, begin - pattern); - - /* Find the first sub-pattern and at the same time find the - rest after the closing brace. */ - next = next_brace_sub (begin + 1, flags); - if (next == NULL) - { - /* It is an invalid expression. */ - illegal_brace: - if (__glibc_unlikely (!alloca_onealt)) - free (onealt); - flags &= ~GLOB_BRACE; - goto no_brace; - } - - /* Now find the end of the whole brace expression. */ - rest = next; - while (*rest != '}') - { - rest = next_brace_sub (rest + 1, flags); - if (rest == NULL) - /* It is an illegal expression. */ - goto illegal_brace; - } - /* Please note that we now can be sure the brace expression - is well-formed. */ - rest_len = strlen (++rest) + 1; - - /* We have a brace expression. BEGIN points to the opening {, - NEXT points past the terminator of the first element, and END - points past the final }. We will accumulate result names from - recursive runs for each brace alternative in the buffer using - GLOB_APPEND. */ - firstc = pglob->gl_pathc; - - p = begin + 1; - while (1) - { - int result; - - /* Construct the new glob expression. */ - mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len); - - result = __glob (onealt, - ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC)) - | GLOB_APPEND), - errfunc, pglob); - - /* If we got an error, return it. */ - if (result && result != GLOB_NOMATCH) - { - if (__glibc_unlikely (!alloca_onealt)) - free (onealt); - if (!(flags & GLOB_APPEND)) - { - globfree (pglob); - pglob->gl_pathc = 0; - } - return result; - } - - if (*next == '}') - /* We saw the last entry. */ - break; - - p = next + 1; - next = next_brace_sub (p, flags); - assert (next != NULL); - } - - if (__glibc_unlikely (!alloca_onealt)) - free (onealt); - - if (pglob->gl_pathc != firstc) - /* We found some entries. */ - return 0; - else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) - return GLOB_NOMATCH; - } + { + /* Allocate working buffer large enough for our work. Note that + we have at least an opening and closing brace. */ + size_t firstc; + char *alt_start; + const char *p; + const char *next; + const char *rest; + size_t rest_len; + char *onealt; + size_t pattern_len = strlen (pattern) - 1; + int alloca_onealt = glob_use_alloca (alloca_used, pattern_len); + if (alloca_onealt) + onealt = alloca_account (pattern_len, alloca_used); + else + { + onealt = malloc (pattern_len); + if (onealt == NULL) + return GLOB_NOSPACE; + } + + /* We know the prefix for all sub-patterns. */ + alt_start = mempcpy (onealt, pattern, begin - pattern); + + /* Find the first sub-pattern and at the same time find the + rest after the closing brace. */ + next = next_brace_sub (begin + 1, flags); + if (next == NULL) + { + /* It is an invalid expression. */ + illegal_brace: + if (__glibc_unlikely (!alloca_onealt)) + free (onealt); + flags &= ~GLOB_BRACE; + goto no_brace; + } + + /* Now find the end of the whole brace expression. */ + rest = next; + while (*rest != '}') + { + rest = next_brace_sub (rest + 1, flags); + if (rest == NULL) + /* It is an illegal expression. */ + goto illegal_brace; + } + /* Please note that we now can be sure the brace expression + is well-formed. */ + rest_len = strlen (++rest) + 1; + + /* We have a brace expression. BEGIN points to the opening {, + NEXT points past the terminator of the first element, and END + points past the final }. We will accumulate result names from + recursive runs for each brace alternative in the buffer using + GLOB_APPEND. */ + firstc = pglob->gl_pathc; + + p = begin + 1; + while (1) + { + int result; + + /* Construct the new glob expression. */ + mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len); + + result = __glob (onealt, + ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC)) + | GLOB_APPEND), + errfunc, pglob); + + /* If we got an error, return it. */ + if (result && result != GLOB_NOMATCH) + { + if (__glibc_unlikely (!alloca_onealt)) + free (onealt); + if (!(flags & GLOB_APPEND)) + { + globfree (pglob); + pglob->gl_pathc = 0; + } + return result; + } + + if (*next == '}') + /* We saw the last entry. */ + break; + + p = next + 1; + next = next_brace_sub (p, flags); + assert (next != NULL); + } + + if (__glibc_unlikely (!alloca_onealt)) + free (onealt); + + if (pglob->gl_pathc != firstc) + /* We found some entries. */ + return 0; + else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) + return GLOB_NOMATCH; + } } no_brace: @@ -479,33 +496,33 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int), if (filename == NULL) { /* This can mean two things: a simple name or "~name". The latter - case is nothing but a notation for a directory. */ + case is nothing but a notation for a directory. */ if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~') - { - dirname = (char *) pattern; - dirlen = strlen (pattern); - - /* Set FILENAME to NULL as a special flag. This is ugly but - other solutions would require much more code. We test for - this special case below. */ - filename = NULL; - } + { + dirname = (char *) pattern; + dirlen = strlen (pattern); + + /* Set FILENAME to NULL as a special flag. This is ugly but + other solutions would require much more code. We test for + this special case below. */ + filename = NULL; + } else - { - if (__glibc_unlikely (pattern[0] == '\0')) - { - dirs.gl_pathv = NULL; - goto no_matches; - } - - filename = pattern; - dirname = (char *) "."; - dirlen = 0; - } + { + if (__glibc_unlikely (pattern[0] == '\0')) + { + dirs.gl_pathv = NULL; + goto no_matches; + } + + filename = pattern; + dirname = (char *) "."; + dirlen = 0; + } } else if (filename == pattern - || (filename == pattern + 1 && pattern[0] == '\\' - && (flags & GLOB_NOESCAPE) == 0)) + || (filename == pattern + 1 && pattern[0] == '\\' + && (flags & GLOB_NOESCAPE) == 0)) { /* "/pattern" or "\\/pattern". */ dirname = (char *) "/"; @@ -518,32 +535,32 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int), dirlen = filename - pattern; #if defined __MSDOS__ || defined WINDOWS32 if (*filename == ':' - || (filename > pattern + 1 && filename[-1] == ':')) - { - char *drive_spec; - - ++dirlen; - drive_spec = __alloca (dirlen + 1); - *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0'; - /* For now, disallow wildcards in the drive spec, to - prevent infinite recursion in glob. */ - if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE))) - return GLOB_NOMATCH; - /* If this is "d:pattern", we need to copy ':' to DIRNAME - as well. If it's "d:/pattern", don't remove the slash - from "d:/", since "d:" and "d:/" are not the same.*/ - } + || (filename > pattern + 1 && filename[-1] == ':')) + { + char *drive_spec; + + ++dirlen; + drive_spec = __alloca (dirlen + 1); + *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0'; + /* For now, disallow wildcards in the drive spec, to + prevent infinite recursion in glob. */ + if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE))) + return GLOB_NOMATCH; + /* If this is "d:pattern", we need to copy ':' to DIRNAME + as well. If it's "d:/pattern", don't remove the slash + from "d:/", since "d:" and "d:/" are not the same.*/ + } #endif if (glob_use_alloca (alloca_used, dirlen + 1)) - newp = alloca_account (dirlen + 1, alloca_used); + newp = alloca_account (dirlen + 1, alloca_used); else - { - newp = malloc (dirlen + 1); - if (newp == NULL) - return GLOB_NOSPACE; - malloc_dirname = 1; - } + { + newp = malloc (dirlen + 1); + if (newp == NULL) + return GLOB_NOSPACE; + malloc_dirname = 1; + } *((char *) mempcpy (newp, pattern, dirlen)) = '\0'; dirname = newp; ++filename; @@ -559,363 +576,366 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int), if (filename[0] == '\0' && dirlen > 1 && !drive_root) /* "pattern/". Expand "pattern", appending slashes. */ - { - int orig_flags = flags; - if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\') - { - /* "pattern\\/". Remove the final backslash if it hasn't - been quoted. */ - char *p = (char *) &dirname[dirlen - 1]; - - while (p > dirname && p[-1] == '\\') --p; - if ((&dirname[dirlen] - p) & 1) - { - *(char *) &dirname[--dirlen] = '\0'; - flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC); - } - } - int val = __glob (dirname, flags | GLOB_MARK, errfunc, pglob); - if (val == 0) - pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK) - | (flags & GLOB_MARK)); - else if (val == GLOB_NOMATCH && flags != orig_flags) - { - /* Make sure globfree (&dirs); is a nop. */ - dirs.gl_pathv = NULL; - flags = orig_flags; - oldcount = pglob->gl_pathc + pglob->gl_offs; - goto no_matches; - } - retval = val; - goto out; - } + { + int orig_flags = flags; + if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\') + { + /* "pattern\\/". Remove the final backslash if it hasn't + been quoted. */ + char *p = (char *) &dirname[dirlen - 1]; + + while (p > dirname && p[-1] == '\\') --p; + if ((&dirname[dirlen] - p) & 1) + { + *(char *) &dirname[--dirlen] = '\0'; + flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC); + } + } + int val = __glob (dirname, flags | GLOB_MARK, errfunc, pglob); + if (val == 0) + pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK) + | (flags & GLOB_MARK)); + else if (val == GLOB_NOMATCH && flags != orig_flags) + { + /* Make sure globfree (&dirs); is a nop. */ + dirs.gl_pathv = NULL; + flags = orig_flags; + oldcount = pglob->gl_pathc + pglob->gl_offs; + goto no_matches; + } + retval = val; + goto out; + } } if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~') { if (dirname[1] == '\0' || dirname[1] == '/' - || (!(flags & GLOB_NOESCAPE) && dirname[1] == '\\' - && (dirname[2] == '\0' || dirname[2] == '/'))) - { - /* Look up home directory. */ - char *home_dir = getenv ("HOME"); - int malloc_home_dir = 0; - if (home_dir == NULL || home_dir[0] == '\0') - { + || (!(flags & GLOB_NOESCAPE) && dirname[1] == '\\' + && (dirname[2] == '\0' || dirname[2] == '/'))) + { + /* Look up home directory. */ + char *home_dir = getenv ("HOME"); + int malloc_home_dir = 0; + if (home_dir == NULL || home_dir[0] == '\0') + { #ifdef WINDOWS32 - /* Windows NT defines HOMEDRIVE and HOMEPATH. But give - preference to HOME, because the user can change HOME. */ - const char *home_drive = getenv ("HOMEDRIVE"); - const char *home_path = getenv ("HOMEPATH"); - - if (home_drive != NULL && home_path != NULL) - { - size_t home_drive_len = strlen (home_drive); - size_t home_path_len = strlen (home_path); - char *mem = alloca (home_drive_len + home_path_len + 1); - - memcpy (mem, home_drive, home_drive_len); - memcpy (mem + home_drive_len, home_path, home_path_len + 1); - home_dir = mem; - } - else - home_dir = "c:/users/default"; /* poor default */ + /* Windows NT defines HOMEDRIVE and HOMEPATH. But give + preference to HOME, because the user can change HOME. */ + const char *home_drive = getenv ("HOMEDRIVE"); + const char *home_path = getenv ("HOMEPATH"); + + if (home_drive != NULL && home_path != NULL) + { + size_t home_drive_len = strlen (home_drive); + size_t home_path_len = strlen (home_path); + char *mem = alloca (home_drive_len + home_path_len + 1); + + memcpy (mem, home_drive, home_drive_len); + memcpy (mem + home_drive_len, home_path, home_path_len + 1); + home_dir = mem; + } + else + home_dir = "c:/users/default"; /* poor default */ #else - int err; - struct passwd *p; - struct passwd pwbuf; - struct scratch_buffer s; - scratch_buffer_init (&s); - while (true) - { - p = NULL; - err = __getlogin_r (s.data, s.length); - if (err == 0) - { + int err; + struct passwd *p; + struct passwd pwbuf; + struct scratch_buffer s; + scratch_buffer_init (&s); + while (true) + { + p = NULL; + err = __getlogin_r (s.data, s.length); + if (err == 0) + { # if defined HAVE_GETPWNAM_R || defined _LIBC - size_t ssize = strlen (s.data) + 1; - char *sdata = s.data; - err = getpwnam_r (sdata, &pwbuf, sdata + ssize, - s.length - ssize, &p); + size_t ssize = strlen (s.data) + 1; + char *sdata = s.data; + err = getpwnam_r (sdata, &pwbuf, sdata + ssize, + s.length - ssize, &p); # else - p = getpwnam (s.data); - if (p == NULL) - err = errno; + p = getpwnam (s.data); + if (p == NULL) + err = errno; # endif - } - if (err != ERANGE) - break; - if (!scratch_buffer_grow (&s)) - { - retval = GLOB_NOSPACE; - goto out; - } - } - if (err == 0) - { - home_dir = strdup (p->pw_dir); - malloc_home_dir = 1; - } - scratch_buffer_free (&s); - if (err == 0 && home_dir == NULL) - { - retval = GLOB_NOSPACE; - goto out; - } + } + if (err != ERANGE) + break; + if (!scratch_buffer_grow (&s)) + { + retval = GLOB_NOSPACE; + goto out; + } + } + if (err == 0) + { + home_dir = strdup (p->pw_dir); + malloc_home_dir = 1; + } + scratch_buffer_free (&s); + if (err == 0 && home_dir == NULL) + { + retval = GLOB_NOSPACE; + goto out; + } #endif /* WINDOWS32 */ - } - if (home_dir == NULL || home_dir[0] == '\0') - { - if (__glibc_unlikely (malloc_home_dir)) - free (home_dir); - if (flags & GLOB_TILDE_CHECK) - { - retval = GLOB_NOMATCH; - goto out; - } - else - { - home_dir = (char *) "~"; /* No luck. */ - malloc_home_dir = 0; - } - } - /* Now construct the full directory. */ - if (dirname[1] == '\0') - { - if (__glibc_unlikely (malloc_dirname)) - free (dirname); - - dirname = home_dir; - dirlen = strlen (dirname); - malloc_dirname = malloc_home_dir; - } - else - { - char *newp; - size_t home_len = strlen (home_dir); - int use_alloca = glob_use_alloca (alloca_used, home_len + dirlen); - if (use_alloca) - newp = alloca_account (home_len + dirlen, alloca_used); - else - { - newp = malloc (home_len + dirlen); - if (newp == NULL) - { - if (__glibc_unlikely (malloc_home_dir)) - free (home_dir); - retval = GLOB_NOSPACE; - goto out; - } - } - - mempcpy (mempcpy (newp, home_dir, home_len), - &dirname[1], dirlen); - - if (__glibc_unlikely (malloc_dirname)) - free (dirname); - - dirname = newp; - dirlen += home_len - 1; - malloc_dirname = !use_alloca; - - if (__glibc_unlikely (malloc_home_dir)) - free (home_dir); - } - dirname_modified = 1; - } + } + if (home_dir == NULL || home_dir[0] == '\0') + { + if (__glibc_unlikely (malloc_home_dir)) + free (home_dir); + if (flags & GLOB_TILDE_CHECK) + { + retval = GLOB_NOMATCH; + goto out; + } + else + { + home_dir = (char *) "~"; /* No luck. */ + malloc_home_dir = 0; + } + } + /* Now construct the full directory. */ + if (dirname[1] == '\0') + { + if (__glibc_unlikely (malloc_dirname)) + free (dirname); + + dirname = home_dir; + dirlen = strlen (dirname); + malloc_dirname = malloc_home_dir; + } + else + { + char *newp; + size_t home_len = strlen (home_dir); + int use_alloca = glob_use_alloca (alloca_used, home_len + dirlen); + if (use_alloca) + newp = alloca_account (home_len + dirlen, alloca_used); + else + { + newp = malloc (home_len + dirlen); + if (newp == NULL) + { + if (__glibc_unlikely (malloc_home_dir)) + free (home_dir); + retval = GLOB_NOSPACE; + goto out; + } + } + + mempcpy (mempcpy (newp, home_dir, home_len), + &dirname[1], dirlen); + + if (__glibc_unlikely (malloc_dirname)) + free (dirname); + + dirname = newp; + dirlen += home_len - 1; + malloc_dirname = !use_alloca; + + if (__glibc_unlikely (malloc_home_dir)) + free (home_dir); + } + dirname_modified = 1; + } else - { + { #ifndef WINDOWS32 - char *end_name = strchr (dirname, '/'); - char *user_name; - int malloc_user_name = 0; - char *unescape = NULL; - - if (!(flags & GLOB_NOESCAPE)) - { - if (end_name == NULL) - { - unescape = strchr (dirname, '\\'); - if (unescape) - end_name = strchr (unescape, '\0'); - } - else - unescape = memchr (dirname, '\\', end_name - dirname); - } - if (end_name == NULL) - user_name = dirname + 1; - else - { - char *newp; - if (glob_use_alloca (alloca_used, end_name - dirname)) - newp = alloca_account (end_name - dirname, alloca_used); - else - { - newp = malloc (end_name - dirname); - if (newp == NULL) - { - retval = GLOB_NOSPACE; - goto out; - } - malloc_user_name = 1; - } - if (unescape != NULL) - { - char *p = mempcpy (newp, dirname + 1, - unescape - dirname - 1); - char *q = unescape; - while (q != end_name) - { - if (*q == '\\') - { - if (q + 1 == end_name) - { - /* "~fo\\o\\" unescape to user_name "foo\\", - but "~fo\\o\\/" unescape to user_name - "foo". */ - if (filename == NULL) - *p++ = '\\'; - break; - } - ++q; - } - *p++ = *q++; - } - *p = '\0'; - } - else - *((char *) mempcpy (newp, dirname + 1, end_name - dirname - 1)) - = '\0'; - user_name = newp; - } - - /* Look up specific user's home directory. */ - { - struct passwd *p; - struct scratch_buffer pwtmpbuf; - scratch_buffer_init (&pwtmpbuf); + char *end_name = strchr (dirname, '/'); + char *user_name; + int malloc_user_name = 0; + char *unescape = NULL; + + if (!(flags & GLOB_NOESCAPE)) + { + if (end_name == NULL) + { + unescape = strchr (dirname, '\\'); + if (unescape) + end_name = strchr (unescape, '\0'); + } + else + unescape = memchr (dirname, '\\', end_name - dirname); + } + if (end_name == NULL) + user_name = dirname + 1; + else + { + char *newp; + if (glob_use_alloca (alloca_used, end_name - dirname)) + newp = alloca_account (end_name - dirname, alloca_used); + else + { + newp = malloc (end_name - dirname); + if (newp == NULL) + { + retval = GLOB_NOSPACE; + goto out; + } + malloc_user_name = 1; + } + if (unescape != NULL) + { + char *p = mempcpy (newp, dirname + 1, + unescape - dirname - 1); + char *q = unescape; + while (q != end_name) + { + if (*q == '\\') + { + if (q + 1 == end_name) + { + /* "~fo\\o\\" unescape to user_name "foo\\", + but "~fo\\o\\/" unescape to user_name + "foo". */ + if (filename == NULL) + *p++ = '\\'; + break; + } + ++q; + } + *p++ = *q++; + } + *p = '\0'; + } + else + *((char *) mempcpy (newp, dirname + 1, end_name - dirname - 1)) + = '\0'; + user_name = newp; + } + + /* Look up specific user's home directory. */ + { + struct passwd *p; + struct scratch_buffer pwtmpbuf; + scratch_buffer_init (&pwtmpbuf); # if defined HAVE_GETPWNAM_R || defined _LIBC - struct passwd pwbuf; - - while (getpwnam_r (user_name, &pwbuf, - pwtmpbuf.data, pwtmpbuf.length, &p) - == ERANGE) - { - if (!scratch_buffer_grow (&pwtmpbuf)) - { - retval = GLOB_NOSPACE; - goto out; - } - } + struct passwd pwbuf; + + while (getpwnam_r (user_name, &pwbuf, + pwtmpbuf.data, pwtmpbuf.length, &p) + == ERANGE) + { + if (!scratch_buffer_grow (&pwtmpbuf)) + { + retval = GLOB_NOSPACE; + goto out; + } + } # else - p = getpwnam (user_name); + p = getpwnam (user_name); # endif - if (__glibc_unlikely (malloc_user_name)) - free (user_name); - - /* If we found a home directory use this. */ - if (p != NULL) - { - size_t home_len = strlen (p->pw_dir); - size_t rest_len = end_name == NULL ? 0 : strlen (end_name); - char *d, *newp; - bool use_alloca = glob_use_alloca (alloca_used, - home_len + rest_len + 1); - - if (use_alloca) - newp = alloca_account (home_len + rest_len + 1, alloca_used); - else - { - newp = malloc (home_len + rest_len + 1); - if (newp == NULL) - { - scratch_buffer_free (&pwtmpbuf); - retval = GLOB_NOSPACE; - goto out; - } - } - d = mempcpy (newp, p->pw_dir, home_len); - if (end_name != NULL) - d = mempcpy (d, end_name, rest_len); - *d = '\0'; - - if (__glibc_unlikely (malloc_dirname)) - free (dirname); - dirname = newp; - malloc_dirname = !use_alloca; - - dirlen = home_len + rest_len; - dirname_modified = 1; - } - else - { - if (flags & GLOB_TILDE_CHECK) - { - /* We have to regard it as an error if we cannot find the - home directory. */ - retval = GLOB_NOMATCH; - goto out; - } - } - scratch_buffer_free (&pwtmpbuf); - } + if (__glibc_unlikely (malloc_user_name)) + free (user_name); + + /* If we found a home directory use this. */ + if (p != NULL) + { + size_t home_len = strlen (p->pw_dir); + size_t rest_len = end_name == NULL ? 0 : strlen (end_name); + /* dirname contains end_name; we can't free it now. */ + char *prev_dirname = + (__glibc_unlikely (malloc_dirname) ? dirname : NULL); + char *d; + + malloc_dirname = 0; + + if (glob_use_alloca (alloca_used, home_len + rest_len + 1)) + dirname = alloca_account (home_len + rest_len + 1, + alloca_used); + else + { + dirname = malloc (home_len + rest_len + 1); + if (dirname == NULL) + { + free (prev_dirname); + scratch_buffer_free (&pwtmpbuf); + retval = GLOB_NOSPACE; + goto out; + } + malloc_dirname = 1; + } + d = mempcpy (dirname, p->pw_dir, home_len); + if (end_name != NULL) + d = mempcpy (d, end_name, rest_len); + *d = '\0'; + + free (prev_dirname); + + dirlen = home_len + rest_len; + dirname_modified = 1; + } + else + { + if (flags & GLOB_TILDE_CHECK) + { + /* We have to regard it as an error if we cannot find the + home directory. */ + retval = GLOB_NOMATCH; + goto out; + } + } + scratch_buffer_free (&pwtmpbuf); + } #endif /* !WINDOWS32 */ - } + } } /* Now test whether we looked for "~" or "~NAME". In this case we can give the answer now. */ if (filename == NULL) { - size_t newcount = pglob->gl_pathc + pglob->gl_offs; - char **new_gl_pathv; - - if (newcount > SIZE_MAX / sizeof (char *) - 2) - { - nospace: - free (pglob->gl_pathv); - pglob->gl_pathv = NULL; - pglob->gl_pathc = 0; - retval = GLOB_NOSPACE; - goto out; - } - - new_gl_pathv = realloc (pglob->gl_pathv, - (newcount + 2) * sizeof (char *)); - if (new_gl_pathv == NULL) - goto nospace; - pglob->gl_pathv = new_gl_pathv; - - if (flags & GLOB_MARK && is_dir (dirname, flags, pglob)) - { - char *p; - pglob->gl_pathv[newcount] = malloc (dirlen + 2); - if (pglob->gl_pathv[newcount] == NULL) - goto nospace; - p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen); - p[0] = '/'; - p[1] = '\0'; - if (__glibc_unlikely (malloc_dirname)) - free (dirname); - } - else - { - if (__glibc_unlikely (malloc_dirname)) - pglob->gl_pathv[newcount] = dirname; - else - { - pglob->gl_pathv[newcount] = strdup (dirname); - if (pglob->gl_pathv[newcount] == NULL) - goto nospace; - } - } - pglob->gl_pathv[++newcount] = NULL; - ++pglob->gl_pathc; - pglob->gl_flags = flags; - - return 0; + size_t newcount = pglob->gl_pathc + pglob->gl_offs; + char **new_gl_pathv; + + if (newcount > SIZE_MAX / sizeof (char *) - 2) + { + nospace: + free (pglob->gl_pathv); + pglob->gl_pathv = NULL; + pglob->gl_pathc = 0; + retval = GLOB_NOSPACE; + goto out; + } + + new_gl_pathv = realloc (pglob->gl_pathv, + (newcount + 2) * sizeof (char *)); + if (new_gl_pathv == NULL) + goto nospace; + pglob->gl_pathv = new_gl_pathv; + + if (flags & GLOB_MARK && is_dir (dirname, flags, pglob)) + { + char *p; + pglob->gl_pathv[newcount] = malloc (dirlen + 2); + if (pglob->gl_pathv[newcount] == NULL) + goto nospace; + p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen); + p[0] = '/'; + p[1] = '\0'; + if (__glibc_unlikely (malloc_dirname)) + free (dirname); + } + else + { + if (__glibc_unlikely (malloc_dirname)) + pglob->gl_pathv[newcount] = dirname; + else + { + pglob->gl_pathv[newcount] = strdup (dirname); + if (pglob->gl_pathv[newcount] == NULL) + goto nospace; + } + } + pglob->gl_pathv[++newcount] = NULL; + ++pglob->gl_pathc; + pglob->gl_flags = flags; + + return 0; } meta = __glob_pattern_type (dirname, !(flags & GLOB_NOESCAPE)); @@ -927,135 +947,135 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int), if (meta & (GLOBPAT_SPECIAL | GLOBPAT_BRACKET)) { /* The directory name contains metacharacters, so we - have to glob for the directory, and then glob for - the pattern in each directory found. */ + have to glob for the directory, and then glob for + the pattern in each directory found. */ size_t i; if (!(flags & GLOB_NOESCAPE) && dirlen > 0 && dirname[dirlen - 1] == '\\') - { - /* "foo\\/bar". Remove the final backslash from dirname - if it has not been quoted. */ - char *p = (char *) &dirname[dirlen - 1]; + { + /* "foo\\/bar". Remove the final backslash from dirname + if it has not been quoted. */ + char *p = (char *) &dirname[dirlen - 1]; - while (p > dirname && p[-1] == '\\') --p; - if ((&dirname[dirlen] - p) & 1) - *(char *) &dirname[--dirlen] = '\0'; - } + while (p > dirname && p[-1] == '\\') --p; + if ((&dirname[dirlen] - p) & 1) + *(char *) &dirname[--dirlen] = '\0'; + } if (__glibc_unlikely ((flags & GLOB_ALTDIRFUNC) != 0)) - { - /* Use the alternative access functions also in the recursive - call. */ - dirs.gl_opendir = pglob->gl_opendir; - dirs.gl_readdir = pglob->gl_readdir; - dirs.gl_closedir = pglob->gl_closedir; - dirs.gl_stat = pglob->gl_stat; - dirs.gl_lstat = pglob->gl_lstat; - } + { + /* Use the alternative access functions also in the recursive + call. */ + dirs.gl_opendir = pglob->gl_opendir; + dirs.gl_readdir = pglob->gl_readdir; + dirs.gl_closedir = pglob->gl_closedir; + dirs.gl_stat = pglob->gl_stat; + dirs.gl_lstat = pglob->gl_lstat; + } status = __glob (dirname, - ((flags & (GLOB_ERR | GLOB_NOESCAPE | GLOB_ALTDIRFUNC)) - | GLOB_NOSORT | GLOB_ONLYDIR), - errfunc, &dirs); + ((flags & (GLOB_ERR | GLOB_NOESCAPE | GLOB_ALTDIRFUNC)) + | GLOB_NOSORT | GLOB_ONLYDIR), + errfunc, &dirs); if (status != 0) - { - if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH) - { - retval = status; - goto out; - } - goto no_matches; - } + { + if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH) + { + retval = status; + goto out; + } + goto no_matches; + } /* We have successfully globbed the preceding directory name. - For each name we found, call glob_in_dir on it and FILENAME, - appending the results to PGLOB. */ + For each name we found, call glob_in_dir on it and FILENAME, + appending the results to PGLOB. */ for (i = 0; i < dirs.gl_pathc; ++i) - { - size_t old_pathc; - - old_pathc = pglob->gl_pathc; - status = glob_in_dir (filename, dirs.gl_pathv[i], - ((flags | GLOB_APPEND) - & ~(GLOB_NOCHECK | GLOB_NOMAGIC)), - errfunc, pglob, alloca_used); - if (status == GLOB_NOMATCH) - /* No matches in this directory. Try the next. */ - continue; - - if (status != 0) - { - globfree (&dirs); - globfree (pglob); - pglob->gl_pathc = 0; - retval = status; - goto out; - } - - /* Stick the directory on the front of each name. */ - if (prefix_array (dirs.gl_pathv[i], - &pglob->gl_pathv[old_pathc + pglob->gl_offs], - pglob->gl_pathc - old_pathc)) - { - globfree (&dirs); - globfree (pglob); - pglob->gl_pathc = 0; - retval = GLOB_NOSPACE; - goto out; - } - } + { + size_t old_pathc; + + old_pathc = pglob->gl_pathc; + status = glob_in_dir (filename, dirs.gl_pathv[i], + ((flags | GLOB_APPEND) + & ~(GLOB_NOCHECK | GLOB_NOMAGIC)), + errfunc, pglob, alloca_used); + if (status == GLOB_NOMATCH) + /* No matches in this directory. Try the next. */ + continue; + + if (status != 0) + { + globfree (&dirs); + globfree (pglob); + pglob->gl_pathc = 0; + retval = status; + goto out; + } + + /* Stick the directory on the front of each name. */ + if (prefix_array (dirs.gl_pathv[i], + &pglob->gl_pathv[old_pathc + pglob->gl_offs], + pglob->gl_pathc - old_pathc)) + { + globfree (&dirs); + globfree (pglob); + pglob->gl_pathc = 0; + retval = GLOB_NOSPACE; + goto out; + } + } flags |= GLOB_MAGCHAR; /* We have ignored the GLOB_NOCHECK flag in the 'glob_in_dir' calls. - But if we have not found any matching entry and the GLOB_NOCHECK - flag was set we must return the input pattern itself. */ + But if we have not found any matching entry and the GLOB_NOCHECK + flag was set we must return the input pattern itself. */ if (pglob->gl_pathc + pglob->gl_offs == oldcount) - { - no_matches: - /* No matches. */ - if (flags & GLOB_NOCHECK) - { - size_t newcount = pglob->gl_pathc + pglob->gl_offs; - char **new_gl_pathv; - - if (newcount > SIZE_MAX / sizeof (char *) - 2) - { - nospace2: - globfree (&dirs); - retval = GLOB_NOSPACE; - goto out; - } - - new_gl_pathv = realloc (pglob->gl_pathv, - (newcount + 2) * sizeof (char *)); - if (new_gl_pathv == NULL) - goto nospace2; - pglob->gl_pathv = new_gl_pathv; - - pglob->gl_pathv[newcount] = strdup (pattern); - if (pglob->gl_pathv[newcount] == NULL) - { - globfree (&dirs); - globfree (pglob); - pglob->gl_pathc = 0; - retval = GLOB_NOSPACE; - goto out; - } - - ++pglob->gl_pathc; - ++newcount; - - pglob->gl_pathv[newcount] = NULL; - pglob->gl_flags = flags; - } - else - { - globfree (&dirs); - retval = GLOB_NOMATCH; - goto out; - } - } + { + no_matches: + /* No matches. */ + if (flags & GLOB_NOCHECK) + { + size_t newcount = pglob->gl_pathc + pglob->gl_offs; + char **new_gl_pathv; + + if (newcount > SIZE_MAX / sizeof (char *) - 2) + { + nospace2: + globfree (&dirs); + retval = GLOB_NOSPACE; + goto out; + } + + new_gl_pathv = realloc (pglob->gl_pathv, + (newcount + 2) * sizeof (char *)); + if (new_gl_pathv == NULL) + goto nospace2; + pglob->gl_pathv = new_gl_pathv; + + pglob->gl_pathv[newcount] = strdup (pattern); + if (pglob->gl_pathv[newcount] == NULL) + { + globfree (&dirs); + globfree (pglob); + pglob->gl_pathc = 0; + retval = GLOB_NOSPACE; + goto out; + } + + ++pglob->gl_pathc; + ++newcount; + + pglob->gl_pathv[newcount] = NULL; + pglob->gl_flags = flags; + } + else + { + globfree (&dirs); + retval = GLOB_NOMATCH; + goto out; + } + } globfree (&dirs); } @@ -1065,57 +1085,57 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int), int orig_flags = flags; if (meta & GLOBPAT_BACKSLASH) - { - char *p = strchr (dirname, '\\'), *q; - /* We need to unescape the dirname string. It is certainly - allocated by alloca, as otherwise filename would be NULL - or dirname wouldn't contain backslashes. */ - q = p; - do - { - if (*p == '\\') - { - *q = *++p; - --dirlen; - } - else - *q = *p; - ++q; - } - while (*p++ != '\0'); - dirname_modified = 1; - } + { + char *p = strchr (dirname, '\\'), *q; + /* We need to unescape the dirname string. It is certainly + allocated by alloca, as otherwise filename would be NULL + or dirname wouldn't contain backslashes. */ + q = p; + do + { + if (*p == '\\') + { + *q = *++p; + --dirlen; + } + else + *q = *p; + ++q; + } + while (*p++ != '\0'); + dirname_modified = 1; + } if (dirname_modified) - flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC); + flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC); status = glob_in_dir (filename, dirname, flags, errfunc, pglob, - alloca_used); + alloca_used); if (status != 0) - { - if (status == GLOB_NOMATCH && flags != orig_flags - && pglob->gl_pathc + pglob->gl_offs == oldcount) - { - /* Make sure globfree (&dirs); is a nop. */ - dirs.gl_pathv = NULL; - flags = orig_flags; - goto no_matches; - } - retval = status; - goto out; - } + { + if (status == GLOB_NOMATCH && flags != orig_flags + && pglob->gl_pathc + pglob->gl_offs == oldcount) + { + /* Make sure globfree (&dirs); is a nop. */ + dirs.gl_pathv = NULL; + flags = orig_flags; + goto no_matches; + } + retval = status; + goto out; + } if (dirlen > 0) - { - /* Stick the directory on the front of each name. */ - if (prefix_array (dirname, - &pglob->gl_pathv[old_pathc + pglob->gl_offs], - pglob->gl_pathc - old_pathc)) - { - globfree (pglob); - pglob->gl_pathc = 0; - retval = GLOB_NOSPACE; - goto out; - } - } + { + /* Stick the directory on the front of each name. */ + if (prefix_array (dirname, + &pglob->gl_pathv[old_pathc + pglob->gl_offs], + pglob->gl_pathc - old_pathc)) + { + globfree (pglob); + pglob->gl_pathc = 0; + retval = GLOB_NOSPACE; + goto out; + } + } } if (flags & GLOB_MARK) @@ -1124,28 +1144,28 @@ __glob (const char *pattern, int flags, int (*errfunc) (const char *, int), size_t i; for (i = oldcount; i < pglob->gl_pathc + pglob->gl_offs; ++i) - if (is_dir (pglob->gl_pathv[i], flags, pglob)) - { - size_t len = strlen (pglob->gl_pathv[i]) + 2; - char *new = realloc (pglob->gl_pathv[i], len); - if (new == NULL) - { - globfree (pglob); - pglob->gl_pathc = 0; - retval = GLOB_NOSPACE; - goto out; - } - strcpy (&new[len - 2], "/"); - pglob->gl_pathv[i] = new; - } + if (is_dir (pglob->gl_pathv[i], flags, pglob)) + { + size_t len = strlen (pglob->gl_pathv[i]) + 2; + char *new = realloc (pglob->gl_pathv[i], len); + if (new == NULL) + { + globfree (pglob); + pglob->gl_pathc = 0; + retval = GLOB_NOSPACE; + goto out; + } + strcpy (&new[len - 2], "/"); + pglob->gl_pathv[i] = new; + } } if (!(flags & GLOB_NOSORT)) { /* Sort the vector. */ qsort (&pglob->gl_pathv[oldcount], - pglob->gl_pathc + pglob->gl_offs - oldcount, - sizeof (char *), collated_compare); + pglob->gl_pathc + pglob->gl_offs - oldcount, + sizeof (char *), collated_compare); } out: @@ -1197,14 +1217,14 @@ prefix_array (const char *dirname, char **array, size_t n) if (dirlen > 1) { if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':') - /* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */ - --dirlen; + /* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */ + --dirlen; else if (dirname[dirlen - 1] == ':') - { - /* DIRNAME is "d:". Use ':' instead of '/'. */ - --dirlen; - dirsep_char = ':'; - } + { + /* DIRNAME is "d:". Use ':' instead of '/'. */ + --dirlen; + dirsep_char = ':'; + } } #endif @@ -1213,16 +1233,16 @@ prefix_array (const char *dirname, char **array, size_t n) size_t eltlen = strlen (array[i]) + 1; char *new = malloc (dirlen + 1 + eltlen); if (new == NULL) - { - while (i > 0) - free (array[--i]); - return 1; - } + { + while (i > 0) + free (array[--i]); + return 1; + } { - char *endp = mempcpy (new, dirname, dirlen); - *endp++ = dirsep_char; - mempcpy (endp, array[i], eltlen); + char *endp = mempcpy (new, dirname, dirlen); + *endp++ = dirsep_char; + mempcpy (endp, array[i], eltlen); } free (array[i]); array[i] = new; @@ -1237,8 +1257,8 @@ prefix_array (const char *dirname, char **array, size_t n) The GLOB_APPEND flag is assumed to be set (always appends). */ static int glob_in_dir (const char *pattern, const char *directory, int flags, - int (*errfunc) (const char *, int), - glob_t *pglob, size_t alloca_used) + int (*errfunc) (const char *, int), + glob_t *pglob, size_t alloca_used) { size_t dirlen = strlen (directory); void *stream = NULL; @@ -1266,8 +1286,8 @@ glob_in_dir (const char *pattern, const char *directory, int flags, if (meta == GLOBPAT_NONE && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) { /* We need not do any tests. The PATTERN contains no meta - characters and we must not return an error therefore the - result will always contain exactly one name. */ + characters and we must not return an error therefore the + result will always contain exactly one name. */ flags |= GLOB_NOCHECK; } else if (meta == GLOBPAT_NONE) @@ -1281,102 +1301,102 @@ glob_in_dir (const char *pattern, const char *directory, int flags, if (alloca_fullname) fullname = alloca_account (fullsize, alloca_used); else - { - fullname = malloc (fullsize); - if (fullname == NULL) - return GLOB_NOSPACE; - } + { + fullname = malloc (fullsize); + if (fullname == NULL) + return GLOB_NOSPACE; + } mempcpy (mempcpy (mempcpy (fullname, directory, dirlen), - "/", 1), - pattern, patlen + 1); + "/", 1), + pattern, patlen + 1); if (glob_lstat (pglob, flags, fullname) == 0 - || errno == EOVERFLOW) - /* We found this file to be existing. Now tell the rest - of the function to copy this name into the result. */ - flags |= GLOB_NOCHECK; + || errno == EOVERFLOW) + /* We found this file to be existing. Now tell the rest + of the function to copy this name into the result. */ + flags |= GLOB_NOCHECK; if (__glibc_unlikely (!alloca_fullname)) - free (fullname); + free (fullname); } else { stream = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) - ? (*pglob->gl_opendir) (directory) - : opendir (directory)); + ? (*pglob->gl_opendir) (directory) + : opendir (directory)); if (stream == NULL) - { - if (errno != ENOTDIR - && ((errfunc != NULL && (*errfunc) (directory, errno)) - || (flags & GLOB_ERR))) - return GLOB_ABORTED; - } + { + if (errno != ENOTDIR + && ((errfunc != NULL && (*errfunc) (directory, errno)) + || (flags & GLOB_ERR))) + return GLOB_ABORTED; + } else - { - int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) - | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)); - flags |= GLOB_MAGCHAR; - - while (1) - { - struct readdir_result d; - { - if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)) - d = convert_dirent (GL_READDIR (pglob, stream)); - else - { + { + int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) + | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)); + flags |= GLOB_MAGCHAR; + + while (1) + { + struct readdir_result d; + { + if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)) + d = convert_dirent (GL_READDIR (pglob, stream)); + else + { #ifdef COMPILE_GLOB64 - d = convert_dirent (__readdir (stream)); + d = convert_dirent (__readdir (stream)); #else - d = convert_dirent64 (__readdir64 (stream)); + d = convert_dirent64 (__readdir64 (stream)); #endif - } - } - if (d.name == NULL) - break; - - /* If we shall match only directories use the information - provided by the dirent call if possible. */ - if (flags & GLOB_ONLYDIR) - switch (readdir_result_type (d)) - { - case DT_DIR: case DT_LNK: case DT_UNKNOWN: break; - default: continue; - } - - if (fnmatch (pattern, d.name, fnm_flags) == 0) - { - if (cur == names->count) - { - struct globnames *newnames; - size_t count = names->count * 2; - size_t nameoff = offsetof (struct globnames, name); - size_t size = FLEXSIZEOF (struct globnames, name, - count * sizeof (char *)); - if ((SIZE_MAX - nameoff) / 2 / sizeof (char *) - < names->count) - goto memory_error; - if (glob_use_alloca (alloca_used, size)) - newnames = names_alloca - = alloca_account (size, alloca_used); - else if ((newnames = malloc (size)) - == NULL) - goto memory_error; - newnames->count = count; - newnames->next = names; - names = newnames; - cur = 0; - } - names->name[cur] = strdup (d.name); - if (names->name[cur] == NULL) - goto memory_error; - ++cur; - ++nfound; - if (SIZE_MAX - pglob->gl_offs <= nfound) - goto memory_error; - } - } - } + } + } + if (d.name == NULL) + break; + + /* If we shall match only directories use the information + provided by the dirent call if possible. */ + if (flags & GLOB_ONLYDIR) + switch (readdir_result_type (d)) + { + case DT_DIR: case DT_LNK: case DT_UNKNOWN: break; + default: continue; + } + + if (fnmatch (pattern, d.name, fnm_flags) == 0) + { + if (cur == names->count) + { + struct globnames *newnames; + size_t count = names->count * 2; + size_t nameoff = offsetof (struct globnames, name); + size_t size = FLEXSIZEOF (struct globnames, name, + count * sizeof (char *)); + if ((SIZE_MAX - nameoff) / 2 / sizeof (char *) + < names->count) + goto memory_error; + if (glob_use_alloca (alloca_used, size)) + newnames = names_alloca + = alloca_account (size, alloca_used); + else if ((newnames = malloc (size)) + == NULL) + goto memory_error; + newnames->count = count; + newnames->next = names; + names = newnames; + cur = 0; + } + names->name[cur] = strdup (d.name); + if (names->name[cur] == NULL) + goto memory_error; + ++cur; + ++nfound; + if (SIZE_MAX - pglob->gl_offs <= nfound) + goto memory_error; + } + } + } } if (nfound == 0 && (flags & GLOB_NOCHECK)) @@ -1385,7 +1405,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags, nfound = 1; names->name[cur] = malloc (len + 1); if (names->name[cur] == NULL) - goto memory_error; + goto memory_error; *((char *) mempcpy (names->name[cur++], pattern, len)) = '\0'; } @@ -1396,80 +1416,80 @@ glob_in_dir (const char *pattern, const char *directory, int flags, result = 0; if (SIZE_MAX / sizeof (char *) - pglob->gl_pathc - < pglob->gl_offs + nfound + 1) - goto memory_error; + < pglob->gl_offs + nfound + 1) + goto memory_error; new_gl_pathv - = realloc (pglob->gl_pathv, - (pglob->gl_pathc + pglob->gl_offs + nfound + 1) - * sizeof (char *)); + = realloc (pglob->gl_pathv, + (pglob->gl_pathc + pglob->gl_offs + nfound + 1) + * sizeof (char *)); if (new_gl_pathv == NULL) - { - memory_error: - while (1) - { - struct globnames *old = names; - for (size_t i = 0; i < cur; ++i) - free (names->name[i]); - names = names->next; - /* NB: we will not leak memory here if we exit without - freeing the current block assigned to OLD. At least - the very first block is always allocated on the stack - and this is the block assigned to OLD here. */ - if (names == NULL) - { - assert (old == init_names); - break; - } - cur = names->count; - if (old == names_alloca) - names_alloca = names; - else - free (old); - } - result = GLOB_NOSPACE; - } + { + memory_error: + while (1) + { + struct globnames *old = names; + for (size_t i = 0; i < cur; ++i) + free (names->name[i]); + names = names->next; + /* NB: we will not leak memory here if we exit without + freeing the current block assigned to OLD. At least + the very first block is always allocated on the stack + and this is the block assigned to OLD here. */ + if (names == NULL) + { + assert (old == init_names); + break; + } + cur = names->count; + if (old == names_alloca) + names_alloca = names; + else + free (old); + } + result = GLOB_NOSPACE; + } else - { - while (1) - { - struct globnames *old = names; - for (size_t i = 0; i < cur; ++i) - new_gl_pathv[pglob->gl_offs + pglob->gl_pathc++] - = names->name[i]; - names = names->next; - /* NB: we will not leak memory here if we exit without - freeing the current block assigned to OLD. At least - the very first block is always allocated on the stack - and this is the block assigned to OLD here. */ - if (names == NULL) - { - assert (old == init_names); - break; - } - cur = names->count; - if (old == names_alloca) - names_alloca = names; - else - free (old); - } - - pglob->gl_pathv = new_gl_pathv; - - pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; - - pglob->gl_flags = flags; - } + { + while (1) + { + struct globnames *old = names; + for (size_t i = 0; i < cur; ++i) + new_gl_pathv[pglob->gl_offs + pglob->gl_pathc++] + = names->name[i]; + names = names->next; + /* NB: we will not leak memory here if we exit without + freeing the current block assigned to OLD. At least + the very first block is always allocated on the stack + and this is the block assigned to OLD here. */ + if (names == NULL) + { + assert (old == init_names); + break; + } + cur = names->count; + if (old == names_alloca) + names_alloca = names; + else + free (old); + } + + pglob->gl_pathv = new_gl_pathv; + + pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; + + pglob->gl_flags = flags; + } } if (stream != NULL) { save = errno; if (__glibc_unlikely (flags & GLOB_ALTDIRFUNC)) - (*pglob->gl_closedir) (stream); + (*pglob->gl_closedir) (stream); else - closedir (stream); + closedir (stream); __set_errno (save); } diff --git a/posix/glob_pattern_p.c b/posix/glob_pattern_p.c index f187baa1a5..436d38126d 100644 --- a/posix/glob_pattern_p.c +++ b/posix/glob_pattern_p.c @@ -17,7 +17,7 @@ . */ #ifndef _LIBC -# include +# include #endif #include diff --git a/posix/globfree.c b/posix/globfree.c index 162b90341a..1144fdd69f 100644 --- a/posix/globfree.c +++ b/posix/globfree.c @@ -17,7 +17,7 @@ . */ #ifndef _LIBC -# include +# include #endif #include From patchwork Wed Dec 30 20:15:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 41603 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id DBA34388C01D; Wed, 30 Dec 2020 20:15:18 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org DBA34388C01D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1609359318; bh=Q1j5yvZcuISX3oMdcIR6H9YAkZO94novgwu0tvixeNw=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=O6hazjEicDawLsQbBWUidJhq48/vUOJDQMJfoO/TZGb2q9VLJMTxWSWeHMot3DNtK J1SBeEU+EKUcIcrhR+XdZ3VTMIjT31T333q5EGJhkB5j6CUDGLm7kCWB0SPIJ+ojxj E5Gvdtl7iFHDlTlOb1RXWmgKkUxmjGmqMwb1eQh4= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qk1-x736.google.com (mail-qk1-x736.google.com [IPv6:2607:f8b0:4864:20::736]) by sourceware.org (Postfix) with ESMTPS id AFB57388C013 for ; Wed, 30 Dec 2020 20:15:16 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org AFB57388C013 Received: by mail-qk1-x736.google.com with SMTP id b64so14827136qkc.12 for ; Wed, 30 Dec 2020 12:15:16 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Q1j5yvZcuISX3oMdcIR6H9YAkZO94novgwu0tvixeNw=; b=Bp446sem91YLpCG2ZvpD/mGX3ut7QuDhbY0Bng8/++hixYCbyjSQV8/TGdYgN/fugp iZyyQ/OUaHJVP32+4cH/DwLhlWuQmqjWj2ie8Vc7ujEUocm2nSNvarmvbv8hg1OXqVqP mKmT0r9GfI17aKu3In/wJrNwGas/6fF3KBHLYql6LRLKd+EDCPmoI44XGEsC45K6noRX 53czthCTmVECrxOhDJLPrC45UdF91rEadzKIOe5LIeNa+4LhsX456jISqbZ5Uw1MR9sM 99zhHVPZAkTLSVLeoHkrS6ejNsjH7Gne1Z/WNi+Qfk3bwOr65kghrnfc+E4r57rh+bOH hxlA== X-Gm-Message-State: AOAM5318Q+xmMDRnnGAacnyprgzMiCh9PKssxaD0FO1nIPE1uMxupW6T qMsWDnNX+ZdOnsTK55sTIdWNkkY1M4glOA== X-Google-Smtp-Source: ABdhPJzz5bM9t91QZgRBfoROK8AXKaDVNTAld7q0M1LglWHwVrGmJCcuLtJUBo1B4pN0oaIdcy5ojw== X-Received: by 2002:a37:a40d:: with SMTP id n13mr54264954qke.47.1609359315973; Wed, 30 Dec 2020 12:15:15 -0800 (PST) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id v145sm5949057qka.27.2020.12.30.12.15.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Dec 2020 12:15:15 -0800 (PST) To: libc-alpha@sourceware.org, Paul Eggert Subject: [PATCH 3/5] Sync intprops.h with gnulib Date: Wed, 30 Dec 2020 17:15:05 -0300 Message-Id: <20201230201507.2755086-3-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201230201507.2755086-1-adhemerval.zanella@linaro.org> References: <20201230201507.2755086-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-13.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Reply-To: Adhemerval Zanella Cc: bug-gnulib@gnu.org Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" It sync with gnulib commit 43ee1a6bf. Checked on x86_64-linux-gnu. --- include/intprops.h | 70 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 12 deletions(-) diff --git a/include/intprops.h b/include/intprops.h index 6de65b067d..52e60e5e2d 100644 --- a/include/intprops.h +++ b/include/intprops.h @@ -48,7 +48,7 @@ /* Minimum and maximum values for integer types and expressions. */ /* The width in bits of the integer type or expression T. - Do not evaluate T. + Do not evaluate T. T must not be a bit-field expression. Padding bits are not supported; this is checked at compile-time below. */ #define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT) @@ -70,7 +70,7 @@ ? _GL_SIGNED_INT_MAXIMUM (e) \ : _GL_INT_NEGATE_CONVERT (e, 1)) #define _GL_SIGNED_INT_MAXIMUM(e) \ - (((_GL_INT_CONVERT (e, 1) << (TYPE_WIDTH ((e) + 0) - 2)) - 1) * 2 + 1) + (((_GL_INT_CONVERT (e, 1) << (TYPE_WIDTH (+ (e)) - 2)) - 1) * 2 + 1) /* Work around OpenVMS incompatibility with C99. */ #if !defined LLONG_MAX && defined __INT64_MAX @@ -86,6 +86,7 @@ /* Does the __typeof__ keyword work? This could be done by 'configure', but for now it's easier to do it by hand. */ #if (2 <= __GNUC__ \ + || (4 <= __clang_major__) \ || (1210 <= __IBMC__ && defined __IBM__TYPEOF__) \ || (0x5110 <= __SUNPRO_C && !__STDC__)) # define _GL_HAVE___TYPEOF__ 1 @@ -94,8 +95,9 @@ #endif /* Return 1 if the integer type or expression T might be signed. Return 0 - if it is definitely unsigned. This macro does not evaluate its argument, - and expands to an integer constant expression. */ + if it is definitely unsigned. T must not be a bit-field expression. + This macro does not evaluate its argument, and expands to an + integer constant expression. */ #if _GL_HAVE___TYPEOF__ # define _GL_SIGNED_TYPE_OR_EXPR(t) TYPE_SIGNED (__typeof__ (t)) #else @@ -108,6 +110,8 @@ #define INT_BITS_STRLEN_BOUND(b) (((b) * 146 + 484) / 485) /* Bound on length of the string representing an integer type or expression T. + T must not be a bit-field expression. + Subtract 1 for the sign bit if T is signed, and then add 1 more for a minus sign if needed. @@ -119,7 +123,7 @@ + _GL_SIGNED_TYPE_OR_EXPR (t)) /* Bound on buffer size needed to represent an integer type or expression T, - including the terminating null. */ + including the terminating null. T must not be a bit-field expression. */ #define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1) @@ -222,7 +226,9 @@ /* True if __builtin_add_overflow (A, B, P) and __builtin_sub_overflow (A, B, P) work when P is non-null. */ -#if 5 <= __GNUC__ && !defined __ICC +/* __builtin_{add,sub}_overflow exists but is not reliable in GCC 5.x and 6.x, + see . */ +#if 7 <= __GNUC__ && !defined __ICC # define _GL_HAS_BUILTIN_ADD_OVERFLOW 1 #elif defined __has_builtin # define _GL_HAS_BUILTIN_ADD_OVERFLOW __has_builtin (__builtin_add_overflow) @@ -239,8 +245,18 @@ #endif /* True if __builtin_add_overflow_p (A, B, C) works, and similarly for - __builtin_mul_overflow_p and __builtin_mul_overflow_p. */ -#define _GL_HAS_BUILTIN_OVERFLOW_P (7 <= __GNUC__) + __builtin_sub_overflow_p and __builtin_mul_overflow_p. */ +#if defined __clang__ || defined __ICC +/* Clang 11 lacks __builtin_mul_overflow_p, and even if it did it + would presumably run afoul of Clang bug 16404. ICC 2021.1's + __builtin_add_overflow_p etc. are not treated as integral constant + expressions even when all arguments are. */ +# define _GL_HAS_BUILTIN_OVERFLOW_P 0 +#elif defined __has_builtin +# define _GL_HAS_BUILTIN_OVERFLOW_P __has_builtin (__builtin_mul_overflow_p) +#else +# define _GL_HAS_BUILTIN_OVERFLOW_P (7 <= __GNUC__) +#endif /* The _GL*_OVERFLOW macros have the same restrictions as the *_RANGE_OVERFLOW macros, except that they do not assume that operands @@ -373,8 +389,9 @@ _GL_INT_OP_WRAPV (a, b, r, -, _GL_INT_SUBTRACT_RANGE_OVERFLOW) #endif #if _GL_HAS_BUILTIN_MUL_OVERFLOW -# if (9 < __GNUC__ + (3 <= __GNUC_MINOR__) \ - || (__GNUC__ == 8 && 4 <= __GNUC_MINOR__)) +# if ((9 < __GNUC__ + (3 <= __GNUC_MINOR__) \ + || (__GNUC__ == 8 && 4 <= __GNUC_MINOR__)) \ + && !defined __ICC) # define INT_MULTIPLY_WRAPV(a, b, r) __builtin_mul_overflow (a, b, r) # else /* Work around GCC bug 91450. */ @@ -395,7 +412,7 @@ For now, assume all versions of GCC-like compilers generate bogus warnings for _Generic. This matters only for compilers that lack relevant builtins. */ -#if __GNUC__ +#if __GNUC__ || defined __clang__ # define _GL__GENERIC_BOGUS 1 #else # define _GL__GENERIC_BOGUS 0 @@ -565,7 +582,7 @@ ? (EXPR_SIGNED (_GL_INT_CONVERT (tmax, b)) \ ? (a) < (tmax) / (b) \ : ((INT_NEGATE_OVERFLOW (b) \ - ? _GL_INT_CONVERT (b, tmax) >> (TYPE_WIDTH (b) - 1) \ + ? _GL_INT_CONVERT (b, tmax) >> (TYPE_WIDTH (+ (b)) - 1) \ : (tmax) / -(b)) \ <= -1 - (a))) \ : INT_NEGATE_OVERFLOW (_GL_INT_CONVERT (b, tmin)) && (b) == -1 \ @@ -581,4 +598,33 @@ : (tmin) / (a) < (b)) \ : (tmax) / (b) < (a))) +/* The following macros compute A + B, A - B, and A * B, respectively. + If no overflow occurs, they set *R to the result and return 1; + otherwise, they return 0 and may modify *R. + + Example usage: + + long int result; + if (INT_ADD_OK (a, b, &result)) + printf ("result is %ld\n", result); + else + printf ("overflow\n"); + + A, B, and *R should be integers; they need not be the same type, + and they need not be all signed or all unsigned. + + These macros work correctly on all known practical hosts, and do not rely + on undefined behavior due to signed arithmetic overflow. + + These macros are not constant expressions. + + These macros may evaluate their arguments zero or multiple times, so the + arguments should not have side effects. + + These macros are tuned for B being a constant. */ + +#define INT_ADD_OK(a, b, r) ! INT_ADD_WRAPV (a, b, r) +#define INT_SUBTRACT_OK(a, b, r) ! INT_SUBTRACT_WRAPV (a, b, r) +#define INT_MULTIPLY_OK(a, b, r) ! INT_MULTIPLY_WRAPV (a, b, r) + #endif /* _GL_INTPROPS_H */ From patchwork Wed Dec 30 20:15:06 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 41604 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 6BB06388C026; Wed, 30 Dec 2020 20:15:20 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6BB06388C026 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1609359320; bh=865jMgKztixWfbcfWMdN64MmWy8TSyjzP5w906qiAeY=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=Ijmx3GgqIXsDnM/nQVp8waqx+VGgox8OZ29m9Zyb0Tg+5K8UXh3Xf+PFhq7gOE2Rw KTUeIdEUw82cccEUzMOG4KoXQW5x/X0a0qo966db5p+JtrE8f4ta6fNhXcQJCUQ4W6 1lVZO+be+eMznB6heGH3TUAO20S0kWGBGYG28Vmw= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qk1-x72a.google.com (mail-qk1-x72a.google.com [IPv6:2607:f8b0:4864:20::72a]) by sourceware.org (Postfix) with ESMTPS id 66070388C017 for ; Wed, 30 Dec 2020 20:15:18 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 66070388C017 Received: by mail-qk1-x72a.google.com with SMTP id f26so14917190qka.0 for ; Wed, 30 Dec 2020 12:15:18 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=865jMgKztixWfbcfWMdN64MmWy8TSyjzP5w906qiAeY=; b=oziH+j9so5d7601hmaNpXgTcbKT3OUBP6T2QuB1belVNWUjS0+t5+zM4sd4w/LcJUw TeZc7s79ZyudZxxHCDxMG9LKY/nFvOFdQ5T5KAC4/NU5OJXWKDAOkG/dzycNb9RH02I/ 4Uh/KKmliDhswxjKeKmU/bWLsNTzSgg3KwbHFHhGhzBiokFiS0JetPsUAChiARLqDKB2 YNkQBzsVKbX1Qe1AhSgr5/fI7oGio+gOPI1FW9iYwAvmsktxLC8qM8pFZKNA+zR+nFma rU1pjyoV0ujEqV368IuC38i/gqQihv6nalyk6jIxJT6esYvsjPaLPsZcE5GYLmJz965c cjZw== X-Gm-Message-State: AOAM532Ls8rPr0BesGgpugno4aoxwLzqgmWKb/uG37lIw7MFY3Wg3IAz eB76jl1R1s36GK04KhJi5me9U4mm1yN41Q== X-Google-Smtp-Source: ABdhPJwuKYo40Sw3ypvw30oO52izNm8WLp4gZ0HJlTQWJeHvTuYzLC5Ym5qH2xIfmRUPYDlGRva/XA== X-Received: by 2002:a37:9505:: with SMTP id x5mr50646293qkd.295.1609359317714; Wed, 30 Dec 2020 12:15:17 -0800 (PST) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id v145sm5949057qka.27.2020.12.30.12.15.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Dec 2020 12:15:17 -0800 (PST) To: libc-alpha@sourceware.org, Paul Eggert Subject: [PATCH 4/5] Sync flexmember.h with gnulib Date: Wed, 30 Dec 2020 17:15:06 -0300 Message-Id: <20201230201507.2755086-4-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201230201507.2755086-1-adhemerval.zanella@linaro.org> References: <20201230201507.2755086-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-13.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Reply-To: Adhemerval Zanella Cc: bug-gnulib@gnu.org Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" It sync with gnulib commit 43ee1a6bf. --- posix/flexmember.h | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/posix/flexmember.h b/posix/flexmember.h index 30e6a6b867..1e839f08c2 100644 --- a/posix/flexmember.h +++ b/posix/flexmember.h @@ -33,11 +33,26 @@ # define FLEXALIGNOF(type) _Alignof (type) #endif -/* Upper bound on the size of a struct of type TYPE with a flexible - array member named MEMBER that is followed by N bytes of other data. - This is not simply sizeof (TYPE) + N, since it may require - alignment on unusually picky C11 platforms, and - FLEXIBLE_ARRAY_MEMBER may be 1 on pre-C11 platforms. +/* Yield a properly aligned upper bound on the size of a struct of + type TYPE with a flexible array member named MEMBER that is + followed by N bytes of other data. The result is suitable as an + argument to malloc. For example: + + struct s { int n; char d[FLEXIBLE_ARRAY_MEMBER]; }; + struct s *p = malloc (FLEXSIZEOF (struct s, d, n * sizeof (char))); + + FLEXSIZEOF (TYPE, MEMBER, N) is not simply (sizeof (TYPE) + N), + since FLEXIBLE_ARRAY_MEMBER may be 1 on pre-C11 platforms. Nor is + it simply (offsetof (TYPE, MEMBER) + N), as that might yield a size + that causes malloc to yield a pointer that is not properly aligned + for TYPE; for example, if sizeof (int) == alignof (int) == 4, + malloc (offsetof (struct s, d) + 3 * sizeof (char)) is equivalent + to malloc (7) and might yield a pointer that is not a multiple of 4 + (which means the pointer is not properly aligned for struct s), + whereas malloc (FLEXSIZEOF (struct s, d, 3 * sizeof (char))) is + equivalent to malloc (8) and must yield a pointer that is a + multiple of 4. + Yield a value less than N if and only if arithmetic overflow occurs. */ #define FLEXSIZEOF(type, member, n) \ From patchwork Wed Dec 30 20:15:07 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 41606 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B65F1388C01B; Wed, 30 Dec 2020 20:15:31 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B65F1388C01B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1609359331; bh=rTAYWez9r91LR7R6P0A6703s+bfjK9PWnKTmhB+/S6M=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=hNrJUgL7EFPQeTvWaR+Nd7U20MkpO95fRfKM8r6Drcfffh7dh0cSHs1INXq3Y+NVz 0bzzX73drD3T7Q4D8zxMAhslVf+67+SYIirnpCYNzXOWHvyxRgJPfkqzb4ZeyBpPa+ dWMfNeJu5fzpLpN/FVwW05NsgWnE9v+YVxdoUr7w= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qk1-x735.google.com (mail-qk1-x735.google.com [IPv6:2607:f8b0:4864:20::735]) by sourceware.org (Postfix) with ESMTPS id 4B4C8388C037 for ; Wed, 30 Dec 2020 20:15:23 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 4B4C8388C037 Received: by mail-qk1-x735.google.com with SMTP id n142so14866663qkn.2 for ; Wed, 30 Dec 2020 12:15:23 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=rTAYWez9r91LR7R6P0A6703s+bfjK9PWnKTmhB+/S6M=; b=ACpN6gYgCD3c75UIUXASqhIYh94P0a9cN8DqA6XSUf3FbwMZB13TdU2TrsxzTVr/i5 XsiTpfP77Y8m6OXO0rNluB96n8v6MEEhernJVTvjSIRUArS4PLhY9Wpnv036bkDTlb53 0eoF3NPvz543KvvCQDBFYM66X9c/GQlkhKrXN2dIc0PQX7Zt/o0xOUnCjpQB5rwRiN+o I3T1W/ngZFFZHPj2wV75oQk9iNyu3m1tUBV/h0xoXteV/mOFcnjN5Vxj2Cwdpa8RJcne VBBQfocSixFXqByIGL5QKWCOFazce5ZK/4LVm7e7TPm97m6K68Ml5I1szfZd0mgBYNyA 2hQw== X-Gm-Message-State: AOAM533Df6fH/kvuVEUSImpvG8yex/Xg4QS0Ikh19f55ua3SUiQGHNGH 3O/TvwPIXbeD8eHXUcWjse+9f8uAmFl82A== X-Google-Smtp-Source: ABdhPJzzei4aJxiQd6O08GU9gumKsYAyi5eW/fwAJc5GWKL+NCADAbG2l8egKqTwZKO3nuWFa4oiRQ== X-Received: by 2002:a37:a943:: with SMTP id s64mr55473837qke.207.1609359320093; Wed, 30 Dec 2020 12:15:20 -0800 (PST) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id v145sm5949057qka.27.2020.12.30.12.15.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Dec 2020 12:15:19 -0800 (PST) To: libc-alpha@sourceware.org, Paul Eggert Subject: [PATCH 5/5] posix: Sync fnmatch with gnulib Date: Wed, 30 Dec 2020 17:15:07 -0300 Message-Id: <20201230201507.2755086-5-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201230201507.2755086-1-adhemerval.zanella@linaro.org> References: <20201230201507.2755086-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-12.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, KAM_STOCKGEN, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Reply-To: Adhemerval Zanella Cc: bug-gnulib@gnu.org Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" It sync with gnulib commit 43ee1a6bf with following changes: --- posix/fnmatch_loop.c +++ ../../gnulib/gnulib-lib/lib/fnmatch_loop.c @@ -978,12 +978,12 @@ bool no_leading_period, int flags, size_t alloca_used) { const CHAR *startp; - ssize_t level; + size_t level; struct patternlist { struct patternlist *next; CHAR malloced; - CHAR str[]; + CHAR str[FLEXIBLE_ARRAY_MEMBER]; } *list = NULL; struct patternlist **lastp = &list; size_t pattern_len = STRLEN (pattern); @@ -994,7 +994,7 @@ /* Parse the pattern. Store the individual parts in the list. */ level = 0; - for (startp = p = pattern + 1; level >= 0; ++p) + for (startp = p = pattern + 1; ; ++p) if (*p == L_('\0')) { /* This is an invalid pattern. */ @@ -1065,6 +1065,7 @@ *lastp = newp; \ lastp = &newp->next NEW_PATTERN; + break; } } else if (*p == L_('|')) Because otherwise it triggers some glibc regressions: FAIL: posix/tst-fnmatch FAIL: posix/tst-fnmatch-mem FAIL: posix/tst-fnmatch3 $ cat posix/tst-fnmatch.out [...] 537: fnmatch ("x?y", "x/y/z", FNM_PATHNAME|FNM_LEADING_DIR) = FNM_NOMATCH Didn't expect signal from child: got `Aborted' $ cat posix/tst-fnmatch3.out Didn't expect signal from child: got `Aborted' It is due the loops returns early and hits the assert below. Checked on x86_64-linux-gnu. --- posix/fnmatch.c | 548 +++++------- posix/fnmatch_loop.c | 1977 +++++++++++++++++++++--------------------- 2 files changed, 1208 insertions(+), 1317 deletions(-) diff --git a/posix/fnmatch.c b/posix/fnmatch.c index 315584f900..c80809e783 100644 --- a/posix/fnmatch.c +++ b/posix/fnmatch.c @@ -15,38 +15,29 @@ License along with the GNU C Library; if not, see . */ -#if HAVE_CONFIG_H -# include +#ifndef _LIBC +# include #endif /* Enable GNU extensions in fnmatch.h. */ #ifndef _GNU_SOURCE -# define _GNU_SOURCE 1 +# define _GNU_SOURCE 1 #endif +#include + #include #include -#include #include #include - -#if defined STDC_HEADERS || defined _LIBC -# include -#endif - -#ifdef _LIBC +#include +#if defined _LIBC || HAVE_ALLOCA # include -#else -# define alloca_account(size., var) alloca (size) -#endif - -/* For platform which support the ISO C amendement 1 functionality we - support user defined character classes. */ -#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) -/* Solaris 2.5 has a bug: must be included before . */ -# include -# include #endif +#include +#include +#include +#include /* We need some of the locale data (the collation sequence information) but there is no interface to get this information in general. Therefore @@ -57,199 +48,125 @@ # include # define CONCAT(a,b) __CONCAT(a,b) +# define btowc __btowc +# define iswctype __iswctype # define mbsrtowcs __mbsrtowcs +# define mempcpy __mempcpy +# define strnlen __strnlen +# define towlower __towlower +# define wcscat __wcscat +# define wcslen __wcslen +# define wctype __wctype +# define wmemchr __wmemchr +# define wmempcpy __wmempcpy # define fnmatch __fnmatch extern int fnmatch (const char *pattern, const char *string, int flags); #endif -/* We often have to test for FNM_FILE_NAME and FNM_PERIOD being both set. */ -#define NO_LEADING_PERIOD(flags) \ - ((flags & (FNM_FILE_NAME | FNM_PERIOD)) == (FNM_FILE_NAME | FNM_PERIOD)) - -/* Comment out all this code if we are using the GNU C Library, and are not - actually compiling the library itself. This code is part of the GNU C - Library, but also included in many other GNU distributions. Compiling - and linking in this code is a waste when using the GNU C library - (especially if it is a shared library). Rather than having every GNU - program understand `configure --with-gnu-libc' and omit the object files, - it is simpler to just do this in the source for each such file. */ +#ifdef _LIBC +# if (__GNUC__ >= 7) || (__clang_major__ >= 10) +# define FALLTHROUGH __attribute__ ((__fallthrough__)) +# else +# define FALLTHROUGH ((void) 0) +# endif +#else +# include "attribute.h" +#endif -#if defined _LIBC || !defined __GNU_LIBRARY__ +#include +#include +#ifdef _LIBC +typedef ptrdiff_t idx_t; +#else +# include "idx.h" +#endif -# if defined STDC_HEADERS || !defined isascii -# define ISASCII(c) 1 -# else -# define ISASCII(c) isascii(c) -# endif +/* We often have to test for FNM_FILE_NAME and FNM_PERIOD being both set. */ +#define NO_LEADING_PERIOD(flags) \ + ((flags & (FNM_FILE_NAME | FNM_PERIOD)) == (FNM_FILE_NAME | FNM_PERIOD)) -# ifdef isblank -# define ISBLANK(c) (ISASCII (c) && isblank (c)) +#ifndef _LIBC +# if HAVE_ALLOCA +/* The OS usually guarantees only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + allocate anything larger than 4096 bytes. Also care for the possibility + of a few compiler-allocated temporary stack slots. */ +# define __libc_use_alloca(n) ((n) < 4032) # else -# define ISBLANK(c) ((c) == ' ' || (c) == '\t') -# endif -# ifdef isgraph -# define ISGRAPH(c) (ISASCII (c) && isgraph (c)) -# else -# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c)) +/* Just use malloc. */ +# define __libc_use_alloca(n) false +# undef alloca +# define alloca(n) malloc (n) # endif +# define alloca_account(size, avar) ((avar) += (size), alloca (size)) +#endif -# define ISPRINT(c) (ISASCII (c) && isprint (c)) -# define ISDIGIT(c) (ISASCII (c) && isdigit (c)) -# define ISALNUM(c) (ISASCII (c) && isalnum (c)) -# define ISALPHA(c) (ISASCII (c) && isalpha (c)) -# define ISCNTRL(c) (ISASCII (c) && iscntrl (c)) -# define ISLOWER(c) (ISASCII (c) && islower (c)) -# define ISPUNCT(c) (ISASCII (c) && ispunct (c)) -# define ISSPACE(c) (ISASCII (c) && isspace (c)) -# define ISUPPER(c) (ISASCII (c) && isupper (c)) -# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c)) - -# define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) - -# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) -/* The GNU C library provides support for user-defined character classes - and the functions from ISO C amendement 1. */ -# ifdef CHARCLASS_NAME_MAX -# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX -# else +/* Provide support for user-defined character classes, based on the functions + from ISO C 90 amendment 1. */ +#ifdef CHARCLASS_NAME_MAX +# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX +#else /* This shouldn't happen but some implementation might still have this problem. Use a reasonable default value. */ -# define CHAR_CLASS_MAX_LENGTH 256 -# endif - -# ifdef _LIBC -# define IS_CHAR_CLASS(string) __wctype (string) -# else -# define IS_CHAR_CLASS(string) wctype (string) -# endif - -# ifdef _LIBC -# define ISWCTYPE(WC, WT) __iswctype (WC, WT) -# else -# define ISWCTYPE(WC, WT) iswctype (WC, WT) -# endif - -# if (HAVE_MBSTATE_T && HAVE_MBSRTOWCS) || _LIBC -/* In this case we are implementing the multibyte character handling. */ -# define HANDLE_MULTIBYTE 1 -# endif +# define CHAR_CLASS_MAX_LENGTH 256 +#endif -# else -# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ - -# define IS_CHAR_CLASS(string) \ - (STREQ (string, "alpha") || STREQ (string, "upper") \ - || STREQ (string, "lower") || STREQ (string, "digit") \ - || STREQ (string, "alnum") || STREQ (string, "xdigit") \ - || STREQ (string, "space") || STREQ (string, "print") \ - || STREQ (string, "punct") || STREQ (string, "graph") \ - || STREQ (string, "cntrl") || STREQ (string, "blank")) -# endif +#define IS_CHAR_CLASS(string) wctype (string) /* Avoid depending on library functions or files whose names are inconsistent. */ -# if !defined _LIBC && !defined getenv -extern char *getenv (); -# endif - -# ifndef errno -extern int errno; -# endif - /* Global variable. */ static int posixly_correct; -/* This function doesn't exist on most systems. */ - -# if !defined HAVE___STRCHRNUL && !defined _LIBC -static char * -__strchrnul (const char *s, int c) -{ - char *result = strchr (s, c); - if (result == NULL) - result = strchr (s, '\0'); - return result; -} -# endif - -# if HANDLE_MULTIBYTE && !defined HAVE___STRCHRNUL && !defined _LIBC -static wchar_t * -__wcschrnul (const wchar_t *s, wint_t c) -{ - wchar_t *result = wcschr (s, c); - if (result == NULL) - result = wcschr (s, '\0'); - return result; -} -# endif - /* Note that this evaluates C many times. */ -# ifdef _LIBC -# define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c)) -# else -# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c)) -# endif -# define CHAR char -# define UCHAR unsigned char -# define INT int -# define FCT internal_fnmatch -# define EXT ext_match -# define END end_pattern -# define STRUCT fnmatch_struct -# define L(CS) CS -# ifdef _LIBC -# define BTOWC(C) __btowc (C) -# else -# define BTOWC(C) btowc (C) -# endif -# define STRLEN(S) strlen (S) -# define STRCAT(D, S) strcat (D, S) -# define MEMPCPY(D, S, N) __mempcpy (D, S, N) -# define MEMCHR(S, C, N) memchr (S, C, N) -# define STRCOLL(S1, S2) strcoll (S1, S2) -# define WIDE_CHAR_VERSION 0 +#define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c)) +#define CHAR char +#define UCHAR unsigned char +#define INT int +#define FCT internal_fnmatch +#define EXT ext_match +#define END end_pattern +#define STRUCT fnmatch_struct +#define L_(CS) CS +#define BTOWC(C) btowc (C) +#define STRLEN(S) strlen (S) +#define STRCAT(D, S) strcat (D, S) +#define MEMPCPY(D, S, N) mempcpy (D, S, N) +#define MEMCHR(S, C, N) memchr (S, C, N) +#define WIDE_CHAR_VERSION 0 +#ifdef _LIBC # include # define FINDIDX findidx -# include "fnmatch_loop.c" - - -# if HANDLE_MULTIBYTE -/* Note that this evaluates C many times. */ -# ifdef _LIBC -# define FOLD(c) ((flags & FNM_CASEFOLD) ? __towlower (c) : (c)) -# else -# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? towlower (c) : (c)) -# endif -# define CHAR wchar_t -# define UCHAR wint_t -# define INT wint_t -# define FCT internal_fnwmatch -# define EXT ext_wmatch -# define END end_wpattern -# define STRUCT fnwmatch_struct -# define L(CS) L##CS -# define BTOWC(C) (C) -# define STRLEN(S) __wcslen (S) -# define STRCAT(D, S) __wcscat (D, S) -# define MEMPCPY(D, S, N) __wmempcpy (D, S, N) -# define MEMCHR(S, C, N) __wmemchr (S, C, N) -# define STRCOLL(S1, S2) wcscoll (S1, S2) -# ifdef _LIBC -# define WMEMCMP(S1, S2, N) __wmemcmp (S1, S2, N) -# else -# define WMEMCMP(S1, S2, N) wmemcmp (S1, S2, N) -# endif -# define WIDE_CHAR_VERSION 1 +#endif +#include "fnmatch_loop.c" + + +#define FOLD(c) ((flags & FNM_CASEFOLD) ? towlower (c) : (c)) +#define CHAR wchar_t +#define UCHAR wint_t +#define INT wint_t +#define FCT internal_fnwmatch +#define EXT ext_wmatch +#define END end_wpattern +#define L_(CS) L##CS +#define BTOWC(C) (C) +#define STRLEN(S) wcslen (S) +#define STRCAT(D, S) wcscat (D, S) +#define MEMPCPY(D, S, N) wmempcpy (D, S, N) +#define MEMCHR(S, C, N) wmemchr (S, C, N) +#define WIDE_CHAR_VERSION 1 +#ifdef _LIBC /* Change the name the header defines so it doesn't conflict with the version included above. */ -# define findidx findidxwc -# include -# undef findidx -# define FINDIDX findidxwc +# define findidx findidxwc +# include +# undef findidx +# define FINDIDX findidxwc +#endif -# undef IS_CHAR_CLASS +#undef IS_CHAR_CLASS /* We have to convert the wide character string in a multibyte string. But we know that the character class names consist of alphanumeric characters from the portable character set, and since the wide character encoding @@ -265,42 +182,42 @@ is_char_class (const wchar_t *wcs) do { /* Test for a printable character from the portable character set. */ -# ifdef _LIBC +#ifdef _LIBC if (*wcs < 0x20 || *wcs > 0x7e - || *wcs == 0x24 || *wcs == 0x40 || *wcs == 0x60) - return (wctype_t) 0; -# else + || *wcs == 0x24 || *wcs == 0x40 || *wcs == 0x60) + return (wctype_t) 0; +#else switch (*wcs) - { - case L' ': case L'!': case L'"': case L'#': case L'%': - case L'&': case L'\'': case L'(': case L')': case L'*': - case L'+': case L',': case L'-': case L'.': case L'/': - case L'0': case L'1': case L'2': case L'3': case L'4': - case L'5': case L'6': case L'7': case L'8': case L'9': - case L':': case L';': case L'<': case L'=': case L'>': - case L'?': - case L'A': case L'B': case L'C': case L'D': case L'E': - case L'F': case L'G': case L'H': case L'I': case L'J': - case L'K': case L'L': case L'M': case L'N': case L'O': - case L'P': case L'Q': case L'R': case L'S': case L'T': - case L'U': case L'V': case L'W': case L'X': case L'Y': - case L'Z': - case L'[': case L'\\': case L']': case L'^': case L'_': - case L'a': case L'b': case L'c': case L'd': case L'e': - case L'f': case L'g': case L'h': case L'i': case L'j': - case L'k': case L'l': case L'm': case L'n': case L'o': - case L'p': case L'q': case L'r': case L's': case L't': - case L'u': case L'v': case L'w': case L'x': case L'y': - case L'z': case L'{': case L'|': case L'}': case L'~': - break; - default: - return (wctype_t) 0; - } -# endif + { + case L' ': case L'!': case L'"': case L'#': case L'%': + case L'&': case L'\'': case L'(': case L')': case L'*': + case L'+': case L',': case L'-': case L'.': case L'/': + case L'0': case L'1': case L'2': case L'3': case L'4': + case L'5': case L'6': case L'7': case L'8': case L'9': + case L':': case L';': case L'<': case L'=': case L'>': + case L'?': + case L'A': case L'B': case L'C': case L'D': case L'E': + case L'F': case L'G': case L'H': case L'I': case L'J': + case L'K': case L'L': case L'M': case L'N': case L'O': + case L'P': case L'Q': case L'R': case L'S': case L'T': + case L'U': case L'V': case L'W': case L'X': case L'Y': + case L'Z': + case L'[': case L'\\': case L']': case L'^': case L'_': + case L'a': case L'b': case L'c': case L'd': case L'e': + case L'f': case L'g': case L'h': case L'i': case L'j': + case L'k': case L'l': case L'm': case L'n': case L'o': + case L'p': case L'q': case L'r': case L's': case L't': + case L'u': case L'v': case L'w': case L'x': case L'y': + case L'z': case L'{': case L'|': case L'}': case L'~': + break; + default: + return (wctype_t) 0; + } +#endif /* Avoid overrunning the buffer. */ if (cp == s + CHAR_CLASS_MAX_LENGTH) - return (wctype_t) 0; + return (wctype_t) 0; *cp++ = (char) *wcs++; } @@ -308,23 +225,17 @@ is_char_class (const wchar_t *wcs) *cp = '\0'; -# ifdef _LIBC - return __wctype (s); -# else return wctype (s); -# endif } -# define IS_CHAR_CLASS(string) is_char_class (string) +#define IS_CHAR_CLASS(string) is_char_class (string) -# include "fnmatch_loop.c" -# endif +#include "fnmatch_loop.c" int fnmatch (const char *pattern, const char *string, int flags) { -# if HANDLE_MULTIBYTE - if (__builtin_expect (MB_CUR_MAX, 1) != 1) + if (__glibc_unlikely (MB_CUR_MAX != 1)) { mbstate_t ps; size_t n; @@ -338,126 +249,113 @@ fnmatch (const char *pattern, const char *string, int flags) /* Convert the strings into wide characters. */ memset (&ps, '\0', sizeof (ps)); p = pattern; -#ifdef _LIBC - n = __strnlen (pattern, 1024); -#else - n = strlen (pattern); -#endif + n = strnlen (pattern, 1024); if (__glibc_likely (n < 1024)) - { - wpattern = (wchar_t *) alloca_account ((n + 1) * sizeof (wchar_t), - alloca_used); - n = mbsrtowcs (wpattern, &p, n + 1, &ps); - if (__glibc_unlikely (n == (size_t) -1)) - /* Something wrong. - XXX Do we have to set `errno' to something which mbsrtows hasn't - already done? */ - return -1; - if (p) - { - memset (&ps, '\0', sizeof (ps)); - goto prepare_wpattern; - } - } + { + wpattern = (wchar_t *) alloca_account ((n + 1) * sizeof (wchar_t), + alloca_used); + n = mbsrtowcs (wpattern, &p, n + 1, &ps); + if (__glibc_unlikely (n == (size_t) -1)) + /* Something wrong. + XXX Do we have to set 'errno' to something which mbsrtows hasn't + already done? */ + return -1; + if (p) + { + memset (&ps, '\0', sizeof (ps)); + goto prepare_wpattern; + } + } else - { - prepare_wpattern: - n = mbsrtowcs (NULL, &pattern, 0, &ps); - if (__glibc_unlikely (n == (size_t) -1)) - /* Something wrong. - XXX Do we have to set `errno' to something which mbsrtows hasn't - already done? */ - return -1; - if (__glibc_unlikely (n >= (size_t) -1 / sizeof (wchar_t))) - { - __set_errno (ENOMEM); - return -2; - } - wpattern_malloc = wpattern - = (wchar_t *) malloc ((n + 1) * sizeof (wchar_t)); - assert (mbsinit (&ps)); - if (wpattern == NULL) - return -2; - (void) mbsrtowcs (wpattern, &pattern, n + 1, &ps); - } + { + prepare_wpattern: + n = mbsrtowcs (NULL, &pattern, 0, &ps); + if (__glibc_unlikely (n == (size_t) -1)) + /* Something wrong. + XXX Do we have to set 'errno' to something which mbsrtows hasn't + already done? */ + return -1; + if (__glibc_unlikely (n >= (size_t) -1 / sizeof (wchar_t))) + { + __set_errno (ENOMEM); + return -2; + } + wpattern_malloc = wpattern + = (wchar_t *) malloc ((n + 1) * sizeof (wchar_t)); + assert (mbsinit (&ps)); + if (wpattern == NULL) + return -2; + (void) mbsrtowcs (wpattern, &pattern, n + 1, &ps); + } assert (mbsinit (&ps)); -#ifdef _LIBC - n = __strnlen (string, 1024); -#else - n = strlen (string); -#endif + n = strnlen (string, 1024); p = string; if (__glibc_likely (n < 1024)) - { - wstring = (wchar_t *) alloca_account ((n + 1) * sizeof (wchar_t), - alloca_used); - n = mbsrtowcs (wstring, &p, n + 1, &ps); - if (__glibc_unlikely (n == (size_t) -1)) - { - /* Something wrong. - XXX Do we have to set `errno' to something which - mbsrtows hasn't already done? */ - free_return: - free (wpattern_malloc); - return -1; - } - if (p) - { - memset (&ps, '\0', sizeof (ps)); - goto prepare_wstring; - } - } + { + wstring = (wchar_t *) alloca_account ((n + 1) * sizeof (wchar_t), + alloca_used); + n = mbsrtowcs (wstring, &p, n + 1, &ps); + if (__glibc_unlikely (n == (size_t) -1)) + { + /* Something wrong. + XXX Do we have to set 'errno' to something which + mbsrtows hasn't already done? */ + free_return: + free (wpattern_malloc); + return -1; + } + if (p) + { + memset (&ps, '\0', sizeof (ps)); + goto prepare_wstring; + } + } else - { - prepare_wstring: - n = mbsrtowcs (NULL, &string, 0, &ps); - if (__glibc_unlikely (n == (size_t) -1)) - /* Something wrong. - XXX Do we have to set `errno' to something which mbsrtows hasn't - already done? */ - goto free_return; - if (__glibc_unlikely (n >= (size_t) -1 / sizeof (wchar_t))) - { - free (wpattern_malloc); - __set_errno (ENOMEM); - return -2; - } - - wstring_malloc = wstring - = (wchar_t *) malloc ((n + 1) * sizeof (wchar_t)); - if (wstring == NULL) - { - free (wpattern_malloc); - return -2; - } - assert (mbsinit (&ps)); - (void) mbsrtowcs (wstring, &string, n + 1, &ps); - } + { + prepare_wstring: + n = mbsrtowcs (NULL, &string, 0, &ps); + if (__glibc_unlikely (n == (size_t) -1)) + /* Something wrong. + XXX Do we have to set 'errno' to something which mbsrtows hasn't + already done? */ + goto free_return; + if (__glibc_unlikely (n >= (size_t) -1 / sizeof (wchar_t))) + { + free (wpattern_malloc); + __set_errno (ENOMEM); + return -2; + } + + wstring_malloc = wstring + = (wchar_t *) malloc ((n + 1) * sizeof (wchar_t)); + if (wstring == NULL) + { + free (wpattern_malloc); + return -2; + } + assert (mbsinit (&ps)); + (void) mbsrtowcs (wstring, &string, n + 1, &ps); + } int res = internal_fnwmatch (wpattern, wstring, wstring + n, - flags & FNM_PERIOD, flags, NULL, - alloca_used); + flags & FNM_PERIOD, flags, NULL, + alloca_used); free (wstring_malloc); free (wpattern_malloc); return res; } -# endif /* mbstate_t and mbsrtowcs or _LIBC. */ return internal_fnmatch (pattern, string, string + strlen (string), - flags & FNM_PERIOD, flags, NULL, 0); + flags & FNM_PERIOD, flags, NULL, 0); } -# ifdef _LIBC -# undef fnmatch +#undef fnmatch versioned_symbol (libc, __fnmatch, fnmatch, GLIBC_2_2_3); -# if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_2_3) +#if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_2_3) strong_alias (__fnmatch, __fnmatch_old) compat_symbol (libc, __fnmatch_old, fnmatch, GLIBC_2_0); -# endif +#endif libc_hidden_ver (__fnmatch, fnmatch) -# endif - -#endif /* _LIBC or not __GNU_LIBRARY__. */ diff --git a/posix/fnmatch_loop.c b/posix/fnmatch_loop.c index 0f890d4782..2804eae6b1 100644 --- a/posix/fnmatch_loop.c +++ b/posix/fnmatch_loop.c @@ -15,28 +15,30 @@ License along with the GNU C Library; if not, see . */ -#include +#ifdef _LIBC +# include +#endif struct STRUCT { const CHAR *pattern; const CHAR *string; - int no_leading_period; + bool no_leading_period; }; -/* Match STRING against the filename pattern PATTERN, returning zero if +/* Match STRING against the file name pattern PATTERN, returning zero if it matches, nonzero if not. */ static int FCT (const CHAR *pattern, const CHAR *string, - const CHAR *string_end, int no_leading_period, int flags, - struct STRUCT *ends, size_t alloca_used); + const CHAR *string_end, bool no_leading_period, int flags, + struct STRUCT *ends, size_t alloca_used); static int EXT (INT opt, const CHAR *pattern, const CHAR *string, - const CHAR *string_end, int no_leading_period, int flags, - size_t alloca_used); + const CHAR *string_end, bool no_leading_period, int flags, + size_t alloca_used); static const CHAR *END (const CHAR *patternp); static int FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end, - int no_leading_period, int flags, struct STRUCT *ends, size_t alloca_used) + bool no_leading_period, int flags, struct STRUCT *ends, size_t alloca_used) { const CHAR *p = pattern, *n = string; UCHAR c; @@ -50,882 +52,868 @@ FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end, # endif #endif - while ((c = *p++) != L('\0')) + while ((c = *p++) != L_('\0')) { - int new_no_leading_period = 0; + bool new_no_leading_period = false; c = FOLD (c); switch (c) - { - case L('?'): - if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(') - { - int res = EXT (c, p, n, string_end, no_leading_period, - flags, alloca_used); - if (res != -1) - return res; - } - - if (n == string_end) - return FNM_NOMATCH; - else if (*n == L('/') && (flags & FNM_FILE_NAME)) - return FNM_NOMATCH; - else if (*n == L('.') && no_leading_period) - return FNM_NOMATCH; - break; - - case L('\\'): - if (!(flags & FNM_NOESCAPE)) - { - c = *p++; - if (c == L('\0')) - /* Trailing \ loses. */ - return FNM_NOMATCH; - c = FOLD (c); - } - if (n == string_end || FOLD ((UCHAR) *n) != c) - return FNM_NOMATCH; - break; - - case L('*'): - if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(') - { - int res = EXT (c, p, n, string_end, no_leading_period, - flags, alloca_used); - if (res != -1) - return res; - } - else if (ends != NULL) - { - ends->pattern = p - 1; - ends->string = n; - ends->no_leading_period = no_leading_period; - return 0; - } - - if (n != string_end && *n == L('.') && no_leading_period) - return FNM_NOMATCH; - - for (c = *p++; c == L('?') || c == L('*'); c = *p++) - { - if (*p == L('(') && (flags & FNM_EXTMATCH) != 0) - { - const CHAR *endp = END (p); - if (endp != p) - { - /* This is a pattern. Skip over it. */ - p = endp; - continue; - } - } - - if (c == L('?')) - { - /* A ? needs to match one character. */ - if (n == string_end) - /* There isn't another character; no match. */ - return FNM_NOMATCH; - else if (*n == L('/') - && __builtin_expect (flags & FNM_FILE_NAME, 0)) - /* A slash does not match a wildcard under - FNM_FILE_NAME. */ - return FNM_NOMATCH; - else - /* One character of the string is consumed in matching - this ? wildcard, so *??? won't match if there are - less than three characters. */ - ++n; - } - } - - if (c == L('\0')) - /* The wildcard(s) is/are the last element of the pattern. - If the name is a file name and contains another slash - this means it cannot match, unless the FNM_LEADING_DIR - flag is set. */ - { - int result = (flags & FNM_FILE_NAME) == 0 ? 0 : FNM_NOMATCH; - - if (flags & FNM_FILE_NAME) - { - if (flags & FNM_LEADING_DIR) - result = 0; - else - { - if (MEMCHR (n, L('/'), string_end - n) == NULL) - result = 0; - } - } - - return result; - } - else - { - const CHAR *endp; - struct STRUCT end; - - end.pattern = NULL; - endp = MEMCHR (n, (flags & FNM_FILE_NAME) ? L('/') : L('\0'), - string_end - n); - if (endp == NULL) - endp = string_end; - - if (c == L('[') - || (__builtin_expect (flags & FNM_EXTMATCH, 0) != 0 - && (c == L('@') || c == L('+') || c == L('!')) - && *p == L('('))) - { - int flags2 = ((flags & FNM_FILE_NAME) - ? flags : (flags & ~FNM_PERIOD)); - - for (--p; n < endp; ++n, no_leading_period = 0) - if (FCT (p, n, string_end, no_leading_period, flags2, - &end, alloca_used) == 0) - goto found; - } - else if (c == L('/') && (flags & FNM_FILE_NAME)) - { - while (n < string_end && *n != L('/')) - ++n; - if (n < string_end && *n == L('/') - && (FCT (p, n + 1, string_end, flags & FNM_PERIOD, flags, - NULL, alloca_used) == 0)) - return 0; - } - else - { - int flags2 = ((flags & FNM_FILE_NAME) - ? flags : (flags & ~FNM_PERIOD)); - - if (c == L('\\') && !(flags & FNM_NOESCAPE)) - c = *p; - c = FOLD (c); - for (--p; n < endp; ++n, no_leading_period = 0) - if (FOLD ((UCHAR) *n) == c - && (FCT (p, n, string_end, no_leading_period, flags2, - &end, alloca_used) == 0)) - { - found: - if (end.pattern == NULL) - return 0; - break; - } - if (end.pattern != NULL) - { - p = end.pattern; - n = end.string; - no_leading_period = end.no_leading_period; - continue; - } - } - } - - /* If we come here no match is possible with the wildcard. */ - return FNM_NOMATCH; - - case L('['): - { - /* Nonzero if the sense of the character class is inverted. */ - const CHAR *p_init = p; - const CHAR *n_init = n; - int not; - CHAR cold; - UCHAR fn; - - if (posixly_correct == 0) - posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; - - if (n == string_end) - return FNM_NOMATCH; - - if (*n == L('.') && no_leading_period) - return FNM_NOMATCH; - - if (*n == L('/') && (flags & FNM_FILE_NAME)) - /* `/' cannot be matched. */ - return FNM_NOMATCH; - - not = (*p == L('!') || (posixly_correct < 0 && *p == L('^'))); - if (not) - ++p; - - fn = FOLD ((UCHAR) *n); - - c = *p++; - for (;;) - { - if (!(flags & FNM_NOESCAPE) && c == L('\\')) - { - if (*p == L('\0')) - return FNM_NOMATCH; - c = FOLD ((UCHAR) *p); - ++p; - - goto normal_bracket; - } - else if (c == L('[') && *p == L(':')) - { - /* Leave room for the null. */ - CHAR str[CHAR_CLASS_MAX_LENGTH + 1]; - size_t c1 = 0; -#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) - wctype_t wt; -#endif - const CHAR *startp = p; - - for (;;) - { - if (c1 == CHAR_CLASS_MAX_LENGTH) - /* The name is too long and therefore the pattern - is ill-formed. */ - return FNM_NOMATCH; - - c = *++p; - if (c == L(':') && p[1] == L(']')) - { - p += 2; - break; - } - if (c < L('a') || c >= L('z')) - { - /* This cannot possibly be a character class name. - Match it as a normal range. */ - p = startp; - c = L('['); - goto normal_bracket; - } - str[c1++] = c; - } - str[c1] = L('\0'); - -#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) - wt = IS_CHAR_CLASS (str); - if (wt == 0) - /* Invalid character class name. */ - return FNM_NOMATCH; - -# if defined _LIBC && ! WIDE_CHAR_VERSION - /* The following code is glibc specific but does - there a good job in speeding up the code since - we can avoid the btowc() call. */ - if (_ISCTYPE ((UCHAR) *n, wt)) - goto matched; -# else - if (ISWCTYPE (BTOWC ((UCHAR) *n), wt)) - goto matched; -# endif + { + case L_('?'): + if (__glibc_unlikely (flags & FNM_EXTMATCH) && *p == '(') + { + int res = EXT (c, p, n, string_end, no_leading_period, + flags, alloca_used); + if (res != -1) + return res; + } + + if (n == string_end) + return FNM_NOMATCH; + else if (*n == L_('/') && (flags & FNM_FILE_NAME)) + return FNM_NOMATCH; + else if (*n == L_('.') && no_leading_period) + return FNM_NOMATCH; + break; + + case L_('\\'): + if (!(flags & FNM_NOESCAPE)) + { + c = *p++; + if (c == L_('\0')) + /* Trailing \ loses. */ + return FNM_NOMATCH; + c = FOLD (c); + } + if (n == string_end || FOLD ((UCHAR) *n) != c) + return FNM_NOMATCH; + break; + + case L_('*'): + if (__glibc_unlikely (flags & FNM_EXTMATCH) && *p == '(') + { + int res = EXT (c, p, n, string_end, no_leading_period, + flags, alloca_used); + if (res != -1) + return res; + } + else if (ends != NULL) + { + ends->pattern = p - 1; + ends->string = n; + ends->no_leading_period = no_leading_period; + return 0; + } + + if (n != string_end && *n == L_('.') && no_leading_period) + return FNM_NOMATCH; + + for (c = *p++; c == L_('?') || c == L_('*'); c = *p++) + { + if (*p == L_('(') && (flags & FNM_EXTMATCH) != 0) + { + const CHAR *endp = END (p); + if (endp != p) + { + /* This is a pattern. Skip over it. */ + p = endp; + continue; + } + } + + if (c == L_('?')) + { + /* A ? needs to match one character. */ + if (n == string_end) + /* There isn't another character; no match. */ + return FNM_NOMATCH; + else if (*n == L_('/') + && __glibc_unlikely (flags & FNM_FILE_NAME)) + /* A slash does not match a wildcard under + FNM_FILE_NAME. */ + return FNM_NOMATCH; + else + /* One character of the string is consumed in matching + this ? wildcard, so *??? won't match if there are + less than three characters. */ + ++n; + } + } + + if (c == L_('\0')) + /* The wildcard(s) is/are the last element of the pattern. + If the name is a file name and contains another slash + this means it cannot match, unless the FNM_LEADING_DIR + flag is set. */ + { + int result = (flags & FNM_FILE_NAME) == 0 ? 0 : FNM_NOMATCH; + + if (flags & FNM_FILE_NAME) + { + if (flags & FNM_LEADING_DIR) + result = 0; + else + { + if (MEMCHR (n, L_('/'), string_end - n) == NULL) + result = 0; + } + } + + return result; + } + else + { + const CHAR *endp; + struct STRUCT end; + + end.pattern = NULL; + endp = MEMCHR (n, (flags & FNM_FILE_NAME) ? L_('/') : L_('\0'), + string_end - n); + if (endp == NULL) + endp = string_end; + + if (c == L_('[') + || (__glibc_unlikely (flags & FNM_EXTMATCH) + && (c == L_('@') || c == L_('+') || c == L_('!')) + && *p == L_('('))) + { + int flags2 = ((flags & FNM_FILE_NAME) + ? flags : (flags & ~FNM_PERIOD)); + + for (--p; n < endp; ++n, no_leading_period = false) + if (FCT (p, n, string_end, no_leading_period, flags2, + &end, alloca_used) == 0) + goto found; + } + else if (c == L_('/') && (flags & FNM_FILE_NAME)) + { + while (n < string_end && *n != L_('/')) + ++n; + if (n < string_end && *n == L_('/') + && (FCT (p, n + 1, string_end, flags & FNM_PERIOD, flags, + NULL, alloca_used) == 0)) + return 0; + } + else + { + int flags2 = ((flags & FNM_FILE_NAME) + ? flags : (flags & ~FNM_PERIOD)); + + if (c == L_('\\') && !(flags & FNM_NOESCAPE)) + c = *p; + c = FOLD (c); + for (--p; n < endp; ++n, no_leading_period = false) + if (FOLD ((UCHAR) *n) == c + && (FCT (p, n, string_end, no_leading_period, flags2, + &end, alloca_used) == 0)) + { + found: + if (end.pattern == NULL) + return 0; + break; + } + if (end.pattern != NULL) + { + p = end.pattern; + n = end.string; + no_leading_period = end.no_leading_period; + continue; + } + } + } + + /* If we come here no match is possible with the wildcard. */ + return FNM_NOMATCH; + + case L_('['): + { + /* Nonzero if the sense of the character class is inverted. */ + const CHAR *p_init = p; + const CHAR *n_init = n; + bool not; + CHAR cold; + UCHAR fn; + + if (posixly_correct == 0) + posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; + + if (n == string_end) + return FNM_NOMATCH; + + if (*n == L_('.') && no_leading_period) + return FNM_NOMATCH; + + if (*n == L_('/') && (flags & FNM_FILE_NAME)) + /* '/' cannot be matched. */ + return FNM_NOMATCH; + + not = (*p == L_('!') || (posixly_correct < 0 && *p == L_('^'))); + if (not) + ++p; + + fn = FOLD ((UCHAR) *n); + + c = *p++; + for (;;) + { + if (!(flags & FNM_NOESCAPE) && c == L_('\\')) + { + if (*p == L_('\0')) + return FNM_NOMATCH; + c = FOLD ((UCHAR) *p); + ++p; + + goto normal_bracket; + } + else if (c == L_('[') && *p == L_(':')) + { + /* Leave room for the null. */ + CHAR str[CHAR_CLASS_MAX_LENGTH + 1]; + size_t c1 = 0; + wctype_t wt; + const CHAR *startp = p; + + for (;;) + { + if (c1 == CHAR_CLASS_MAX_LENGTH) + /* The name is too long and therefore the pattern + is ill-formed. */ + return FNM_NOMATCH; + + c = *++p; + if (c == L_(':') && p[1] == L_(']')) + { + p += 2; + break; + } + if (c < L_('a') || c >= L_('z')) + { + /* This cannot possibly be a character class name. + Match it as a normal range. */ + p = startp; + c = L_('['); + goto normal_bracket; + } + str[c1++] = c; + } + str[c1] = L_('\0'); + + wt = IS_CHAR_CLASS (str); + if (wt == 0) + /* Invalid character class name. */ + return FNM_NOMATCH; + +#if defined _LIBC && ! WIDE_CHAR_VERSION + /* The following code is glibc specific but does + there a good job in speeding up the code since + we can avoid the btowc() call. */ + if (_ISCTYPE ((UCHAR) *n, wt)) + goto matched; #else - if ((STREQ (str, L("alnum")) && ISALNUM ((UCHAR) *n)) - || (STREQ (str, L("alpha")) && ISALPHA ((UCHAR) *n)) - || (STREQ (str, L("blank")) && ISBLANK ((UCHAR) *n)) - || (STREQ (str, L("cntrl")) && ISCNTRL ((UCHAR) *n)) - || (STREQ (str, L("digit")) && ISDIGIT ((UCHAR) *n)) - || (STREQ (str, L("graph")) && ISGRAPH ((UCHAR) *n)) - || (STREQ (str, L("lower")) && ISLOWER ((UCHAR) *n)) - || (STREQ (str, L("print")) && ISPRINT ((UCHAR) *n)) - || (STREQ (str, L("punct")) && ISPUNCT ((UCHAR) *n)) - || (STREQ (str, L("space")) && ISSPACE ((UCHAR) *n)) - || (STREQ (str, L("upper")) && ISUPPER ((UCHAR) *n)) - || (STREQ (str, L("xdigit")) && ISXDIGIT ((UCHAR) *n))) - goto matched; + if (iswctype (BTOWC ((UCHAR) *n), wt)) + goto matched; #endif - c = *p++; - } + c = *p++; + } #ifdef _LIBC - else if (c == L('[') && *p == L('=')) - { - /* It's important that STR be a scalar variable rather - than a one-element array, because GCC (at least 4.9.2 - -O2 on x86-64) can be confused by the array and - diagnose a "used initialized" in a dead branch in the - findidx function. */ - UCHAR str; - uint32_t nrules = - _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); - const CHAR *startp = p; - - c = *++p; - if (c == L('\0')) - { - p = startp; - c = L('['); - goto normal_bracket; - } - str = c; - - c = *++p; - if (c != L('=') || p[1] != L(']')) - { - p = startp; - c = L('['); - goto normal_bracket; - } - p += 2; - - if (nrules == 0) - { - if ((UCHAR) *n == str) - goto matched; - } - else - { - const int32_t *table; + else if (c == L_('[') && *p == L_('=')) + { + /* It's important that STR be a scalar variable rather + than a one-element array, because GCC (at least 4.9.2 + -O2 on x86-64) can be confused by the array and + diagnose a "used initialized" in a dead branch in the + findidx function. */ + UCHAR str; + uint32_t nrules = + _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); + const CHAR *startp = p; + + c = *++p; + if (c == L_('\0')) + { + p = startp; + c = L_('['); + goto normal_bracket; + } + str = c; + + c = *++p; + if (c != L_('=') || p[1] != L_(']')) + { + p = startp; + c = L_('['); + goto normal_bracket; + } + p += 2; + + if (nrules == 0) + { + if ((UCHAR) *n == str) + goto matched; + } + else + { + const int32_t *table; # if WIDE_CHAR_VERSION - const int32_t *weights; - const wint_t *extra; + const int32_t *weights; + const wint_t *extra; # else - const unsigned char *weights; - const unsigned char *extra; + const unsigned char *weights; + const unsigned char *extra; # endif - const int32_t *indirect; - int32_t idx; - const UCHAR *cp = (const UCHAR *) &str; + const int32_t *indirect; + int32_t idx; + const UCHAR *cp = (const UCHAR *) &str; # if WIDE_CHAR_VERSION - table = (const int32_t *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEWC); - weights = (const int32_t *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTWC); - extra = (const wint_t *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAWC); - indirect = (const int32_t *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTWC); + table = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEWC); + weights = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTWC); + extra = (const wint_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAWC); + indirect = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTWC); # else - table = (const int32_t *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); - weights = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB); - extra = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); - indirect = (const int32_t *) - _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); + table = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); + weights = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB); + extra = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); + indirect = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); # endif - idx = FINDIDX (table, indirect, extra, &cp, 1); - if (idx != 0) - { - /* We found a table entry. Now see whether the - character we are currently at has the same - equivalance class value. */ - int len = weights[idx & 0xffffff]; - int32_t idx2; - const UCHAR *np = (const UCHAR *) n; - - idx2 = FINDIDX (table, indirect, extra, - &np, string_end - n); - if (idx2 != 0 - && (idx >> 24) == (idx2 >> 24) - && len == weights[idx2 & 0xffffff]) - { - int cnt = 0; - - idx &= 0xffffff; - idx2 &= 0xffffff; - - while (cnt < len - && (weights[idx + 1 + cnt] - == weights[idx2 + 1 + cnt])) - ++cnt; - - if (cnt == len) - goto matched; - } - } - } - - c = *p++; - } + idx = FINDIDX (table, indirect, extra, &cp, 1); + if (idx != 0) + { + /* We found a table entry. Now see whether the + character we are currently at has the same + equivalence class value. */ + int len = weights[idx & 0xffffff]; + int32_t idx2; + const UCHAR *np = (const UCHAR *) n; + + idx2 = FINDIDX (table, indirect, extra, + &np, string_end - n); + if (idx2 != 0 + && (idx >> 24) == (idx2 >> 24) + && len == weights[idx2 & 0xffffff]) + { + int cnt = 0; + + idx &= 0xffffff; + idx2 &= 0xffffff; + + while (cnt < len + && (weights[idx + 1 + cnt] + == weights[idx2 + 1 + cnt])) + ++cnt; + + if (cnt == len) + goto matched; + } + } + } + + c = *p++; + } #endif - else if (c == L('\0')) - { - /* [ unterminated, treat as normal character. */ - p = p_init; - n = n_init; - c = L('['); - goto normal_match; - } - else - { - int is_range = 0; + else if (c == L_('\0')) + { + /* [ unterminated, treat as normal character. */ + p = p_init; + n = n_init; + c = L_('['); + goto normal_match; + } + else + { + bool is_range = false; #ifdef _LIBC - int is_seqval = 0; - - if (c == L('[') && *p == L('.')) - { - uint32_t nrules = - _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); - const CHAR *startp = p; - size_t c1 = 0; - - while (1) - { - c = *++p; - if (c == L('.') && p[1] == L(']')) - { - p += 2; - break; - } - if (c == '\0') - return FNM_NOMATCH; - ++c1; - } - - /* We have to handling the symbols differently in - ranges since then the collation sequence is - important. */ - is_range = *p == L('-') && p[1] != L('\0'); - - if (nrules == 0) - { - /* There are no names defined in the collation - data. Therefore we only accept the trivial - names consisting of the character itself. */ - if (c1 != 1) - return FNM_NOMATCH; - - if (!is_range && *n == startp[1]) - goto matched; - - cold = startp[1]; - c = *p++; - } - else - { - int32_t table_size; - const int32_t *symb_table; - const unsigned char *extra; - int32_t idx; - int32_t elem; + bool is_seqval = false; + + if (c == L_('[') && *p == L_('.')) + { + uint32_t nrules = + _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); + const CHAR *startp = p; + size_t c1 = 0; + + while (1) + { + c = *++p; + if (c == L_('.') && p[1] == L_(']')) + { + p += 2; + break; + } + if (c == '\0') + return FNM_NOMATCH; + ++c1; + } + + /* We have to handling the symbols differently in + ranges since then the collation sequence is + important. */ + is_range = *p == L_('-') && p[1] != L_('\0'); + + if (nrules == 0) + { + /* There are no names defined in the collation + data. Therefore we only accept the trivial + names consisting of the character itself. */ + if (c1 != 1) + return FNM_NOMATCH; + + if (!is_range && *n == startp[1]) + goto matched; + + cold = startp[1]; + c = *p++; + } + else + { + int32_t table_size; + const int32_t *symb_table; + const unsigned char *extra; + int32_t idx; + int32_t elem; # if WIDE_CHAR_VERSION - CHAR *wextra; + CHAR *wextra; # endif - table_size = - _NL_CURRENT_WORD (LC_COLLATE, - _NL_COLLATE_SYMB_HASH_SIZEMB); - symb_table = (const int32_t *) - _NL_CURRENT (LC_COLLATE, - _NL_COLLATE_SYMB_TABLEMB); - extra = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, - _NL_COLLATE_SYMB_EXTRAMB); - - for (elem = 0; elem < table_size; elem++) - if (symb_table[2 * elem] != 0) - { - idx = symb_table[2 * elem + 1]; - /* Skip the name of collating element. */ - idx += 1 + extra[idx]; + table_size = + _NL_CURRENT_WORD (LC_COLLATE, + _NL_COLLATE_SYMB_HASH_SIZEMB); + symb_table = (const int32_t *) + _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_SYMB_TABLEMB); + extra = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_SYMB_EXTRAMB); + + for (elem = 0; elem < table_size; elem++) + if (symb_table[2 * elem] != 0) + { + idx = symb_table[2 * elem + 1]; + /* Skip the name of collating element. */ + idx += 1 + extra[idx]; # if WIDE_CHAR_VERSION - /* Skip the byte sequence of the - collating element. */ - idx += 1 + extra[idx]; - /* Adjust for the alignment. */ - idx = (idx + 3) & ~3; - - wextra = (CHAR *) &extra[idx + 4]; - - if (/* Compare the length of the sequence. */ - c1 == wextra[0] - /* Compare the wide char sequence. */ - && WMEMCMP (startp + 1, &wextra[1], - c1) == 0) - /* Yep, this is the entry. */ - break; + /* Skip the byte sequence of the + collating element. */ + idx += 1 + extra[idx]; + /* Adjust for the alignment. */ + idx = (idx + 3) & ~3; + + wextra = (CHAR *) &extra[idx + 4]; + + if (/* Compare the length of the sequence. */ + c1 == wextra[0] + /* Compare the wide char sequence. */ + && (__wmemcmp (startp + 1, &wextra[1], + c1) + == 0)) + /* Yep, this is the entry. */ + break; # else - if (/* Compare the length of the sequence. */ - c1 == extra[idx] - /* Compare the byte sequence. */ - && memcmp (startp + 1, - &extra[idx + 1], c1) == 0) - /* Yep, this is the entry. */ - break; + if (/* Compare the length of the sequence. */ + c1 == extra[idx] + /* Compare the byte sequence. */ + && memcmp (startp + 1, + &extra[idx + 1], c1) == 0) + /* Yep, this is the entry. */ + break; # endif - } + } - if (elem < table_size) - { - /* Compare the byte sequence but only if - this is not part of a range. */ - if (! is_range + if (elem < table_size) + { + /* Compare the byte sequence but only if + this is not part of a range. */ + if (! is_range # if WIDE_CHAR_VERSION - && WMEMCMP (n, &wextra[1], c1) == 0 + && __wmemcmp (n, &wextra[1], c1) == 0 # else - && memcmp (n, &extra[idx + 1], c1) == 0 + && memcmp (n, &extra[idx + 1], c1) == 0 # endif - ) - { - n += c1 - 1; - goto matched; - } - - /* Get the collation sequence value. */ - is_seqval = 1; + ) + { + n += c1 - 1; + goto matched; + } + + /* Get the collation sequence value. */ + is_seqval = true; # if WIDE_CHAR_VERSION - cold = wextra[1 + wextra[0]]; + cold = wextra[1 + wextra[0]]; # else - idx += 1 + extra[idx]; - /* Adjust for the alignment. */ - idx = (idx + 3) & ~3; - cold = *((int32_t *) &extra[idx]); + idx += 1 + extra[idx]; + /* Adjust for the alignment. */ + idx = (idx + 3) & ~3; + cold = *((int32_t *) &extra[idx]); # endif - c = *p++; - } - else if (c1 == 1) - { - /* No valid character. Match it as a - single byte. */ - if (!is_range && *n == startp[1]) - goto matched; - - cold = startp[1]; - c = *p++; - } - else - return FNM_NOMATCH; - } - } - else + c = *p++; + } + else if (c1 == 1) + { + /* No valid character. Match it as a + single byte. */ + if (!is_range && *n == startp[1]) + goto matched; + + cold = startp[1]; + c = *p++; + } + else + return FNM_NOMATCH; + } + } + else #endif - { - c = FOLD (c); - normal_bracket: - - /* We have to handling the symbols differently in - ranges since then the collation sequence is - important. */ - is_range = (*p == L('-') && p[1] != L('\0') - && p[1] != L(']')); - - if (!is_range && c == fn) - goto matched; - - /* This is needed if we goto normal_bracket; from - outside of is_seqval's scope. */ - is_seqval = 0; - cold = c; - c = *p++; - } - - if (c == L('-') && *p != L(']')) - { + { + c = FOLD (c); + normal_bracket: + + /* We have to handling the symbols differently in + ranges since then the collation sequence is + important. */ + is_range = (*p == L_('-') && p[1] != L_('\0') + && p[1] != L_(']')); + + if (!is_range && c == fn) + goto matched; + +#if _LIBC + /* This is needed if we goto normal_bracket; from + outside of is_seqval's scope. */ + is_seqval = false; +#endif + cold = c; + c = *p++; + } + + if (c == L_('-') && *p != L_(']')) + { #if _LIBC - /* We have to find the collation sequence - value for C. Collation sequence is nothing - we can regularly access. The sequence - value is defined by the order in which the - definitions of the collation values for the - various characters appear in the source - file. A strange concept, nowhere - documented. */ - uint32_t fcollseq; - uint32_t lcollseq; - UCHAR cend = *p++; + /* We have to find the collation sequence + value for C. Collation sequence is nothing + we can regularly access. The sequence + value is defined by the order in which the + definitions of the collation values for the + various characters appear in the source + file. A strange concept, nowhere + documented. */ + uint32_t fcollseq; + uint32_t lcollseq; + UCHAR cend = *p++; # if WIDE_CHAR_VERSION - /* Search in the `names' array for the characters. */ - fcollseq = __collseq_table_lookup (collseq, fn); - if (fcollseq == ~((uint32_t) 0)) - /* XXX We don't know anything about the character - we are supposed to match. This means we are - failing. */ - goto range_not_matched; - - if (is_seqval) - lcollseq = cold; - else - lcollseq = __collseq_table_lookup (collseq, cold); + /* Search in the 'names' array for the characters. */ + fcollseq = __collseq_table_lookup (collseq, fn); + if (fcollseq == ~((uint32_t) 0)) + /* XXX We don't know anything about the character + we are supposed to match. This means we are + failing. */ + goto range_not_matched; + + if (is_seqval) + lcollseq = cold; + else + lcollseq = __collseq_table_lookup (collseq, cold); # else - fcollseq = collseq[fn]; - lcollseq = is_seqval ? cold : collseq[(UCHAR) cold]; + fcollseq = collseq[fn]; + lcollseq = is_seqval ? cold : collseq[(UCHAR) cold]; # endif - is_seqval = 0; - if (cend == L('[') && *p == L('.')) - { - uint32_t nrules = - _NL_CURRENT_WORD (LC_COLLATE, - _NL_COLLATE_NRULES); - const CHAR *startp = p; - size_t c1 = 0; - - while (1) - { - c = *++p; - if (c == L('.') && p[1] == L(']')) - { - p += 2; - break; - } - if (c == '\0') - return FNM_NOMATCH; - ++c1; - } - - if (nrules == 0) - { - /* There are no names defined in the - collation data. Therefore we only - accept the trivial names consisting - of the character itself. */ - if (c1 != 1) - return FNM_NOMATCH; - - cend = startp[1]; - } - else - { - int32_t table_size; - const int32_t *symb_table; - const unsigned char *extra; - int32_t idx; - int32_t elem; + is_seqval = false; + if (cend == L_('[') && *p == L_('.')) + { + uint32_t nrules = + _NL_CURRENT_WORD (LC_COLLATE, + _NL_COLLATE_NRULES); + const CHAR *startp = p; + size_t c1 = 0; + + while (1) + { + c = *++p; + if (c == L_('.') && p[1] == L_(']')) + { + p += 2; + break; + } + if (c == '\0') + return FNM_NOMATCH; + ++c1; + } + + if (nrules == 0) + { + /* There are no names defined in the + collation data. Therefore we only + accept the trivial names consisting + of the character itself. */ + if (c1 != 1) + return FNM_NOMATCH; + + cend = startp[1]; + } + else + { + int32_t table_size; + const int32_t *symb_table; + const unsigned char *extra; + int32_t idx; + int32_t elem; # if WIDE_CHAR_VERSION - CHAR *wextra; + CHAR *wextra; # endif - table_size = - _NL_CURRENT_WORD (LC_COLLATE, - _NL_COLLATE_SYMB_HASH_SIZEMB); - symb_table = (const int32_t *) - _NL_CURRENT (LC_COLLATE, - _NL_COLLATE_SYMB_TABLEMB); - extra = (const unsigned char *) - _NL_CURRENT (LC_COLLATE, - _NL_COLLATE_SYMB_EXTRAMB); - - for (elem = 0; elem < table_size; elem++) - if (symb_table[2 * elem] != 0) - { - idx = symb_table[2 * elem + 1]; - /* Skip the name of collating - element. */ - idx += 1 + extra[idx]; + table_size = + _NL_CURRENT_WORD (LC_COLLATE, + _NL_COLLATE_SYMB_HASH_SIZEMB); + symb_table = (const int32_t *) + _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_SYMB_TABLEMB); + extra = (const unsigned char *) + _NL_CURRENT (LC_COLLATE, + _NL_COLLATE_SYMB_EXTRAMB); + + for (elem = 0; elem < table_size; elem++) + if (symb_table[2 * elem] != 0) + { + idx = symb_table[2 * elem + 1]; + /* Skip the name of collating + element. */ + idx += 1 + extra[idx]; # if WIDE_CHAR_VERSION - /* Skip the byte sequence of the - collating element. */ - idx += 1 + extra[idx]; - /* Adjust for the alignment. */ - idx = (idx + 3) & ~3; - - wextra = (CHAR *) &extra[idx + 4]; - - if (/* Compare the length of the - sequence. */ - c1 == wextra[0] - /* Compare the wide char sequence. */ - && WMEMCMP (startp + 1, &wextra[1], - c1) == 0) - /* Yep, this is the entry. */ - break; + /* Skip the byte sequence of the + collating element. */ + idx += 1 + extra[idx]; + /* Adjust for the alignment. */ + idx = (idx + 3) & ~3; + + wextra = (CHAR *) &extra[idx + 4]; + + if (/* Compare the length of the + sequence. */ + c1 == wextra[0] + /* Compare the wide char sequence. */ + && (__wmemcmp (startp + 1, + &wextra[1], c1) + == 0)) + /* Yep, this is the entry. */ + break; # else - if (/* Compare the length of the - sequence. */ - c1 == extra[idx] - /* Compare the byte sequence. */ - && memcmp (startp + 1, - &extra[idx + 1], c1) == 0) - /* Yep, this is the entry. */ - break; + if (/* Compare the length of the + sequence. */ + c1 == extra[idx] + /* Compare the byte sequence. */ + && memcmp (startp + 1, + &extra[idx + 1], c1) == 0) + /* Yep, this is the entry. */ + break; # endif - } + } - if (elem < table_size) - { - /* Get the collation sequence value. */ - is_seqval = 1; + if (elem < table_size) + { + /* Get the collation sequence value. */ + is_seqval = true; # if WIDE_CHAR_VERSION - cend = wextra[1 + wextra[0]]; + cend = wextra[1 + wextra[0]]; # else - idx += 1 + extra[idx]; - /* Adjust for the alignment. */ - idx = (idx + 3) & ~3; - cend = *((int32_t *) &extra[idx]); + idx += 1 + extra[idx]; + /* Adjust for the alignment. */ + idx = (idx + 3) & ~3; + cend = *((int32_t *) &extra[idx]); # endif - } - else if (c1 == 1) - { - cend = startp[1]; - c = *p++; - } - else - return FNM_NOMATCH; - } - } - else - { - if (!(flags & FNM_NOESCAPE) && cend == L('\\')) - cend = *p++; - if (cend == L('\0')) - return FNM_NOMATCH; - cend = FOLD (cend); - } - - /* XXX It is not entirely clear to me how to handle - characters which are not mentioned in the - collation specification. */ - if ( + } + else if (c1 == 1) + { + cend = startp[1]; + c = *p++; + } + else + return FNM_NOMATCH; + } + } + else + { + if (!(flags & FNM_NOESCAPE) && cend == L_('\\')) + cend = *p++; + if (cend == L_('\0')) + return FNM_NOMATCH; + cend = FOLD (cend); + } + + /* XXX It is not entirely clear to me how to handle + characters which are not mentioned in the + collation specification. */ + if ( # if WIDE_CHAR_VERSION - lcollseq == 0xffffffff || + lcollseq == 0xffffffff || # endif - lcollseq <= fcollseq) - { - /* We have to look at the upper bound. */ - uint32_t hcollseq; - - if (is_seqval) - hcollseq = cend; - else - { + lcollseq <= fcollseq) + { + /* We have to look at the upper bound. */ + uint32_t hcollseq; + + if (is_seqval) + hcollseq = cend; + else + { # if WIDE_CHAR_VERSION - hcollseq = - __collseq_table_lookup (collseq, cend); - if (hcollseq == ~((uint32_t) 0)) - { - /* Hum, no information about the upper - bound. The matching succeeds if the - lower bound is matched exactly. */ - if (lcollseq != fcollseq) - goto range_not_matched; - - goto matched; - } + hcollseq = + __collseq_table_lookup (collseq, cend); + if (hcollseq == ~((uint32_t) 0)) + { + /* Hum, no information about the upper + bound. The matching succeeds if the + lower bound is matched exactly. */ + if (lcollseq != fcollseq) + goto range_not_matched; + + goto matched; + } # else - hcollseq = collseq[cend]; + hcollseq = collseq[cend]; # endif - } + } - if (lcollseq <= hcollseq && fcollseq <= hcollseq) - goto matched; - } + if (lcollseq <= hcollseq && fcollseq <= hcollseq) + goto matched; + } # if WIDE_CHAR_VERSION - range_not_matched: + range_not_matched: # endif #else - /* We use a boring value comparison of the character - values. This is better than comparing using - `strcoll' since the latter would have surprising - and sometimes fatal consequences. */ - UCHAR cend = *p++; - - if (!(flags & FNM_NOESCAPE) && cend == L('\\')) - cend = *p++; - if (cend == L('\0')) - return FNM_NOMATCH; - - /* It is a range. */ - if (cold <= fn && fn <= cend) - goto matched; + /* We use a boring value comparison of the character + values. This is better than comparing using + 'strcoll' since the latter would have surprising + and sometimes fatal consequences. */ + UCHAR cend = *p++; + + if (!(flags & FNM_NOESCAPE) && cend == L_('\\')) + cend = *p++; + if (cend == L_('\0')) + return FNM_NOMATCH; + + /* It is a range. */ + if ((UCHAR) cold <= fn && fn <= cend) + goto matched; #endif - c = *p++; - } - } - - if (c == L(']')) - break; - } - - if (!not) - return FNM_NOMATCH; - break; - - matched: - /* Skip the rest of the [...] that already matched. */ - while ((c = *p++) != L (']')) - { - if (c == L('\0')) - /* [... (unterminated) loses. */ - return FNM_NOMATCH; - - if (!(flags & FNM_NOESCAPE) && c == L('\\')) - { - if (*p == L('\0')) - return FNM_NOMATCH; - /* XXX 1003.2d11 is unclear if this is right. */ - ++p; - } - else if (c == L('[') && *p == L(':')) - { - int c1 = 0; - const CHAR *startp = p; - - while (1) - { - c = *++p; - if (++c1 == CHAR_CLASS_MAX_LENGTH) - return FNM_NOMATCH; - - if (*p == L(':') && p[1] == L(']')) - break; - - if (c < L('a') || c >= L('z')) - { - p = startp - 2; - break; - } - } - p += 2; - } - else if (c == L('[') && *p == L('=')) - { - c = *++p; - if (c == L('\0')) - return FNM_NOMATCH; - c = *++p; - if (c != L('=') || p[1] != L(']')) - return FNM_NOMATCH; - p += 2; - } - else if (c == L('[') && *p == L('.')) - { - while (1) - { - c = *++p; - if (c == L('\0')) - return FNM_NOMATCH; - - if (c == L('.') && p[1] == L(']')) - break; - } - p += 2; - } - } - if (not) - return FNM_NOMATCH; - } - break; - - case L('+'): - case L('@'): - case L('!'): - if (__builtin_expect (flags & FNM_EXTMATCH, 0) && *p == '(') - { - int res = EXT (c, p, n, string_end, no_leading_period, flags, - alloca_used); - if (res != -1) - return res; - } - goto normal_match; - - case L('/'): - if (NO_LEADING_PERIOD (flags)) - { - if (n == string_end || c != (UCHAR) *n) - return FNM_NOMATCH; - - new_no_leading_period = 1; - break; - } - /* FALLTHROUGH */ - default: - normal_match: - if (n == string_end || c != FOLD ((UCHAR) *n)) - return FNM_NOMATCH; - } + c = *p++; + } + } + + if (c == L_(']')) + break; + } + + if (!not) + return FNM_NOMATCH; + break; + + matched: + /* Skip the rest of the [...] that already matched. */ + while ((c = *p++) != L_(']')) + { + if (c == L_('\0')) + /* [... (unterminated) loses. */ + return FNM_NOMATCH; + + if (!(flags & FNM_NOESCAPE) && c == L_('\\')) + { + if (*p == L_('\0')) + return FNM_NOMATCH; + /* XXX 1003.2d11 is unclear if this is right. */ + ++p; + } + else if (c == L_('[') && *p == L_(':')) + { + int c1 = 0; + const CHAR *startp = p; + + while (1) + { + c = *++p; + if (++c1 == CHAR_CLASS_MAX_LENGTH) + return FNM_NOMATCH; + + if (*p == L_(':') && p[1] == L_(']')) + break; + + if (c < L_('a') || c >= L_('z')) + { + p = startp - 2; + break; + } + } + p += 2; + } + else if (c == L_('[') && *p == L_('=')) + { + c = *++p; + if (c == L_('\0')) + return FNM_NOMATCH; + c = *++p; + if (c != L_('=') || p[1] != L_(']')) + return FNM_NOMATCH; + p += 2; + } + else if (c == L_('[') && *p == L_('.')) + { + while (1) + { + c = *++p; + if (c == L_('\0')) + return FNM_NOMATCH; + + if (c == L_('.') && p[1] == L_(']')) + break; + } + p += 2; + } + } + if (not) + return FNM_NOMATCH; + } + break; + + case L_('+'): + case L_('@'): + case L_('!'): + if (__glibc_unlikely (flags & FNM_EXTMATCH) && *p == '(') + { + int res = EXT (c, p, n, string_end, no_leading_period, flags, + alloca_used); + if (res != -1) + return res; + } + goto normal_match; + + case L_('/'): + if (NO_LEADING_PERIOD (flags)) + { + if (n == string_end || c != (UCHAR) *n) + return FNM_NOMATCH; + + new_no_leading_period = true; + break; + } + FALLTHROUGH; + default: + normal_match: + if (n == string_end || c != FOLD ((UCHAR) *n)) + return FNM_NOMATCH; + } no_leading_period = new_no_leading_period; ++n; @@ -934,7 +922,7 @@ FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end, if (n == string_end) return 0; - if ((flags & FNM_LEADING_DIR) && n != string_end && *n == L('/')) + if ((flags & FNM_LEADING_DIR) && n != string_end && *n == L_('/')) /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ return 0; @@ -948,37 +936,37 @@ END (const CHAR *pattern) const CHAR *p = pattern; while (1) - if (*++p == L('\0')) + if (*++p == L_('\0')) /* This is an invalid pattern. */ return pattern; - else if (*p == L('[')) + else if (*p == L_('[')) { - /* Handle brackets special. */ - if (posixly_correct == 0) - posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; - - /* Skip the not sign. We have to recognize it because of a possibly - following ']'. */ - if (*++p == L('!') || (posixly_correct < 0 && *p == L('^'))) - ++p; - /* A leading ']' is recognized as such. */ - if (*p == L(']')) - ++p; - /* Skip over all characters of the list. */ - while (*p != L(']')) - if (*p++ == L('\0')) - /* This is no valid pattern. */ - return pattern; + /* Handle brackets special. */ + if (posixly_correct == 0) + posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; + + /* Skip the not sign. We have to recognize it because of a possibly + following ']'. */ + if (*++p == L_('!') || (posixly_correct < 0 && *p == L_('^'))) + ++p; + /* A leading ']' is recognized as such. */ + if (*p == L_(']')) + ++p; + /* Skip over all characters of the list. */ + while (*p != L_(']')) + if (*p++ == L_('\0')) + /* This is no valid pattern. */ + return pattern; } - else if ((*p == L('?') || *p == L('*') || *p == L('+') || *p == L('@') - || *p == L('!')) && p[1] == L('(')) + else if ((*p == L_('?') || *p == L_('*') || *p == L_('+') || *p == L_('@') + || *p == L_('!')) && p[1] == L_('(')) { - p = END (p + 1); - if (*p == L('\0')) - /* This is an invalid pattern. */ - return pattern; + p = END (p + 1); + if (*p == L_('\0')) + /* This is an invalid pattern. */ + return pattern; } - else if (*p == L(')')) + else if (*p == L_(')')) break; return p + 1; @@ -987,19 +975,19 @@ END (const CHAR *pattern) static int EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end, - int no_leading_period, int flags, size_t alloca_used) + bool no_leading_period, int flags, size_t alloca_used) { const CHAR *startp; - int level; + ssize_t level; struct patternlist { struct patternlist *next; CHAR malloced; - CHAR str[0]; + CHAR str[]; } *list = NULL; struct patternlist **lastp = &list; size_t pattern_len = STRLEN (pattern); - int any_malloced = 0; + bool any_malloced = false; const CHAR *p; const CHAR *rs; int retval = 0; @@ -1007,174 +995,180 @@ EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end, /* Parse the pattern. Store the individual parts in the list. */ level = 0; for (startp = p = pattern + 1; level >= 0; ++p) - if (*p == L('\0')) + if (*p == L_('\0')) { - /* This is an invalid pattern. */ - retval = -1; - goto out; + /* This is an invalid pattern. */ + retval = -1; + goto out; } - else if (*p == L('[')) + else if (*p == L_('[')) { - /* Handle brackets special. */ - if (posixly_correct == 0) - posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; - - /* Skip the not sign. We have to recognize it because of a possibly - following ']'. */ - if (*++p == L('!') || (posixly_correct < 0 && *p == L('^'))) - ++p; - /* A leading ']' is recognized as such. */ - if (*p == L(']')) - ++p; - /* Skip over all characters of the list. */ - while (*p != L(']')) - if (*p++ == L('\0')) - { - /* This is no valid pattern. */ - retval = -1; - goto out; - } + /* Handle brackets special. */ + if (posixly_correct == 0) + posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; + + /* Skip the not sign. We have to recognize it because of a possibly + following ']'. */ + if (*++p == L_('!') || (posixly_correct < 0 && *p == L_('^'))) + ++p; + /* A leading ']' is recognized as such. */ + if (*p == L_(']')) + ++p; + /* Skip over all characters of the list. */ + while (*p != L_(']')) + if (*p++ == L_('\0')) + { + /* This is no valid pattern. */ + retval = -1; + goto out; + } } - else if ((*p == L('?') || *p == L('*') || *p == L('+') || *p == L('@') - || *p == L('!')) && p[1] == L('(')) + else if ((*p == L_('?') || *p == L_('*') || *p == L_('+') || *p == L_('@') + || *p == L_('!')) && p[1] == L_('(')) /* Remember the nesting level. */ ++level; - else if (*p == L(')')) + else if (*p == L_(')')) { - if (level-- == 0) - { - /* This means we found the end of the pattern. */ + if (level-- == 0) + { + /* This means we found the end of the pattern. */ #define NEW_PATTERN \ - struct patternlist *newp; \ - size_t slen = (opt == L('?') || opt == L('@') \ - ? pattern_len : (p - startp + 1)); \ - slen = sizeof (struct patternlist) + (slen * sizeof (CHAR)); \ - int malloced = ! __libc_use_alloca (alloca_used + slen); \ - if (__builtin_expect (malloced, 0)) \ - { \ - newp = malloc (slen); \ - if (newp == NULL) \ - { \ - retval = -2; \ - goto out; \ - } \ - any_malloced = 1; \ - } \ - else \ - newp = alloca_account (slen, alloca_used); \ - newp->next = NULL; \ - newp->malloced = malloced; \ - *((CHAR *) MEMPCPY (newp->str, startp, p - startp)) = L('\0'); \ - *lastp = newp; \ - lastp = &newp->next - NEW_PATTERN; - } + struct patternlist *newp; \ + size_t plen = (opt == L_('?') || opt == L_('@') \ + ? pattern_len : (p - startp + 1UL)); \ + idx_t slen = FLEXSIZEOF (struct patternlist, str, 0); \ + idx_t new_used = alloca_used + slen; \ + idx_t plensize; \ + if (INT_MULTIPLY_WRAPV (plen, sizeof (CHAR), &plensize) \ + || INT_ADD_WRAPV (new_used, plensize, &new_used)) \ + { \ + retval = -2; \ + goto out; \ + } \ + slen += plensize; \ + bool malloced = ! __libc_use_alloca (new_used); \ + if (__glibc_unlikely (malloced)) \ + { \ + newp = malloc (slen); \ + if (newp == NULL) \ + { \ + retval = -2; \ + goto out; \ + } \ + any_malloced = true; \ + } \ + else \ + newp = alloca_account (slen, alloca_used); \ + newp->next = NULL; \ + newp->malloced = malloced; \ + *((CHAR *) MEMPCPY (newp->str, startp, p - startp)) = L_('\0'); \ + *lastp = newp; \ + lastp = &newp->next + NEW_PATTERN; + } } - else if (*p == L('|')) + else if (*p == L_('|')) { - if (level == 0) - { - NEW_PATTERN; - startp = p + 1; - } + if (level == 0) + { + NEW_PATTERN; + startp = p + 1; + } } assert (list != NULL); - assert (p[-1] == L(')')); + assert (p[-1] == L_(')')); #undef NEW_PATTERN switch (opt) { - case L('*'): + case L_('*'): if (FCT (p, string, string_end, no_leading_period, flags, NULL, - alloca_used) == 0) - goto success; - /* FALLTHROUGH */ - - case L('+'): + alloca_used) == 0) + goto success; + FALLTHROUGH; + case L_('+'): do - { - for (rs = string; rs <= string_end; ++rs) - /* First match the prefix with the current pattern with the - current pattern. */ - if (FCT (list->str, string, rs, no_leading_period, - flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD, - NULL, alloca_used) == 0 - /* This was successful. Now match the rest with the rest - of the pattern. */ - && (FCT (p, rs, string_end, - rs == string - ? no_leading_period - : rs[-1] == '/' && NO_LEADING_PERIOD (flags) ? 1 : 0, - flags & FNM_FILE_NAME - ? flags : flags & ~FNM_PERIOD, NULL, alloca_used) == 0 - /* This didn't work. Try the whole pattern. */ - || (rs != string - && FCT (pattern - 1, rs, string_end, - rs == string - ? no_leading_period - : (rs[-1] == '/' && NO_LEADING_PERIOD (flags) - ? 1 : 0), - flags & FNM_FILE_NAME - ? flags : flags & ~FNM_PERIOD, NULL, - alloca_used) == 0))) - /* It worked. Signal success. */ - goto success; - } + { + for (rs = string; rs <= string_end; ++rs) + /* First match the prefix with the current pattern with the + current pattern. */ + if (FCT (list->str, string, rs, no_leading_period, + flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD, + NULL, alloca_used) == 0 + /* This was successful. Now match the rest with the rest + of the pattern. */ + && (FCT (p, rs, string_end, + rs == string + ? no_leading_period + : rs[-1] == '/' && NO_LEADING_PERIOD (flags), + flags & FNM_FILE_NAME + ? flags : flags & ~FNM_PERIOD, NULL, alloca_used) == 0 + /* This didn't work. Try the whole pattern. */ + || (rs != string + && FCT (pattern - 1, rs, string_end, + rs == string + ? no_leading_period + : rs[-1] == '/' && NO_LEADING_PERIOD (flags), + flags & FNM_FILE_NAME + ? flags : flags & ~FNM_PERIOD, NULL, + alloca_used) == 0))) + /* It worked. Signal success. */ + goto success; + } while ((list = list->next) != NULL); /* None of the patterns lead to a match. */ retval = FNM_NOMATCH; break; - case L('?'): + case L_('?'): if (FCT (p, string, string_end, no_leading_period, flags, NULL, - alloca_used) == 0) - goto success; - /* FALLTHROUGH */ - - case L('@'): + alloca_used) == 0) + goto success; + FALLTHROUGH; + case L_('@'): do - /* I cannot believe it but `strcat' is actually acceptable - here. Match the entire string with the prefix from the - pattern list and the rest of the pattern following the - pattern list. */ - if (FCT (STRCAT (list->str, p), string, string_end, - no_leading_period, - flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD, - NULL, alloca_used) == 0) - /* It worked. Signal success. */ - goto success; + /* I cannot believe it but 'strcat' is actually acceptable + here. Match the entire string with the prefix from the + pattern list and the rest of the pattern following the + pattern list. */ + if (FCT (STRCAT (list->str, p), string, string_end, + no_leading_period, + flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD, + NULL, alloca_used) == 0) + /* It worked. Signal success. */ + goto success; while ((list = list->next) != NULL); /* None of the patterns lead to a match. */ retval = FNM_NOMATCH; break; - case L('!'): + case L_('!'): for (rs = string; rs <= string_end; ++rs) - { - struct patternlist *runp; - - for (runp = list; runp != NULL; runp = runp->next) - if (FCT (runp->str, string, rs, no_leading_period, - flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD, - NULL, alloca_used) == 0) - break; - - /* If none of the patterns matched see whether the rest does. */ - if (runp == NULL - && (FCT (p, rs, string_end, - rs == string - ? no_leading_period - : rs[-1] == '/' && NO_LEADING_PERIOD (flags) ? 1 : 0, - flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD, - NULL, alloca_used) == 0)) - /* This is successful. */ - goto success; - } + { + struct patternlist *runp; + + for (runp = list; runp != NULL; runp = runp->next) + if (FCT (runp->str, string, rs, no_leading_period, + flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD, + NULL, alloca_used) == 0) + break; + + /* If none of the patterns matched see whether the rest does. */ + if (runp == NULL + && (FCT (p, rs, string_end, + rs == string + ? no_leading_period + : rs[-1] == '/' && NO_LEADING_PERIOD (flags), + flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD, + NULL, alloca_used) == 0)) + /* This is successful. */ + goto success; + } /* None of the patterns together with the rest of the pattern - lead to a match. */ + lead to a match. */ retval = FNM_NOMATCH; break; @@ -1189,10 +1183,10 @@ EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end, if (any_malloced) while (list != NULL) { - struct patternlist *old = list; - list = list->next; - if (old->malloced) - free (old); + struct patternlist *old = list; + list = list->next; + if (old->malloced) + free (old); } return retval; @@ -1209,10 +1203,9 @@ EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end, #undef STRUCT #undef MEMPCPY #undef MEMCHR -#undef STRCOLL #undef STRLEN #undef STRCAT -#undef L +#undef L_ #undef BTOWC #undef WIDE_CHAR_VERSION #undef FINDIDX