1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 package org.eclipse.jgit.fnmatch;
46
47 import java.text.MessageFormat;
48 import java.util.ArrayList;
49 import java.util.List;
50 import java.util.regex.Matcher;
51 import java.util.regex.Pattern;
52
53 import org.eclipse.jgit.errors.InvalidPatternException;
54 import org.eclipse.jgit.internal.JGitText;
55
56 final class GroupHead extends AbstractHead {
57 private final List<CharacterPattern> characterClasses;
58
59 private static final Pattern REGEX_PATTERN = Pattern
60 .compile("([^-][-][^-]|\\[[.:=].*?[.:=]\\])");
61
62 private final boolean inverse;
63
64 GroupHead(String pattern, final String wholePattern)
65 throws InvalidPatternException {
66 super(false);
67 this.characterClasses = new ArrayList<>();
68 this.inverse = pattern.startsWith("!");
69 if (inverse) {
70 pattern = pattern.substring(1);
71 }
72 final Matcher matcher = REGEX_PATTERN.matcher(pattern);
73 while (matcher.find()) {
74 final String characterClass = matcher.group(0);
75 if (characterClass.length() == 3 && characterClass.charAt(1) == '-') {
76 final char start = characterClass.charAt(0);
77 final char end = characterClass.charAt(2);
78 characterClasses.add(new CharacterRange(start, end));
79 } else if (characterClass.equals("[:alnum:]")) {
80 characterClasses.add(LetterPattern.INSTANCE);
81 characterClasses.add(DigitPattern.INSTANCE);
82 } else if (characterClass.equals("[:alpha:]")) {
83 characterClasses.add(LetterPattern.INSTANCE);
84 } else if (characterClass.equals("[:blank:]")) {
85 characterClasses.add(new OneCharacterPattern(' '));
86 characterClasses.add(new OneCharacterPattern('\t'));
87 } else if (characterClass.equals("[:cntrl:]")) {
88 characterClasses.add(new CharacterRange('\u0000', '\u001F'));
89 characterClasses.add(new OneCharacterPattern('\u007F'));
90 } else if (characterClass.equals("[:digit:]")) {
91 characterClasses.add(DigitPattern.INSTANCE);
92 } else if (characterClass.equals("[:graph:]")) {
93 characterClasses.add(new CharacterRange('\u0021', '\u007E'));
94 characterClasses.add(LetterPattern.INSTANCE);
95 characterClasses.add(DigitPattern.INSTANCE);
96 } else if (characterClass.equals("[:lower:]")) {
97 characterClasses.add(LowerPattern.INSTANCE);
98 } else if (characterClass.equals("[:print:]")) {
99 characterClasses.add(new CharacterRange('\u0020', '\u007E'));
100 characterClasses.add(LetterPattern.INSTANCE);
101 characterClasses.add(DigitPattern.INSTANCE);
102 } else if (characterClass.equals("[:punct:]")) {
103 characterClasses.add(PunctPattern.INSTANCE);
104 } else if (characterClass.equals("[:space:]")) {
105 characterClasses.add(WhitespacePattern.INSTANCE);
106 } else if (characterClass.equals("[:upper:]")) {
107 characterClasses.add(UpperPattern.INSTANCE);
108 } else if (characterClass.equals("[:xdigit:]")) {
109 characterClasses.add(new CharacterRange('0', '9'));
110 characterClasses.add(new CharacterRange('a', 'f'));
111 characterClasses.add(new CharacterRange('A', 'F'));
112 } else if (characterClass.equals("[:word:]")) {
113 characterClasses.add(new OneCharacterPattern('_'));
114 characterClasses.add(LetterPattern.INSTANCE);
115 characterClasses.add(DigitPattern.INSTANCE);
116 } else {
117 final String message = MessageFormat.format(
118 JGitText.get().characterClassIsNotSupported,
119 characterClass);
120 throw new InvalidPatternException(message, wholePattern);
121 }
122
123 pattern = matcher.replaceFirst("");
124 matcher.reset(pattern);
125 }
126
127 for (int i = 0; i < pattern.length(); i++) {
128 final char c = pattern.charAt(i);
129 characterClasses.add(new OneCharacterPattern(c));
130 }
131 }
132
133 @Override
134 protected final boolean matches(final char c) {
135 for (CharacterPattern pattern : characterClasses) {
136 if (pattern.matches(c)) {
137 return !inverse;
138 }
139 }
140 return inverse;
141 }
142
143 private interface CharacterPattern {
144
145
146
147
148
149 boolean matches(char c);
150 }
151
152 private static final class CharacterRange implements CharacterPattern {
153 private final char start;
154
155 private final char end;
156
157 CharacterRange(char start, char end) {
158 this.start = start;
159 this.end = end;
160 }
161
162 @Override
163 public final boolean matches(char c) {
164 return start <= c && c <= end;
165 }
166 }
167
168 private static final class DigitPattern implements CharacterPattern {
169 static final GroupHead.DigitPattern INSTANCE = new DigitPattern();
170
171 @Override
172 public final boolean matches(char c) {
173 return Character.isDigit(c);
174 }
175 }
176
177 private static final class LetterPattern implements CharacterPattern {
178 static final GroupHead.LetterPattern INSTANCE = new LetterPattern();
179
180 @Override
181 public final boolean matches(char c) {
182 return Character.isLetter(c);
183 }
184 }
185
186 private static final class LowerPattern implements CharacterPattern {
187 static final GroupHead.LowerPattern INSTANCE = new LowerPattern();
188
189 @Override
190 public final boolean matches(char c) {
191 return Character.isLowerCase(c);
192 }
193 }
194
195 private static final class UpperPattern implements CharacterPattern {
196 static final GroupHead.UpperPattern INSTANCE = new UpperPattern();
197
198 @Override
199 public final boolean matches(char c) {
200 return Character.isUpperCase(c);
201 }
202 }
203
204 private static final class WhitespacePattern implements CharacterPattern {
205 static final GroupHead.WhitespacePattern INSTANCE = new WhitespacePattern();
206
207 @Override
208 public final boolean matches(char c) {
209 return Character.isWhitespace(c);
210 }
211 }
212
213 private static final class OneCharacterPattern implements CharacterPattern {
214 private char expectedCharacter;
215
216 OneCharacterPattern(final char c) {
217 this.expectedCharacter = c;
218 }
219
220 @Override
221 public final boolean matches(char c) {
222 return this.expectedCharacter == c;
223 }
224 }
225
226 private static final class PunctPattern implements CharacterPattern {
227 static final GroupHead.PunctPattern INSTANCE = new PunctPattern();
228
229 private static String punctCharacters = "-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~";
230
231 @Override
232 public boolean matches(char c) {
233 return punctCharacters.indexOf(c) != -1;
234 }
235 }
236
237 }