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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
package Torello.Java;

import java.io.IOException;
import java.util.*;

/**
 * A utility that attempts to mimic the UNIX command <CODE>'grep'</CODE>.
 * <EMBED CLASS='external-html' DATA-FILE-ID=GREP>
 */
@Torello.JavaDoc.StaticFunctional
public class GREP
{
    private GREP() { }

    /**
     * Convenience Method.
     * <BR />Automatically Selects: {@link RTC#VECTOR()}
     * <BR />Invokes: {@link #search(RTC, Iterator, SearchAndPrint, IOExceptionHandler)}
     */
    public static Vector<FileNode> search
        (Iterable<FileNode> iterable, SearchAndPrint sp, IOExceptionHandler ioeh)
    { return search(RTC.VECTOR(), iterable.iterator(), sp, ioeh); }

    /**
     * Convenience Method.
     * <BR />Automatically Selects: {@link RTC#VECTOR()}
     * <BR />Invokes: {@link #search(RTC, Iterator, SearchAndPrint, IOExceptionHandler)}.
     */
    public static Vector<FileNode> search
        (Iterator<FileNode> iter, SearchAndPrint sp, IOExceptionHandler ioeh)
    { return search(RTC.VECTOR(), iter, sp, ioeh); }

    /**
     * This version of GREP shall search every file in a java {@code Iterator<FileNode>}
     * data-structure.  Any 'directories' (which are not files) returned by this {@code Iterator}
     * shall be skipped / ignored.
     *
     * @param dataStructureChoice <EMBED CLASS='external-html' DATA-FILE-ID=FN_RTC_PARAM>
     *
     * @param iter Any Iterator of type {@code Iterator<FileNode>}.  Each file that is returned in
     * the return set shall be searched for the described matches using {@code 'SearchAndPrint'}
     * parameter {@code 'sp'}
     *
     * @param sp The {@code 'sp'} parameter is the implementation of the file-grep operation that
     * the user is requesting.  The actions that this SearchAndPrint method-pointer should perform
     * include:
     *
     * <BR /><BR /><UL CLASS=JDUL>
     * <LI> Test if the file contains a match - using whatever string-testing procedure required.
     *      Usually either a simple {@code String} token is being searched, or an entire 
     *      {@code String} regular-expression is used.
     *      </LI>
     * 
     * <LI> Do some kind of output printing to a writable printing parameter to report these
     *      {@code String}-match results
     *      </LI>
     * 
     * <LI> return either {@code TRUE} or {@code FALSE} to indicate whether or not a particular file
     *      contained matches.
     *      </LI>
     * </UL>
     *
     * <BR /><BR /><B><SPAN STYLE="color: red;">IMPORTANT:</B></SPAN> This parameter cannot be
     * null.  It is the core of the grep-search algorithm.  If the programmer wishes to rely on the
     * standard 'token-search' or 'regular-expression-search' methods defined in
     * {@code class 'SearchAndPrint'} - <I>then the programmer should simply use one of the
     * standard factory methods provided in {@code 'SearchAndPrint'} to build an instance of
     * this class.</I> 
     *
     * @param ioeh When performing these UNIX-GREP styled text-file searches, it becomes imperative
     * to catch any potential {@code IOException's} so that if one file is failing to load to Java,
     * the rest of the entire search will not be sacrificed or ceased.  Using this parameter allows
     * a programmer to log exceptions, or take any user-defined action when any potential
     * {@code IOException's} occur while reading the files in a directory tree.  Using this
     * exception-handler allows the GREP-Search to continue, even if reading one particular file
     * fails.
     *
     * <BR /><BR /><B>NOTE:</B> This parameter may be null, and if it is, it will be ignored -
     * <I>and all exceptions shall suppressed</I>.  This means that no exception information will
     * be reported back to the user.  If this parameter is null, and if an {@code IOException} is
     * generated while traversing a particular file for GREP-search, that file will merely be
     * skipped (gracefully), and its contents will not be searched.
     *
     * @return The return-list shall contain a reference of every instance of
     * {@code FileNode} for which whose contents on the file-system contained a match - as
     * determined by the {@code SearchAndPrint} instance that is passed to parameter {@code 'sp'}.
     *
     * <EMBED CLASS='external-html' DATA-FILE-ID=FN_RTC_RET>
     *
     * @see SearchAndPrint
     * @see FileRW#loadFileToString(String)
     * @see FileNode#isDirectory
     * @see FileNode#toString()
     * @see SearchAndPrint#test(String, String)
     * @see IOExceptionHandler#accept(FileNode, IOException)
     */
    public static <T> T search(
            RTC<T> dataStructureChoice, Iterator<FileNode> iter, SearchAndPrint sp,
            IOExceptionHandler ioeh
        )
    { 
        while (iter.hasNext())
        {
            FileNode fn = iter.next();

            if (fn.isDirectory) continue;

            try
            {
                String  fileContents    = FileRW.loadFileToString(fn.toString());
                boolean wasMatch        = sp.test(fn.toString(), fileContents);

                if (wasMatch) dataStructureChoice.inserter.accept(fn);
            }

            catch (IOException e)
                { if (ioeh != null) ioeh.accept(fn, e); }
        }

        return dataStructureChoice.finisher.get();
    }

