View Javadoc

1   /*
2    * Fsgrep is a simple Java application which allows a user to
3    * search all files in a directory structure for lines matching
4    * a given pattern.  Its functionality is a combination of the
5    * Unix 'find' and 'grep' utilities.
6    * Visit [http://fsgrep.sourceforge.net/] for more information.
7    * 
8    * Copyright (C) 2003-2006 Murali Krishnan [murali_ca_us@users.sourceforge.net]
9    * 
10   * Fsgrep is free software; you can redistribute it and/or modify
11   * it under the terms of version 2 of the GNU General Public
12   * License as published by the Free Software Foundation.
13   * 
14   * Fsgrep is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Public License for more details.
18   * 
19   * You should have received a copy of the GNU General Public License
20   * along with Fsgrep (see the file named LICENSE.txt); if not, write
21   * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
22   * Boston, MA  02111-1307  USA
23   */
24  
25  package mk.fsgrep.util;
26  
27  import java.io.*;
28  import java.util.*;
29  
30  /***
31   * A utility that fully reads a file and provides access to the contents
32   * as a List of lines.
33   * It is meant to replace LineNumberReader and (its parent) BufferedReader
34   * because those consume the EOL characters when returning lines.
35   * 
36   * @author  Murali Krishnan
37   *
38   */
39  public class RawLineReader {
40  
41      //------------------------------------------------------------
42      //- Class Variables
43  
44      private static final int BUFFER_SIZE = 36;
45      private static final char CR = '\r';
46      private static final char LF = '\n';
47  
48  
49      //------------------------------------------------------------
50      //- Class Functions
51  
52  
53  
54      //------------------------------------------------------------
55      //- Instance Variables
56  
57      private File vFile = null;
58      private LinkedList<FileLine> vLines = new LinkedList<FileLine>();
59      private int vSize = 0;
60  
61  
62      //------------------------------------------------------------
63      //- Constructors
64  
65      public RawLineReader(String pFileName) {
66          this(new File(pFileName));
67      }
68  
69  
70      public RawLineReader(File pFile) {
71          vFile = pFile;
72  
73          initialize();
74      }
75  
76  
77      /***
78       * For testing only.
79       * 
80       */
81      protected RawLineReader() {
82      }
83  
84  
85      //------------------------------------------------------------
86      //- Accessors
87  
88      protected File getFile() {
89          return vFile;
90      }
91  
92      public int getSize() {
93          return vSize;
94      }
95  
96      protected LinkedList<FileLine> getLines() {
97          return vLines;
98      }
99  
100 
101 
102     //------------------------------------------------------------
103     //- Settors
104 
105     public void setSize(int val) {
106         vSize = val;
107     }
108 
109 
110 
111     //------------------------------------------------------------
112     //- Private/Protected Utility Functions
113 
114     protected void initialize() {
115         try {
116             FileReader fr = new FileReader(getFile());
117             initialize(fr);
118             fr.close();
119         } catch (IOException ioe) {
120             System.err.println("Problem reading [" + getFileName() + "].");
121             ioe.printStackTrace();
122         }
123     }
124 
125 
126     protected void initialize(Reader reader) throws IOException {
127         int size = 0;
128         char[] buffer = new char[BUFFER_SIZE];
129         Splitter splitter = new Splitter(getLines());
130 
131         boolean done;
132         do {
133             int charsRead = reader.read(buffer);
134             done = (charsRead == -1);
135             if (done) {
136                 if (splitter.hasRemainder()) {
137                     getLines().add(splitter.giveRemainder());
138                 }
139             } else {
140                 size += charsRead;
141                 splitter.add(buffer, charsRead);
142             }
143         } while(!done);
144 
145         setSize(size);
146     }
147 
148 
149     protected void initialize(String content) {
150         try {
151             StringReader reader = new StringReader(content);
152             initialize(reader);
153             reader.close();
154         } catch (IOException ioe) {
155             System.err.println("Problem reading content.");
156             ioe.printStackTrace();
157         }
158     }
159 
160 
161     protected String getFileName() {
162         String result = getFile().getAbsolutePath();
163         return result;
164     }
165 
166 
167     protected void saveTo(String pString) {
168         try {
169             FileWriter fw = new FileWriter(pString);
170             for (FileLine line : getLines()) {
171                 fw.write(line.getText());
172             }
173             fw.close();
174         } catch (Exception ex) {
175             ex.printStackTrace();
176         }
177     }
178 
179 
180     //------------------------------------------------------------
181     //- Public Interface Functions
182 
183     public String toString() {
184         String result = "RawLineReader[name=" + getFileName() + ",lines=" + getLines().size() + ",characters=" + getSize() + "]";
185         return result;
186     }
187 
188 
189     public boolean hasMore() {
190         boolean result = !getLines().isEmpty();
191         return result;
192     }
193 
194 
195     public FileLine nextLine() {
196         return getLines().removeFirst();
197     }
198 
199 
200     //------------------------------------------------------------
201     //- Class Interface Functions
202 
203 
204 
205     //------------------------------------------------------------
206     //- Inner Classes
207 
208     private class Splitter {
209         private StringBuffer vRemainder = new StringBuffer();
210         private char vLastRemainderChar = Character.MIN_VALUE;
211         private char[] vBuffer = null;
212         private int vStart = 0;
213         private int vCurrent = 0;
214         private int vEnd = 0;
215         private int vLineNumber = 0;
216         private LinkedList<FileLine> vBufferLines = null;
217 
218         public Splitter(LinkedList<FileLine> pBufferLines) {
219             vBufferLines = pBufferLines;
220         }
221 
222 
223         private boolean currentIs(char ch) {
224             boolean result = vBuffer[vCurrent] == ch;
225             return result;
226         }
227 
228         private boolean nextIs(char ch) {
229             int next = vCurrent + 1;
230             boolean result = (next < vEnd) && (vBuffer[next] == ch);
231             return result;
232         }
233 
234         private boolean atEol() {
235             boolean result = currentIs(LF) ||
236                 (currentIs(CR) && !nextIs(LF));
237             return result;
238         }
239 
240         private boolean atEob() {
241             boolean result = (vCurrent >= vEnd);
242             return result;
243         }
244 
245         public boolean hasRemainder() {
246             boolean result = (vRemainder.length() > 0);
247             return result;
248         }
249 
250 
251         public FileLine giveRemainder() {
252             FileLine result = new FileLine(++vLineNumber, vRemainder.toString());
253             vRemainder = new StringBuffer();
254             return result;
255         }
256 
257         public boolean needToProcess() {
258             boolean result = true;
259 
260             while (!(atEob() || atEol())) {
261                 vCurrent++;
262             }
263 
264             if (atEob()) {
265                 result = false;
266                 --vCurrent;
267 
268                 int length = (vCurrent-vStart+1);
269                 if (length > 0) {
270                     vRemainder.append(new String(vBuffer, vStart, length));
271                 } else {
272                     // Store what the last char in the buffer was.
273                     vLastRemainderChar = vBuffer[vCurrent];
274                 }
275             } else {
276                 int length = (vCurrent-vStart+1);
277                 String text = new String(vBuffer, vStart, length);
278                 if (vRemainder.length() > 0) {
279                     text = vRemainder + text;
280                     vRemainder = new StringBuffer();
281                 }
282 
283                 vStart = ++vCurrent;
284 
285                 FileLine newLine = new FileLine(++vLineNumber, text);
286                 vBufferLines.add(newLine);
287             }
288 
289             return result;
290         }
291 
292 
293         public boolean hasMore() {
294             boolean result = !vBufferLines.isEmpty();
295             return result;
296         }
297 
298 
299         public FileLine nextLine() {
300             return vBufferLines.removeFirst();
301         }
302 
303 
304         public void add(char[] buffer, int len) {
305             vBuffer = buffer;
306             vStart = 0;
307             vCurrent = 0;
308             vEnd = len;
309 
310             // If last line ended in CR, check if buffer start with LF.
311             if ((vLastRemainderChar == CR) && (buffer[0] == LF)) {
312                 // This means it was a CRLF that was prematurely seen as
313                 // as just CR.  Rectify by adding the LF.
314                 FileLine last = vBufferLines.getLast();
315                 last.setText(last.getText() + LF);
316 
317                 // And skip over the LF.
318                 vStart = 1;
319                 vCurrent = 1;
320             }
321 
322             //noinspection StatementWithEmptyBody
323             while (needToProcess());
324         }
325     }
326 
327 
328     //------------------------------------------------------------
329     //- Main
330 
331     public static void main(String[] args) {
332         try {
333             for (String arg : args) {
334                 RawLineReader rlr = new RawLineReader(arg);
335                 System.out.println(rlr);
336                 rlr.saveTo("testout.txt");
337             }
338 
339         } catch (Throwable thr) {
340             System.err.println("Fatal error.");
341             thr.printStackTrace();
342         }
343     }
344 
345 
346 
347 }