1 /* 2 * Copyright (C) 2005 Christian Schulte <cs@schulte.it> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * o Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * o Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 19 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $JOMC: LineEditor.java 5091 2016-04-04 15:40:17Z schulte $ 29 * 30 */ 31 package org.jomc.util; 32 33 import java.io.BufferedReader; 34 import java.io.IOException; 35 import java.io.StringReader; 36 37 /** 38 * Interface to line based editing. 39 * 40 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 41 * @version $JOMC: LineEditor.java 5091 2016-04-04 15:40:17Z schulte $ 42 * 43 * @see #edit(java.lang.String) 44 */ 45 public class LineEditor 46 { 47 48 /** 49 * Editor to chain. 50 */ 51 private LineEditor editor; 52 53 /** 54 * Line separator. 55 */ 56 private String lineSeparator; 57 58 /** 59 * Current line number. 60 * 61 * @since 1.2 62 */ 63 private long lineNumber; 64 65 /** 66 * Creates a new {@code LineEditor} instance. 67 */ 68 public LineEditor() 69 { 70 this( null, null ); 71 } 72 73 /** 74 * Creates a new {@code LineEditor} instance taking a string to use for separating lines. 75 * 76 * @param lineSeparator String to use for separating lines. 77 */ 78 public LineEditor( final String lineSeparator ) 79 { 80 this( null, lineSeparator ); 81 } 82 83 /** 84 * Creates a new {@code LineEditor} instance taking an editor to chain. 85 * 86 * @param editor The editor to chain. 87 */ 88 public LineEditor( final LineEditor editor ) 89 { 90 this( editor, null ); 91 } 92 93 /** 94 * Creates a new {@code LineEditor} instance taking an editor to chain and a string to use for separating lines. 95 * 96 * @param editor The editor to chain. 97 * @param lineSeparator String to use for separating lines. 98 */ 99 public LineEditor( final LineEditor editor, final String lineSeparator ) 100 { 101 super(); 102 this.editor = editor; 103 this.lineSeparator = lineSeparator; 104 this.lineNumber = 0L; 105 } 106 107 /** 108 * Gets the line separator of the editor. 109 * 110 * @return The line separator of the editor. 111 */ 112 public final String getLineSeparator() 113 { 114 if ( this.lineSeparator == null ) 115 { 116 this.lineSeparator = System.getProperty( "line.separator", "\n" ); 117 } 118 119 return this.lineSeparator; 120 } 121 122 /** 123 * Gets the current line number. 124 * 125 * @return The current line number. 126 * 127 * @since 1.2 128 */ 129 public final long getLineNumber() 130 { 131 return this.lineNumber; 132 } 133 134 /** 135 * Edits text. 136 * <p> 137 * This method splits the given string into lines and passes every line to method {@code editLine} in order of 138 * occurrence. On end of input, method {@code editLine} is called with a {@code null} argument. 139 * </p> 140 * 141 * @param text The text to edit or {@code null}. 142 * 143 * @return The edited text or {@code null}. 144 * 145 * @throws IOException if editing fails. 146 */ 147 public final String edit( final String text ) throws IOException 148 { 149 String edited = text; 150 this.lineNumber = 0L; 151 BufferedReader reader = null; 152 boolean suppressExceptionOnClose = true; 153 154 try 155 { 156 if ( edited != null ) 157 { 158 final StringBuilder buf = new StringBuilder( edited.length() + 16 ); 159 boolean appended = false; 160 161 if ( edited.length() > 0 ) 162 { 163 reader = new BufferedReader( new StringReader( edited ) ); 164 165 String line = null; 166 while ( ( line = reader.readLine() ) != null ) 167 { 168 this.lineNumber++; 169 final String replacement = this.editLine( line ); 170 if ( replacement != null ) 171 { 172 buf.append( replacement ).append( this.getLineSeparator() ); 173 appended = true; 174 } 175 } 176 } 177 else 178 { 179 this.lineNumber++; 180 final String replacement = this.editLine( edited ); 181 if ( replacement != null ) 182 { 183 buf.append( replacement ).append( this.getLineSeparator() ); 184 appended = true; 185 } 186 } 187 188 final String replacement = this.editLine( null ); 189 if ( replacement != null ) 190 { 191 buf.append( replacement ); 192 appended = true; 193 } 194 195 edited = appended ? buf.toString() : null; 196 } 197 198 if ( this.editor != null ) 199 { 200 edited = this.editor.edit( edited ); 201 } 202 203 suppressExceptionOnClose = false; 204 return edited; 205 } 206 finally 207 { 208 try 209 { 210 if ( reader != null ) 211 { 212 reader.close(); 213 } 214 } 215 catch ( final IOException e ) 216 { 217 if ( !suppressExceptionOnClose ) 218 { 219 throw e; 220 } 221 } 222 } 223 } 224 225 /** 226 * Edits a line. 227 * 228 * @param line The line to edit or {@code null}, indicating the end of input. 229 * 230 * @return The string to replace {@code line} with or {@code null}, to replace {@code line} with nothing. 231 * 232 * @throws IOException if editing fails. 233 */ 234 protected String editLine( final String line ) throws IOException 235 { 236 return line; 237 } 238 239 }