Fixes null captured parameters
[jpf-core.git] / src / main / gov / nasa / jpf / util / FileUtils.java
1 /*
2  * Copyright (C) 2014, United States Government, as represented by the
3  * Administrator of the National Aeronautics and Space Administration.
4  * All rights reserved.
5  *
6  * The Java Pathfinder core (jpf-core) platform is licensed under the
7  * Apache License, Version 2.0 (the "License"); you may not use this file except
8  * in compliance with the License. You may obtain a copy of the License at
9  * 
10  *        http://www.apache.org/licenses/LICENSE-2.0. 
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and 
16  * limitations under the License.
17  */
18 package gov.nasa.jpf.util;
19
20 import java.io.*;
21 import java.net.URL;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.List;
25
26 /**
27  * utility class to find all files matching (possibly hierarchical)
28  * wildcard path specs
29  *
30  * we support single '*' wildcards as in filename matching, plus "**" patterns
31  * that match all (recursive) subdirectories
32  */
33 // example:  List<File> list = findMatches("/U*/p*/tmp/**/*.java");
34
35 public class FileUtils {
36
37   public static boolean containsWildcards (String pattern) {
38     return (pattern.indexOf('*') >= 0);
39   }
40
41   //--- processing wildcard path specs
42
43   public static String[] expandWildcards (String[] pathNames){
44     ArrayList<String> list = null;
45
46     if (pathNames == null){
47       return new String[0];
48     }
49
50     for (int i=0; i<pathNames.length; i++){
51       String e = pathNames[i];
52
53       if (containsWildcards(e)){
54         if (list == null){
55           list= new ArrayList<String>(pathNames.length + 20);
56           for (int j=0; j<i; j++){
57             list.add(pathNames[j]);
58           }
59         }
60
61         for (File f : findMatches(e)){
62           list.add(f.getAbsolutePath());
63         }
64
65       } else {
66         if (list != null){
67           list.add(e);
68         }
69       }
70     }
71
72     if (list != null){
73       return list.toArray(new String[list.size()]);
74     } else {
75       return pathNames;
76     }
77   }
78
79
80   private static List<File> splitPath (String pattern) {
81     ArrayList<File> list = new ArrayList<File>();
82
83     for (File f = new File(pattern); f != null; f = f.getParentFile()) {
84       list.add(f);
85     }
86
87     Collections.reverse(list);
88     return list;
89   }
90
91   private static void addSubdirs (List<File> list, File dir){
92     for (File f : dir.listFiles()) {
93       if (f.isDirectory()){
94         list.add(f);
95         addSubdirs(list, f);
96       }
97     }
98   }
99
100   private static List<File> findMatches (File dir, String pattern) {
101     ArrayList<File> list = new ArrayList<File>();
102
103     if (dir.isDirectory()) {
104       if ("**".equals(pattern)) { // recursively add all subdirectories
105         addSubdirs(list, dir);
106
107       } else {
108         StringMatcher sm = new StringMatcher(pattern);
109         for (File f : dir.listFiles()) {
110           if (sm.matches(f.getName())) {
111             list.add(f);
112           }
113         }
114       }
115     }
116
117     return list;
118   }
119
120   public static List<File> findMatches (String pattern) {
121     List<File> pathComponents = splitPath(pattern);
122     List<File> matches = null;
123
124     for (File f : pathComponents) {
125       String fname = f.getName();
126       if (matches == null) { // first one
127         if (fname.isEmpty()) { // filesystem root
128           matches = new ArrayList<File>();
129           matches.add(f);
130         } else {
131           matches = findMatches(new File(System.getProperty("user.dir")), fname);
132         }
133
134       } else {
135         List<File> newMatches = new ArrayList<File>();
136         for (File d : matches) {
137           newMatches.addAll(findMatches(d, fname));
138         }
139         matches = newMatches;
140       }
141
142       if (matches.isEmpty()) {
143         return matches;
144       }
145     }
146     return matches;
147   }
148
149
150   //--- URL conversion
151
152   public static URL getURL (String spec){
153     try {
154       // check if there is a protocol specification
155       if (spec.indexOf("://") >= 0) {
156         return new URL(spec);
157
158       } else {
159         File f = new File(spec).getCanonicalFile();
160         return f.toURI().toURL();
161       }
162     } catch (Throwable x) {
163       throw new RuntimeException("illegal pathname: " + spec);
164     }
165   }
166
167   public static URL[] getURLs (String[] paths){
168     ArrayList<URL> urls = new ArrayList<URL>();
169
170     for (String p : paths) {
171       urls.add( getURL(p));
172     }
173
174     return urls.toArray(new URL[urls.size()]);
175   }
176
177   public static URL[] getURLs (List<String> paths){
178     ArrayList<URL> urls = new ArrayList<URL>();
179
180     for (String p : paths) {
181       urls.add( getURL(p));
182     }
183
184     return urls.toArray(new URL[urls.size()]);
185   }
186
187
188   //--- platform specific path conversion
189
190   /**
191    * turn a mixed path list into a valid Unix path set without drive letters,
192    * and with '/' and ':' separators. Also remove multiple consecutive separators
193    * this assumes the path String to be already expanded
194    */
195   public static String asCanonicalUnixPath (String p) {
196     boolean changed = false;
197
198     int n = p.length();
199     char[] buf = new char[n];
200     p.getChars(0, n, buf, 0);
201
202     for (int i=0; i<n; i++) {
203       char c = buf[i];
204       if (c == '/' || c == '\\') {
205         if (c == '\\'){
206           buf[i] = '/'; changed = true;
207         }
208
209         // remove multiple occurrences of dir separators
210         int i1 = i+1;
211         if (i1 < n){
212           for (c = buf[i1]; i1 < n && (c == '/' || c == '\\'); c = buf[i1]) {
213             System.arraycopy(buf, i + 2, buf, i1, n - (i + 2));
214             n--;
215             changed = true;
216           }
217         }
218
219       } else if (c == ':') {
220         // strip drive letters - maybe this is trying to be too smart,
221         // since we only do this for a "...:X:\..." but not a
222         // "...:X:/...", which could be a valid unix path list
223
224         // is this part of a drive letter spec?
225         int i1 = i+1;
226         if (i1<n) {
227           if (buf[i1] == '\\') {
228             if (i>0) {
229               if (i == 1 || (buf[i-2] == ':')){  // strip the drive letter
230                 System.arraycopy(buf, i1, buf, i-1, n - (i1));
231                 n-=2;
232                 changed = true;
233               }
234             }
235           }
236         }
237
238       } else if (c == ';'){
239         buf[i] = ':'; changed = true;
240
241       } else if (c == ',') {
242         buf[i] = ':'; changed = true;
243       }
244
245       if (buf[i] == ':') {  // remove multiple occurrences of path separators
246         int i1 = i+1;
247         if (i1<n) {
248           for (c = buf[i1] ;(c == ':' || c == ';' || c == ','); c = buf[i1]){
249             System.arraycopy(buf, i+2, buf, i1, n - (i+2));
250             n--;
251             changed = true;
252           }
253         }
254       }
255     }
256
257     if (changed) {
258       p = new String(buf, 0, n);
259     }
260
261     return p;
262   }
263
264   /**
265    * turn a mixed path list into a valid Windows path set with drive letters,
266    * and '\' and ';' separators. Also remove multiple consecutive separators
267    * this assumes the path String to be already expanded
268    */
269   public static String asCanonicalWindowsPath (String p) {
270     boolean changed = false;
271
272     int n = p.length();
273     char[] buf = new char[n];
274     p.getChars(0, n, buf, 0);
275
276     for (int i=0; i<n; i++) {
277       char c = buf[i];
278       if (c == '/' || c == '\\') {
279         if (c == '/'){
280           buf[i] = '\\'; changed = true;
281         }
282
283         // remove multiple occurrences of dir separators
284         int i1 = i+1;
285         if (i1 < n) {
286           for (c = buf[i1]; i1 < n && (c == '/' || c == '\\'); c = buf[i1]) {
287             System.arraycopy(buf, i + 2, buf, i1, n - (i + 2));
288             n--;
289             changed = true;
290           }
291         }
292
293       } else if (c == ':') {
294         // is this part of a drive letter spec?
295         int i1 = i+1;
296         if (i1<n && (buf[i1] == '\\' || buf[i1] == '/')) {
297           if (i>0) {
298             if (i == 1 || (buf[i-2] == ';')){
299               continue;
300             }
301           }
302         }
303         buf[i] = ';'; changed = true;
304
305       } else if (c == ',') {
306         buf[i] = ';'; changed = true;
307       }
308
309       if (buf[i] == ';') { // remove multiple occurrences of path separators
310         int i1 = i+1;
311         if (i1<n) {
312           for (c = buf[i1] ;(c == ':' || c == ';' || c == ','); c = buf[i1]){
313             System.arraycopy(buf, i+2, buf, i1, n - (i+2));
314             n--;
315             changed = true;
316           }
317         }
318       }
319     }
320
321     if (changed) {
322       p = new String(buf, 0, n);
323     }
324
325     return p;
326   }
327
328
329   public static String asPlatformPath (String p) {
330     if (File.separatorChar == '/') { // Unix'ish file system
331       p = asCanonicalUnixPath(p);
332     } else { // Windows'ish file system
333       p = asCanonicalWindowsPath(p);
334     }
335
336     return p;
337   }
338
339   public static void printFile (PrintWriter pw, File file){
340     try {
341       FileReader fr = new FileReader(file);
342       BufferedReader r = new BufferedReader(fr);
343
344       String line;
345       while ((line = r.readLine()) != null){
346         pw.println(line);
347       }
348
349       r.close();
350
351     } catch (IOException iox){
352       pw.println("!! error printing file: " + file.getPath());
353     }
354   }
355
356   public static boolean removeRecursively(File file) {
357     if (file.exists()) {
358       File[] childs = file.listFiles();
359
360       for (File child : childs) {
361         if (child.isDirectory()){
362           removeRecursively(child);
363         } else {
364           child.delete();
365         }
366       }
367
368       return file.delete();
369     }
370
371     return false;
372   }
373
374   public static byte[] getContents( File file) throws IOException {
375     if (file.isFile()){
376       long length = file.length();
377       byte[] data = new byte[(int)length];
378
379       FileInputStream is = new FileInputStream(file);
380       try {
381         getContents(is, data);
382
383       } catch (IOException iox){
384         return null;
385
386       } finally {
387         is.close();
388       }
389
390       return data;
391     }
392
393     return null;
394   }
395
396   public static void getContents(InputStream is, byte[] buf) throws IOException {
397     int nRead = 0;
398     while (nRead < buf.length) {
399       int n = is.read(buf, nRead, buf.length - nRead);
400       if (n < 0) {
401         throw new IOException("premature end of inputstream: " + buf.length + '/' + nRead);
402       }
403       nRead += n;
404     }
405   }
406
407   public static String getContentsAsString( File file) throws IOException {
408     byte[] data = getContents(file);
409     return new String(data);
410   }
411   
412   public static void setContents(File file, byte[] data) throws IOException {
413     FileOutputStream os = new FileOutputStream(file);
414     os.write(data);
415     os.close();
416   }
417
418   public static void setContents(File file, String data) throws IOException {
419     FileWriter fw = new FileWriter(file);
420     fw.append(data);
421     fw.close();
422   }
423     
424   public static String asCanonicalUserPathName (String path){
425     String userHome = System.getProperty("user.home");
426     int len = userHome.length();
427     if (path.startsWith(userHome) && path.charAt(len) == '/') {
428       return "${user.home}" + path.substring(len).replace('\\', '/');
429     } else {
430       return path.replace('\\', '/');
431     }
432   }
433   
434   public static String asUnixPathName (File file){
435     String userHome = System.getProperty("user.home") + File.separatorChar;
436     int uhLen = userHome.length();
437
438     String pn = file.getAbsolutePath();
439     if (pn.startsWith(userHome)) {
440       pn = "~/" + pn.substring(uhLen).replace('\\', '/');
441     } else {
442       pn = pn.replace('\\', '/');
443     }
444     return pn;
445   }
446
447   public static String unixToUserPathName (String unixPathName){
448     if (unixPathName.startsWith("~/")){
449       return "${user.home}" + unixPathName.substring(1);
450     } else {
451       String userHome = System.getProperty("user.home");
452       int len = userHome.length();
453       if (unixPathName.startsWith(userHome) && unixPathName.charAt(len) == '/'){
454         return "${user.home}" + unixPathName.substring(len);
455       } else {
456         return unixPathName;
457       }
458     }
459   }
460   
461   public static boolean ensureDirs (File file){
462     File dir = file.getParentFile();
463     if (!dir.isDirectory()){
464       return dir.mkdirs();
465     } else {
466       return true;
467     }
468   }
469   
470   public static String getRelativeUnixPath (File baseDir, File refFile) throws IOException {
471                 String bpn = baseDir.getCanonicalPath().replace('\\', '/');
472                 String rpn = refFile.getCanonicalPath().replace('\\', '/');
473
474                 int len = Math.min(bpn.length(), rpn.length());
475                 for (int i = 0, n = 0; i < len; i++) {
476                         char c = bpn.charAt(i);
477                         if (c == '/') {
478                                 n = i + 1;
479                         } else if (c != rpn.charAt(i)) {
480                                 bpn = bpn.substring(n);
481                                 rpn = rpn.substring(n);
482                                 break;
483                         }
484                 }
485
486                 len = bpn.length();
487                 String up = "";
488                 for (int i = 0; i < len; i++) {
489                         if (bpn.charAt(i) == '/') {
490                                 up += "../";
491                         }
492                 }
493
494                 String relPath = up + rpn;
495                 return relPath;
496   }
497   
498   public static boolean copyFile (File src, File toDir) throws IOException {
499     if (src.isFile()) {
500       File tgt = new File(toDir, src.getName());
501       if (tgt.createNewFile()) {
502         byte[] data = getContents(src);
503         setContents(tgt, data);
504         return true;
505       }
506     }
507
508     return false;
509   }
510 }