]> git.ipfire.org Git - thirdparty/bash.git/blob - lib/glob/fnmatch.c
Imported from ../bash-2.04.tar.gz.
[thirdparty/bash.git] / lib / glob / fnmatch.c
1 /* fnmatch.c -- ksh-like extended pattern matching for the shell and filename
2 globbing. */
3
4 /* Copyright (C) 1991, 1997 Free Software Foundation, Inc.
5
6 This file is part of GNU Bash, the Bourne Again SHell.
7
8 Bash is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
12
13 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with Bash; see the file COPYING. If not, write to the Free Software
20 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
21
22 #include <config.h>
23
24 #include <stdio.h> /* for debugging */
25
26 #include "fnmatch.h"
27 #include "collsyms.h"
28 #include <ctype.h>
29
30 #if defined (HAVE_STRING_H)
31 # include <string.h>
32 #else
33 # include <strings.h>
34 #endif /* HAVE_STRING_H */
35
36 static int gmatch ();
37 static char *brackmatch ();
38 #ifdef EXTENDED_GLOB
39 static int extmatch ();
40 static char *patscan ();
41 #endif
42
43 #if !defined (isascii)
44 # define isascii(c) ((unsigned int)(c) <= 0177)
45 #endif
46
47 /* Note that these evaluate C many times. */
48
49 #ifndef isblank
50 # define isblank(c) ((c) == ' ' || (c) == '\t')
51 #endif
52
53 #ifndef isgraph
54 # define isgraph(c) ((c) != ' ' && isprint((c)))
55 #endif
56
57 #ifndef isxdigit
58 # define isxdigit(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
59 #endif
60
61 /* The result of FOLD is an `unsigned char' */
62 # define FOLD(c) ((flags & FNM_CASEFOLD) && isupper ((unsigned char)c) \
63 ? tolower ((unsigned char)c) \
64 : ((unsigned char)c))
65
66 #ifndef STREQ
67 #define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0)
68 #define STREQN(a, b, n) ((a)[0] == (b)[0] && strncmp(a, b, n) == 0)
69 #endif
70
71 /* We don't use strcoll(3) for range comparisons in bracket expressions,
72 even if we have it, since it can have unwanted side effects in locales
73 other than POSIX or US. For instance, in the de locale, [A-Z] matches
74 all characters. So, for ranges we use ASCII collation, and for
75 collating symbol equivalence we use strcoll(). The casts to int are
76 to handle tests that use unsigned chars. */
77
78 #define rangecmp(c1, c2) ((int)(c1) - (int)(c2))
79
80 #if defined (HAVE_STRCOLL)
81 /* Helper function for collating symbol equivalence. */
82 static int rangecmp2 (c1, c2)
83 int c1, c2;
84 {
85 static char s1[2] = { ' ', '\0' };
86 static char s2[2] = { ' ', '\0' };
87 int ret;
88
89 /* Eight bits only. Period. */
90 c1 &= 0xFF;
91 c2 &= 0xFF;
92
93 if (c1 == c2)
94 return (0);
95
96 s1[0] = c1;
97 s2[0] = c2;
98
99 if ((ret = strcoll (s1, s2)) != 0)
100 return ret;
101 return (c1 - c2);
102 }
103 #else /* !HAVE_STRCOLL */
104 # define rangecmp2(c1, c2) ((int)(c1) - (int)(c2))
105 #endif /* !HAVE_STRCOLL */
106
107 #if defined (HAVE_STRCOLL)
108 static int collequiv (c1, c2)
109 int c1, c2;
110 {
111 return (rangecmp2 (c1, c2) == 0);
112 }
113 #else
114 # define collequiv(c1, c2) ((c1) == (c2))
115 #endif
116
117 static int
118 collsym (s, len)
119 char *s;
120 int len;
121 {
122 register struct _collsym *csp;
123
124 for (csp = posix_collsyms; csp->name; csp++)
125 {
126 if (STREQN(csp->name, s, len) && csp->name[len] == '\0')
127 return (csp->code);
128 }
129 if (len == 1)
130 return s[0];
131 return -1;
132 }
133
134 int
135 fnmatch (pattern, string, flags)
136 char *pattern;
137 char *string;
138 int flags;
139 {
140 char *se, *pe;
141
142 if (string == 0 || pattern == 0)
143 return FNM_NOMATCH;
144
145 se = string + strlen (string);
146 pe = pattern + strlen (pattern);
147
148 return (gmatch (string, se, pattern, pe, flags));
149 }
150
151 /* Match STRING against the filename pattern PATTERN, returning zero if
152 it matches, FNM_NOMATCH if not. */
153 static int
154 gmatch (string, se, pattern, pe, flags)
155 char *string, *se;
156 char *pattern, *pe;
157 int flags;
158 {
159 register char *p, *n; /* pattern, string */
160 register char c; /* current pattern character */
161 register char sc; /* current string character */
162
163 p = pattern;
164 n = string;
165
166 if (string == 0 || pattern == 0)
167 return FNM_NOMATCH;
168
169 while (p < pe)
170 {
171 c = *p++;
172 c = FOLD (c);
173
174 sc = n < se ? *n : '\0';
175
176 #ifdef EXTENDED_GLOB
177 /* extmatch () will handle recursively calling gmatch, so we can
178 just return what extmatch() returns. */
179 if ((flags & FNM_EXTMATCH) && *p == '(' &&
180 (c == '+' || c == '*' || c == '?' || c == '@' || c == '!')) /* ) */
181 {
182 int lflags;
183 /* If we're not matching the start of the string, we're not
184 concerned about the special cases for matching `.' */
185 lflags = (n == string) ? flags : (flags & ~FNM_PERIOD);
186 return (extmatch (c, n, se, p, pe, lflags));
187 }
188 #endif
189
190 switch (c)
191 {
192 case '?': /* Match single character */
193 if (sc == '\0')
194 return FNM_NOMATCH;
195 else if ((flags & FNM_PATHNAME) && sc == '/')
196 /* If we are matching a pathname, `?' can never match a `/'. */
197 return FNM_NOMATCH;
198 else if ((flags & FNM_PERIOD) && sc == '.' &&
199 (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
200 /* `?' cannot match a `.' if it is the first character of the
201 string or if it is the first character following a slash and
202 we are matching a pathname. */
203 return FNM_NOMATCH;
204 break;
205
206 case '\\': /* backslash escape removes special meaning */
207 if (p == pe)
208 return FNM_NOMATCH;
209
210 if ((flags & FNM_NOESCAPE) == 0)
211 {
212 c = *p++;
213 /* A trailing `\' cannot match. */
214 if (p > pe)
215 return FNM_NOMATCH;
216 c = FOLD (c);
217 }
218 if (FOLD (sc) != (unsigned char)c)
219 return FNM_NOMATCH;
220 break;
221
222 case '*': /* Match zero or more characters */
223 if (p == pe)
224 return 0;
225
226 if ((flags & FNM_PERIOD) && sc == '.' &&
227 (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
228 /* `*' cannot match a `.' if it is the first character of the
229 string or if it is the first character following a slash and
230 we are matching a pathname. */
231 return FNM_NOMATCH;
232
233 /* Collapse multiple consecutive, `*' and `?', but make sure that
234 one character of the string is consumed for each `?'. */
235 for (c = *p++; (c == '?' || c == '*'); c = *p++)
236 {
237 if ((flags & FNM_PATHNAME) && sc == '/')
238 /* A slash does not match a wildcard under FNM_PATHNAME. */
239 return FNM_NOMATCH;
240 else if (c == '?')
241 {
242 if (sc == '\0')
243 return FNM_NOMATCH;
244 /* One character of the string is consumed in matching
245 this ? wildcard, so *??? won't match if there are
246 fewer than three characters. */
247 n++;
248 sc = n < se ? *n : '\0';
249 }
250
251 #ifdef EXTENDED_GLOB
252 /* Handle ******(patlist) */
253 if ((flags & FNM_EXTMATCH) && c == '*' && *p == '(') /*)*/
254 {
255 char *newn;
256 /* We need to check whether or not the extended glob
257 pattern matches the remainder of the string.
258 If it does, we match the entire pattern. */
259 for (newn = n; newn < se; ++newn)
260 {
261 if (extmatch (c, newn, se, p, pe, flags) == 0)
262 return (0);
263 }
264 /* We didn't match the extended glob pattern, but
265 that's OK, since we can match 0 or more occurrences.
266 We need to skip the glob pattern and see if we
267 match the rest of the string. */
268 newn = patscan (p + 1, pe, 0);
269 p = newn;
270 }
271 #endif
272 if (p == pe)
273 break;
274 }
275
276 /* If we've hit the end of the pattern and the last character of
277 the pattern was handled by the loop above, we've succeeded.
278 Otherwise, we need to match that last character. */
279 if (p == pe && (c == '?' || c == '*'))
280 return (0);
281
282 /* General case, use recursion. */
283 {
284 unsigned char c1;
285
286 c1 = (unsigned char)((flags & FNM_NOESCAPE) == 0 && c == '\\') ? *p : c;
287 c1 = FOLD (c1);
288 for (--p; n < se; ++n)
289 {
290 /* Only call fnmatch if the first character indicates a
291 possible match. We can check the first character if
292 we're not doing an extended glob match. */
293 if ((flags & FNM_EXTMATCH) == 0 && c != '[' && FOLD (*n) != c1)
294 continue;
295
296 /* If we're doing an extended glob match and the pattern is not
297 one of the extended glob patterns, we can check the first
298 character. */
299 if ((flags & FNM_EXTMATCH) && p[1] != '(' && /*)*/
300 strchr ("?*+@!", *p) == 0 && c != '[' && FOLD (*n) != c1)
301 continue;
302
303 /* Otherwise, we just recurse. */
304 if (gmatch (n, se, p, pe, flags & ~FNM_PERIOD) == 0)
305 return (0);
306 }
307 return FNM_NOMATCH;
308 }
309
310 case '[':
311 {
312 if (sc == '\0' || n == se)
313 return FNM_NOMATCH;
314
315 /* A character class cannot match a `.' if it is the first
316 character of the string or if it is the first character
317 following a slash and we are matching a pathname. */
318 if ((flags & FNM_PERIOD) && sc == '.' &&
319 (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
320 return (FNM_NOMATCH);
321
322 p = brackmatch (p, sc, flags);
323 if (p == 0)
324 return FNM_NOMATCH;
325 }
326 break;
327
328 default:
329 if ((unsigned char)c != FOLD (sc))
330 return (FNM_NOMATCH);
331 }
332
333 ++n;
334 }
335
336 if (n == se)
337 return (0);
338
339 if ((flags & FNM_LEADING_DIR) && *n == '/')
340 /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
341 return 0;
342
343 return (FNM_NOMATCH);
344 }
345
346 /* Parse a bracket expression collating symbol ([.sym.]) starting at P, find
347 the value of the symbol, and move P past the collating symbol expression.
348 The value is returned in *VP, if VP is not null. */
349 static char *
350 parse_collsym (p, vp)
351 char *p;
352 int *vp;
353 {
354 register int pc;
355 int val;
356
357 p++; /* move past the `.' */
358
359 for (pc = 0; p[pc]; pc++)
360 if (p[pc] == '.' && p[pc+1] == ']')
361 break;
362 val = collsym (p, pc);
363 if (vp)
364 *vp = val;
365 return (p + pc + 2);
366 }
367
368 static char *
369 brackmatch (p, test, flags)
370 char *p;
371 unsigned char test;
372 int flags;
373 {
374 register char cstart, cend, c;
375 register int not; /* Nonzero if the sense of the character class is inverted. */
376 int pc, brcnt;
377 char *savep;
378
379 test = FOLD (test);
380
381 savep = p;
382
383 /* POSIX.2 3.13.1 says that an exclamation mark (`!') shall replace the
384 circumflex (`^') in its role in a `nonmatching list'. A bracket
385 expression starging with an unquoted circumflex character produces
386 unspecified results. This implementation treats the two identically. */
387 if (not = (*p == '!' || *p == '^'))
388 ++p;
389
390 c = *p++;
391 for (;;)
392 {
393 /* Initialize cstart and cend in case `-' is the last
394 character of the pattern. */
395 cstart = cend = c;
396
397 /* POSIX.2 equivalence class: [=c=]. See POSIX.2 2.8.3.2. Find
398 the end of the equivalence class, move the pattern pointer past
399 it, and check for equivalence. XXX - this handles only
400 single-character equivalence classes, which is wrong, or at
401 least incomplete. */
402 if (c == '[' && *p == '=' && p[2] == '=' && p[3] == ']')
403 {
404 pc = FOLD (p[1]);
405 p += 4;
406 if (collequiv (test, pc))
407 goto matched;
408 else
409 {
410 c = *p++;
411 if (c == '\0')
412 return ((test == '[') ? savep : (char *)0);
413 c = FOLD (c);
414 continue;
415 }
416 }
417
418 /* POSIX.2 character class expression. See POSIX.2 2.8.3.2. */
419 if (c == '[' && *p == ':')
420 {
421 pc = 0; /* make sure invalid char classes don't match. */
422 if (STREQN (p+1, "alnum:]", 7))
423 { pc = isalnum (test); p += 8; }
424 else if (STREQN (p+1, "alpha:]", 7))
425 { pc = isalpha (test); p += 8; }
426 else if (STREQN (p+1, "blank:]", 7))
427 { pc = isblank (test); p += 8; }
428 else if (STREQN (p+1, "cntrl:]", 7))
429 { pc = iscntrl (test); p += 8; }
430 else if (STREQN (p+1, "digit:]", 7))
431 { pc = isdigit (test); p += 8; }
432 else if (STREQN (p+1, "graph:]", 7))
433 { pc = isgraph (test); p += 8; }
434 else if (STREQN (p+1, "lower:]", 7))
435 { pc = islower (test); p += 8; }
436 else if (STREQN (p+1, "print:]", 7))
437 { pc = isprint (test); p += 8; }
438 else if (STREQN (p+1, "punct:]", 7))
439 { pc = ispunct (test); p += 8; }
440 else if (STREQN (p+1, "space:]", 7))
441 { pc = isspace (test); p += 8; }
442 else if (STREQN (p+1, "upper:]", 7))
443 { pc = isupper (test); p += 8; }
444 else if (STREQN (p+1, "xdigit:]", 8))
445 { pc = isxdigit (test); p += 9; }
446 else if (STREQN (p+1, "ascii:]", 7))
447 { pc = isascii (test); p += 8; }
448 if (pc)
449 goto matched;
450 else
451 {
452 /* continue the loop here, since this expression can't be
453 the first part of a range expression. */
454 c = *p++;
455 if (c == '\0')
456 return ((test == '[') ? savep : (char *)0);
457 else if (c == ']')
458 break;
459 c = FOLD (c);
460 continue;
461 }
462 }
463
464 /* POSIX.2 collating symbols. See POSIX.2 2.8.3.2. Find the end of
465 the symbol name, make sure it is terminated by `.]', translate
466 the name to a character using the external table, and do the
467 comparison. */
468 if (c == '[' && *p == '.')
469 {
470 p = parse_collsym (p, &pc);
471 /* An invalid collating symbol cannot be the first point of a
472 range. If it is, we set cstart to one greater than `test',
473 so any comparisons later will fail. */
474 cstart = (pc == -1) ? test + 1 : pc;
475 }
476
477 if (!(flags & FNM_NOESCAPE) && c == '\\')
478 {
479 if (*p == '\0')
480 return (char *)0;
481 cstart = cend = *p++;
482 }
483
484 cstart = cend = FOLD (cstart);
485
486 /* POSIX.2 2.8.3.1.2 says: `An expression containing a `[' that
487 is not preceded by a backslash and is not part of a bracket
488 expression produces undefined results.' This implementation
489 treats the `[' as just a character to be matched if there is
490 not a closing `]'. */
491 if (c == '\0')
492 return ((test == '[') ? savep : (char *)0);
493
494 c = *p++;
495 c = FOLD (c);
496
497 if ((flags & FNM_PATHNAME) && c == '/')
498 /* [/] can never match when matching a pathname. */
499 return (char *)0;
500
501 /* This introduces a range, unless the `-' is the last
502 character of the class. Find the end of the range
503 and move past it. */
504 if (c == '-' && *p != ']')
505 {
506 cend = *p++;
507 if (!(flags & FNM_NOESCAPE) && cend == '\\')
508 cend = *p++;
509 if (cend == '\0')
510 return (char *)0;
511 if (cend == '[' && *p == '.')
512 {
513 p = parse_collsym (p, &pc);
514 /* An invalid collating symbol cannot be the second part of a
515 range expression. If we get one, we set cend to one fewer
516 than the test character to make sure the range test fails. */
517 cend = (pc == -1) ? test - 1 : pc;
518 }
519 cend = FOLD (cend);
520
521 c = *p++;
522
523 /* POSIX.2 2.8.3.2: ``The ending range point shall collate
524 equal to or higher than the starting range point; otherwise
525 the expression shall be treated as invalid.'' Note that this
526 applies to only the range expression; the rest of the bracket
527 expression is still checked for matches. */
528 if (rangecmp (cstart, cend) > 0)
529 {
530 if (c == ']')
531 break;
532 c = FOLD (c);
533 continue;
534 }
535 }
536
537 if (rangecmp (test, cstart) >= 0 && rangecmp (test, cend) <= 0)
538 goto matched;
539
540 if (c == ']')
541 break;
542 }
543 /* No match. */
544 return (!not ? (char *)0 : p);
545
546 matched:
547 /* Skip the rest of the [...] that already matched. */
548 brcnt = (c != ']') + (c == '[' && (*p == '=' || *p == ':' || *p == '.'));
549 while (brcnt > 0)
550 {
551 /* A `[' without a matching `]' is just another character to match. */
552 if (c == '\0')
553 return ((test == '[') ? savep : (char *)0);
554
555 c = *p++;
556 if (c == '[' && (*p == '=' || *p == ':' || *p == '.'))
557 brcnt++;
558 else if (c == ']')
559 brcnt--;
560 else if (!(flags & FNM_NOESCAPE) && c == '\\')
561 {
562 if (*p == '\0')
563 return (char *)0;
564 /* XXX 1003.2d11 is unclear if this is right. */
565 ++p;
566 }
567 }
568 return (not ? (char *)0 : p);
569 }
570
571 #if defined (EXTENDED_GLOB)
572 /* ksh-like extended pattern matching:
573
574 [?*+@!](pat-list)
575
576 where pat-list is a list of one or patterns separated by `|'. Operation
577 is as follows:
578
579 ?(patlist) match zero or one of the given patterns
580 *(patlist) match zero or more of the given patterns
581 +(patlist) match one or more of the given patterns
582 @(patlist) match exactly one of the given patterns
583 !(patlist) match anything except one of the given patterns
584 */
585
586 /* Scan a pattern starting at STRING and ending at END, keeping track of
587 embedded () and []. If DELIM is 0, we scan until a matching `)'
588 because we're scanning a `patlist'. Otherwise, we scan until we see
589 DELIM. In all cases, we never scan past END. The return value is the
590 first character after the matching DELIM. */
591 static char *
592 patscan (string, end, delim)
593 char *string, *end;
594 int delim;
595 {
596 int pnest, bnest;
597 char *s, c;
598
599 pnest = bnest = 0;
600 for (s = string; c = *s; s++)
601 {
602 if (s >= end)
603 return (s);
604 switch (c)
605 {
606 case '\0':
607 return ((char *)0);
608 case '[':
609 bnest++;
610 break;
611 case ']':
612 if (bnest)
613 bnest--;
614 break;
615 case '(':
616 if (bnest == 0)
617 pnest++;
618 break;
619 case ')':
620 #if 0
621 if (bnest == 0)
622 pnest--;
623 if (pnest <= 0)
624 return ++s;
625 #else
626 if (bnest == 0 && pnest-- <= 0)
627 return ++s;
628 #endif
629 break;
630 case '|':
631 if (bnest == 0 && pnest == 0 && delim == '|')
632 return ++s;
633 break;
634 }
635 }
636
637 return (char *)0;
638 }
639
640 /* Return 0 if dequoted pattern matches S in the current locale. */
641 static int
642 strcompare (p, pe, s, se)
643 char *p, *pe, *s, *se;
644 {
645 int ret;
646 char c1, c2;
647
648 c1 = *pe;
649 c2 = *se;
650
651 *pe = *se = '\0';
652 #if defined (HAVE_STRCOLL)
653 ret = strcoll (p, s);
654 #else
655 ret = strcmp (p, s);
656 #endif
657
658 *pe = c1;
659 *se = c2;
660
661 return (ret == 0 ? ret : FNM_NOMATCH);
662 }
663
664 /* Match a ksh extended pattern specifier. Return FNM_NOMATCH on failure or
665 0 on success. This is handed the entire rest of the pattern and string
666 the first time an extended pattern specifier is encountered, so it calls
667 gmatch recursively. */
668 static int
669 extmatch (xc, s, se, p, pe, flags)
670 int xc; /* select which operation */
671 char *s, *se;
672 char *p, *pe;
673 int flags;
674 {
675 char *prest; /* pointer to rest of pattern */
676 char *psub; /* pointer to sub-pattern */
677 char *pnext; /* pointer to next sub-pattern */
678 char *srest; /* pointer to rest of string */
679 int m1, m2;
680
681 #if 0
682 fprintf(stderr, "extmatch: xc = %c\n", xc);
683 fprintf(stderr, "extmatch: s = %s; se = %s\n", s, se);
684 fprintf(stderr, "extmatch: p = %s; pe = %s\n", p, pe);
685 #endif
686
687 prest = patscan (p + (*p == '('), pe, 0); /* ) */
688 if (prest == 0)
689 /* If PREST is 0, we failed to scan a valid pattern. In this
690 case, we just want to compare the two as strings. */
691 return (strcompare (p - 1, pe, s, se));
692
693 switch (xc)
694 {
695 case '+': /* match one or more occurrences */
696 case '*': /* match zero or more occurrences */
697 /* If we can get away with no matches, don't even bother. Just
698 call gmatch on the rest of the pattern and return success if
699 it succeeds. */
700 if (xc == '*' && (gmatch (s, se, prest, pe, flags) == 0))
701 return 0;
702
703 /* OK, we have to do this the hard way. First, we make sure one of
704 the subpatterns matches, then we try to match the rest of the
705 string. */
706 for (psub = p + 1; ; psub = pnext)
707 {
708 pnext = patscan (psub, pe, '|');
709 for (srest = s; srest <= se; srest++)
710 {
711 /* Match this substring (S -> SREST) against this
712 subpattern (psub -> pnext - 1) */
713 m1 = gmatch (s, srest, psub, pnext - 1, flags) == 0;
714 /* OK, we matched a subpattern, so make sure the rest of the
715 string matches the rest of the pattern. Also handle
716 multiple matches of the pattern. */
717 if (m1)
718 m2 = (gmatch (srest, se, prest, pe, flags) == 0) ||
719 (s != srest && gmatch (srest, se, p - 1, pe, flags) == 0);
720 if (m1 && m2)
721 return (0);
722 }
723 if (pnext == prest)
724 break;
725 }
726 return (FNM_NOMATCH);
727
728 case '?': /* match zero or one of the patterns */
729 case '@': /* match exactly one of the patterns */
730 /* If we can get away with no matches, don't even bother. Just
731 call gmatch on the rest of the pattern and return success if
732 it succeeds. */
733 if (xc == '?' && (gmatch (s, se, prest, pe, flags) == 0))
734 return 0;
735
736 /* OK, we have to do this the hard way. First, we see if one of
737 the subpatterns matches, then, if it does, we try to match the
738 rest of the string. */
739 for (psub = p + 1; ; psub = pnext)
740 {
741 pnext = patscan (psub, pe, '|');
742 srest = (prest == pe) ? se : s;
743 for ( ; srest <= se; srest++)
744 {
745 if (gmatch (s, srest, psub, pnext - 1, flags) == 0 &&
746 gmatch (srest, se, prest, pe, flags) == 0)
747 return (0);
748 }
749 if (pnext == prest)
750 break;
751 }
752 return (FNM_NOMATCH);
753
754 case '!': /* match anything *except* one of the patterns */
755 for (srest = s; srest <= se; srest++)
756 {
757 m1 = 0;
758 for (psub = p + 1; ; psub = pnext)
759 {
760 pnext = patscan (psub, pe, '|');
761 /* If one of the patterns matches, just bail immediately. */
762 if (m1 = (gmatch (s, srest, psub, pnext - 1, flags) == 0))
763 break;
764 if (pnext == prest)
765 break;
766 }
767 if (m1 == 0 && gmatch (srest, se, prest, pe, flags) == 0)
768 return (0);
769 }
770 return (FNM_NOMATCH);
771 }
772
773 return (FNM_NOMATCH);
774 }
775 #endif /* EXTENDED_GLOB */
776
777 #ifdef TEST
778 main (c, v)
779 int c;
780 char **v;
781 {
782 char *string, *pat;
783
784 string = v[1];
785 pat = v[2];
786
787 if (fnmatch (pat, string, 0) == 0)
788 {
789 printf ("%s matches %s\n", string, pat);
790 exit (0);
791 }
792 else
793 {
794 printf ("%s does not match %s\n", string, pat);
795 exit (1);
796 }
797 }
798 #endif