2 * Copyright (C) 2008, Florian Köberle <florianskarten@web.de>
6 * Redistribution and use in source and binary forms, with or
7 * without modification, are permitted provided that the following
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * - Neither the name of the Git Development Community nor the
19 * names of its contributors may be used to endorse or promote
20 * products derived from this software without specific prior
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
24 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 package org
.spearce
.jgit
.fnmatch
;
40 import java
.util
.ArrayList
;
41 import java
.util
.List
;
42 import java
.util
.regex
.Matcher
;
43 import java
.util
.regex
.Pattern
;
45 import org
.spearce
.jgit
.errors
.InvalidPatternException
;
47 final class GroupHead
extends AbstractHead
{
48 private final List
<CharacterPattern
> characterClasses
;
50 private static final Pattern REGEX_PATTERN
= Pattern
51 .compile("([^-][-][^-]|\\[[.:=].*?[.:=]\\])");
53 private final boolean inverse
;
55 GroupHead(String pattern
, final String wholePattern
)
56 throws InvalidPatternException
{
58 this.characterClasses
= new ArrayList
<CharacterPattern
>();
59 this.inverse
= pattern
.startsWith("!");
61 pattern
= pattern
.substring(1);
63 final Matcher matcher
= REGEX_PATTERN
.matcher(pattern
);
64 while (matcher
.find()) {
65 final String characterClass
= matcher
.group(0);
66 if (characterClass
.length() == 3 && characterClass
.charAt(1) == '-') {
67 final char start
= characterClass
.charAt(0);
68 final char end
= characterClass
.charAt(2);
69 characterClasses
.add(new CharacterRange(start
, end
));
70 } else if (characterClass
.equals("[:alnum:]")) {
71 characterClasses
.add(LetterPattern
.INSTANCE
);
72 characterClasses
.add(DigitPattern
.INSTANCE
);
73 } else if (characterClass
.equals("[:alpha:]")) {
74 characterClasses
.add(LetterPattern
.INSTANCE
);
75 } else if (characterClass
.equals("[:blank:]")) {
76 characterClasses
.add(new OneCharacterPattern(' '));
77 characterClasses
.add(new OneCharacterPattern('\t'));
78 } else if (characterClass
.equals("[:cntrl:]")) {
79 characterClasses
.add(new CharacterRange('\u0000', '\u001F'));
80 characterClasses
.add(new OneCharacterPattern('\u007F'));
81 } else if (characterClass
.equals("[:digit:]")) {
82 characterClasses
.add(DigitPattern
.INSTANCE
);
83 } else if (characterClass
.equals("[:graph:]")) {
84 characterClasses
.add(new CharacterRange('\u0021', '\u007E'));
85 characterClasses
.add(LetterPattern
.INSTANCE
);
86 characterClasses
.add(DigitPattern
.INSTANCE
);
87 } else if (characterClass
.equals("[:lower:]")) {
88 characterClasses
.add(LowerPattern
.INSTANCE
);
89 } else if (characterClass
.equals("[:print:]")) {
90 characterClasses
.add(new CharacterRange('\u0020', '\u007E'));
91 characterClasses
.add(LetterPattern
.INSTANCE
);
92 characterClasses
.add(DigitPattern
.INSTANCE
);
93 } else if (characterClass
.equals("[:punct:]")) {
94 characterClasses
.add(PunctPattern
.INSTANCE
);
95 } else if (characterClass
.equals("[:space:]")) {
96 characterClasses
.add(WhitespacePattern
.INSTANCE
);
97 } else if (characterClass
.equals("[:upper:]")) {
98 characterClasses
.add(UpperPattern
.INSTANCE
);
99 } else if (characterClass
.equals("[:xdigit:]")) {
100 characterClasses
.add(new CharacterRange('0', '9'));
101 characterClasses
.add(new CharacterRange('a', 'f'));
102 characterClasses
.add(new CharacterRange('A', 'F'));
103 } else if (characterClass
.equals("[:word:]")) {
104 characterClasses
.add(new OneCharacterPattern('_'));
105 characterClasses
.add(LetterPattern
.INSTANCE
);
106 characterClasses
.add(DigitPattern
.INSTANCE
);
108 final String message
= String
.format(
109 "The character class %s is not supported.",
111 throw new InvalidPatternException(message
, wholePattern
);
114 pattern
= matcher
.replaceFirst("");
115 matcher
.reset(pattern
);
117 // pattern contains now no ranges
118 for (int i
= 0; i
< pattern
.length(); i
++) {
119 final char c
= pattern
.charAt(i
);
120 characterClasses
.add(new OneCharacterPattern(c
));
125 protected final boolean matches(final char c
) {
126 for (CharacterPattern pattern
: characterClasses
) {
127 if (pattern
.matches(c
)) {
134 private interface CharacterPattern
{
137 * the character to test
138 * @return returns true if the character matches a pattern.
140 boolean matches(char c
);
143 private static final class CharacterRange
implements CharacterPattern
{
144 private final char start
;
146 private final char end
;
148 CharacterRange(char start
, char end
) {
153 public final boolean matches(char c
) {
154 return start
<= c
&& c
<= end
;
158 private static final class DigitPattern
implements CharacterPattern
{
159 static final GroupHead
.DigitPattern INSTANCE
= new DigitPattern();
161 public final boolean matches(char c
) {
162 return Character
.isDigit(c
);
166 private static final class LetterPattern
implements CharacterPattern
{
167 static final GroupHead
.LetterPattern INSTANCE
= new LetterPattern();
169 public final boolean matches(char c
) {
170 return Character
.isLetter(c
);
174 private static final class LowerPattern
implements CharacterPattern
{
175 static final GroupHead
.LowerPattern INSTANCE
= new LowerPattern();
177 public final boolean matches(char c
) {
178 return Character
.isLowerCase(c
);
182 private static final class UpperPattern
implements CharacterPattern
{
183 static final GroupHead
.UpperPattern INSTANCE
= new UpperPattern();
185 public final boolean matches(char c
) {
186 return Character
.isUpperCase(c
);
190 private static final class WhitespacePattern
implements CharacterPattern
{
191 static final GroupHead
.WhitespacePattern INSTANCE
= new WhitespacePattern();
193 public final boolean matches(char c
) {
194 return Character
.isWhitespace(c
);
198 private static final class OneCharacterPattern
implements CharacterPattern
{
199 private char expectedCharacter
;
201 OneCharacterPattern(final char c
) {
202 this.expectedCharacter
= c
;
205 public final boolean matches(char c
) {
206 return this.expectedCharacter
== c
;
210 private static final class PunctPattern
implements CharacterPattern
{
211 static final GroupHead
.PunctPattern INSTANCE
= new PunctPattern();
213 private static String punctCharacters
= "-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~";
215 public boolean matches(char c
) {
216 return punctCharacters
.indexOf(c
) != -1;