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