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<CharacterPattern>();
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 public final boolean matches(char c) {
163 return start <= c && c <= end;
164 }
165 }
166
167 private static final class DigitPattern implements CharacterPattern {
168 static final GroupHead.DigitPattern INSTANCE = new DigitPattern();
169
170 public final boolean matches(char c) {
171 return Character.isDigit(c);
172 }
173 }
174
175 private static final class LetterPattern implements CharacterPattern {
176 static final GroupHead.LetterPattern INSTANCE = new LetterPattern();
177
178 public final boolean matches(char c) {
179 return Character.isLetter(c);
180 }
181 }
182
183 private static final class LowerPattern implements CharacterPattern {
184 static final GroupHead.LowerPattern INSTANCE = new LowerPattern();
185
186 public final boolean matches(char c) {
187 return Character.isLowerCase(c);
188 }
189 }
190
191 private static final class UpperPattern implements CharacterPattern {
192 static final GroupHead.UpperPattern INSTANCE = new UpperPattern();
193
194 public final boolean matches(char c) {
195 return Character.isUpperCase(c);
196 }
197 }
198
199 private static final class WhitespacePattern implements CharacterPattern {
200 static final GroupHead.WhitespacePattern INSTANCE = new WhitespacePattern();
201
202 public final boolean matches(char c) {
203 return Character.isWhitespace(c);
204 }
205 }
206
207 private static final class OneCharacterPattern implements CharacterPattern {
208 private char expectedCharacter;
209
210 OneCharacterPattern(final char c) {
211 this.expectedCharacter = c;
212 }
213
214 public final boolean matches(char c) {
215 return this.expectedCharacter == c;
216 }
217 }
218
219 private static final class PunctPattern implements CharacterPattern {
220 static final GroupHead.PunctPattern INSTANCE = new PunctPattern();
221
222 private static String punctCharacters = "-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~";
223
224 public boolean matches(char c) {
225 return punctCharacters.indexOf(c) != -1;
226 }
227 }
228
229 }