    /**
     * This version of GREP shall search a single file only.  The passed parameter 'file' must be
     * a {@code FileNode} instance that represents a UNIX or MS-DOS file, not a directory.
     *
     * @param file This is the file to be searched or "GREPPED."
     *
     * @param sp The {@code 'sp'} parameter is the implementation of the file-grep operation
     * that the user is requesting.  The actions that this SearchAndPrint method-pointer should
     * perform include:
     *
     * <BR /><BR /><UL CLASS=JDUL>
     * <LI> Test if the file contains a match - using whatever string-testing procedure required.
     *      Usually either a simple {@code String} token is being searched, or an entire 
     *      {@code String} regular-expression is used.
     *      </LI>
     * 
     * <LI> Do some kind of output printing to a writable printing parameter to report these
     *      {@code String}-match results
     *      </LI>
     * 
     * <LI> return either {@code TRUE} or {@code FALSE} to indicate whether or not a particular file
     *      contained matches.
     *      </LI>
     * </UL>
     *
     * <BR /><B><SPAN STYLE="color: red;">IMPORTANT:</B></SPAN> This parameter cannot be null.
     * It is the core of the grep-search algorithm.  If the programmer wishes to rely on the
     * standard 'token-search' or 'regular-expression-search' methods defined in class
     * {@code 'SearchAndPrint'} - <I>then the programmer should simply use one of the standard
     * factory methods provided in {@code 'SearchAndPrint'} to build an instance of this class.</I>
     *
     * @param ioeh This parameter may be used, or it may be left null.  It is less emphasized here,
     * because only a single file is being searched.  That file is specified in the parameters to
     * this method.  Since there is only one file to search, catching the {@code IOException's}
     * makes little difference because GREP-search on other files will not be hindered, since there
     * are no other files being searched.
     *
     * @return A value of {@code TRUE} shall indicate that there was a match found.
     *
     * @throws FileExpectedException The parameter {@code 'file'} must actually be a 'file' instance
     * of {@code FileNode}.  If {@code 'file'} is not actually a file, but rather a directory, then
     * this exception shall throw.
     *
     * @see FileExpectedException#check(FileNode)
     * @see FileRW#loadFileToString(String)
     * @see FileNode#toString()
     * @see SearchAndPrint#test(String, String)
     * @see IOExceptionHandler#accept(FileNode, IOException)
     */
    public static boolean searchFile(FileNode file, SearchAndPrint sp, IOExceptionHandler ioeh)
    {
        // Can only test files, not directories...
        FileExpectedException.check(file);

        // Test to see if there is a match
        try
            { return sp.test(file.toString(), FileRW.loadFileToString(file.toString())); }

        catch (IOException e)
            { if (ioeh != null) ioeh.accept(file, e); return false; }
    }
}