Simple embedded shell with runtime pluggable commands.
Implements a simple unix-like shell for embedded systems with a pluggable command architecture.
fnmatch.c@31:27e8130a0d8f, 2018-12-28 (annotated)
- Committer:
- shimniok
- Date:
- Fri Dec 28 17:10:31 2018 +0000
- Revision:
- 31:27e8130a0d8f
began wildcard implementation
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
shimniok | 31:27e8130a0d8f | 1 | /* |
shimniok | 31:27e8130a0d8f | 2 | * Copyright (c) 1989, 1993, 1994 |
shimniok | 31:27e8130a0d8f | 3 | * The Regents of the University of California. All rights reserved. |
shimniok | 31:27e8130a0d8f | 4 | * |
shimniok | 31:27e8130a0d8f | 5 | * This code is derived from software contributed to Berkeley by |
shimniok | 31:27e8130a0d8f | 6 | * Guido van Rossum. |
shimniok | 31:27e8130a0d8f | 7 | * |
shimniok | 31:27e8130a0d8f | 8 | * Redistribution and use in source and binary forms, with or without |
shimniok | 31:27e8130a0d8f | 9 | * modification, are permitted provided that the following conditions |
shimniok | 31:27e8130a0d8f | 10 | * are met: |
shimniok | 31:27e8130a0d8f | 11 | * 1. Redistributions of source code must retain the above copyright |
shimniok | 31:27e8130a0d8f | 12 | * notice, this list of conditions and the following disclaimer. |
shimniok | 31:27e8130a0d8f | 13 | * 2. Redistributions in binary form must reproduce the above copyright |
shimniok | 31:27e8130a0d8f | 14 | * notice, this list of conditions and the following disclaimer in the |
shimniok | 31:27e8130a0d8f | 15 | * documentation and/or other materials provided with the distribution. |
shimniok | 31:27e8130a0d8f | 16 | * 3. All advertising materials mentioning features or use of this software |
shimniok | 31:27e8130a0d8f | 17 | * must display the following acknowledgement: |
shimniok | 31:27e8130a0d8f | 18 | * This product includes software developed by the University of |
shimniok | 31:27e8130a0d8f | 19 | * California, Berkeley and its contributors. |
shimniok | 31:27e8130a0d8f | 20 | * 4. Neither the name of the University nor the names of its contributors |
shimniok | 31:27e8130a0d8f | 21 | * may be used to endorse or promote products derived from this software |
shimniok | 31:27e8130a0d8f | 22 | * without specific prior written permission. |
shimniok | 31:27e8130a0d8f | 23 | * |
shimniok | 31:27e8130a0d8f | 24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
shimniok | 31:27e8130a0d8f | 25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
shimniok | 31:27e8130a0d8f | 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
shimniok | 31:27e8130a0d8f | 27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
shimniok | 31:27e8130a0d8f | 28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
shimniok | 31:27e8130a0d8f | 29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
shimniok | 31:27e8130a0d8f | 30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
shimniok | 31:27e8130a0d8f | 31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
shimniok | 31:27e8130a0d8f | 32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
shimniok | 31:27e8130a0d8f | 33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
shimniok | 31:27e8130a0d8f | 34 | * SUCH DAMAGE. |
shimniok | 31:27e8130a0d8f | 35 | * |
shimniok | 31:27e8130a0d8f | 36 | * From FreeBSD fnmatch.c 1.11 |
shimniok | 31:27e8130a0d8f | 37 | * $Id: fnmatch.c,v 1.3 1997/08/19 02:34:30 jdp Exp $ |
shimniok | 31:27e8130a0d8f | 38 | */ |
shimniok | 31:27e8130a0d8f | 39 | |
shimniok | 31:27e8130a0d8f | 40 | #if defined(LIBC_SCCS) && !defined(lint) |
shimniok | 31:27e8130a0d8f | 41 | static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94"; |
shimniok | 31:27e8130a0d8f | 42 | #endif /* LIBC_SCCS and not lint */ |
shimniok | 31:27e8130a0d8f | 43 | |
shimniok | 31:27e8130a0d8f | 44 | /* |
shimniok | 31:27e8130a0d8f | 45 | * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6. |
shimniok | 31:27e8130a0d8f | 46 | * Compares a filename or pathname to a pattern. |
shimniok | 31:27e8130a0d8f | 47 | */ |
shimniok | 31:27e8130a0d8f | 48 | |
shimniok | 31:27e8130a0d8f | 49 | #include <ctype.h> |
shimniok | 31:27e8130a0d8f | 50 | #include <string.h> |
shimniok | 31:27e8130a0d8f | 51 | #include <stdio.h> |
shimniok | 31:27e8130a0d8f | 52 | |
shimniok | 31:27e8130a0d8f | 53 | #include "fnmatch.h" |
shimniok | 31:27e8130a0d8f | 54 | |
shimniok | 31:27e8130a0d8f | 55 | #define EOS '\0' |
shimniok | 31:27e8130a0d8f | 56 | |
shimniok | 31:27e8130a0d8f | 57 | static const char *rangematch(const char *, char, int); |
shimniok | 31:27e8130a0d8f | 58 | |
shimniok | 31:27e8130a0d8f | 59 | int fnmatch(const char *pattern, const char *string, int flags) |
shimniok | 31:27e8130a0d8f | 60 | { |
shimniok | 31:27e8130a0d8f | 61 | const char *stringstart; |
shimniok | 31:27e8130a0d8f | 62 | char c, test; |
shimniok | 31:27e8130a0d8f | 63 | |
shimniok | 31:27e8130a0d8f | 64 | for (stringstart = string;;) |
shimniok | 31:27e8130a0d8f | 65 | switch (c = *pattern++) { |
shimniok | 31:27e8130a0d8f | 66 | case EOS: |
shimniok | 31:27e8130a0d8f | 67 | if ((flags & FNM_LEADING_DIR) && *string == '/') |
shimniok | 31:27e8130a0d8f | 68 | return (0); |
shimniok | 31:27e8130a0d8f | 69 | return (*string == EOS ? 0 : FNM_NOMATCH); |
shimniok | 31:27e8130a0d8f | 70 | case '?': |
shimniok | 31:27e8130a0d8f | 71 | if (*string == EOS) |
shimniok | 31:27e8130a0d8f | 72 | return (FNM_NOMATCH); |
shimniok | 31:27e8130a0d8f | 73 | if (*string == '/' && (flags & FNM_PATHNAME)) |
shimniok | 31:27e8130a0d8f | 74 | return (FNM_NOMATCH); |
shimniok | 31:27e8130a0d8f | 75 | if (*string == '.' && (flags & FNM_PERIOD) && |
shimniok | 31:27e8130a0d8f | 76 | (string == stringstart || |
shimniok | 31:27e8130a0d8f | 77 | ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) |
shimniok | 31:27e8130a0d8f | 78 | return (FNM_NOMATCH); |
shimniok | 31:27e8130a0d8f | 79 | ++string; |
shimniok | 31:27e8130a0d8f | 80 | break; |
shimniok | 31:27e8130a0d8f | 81 | case '*': |
shimniok | 31:27e8130a0d8f | 82 | c = *pattern; |
shimniok | 31:27e8130a0d8f | 83 | /* Collapse multiple stars. */ |
shimniok | 31:27e8130a0d8f | 84 | while (c == '*') |
shimniok | 31:27e8130a0d8f | 85 | c = *++pattern; |
shimniok | 31:27e8130a0d8f | 86 | |
shimniok | 31:27e8130a0d8f | 87 | if (*string == '.' && (flags & FNM_PERIOD) && |
shimniok | 31:27e8130a0d8f | 88 | (string == stringstart || |
shimniok | 31:27e8130a0d8f | 89 | ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) |
shimniok | 31:27e8130a0d8f | 90 | return (FNM_NOMATCH); |
shimniok | 31:27e8130a0d8f | 91 | |
shimniok | 31:27e8130a0d8f | 92 | /* Optimize for pattern with * at end or before /. */ |
shimniok | 31:27e8130a0d8f | 93 | if (c == EOS) |
shimniok | 31:27e8130a0d8f | 94 | if (flags & FNM_PATHNAME) |
shimniok | 31:27e8130a0d8f | 95 | return ((flags & FNM_LEADING_DIR) || |
shimniok | 31:27e8130a0d8f | 96 | strchr(string, '/') == NULL ? |
shimniok | 31:27e8130a0d8f | 97 | 0 : FNM_NOMATCH); |
shimniok | 31:27e8130a0d8f | 98 | else |
shimniok | 31:27e8130a0d8f | 99 | return (0); |
shimniok | 31:27e8130a0d8f | 100 | else if (c == '/' && flags & FNM_PATHNAME) { |
shimniok | 31:27e8130a0d8f | 101 | if ((string = strchr(string, '/')) == NULL) |
shimniok | 31:27e8130a0d8f | 102 | return (FNM_NOMATCH); |
shimniok | 31:27e8130a0d8f | 103 | break; |
shimniok | 31:27e8130a0d8f | 104 | } |
shimniok | 31:27e8130a0d8f | 105 | |
shimniok | 31:27e8130a0d8f | 106 | /* General case, use recursion. */ |
shimniok | 31:27e8130a0d8f | 107 | while ((test = *string) != EOS) { |
shimniok | 31:27e8130a0d8f | 108 | if (!fnmatch(pattern, string, flags & ~FNM_PERIOD)) |
shimniok | 31:27e8130a0d8f | 109 | return (0); |
shimniok | 31:27e8130a0d8f | 110 | if (test == '/' && flags & FNM_PATHNAME) |
shimniok | 31:27e8130a0d8f | 111 | break; |
shimniok | 31:27e8130a0d8f | 112 | ++string; |
shimniok | 31:27e8130a0d8f | 113 | } |
shimniok | 31:27e8130a0d8f | 114 | return (FNM_NOMATCH); |
shimniok | 31:27e8130a0d8f | 115 | case '[': |
shimniok | 31:27e8130a0d8f | 116 | if (*string == EOS) |
shimniok | 31:27e8130a0d8f | 117 | return (FNM_NOMATCH); |
shimniok | 31:27e8130a0d8f | 118 | if (*string == '/' && flags & FNM_PATHNAME) |
shimniok | 31:27e8130a0d8f | 119 | return (FNM_NOMATCH); |
shimniok | 31:27e8130a0d8f | 120 | if ((pattern = |
shimniok | 31:27e8130a0d8f | 121 | rangematch(pattern, *string, flags)) == NULL) |
shimniok | 31:27e8130a0d8f | 122 | return (FNM_NOMATCH); |
shimniok | 31:27e8130a0d8f | 123 | ++string; |
shimniok | 31:27e8130a0d8f | 124 | break; |
shimniok | 31:27e8130a0d8f | 125 | case '\\': |
shimniok | 31:27e8130a0d8f | 126 | if (!(flags & FNM_NOESCAPE)) { |
shimniok | 31:27e8130a0d8f | 127 | if ((c = *pattern++) == EOS) { |
shimniok | 31:27e8130a0d8f | 128 | c = '\\'; |
shimniok | 31:27e8130a0d8f | 129 | --pattern; |
shimniok | 31:27e8130a0d8f | 130 | } |
shimniok | 31:27e8130a0d8f | 131 | } |
shimniok | 31:27e8130a0d8f | 132 | /* FALLTHROUGH */ |
shimniok | 31:27e8130a0d8f | 133 | default: |
shimniok | 31:27e8130a0d8f | 134 | if (c == *string) |
shimniok | 31:27e8130a0d8f | 135 | ; |
shimniok | 31:27e8130a0d8f | 136 | else if ((flags & FNM_CASEFOLD) && |
shimniok | 31:27e8130a0d8f | 137 | (tolower((unsigned char)c) == |
shimniok | 31:27e8130a0d8f | 138 | tolower((unsigned char)*string))) |
shimniok | 31:27e8130a0d8f | 139 | ; |
shimniok | 31:27e8130a0d8f | 140 | else if ((flags & FNM_PREFIX_DIRS) && *string == EOS && |
shimniok | 31:27e8130a0d8f | 141 | ((c == '/' && string != stringstart) || |
shimniok | 31:27e8130a0d8f | 142 | (string == stringstart+1 && *stringstart == '/'))) |
shimniok | 31:27e8130a0d8f | 143 | return (0); |
shimniok | 31:27e8130a0d8f | 144 | else |
shimniok | 31:27e8130a0d8f | 145 | return (FNM_NOMATCH); |
shimniok | 31:27e8130a0d8f | 146 | string++; |
shimniok | 31:27e8130a0d8f | 147 | break; |
shimniok | 31:27e8130a0d8f | 148 | } |
shimniok | 31:27e8130a0d8f | 149 | /* NOTREACHED */ |
shimniok | 31:27e8130a0d8f | 150 | } |
shimniok | 31:27e8130a0d8f | 151 | |
shimniok | 31:27e8130a0d8f | 152 | static const char * |
shimniok | 31:27e8130a0d8f | 153 | rangematch(const char *pattern, char test, int flags) |
shimniok | 31:27e8130a0d8f | 154 | { |
shimniok | 31:27e8130a0d8f | 155 | int negate, ok; |
shimniok | 31:27e8130a0d8f | 156 | char c, c2; |
shimniok | 31:27e8130a0d8f | 157 | |
shimniok | 31:27e8130a0d8f | 158 | /* |
shimniok | 31:27e8130a0d8f | 159 | * A bracket expression starting with an unquoted circumflex |
shimniok | 31:27e8130a0d8f | 160 | * character produces unspecified results (IEEE 1003.2-1992, |
shimniok | 31:27e8130a0d8f | 161 | * 3.13.2). This implementation treats it like '!', for |
shimniok | 31:27e8130a0d8f | 162 | * consistency with the regular expression syntax. |
shimniok | 31:27e8130a0d8f | 163 | * J.T. Conklin (conklin@ngai.kaleida.com) |
shimniok | 31:27e8130a0d8f | 164 | */ |
shimniok | 31:27e8130a0d8f | 165 | if ( (negate = (*pattern == '!' || *pattern == '^')) ) |
shimniok | 31:27e8130a0d8f | 166 | ++pattern; |
shimniok | 31:27e8130a0d8f | 167 | |
shimniok | 31:27e8130a0d8f | 168 | if (flags & FNM_CASEFOLD) |
shimniok | 31:27e8130a0d8f | 169 | test = tolower((unsigned char)test); |
shimniok | 31:27e8130a0d8f | 170 | |
shimniok | 31:27e8130a0d8f | 171 | for (ok = 0; (c = *pattern++) != ']';) { |
shimniok | 31:27e8130a0d8f | 172 | if (c == '\\' && !(flags & FNM_NOESCAPE)) |
shimniok | 31:27e8130a0d8f | 173 | c = *pattern++; |
shimniok | 31:27e8130a0d8f | 174 | if (c == EOS) |
shimniok | 31:27e8130a0d8f | 175 | return (NULL); |
shimniok | 31:27e8130a0d8f | 176 | |
shimniok | 31:27e8130a0d8f | 177 | if (flags & FNM_CASEFOLD) |
shimniok | 31:27e8130a0d8f | 178 | c = tolower((unsigned char)c); |
shimniok | 31:27e8130a0d8f | 179 | |
shimniok | 31:27e8130a0d8f | 180 | if (*pattern == '-' |
shimniok | 31:27e8130a0d8f | 181 | && (c2 = *(pattern+1)) != EOS && c2 != ']') { |
shimniok | 31:27e8130a0d8f | 182 | pattern += 2; |
shimniok | 31:27e8130a0d8f | 183 | if (c2 == '\\' && !(flags & FNM_NOESCAPE)) |
shimniok | 31:27e8130a0d8f | 184 | c2 = *pattern++; |
shimniok | 31:27e8130a0d8f | 185 | if (c2 == EOS) |
shimniok | 31:27e8130a0d8f | 186 | return (NULL); |
shimniok | 31:27e8130a0d8f | 187 | |
shimniok | 31:27e8130a0d8f | 188 | if (flags & FNM_CASEFOLD) |
shimniok | 31:27e8130a0d8f | 189 | c2 = tolower((unsigned char)c2); |
shimniok | 31:27e8130a0d8f | 190 | |
shimniok | 31:27e8130a0d8f | 191 | if ((unsigned char)c <= (unsigned char)test && |
shimniok | 31:27e8130a0d8f | 192 | (unsigned char)test <= (unsigned char)c2) |
shimniok | 31:27e8130a0d8f | 193 | ok = 1; |
shimniok | 31:27e8130a0d8f | 194 | } else if (c == test) |
shimniok | 31:27e8130a0d8f | 195 | ok = 1; |
shimniok | 31:27e8130a0d8f | 196 | } |
shimniok | 31:27e8130a0d8f | 197 | return (ok == negate ? NULL : pattern); |
shimniok | 31:27e8130a0d8f | 198 | } |