blob: d492698d22effddb6379ce14f40ed509b63d1bde [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*
*/
package org.apache.geode.redis.internal.executor;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
/**
* A class for POSIX glob pattern with brace expansions.
*/
public class GlobPattern {
private static final char BACKSLASH = '\\';
private final Pattern compiled;
private final String globPattern;
private boolean hasWildcard = false;
/**
* Construct the glob pattern object with a glob pattern string
*
* @param globPattern the glob pattern string
*/
public GlobPattern(String globPattern) {
this.compiled = createPattern(globPattern);
this.globPattern = globPattern;
}
/**
* @return the compiled pattern
*/
public Pattern compiled() {
return compiled;
}
/**
* @return the original glob pattern
*/
public String globPattern() {
return globPattern;
}
/**
* Compile glob pattern string
*
* @param globPattern the glob pattern
* @return the pattern object
*/
public static Pattern compile(String globPattern) {
return new GlobPattern(globPattern).compiled();
}
/**
* Match input against the compiled glob pattern
*
* @param s input chars
* @return true for successful matches
*/
public boolean matches(CharSequence s) {
return compiled.matcher(s).matches();
}
/**
* Set and compile a glob pattern
*
* @param glob the glob pattern string
*/
private Pattern createPattern(String glob) {
StringBuilder regex = new StringBuilder();
int setOpen = 0;
int len = glob.length();
hasWildcard = false;
for (int i = 0; i < len; i++) {
char c = glob.charAt(i);
switch (c) {
case BACKSLASH:
if (++i < len) {
regex.append(c).append(glob.charAt(i));
continue;
}
break;
case '.':
case '$':
case '(':
case ')':
case '|':
case '+':
case '{':
case '!':
// escape regex special chars that are not glob special chars
regex.append(BACKSLASH);
break;
case '*':
regex.append('.');
hasWildcard = true;
break;
case '?':
regex.append('.');
hasWildcard = true;
continue;
case '[':
if (setOpen > 0) {
regex.append(BACKSLASH);
}
setOpen++;
hasWildcard = true;
break;
case '^': // ^ inside [...] can be unescaped
if (setOpen == 0) {
regex.append(BACKSLASH);
}
break;
case ']':
setOpen = 0;
break;
default:
}
regex.append(c);
}
if (setOpen > 0) {
regex.append(']');
}
return Pattern.compile(regex.toString(), Pattern.DOTALL | Pattern.MULTILINE);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof GlobPattern)) {
return false;
}
GlobPattern that = (GlobPattern) o;
return this.compiled.pattern().equals(that.compiled.pattern());
}
@Override
public int hashCode() {
return Objects.hash(compiled, hasWildcard);
}
private static void error(String message, String pattern, int pos) {
throw new PatternSyntaxException(message, pattern, pos);
}
}