Source code for /engineering/autohit-2003/src/autohit/common/Formatter.javaOriginal file Formatter.java
   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 }