001package Torello.Java; 002 003import Torello.Java.HelperPackages.SED.SingleLine; 004import Torello.Java.HelperPackages.SED.MultiLine; 005 006import static Torello.Java.C.*; 007 008import java.io.IOException; 009import java.io.FilenameFilter; 010import java.io.File; 011 012import java.util.List; 013import java.util.regex.Pattern; 014import java.util.regex.MatchResult; 015import java.util.function.Function; 016 017/** 018 * Based on the UNIX {@code 'SED'} Command, this class updates files based on 019 * <B STYLE='color: red;'><I>either</I></B> {@code String}-Literal matches & replacements, or 020 * <B STYLE='color: red;'><I>or</I></B> Regular-Expression matches. 021 * 022 * <EMBED CLASS='external-html' DATA-FILE-ID=SED> 023 */ 024@Torello.JavaDoc.StaticFunctional 025public class SED 026{ 027 private SED() { } 028 029 030 // ******************************************************************************************** 031 // ******************************************************************************************** 032 // Some Filters 033 // ******************************************************************************************** 034 // ******************************************************************************************** 035 036 037 /** A {@code java.io.FilenameFilter} that looks for JavaDoc Upgrader HTML-Files. */ 038 public static final FilenameFilter filterFilesHTML = (File dir, String fileName) -> 039 { 040 if (! fileName.endsWith(".html")) return false; 041 042 if (! StrCmpr.containsAND(dir.getPath(), "upgrade-files", "external-html")) return false; 043 044 return true; 045 }; 046 047 /** A {@code java.io.FilenameFilter} that looks for {@code '.java'} Files. */ 048 public static final FilenameFilter filterFilesJava = (File dir, String fileName) -> 049 { 050 if (! fileName.endsWith(".java")) return false; 051 052 return true; 053 }; 054 055 056 // ******************************************************************************************** 057 // ******************************************************************************************** 058 // Single-Line String-Match 059 // ******************************************************************************************** 060 // ******************************************************************************************** 061 062 063 /** 064 * Convenience Method. 065 * <BR />Invokes: {@link #singleLine(Iterable, String, String, boolean, IOExceptionHandler, 066 * Appendable, boolean, Verbosity)} 067 * <BR />Passes: <CODE> 068 * <B STYLE='color: blue'>askFirst</B>: TRUE, 069 * <B STYLE='color: blue'>ioeh</B>: null, 070 * <B STYLE='color: blue'>outputSaver</B>: null, 071 * <B STYLE='color: blue'>useUNIXColors</B>: TRUE, 072 * <B STYLE='color: blue'>verbosity</B>: Verbosity.Normal 073 * </CODE> 074 */ 075 public static List<FileNode> singleLine 076 (Iterable<FileNode> files, String matchStr, String replaceStr) 077 throws IOException 078 { 079 return SingleLine.strMatch 080 (files, matchStr, replaceStr, true, null, null, true, Verbosity.Normal); 081 } 082 083 /** 084 * Makes updates to Text-Files listed in parameter {@code 'files'}. 085 * 086 * <BR /><BR />In the example below, all {@code '.java'} Source-Code Files in the Java-HTML 087 * Library are loaded into a {@code Vector<FileNode>}. Using this particular {@code 'SED'} 088 * method, each substring that looks like <B STYLE='color: blue'>{@code <B>TRUE</B>}</B> (in 089 * all {@code '.java'} Source-Files) is converted to look like 090 * <B STYLE='color: blue'><CODE>{@code TRUE}</CODE></B> 091 * 092 * <DIV CLASS=EXAMPLE>{@code 093 * StringBuilder log = new StringBuilder(); 094 * 095 * // Load all Java-HTML Source-Files (in all packages) into a FileNode-Vector 096 * Vector<FileNode> files = FileNode 097 * .createRoot("Torello/") 098 * .loadTree(-1, SED.filterFilesJava, null) 099 * .flattenJustFiles(RTC.VECTOR()); 100 * 101 * // Invoke this method 102 * singleLine(files, "<B>TRUE</B>", "{@code TRUE}", true, null, log, true, Verbosity.Normal); 103 * 104 * // Save the Changes that were made to a log 105 * FileRW.writeFile(log, "ChangesMade.log.txt"); 106 * }</DIV> 107 * 108 * @param matchStr Any Java {@code String}-Literal. It is required that this {@code String} 109 * not contain any new-line ({@code '\n'}) characters, or an {@code IllegalArgumentException} 110 * will throw. 111 * 112 * @param replaceStr For all {@code 'files'}, each instance of the {@code String}-Literal 113 * parameter {@code 'matchStr'} found in any file will be replaced by {@code 'replaceStr'}. 114 * 115 * <BR /><BR />As with parameter {@code 'matchStr'}, if this {@code String} contains any 116 * new-line ({@code '\n'}) characters, an {@code IllegalArgumentException} will throw. 117 * 118 * @return A list of {@link FileNode} instances whose File-Contents were modified / updated 119 * by this method. 120 * 121 * @throws IllegalArgumentException If either of the {@code String} parameters 122 * {@code 'matchStr'} or {@code 'replaceStr'} contain any newline ({@code '\n'}) characters. 123 * 124 * <BR /><BR />If a {@code 'SED'} replacement needs to be done using a {@code String}-Match 125 * that spans more than one line, use the Multi-Line method provided in this class. 126 * 127 * @throws AppendableError <EMBED CLASS='external-html' DATA-FILE-ID=SED_APPEND_ERROR> 128 * @throws IOException On File-System read / write error. 129 */ 130 public static List<FileNode> singleLine( 131 Iterable<FileNode> files, 132 String matchStr, 133 String replaceStr, 134 boolean askFirst, 135 IOExceptionHandler ioeh, 136 Appendable outputSaver, 137 boolean useUNIXColors, 138 Verbosity verbosity 139 ) 140 throws IOException 141 { 142 return SingleLine.strMatch 143 (files, matchStr, replaceStr, askFirst, ioeh, outputSaver, useUNIXColors, verbosity); 144 } 145 146 147 // ******************************************************************************************** 148 // ******************************************************************************************** 149 // Single-Line Regular-Expression-Match 150 // ******************************************************************************************** 151 // ******************************************************************************************** 152 153 154 /** 155 * Convenience Method. 156 * <BR />Invokes: {@link #singleLine(Iterable, Pattern, Function, boolean, IOExceptionHandler, 157 * Appendable, boolean, Verbosity)} 158 * <BR />Passes: <CODE> 159 * <B STYLE='color: blue'>askFirst</B>: TRUE, 160 * <B STYLE='color: blue'>ioeh</B>: null, 161 * <B STYLE='color: blue'>outputSaver</B>: null, 162 * <B STYLE='color: blue'>useUNIXColors</B>: TRUE, 163 * <B STYLE='color: blue'>verbosity</B>: Verbosity.Normal 164 * </CODE> 165 */ 166 public static List<FileNode> singleLine 167 (Iterable<FileNode> files, Pattern regEx, Function<MatchResult, String> replaceFunction) 168 throws IOException 169 { 170 return SingleLine.regExMatch 171 (files, regEx, replaceFunction, true, null, null, true, Verbosity.Normal); 172 } 173 174 /** 175 * Makes updates to Text-Files listed in parameter {@code 'files'}. Matches that are eligible 176 * for replacement are identified using the Regular-Expression parameter {@code 'regEx'}. 177 * 178 * <BR /><BR />Replacement-{@code String's} are obtained by invoking the 179 * {@code 'replaceFunction'} parameter. 180 * 181 * <BR /><BR />In the example below, all Java HTML Library Source-Files are loaded into a 182 * {@code Vector<FileNode>}, and then iterated by this method. In each file, any instances of 183 * an {@code EMBED}-Tag that contains a {@code FILE-ID} Data-Attribute whose value is wrapped 184 * in Double Quotation-Marks has that value extracted and re-inserted without any 185 * Quotation-Marks. 186 * 187 * <DIV CLASS=EXAMPLE>{@code 188 * StringBuilder log = new StringBuilder(); 189 * 190 * // Load all Java-HTML Source-Files (in all packages) into a FileNode-Vector 191 * Vector<FileNode> files = FileNode 192 * .createRoot("Torello/") 193 * .loadTree(-1, filterFilesJava, null) 194 * .flattenJustFiles(RTC.VECTOR()); 195 * 196 * // Matches an <EMBED> Tag's FILE-ID Data-Attribute. There are parenthesis placed around the 197 * // actual ID-Name. The contents of the parenthesis are "Reg-Ex Match-Group #1" 198 * 199 * Pattern regEx = Pattern.compile("DATA-FILE-ID=\"(\\w+)\""); 200 * 201 * // This Function extracts Reg-Ex Group-1, and re-inserts it **WITHOUT** the Double 202 * // Quotation-Marks that were placed around it. Look Closely at Previous Line of Code, the 203 * // 'replacer' function does not include the Double-Quotes. 204 * 205 * Function<MatchResult, String> replacer = (MatchResult mr) -> "DATA-FILE-ID=" + mr.group(1); 206 * 207 * // Invoke this method 208 * singleLine(files, regEx, replacer, true, null, log, true, Verbosity.Normal); 209 * 210 * // Write the changes that have been made to a log-file 211 * FileRW.writeFile(log, "ChangesMade.log.txt"); 212 * }</DIV> 213 * 214 * @param regEx Any Java Regular-Expression. This will be used to match against the text 215 * inside each file returned by the {@code Iterable} parameter {@code 'files'}. 216 * 217 * <BR /><BR />If this Regular-Expression returns a match that spans more than a single line of 218 * text, this method will throw an exception. To perform matches that span multiple lines of 219 * text, use the Multi-Line methods, provided by this class 220 * 221 * @param replaceFunction Any Lambda-Expression or Function-Pointer that accepts a 222 * {@code java.util.regex.MatchResult}, and returns a Replacement-{@code String}. 223 * 224 * <BR /><BR />If this Replace-Function returns a match that contains any newline {@code '\n'} 225 * characters, this method will throw a {@link RegExException}. 226 * 227 * @return A list of {@link FileNode} instances whose File-Contents were modified / updated 228 * by this method. 229 * 230 * @throws RegExExpression Throws if the {@code Pattern} parameter {@code 'regEx'} returns a 231 * match that covers more than one line of text in any of the files that are scanned. 232 * 233 * <BR /><BR />This exception will also throw if the Lambda-Target / Function-Pointer parameter 234 * {@code 'replaceFunction'} ever returns a {@code String} that spans multiple lines. 235 * 236 * <BR /><BR />In both of these cases, the logic simply checks for the presence of a newline 237 * {@code '\n'} character. 238 * 239 * @throws AppendableError <EMBED CLASS='external-html' DATA-FILE-ID=SED_APPEND_ERROR> 240 * @throws IOException On File-System read / write error. 241 */ 242 public static List<FileNode> singleLine( 243 Iterable<FileNode> files, 244 Pattern regEx, 245 Function<MatchResult, String> replaceFunction, 246 boolean askFirst, 247 IOExceptionHandler ioeh, 248 Appendable outputSaver, 249 boolean useUNIXColors, 250 Verbosity verbosity 251 ) 252 throws IOException 253 { 254 return SingleLine.regExMatch 255 (files, regEx, replaceFunction, askFirst, ioeh, outputSaver, useUNIXColors, verbosity); 256 } 257 258 259 // ******************************************************************************************** 260 // ******************************************************************************************** 261 // Multi-Line String-Match 262 // ******************************************************************************************** 263 // ******************************************************************************************** 264 265 266 /** 267 * Convenience Method. 268 * <BR />Invokes: {@link #multiLine(Iterable, String, String, boolean, IOExceptionHandler, 269 * Appendable, boolean, Verbosity)} 270 * <BR />Passes: <CODE> 271 * <B STYLE='color: blue'>askFirst</B>: TRUE, 272 * <B STYLE='color: blue'>ioeh</B>: null, 273 * <B STYLE='color: blue'>outputSaver</B>: null, 274 * <B STYLE='color: blue'>useUNIXColors</B>: TRUE, 275 * <B STYLE='color: blue'>verbosity</B>: Verbosity.Normal 276 * </CODE> 277 */ 278 public static List<FileNode> multiLine 279 (Iterable<FileNode> files, String matchStr, String replaceStr) 280 throws IOException 281 { 282 return MultiLine.strMatch 283 (files, matchStr, replaceStr, true, null, null, true, Verbosity.Normal); 284 } 285 286 /** 287 * Makes updates to Text-Files listed in parameter {@code 'files'}. 288 * 289 * <BR /><BR /><B CLASS=JDDescLabel>Single-Line & Multi-Line:</B> 290 * 291 * <BR />If either parameters {@code 'matchStr'} or {@code 'replaceStr'} receive a 292 * {@code String} that does not actually contain any new-line characters ({@code '\n'}), 293 * <I>this method will not throw any exceptions. All User-Requested Text-Updates will be 294 * processed to completion!</I> 295 * 296 * <BR /><BR />This somewhat in contrast to method {@code 'singleLine'} which will, indeed, 297 * throw an {@code IllegalArgumentException} if either {@code 'matchStr'} or 298 * {@code 'replaceStr'} contain newline characters. 299 * 300 * @param matchStr Any Java {@code String}-Literal. 301 * 302 * @param replaceStr For all {@code 'files'}, each instance of the {@code String}-Literal 303 * parameter {@code 'matchStr'} found in any file will be replaced by {@code 'replaceStr'}. 304 * 305 * @return A list of {@link FileNode} instances whose File-Contents were modified / updated 306 * by this method. 307 * 308 * @throws AppendableError <EMBED CLASS='external-html' DATA-FILE-ID=SED_APPEND_ERROR> 309 * @throws IOException On File-System read / write error. 310 */ 311 public static List<FileNode> multiLine( 312 Iterable<FileNode> files, 313 String matchStr, 314 String replaceStr, 315 boolean askFirst, 316 IOExceptionHandler ioeh, 317 Appendable outputSaver, 318 boolean useUNIXColors, 319 Verbosity verbosity 320 ) 321 throws IOException 322 { 323 return MultiLine.strMatch 324 (files, matchStr, replaceStr, askFirst, ioeh, outputSaver, useUNIXColors, verbosity); 325 } 326 327 328 // ******************************************************************************************** 329 // ******************************************************************************************** 330 // Multi-Line Regular-Expression Match 331 // ******************************************************************************************** 332 // ******************************************************************************************** 333 334 335 /** 336 * Convenience Method. 337 * <BR />Invokes: {@link #multiLine(Iterable, Pattern, Function, boolean, IOExceptionHandler, 338 * Appendable, boolean, Verbosity)} 339 * <BR />Passes: <CODE> 340 * <B STYLE='color: blue'>askFirst</B>: TRUE, 341 * <B STYLE='color: blue'>ioeh</B>: null, 342 * <B STYLE='color: blue'>outputSaver</B>: null, 343 * <B STYLE='color: blue'>useUNIXColors</B>: TRUE, 344 * <B STYLE='color: blue'>verbosity</B>: Verbosity.Normal 345 * </CODE> 346 */ 347 public static List<FileNode> multiLine 348 (Iterable<FileNode> files, Pattern regEx, Function<MatchResult, String> replaceFunction) 349 throws IOException 350 { 351 return MultiLine.regExMatch 352 (files, regEx, replaceFunction, true, null, null, true, Verbosity.Normal); 353 } 354 355 /** 356 * Makes updates to Text-Files listed in parameter {@code 'files'}. 357 * 358 * <BR /><BR /><B CLASS=JDDescLabel>Single-Line & Multi-Line:</B> 359 * 360 * <BR />When unsure whether to use the {@code 'singleLine'} versus the {@code 'multiLine'} 361 * variants class {@coce 'SED'}, given a {@code 'regEx'} that might match either one or many 362 * lines of text - <I>always use the Multi-Line Version (this method) to avoid exception 363 * throws!</I> 364 * 365 * <BR /><BR />The main differences between methods {@code 'singleLine'} and 366 * {@code 'multiLine'} lays with the formatting of the User-Output Text that is printed by this 367 * method as matches are found. 368 * 369 * <BR /><BR />This method can easily handle falling back to printing only one line of 370 * Matching-Text. However, {@code 'singleLine'} is simply incapable of printing a Multi-Line 371 * Regular-Expression Match, and will instead throw an exception if such a match is identified. 372 * 373 * @param regEx Any Java Regular-Expression. This will be used to match against the text 374 * inside each file returned by the {@code Iterable} parameter {@code 'files'}. 375 * 376 * <BR /><BR />The Regular-Expression passed may match any number of characters or lines in the 377 * Source-File. If just one line of the original file is matched by {@code 'regEx'}, this is 378 * perfectly fine and will not produce any exception throws. 379 * 380 * <BR /><BR />This method's User Output-Text Printing-Mechanism is written to handle 381 * {@code 'regEx'} Match-Text of any size. 382 * 383 * @param replaceFunction Any Lambda-Expression or Function-Pointer that accepts a 384 * {@code java.util.regex.MatchResult}, and returns a Replacement-{@code String}. 385 * 386 * @return A list of {@link FileNode} instances whose File-Contents were modified / updated 387 * by this method. 388 * 389 * @throws AppendableError <EMBED CLASS='external-html' DATA-FILE-ID=SED_APPEND_ERROR> 390 * @throws IOException On File-System read / write error. 391 */ 392 public static List<FileNode> multiLine( 393 Iterable<FileNode> files, 394 Pattern regEx, 395 Function<MatchResult, String> replaceFunction, 396 boolean askFirst, 397 IOExceptionHandler ioeh, 398 Appendable outputSaver, 399 boolean useUNIXColors, 400 Verbosity verbosity 401 ) 402 throws IOException 403 { 404 return MultiLine.regExMatch( 405 files, regEx, replaceFunction, askFirst, ioeh, outputSaver, 406 useUNIXColors, verbosity 407 ); 408 } 409}