1 1.1.1.2 christos /* Copyright (C) 1991-2022 Free Software Foundation, Inc. 2 1.1 christos This file is part of the GNU C Library. 3 1.1 christos 4 1.1 christos The GNU C Library is free software; you can redistribute it and/or 5 1.1.1.2 christos modify it under the terms of the GNU Lesser General Public 6 1.1 christos License as published by the Free Software Foundation; either 7 1.1.1.2 christos version 2.1 of the License, or (at your option) any later version. 8 1.1 christos 9 1.1 christos The GNU C Library is distributed in the hope that it will be useful, 10 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 11 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 1.1.1.2 christos Lesser General Public License for more details. 13 1.1 christos 14 1.1.1.2 christos You should have received a copy of the GNU Lesser General Public 15 1.1 christos License along with the GNU C Library; if not, see 16 1.1 christos <https://www.gnu.org/licenses/>. */ 17 1.1 christos 18 1.1 christos #ifdef _LIBC 19 1.1 christos # include <stdint.h> 20 1.1 christos #endif 21 1.1 christos 22 1.1 christos struct STRUCT 23 1.1 christos { 24 1.1 christos const CHAR *pattern; 25 1.1 christos const CHAR *string; 26 1.1 christos bool no_leading_period; 27 1.1 christos }; 28 1.1 christos 29 1.1 christos /* Match STRING against the file name pattern PATTERN, returning zero if 30 1.1 christos it matches, nonzero if not. */ 31 1.1 christos static int FCT (const CHAR *pattern, const CHAR *string, 32 1.1 christos const CHAR *string_end, bool no_leading_period, int flags, 33 1.1 christos struct STRUCT *ends, size_t alloca_used); 34 1.1 christos static int EXT (INT opt, const CHAR *pattern, const CHAR *string, 35 1.1 christos const CHAR *string_end, bool no_leading_period, int flags, 36 1.1 christos size_t alloca_used); 37 1.1 christos static const CHAR *END (const CHAR *patternp); 38 1.1 christos 39 1.1 christos static int 40 1.1 christos FCT (const CHAR *pattern, const CHAR *string, const CHAR *string_end, 41 1.1 christos bool no_leading_period, int flags, struct STRUCT *ends, size_t alloca_used) 42 1.1 christos { 43 1.1 christos const CHAR *p = pattern, *n = string; 44 1.1 christos UCHAR c; 45 1.1 christos #ifdef _LIBC 46 1.1 christos # if WIDE_CHAR_VERSION 47 1.1 christos const char *collseq = (const char *) 48 1.1 christos _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQWC); 49 1.1 christos # else 50 1.1 christos const UCHAR *collseq = (const UCHAR *) 51 1.1 christos _NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQMB); 52 1.1 christos # endif 53 1.1 christos #endif 54 1.1 christos 55 1.1 christos while ((c = *p++) != L_('\0')) 56 1.1 christos { 57 1.1 christos bool new_no_leading_period = false; 58 1.1 christos c = FOLD (c); 59 1.1 christos 60 1.1 christos switch (c) 61 1.1 christos { 62 1.1 christos case L_('?'): 63 1.1 christos if (__glibc_unlikely (flags & FNM_EXTMATCH) && *p == '(') 64 1.1 christos { 65 1.1 christos int res = EXT (c, p, n, string_end, no_leading_period, 66 1.1 christos flags, alloca_used); 67 1.1 christos if (res != -1) 68 1.1 christos return res; 69 1.1 christos } 70 1.1 christos 71 1.1 christos if (n == string_end) 72 1.1 christos return FNM_NOMATCH; 73 1.1 christos else if (*n == L_('/') && (flags & FNM_FILE_NAME)) 74 1.1 christos return FNM_NOMATCH; 75 1.1 christos else if (*n == L_('.') && no_leading_period) 76 1.1 christos return FNM_NOMATCH; 77 1.1 christos break; 78 1.1 christos 79 1.1 christos case L_('\\'): 80 1.1 christos if (!(flags & FNM_NOESCAPE)) 81 1.1 christos { 82 1.1 christos c = *p++; 83 1.1 christos if (c == L_('\0')) 84 1.1 christos /* Trailing \ loses. */ 85 1.1 christos return FNM_NOMATCH; 86 1.1 christos c = FOLD (c); 87 1.1 christos } 88 1.1 christos if (n == string_end || FOLD ((UCHAR) *n) != c) 89 1.1 christos return FNM_NOMATCH; 90 1.1 christos break; 91 1.1 christos 92 1.1 christos case L_('*'): 93 1.1 christos if (__glibc_unlikely (flags & FNM_EXTMATCH) && *p == '(') 94 1.1 christos { 95 1.1 christos int res = EXT (c, p, n, string_end, no_leading_period, 96 1.1 christos flags, alloca_used); 97 1.1 christos if (res != -1) 98 1.1 christos return res; 99 1.1 christos } 100 1.1 christos else if (ends != NULL) 101 1.1 christos { 102 1.1 christos ends->pattern = p - 1; 103 1.1 christos ends->string = n; 104 1.1 christos ends->no_leading_period = no_leading_period; 105 1.1 christos return 0; 106 1.1 christos } 107 1.1 christos 108 1.1 christos if (n != string_end && *n == L_('.') && no_leading_period) 109 1.1 christos return FNM_NOMATCH; 110 1.1 christos 111 1.1 christos for (c = *p++; c == L_('?') || c == L_('*'); c = *p++) 112 1.1 christos { 113 1.1 christos if (*p == L_('(') && (flags & FNM_EXTMATCH) != 0) 114 1.1 christos { 115 1.1 christos const CHAR *endp = END (p); 116 1.1 christos if (endp != p) 117 1.1 christos { 118 1.1 christos /* This is a pattern. Skip over it. */ 119 1.1 christos p = endp; 120 1.1 christos continue; 121 1.1 christos } 122 1.1 christos } 123 1.1 christos 124 1.1 christos if (c == L_('?')) 125 1.1 christos { 126 1.1 christos /* A ? needs to match one character. */ 127 1.1 christos if (n == string_end) 128 1.1 christos /* There isn't another character; no match. */ 129 1.1 christos return FNM_NOMATCH; 130 1.1 christos else if (*n == L_('/') 131 1.1 christos && __glibc_unlikely (flags & FNM_FILE_NAME)) 132 1.1 christos /* A slash does not match a wildcard under 133 1.1 christos FNM_FILE_NAME. */ 134 1.1 christos return FNM_NOMATCH; 135 1.1 christos else 136 1.1 christos /* One character of the string is consumed in matching 137 1.1 christos this ? wildcard, so *??? won't match if there are 138 1.1 christos less than three characters. */ 139 1.1 christos ++n; 140 1.1 christos } 141 1.1 christos } 142 1.1 christos 143 1.1 christos if (c == L_('\0')) 144 1.1 christos /* The wildcard(s) is/are the last element of the pattern. 145 1.1 christos If the name is a file name and contains another slash 146 1.1 christos this means it cannot match, unless the FNM_LEADING_DIR 147 1.1 christos flag is set. */ 148 1.1 christos { 149 1.1 christos int result = (flags & FNM_FILE_NAME) == 0 ? 0 : FNM_NOMATCH; 150 1.1 christos 151 1.1 christos if (flags & FNM_FILE_NAME) 152 1.1 christos { 153 1.1 christos if (flags & FNM_LEADING_DIR) 154 1.1 christos result = 0; 155 1.1 christos else 156 1.1 christos { 157 1.1 christos if (MEMCHR (n, L_('/'), string_end - n) == NULL) 158 1.1 christos result = 0; 159 1.1 christos } 160 1.1 christos } 161 1.1 christos 162 1.1 christos return result; 163 1.1 christos } 164 1.1 christos else 165 1.1 christos { 166 1.1 christos const CHAR *endp; 167 1.1 christos struct STRUCT end; 168 1.1 christos 169 1.1 christos end.pattern = NULL; 170 1.1 christos endp = MEMCHR (n, (flags & FNM_FILE_NAME) ? L_('/') : L_('\0'), 171 1.1 christos string_end - n); 172 1.1 christos if (endp == NULL) 173 1.1 christos endp = string_end; 174 1.1 christos 175 1.1 christos if (c == L_('[') 176 1.1 christos || (__glibc_unlikely (flags & FNM_EXTMATCH) 177 1.1 christos && (c == L_('@') || c == L_('+') || c == L_('!')) 178 1.1 christos && *p == L_('('))) 179 1.1 christos { 180 1.1 christos int flags2 = ((flags & FNM_FILE_NAME) 181 1.1 christos ? flags : (flags & ~FNM_PERIOD)); 182 1.1 christos 183 1.1 christos for (--p; n < endp; ++n, no_leading_period = false) 184 1.1 christos if (FCT (p, n, string_end, no_leading_period, flags2, 185 1.1 christos &end, alloca_used) == 0) 186 1.1 christos goto found; 187 1.1 christos } 188 1.1 christos else if (c == L_('/') && (flags & FNM_FILE_NAME)) 189 1.1 christos { 190 1.1 christos while (n < string_end && *n != L_('/')) 191 1.1 christos ++n; 192 1.1 christos if (n < string_end && *n == L_('/') 193 1.1 christos && (FCT (p, n + 1, string_end, flags & FNM_PERIOD, flags, 194 1.1 christos NULL, alloca_used) == 0)) 195 1.1 christos return 0; 196 1.1 christos } 197 1.1 christos else 198 1.1 christos { 199 1.1 christos int flags2 = ((flags & FNM_FILE_NAME) 200 1.1 christos ? flags : (flags & ~FNM_PERIOD)); 201 1.1 christos 202 1.1 christos if (c == L_('\\') && !(flags & FNM_NOESCAPE)) 203 1.1 christos c = *p; 204 1.1 christos c = FOLD (c); 205 1.1 christos for (--p; n < endp; ++n, no_leading_period = false) 206 1.1 christos if (FOLD ((UCHAR) *n) == c 207 1.1 christos && (FCT (p, n, string_end, no_leading_period, flags2, 208 1.1 christos &end, alloca_used) == 0)) 209 1.1 christos { 210 1.1 christos found: 211 1.1 christos if (end.pattern == NULL) 212 1.1 christos return 0; 213 1.1 christos break; 214 1.1 christos } 215 1.1 christos if (end.pattern != NULL) 216 1.1 christos { 217 1.1 christos p = end.pattern; 218 1.1 christos n = end.string; 219 1.1 christos no_leading_period = end.no_leading_period; 220 1.1 christos continue; 221 1.1 christos } 222 1.1 christos } 223 1.1 christos } 224 1.1 christos 225 1.1 christos /* If we come here no match is possible with the wildcard. */ 226 1.1 christos return FNM_NOMATCH; 227 1.1 christos 228 1.1 christos case L_('['): 229 1.1 christos { 230 1.1 christos /* Nonzero if the sense of the character class is inverted. */ 231 1.1 christos const CHAR *p_init = p; 232 1.1 christos const CHAR *n_init = n; 233 1.1 christos bool not; 234 1.1 christos CHAR cold; 235 1.1 christos UCHAR fn; 236 1.1 christos 237 1.1 christos if (posixly_correct == 0) 238 1.1 christos posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; 239 1.1 christos 240 1.1 christos if (n == string_end) 241 1.1 christos return FNM_NOMATCH; 242 1.1 christos 243 1.1 christos if (*n == L_('.') && no_leading_period) 244 1.1 christos return FNM_NOMATCH; 245 1.1 christos 246 1.1 christos if (*n == L_('/') && (flags & FNM_FILE_NAME)) 247 1.1 christos /* '/' cannot be matched. */ 248 1.1 christos return FNM_NOMATCH; 249 1.1 christos 250 1.1 christos not = (*p == L_('!') || (posixly_correct < 0 && *p == L_('^'))); 251 1.1 christos if (not) 252 1.1 christos ++p; 253 1.1 christos 254 1.1 christos fn = FOLD ((UCHAR) *n); 255 1.1 christos 256 1.1 christos c = *p++; 257 1.1 christos for (;;) 258 1.1 christos { 259 1.1 christos if (!(flags & FNM_NOESCAPE) && c == L_('\\')) 260 1.1 christos { 261 1.1 christos if (*p == L_('\0')) 262 1.1 christos return FNM_NOMATCH; 263 1.1 christos c = FOLD ((UCHAR) *p); 264 1.1 christos ++p; 265 1.1 christos 266 1.1 christos goto normal_bracket; 267 1.1 christos } 268 1.1 christos else if (c == L_('[') && *p == L_(':')) 269 1.1 christos { 270 1.1 christos /* Leave room for the null. */ 271 1.1 christos CHAR str[CHAR_CLASS_MAX_LENGTH + 1]; 272 1.1 christos size_t c1 = 0; 273 1.1 christos wctype_t wt; 274 1.1 christos const CHAR *startp = p; 275 1.1 christos 276 1.1 christos for (;;) 277 1.1 christos { 278 1.1 christos if (c1 == CHAR_CLASS_MAX_LENGTH) 279 1.1 christos /* The name is too long and therefore the pattern 280 1.1 christos is ill-formed. */ 281 1.1 christos return FNM_NOMATCH; 282 1.1 christos 283 1.1 christos c = *++p; 284 1.1 christos if (c == L_(':') && p[1] == L_(']')) 285 1.1 christos { 286 1.1 christos p += 2; 287 1.1 christos break; 288 1.1 christos } 289 1.1 christos if (c < L_('a') || c >= L_('z')) 290 1.1 christos { 291 1.1 christos /* This cannot possibly be a character class name. 292 1.1 christos Match it as a normal range. */ 293 1.1 christos p = startp; 294 1.1 christos c = L_('['); 295 1.1 christos goto normal_bracket; 296 1.1 christos } 297 1.1 christos str[c1++] = c; 298 1.1 christos } 299 1.1 christos str[c1] = L_('\0'); 300 1.1 christos 301 1.1 christos wt = IS_CHAR_CLASS (str); 302 1.1 christos if (wt == 0) 303 1.1 christos /* Invalid character class name. */ 304 1.1 christos return FNM_NOMATCH; 305 1.1 christos 306 1.1 christos #if defined _LIBC && ! WIDE_CHAR_VERSION 307 1.1 christos /* The following code is glibc specific but does 308 1.1 christos there a good job in speeding up the code since 309 1.1 christos we can avoid the btowc() call. */ 310 1.1 christos if (_ISCTYPE ((UCHAR) *n, wt)) 311 1.1 christos goto matched; 312 1.1 christos #else 313 1.1 christos if (iswctype (BTOWC ((UCHAR) *n), wt)) 314 1.1 christos goto matched; 315 1.1 christos #endif 316 1.1 christos c = *p++; 317 1.1 christos } 318 1.1 christos #ifdef _LIBC 319 1.1 christos else if (c == L_('[') && *p == L_('=')) 320 1.1 christos { 321 1.1 christos /* It's important that STR be a scalar variable rather 322 1.1 christos than a one-element array, because GCC (at least 4.9.2 323 1.1 christos -O2 on x86-64) can be confused by the array and 324 1.1 christos diagnose a "used initialized" in a dead branch in the 325 1.1 christos findidx function. */ 326 1.1 christos UCHAR str; 327 1.1 christos uint32_t nrules = 328 1.1 christos _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); 329 1.1 christos const CHAR *startp = p; 330 1.1 christos 331 1.1 christos c = *++p; 332 1.1 christos if (c == L_('\0')) 333 1.1 christos { 334 1.1 christos p = startp; 335 1.1 christos c = L_('['); 336 1.1 christos goto normal_bracket; 337 1.1 christos } 338 1.1 christos str = c; 339 1.1 christos 340 1.1 christos c = *++p; 341 1.1 christos if (c != L_('=') || p[1] != L_(']')) 342 1.1 christos { 343 1.1 christos p = startp; 344 1.1 christos c = L_('['); 345 1.1 christos goto normal_bracket; 346 1.1 christos } 347 1.1 christos p += 2; 348 1.1 christos 349 1.1 christos if (nrules == 0) 350 1.1 christos { 351 1.1 christos if ((UCHAR) *n == str) 352 1.1 christos goto matched; 353 1.1 christos } 354 1.1 christos else 355 1.1 christos { 356 1.1 christos const int32_t *table; 357 1.1 christos # if WIDE_CHAR_VERSION 358 1.1 christos const int32_t *weights; 359 1.1 christos const wint_t *extra; 360 1.1 christos # else 361 1.1 christos const unsigned char *weights; 362 1.1 christos const unsigned char *extra; 363 1.1 christos # endif 364 1.1 christos const int32_t *indirect; 365 1.1 christos int32_t idx; 366 1.1 christos const UCHAR *cp = (const UCHAR *) &str; 367 1.1 christos 368 1.1 christos # if WIDE_CHAR_VERSION 369 1.1 christos table = (const int32_t *) 370 1.1 christos _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEWC); 371 1.1 christos weights = (const int32_t *) 372 1.1 christos _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTWC); 373 1.1 christos extra = (const wint_t *) 374 1.1 christos _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAWC); 375 1.1 christos indirect = (const int32_t *) 376 1.1 christos _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTWC); 377 1.1 christos # else 378 1.1 christos table = (const int32_t *) 379 1.1 christos _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); 380 1.1 christos weights = (const unsigned char *) 381 1.1 christos _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB); 382 1.1 christos extra = (const unsigned char *) 383 1.1 christos _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); 384 1.1 christos indirect = (const int32_t *) 385 1.1 christos _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); 386 1.1 christos # endif 387 1.1 christos 388 1.1 christos idx = FINDIDX (table, indirect, extra, &cp, 1); 389 1.1 christos if (idx != 0) 390 1.1 christos { 391 1.1 christos /* We found a table entry. Now see whether the 392 1.1 christos character we are currently at has the same 393 1.1 christos equivalence class value. */ 394 1.1 christos int len = weights[idx & 0xffffff]; 395 1.1 christos int32_t idx2; 396 1.1 christos const UCHAR *np = (const UCHAR *) n; 397 1.1 christos 398 1.1 christos idx2 = FINDIDX (table, indirect, extra, 399 1.1 christos &np, string_end - n); 400 1.1 christos if (idx2 != 0 401 1.1 christos && (idx >> 24) == (idx2 >> 24) 402 1.1 christos && len == weights[idx2 & 0xffffff]) 403 1.1 christos { 404 1.1 christos int cnt = 0; 405 1.1 christos 406 1.1 christos idx &= 0xffffff; 407 1.1 christos idx2 &= 0xffffff; 408 1.1 christos 409 1.1 christos while (cnt < len 410 1.1 christos && (weights[idx + 1 + cnt] 411 1.1 christos == weights[idx2 + 1 + cnt])) 412 1.1 christos ++cnt; 413 1.1 christos 414 1.1 christos if (cnt == len) 415 1.1 christos goto matched; 416 1.1 christos } 417 1.1 christos } 418 1.1 christos } 419 1.1 christos 420 1.1 christos c = *p++; 421 1.1 christos } 422 1.1 christos #endif 423 1.1 christos else if (c == L_('\0')) 424 1.1 christos { 425 1.1 christos /* [ unterminated, treat as normal character. */ 426 1.1 christos p = p_init; 427 1.1 christos n = n_init; 428 1.1 christos c = L_('['); 429 1.1 christos goto normal_match; 430 1.1 christos } 431 1.1 christos else 432 1.1 christos { 433 1.1 christos bool is_range = false; 434 1.1 christos 435 1.1 christos #ifdef _LIBC 436 1.1 christos bool is_seqval = false; 437 1.1 christos 438 1.1 christos if (c == L_('[') && *p == L_('.')) 439 1.1 christos { 440 1.1 christos uint32_t nrules = 441 1.1 christos _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); 442 1.1 christos const CHAR *startp = p; 443 1.1 christos size_t c1 = 0; 444 1.1 christos 445 1.1 christos while (1) 446 1.1 christos { 447 1.1 christos c = *++p; 448 1.1 christos if (c == L_('.') && p[1] == L_(']')) 449 1.1 christos { 450 1.1 christos p += 2; 451 1.1 christos break; 452 1.1 christos } 453 1.1 christos if (c == '\0') 454 1.1 christos return FNM_NOMATCH; 455 1.1 christos ++c1; 456 1.1 christos } 457 1.1 christos 458 1.1 christos /* We have to handling the symbols differently in 459 1.1 christos ranges since then the collation sequence is 460 1.1 christos important. */ 461 1.1 christos is_range = *p == L_('-') && p[1] != L_('\0'); 462 1.1 christos 463 1.1 christos if (nrules == 0) 464 1.1 christos { 465 1.1 christos /* There are no names defined in the collation 466 1.1 christos data. Therefore we only accept the trivial 467 1.1 christos names consisting of the character itself. */ 468 1.1 christos if (c1 != 1) 469 1.1 christos return FNM_NOMATCH; 470 1.1 christos 471 1.1 christos if (!is_range && *n == startp[1]) 472 1.1 christos goto matched; 473 1.1 christos 474 1.1 christos cold = startp[1]; 475 1.1 christos c = *p++; 476 1.1 christos } 477 1.1 christos else 478 1.1 christos { 479 1.1 christos int32_t table_size; 480 1.1 christos const int32_t *symb_table; 481 1.1 christos const unsigned char *extra; 482 1.1 christos int32_t idx; 483 1.1 christos int32_t elem; 484 1.1 christos # if WIDE_CHAR_VERSION 485 1.1 christos CHAR *wextra; 486 1.1 christos # endif 487 1.1 christos 488 1.1 christos table_size = 489 1.1 christos _NL_CURRENT_WORD (LC_COLLATE, 490 1.1 christos _NL_COLLATE_SYMB_HASH_SIZEMB); 491 1.1 christos symb_table = (const int32_t *) 492 1.1 christos _NL_CURRENT (LC_COLLATE, 493 1.1 christos _NL_COLLATE_SYMB_TABLEMB); 494 1.1 christos extra = (const unsigned char *) 495 1.1 christos _NL_CURRENT (LC_COLLATE, 496 1.1 christos _NL_COLLATE_SYMB_EXTRAMB); 497 1.1 christos 498 1.1 christos for (elem = 0; elem < table_size; elem++) 499 1.1 christos if (symb_table[2 * elem] != 0) 500 1.1 christos { 501 1.1 christos idx = symb_table[2 * elem + 1]; 502 1.1 christos /* Skip the name of collating element. */ 503 1.1 christos idx += 1 + extra[idx]; 504 1.1 christos # if WIDE_CHAR_VERSION 505 1.1 christos /* Skip the byte sequence of the 506 1.1 christos collating element. */ 507 1.1 christos idx += 1 + extra[idx]; 508 1.1 christos /* Adjust for the alignment. */ 509 1.1 christos idx = (idx + 3) & ~3; 510 1.1 christos 511 1.1 christos wextra = (CHAR *) &extra[idx + 4]; 512 1.1 christos 513 1.1 christos if (/* Compare the length of the sequence. */ 514 1.1 christos c1 == wextra[0] 515 1.1 christos /* Compare the wide char sequence. */ 516 1.1 christos && (__wmemcmp (startp + 1, &wextra[1], 517 1.1 christos c1) 518 1.1 christos == 0)) 519 1.1 christos /* Yep, this is the entry. */ 520 1.1 christos break; 521 1.1 christos # else 522 1.1 christos if (/* Compare the length of the sequence. */ 523 1.1 christos c1 == extra[idx] 524 1.1 christos /* Compare the byte sequence. */ 525 1.1 christos && memcmp (startp + 1, 526 1.1 christos &extra[idx + 1], c1) == 0) 527 1.1 christos /* Yep, this is the entry. */ 528 1.1 christos break; 529 1.1 christos # endif 530 1.1 christos } 531 1.1 christos 532 1.1 christos if (elem < table_size) 533 1.1 christos { 534 1.1 christos /* Compare the byte sequence but only if 535 1.1 christos this is not part of a range. */ 536 1.1 christos if (! is_range 537 1.1 christos 538 1.1 christos # if WIDE_CHAR_VERSION 539 1.1 christos && __wmemcmp (n, &wextra[1], c1) == 0 540 1.1 christos # else 541 1.1 christos && memcmp (n, &extra[idx + 1], c1) == 0 542 1.1 christos # endif 543 1.1 christos ) 544 1.1 christos { 545 1.1 christos n += c1 - 1; 546 1.1 christos goto matched; 547 1.1 christos } 548 1.1 christos 549 1.1 christos /* Get the collation sequence value. */ 550 1.1 christos is_seqval = true; 551 1.1 christos # if WIDE_CHAR_VERSION 552 1.1.1.2 christos cold = wextra[1 + wextra[0]]; 553 1.1 christos # else 554 1.1 christos idx += 1 + extra[idx]; 555 1.1 christos /* Adjust for the alignment. */ 556 1.1 christos idx = (idx + 3) & ~3; 557 1.1 christos cold = *((int32_t *) &extra[idx]); 558 1.1 christos # endif 559 1.1 christos 560 1.1 christos c = *p++; 561 1.1 christos } 562 1.1 christos else if (c1 == 1) 563 1.1 christos { 564 1.1 christos /* No valid character. Match it as a 565 1.1 christos single byte. */ 566 1.1 christos if (!is_range && *n == startp[1]) 567 1.1 christos goto matched; 568 1.1 christos 569 1.1 christos cold = startp[1]; 570 1.1 christos c = *p++; 571 1.1 christos } 572 1.1 christos else 573 1.1 christos return FNM_NOMATCH; 574 1.1 christos } 575 1.1 christos } 576 1.1 christos else 577 1.1 christos #endif 578 1.1 christos { 579 1.1 christos c = FOLD (c); 580 1.1 christos normal_bracket: 581 1.1 christos 582 1.1 christos /* We have to handling the symbols differently in 583 1.1 christos ranges since then the collation sequence is 584 1.1 christos important. */ 585 1.1 christos is_range = (*p == L_('-') && p[1] != L_('\0') 586 1.1 christos && p[1] != L_(']')); 587 1.1 christos 588 1.1 christos if (!is_range && c == fn) 589 1.1 christos goto matched; 590 1.1 christos 591 1.1 christos #if _LIBC 592 1.1 christos /* This is needed if we goto normal_bracket; from 593 1.1 christos outside of is_seqval's scope. */ 594 1.1 christos is_seqval = false; 595 1.1 christos #endif 596 1.1 christos cold = c; 597 1.1 christos c = *p++; 598 1.1 christos } 599 1.1 christos 600 1.1 christos if (c == L_('-') && *p != L_(']')) 601 1.1 christos { 602 1.1 christos #if _LIBC 603 1.1 christos /* We have to find the collation sequence 604 1.1 christos value for C. Collation sequence is nothing 605 1.1 christos we can regularly access. The sequence 606 1.1 christos value is defined by the order in which the 607 1.1 christos definitions of the collation values for the 608 1.1 christos various characters appear in the source 609 1.1 christos file. A strange concept, nowhere 610 1.1 christos documented. */ 611 1.1 christos uint32_t fcollseq; 612 1.1 christos uint32_t lcollseq; 613 1.1 christos UCHAR cend = *p++; 614 1.1 christos 615 1.1 christos # if WIDE_CHAR_VERSION 616 1.1 christos /* Search in the 'names' array for the characters. */ 617 1.1 christos fcollseq = __collseq_table_lookup (collseq, fn); 618 1.1 christos if (fcollseq == ~((uint32_t) 0)) 619 1.1 christos /* XXX We don't know anything about the character 620 1.1 christos we are supposed to match. This means we are 621 1.1 christos failing. */ 622 1.1 christos goto range_not_matched; 623 1.1 christos 624 1.1 christos if (is_seqval) 625 1.1 christos lcollseq = cold; 626 1.1 christos else 627 1.1 christos lcollseq = __collseq_table_lookup (collseq, cold); 628 1.1 christos # else 629 1.1 christos fcollseq = collseq[fn]; 630 1.1 christos lcollseq = is_seqval ? cold : collseq[(UCHAR) cold]; 631 1.1 christos # endif 632 1.1 christos 633 1.1 christos is_seqval = false; 634 1.1 christos if (cend == L_('[') && *p == L_('.')) 635 1.1 christos { 636 1.1 christos uint32_t nrules = 637 1.1 christos _NL_CURRENT_WORD (LC_COLLATE, 638 1.1 christos _NL_COLLATE_NRULES); 639 1.1 christos const CHAR *startp = p; 640 1.1 christos size_t c1 = 0; 641 1.1 christos 642 1.1 christos while (1) 643 1.1 christos { 644 1.1 christos c = *++p; 645 1.1 christos if (c == L_('.') && p[1] == L_(']')) 646 1.1 christos { 647 1.1 christos p += 2; 648 1.1 christos break; 649 1.1 christos } 650 1.1 christos if (c == '\0') 651 1.1 christos return FNM_NOMATCH; 652 1.1 christos ++c1; 653 1.1 christos } 654 1.1 christos 655 1.1 christos if (nrules == 0) 656 1.1 christos { 657 1.1 christos /* There are no names defined in the 658 1.1 christos collation data. Therefore we only 659 1.1 christos accept the trivial names consisting 660 1.1 christos of the character itself. */ 661 1.1 christos if (c1 != 1) 662 1.1 christos return FNM_NOMATCH; 663 1.1 christos 664 1.1 christos cend = startp[1]; 665 1.1 christos } 666 1.1 christos else 667 1.1 christos { 668 1.1 christos int32_t table_size; 669 1.1 christos const int32_t *symb_table; 670 1.1 christos const unsigned char *extra; 671 1.1 christos int32_t idx; 672 1.1 christos int32_t elem; 673 1.1 christos # if WIDE_CHAR_VERSION 674 1.1 christos CHAR *wextra; 675 1.1 christos # endif 676 1.1 christos 677 1.1 christos table_size = 678 1.1 christos _NL_CURRENT_WORD (LC_COLLATE, 679 1.1 christos _NL_COLLATE_SYMB_HASH_SIZEMB); 680 1.1 christos symb_table = (const int32_t *) 681 1.1 christos _NL_CURRENT (LC_COLLATE, 682 1.1 christos _NL_COLLATE_SYMB_TABLEMB); 683 1.1 christos extra = (const unsigned char *) 684 1.1 christos _NL_CURRENT (LC_COLLATE, 685 1.1 christos _NL_COLLATE_SYMB_EXTRAMB); 686 1.1 christos 687 1.1 christos for (elem = 0; elem < table_size; elem++) 688 1.1 christos if (symb_table[2 * elem] != 0) 689 1.1 christos { 690 1.1 christos idx = symb_table[2 * elem + 1]; 691 1.1 christos /* Skip the name of collating 692 1.1 christos element. */ 693 1.1 christos idx += 1 + extra[idx]; 694 1.1 christos # if WIDE_CHAR_VERSION 695 1.1 christos /* Skip the byte sequence of the 696 1.1 christos collating element. */ 697 1.1 christos idx += 1 + extra[idx]; 698 1.1 christos /* Adjust for the alignment. */ 699 1.1 christos idx = (idx + 3) & ~3; 700 1.1 christos 701 1.1 christos wextra = (CHAR *) &extra[idx + 4]; 702 1.1 christos 703 1.1 christos if (/* Compare the length of the 704 1.1 christos sequence. */ 705 1.1 christos c1 == wextra[0] 706 1.1 christos /* Compare the wide char sequence. */ 707 1.1 christos && (__wmemcmp (startp + 1, 708 1.1 christos &wextra[1], c1) 709 1.1 christos == 0)) 710 1.1 christos /* Yep, this is the entry. */ 711 1.1 christos break; 712 1.1 christos # else 713 1.1 christos if (/* Compare the length of the 714 1.1 christos sequence. */ 715 1.1 christos c1 == extra[idx] 716 1.1 christos /* Compare the byte sequence. */ 717 1.1 christos && memcmp (startp + 1, 718 1.1 christos &extra[idx + 1], c1) == 0) 719 1.1 christos /* Yep, this is the entry. */ 720 1.1 christos break; 721 1.1 christos # endif 722 1.1 christos } 723 1.1 christos 724 1.1 christos if (elem < table_size) 725 1.1 christos { 726 1.1 christos /* Get the collation sequence value. */ 727 1.1 christos is_seqval = true; 728 1.1 christos # if WIDE_CHAR_VERSION 729 1.1.1.2 christos cend = wextra[1 + wextra[0]]; 730 1.1 christos # else 731 1.1 christos idx += 1 + extra[idx]; 732 1.1 christos /* Adjust for the alignment. */ 733 1.1 christos idx = (idx + 3) & ~3; 734 1.1 christos cend = *((int32_t *) &extra[idx]); 735 1.1 christos # endif 736 1.1 christos } 737 1.1 christos else if (c1 == 1) 738 1.1 christos { 739 1.1 christos cend = startp[1]; 740 1.1 christos c = *p++; 741 1.1 christos } 742 1.1 christos else 743 1.1 christos return FNM_NOMATCH; 744 1.1 christos } 745 1.1 christos } 746 1.1 christos else 747 1.1 christos { 748 1.1 christos if (!(flags & FNM_NOESCAPE) && cend == L_('\\')) 749 1.1 christos cend = *p++; 750 1.1 christos if (cend == L_('\0')) 751 1.1 christos return FNM_NOMATCH; 752 1.1 christos cend = FOLD (cend); 753 1.1 christos } 754 1.1 christos 755 1.1 christos /* XXX It is not entirely clear to me how to handle 756 1.1 christos characters which are not mentioned in the 757 1.1 christos collation specification. */ 758 1.1 christos if ( 759 1.1 christos # if WIDE_CHAR_VERSION 760 1.1 christos lcollseq == 0xffffffff || 761 1.1 christos # endif 762 1.1 christos lcollseq <= fcollseq) 763 1.1 christos { 764 1.1 christos /* We have to look at the upper bound. */ 765 1.1 christos uint32_t hcollseq; 766 1.1 christos 767 1.1 christos if (is_seqval) 768 1.1 christos hcollseq = cend; 769 1.1 christos else 770 1.1 christos { 771 1.1 christos # if WIDE_CHAR_VERSION 772 1.1 christos hcollseq = 773 1.1 christos __collseq_table_lookup (collseq, cend); 774 1.1 christos if (hcollseq == ~((uint32_t) 0)) 775 1.1 christos { 776 1.1 christos /* Hum, no information about the upper 777 1.1 christos bound. The matching succeeds if the 778 1.1 christos lower bound is matched exactly. */ 779 1.1 christos if (lcollseq != fcollseq) 780 1.1 christos goto range_not_matched; 781 1.1 christos 782 1.1 christos goto matched; 783 1.1 christos } 784 1.1 christos # else 785 1.1 christos hcollseq = collseq[cend]; 786 1.1 christos # endif 787 1.1 christos } 788 1.1 christos 789 1.1 christos if (lcollseq <= hcollseq && fcollseq <= hcollseq) 790 1.1 christos goto matched; 791 1.1 christos } 792 1.1 christos # if WIDE_CHAR_VERSION 793 1.1 christos range_not_matched: 794 1.1 christos # endif 795 1.1 christos #else 796 1.1 christos /* We use a boring value comparison of the character 797 1.1 christos values. This is better than comparing using 798 1.1 christos 'strcoll' since the latter would have surprising 799 1.1 christos and sometimes fatal consequences. */ 800 1.1 christos UCHAR cend = *p++; 801 1.1 christos 802 1.1 christos if (!(flags & FNM_NOESCAPE) && cend == L_('\\')) 803 1.1 christos cend = *p++; 804 1.1 christos if (cend == L_('\0')) 805 1.1 christos return FNM_NOMATCH; 806 1.1 christos 807 1.1 christos /* It is a range. */ 808 1.1 christos if ((UCHAR) cold <= fn && fn <= cend) 809 1.1 christos goto matched; 810 1.1 christos #endif 811 1.1 christos 812 1.1 christos c = *p++; 813 1.1 christos } 814 1.1 christos } 815 1.1 christos 816 1.1 christos if (c == L_(']')) 817 1.1 christos break; 818 1.1 christos } 819 1.1 christos 820 1.1 christos if (!not) 821 1.1 christos return FNM_NOMATCH; 822 1.1 christos break; 823 1.1 christos 824 1.1 christos matched: 825 1.1 christos /* Skip the rest of the [...] that already matched. */ 826 1.1 christos while ((c = *p++) != L_(']')) 827 1.1 christos { 828 1.1 christos if (c == L_('\0')) 829 1.1 christos /* [... (unterminated) loses. */ 830 1.1 christos return FNM_NOMATCH; 831 1.1 christos 832 1.1 christos if (!(flags & FNM_NOESCAPE) && c == L_('\\')) 833 1.1 christos { 834 1.1 christos if (*p == L_('\0')) 835 1.1 christos return FNM_NOMATCH; 836 1.1 christos /* XXX 1003.2d11 is unclear if this is right. */ 837 1.1 christos ++p; 838 1.1 christos } 839 1.1 christos else if (c == L_('[') && *p == L_(':')) 840 1.1 christos { 841 1.1 christos int c1 = 0; 842 1.1 christos const CHAR *startp = p; 843 1.1 christos 844 1.1 christos while (1) 845 1.1 christos { 846 1.1 christos c = *++p; 847 1.1 christos if (++c1 == CHAR_CLASS_MAX_LENGTH) 848 1.1 christos return FNM_NOMATCH; 849 1.1 christos 850 1.1 christos if (*p == L_(':') && p[1] == L_(']')) 851 1.1 christos break; 852 1.1 christos 853 1.1 christos if (c < L_('a') || c >= L_('z')) 854 1.1 christos { 855 1.1 christos p = startp - 2; 856 1.1 christos break; 857 1.1 christos } 858 1.1 christos } 859 1.1 christos p += 2; 860 1.1 christos } 861 1.1 christos else if (c == L_('[') && *p == L_('=')) 862 1.1 christos { 863 1.1 christos c = *++p; 864 1.1 christos if (c == L_('\0')) 865 1.1 christos return FNM_NOMATCH; 866 1.1 christos c = *++p; 867 1.1 christos if (c != L_('=') || p[1] != L_(']')) 868 1.1 christos return FNM_NOMATCH; 869 1.1 christos p += 2; 870 1.1 christos } 871 1.1 christos else if (c == L_('[') && *p == L_('.')) 872 1.1 christos { 873 1.1 christos while (1) 874 1.1 christos { 875 1.1 christos c = *++p; 876 1.1 christos if (c == L_('\0')) 877 1.1 christos return FNM_NOMATCH; 878 1.1 christos 879 1.1 christos if (c == L_('.') && p[1] == L_(']')) 880 1.1 christos break; 881 1.1 christos } 882 1.1 christos p += 2; 883 1.1 christos } 884 1.1 christos } 885 1.1 christos if (not) 886 1.1 christos return FNM_NOMATCH; 887 1.1 christos } 888 1.1 christos break; 889 1.1 christos 890 1.1 christos case L_('+'): 891 1.1 christos case L_('@'): 892 1.1 christos case L_('!'): 893 1.1 christos if (__glibc_unlikely (flags & FNM_EXTMATCH) && *p == '(') 894 1.1 christos { 895 1.1 christos int res = EXT (c, p, n, string_end, no_leading_period, flags, 896 1.1 christos alloca_used); 897 1.1 christos if (res != -1) 898 1.1 christos return res; 899 1.1 christos } 900 1.1 christos goto normal_match; 901 1.1 christos 902 1.1 christos case L_('/'): 903 1.1 christos if (NO_LEADING_PERIOD (flags)) 904 1.1 christos { 905 1.1 christos if (n == string_end || c != (UCHAR) *n) 906 1.1 christos return FNM_NOMATCH; 907 1.1 christos 908 1.1 christos new_no_leading_period = true; 909 1.1 christos break; 910 1.1 christos } 911 1.1 christos FALLTHROUGH; 912 1.1 christos default: 913 1.1 christos normal_match: 914 1.1 christos if (n == string_end || c != FOLD ((UCHAR) *n)) 915 1.1 christos return FNM_NOMATCH; 916 1.1 christos } 917 1.1 christos 918 1.1 christos no_leading_period = new_no_leading_period; 919 1.1 christos ++n; 920 1.1 christos } 921 1.1 christos 922 1.1 christos if (n == string_end) 923 1.1 christos return 0; 924 1.1 christos 925 1.1 christos if ((flags & FNM_LEADING_DIR) && n != string_end && *n == L_('/')) 926 1.1 christos /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ 927 1.1 christos return 0; 928 1.1 christos 929 1.1 christos return FNM_NOMATCH; 930 1.1 christos } 931 1.1 christos 932 1.1 christos 933 1.1 christos static const CHAR * 934 1.1 christos END (const CHAR *pattern) 935 1.1 christos { 936 1.1 christos const CHAR *p = pattern; 937 1.1 christos 938 1.1 christos while (1) 939 1.1 christos if (*++p == L_('\0')) 940 1.1 christos /* This is an invalid pattern. */ 941 1.1 christos return pattern; 942 1.1 christos else if (*p == L_('[')) 943 1.1 christos { 944 1.1 christos /* Handle brackets special. */ 945 1.1 christos if (posixly_correct == 0) 946 1.1 christos posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; 947 1.1 christos 948 1.1 christos /* Skip the not sign. We have to recognize it because of a possibly 949 1.1 christos following ']'. */ 950 1.1 christos if (*++p == L_('!') || (posixly_correct < 0 && *p == L_('^'))) 951 1.1 christos ++p; 952 1.1 christos /* A leading ']' is recognized as such. */ 953 1.1 christos if (*p == L_(']')) 954 1.1 christos ++p; 955 1.1 christos /* Skip over all characters of the list. */ 956 1.1 christos while (*p != L_(']')) 957 1.1 christos if (*p++ == L_('\0')) 958 1.1 christos /* This is no valid pattern. */ 959 1.1 christos return pattern; 960 1.1 christos } 961 1.1 christos else if ((*p == L_('?') || *p == L_('*') || *p == L_('+') || *p == L_('@') 962 1.1 christos || *p == L_('!')) && p[1] == L_('(')) 963 1.1 christos { 964 1.1 christos p = END (p + 1); 965 1.1 christos if (*p == L_('\0')) 966 1.1 christos /* This is an invalid pattern. */ 967 1.1 christos return pattern; 968 1.1 christos } 969 1.1 christos else if (*p == L_(')')) 970 1.1 christos break; 971 1.1 christos 972 1.1 christos return p + 1; 973 1.1 christos } 974 1.1 christos 975 1.1 christos 976 1.1 christos static int 977 1.1 christos EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end, 978 1.1 christos bool no_leading_period, int flags, size_t alloca_used) 979 1.1 christos { 980 1.1 christos const CHAR *startp; 981 1.1.1.2 christos ptrdiff_t level; 982 1.1 christos struct patternlist 983 1.1 christos { 984 1.1 christos struct patternlist *next; 985 1.1 christos CHAR malloced; 986 1.1.1.2 christos CHAR str __flexarr; 987 1.1 christos } *list = NULL; 988 1.1 christos struct patternlist **lastp = &list; 989 1.1 christos size_t pattern_len = STRLEN (pattern); 990 1.1 christos bool any_malloced = false; 991 1.1 christos const CHAR *p; 992 1.1 christos const CHAR *rs; 993 1.1 christos int retval = 0; 994 1.1 christos 995 1.1 christos /* Parse the pattern. Store the individual parts in the list. */ 996 1.1 christos level = 0; 997 1.1.1.2 christos for (startp = p = pattern + 1; level >= 0; ++p) 998 1.1 christos if (*p == L_('\0')) 999 1.1 christos { 1000 1.1 christos /* This is an invalid pattern. */ 1001 1.1 christos retval = -1; 1002 1.1 christos goto out; 1003 1.1 christos } 1004 1.1 christos else if (*p == L_('[')) 1005 1.1 christos { 1006 1.1 christos /* Handle brackets special. */ 1007 1.1 christos if (posixly_correct == 0) 1008 1.1 christos posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; 1009 1.1 christos 1010 1.1 christos /* Skip the not sign. We have to recognize it because of a possibly 1011 1.1 christos following ']'. */ 1012 1.1 christos if (*++p == L_('!') || (posixly_correct < 0 && *p == L_('^'))) 1013 1.1 christos ++p; 1014 1.1 christos /* A leading ']' is recognized as such. */ 1015 1.1 christos if (*p == L_(']')) 1016 1.1 christos ++p; 1017 1.1 christos /* Skip over all characters of the list. */ 1018 1.1 christos while (*p != L_(']')) 1019 1.1 christos if (*p++ == L_('\0')) 1020 1.1 christos { 1021 1.1 christos /* This is no valid pattern. */ 1022 1.1 christos retval = -1; 1023 1.1 christos goto out; 1024 1.1 christos } 1025 1.1 christos } 1026 1.1 christos else if ((*p == L_('?') || *p == L_('*') || *p == L_('+') || *p == L_('@') 1027 1.1 christos || *p == L_('!')) && p[1] == L_('(')) 1028 1.1 christos /* Remember the nesting level. */ 1029 1.1 christos ++level; 1030 1.1 christos else if (*p == L_(')')) 1031 1.1 christos { 1032 1.1 christos if (level-- == 0) 1033 1.1 christos { 1034 1.1 christos /* This means we found the end of the pattern. */ 1035 1.1 christos #define NEW_PATTERN \ 1036 1.1 christos struct patternlist *newp; \ 1037 1.1 christos size_t plen = (opt == L_('?') || opt == L_('@') \ 1038 1.1 christos ? pattern_len : (p - startp + 1UL)); \ 1039 1.1.1.2 christos idx_t slen = FLEXSIZEOF (struct patternlist, str, 0); \ 1040 1.1.1.2 christos idx_t new_used = alloca_used + slen; \ 1041 1.1.1.2 christos idx_t plensize; \ 1042 1.1 christos if (INT_MULTIPLY_WRAPV (plen, sizeof (CHAR), &plensize) \ 1043 1.1 christos || INT_ADD_WRAPV (new_used, plensize, &new_used)) \ 1044 1.1 christos { \ 1045 1.1 christos retval = -2; \ 1046 1.1 christos goto out; \ 1047 1.1 christos } \ 1048 1.1 christos slen += plensize; \ 1049 1.1 christos bool malloced = ! __libc_use_alloca (new_used); \ 1050 1.1 christos if (__glibc_unlikely (malloced)) \ 1051 1.1 christos { \ 1052 1.1 christos newp = malloc (slen); \ 1053 1.1 christos if (newp == NULL) \ 1054 1.1 christos { \ 1055 1.1 christos retval = -2; \ 1056 1.1 christos goto out; \ 1057 1.1 christos } \ 1058 1.1 christos any_malloced = true; \ 1059 1.1 christos } \ 1060 1.1 christos else \ 1061 1.1 christos newp = alloca_account (slen, alloca_used); \ 1062 1.1 christos newp->next = NULL; \ 1063 1.1 christos newp->malloced = malloced; \ 1064 1.1 christos *((CHAR *) MEMPCPY (newp->str, startp, p - startp)) = L_('\0'); \ 1065 1.1 christos *lastp = newp; \ 1066 1.1 christos lastp = &newp->next 1067 1.1 christos NEW_PATTERN; 1068 1.1 christos } 1069 1.1 christos } 1070 1.1 christos else if (*p == L_('|')) 1071 1.1 christos { 1072 1.1 christos if (level == 0) 1073 1.1 christos { 1074 1.1 christos NEW_PATTERN; 1075 1.1 christos startp = p + 1; 1076 1.1 christos } 1077 1.1 christos } 1078 1.1 christos assert (list != NULL); 1079 1.1 christos assert (p[-1] == L_(')')); 1080 1.1 christos #undef NEW_PATTERN 1081 1.1 christos 1082 1.1 christos switch (opt) 1083 1.1 christos { 1084 1.1 christos case L_('*'): 1085 1.1 christos if (FCT (p, string, string_end, no_leading_period, flags, NULL, 1086 1.1 christos alloca_used) == 0) 1087 1.1 christos goto success; 1088 1.1 christos FALLTHROUGH; 1089 1.1 christos case L_('+'): 1090 1.1 christos do 1091 1.1 christos { 1092 1.1 christos for (rs = string; rs <= string_end; ++rs) 1093 1.1 christos /* First match the prefix with the current pattern with the 1094 1.1 christos current pattern. */ 1095 1.1 christos if (FCT (list->str, string, rs, no_leading_period, 1096 1.1 christos flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD, 1097 1.1 christos NULL, alloca_used) == 0 1098 1.1 christos /* This was successful. Now match the rest with the rest 1099 1.1 christos of the pattern. */ 1100 1.1 christos && (FCT (p, rs, string_end, 1101 1.1 christos rs == string 1102 1.1 christos ? no_leading_period 1103 1.1 christos : rs[-1] == '/' && NO_LEADING_PERIOD (flags), 1104 1.1 christos flags & FNM_FILE_NAME 1105 1.1 christos ? flags : flags & ~FNM_PERIOD, NULL, alloca_used) == 0 1106 1.1 christos /* This didn't work. Try the whole pattern. */ 1107 1.1 christos || (rs != string 1108 1.1 christos && FCT (pattern - 1, rs, string_end, 1109 1.1 christos rs == string 1110 1.1 christos ? no_leading_period 1111 1.1 christos : rs[-1] == '/' && NO_LEADING_PERIOD (flags), 1112 1.1 christos flags & FNM_FILE_NAME 1113 1.1 christos ? flags : flags & ~FNM_PERIOD, NULL, 1114 1.1 christos alloca_used) == 0))) 1115 1.1 christos /* It worked. Signal success. */ 1116 1.1 christos goto success; 1117 1.1 christos } 1118 1.1 christos while ((list = list->next) != NULL); 1119 1.1 christos 1120 1.1 christos /* None of the patterns lead to a match. */ 1121 1.1 christos retval = FNM_NOMATCH; 1122 1.1 christos break; 1123 1.1 christos 1124 1.1 christos case L_('?'): 1125 1.1 christos if (FCT (p, string, string_end, no_leading_period, flags, NULL, 1126 1.1 christos alloca_used) == 0) 1127 1.1 christos goto success; 1128 1.1 christos FALLTHROUGH; 1129 1.1 christos case L_('@'): 1130 1.1 christos do 1131 1.1 christos /* I cannot believe it but 'strcat' is actually acceptable 1132 1.1 christos here. Match the entire string with the prefix from the 1133 1.1 christos pattern list and the rest of the pattern following the 1134 1.1 christos pattern list. */ 1135 1.1 christos if (FCT (STRCAT (list->str, p), string, string_end, 1136 1.1 christos no_leading_period, 1137 1.1 christos flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD, 1138 1.1 christos NULL, alloca_used) == 0) 1139 1.1 christos /* It worked. Signal success. */ 1140 1.1 christos goto success; 1141 1.1 christos while ((list = list->next) != NULL); 1142 1.1 christos 1143 1.1 christos /* None of the patterns lead to a match. */ 1144 1.1 christos retval = FNM_NOMATCH; 1145 1.1 christos break; 1146 1.1 christos 1147 1.1 christos case L_('!'): 1148 1.1 christos for (rs = string; rs <= string_end; ++rs) 1149 1.1 christos { 1150 1.1 christos struct patternlist *runp; 1151 1.1 christos 1152 1.1 christos for (runp = list; runp != NULL; runp = runp->next) 1153 1.1 christos if (FCT (runp->str, string, rs, no_leading_period, 1154 1.1 christos flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD, 1155 1.1 christos NULL, alloca_used) == 0) 1156 1.1 christos break; 1157 1.1 christos 1158 1.1 christos /* If none of the patterns matched see whether the rest does. */ 1159 1.1 christos if (runp == NULL 1160 1.1 christos && (FCT (p, rs, string_end, 1161 1.1 christos rs == string 1162 1.1 christos ? no_leading_period 1163 1.1 christos : rs[-1] == '/' && NO_LEADING_PERIOD (flags), 1164 1.1 christos flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD, 1165 1.1 christos NULL, alloca_used) == 0)) 1166 1.1 christos /* This is successful. */ 1167 1.1 christos goto success; 1168 1.1 christos } 1169 1.1 christos 1170 1.1 christos /* None of the patterns together with the rest of the pattern 1171 1.1 christos lead to a match. */ 1172 1.1 christos retval = FNM_NOMATCH; 1173 1.1 christos break; 1174 1.1 christos 1175 1.1 christos default: 1176 1.1 christos assert (! "Invalid extended matching operator"); 1177 1.1 christos retval = -1; 1178 1.1 christos break; 1179 1.1 christos } 1180 1.1 christos 1181 1.1 christos success: 1182 1.1 christos out: 1183 1.1 christos if (any_malloced) 1184 1.1 christos while (list != NULL) 1185 1.1 christos { 1186 1.1 christos struct patternlist *old = list; 1187 1.1 christos list = list->next; 1188 1.1 christos if (old->malloced) 1189 1.1 christos free (old); 1190 1.1 christos } 1191 1.1 christos 1192 1.1 christos return retval; 1193 1.1 christos } 1194 1.1 christos 1195 1.1 christos 1196 1.1 christos #undef FOLD 1197 1.1 christos #undef CHAR 1198 1.1 christos #undef UCHAR 1199 1.1 christos #undef INT 1200 1.1 christos #undef FCT 1201 1.1 christos #undef EXT 1202 1.1 christos #undef END 1203 1.1 christos #undef STRUCT 1204 1.1 christos #undef MEMPCPY 1205 1.1 christos #undef MEMCHR 1206 1.1 christos #undef STRLEN 1207 1.1 christos #undef STRCAT 1208 1.1 christos #undef L_ 1209 1.1 christos #undef BTOWC 1210 1.1 christos #undef WIDE_CHAR_VERSION 1211 1.1 christos #undef FINDIDX 1212