1 34 package org.jruby.util; 35 36 import java.io.File ; 37 import java.io.FileFilter ; 38 import java.io.IOException ; 39 import java.util.ArrayList ; 40 import java.util.Collection ; 41 import java.util.Iterator ; 42 import java.util.List ; 43 import java.util.TreeSet ; 44 import java.util.regex.Matcher ; 45 import java.util.regex.Pattern ; 46 import java.util.regex.PatternSyntaxException ; 47 48 public class Glob { 50 private final List patterns; 51 private static final Pattern BRACE_PATTERN = Pattern.compile("(.*)\\{([^\\{\\}]*)\\}(.*)"); 53 54 public Glob(String cwd, String pattern) { 55 List expansion = new ArrayList (); 56 expansion.add(pattern); 57 58 expansion = splitPatternBraces(expansion); 60 61 cwd = canonicalize(cwd); 62 63 int size = expansion.size(); 64 patterns = new ArrayList (size); 65 for (int i = 0; i < size; i++) { 66 String newPattern = (String ) expansion.get(i); 67 68 patterns.add(i, new GlobPattern(cwd, newPattern)); 69 } 70 } 71 72 private static String canonicalize(String path) { 73 try { 74 return new NormalizedFile(path).getCanonicalPath(); 75 } catch (IOException e) { 76 return path; 77 } 78 } 79 80 private static List splitPatternBraces(List dirs) { 81 for (int i = 0; i < dirs.size(); i++) { 84 String fragment = (String ) dirs.get(i); 85 Matcher matcher = BRACE_PATTERN.matcher(fragment); 86 87 if (matcher.find()) { 89 dirs.remove(i); 90 String beforeBrace = matcher.group(1); 91 String [] subElementList = matcher.group(2).split(","); 92 String afterBrace = matcher.group(3); 93 94 for (int j = 0; j < subElementList.length; j++) { 95 dirs.add(beforeBrace + subElementList[j] + afterBrace); 96 } 97 } 98 } 99 100 return dirs; 101 } 102 103 106 private void getFiles() { 107 String pathSplitter = "/"; 109 110 for (Iterator iter = patterns.iterator(); iter.hasNext();) { 111 GlobPattern globPattern = (GlobPattern) iter.next(); 112 String [] dirs = globPattern.getPattern().split(pathSplitter); 113 NormalizedFile root = new NormalizedFile(dirs[0]); 114 int idx = 1; 115 if (glob2Regexp(dirs[0]) != null) { 116 root = new NormalizedFile("."); 117 idx = 0; 118 } 119 for (int size = dirs.length; idx < size; idx++) { 120 if (glob2Regexp(dirs[idx]) == null) { 121 root = new NormalizedFile(root, dirs[idx]); 122 } else { 123 break; 124 } 125 } 126 ArrayList matchingFiles = new ArrayList (); 127 128 if (idx == dirs.length) { 129 if (root.exists()) { 130 matchingFiles.add(root); 131 } 132 133 globPattern.setMatchedFiles(matchingFiles); 134 continue; 135 } 136 137 matchingFiles.add(root); 138 for (int length = dirs.length; idx < length; idx++) { 139 ArrayList currentMatchingFiles = new ArrayList (); 140 for (int i = 0, size = matchingFiles.size(); i < size; i++) { 141 boolean isDirectory = idx + 1 != length; 142 String pattern = dirs[idx]; 143 NormalizedFile parent = (NormalizedFile) matchingFiles.get(i); 144 currentMatchingFiles.addAll(getMatchingFiles(parent, pattern, isDirectory)); 145 } 146 matchingFiles = currentMatchingFiles; 147 } 148 globPattern.setMatchedFiles(matchingFiles); 149 } 150 } 151 152 private static Collection getMatchingFiles(final NormalizedFile parent, final String pattern, final boolean isDirectory) { 153 String expandedPattern = glob2Regexp(pattern); 154 if (expandedPattern == null) expandedPattern = pattern; 155 156 final Pattern p = Pattern.compile(expandedPattern); 157 158 final boolean firstDot = pattern.length()>0 && pattern.charAt(0) == '.'; 159 160 FileFilter filter = new FileFilter () { 161 public boolean accept(File pathname) { 162 String n = pathname.getName(); 163 return (pathname.isDirectory() || !isDirectory) && p.matcher(n).matches() && (firstDot || (n.length()==0 || n.charAt(0) != '.')); 164 } 165 }; 166 167 NormalizedFile[] matchArray = (NormalizedFile[])parent.listFiles(filter); 168 Collection matchingFiles = new ArrayList (); 169 170 if (matchArray != null) { 171 for (int i = 0; i < matchArray.length; i++) { 172 matchingFiles.add(matchArray[i]); 173 174 if (pattern.equals("**")) { 175 if (matchArray[i].isDirectory()) { 177 matchingFiles.addAll(getMatchingFiles(matchArray[i], pattern, isDirectory)); 178 } 179 } 180 } 181 } 182 183 if("**".equals(pattern)) { 184 matchingFiles.add(parent); 185 } 186 187 return matchingFiles; 188 } 189 190 public String [] getNames() { 191 try { 192 getFiles(); 193 } catch (PatternSyntaxException e) { 194 return new String [] {}; 196 } 197 198 Collection allMatchedNames = new TreeSet (); 199 for (Iterator iter = patterns.iterator(); iter.hasNext();) { 200 GlobPattern pattern = (GlobPattern) iter.next(); 201 202 allMatchedNames.addAll(pattern.getMatchedFiles()); 203 } 204 205 return (String []) allMatchedNames.toArray(new String [allMatchedNames.size()]); 206 } 207 208 215 private static String glob2Regexp(String s) { 216 StringBuffer t = new StringBuffer (s.length()); 217 boolean pattern = false; 218 int mode = 0; 219 boolean escape = false; 220 for (int i = 0; i < s.length(); i++) { 221 char c = s.charAt(i); 222 if (c == '\\') { 223 escape = true; 224 continue; 225 } 226 if (escape) { 227 t.append(c); 228 escape = false; 229 continue; 230 } 231 switch (mode) { 232 case 0: switch (c) { 234 case '*': 235 pattern = true; 236 t.append(".*"); 237 break; 238 case '?': 239 pattern = true; 240 t.append('.'); 241 break; 242 case '[': 243 pattern = true; 244 t.append(c); 245 mode = 1; 246 break; 247 case '.': case '(': case ')': case '+': case '|': case '^': case '$': 248 t.append('\\'); 249 default: 251 t.append(c); 252 } 253 break; 254 case 1: t.append(c); 256 if (c == ']') { 257 mode = 0; 258 } 259 break; 260 default: 261 throw new Error (); } 263 } 264 return pattern ? t.toString() : null; 265 } 266 267 277 private class GlobPattern { 278 private String pattern; 279 private String cwd; 280 private boolean endsWithDelimeter; 281 private boolean patternIsRelative; 282 private ArrayList files = null; 283 284 public GlobPattern(String cwd, String pattern) { 285 this.cwd = cwd; 286 287 this.endsWithDelimeter = pattern.endsWith("/") || pattern.endsWith("\\"); 290 291 if (new NormalizedFile(pattern).isAbsolute()) { 292 this.patternIsRelative = false; 293 this.pattern = canonicalize(pattern); 294 } else { 295 this.patternIsRelative = true; 297 this.pattern = canonicalize(new NormalizedFile(cwd, pattern).getAbsolutePath()); 298 } 299 } 300 301 public ArrayList getMatchedFiles() { 302 ArrayList fileNames = new ArrayList (); 303 int size = files.size(); 304 int offset = cwd.endsWith("/") ? 0 : 1; 305 306 for (int i = 0; i < size; i++) { 307 String path = ((NormalizedFile) files.get(i)).getPath(); 308 String name; 309 310 if (patternIsRelative && !path.equals(cwd) && path.startsWith(cwd)) { 311 name = path.substring(cwd.length() + offset); 313 } else { 314 name = path; 315 } 316 if (endsWithDelimeter) { 317 name += "/"; 318 } 319 320 321 fileNames.add(name.replace('\\', '/')); 322 } 323 324 return fileNames; 325 } 326 327 public void setMatchedFiles(ArrayList files) { 328 this.files = files; 329 } 330 331 public String getPattern() { 332 return pattern; 333 } 334 } 335 } 336 | Popular Tags |