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