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