1 /**
2 * AUTOHIT 2003
3 * Copyright Erich P Gatejen (c) 1989,1997,2003,2004
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Additional license information can be found in the documentation.
19 * @author Erich P Gatejen
20 */
21 package autohit.common;
22 import java.io.Writer;
23 import autohit.common.AutohitProperties;
24
25 /**
26 * formatting helpers
27 *
28 * @author Erich P. Gatejen
29 * @version 1.0
30 * <i>Version History</i>
31 * <code>EPG - New - 1 Jul 03<br>
32 * EPG - Added change to catch newlines as the end of the text - 30Jul03</code>
33 *
34 */
35 public class Formatter {
36
37 // internal state values
38 private final static int STATE_FRESH = 0;
39 private final static int STATE_CR = 1;
40 private final static int STATE_LF = 2;
41 private final static int STATE_WHITESPACE = 3;
42 private final static int STATE_BUST = 4;
43 private final static int ARBITRARY_ENTRY_LIMIT = 6000;
44
45 // Line separator
46 private String lineSeparator;
47
48 /*
49 * Setable attributes. Line length says how big the formatted lines
50 * should be, including headers.
51 */
52 public int lineLength = AutohitProperties.LOGS_LINE_SIZE_DEFAULT; // default
53
54 /*
55 * Setable attributes. Line limit is the biggest any single entry can be.
56 */
57 public int lineLimit = AutohitProperties.LOGS_ARBITRARY_ENTRY_LIMIT_DEFAULT;
58
59 /*
60 * Constructor
61 */
62 public Formatter() {
63 lineSeparator = System.getProperty("line.separator");
64 }
65
66 /**
67 * Formatting writer that accepts an initial and subsiquent prefixes.
68 * @param initialPrefix prefix for the first line
69 * @param prefix prefix for the following lines
70 * @param text the text to write
71 * @param target the target Writer
72 * @throws Exception
73 */
74 public void prefixedWriter(
75 String initialPrefix,
76 String prefix,
77 String text,
78 Writer target)
79 throws Exception {
80
81 int prelength = prefix.length();
82 int fieldlength = lineLength - prelength;
83 int endspot = text.length();
84
85 // trivial case
86 if (endspot <= fieldlength) {
87 target.write(initialPrefix + text + lineSeparator);
88 target.flush();
89 return;
90 }
91
92 // Bound it
93 if (endspot > lineLimit)
94 endspot = lineLimit;
95
96 // Header
97 target.write(initialPrefix);
98
99 // set up work through the text
100 int state = STATE_FRESH;
101
102 int runstart = 0;
103 int runlast = 0;
104 int rover;
105 boolean reset = false;
106 char c;
107 try {
108
109 for (rover = 0; rover < endspot; rover++) {
110 c = text.charAt(rover);
111
112 // reset?
113 if (reset) {
114
115 if (rover == endspot-1) {
116 // this catches trailing newlines
117 target.write(lineSeparator);
118 reset = false;
119 } else {
120 runstart = runlast = rover;
121 target.write(lineSeparator);
122 target.write(prefix);
123 reset = false;
124 }
125
126 // Did we bust?
127 } else if ((rover - runstart) > fieldlength) {
128
129 if (runlast != runstart) {
130
131 // it's not a super big line.
132 target.write(text.substring(runstart, runlast));
133 target.write(lineSeparator);
134 target.write(prefix);
135 runstart = runlast;
136 }
137
138 } // end if bust
139
140 switch (state) {
141
142 case STATE_FRESH :
143 if (c == Constants.CHAR_CR) {
144 // New line
145 target.write(text.substring(runstart, rover));
146 reset = true;
147 state = STATE_CR;
148
149 } else if (c == Constants.CHAR_LF) {
150 // New line
151 target.write(text.substring(runstart, rover));
152 reset = true;
153 state = STATE_LF;
154
155 } else if (Character.isWhitespace(c)) {
156 // New word
157 runlast = rover;
158 }
159 break;
160
161 case STATE_CR :
162
163 if (c == Constants.CHAR_CR) {
164 // Another return
165 reset = true;
166 } else if (c == Constants.CHAR_LF) {
167 //rover++;
168 runstart = runlast = rover+1;
169 } else {
170 state = STATE_FRESH;
171 }
172 break;
173
174 case STATE_LF :
175
176 if (c == Constants.CHAR_LF) {
177 // Another linefeed
178 reset = true;
179 } else if (c == Constants.CHAR_CR) {
180 //rover++;
181 runstart = runlast = rover+1;
182 } else {
183 state = STATE_FRESH;
184 }
185 break;
186
187 default :
188 // SOFTWARE FAULT!
189 break;
190 } // end case
191
192 } // end for
193
194 // catch any dangling
195 if (runlast < rover) {
196 target.write(text.substring(runstart, rover));
197 target.write(lineSeparator);
198 }
199
200 } catch (IndexOutOfBoundsException e) {
201 reset = false;
202 // ignore this one. :^)
203 } catch (Exception ex) {
204 throw ex;
205 }
206 target.flush();
207 }
208
209 }
|