]> git.proxmox.com Git - libgit2.git/blame - src/win32/fnmatch.c
Tabify everything
[libgit2.git] / src / win32 / fnmatch.c
CommitLineData
e9c6571d 1/*
bb742ede 2 * Copyright (C) 2009-2011 the libgit2 contributors
e9c6571d 3 *
bb742ede
VM
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
e9c6571d
VM
6 */
7
8/*
9 * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
10 * Compares a filename or pathname to a pattern.
11 */
12
13#include <ctype.h>
14#include <stdio.h>
15#include <string.h>
16
17#include "fnmatch.h"
18
87d9869f 19#define EOS '\0'
e9c6571d 20
87d9869f
VM
21#define RANGE_MATCH 1
22#define RANGE_NOMATCH 0
23#define RANGE_ERROR (-1)
e9c6571d
VM
24
25static int rangematch(const char *, char, int, char **);
26
27int
28p_fnmatch(const char *pattern, const char *string, int flags)
29{
87d9869f
VM
30 const char *stringstart;
31 char *newp;
32 char c, test;
33
34 for (stringstart = string;;)
35 switch (c = *pattern++) {
36 case EOS:
37 if ((flags & FNM_LEADING_DIR) && *string == '/')
38 return (0);
39 return (*string == EOS ? 0 : FNM_NOMATCH);
40 case '?':
41 if (*string == EOS)
42 return (FNM_NOMATCH);
43 if (*string == '/' && (flags & FNM_PATHNAME))
44 return (FNM_NOMATCH);
45 if (*string == '.' && (flags & FNM_PERIOD) &&
46 (string == stringstart ||
47 ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
48 return (FNM_NOMATCH);
49 ++string;
50 break;
51 case '*':
52 c = *pattern;
53 /* Collapse multiple stars. */
54 while (c == '*')
55 c = *++pattern;
56
57 if (*string == '.' && (flags & FNM_PERIOD) &&
58 (string == stringstart ||
59 ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
60 return (FNM_NOMATCH);
61
62 /* Optimize for pattern with * at end or before /. */
63 if (c == EOS) {
64 if (flags & FNM_PATHNAME)
65 return ((flags & FNM_LEADING_DIR) ||
66 strchr(string, '/') == NULL ?
67 0 : FNM_NOMATCH);
68 else
69 return (0);
70 } else if (c == '/' && (flags & FNM_PATHNAME)) {
71 if ((string = strchr(string, '/')) == NULL)
72 return (FNM_NOMATCH);
73 break;
74 }
75
76 /* General case, use recursion. */
77 while ((test = *string) != EOS) {
78 if (!p_fnmatch(pattern, string, flags & ~FNM_PERIOD))
79 return (0);
80 if (test == '/' && (flags & FNM_PATHNAME))
81 break;
82 ++string;
83 }
84 return (FNM_NOMATCH);
85 case '[':
86 if (*string == EOS)
87 return (FNM_NOMATCH);
88 if (*string == '/' && (flags & FNM_PATHNAME))
89 return (FNM_NOMATCH);
90 if (*string == '.' && (flags & FNM_PERIOD) &&
91 (string == stringstart ||
92 ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
93 return (FNM_NOMATCH);
94
95 switch (rangematch(pattern, *string, flags, &newp)) {
96 case RANGE_ERROR:
97 /* not a good range, treat as normal text */
98 goto normal;
99 case RANGE_MATCH:
100 pattern = newp;
101 break;
102 case RANGE_NOMATCH:
103 return (FNM_NOMATCH);
104 }
105 ++string;
106 break;
107 case '\\':
108 if (!(flags & FNM_NOESCAPE)) {
109 if ((c = *pattern++) == EOS) {
110 c = '\\';
111 --pattern;
112 }
113 }
114 /* FALLTHROUGH */
115 default:
116 normal:
117 if (c != *string && !((flags & FNM_CASEFOLD) &&
118 (tolower((unsigned char)c) ==
119 tolower((unsigned char)*string))))
120 return (FNM_NOMATCH);
121 ++string;
122 break;
123 }
124 /* NOTREACHED */
e9c6571d
VM
125}
126
127static int
128rangematch(const char *pattern, char test, int flags, char **newp)
129{
87d9869f
VM
130 int negate, ok;
131 char c, c2;
132
133 /*
134 * A bracket expression starting with an unquoted circumflex
135 * character produces unspecified results (IEEE 1003.2-1992,
136 * 3.13.2). This implementation treats it like '!', for
137 * consistency with the regular expression syntax.
138 * J.T. Conklin (conklin@ngai.kaleida.com)
139 */
140 if ((negate = (*pattern == '!' || *pattern == '^')) != 0)
141 ++pattern;
142
143 if (flags & FNM_CASEFOLD)
144 test = (char)tolower((unsigned char)test);
145
146 /*
147 * A right bracket shall lose its special meaning and represent
148 * itself in a bracket expression if it occurs first in the list.
149 * -- POSIX.2 2.8.3.2
150 */
151 ok = 0;
152 c = *pattern++;
153 do {
154 if (c == '\\' && !(flags & FNM_NOESCAPE))
155 c = *pattern++;
156 if (c == EOS)
157 return (RANGE_ERROR);
158 if (c == '/' && (flags & FNM_PATHNAME))
159 return (RANGE_NOMATCH);
160 if ((flags & FNM_CASEFOLD))
161 c = (char)tolower((unsigned char)c);
162 if (*pattern == '-'
163 && (c2 = *(pattern+1)) != EOS && c2 != ']') {
164 pattern += 2;
165 if (c2 == '\\' && !(flags & FNM_NOESCAPE))
166 c2 = *pattern++;
167 if (c2 == EOS)
168 return (RANGE_ERROR);
169 if (flags & FNM_CASEFOLD)
170 c2 = (char)tolower((unsigned char)c2);
171 if (c <= test && test <= c2)
172 ok = 1;
173 } else if (c == test)
174 ok = 1;
175 } while ((c = *pattern++) != ']');
176
177 *newp = (char *)pattern;
178 return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
e9c6571d
VM
179}
180