1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package mk.fsgrep;
26
27
28 import java.io.*;
29 import java.util.*;
30 import java.util.regex.*;
31
32 import mk.fsgrep.find.Finder;
33 import mk.fsgrep.find.ScanProfile;
34 import mk.fsgrep.gui.App;
35 import mk.fsgrep.gui.Preferences;
36 import mk.fsgrep.match.FileSearch;
37 import mk.fsgrep.match.MatchResult;
38 import mk.fsgrep.match.Replace;
39 import mk.fsgrep.match.ReplaceControl;
40 import mk.fsgrep.match.SearchFactory;
41 import mk.fsgrep.util.*;
42 import mk.fsgrep.util.Timer;
43 import mk.fsgrep.util.output.NullOutput;
44 import mk.fsgrep.util.output.OutputDestination;
45
46
47 /***
48 * The primary application class.
49 *
50 * @author Murali Krishnan
51 *
52 */
53 public class Fsgrep implements Runnable {
54
55
56
57
58 public static final ManifestProperties MANIFEST_PROPS = new ManifestProperties(Fsgrep.class);
59 public static final String USAGE = TextResource.get("USAGE.txt");
60 public static final String README = TextResource.get("README.txt");
61 public static final String LICENSE = MANIFEST_PROPS.getLicense();
62 public static final String VERSION = MANIFEST_PROPS.getProjectVersion();
63 public static final String VERSION_EXTRA = TextResource.get("VERSION_EXTRA.txt");
64
65 public static final Action ACTION_UNDEFINED = new Action.Undefined();
66 public static final Action ACTION_SEARCH = new Action.Search();
67 public static final Action ACTION_REPLACE = new Action.Replace();
68 public static final Action ACTION_LISTFILES = new Action.ListFiles();
69 public static final Action ACTION_RESCAN = new Action.Rescan();
70
71 protected static final SearchFactory factory = SearchFactory.getInstance();
72
73 /***
74 * A reference to the persistent data object (singleton).
75 */
76 private static final PersistentData pdata = PersistentData.getInstance();
77
78 public static final boolean DEBUG = Boolean.getBoolean("fsgrep.debug");
79
80 protected static final Pattern RE_STRIP_EOL = Pattern.compile("(//n|//r//n|//r)//z");
81
82
83
84
85
86
87 static public void run(Args args) {
88 try {
89 Fsgrep fsgrep = new Fsgrep(args);
90 if (args.launchGui()) {
91 if (!DEBUG) {
92
93 OutputRedirector.getInstance().redirect();
94 }
95 App app = new App();
96 app.launch(fsgrep);
97 } else {
98 OutputDestination report = args.createReportOutput();
99 OutputDestination result = args.createResultOutput();
100 OutputDestination live = new NullOutput();
101 OutputDestination status = new NullOutput();
102 fsgrep.initialize(report,
103 result,
104 live,
105 status,
106 new TextProgressBar(report));
107 fsgrep.setPattern(args.getPattern());
108 fsgrep.setAction(ACTION_SEARCH);
109
110 fsgrep.run();
111 }
112 } catch (PatternSyntaxException rese) {
113 System.err.println("'" + args.getPattern() + "': " + rese.getMessage());
114 } catch (Throwable thr) {
115 System.err.println("Fatal error.");
116 thr.printStackTrace();
117 }
118 }
119
120
121 public static String stripEol(String string) {
122 String result = RE_STRIP_EOL.matcher(string).replaceAll("");
123 return result;
124 }
125
126
127
128
129
130
131 private Args _args = null;
132 private Finder _finder = null;
133 private Finder vBackupFinder = null;
134 private List<MatchResult> fResultList = new ArrayList<MatchResult>();
135 private OutputDestination _reportOutput = null;
136 private OutputDestination _resultOutput = null;
137 private OutputDestination _liveOutput = null;
138 private OutputDestination _statusOutput = null;
139 private ProgressBar _progress = new NullProgressBar();
140 private ResultCounter _matchCounter = new ResultCounter();
141 private ResultCounter _finishedCounter = new ResultCounter();
142 private ResultCounter _remainingCounter = new ResultCounter();
143 private Pattern _re = null;
144 private String _pattern = "";
145 private String _replacement = "";
146 private boolean _aborted = false;
147 private Action _action = ACTION_UNDEFINED;
148 private int _totalLinesSearched = 0;
149
150
151
152
153
154
155 public Fsgrep(Args pArgs) {
156 _args = pArgs;
157
158 _finder = new Finder(this, new ScanProfile(pArgs.getRoot(), pArgs.getSuffix()));
159 }
160
161 /***
162 * Only for testing.
163 *
164 */
165 protected Fsgrep() {
166 }
167
168
169 public void initialize(OutputDestination pReport, OutputDestination pResult, OutputDestination pLive, OutputDestination pStatus, ProgressBar pBar) {
170 _reportOutput = pReport;
171 _resultOutput = pResult;
172 _liveOutput = pLive;
173 _statusOutput = pStatus;
174 _progress = pBar;
175 }
176
177
178
179
180
181 public Args getArgs() {return _args;}
182 public Finder getFinder() {return _finder;}
183 public List<MatchResult> getResultList() {return fResultList;}
184 public OutputDestination getReportOutput() {return _reportOutput;}
185 public OutputDestination getResultOutput() {return _resultOutput;}
186 public OutputDestination getLiveOutput() {return _liveOutput;}
187 public OutputDestination getStatusOutput() {return _statusOutput;}
188 protected ProgressBar getProgress() {return _progress;}
189 public ResultCounter getMatchCounter() {return _matchCounter;}
190 public ResultCounter getRemainingCounter() {return _remainingCounter;}
191 public ResultCounter getFinishedCounter() {return _finishedCounter;}
192 public Pattern getRE() {return _re;}
193 public String getPattern() {return _pattern;}
194 public String getReplacement() {return _replacement;}
195 public boolean isAborted() {return _aborted;}
196 public Action getAction() {return _action;}
197 protected int totalLinesSearched() {return _totalLinesSearched;}
198
199 protected Finder getBackupFinder() {
200 return vBackupFinder;
201 }
202
203
204
205
206
207
208 public void setLiveOutput(OutputDestination val) {_liveOutput=val;}
209 public void setMatchCounter(ResultCounter val) {_matchCounter=val;}
210 public void setRemainingCounter(ResultCounter val) {_remainingCounter=val;}
211 public void setFinishedCounter(ResultCounter val) {_finishedCounter=val;}
212
213 public void setFinder(Finder val) {
214 _finder=val;
215 }
216
217 protected void setRE(Pattern val) {_re=val;}
218 public void setReplacement(String val) {_replacement=val;}
219 public void setAborted(boolean val) {_aborted=val;}
220 protected void totalLinesSearched(int val) {_totalLinesSearched=val;}
221
222 protected void setBackupFinder(Finder val) {
223 vBackupFinder = val;
224 }
225
226
227
228
229
230 public void setAction(Action val) {
231 val.setModel(this);
232
233 _action = val;
234 }
235
236
237 public boolean getAlwaysRescan() {
238 boolean result = pdata.getBooleanProperty(Preferences.KEY_RESCAN);
239
240 return result;
241 }
242
243
244 protected void search() {
245 int lineCount = 0;
246 Iterator iterator = getFinder().getFileList().iterator();
247 while (!isAborted() && iterator.hasNext()) {
248 TargetFile file = (TargetFile) iterator.next();
249 FileSearch fileSearch = factory.create(file.getSuffix(), getArgs());
250 fileSearch.initialize(getRE(), file, this);
251
252
253
254
255 if (getArgs().isListFileMatches()) {
256 fileSearch.stopAfterFirstMatch();
257 }
258
259 fileSearch.run();
260 lineCount += fileSearch.getLinesSearched();
261 }
262
263 getProgress().finish();
264 totalLinesSearched(lineCount);
265 }
266
267
268 protected void replace() {
269 int lineCount = 0;
270 ReplaceControl control = new ReplaceControl(getRE(), getReplacement());
271 control.setReplaceCount(getMatchCounter());
272
273 Iterator iterator = getFinder().getFileList().iterator();
274 while (control.getDoContinue() && iterator.hasNext()) {
275 TargetFile file = (TargetFile) iterator.next();
276 Replace replace = new Replace(control, file);
277 replace.run();
278
279 finishFile(null);
280 }
281 setAborted(iterator.hasNext());
282
283 getProgress().finish();
284 totalLinesSearched(lineCount);
285 }
286
287
288 protected void searchForPattern() {
289 prepare();
290
291 if (getArgs().isSearchFileNames()) {
292 getStatusOutput().print("Applying the pattern to filenames ...");
293 } else {
294 getStatusOutput().print("Searching for matches in files ...");
295 }
296
297 getProgress().initialize(getFinder().getFileList().size());
298
299 Timer timer = new Timer();
300 search();
301 timer.stop();
302
303 if (getArgs().isListFileMatches()) {
304 showFilelistResult();
305 } else {
306 showMatchResult();
307 }
308
309 showResult(timer);
310 }
311
312
313 protected void replacePattern() {
314 prepare();
315
316 getStatusOutput().print("Searching for matches in files ...");
317
318 getProgress().initialize(getFinder().getFileList().size());
319
320 Timer timer = new Timer();
321 replace();
322 timer.stop();
323
324 showResult(timer);
325 }
326
327
328 protected void showMatchResult() {
329 if (!getResultList().isEmpty()) {
330 for (MatchResult result : getResultList()) {
331 getResultOutput().print(result);
332 }
333
334 getResultOutput().print(MatchResult.SEPARATOR);
335 getResultOutput().flush();
336 }
337
338
339
340 {
341 StringBuffer buffer = new StringBuffer();
342 buffer.append(getMatchCounter().getValue()).append(" matches");
343 if (totalLinesSearched() > 0) {
344 buffer.append("; ")
345 .append(totalLinesSearched())
346 .append(" total lines searched");
347 }
348 buffer.append(".");
349 getReportOutput().println(buffer);
350 }
351 }
352
353
354 protected List<String> getResultFilelist() {
355 List<String> result = new ArrayList<String>();
356 for (MatchResult match : getResultList()) {
357 result.add(match.getFilename());
358 }
359
360 if (getArgs().isListFilesWithoutMatch()) {
361
362 List<String> exclusions = result;
363 result = new ArrayList<String>();
364
365 for (TargetFile file : getFinder().getFileList()) {
366 String candidate = file.getName();
367
368 if (!exclusions.contains(candidate)) {
369 result.add(candidate);
370 }
371 }
372 }
373
374 return result;
375 }
376
377
378 protected void showFilelistResult() {
379 List<String> results = getResultFilelist();
380
381 if (!results.isEmpty()) {
382 getReportOutput().print(MatchResult.SEPARATOR);
383
384 for (String result : results) {
385 getResultOutput().println(result);
386 }
387
388 getReportOutput().print(MatchResult.SEPARATOR);
389 getResultOutput().flush();
390 }
391
392 String resultsTag = getArgs().isListFilesWithoutMatch() ?
393 " files did not contain matches." :
394 " files contained matches.";
395 getReportOutput().println(results.size() + resultsTag);
396 }
397
398
399 protected void showResult(Timer timer) {
400 long total = timer.getTotal();
401 int count = getFinder().getFileList().size();
402 double avg = timer.findAverage(count);
403
404 getReportOutput().println("Search time: " + total + " ms, " +
405 count + " files, " + avg + " ms per file.");
406
407
408 }
409
410
411 protected void printMemory() {
412 Runtime runtime = Runtime.getRuntime();
413
414 runtime.gc();
415
416 long total = runtime.totalMemory() / 1024;
417 long free = runtime.freeMemory() / 1024;
418 long used = (total - free);
419
420 System.out.println("Memory <used,free> = <" + used + "," + free + ">");
421 }
422
423
424 protected void prepare() {
425 fResultList = new ArrayList<MatchResult>();
426
427 getMatchCounter().reset();
428 getFinishedCounter().reset();
429
430 if (getFinder().getFileList().isEmpty() || getAlwaysRescan()) {
431 getRemainingCounter().reset();
432 getFinder().scan();
433 }
434 getRemainingCounter().setValue(getFinder().getFileCount().getValue());
435 }
436
437
438 protected void listFiles() {
439 prepare();
440
441 getReportOutput().println("Found " + getFinder().getFileList().size() +
442 " files.");
443 getStatusOutput().print("Listing files ...");
444
445 for (TargetFile targetFile : getFinder().getFileList()) {
446 String result = String.valueOf(targetFile);
447 getResultOutput().println(result);
448 getLiveOutput().println(result);
449 }
450
451 getResultOutput().flush();
452 }
453
454
455 protected int getMatchFlag() {
456 int result = getArgs().isCaseSensitive() ?
457 0 : Pattern.CASE_INSENSITIVE;
458
459 return result;
460 }
461
462
463
464
465
466
467 public String toString() {
468 String result = "Fsgrep [" + getFinder().toProfileString() + ", \"" + getPattern() + "\"]";
469
470 return result;
471 }
472
473 public void run() {
474 setAborted(false);
475 getReportOutput().println(this);
476
477 getAction().execute();
478 restoreFinder();
479 }
480
481 public void setPattern(String pPattern) {
482 _pattern = pPattern;
483
484 setRE(Pattern.compile(pPattern, getMatchFlag()));
485 }
486
487
488 public synchronized void finishFile(FileSearch fileSearch) {
489 if ((fileSearch != null) && (fileSearch.getResults() != null)) {
490 getResultList().add(fileSearch.getResults());
491 getMatchCounter().increment(fileSearch.getCount());
492 getLiveOutput().print(fileSearch.getResults());
493 }
494
495 getFinishedCounter().increment();
496 getRemainingCounter().decrement();
497 getProgress().update();
498 }
499
500
501 public boolean isActionSearch() {
502 boolean result = getAction().isSearch();
503
504 return result;
505 }
506
507
508 public void useTransientFinder(Finder pFinder) {
509 setBackupFinder(getFinder());
510 setFinder(pFinder);
511 }
512
513
514 public void restoreFinder() {
515 if (getBackupFinder() != null) {
516 setFinder(getBackupFinder());
517 setBackupFinder(null);
518 }
519 }
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535 static public void main(String[] cmdLineArgs) {
536 Args args = new Args(cmdLineArgs);
537
538 if (args.getShowUsage()) {
539 System.out.println(USAGE);
540 } else if (args.getShowVersion()) {
541 System.out.println("fsgrep (file system grep) " + VERSION + ", " + MANIFEST_PROPS.getBuildTime());
542 System.out.println();
543 System.out.println(VERSION_EXTRA);
544 } else {
545 File root = new File(args.getRoot());
546 if (root.isDirectory()) {
547 run(args);
548 } else {
549 System.err.println("No directory [" + args.getRoot() + "].");
550 }
551 }
552 }
553
554
555 }